diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index ce8967337b02f9..efbdcd402cdf67 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -9,8 +9,8 @@ ENV WASMTIME_HOME=/opt/wasmtime
ENV WASMTIME_VERSION=7.0.0
ENV WASMTIME_CPU_ARCH=x86_64
-RUN dnf -y --nodocs install git clang xz python3-blurb dnf-plugins-core && \
- dnf -y --nodocs builddep python3 && \
+RUN dnf -y --nodocs --setopt=install_weak_deps=False install /usr/bin/{blurb,clang,curl,git,ln,tar,xz} 'dnf-command(builddep)' && \
+ dnf -y --nodocs --setopt=install_weak_deps=False builddep python3 && \
dnf -y clean all
RUN mkdir ${WASI_SDK_PATH} && \
diff --git a/.gitattributes b/.gitattributes
index 13289182400109..4ed95069442f3d 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -32,6 +32,10 @@ Lib/test/test_importlib/resources/data01/* noeol
Lib/test/test_importlib/resources/namespacedata01/* noeol
Lib/test/xmltestdata/* noeol
+# Shell scripts should have LF even on Windows because of Cygwin
+Lib/venv/scripts/common/activate text eol=lf
+Lib/venv/scripts/posix/* text eol=lf
+
# CRLF files
[attr]dos text eol=crlf
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index fc1bb3388976d5..9149b38d87601c 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -5,7 +5,7 @@
# https://git-scm.com/docs/gitignore#_pattern_format
# GitHub
-.github/** @ezio-melotti
+.github/** @ezio-melotti @hugovk
# Build system
configure* @erlend-aasland @corona10
@@ -61,11 +61,7 @@ Python/traceback.c @iritkatriel
/Tools/build/parse_html5_entities.py @ezio-melotti
# Import (including importlib).
-# Ignoring importlib.h so as to not get flagged on
-# all pull requests that change the emitted
-# bytecode.
-**/*import*.c @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
-**/*import*.py @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
+**/*import* @brettcannon @encukou @ericsnowcurrently @ncoghlan @warsaw
**/*importlib/resources/* @jaraco @warsaw @FFY00
**/importlib/metadata/* @jaraco @warsaw
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index 4e5328282f1224..df0f107a541614 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -33,6 +33,7 @@ jobs:
check_source:
name: 'Check for source changes'
runs-on: ubuntu-latest
+ timeout-minutes: 10
outputs:
run_tests: ${{ steps.check.outputs.run_tests }}
steps:
@@ -63,6 +64,7 @@ jobs:
check_generated_files:
name: 'Check if generated files are up to date'
runs-on: ubuntu-latest
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
steps:
@@ -118,6 +120,7 @@ jobs:
build_win32:
name: 'Windows (x86)'
runs-on: windows-latest
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
@@ -126,7 +129,6 @@ jobs:
- uses: actions/checkout@v3
- name: Build CPython
run: .\PCbuild\build.bat -e -d -p Win32
- timeout-minutes: 30
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
@@ -135,6 +137,7 @@ jobs:
build_win_amd64:
name: 'Windows (x64)'
runs-on: windows-latest
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
@@ -145,7 +148,6 @@ jobs:
run: echo "::add-matcher::.github/problem-matchers/msvc.json"
- name: Build CPython
run: .\PCbuild\build.bat -e -d -p x64
- timeout-minutes: 30
- name: Display build info
run: .\python.bat -m test.pythoninfo
- name: Tests
@@ -154,6 +156,7 @@ jobs:
build_macos:
name: 'macOS'
runs-on: macos-latest
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
@@ -184,6 +187,7 @@ jobs:
build_ubuntu:
name: 'Ubuntu'
runs-on: ubuntu-20.04
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
@@ -241,6 +245,7 @@ jobs:
build_ubuntu_ssltests:
name: 'Ubuntu SSL tests with OpenSSL'
runs-on: ubuntu-20.04
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
strategy:
@@ -290,6 +295,7 @@ jobs:
build_asan:
name: 'Address sanitizer'
runs-on: ubuntu-20.04
+ timeout-minutes: 60
needs: check_source
if: needs.check_source.outputs.run_tests == 'true'
env:
@@ -302,6 +308,10 @@ jobs:
run: echo "::add-matcher::.github/problem-matchers/gcc.json"
- name: Install Dependencies
run: sudo ./.github/workflows/posix-deps-apt.sh
+ - name: Set up GCC-10 for ASAN
+ uses: egor-tensin/setup-gcc@v1
+ with:
+ version: 10
- name: Configure OpenSSL env vars
run: |
echo "MULTISSL_DIR=${GITHUB_WORKSPACE}/multissl" >> $GITHUB_ENV
diff --git a/.github/workflows/build_msi.yml b/.github/workflows/build_msi.yml
index 5f1dcae190efbc..2bed09014e0ff2 100644
--- a/.github/workflows/build_msi.yml
+++ b/.github/workflows/build_msi.yml
@@ -26,6 +26,7 @@ jobs:
build:
name: Windows Installer
runs-on: windows-latest
+ timeout-minutes: 60
strategy:
matrix:
type: [x86, x64, arm64]
diff --git a/.github/workflows/doc.yml b/.github/workflows/doc.yml
index 314a7da647ff70..3101b30231c355 100644
--- a/.github/workflows/doc.yml
+++ b/.github/workflows/doc.yml
@@ -36,6 +36,7 @@ jobs:
build_doc:
name: 'Docs'
runs-on: ubuntu-latest
+ timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- name: Register Sphinx problem matcher
@@ -80,6 +81,7 @@ jobs:
doctest:
name: 'Doctest'
runs-on: ubuntu-latest
+ timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- name: Register Sphinx problem matcher
diff --git a/.github/workflows/new-bugs-announce-notifier.yml b/.github/workflows/new-bugs-announce-notifier.yml
index b2a76ef7d36153..73806c5d6d58af 100644
--- a/.github/workflows/new-bugs-announce-notifier.yml
+++ b/.github/workflows/new-bugs-announce-notifier.yml
@@ -11,6 +11,7 @@ permissions:
jobs:
notify-new-bugs-announce:
runs-on: ubuntu-latest
+ timeout-minutes: 10
steps:
- uses: actions/setup-node@v3
with:
diff --git a/.github/workflows/project-updater.yml b/.github/workflows/project-updater.yml
index 99c7a05ae8cab0..7574bfc208ff76 100644
--- a/.github/workflows/project-updater.yml
+++ b/.github/workflows/project-updater.yml
@@ -13,16 +13,15 @@ jobs:
add-to-project:
name: Add issues to projects
runs-on: ubuntu-latest
+ timeout-minutes: 10
strategy:
matrix:
include:
# if an issue has any of these labels, it will be added
# to the corresponding project
- { project: 2, label: "release-blocker, deferred-blocker" }
- - { project: 3, label: expert-subinterpreters }
- - { project: 29, label: expert-asyncio }
- { project: 32, label: sprint }
-
+
steps:
- uses: actions/add-to-project@v0.1.0
with:
diff --git a/.github/workflows/require-pr-label.yml b/.github/workflows/require-pr-label.yml
new file mode 100644
index 00000000000000..916bbeb4352734
--- /dev/null
+++ b/.github/workflows/require-pr-label.yml
@@ -0,0 +1,18 @@
+name: Check labels
+
+on:
+ pull_request:
+ types: [opened, reopened, labeled, unlabeled, synchronize]
+
+jobs:
+ label:
+ name: DO-NOT-MERGE / unresolved review
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+
+ steps:
+ - uses: mheap/github-action-required-labels@v4
+ with:
+ mode: exactly
+ count: 0
+ labels: "DO-NOT-MERGE, awaiting changes, awaiting change review"
diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml
index 07dbcfe31d6563..94676f5ee5fffc 100644
--- a/.github/workflows/stale.yml
+++ b/.github/workflows/stale.yml
@@ -12,10 +12,11 @@ jobs:
if: github.repository_owner == 'python'
runs-on: ubuntu-latest
+ timeout-minutes: 10
steps:
- name: "Check PRs"
- uses: actions/stale@v7
+ uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR is stale because it has been open for 30 days with no activity.'
diff --git a/.github/workflows/verify-ensurepip-wheels.yml b/.github/workflows/verify-ensurepip-wheels.yml
index 969515ed287b55..17d841f1f1c54a 100644
--- a/.github/workflows/verify-ensurepip-wheels.yml
+++ b/.github/workflows/verify-ensurepip-wheels.yml
@@ -1,4 +1,4 @@
-name: Verify bundled pip and setuptools
+name: Verify bundled wheels
on:
workflow_dispatch:
@@ -23,10 +23,11 @@ concurrency:
jobs:
verify:
runs-on: ubuntu-latest
+ timeout-minutes: 10
steps:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: '3'
- - name: Compare checksums of bundled pip and setuptools to ones published on PyPI
+ - name: Compare checksum of bundled wheels to the ones published on PyPI
run: ./Tools/build/verify_ensurepip_wheels.py
diff --git a/Doc/c-api/type.rst b/Doc/c-api/type.rst
index 7b5d1fac40ed87..69b15296993301 100644
--- a/Doc/c-api/type.rst
+++ b/Doc/c-api/type.rst
@@ -232,6 +232,15 @@ Type Objects
.. versionadded:: 3.11
+.. c:function:: int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
+
+ Attempt to assign a version tag to the given type.
+
+ Returns 1 if the type already had a valid version tag or a new one was
+ assigned, or 0 if a new tag could not be assigned.
+
+ .. versionadded:: 3.12
+
Creating Heap-Allocated Types
.............................
diff --git a/Doc/conf.py b/Doc/conf.py
index 29fb63cbcc8614..42c23bf77c7034 100644
--- a/Doc/conf.py
+++ b/Doc/conf.py
@@ -68,12 +68,21 @@
# Minimum version of sphinx required
needs_sphinx = '3.2'
+# Ignore any .rst files in the includes/ directory;
+# they're embedded in pages but not rendered individually.
# Ignore any .rst files in the venv/ directory.
-exclude_patterns = ['venv/*', 'README.rst']
+exclude_patterns = ['includes/*.rst', 'venv/*', 'README.rst']
venvdir = os.getenv('VENVDIR')
if venvdir is not None:
exclude_patterns.append(venvdir + '/*')
+nitpick_ignore = [
+ # 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.
+ ('py:meth', '_SubParsersAction.add_parser'),
+]
+
# Disable Docutils smartquotes for several translations
smartquotes_excludes = {
'languages': ['ja', 'fr', 'zh_TW', 'zh_CN'], 'builders': ['man', 'text'],
@@ -252,8 +261,31 @@
# Options for the link checker
# ----------------------------
-# Ignore certain URLs.
-linkcheck_ignore = [r'https://bugs.python.org/(issue)?\d+']
+linkcheck_allowed_redirects = {
+ # bpo-NNNN -> BPO -> GH Issues
+ r'https://bugs.python.org/issue\?@action=redirect&bpo=\d+': 'https://github.com/python/cpython/issues/\d+',
+ # GH-NNNN used to refer to pull requests
+ r'https://github.com/python/cpython/issues/\d+': 'https://github.com/python/cpython/pull/\d+',
+ # :source:`something` linking files in the repository
+ r'https://github.com/python/cpython/tree/.*': 'https://github.com/python/cpython/blob/.*'
+}
+
+linkcheck_anchors_ignore = [
+ # ignore anchors that start with a '/', e.g. Wikipedia media files:
+ # https://en.wikipedia.org/wiki/Walrus#/media/File:Pacific_Walrus_-_Bull_(8247646168).jpg
+ r'\/.*',
+]
+
+linkcheck_ignore = [
+ # The crawler gets "Anchor not found"
+ r'https://developer.apple.com/documentation/.+?#.*',
+ r'https://devguide.python.org.+?/#.*',
+ r'https://github.com.+?#.*',
+ # Robot crawlers not allowed: "403 Client Error: Forbidden"
+ r'https://support.enthought.com/hc/.*',
+ # SSLError CertificateError, even though it is valid
+ r'https://unix.org/version2/whatsnew/lp64_wp.html',
+]
# Options for extensions
diff --git a/Doc/distributing/index.rst b/Doc/distributing/index.rst
index 21389adedf9c15..d237f8f082d87b 100644
--- a/Doc/distributing/index.rst
+++ b/Doc/distributing/index.rst
@@ -129,14 +129,10 @@ involved in creating and publishing a 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/
+.. _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...?
diff --git a/Doc/extending/newtypes.rst b/Doc/extending/newtypes.rst
index 80a1387db200c2..56b40acdb69fed 100644
--- a/Doc/extending/newtypes.rst
+++ b/Doc/extending/newtypes.rst
@@ -337,7 +337,7 @@ Here is an example::
}
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%.400s'",
+ "'%.100s' object has no attribute '%.400s'",
tp->tp_name, name);
return NULL;
}
diff --git a/Doc/faq/library.rst b/Doc/faq/library.rst
index a9cde456575020..597caaa778e1c8 100644
--- a/Doc/faq/library.rst
+++ b/Doc/faq/library.rst
@@ -780,7 +780,7 @@ socket to :meth:`select.select` to check if it's writable.
The :mod:`asyncio` module provides a general purpose single-threaded and
concurrent asynchronous library, which can be used for writing non-blocking
network code.
- The third-party `Twisted `_ library is
+ The third-party `Twisted `_ library is
a popular and feature-rich alternative.
diff --git a/Doc/glossary.rst b/Doc/glossary.rst
index 3d74d550dc345a..53e8cdcae1cd66 100644
--- a/Doc/glossary.rst
+++ b/Doc/glossary.rst
@@ -214,7 +214,7 @@ Glossary
A callable is an object that can be called, possibly with a set
of arguments (see :term:`argument`), with the following syntax::
- callable(argument1, argument2, ...)
+ callable(argument1, argument2, argumentN)
A :term:`function`, and by extension a :term:`method`, is a callable.
An instance of a class that implements the :meth:`~object.__call__`
diff --git a/Doc/howto/argparse.rst b/Doc/howto/argparse.rst
index f682587488a227..52e98fa9620194 100644
--- a/Doc/howto/argparse.rst
+++ b/Doc/howto/argparse.rst
@@ -1,10 +1,12 @@
+.. _argparse-tutorial:
+
*****************
Argparse Tutorial
*****************
:author: Tshepang Mbambo
-.. _argparse-tutorial:
+.. currentmodule:: argparse
This tutorial is intended to be a gentle introduction to :mod:`argparse`, the
recommended command-line parsing module in the Python standard library.
@@ -12,7 +14,7 @@ recommended command-line parsing module in the Python standard library.
.. note::
There are two other modules that fulfill the same task, namely
- :mod:`getopt` (an equivalent for :c:func:`getopt` from the C
+ :mod:`getopt` (an equivalent for ``getopt()`` from the C
language) and the deprecated :mod:`optparse`.
Note also that :mod:`argparse` is based on :mod:`optparse`,
and therefore very similar in terms of usage.
@@ -137,13 +139,13 @@ And running the code:
Here is what's happening:
-* We've added the :meth:`add_argument` method, which is what we use to specify
+* We've added the :meth:`~ArgumentParser.add_argument` method, which is what we use to specify
which command-line options the program is willing to accept. In this case,
I've named it ``echo`` so that it's in line with its function.
* Calling our program now requires us to specify an option.
-* The :meth:`parse_args` method actually returns some data from the
+* The :meth:`~ArgumentParser.parse_args` method actually returns some data from the
options specified, in this case, ``echo``.
* The variable is some form of 'magic' that :mod:`argparse` performs for free
@@ -256,7 +258,7 @@ Here is what is happening:
* To show that the option is actually optional, there is no error when running
the program without it. Note that by default, if an optional argument isn't
- used, the relevant variable, in this case :attr:`args.verbosity`, is
+ used, the relevant variable, in this case ``args.verbosity``, is
given ``None`` as a value, which is the reason it fails the truth
test of the :keyword:`if` statement.
@@ -299,7 +301,7 @@ Here is what is happening:
We even changed the name of the option to match that idea.
Note that we now specify a new keyword, ``action``, and give it the value
``"store_true"``. This means that, if the option is specified,
- assign the value ``True`` to :data:`args.verbose`.
+ assign the value ``True`` to ``args.verbose``.
Not specifying it implies ``False``.
* It complains when you specify a value, in true spirit of what flags
@@ -698,7 +700,7 @@ Conflicting options
So far, we have been working with two methods of an
:class:`argparse.ArgumentParser` instance. Let's introduce a third one,
-:meth:`add_mutually_exclusive_group`. It allows for us to specify options that
+:meth:`~ArgumentParser.add_mutually_exclusive_group`. It allows for us to specify options that
conflict with each other. Let's also change the rest of the program so that
the new functionality makes more sense:
we'll introduce the ``--quiet`` option,
diff --git a/Doc/howto/descriptor.rst b/Doc/howto/descriptor.rst
index 74710d9b3fc2ed..3688c47f0d6ec9 100644
--- a/Doc/howto/descriptor.rst
+++ b/Doc/howto/descriptor.rst
@@ -1273,11 +1273,14 @@ Using the non-data descriptor protocol, a pure Python version of
.. testcode::
+ import functools
+
class StaticMethod:
"Emulate PyStaticMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
+ functools.update_wrapper(self, f)
def __get__(self, obj, objtype=None):
return self.f
@@ -1285,13 +1288,19 @@ Using the non-data descriptor protocol, a pure Python version of
def __call__(self, *args, **kwds):
return self.f(*args, **kwds)
+The :func:`functools.update_wrapper` call adds a ``__wrapped__`` attribute
+that refers to the underlying function. Also it carries forward
+the attributes necessary to make the wrapper look like the wrapped
+function: ``__name__``, ``__qualname__``, ``__doc__``, and ``__annotations__``.
+
.. testcode::
:hide:
class E_sim:
@StaticMethod
- def f(x):
- return x * 10
+ def f(x: int) -> str:
+ "Simple function example"
+ return "!" * x
wrapped_ord = StaticMethod(ord)
@@ -1299,11 +1308,51 @@ Using the non-data descriptor protocol, a pure Python version of
:hide:
>>> E_sim.f(3)
- 30
+ '!!!'
>>> E_sim().f(3)
- 30
+ '!!!'
+
+ >>> sm = vars(E_sim)['f']
+ >>> type(sm).__name__
+ 'StaticMethod'
+ >>> f = E_sim.f
+ >>> type(f).__name__
+ 'function'
+ >>> sm.__name__
+ 'f'
+ >>> f.__name__
+ 'f'
+ >>> sm.__qualname__
+ 'E_sim.f'
+ >>> f.__qualname__
+ 'E_sim.f'
+ >>> sm.__doc__
+ 'Simple function example'
+ >>> f.__doc__
+ 'Simple function example'
+ >>> sm.__annotations__
+ {'x': , 'return': }
+ >>> f.__annotations__
+ {'x': , 'return': }
+ >>> sm.__module__ == f.__module__
+ True
+ >>> sm(3)
+ '!!!'
+ >>> f(3)
+ '!!!'
+
>>> wrapped_ord('A')
65
+ >>> wrapped_ord.__module__ == ord.__module__
+ True
+ >>> wrapped_ord.__wrapped__ == ord
+ True
+ >>> wrapped_ord.__name__ == ord.__name__
+ True
+ >>> wrapped_ord.__qualname__ == ord.__qualname__
+ True
+ >>> wrapped_ord.__doc__ == ord.__doc__
+ True
Class methods
@@ -1359,11 +1408,14 @@ Using the non-data descriptor protocol, a pure Python version of
.. testcode::
+ import functools
+
class ClassMethod:
"Emulate PyClassMethod_Type() in Objects/funcobject.c"
def __init__(self, f):
self.f = f
+ functools.update_wrapper(self, f)
def __get__(self, obj, cls=None):
if cls is None:
@@ -1380,8 +1432,9 @@ Using the non-data descriptor protocol, a pure Python version of
# Verify the emulation works
class T:
@ClassMethod
- def cm(cls, x, y):
- return (cls, x, y)
+ def cm(cls, x: int, y: str) -> tuple[str, int, str]:
+ "Class method that returns a tuple"
+ return (cls.__name__, x, y)
@ClassMethod
@property
@@ -1393,17 +1446,40 @@ Using the non-data descriptor protocol, a pure Python version of
:hide:
>>> T.cm(11, 22)
- (, 11, 22)
+ ('T', 11, 22)
# Also call it from an instance
>>> t = T()
>>> t.cm(11, 22)
- (, 11, 22)
+ ('T', 11, 22)
# Check the alternate path for chained descriptors
>>> T.__doc__
"A doc for 'T'"
+ # Verify that T uses our emulation
+ >>> type(vars(T)['cm']).__name__
+ 'ClassMethod'
+
+ # Verify that update_wrapper() correctly copied attributes
+ >>> T.cm.__name__
+ 'cm'
+ >>> T.cm.__qualname__
+ 'T.cm'
+ >>> T.cm.__doc__
+ 'Class method that returns a tuple'
+ >>> T.cm.__annotations__
+ {'x': , 'y': , 'return': tuple[str, int, str]}
+
+ # Verify that __wrapped__ was added and works correctly
+ >>> f = vars(T)['cm'].__wrapped__
+ >>> type(f).__name__
+ 'function'
+ >>> f.__name__
+ 'cm'
+ >>> f(T, 11, 22)
+ ('T', 11, 22)
+
The code path for ``hasattr(type(self.f), '__get__')`` was added in
Python 3.9 and makes it possible for :func:`classmethod` to support
@@ -1423,6 +1499,12 @@ chained together. In Python 3.11, this functionality was deprecated.
>>> G.__doc__
"A doc for 'G'"
+The :func:`functools.update_wrapper` call in ``ClassMethod`` adds a
+``__wrapped__`` attribute that refers to the underlying function. Also
+it carries forward the attributes necessary to make the wrapper look
+like the wrapped function: ``__name__``, ``__qualname__``, ``__doc__``,
+and ``__annotations__``.
+
Member objects and __slots__
----------------------------
diff --git a/Doc/howto/enum.rst b/Doc/howto/enum.rst
index 9390faded2fb8d..68b75c529e92c7 100644
--- a/Doc/howto/enum.rst
+++ b/Doc/howto/enum.rst
@@ -36,8 +36,10 @@ inherits from :class:`Enum` itself.
.. note:: Case of Enum Members
- Because Enums are used to represent constants we recommend using
- UPPER_CASE names for members, and will be using that style in our examples.
+ Because Enums are used to represent constants, and to help avoid issues
+ with name clashes between mixin-class methods/attributes and enum names,
+ we strongly recommend using UPPER_CASE names for members, and will be using
+ that style in our examples.
Depending on the nature of the enum a member's value may or may not be
important, but either way that value can be used to get the corresponding
@@ -490,6 +492,10 @@ the :meth:`~Enum.__repr__` omits the inherited class' name. For example::
Use the :func:`!dataclass` argument ``repr=False``
to use the standard :func:`repr`.
+.. versionchanged:: 3.12
+ Only the dataclass fields are shown in the value area, not the dataclass'
+ name.
+
Pickling
--------
@@ -865,17 +871,19 @@ Some rules:
4. When another data type is mixed in, the :attr:`value` attribute is *not the
same* as the enum member itself, although it is equivalent and will compare
equal.
-5. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's
+5. A ``data type`` is a mixin that defines :meth:`__new__`, or a
+ :class:`~dataclasses.dataclass`
+6. %-style formatting: ``%s`` and ``%r`` call the :class:`Enum` class's
:meth:`__str__` and :meth:`__repr__` respectively; other codes (such as
``%i`` or ``%h`` for IntEnum) treat the enum member as its mixed-in type.
-6. :ref:`Formatted string literals `, :meth:`str.format`,
+7. :ref:`Formatted string literals `, :meth:`str.format`,
and :func:`format` will use the enum's :meth:`__str__` method.
.. note::
Because :class:`IntEnum`, :class:`IntFlag`, and :class:`StrEnum` are
designed to be drop-in replacements for existing constants, their
- :meth:`__str__` method has been reset to their data types
+ :meth:`__str__` method has been reset to their data types'
:meth:`__str__` method.
When to use :meth:`__new__` vs. :meth:`__init__`
@@ -990,7 +998,9 @@ but remain normal attributes.
Enum members are instances of their enum class, and are normally accessed as
``EnumClass.member``. In certain situations, such as writing custom enum
behavior, being able to access one member directly from another is useful,
-and is supported.
+and is supported; however, in order to avoid name clashes between member names
+and attributes/methods from mixed-in classes, upper-case names are strongly
+recommended.
.. versionchanged:: 3.5
diff --git a/Doc/howto/functional.rst b/Doc/howto/functional.rst
index 38a651b0f964a6..5cf12cc52bde4e 100644
--- a/Doc/howto/functional.rst
+++ b/Doc/howto/functional.rst
@@ -1208,8 +1208,8 @@ General
-------
**Structure and Interpretation of Computer Programs**, by Harold Abelson and
-Gerald Jay Sussman with Julie Sussman. Full text at
-https://mitpress.mit.edu/sicp/. In this classic textbook of computer science,
+Gerald Jay Sussman with Julie Sussman. The book can be found at
+https://mitpress.mit.edu/sicp. In this classic textbook of computer science,
chapters 2 and 3 discuss the use of sequences and streams to organize the data
flow inside a program. The book uses Scheme for its examples, but many of the
design approaches described in these chapters are applicable to functional-style
diff --git a/Doc/howto/isolating-extensions.rst b/Doc/howto/isolating-extensions.rst
index 2eddb582da7c24..0262054ae2b4a0 100644
--- a/Doc/howto/isolating-extensions.rst
+++ b/Doc/howto/isolating-extensions.rst
@@ -372,7 +372,7 @@ To save a some tedious error-handling boilerplate code, you can combine
these two steps with :c:func:`PyType_GetModuleState`, resulting in::
my_struct *state = (my_struct*)PyType_GetModuleState(type);
- if (state === NULL) {
+ if (state == NULL) {
return NULL;
}
@@ -435,7 +435,7 @@ For example::
PyObject *kwnames)
{
my_struct *state = (my_struct*)PyType_GetModuleState(defining_class);
- if (state === NULL) {
+ if (state == NULL) {
return NULL;
}
... // rest of logic
@@ -479,7 +479,7 @@ to get the state::
PyObject *module = PyType_GetModuleByDef(Py_TYPE(self), &module_def);
my_struct *state = (my_struct*)PyModule_GetState(module);
- if (state === NULL) {
+ if (state == NULL) {
return NULL;
}
diff --git a/Doc/howto/perf_profiling.rst b/Doc/howto/perf_profiling.rst
index ad2eb7b4d58aa5..6af5536166f58a 100644
--- a/Doc/howto/perf_profiling.rst
+++ b/Doc/howto/perf_profiling.rst
@@ -15,9 +15,9 @@ information about the performance of your application.
that aid with the analysis of the data that it produces.
The main problem with using the ``perf`` profiler with Python applications is that
-``perf`` only allows to get information about native symbols, this is, the names of
-the functions and procedures written in C. This means that the names and file names
-of the Python functions in your code will not appear in the output of the ``perf``.
+``perf`` only gets information about native symbols, that is, the names of
+functions and procedures written in C. This means that the names and file names
+of Python functions in your code will not appear in the output of ``perf``.
Since Python 3.12, the interpreter can run in a special mode that allows Python
functions to appear in the output of the ``perf`` profiler. When this mode is
@@ -28,8 +28,8 @@ relationship between this piece of code and the associated Python function using
.. note::
- Support for the ``perf`` profiler is only currently available for Linux on
- selected architectures. Check the output of the configure build step or
+ Support for the ``perf`` profiler is currently only available for Linux on
+ select architectures. Check the output of the ``configure`` build step or
check the output of ``python -m sysconfig | grep HAVE_PERF_TRAMPOLINE``
to see if your system is supported.
@@ -52,11 +52,11 @@ For example, consider the following script:
if __name__ == "__main__":
baz(1000000)
-We can run ``perf`` to sample CPU stack traces at 9999 Hertz::
+We can run ``perf`` to sample CPU stack traces at 9999 hertz::
$ perf record -F 9999 -g -o perf.data python my_script.py
-Then we can use ``perf`` report to analyze the data:
+Then we can use ``perf report`` to analyze the data:
.. code-block:: shell-session
@@ -97,7 +97,7 @@ Then we can use ``perf`` report to analyze the data:
| | | | | |--2.97%--_PyObject_Malloc
...
-As you can see here, the Python functions are not shown in the output, only ``_Py_Eval_EvalFrameDefault`` appears
+As you can see, the Python functions are not shown in the output, only ``_Py_Eval_EvalFrameDefault``
(the function that evaluates the Python bytecode) shows up. Unfortunately that's not very useful because all Python
functions use the same C function to evaluate bytecode so we cannot know which Python function corresponds to which
bytecode-evaluating function.
@@ -151,7 +151,7 @@ Instead, if we run the same experiment with ``perf`` support enabled we get:
How to enable ``perf`` profiling support
----------------------------------------
-``perf`` profiling support can either be enabled from the start using
+``perf`` profiling support can be enabled either from the start using
the environment variable :envvar:`PYTHONPERFSUPPORT` or the
:option:`-X perf <-X>` option,
or dynamically using :func:`sys.activate_stack_trampoline` and
@@ -192,7 +192,7 @@ Example, using the :mod:`sys` APIs in file :file:`example.py`:
How to obtain the best results
------------------------------
-For the best results, Python should be compiled with
+For best results, Python should be compiled with
``CFLAGS="-fno-omit-frame-pointer -mno-omit-leaf-frame-pointer"`` as this allows
profilers to unwind using only the frame pointer and not on DWARF debug
information. This is because as the code that is interposed to allow ``perf``
diff --git a/Doc/howto/urllib2.rst b/Doc/howto/urllib2.rst
index 69af3c3a85c5d6..61ba6bd7224fcc 100644
--- a/Doc/howto/urllib2.rst
+++ b/Doc/howto/urllib2.rst
@@ -86,7 +86,7 @@ response::
import urllib.request
- req = urllib.request.Request('http://www.voidspace.org.uk')
+ req = urllib.request.Request('http://python.org/')
with urllib.request.urlopen(req) as response:
the_page = response.read()
@@ -458,7 +458,7 @@ To illustrate creating and installing a handler we will use the
``HTTPBasicAuthHandler``. For a more detailed discussion of this subject --
including an explanation of how Basic Authentication works - see the `Basic
Authentication Tutorial
-`_.
+`__.
When authentication is required, the server sends a header (as well as the 401
error code) requesting authentication. This specifies the authentication scheme
diff --git a/Doc/library/argparse.rst b/Doc/library/argparse.rst
index ee68ac58d3de75..33e367f3ccda89 100644
--- a/Doc/library/argparse.rst
+++ b/Doc/library/argparse.rst
@@ -67,7 +67,7 @@ default_ Default value used when an argument is not provided
dest_ Specify the attribute name used in the result namespace
help_ Help message for an argument
metavar_ Alternate display name for the argument as shown in help
-nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, ``'+'``, or ``argparse.REMAINDER``
+nargs_ Number of times the argument can be used :class:`int`, ``'?'``, ``'*'``, or ``'+'``
required_ Indicate whether an argument is required or optional ``True`` or ``False``
type_ Automatically convert an argument to the given type :class:`int`, :class:`float`, ``argparse.FileType('w')``, or callable function
====================== =========================================================== ==========================================================================================================================
@@ -585,7 +585,7 @@ arguments will never be treated as file references.
.. versionchanged:: 3.12
:class:`ArgumentParser` changed encoding and errors to read arguments files
- from default (e.g. :func:`locale.getpreferredencoding(False)` and
+ from default (e.g. :func:`locale.getpreferredencoding(False) ` and
``"strict"``) to :term:`filesystem encoding and error handler`.
Arguments file should be encoded in UTF-8 instead of ANSI Codepage on Windows.
@@ -1191,7 +1191,7 @@ done downstream after the arguments are parsed.
For example, JSON or YAML conversions have complex error cases that require
better reporting than can be given by the ``type`` keyword. A
:exc:`~json.JSONDecodeError` would not be well formatted and a
-:exc:`FileNotFound` exception would not be handled at all.
+:exc:`FileNotFoundError` exception would not be handled at all.
Even :class:`~argparse.FileType` has its limitations for use with the ``type``
keyword. If one argument uses *FileType* and then a subsequent argument fails,
@@ -1445,7 +1445,7 @@ Action classes
Action classes implement the Action API, a callable which returns a callable
which processes arguments from the command-line. Any object which follows
this API may be passed as the ``action`` parameter to
-:meth:`add_argument`.
+:meth:`~ArgumentParser.add_argument`.
.. class:: Action(option_strings, dest, nargs=None, const=None, default=None, \
type=None, choices=None, required=False, help=None, \
@@ -1723,7 +1723,7 @@ Sub-commands
:class:`ArgumentParser` supports the creation of such sub-commands with the
:meth:`add_subparsers` method. The :meth:`add_subparsers` method is normally
called with no arguments and returns a special action object. This object
- has a single method, :meth:`~ArgumentParser.add_parser`, which takes a
+ has a single method, :meth:`~_SubParsersAction.add_parser`, which takes a
command name and any :class:`ArgumentParser` constructor arguments, and
returns an :class:`ArgumentParser` object that can be modified as usual.
@@ -1789,7 +1789,7 @@ Sub-commands
for that particular parser will be printed. The help message will not
include parent parser or sibling parser messages. (A help message for each
subparser command, however, can be given by supplying the ``help=`` argument
- to :meth:`add_parser` as above.)
+ to :meth:`~_SubParsersAction.add_parser` as above.)
::
@@ -2157,7 +2157,7 @@ the populated namespace and the list of remaining argument strings.
.. warning::
:ref:`Prefix matching ` rules apply to
- :meth:`parse_known_args`. The parser may consume an option even if it's just
+ :meth:`~ArgumentParser.parse_known_args`. The parser may consume an option even if it's just
a prefix of one of its known options, instead of leaving it in the remaining
arguments list.
@@ -2218,7 +2218,7 @@ support this parsing style.
These parsers do not support all the argparse features, and will raise
exceptions if unsupported features are used. In particular, subparsers,
-``argparse.REMAINDER``, and mutually exclusive groups that include both
+and mutually exclusive groups that include both
optionals and positionals are not supported.
The following example shows the difference between
@@ -2295,3 +2295,17 @@ A partial upgrade path from :mod:`optparse` to :mod:`argparse`:
* Replace the OptionParser constructor ``version`` argument with a call to
``parser.add_argument('--version', action='version', version='')``.
+
+Exceptions
+----------
+
+.. exception:: ArgumentError
+
+ An error from creating or using an argument (optional or positional).
+
+ The string value of this exception is the message, augmented with
+ information about the argument that caused it.
+
+.. exception:: ArgumentTypeError
+
+ Raised when something goes wrong converting a command line string to a type.
diff --git a/Doc/library/asyncio-task.rst b/Doc/library/asyncio-task.rst
index 41d09e1e79705c..ba0f909c405a34 100644
--- a/Doc/library/asyncio-task.rst
+++ b/Doc/library/asyncio-task.rst
@@ -256,8 +256,9 @@ Creating Tasks
.. note::
- :meth:`asyncio.TaskGroup.create_task` is a newer alternative
- that allows for convenient waiting for a group of related tasks.
+ :meth:`asyncio.TaskGroup.create_task` is a new alternative
+ leveraging structural concurrency; it allows for waiting
+ for a group of related tasks with strong safety guarantees.
.. important::
@@ -340,7 +341,7 @@ Example::
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(some_coro(...))
task2 = tg.create_task(another_coro(...))
- print("Both tasks have completed now.")
+ print(f"Both tasks have completed now: {task1.result()}, {task2.result()}")
The ``async with`` statement will wait for all tasks in the group to finish.
While waiting, new tasks may still be added to the group
@@ -459,8 +460,12 @@ Running Tasks Concurrently
Tasks/Futures to be cancelled.
.. note::
- A more modern way to create and run tasks concurrently and
- wait for their completion is :class:`asyncio.TaskGroup`.
+ A new alternative to create and run tasks concurrently and
+ wait for their completion is :class:`asyncio.TaskGroup`. *TaskGroup*
+ provides stronger safety guarantees than *gather* for scheduling a nesting of subtasks:
+ if a task (or a subtask, a task scheduled by a task)
+ raises an exception, *TaskGroup* will, while *gather* will not,
+ cancel the remaining scheduled tasks).
.. _asyncio_example_gather:
@@ -829,6 +834,9 @@ Waiting Primitives
Deprecation warning is emitted if not all awaitable objects in the *aws*
iterable are Future-like objects and there is no running event loop.
+ .. versionchanged:: 3.12
+ Added support for generators yielding tasks.
+
Running in Threads
==================
diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst
index 1b55868c3aa62f..7cd081d1f54f43 100644
--- a/Doc/library/contextlib.rst
+++ b/Doc/library/contextlib.rst
@@ -304,8 +304,15 @@ Functions and classes provided:
This context manager is :ref:`reentrant `.
+ If the code within the :keyword:`!with` block raises an
+ :exc:`ExceptionGroup`, suppressed exceptions are removed from the
+ group. If any exceptions in the group are not suppressed, a group containing them is re-raised.
+
.. versionadded:: 3.4
+ .. versionchanged:: 3.12
+ ``suppress`` now supports suppressing exceptions raised as
+ part of an :exc:`ExceptionGroup`.
.. function:: redirect_stdout(new_target)
diff --git a/Doc/library/copyreg.rst b/Doc/library/copyreg.rst
index 866b180f4bc3b8..2107215c0c1967 100644
--- a/Doc/library/copyreg.rst
+++ b/Doc/library/copyreg.rst
@@ -28,8 +28,8 @@ Such constructors may be factory functions or class instances.
.. function:: pickle(type, function, constructor_ob=None)
Declares that *function* should be used as a "reduction" function for objects
- of type *type*. *function* should return either a string or a tuple
- containing two or three elements. See the :attr:`~pickle.Pickler.dispatch_table`
+ of type *type*. *function* must return either a string or a tuple
+ containing two or five elements. See the :attr:`~pickle.Pickler.dispatch_table`
for more details on the interface of *function*.
The *constructor_ob* parameter is a legacy feature and is now ignored, but if
diff --git a/Doc/library/csv.rst b/Doc/library/csv.rst
index f1776554d8b9f2..64baa69be4af31 100644
--- a/Doc/library/csv.rst
+++ b/Doc/library/csv.rst
@@ -327,7 +327,7 @@ The :mod:`csv` module defines the following constants:
Instructs :class:`writer` objects to quote all non-numeric fields.
- Instructs the reader to convert all non-quoted fields to type *float*.
+ Instructs :class:`reader` objects to convert all non-quoted fields to type *float*.
.. data:: QUOTE_NONE
@@ -337,7 +337,25 @@ The :mod:`csv` module defines the following constants:
character. If *escapechar* is not set, the writer will raise :exc:`Error` if
any characters that require escaping are encountered.
- Instructs :class:`reader` to perform no special processing of quote characters.
+ Instructs :class:`reader` objects to perform no special processing of quote characters.
+
+.. data:: QUOTE_NOTNULL
+
+ Instructs :class:`writer` objects to quote all fields which are not
+ ``None``. This is similar to :data:`QUOTE_ALL`, except that if a
+ field value is ``None`` an empty (unquoted) string is written.
+
+ Instructs :class:`reader` objects to interpret an empty (unquoted) field as None and
+ to otherwise behave as :data:`QUOTE_ALL`.
+
+.. data:: QUOTE_STRINGS
+
+ Instructs :class:`writer` objects to always place quotes around fields
+ which are strings. This is similar to :data:`QUOTE_NONNUMERIC`, except that if a
+ field value is ``None`` an empty (unquoted) string is written.
+
+ Instructs :class:`reader` objects to interpret an empty (unquoted) string as ``None`` and
+ to otherwise behave as :data:`QUOTE_NONNUMERIC`.
The :mod:`csv` module defines the following exception:
diff --git a/Doc/library/ctypes.rst b/Doc/library/ctypes.rst
index d49d702e9e7999..81509c0920bb6e 100644
--- a/Doc/library/ctypes.rst
+++ b/Doc/library/ctypes.rst
@@ -390,7 +390,7 @@ regular, non-variadic, function arguments:
libc.printf.argtypes = [ctypes.c_char_p]
-Because specifying the attribute does inhibit portability it is advised to always
+Because specifying the attribute does not inhibit portability it is advised to always
specify ``argtypes`` for all variadic functions.
diff --git a/Doc/library/dataclasses.rst b/Doc/library/dataclasses.rst
index 5f4dc25bfd7877..85a7d9026d1d30 100644
--- a/Doc/library/dataclasses.rst
+++ b/Doc/library/dataclasses.rst
@@ -12,8 +12,8 @@
--------------
This module provides a decorator and functions for automatically
-adding generated :term:`special method`\s such as :meth:`__init__` and
-:meth:`__repr__` to user-defined classes. It was originally described
+adding generated :term:`special method`\s such as :meth:`~object.__init__` and
+:meth:`~object.__repr__` to user-defined classes. It was originally described
in :pep:`557`.
The member variables to use in these generated methods are defined
@@ -31,7 +31,7 @@ using :pep:`526` type annotations. For example, this code::
def total_cost(self) -> float:
return self.unit_price * self.quantity_on_hand
-will add, among other things, a :meth:`__init__` that looks like::
+will add, among other things, a :meth:`~object.__init__` that looks like::
def __init__(self, name: str, unit_price: float, quantity_on_hand: int = 0):
self.name = name
@@ -86,86 +86,86 @@ Module contents
The parameters to :func:`dataclass` are:
- - ``init``: If true (the default), a :meth:`__init__` method will be
+ - ``init``: If true (the default), a :meth:`~object.__init__` method will be
generated.
- If the class already defines :meth:`__init__`, this parameter is
+ If the class already defines :meth:`~object.__init__`, this parameter is
ignored.
- - ``repr``: If true (the default), a :meth:`__repr__` method will be
+ - ``repr``: If true (the default), a :meth:`~object.__repr__` method will be
generated. The generated repr string will have the class name and
the name and repr of each field, in the order they are defined in
the class. Fields that are marked as being excluded from the repr
are not included. For example:
``InventoryItem(name='widget', unit_price=3.0, quantity_on_hand=10)``.
- If the class already defines :meth:`__repr__`, this parameter is
+ If the class already defines :meth:`~object.__repr__`, this parameter is
ignored.
- - ``eq``: If true (the default), an :meth:`__eq__` method will be
+ - ``eq``: If true (the default), an :meth:`~object.__eq__` method will be
generated. This method compares the class as if it were a tuple
of its fields, in order. Both instances in the comparison must
be of the identical type.
- If the class already defines :meth:`__eq__`, this parameter is
+ If the class already defines :meth:`~object.__eq__`, this parameter is
ignored.
- - ``order``: If true (the default is ``False``), :meth:`__lt__`,
- :meth:`__le__`, :meth:`__gt__`, and :meth:`__ge__` methods will be
+ - ``order``: If true (the default is ``False``), :meth:`~object.__lt__`,
+ :meth:`~object.__le__`, :meth:`~object.__gt__`, and :meth:`~object.__ge__` methods will be
generated. These compare the class as if it were a tuple of its
fields, in order. Both instances in the comparison must be of the
identical type. If ``order`` is true and ``eq`` is false, a
:exc:`ValueError` is raised.
- If the class already defines any of :meth:`__lt__`,
- :meth:`__le__`, :meth:`__gt__`, or :meth:`__ge__`, then
+ If the class already defines any of :meth:`~object.__lt__`,
+ :meth:`~object.__le__`, :meth:`~object.__gt__`, or :meth:`~object.__ge__`, then
:exc:`TypeError` is raised.
- - ``unsafe_hash``: If ``False`` (the default), a :meth:`__hash__` method
+ - ``unsafe_hash``: If ``False`` (the default), a :meth:`~object.__hash__` method
is generated according to how ``eq`` and ``frozen`` are set.
- :meth:`__hash__` is used by built-in :meth:`hash()`, and when objects are
+ :meth:`~object.__hash__` is used by built-in :meth:`hash()`, and when objects are
added to hashed collections such as dictionaries and sets. Having a
- :meth:`__hash__` implies that instances of the class are immutable.
+ :meth:`~object.__hash__` implies that instances of the class are immutable.
Mutability is a complicated property that depends on the programmer's
- intent, the existence and behavior of :meth:`__eq__`, and the values of
+ intent, the existence and behavior of :meth:`~object.__eq__`, and the values of
the ``eq`` and ``frozen`` flags in the :func:`dataclass` decorator.
- By default, :func:`dataclass` will not implicitly add a :meth:`__hash__`
+ By default, :func:`dataclass` will not implicitly add a :meth:`~object.__hash__`
method unless it is safe to do so. Neither will it add or change an
- existing explicitly defined :meth:`__hash__` method. Setting the class
+ existing explicitly defined :meth:`~object.__hash__` method. Setting the class
attribute ``__hash__ = None`` has a specific meaning to Python, as
- described in the :meth:`__hash__` documentation.
+ described in the :meth:`~object.__hash__` documentation.
- If :meth:`__hash__` is not explicitly defined, or if it is set to ``None``,
- then :func:`dataclass` *may* add an implicit :meth:`__hash__` method.
+ If :meth:`~object.__hash__` is not explicitly defined, or if it is set to ``None``,
+ then :func:`dataclass` *may* add an implicit :meth:`~object.__hash__` method.
Although not recommended, you can force :func:`dataclass` to create a
- :meth:`__hash__` method with ``unsafe_hash=True``. This might be the case
+ :meth:`~object.__hash__` method with ``unsafe_hash=True``. This might be the case
if your class is logically immutable but can nonetheless be mutated.
This is a specialized use case and should be considered carefully.
- Here are the rules governing implicit creation of a :meth:`__hash__`
- method. Note that you cannot both have an explicit :meth:`__hash__`
+ Here are the rules governing implicit creation of a :meth:`~object.__hash__`
+ method. Note that you cannot both have an explicit :meth:`~object.__hash__`
method in your dataclass and set ``unsafe_hash=True``; this will result
in a :exc:`TypeError`.
If ``eq`` and ``frozen`` are both true, by default :func:`dataclass` will
- generate a :meth:`__hash__` method for you. If ``eq`` is true and
- ``frozen`` is false, :meth:`__hash__` will be set to ``None``, marking it
+ generate a :meth:`~object.__hash__` method for you. If ``eq`` is true and
+ ``frozen`` is false, :meth:`~object.__hash__` will be set to ``None``, marking it
unhashable (which it is, since it is mutable). If ``eq`` is false,
- :meth:`__hash__` will be left untouched meaning the :meth:`__hash__`
+ :meth:`~object.__hash__` will be left untouched meaning the :meth:`~object.__hash__`
method of the superclass will be used (if the superclass is
:class:`object`, this means it will fall back to id-based hashing).
- ``frozen``: If true (the default is ``False``), assigning to fields will
generate an exception. This emulates read-only frozen instances. If
- :meth:`__setattr__` or :meth:`__delattr__` is defined in the class, then
+ :meth:`~object.__setattr__` or :meth:`~object.__delattr__` is defined in the class, then
:exc:`TypeError` is raised. See the discussion below.
- ``match_args``: If true (the default is ``True``), the
``__match_args__`` tuple will be created from the list of
- parameters to the generated :meth:`__init__` method (even if
- :meth:`__init__` is not generated, see above). If false, or if
+ parameters to the generated :meth:`~object.__init__` method (even if
+ :meth:`~object.__init__` is not generated, see above). If false, or if
``__match_args__`` is already defined in the class, then
``__match_args__`` will not be generated.
@@ -173,18 +173,18 @@ Module contents
- ``kw_only``: If true (the default value is ``False``), then all
fields will be marked as keyword-only. If a field is marked as
- keyword-only, then the only effect is that the :meth:`__init__`
+ keyword-only, then the only effect is that the :meth:`~object.__init__`
parameter generated from a keyword-only field must be specified
- with a keyword when :meth:`__init__` is called. There is no
+ with a keyword when :meth:`~object.__init__` is called. There is no
effect on any other aspect of dataclasses. See the
:term:`parameter` glossary entry for details. Also see the
:const:`KW_ONLY` section.
.. versionadded:: 3.10
- - ``slots``: If true (the default is ``False``), :attr:`__slots__` attribute
+ - ``slots``: If true (the default is ``False``), :attr:`~object.__slots__` attribute
will be generated and new class will be returned instead of the original one.
- If :attr:`__slots__` is already defined in the class, then :exc:`TypeError`
+ If :attr:`~object.__slots__` is already defined in the class, then :exc:`TypeError`
is raised.
.. versionadded:: 3.10
@@ -215,7 +215,7 @@ Module contents
b: int = 0 # assign a default value for 'b'
In this example, both ``a`` and ``b`` will be included in the added
- :meth:`__init__` method, which will be defined as::
+ :meth:`~object.__init__` method, which will be defined as::
def __init__(self, a: int, b: int = 0):
@@ -256,13 +256,13 @@ Module contents
error to specify both ``default`` and ``default_factory``.
- ``init``: If true (the default), this field is included as a
- parameter to the generated :meth:`__init__` method.
+ parameter to the generated :meth:`~object.__init__` method.
- ``repr``: If true (the default), this field is included in the
- string returned by the generated :meth:`__repr__` method.
+ string returned by the generated :meth:`~object.__repr__` method.
- ``hash``: This can be a bool or ``None``. If true, this field is
- included in the generated :meth:`__hash__` method. If ``None`` (the
+ included in the generated :meth:`~object.__hash__` method. If ``None`` (the
default), use the value of ``compare``: this would normally be
the expected behavior. A field should be considered in the hash
if it's used for comparisons. Setting this value to anything
@@ -275,8 +275,8 @@ Module contents
is excluded from the hash, it will still be used for comparisons.
- ``compare``: If true (the default), this field is included in the
- generated equality and comparison methods (:meth:`__eq__`,
- :meth:`__gt__`, et al.).
+ generated equality and comparison methods (:meth:`~object.__eq__`,
+ :meth:`~object.__gt__`, et al.).
- ``metadata``: This can be a mapping or None. None is treated as
an empty dict. This value is wrapped in
@@ -287,7 +287,7 @@ Module contents
namespace in the metadata.
- ``kw_only``: If true, this field will be marked as keyword-only.
- This is used when the generated :meth:`__init__` method's
+ This is used when the generated :meth:`~object.__init__` method's
parameters are computed.
.. versionadded:: 3.10
@@ -435,13 +435,13 @@ Module contents
Class, raises :exc:`TypeError`. If values in ``changes`` do not
specify fields, raises :exc:`TypeError`.
- The newly returned object is created by calling the :meth:`__init__`
+ The newly returned object is created by calling the :meth:`~object.__init__`
method of the dataclass. This ensures that
- :meth:`__post_init__`, if present, is also called.
+ :ref:`__post_init__ `, if present, is also called.
Init-only variables without default values, if any exist, must be
specified on the call to :func:`replace` so that they can be passed to
- :meth:`__init__` and :meth:`__post_init__`.
+ :meth:`~object.__init__` and :ref:`__post_init__ `.
It is an error for ``changes`` to contain any fields that are
defined as having ``init=False``. A :exc:`ValueError` will be raised
@@ -449,7 +449,7 @@ Module contents
Be forewarned about how ``init=False`` fields work during a call to
:func:`replace`. They are not copied from the source object, but
- rather are initialized in :meth:`__post_init__`, if they're
+ rather are initialized in :ref:`__post_init__ `, if they're
initialized at all. It is expected that ``init=False`` fields will
be rarely and judiciously used. If they are used, it might be wise
to have alternate class constructors, or perhaps a custom
@@ -480,7 +480,7 @@ Module contents
:const:`KW_ONLY` is otherwise completely ignored. This includes the
name of such a field. By convention, a name of ``_`` is used for a
:const:`KW_ONLY` field. Keyword-only fields signify
- :meth:`__init__` parameters that must be specified as keywords when
+ :meth:`~object.__init__` parameters that must be specified as keywords when
the class is instantiated.
In this example, the fields ``y`` and ``z`` will be marked as keyword-only fields::
@@ -501,20 +501,22 @@ Module contents
.. exception:: FrozenInstanceError
- Raised when an implicitly defined :meth:`__setattr__` or
- :meth:`__delattr__` is called on a dataclass which was defined with
+ Raised when an implicitly defined :meth:`~object.__setattr__` or
+ :meth:`~object.__delattr__` is called on a dataclass which was defined with
``frozen=True``. It is a subclass of :exc:`AttributeError`.
+.. _post-init-processing:
+
Post-init processing
--------------------
-The generated :meth:`__init__` code will call a method named
-:meth:`__post_init__`, if :meth:`__post_init__` is defined on the
+The generated :meth:`~object.__init__` code will call a method named
+:meth:`!__post_init__`, if :meth:`!__post_init__` is defined on the
class. It will normally be called as ``self.__post_init__()``.
However, if any ``InitVar`` fields are defined, they will also be
-passed to :meth:`__post_init__` in the order they were defined in the
-class. If no :meth:`__init__` method is generated, then
-:meth:`__post_init__` will not automatically be called.
+passed to :meth:`!__post_init__` in the order they were defined in the
+class. If no :meth:`~object.__init__` method is generated, then
+:meth:`!__post_init__` will not automatically be called.
Among other uses, this allows for initializing field values that
depend on one or more other fields. For example::
@@ -528,10 +530,10 @@ depend on one or more other fields. For example::
def __post_init__(self):
self.c = self.a + self.b
-The :meth:`__init__` method generated by :func:`dataclass` does not call base
-class :meth:`__init__` methods. If the base class has an :meth:`__init__` method
+The :meth:`~object.__init__` method generated by :func:`dataclass` does not call base
+class :meth:`~object.__init__` methods. If the base class has an :meth:`~object.__init__` method
that has to be called, it is common to call this method in a
-:meth:`__post_init__` method::
+:meth:`!__post_init__` method::
@dataclass
class Rectangle:
@@ -545,12 +547,12 @@ that has to be called, it is common to call this method in a
def __post_init__(self):
super().__init__(self.side, self.side)
-Note, however, that in general the dataclass-generated :meth:`__init__` methods
+Note, however, that in general the dataclass-generated :meth:`~object.__init__` methods
don't need to be called, since the derived dataclass will take care of
initializing all fields of any base class that is a dataclass itself.
See the section below on init-only variables for ways to pass
-parameters to :meth:`__post_init__`. Also see the warning about how
+parameters to :meth:`!__post_init__`. Also see the warning about how
:func:`replace` handles ``init=False`` fields.
Class variables
@@ -573,8 +575,8 @@ if the type of a field is of type ``dataclasses.InitVar``. If a field
is an ``InitVar``, it is considered a pseudo-field called an init-only
field. As it is not a true field, it is not returned by the
module-level :func:`fields` function. Init-only fields are added as
-parameters to the generated :meth:`__init__` method, and are passed to
-the optional :meth:`__post_init__` method. They are not otherwise used
+parameters to the generated :meth:`~object.__init__` method, and are passed to
+the optional :ref:`__post_init__ ` method. They are not otherwise used
by dataclasses.
For example, suppose a field will be initialized from a database, if a
@@ -601,12 +603,12 @@ Frozen instances
It is not possible to create truly immutable Python objects. However,
by passing ``frozen=True`` to the :meth:`dataclass` decorator you can
emulate immutability. In that case, dataclasses will add
-:meth:`__setattr__` and :meth:`__delattr__` methods to the class. These
+:meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These
methods will raise a :exc:`FrozenInstanceError` when invoked.
There is a tiny performance penalty when using ``frozen=True``:
-:meth:`__init__` cannot use simple assignment to initialize fields, and
-must use :meth:`object.__setattr__`.
+:meth:`~object.__init__` cannot use simple assignment to initialize fields, and
+must use :meth:`~object.__setattr__`.
Inheritance
-----------
@@ -634,14 +636,14 @@ example::
The final list of fields is, in order, ``x``, ``y``, ``z``. The final
type of ``x`` is ``int``, as specified in class ``C``.
-The generated :meth:`__init__` method for ``C`` will look like::
+The generated :meth:`~object.__init__` method for ``C`` will look like::
def __init__(self, x: int = 15, y: int = 0, z: int = 10):
-Re-ordering of keyword-only parameters in :meth:`__init__`
-----------------------------------------------------------
+Re-ordering of keyword-only parameters in :meth:`~object.__init__`
+------------------------------------------------------------------
-After the parameters needed for :meth:`__init__` are computed, any
+After the parameters needed for :meth:`~object.__init__` are computed, any
keyword-only parameters are moved to come after all regular
(non-keyword-only) parameters. This is a requirement of how
keyword-only parameters are implemented in Python: they must come
@@ -662,7 +664,7 @@ fields, and ``Base.x`` and ``D.z`` are regular fields::
z: int = 10
t: int = field(kw_only=True, default=0)
-The generated :meth:`__init__` method for ``D`` will look like::
+The generated :meth:`~object.__init__` method for ``D`` will look like::
def __init__(self, x: Any = 15.0, z: int = 10, *, y: int = 0, w: int = 1, t: int = 0):
@@ -671,7 +673,7 @@ the list of fields: parameters derived from regular fields are
followed by parameters derived from keyword-only fields.
The relative ordering of keyword-only parameters is maintained in the
-re-ordered :meth:`__init__` parameter list.
+re-ordered :meth:`~object.__init__` parameter list.
Default factory functions
@@ -683,10 +685,10 @@ example, to create a new instance of a list, use::
mylist: list = field(default_factory=list)
-If a field is excluded from :meth:`__init__` (using ``init=False``)
+If a field is excluded from :meth:`~object.__init__` (using ``init=False``)
and the field also specifies ``default_factory``, then the default
factory function will always be called from the generated
-:meth:`__init__` function. This happens because there is no other
+:meth:`~object.__init__` function. This happens because there is no other
way to give the field an initial value.
Mutable default values
@@ -714,7 +716,7 @@ Using dataclasses, *if* this code was valid::
@dataclass
class D:
- x: List = []
+ x: list = [] # This code raises ValueError
def add(self, element):
self.x += element
diff --git a/Doc/library/datetime.rst b/Doc/library/datetime.rst
index 761f5f04b9b288..7889dd7d1c3ef0 100644
--- a/Doc/library/datetime.rst
+++ b/Doc/library/datetime.rst
@@ -1043,7 +1043,7 @@ Other constructors, all class methods:
Return a :class:`.datetime` corresponding to *date_string*, parsed according to
*format*.
- This is equivalent to::
+ If *format* does not contain microseconds or timezone information, this is equivalent to::
datetime(*(time.strptime(date_string, format)[0:6]))
@@ -2510,10 +2510,7 @@ Notes:
Because the format depends on the current locale, care should be taken when
making assumptions about the output value. Field orderings will vary (for
example, "month/day/year" versus "day/month/year"), and the output may
- contain Unicode characters encoded using the locale's default encoding (for
- example, if the current locale is ``ja_JP``, the default encoding could be
- any one of ``eucJP``, ``SJIS``, or ``utf-8``; use :meth:`locale.getlocale`
- to determine the current locale's encoding).
+ contain non-ASCII characters.
(2)
The :meth:`strptime` method can parse years in the full [1, 9999] range, but
diff --git a/Doc/library/decimal.rst b/Doc/library/decimal.rst
index 6187098a752053..0b4a4973cb4da0 100644
--- a/Doc/library/decimal.rst
+++ b/Doc/library/decimal.rst
@@ -926,7 +926,7 @@ Each thread has its own current context which is accessed or changed using the
You can also use the :keyword:`with` statement and the :func:`localcontext`
function to temporarily change the active context.
-.. function:: localcontext(ctx=None, \*\*kwargs)
+.. function:: localcontext(ctx=None, **kwargs)
Return a context manager that will set the current context for the active thread
to a copy of *ctx* on entry to the with-statement and restore the previous context
diff --git a/Doc/library/dis.rst b/Doc/library/dis.rst
index 19c08b225ef2bc..3894837127877c 100644
--- a/Doc/library/dis.rst
+++ b/Doc/library/dis.rst
@@ -1036,6 +1036,24 @@ iterations of the loop.
pushed to the stack before the attribute or unbound method respectively.
+.. opcode:: LOAD_SUPER_ATTR (namei)
+
+ This opcode implements :func:`super` (e.g. ``super().method()`` and
+ ``super().attr``). It works the same as :opcode:`LOAD_ATTR`, except that
+ ``namei`` is shifted left by 2 bits instead of 1, and instead of expecting a
+ single receiver on the stack, it expects three objects (from top of stack
+ down): ``self`` (the first argument to the current method), ``cls`` (the
+ class within which the current method was defined), and the global ``super``.
+
+ The low bit of ``namei`` signals to attempt a method load, as with
+ :opcode:`LOAD_ATTR`.
+
+ The second-low bit of ``namei``, if set, means that this was a two-argument
+ call to :func:`super` (unset means zero-argument).
+
+ .. versionadded:: 3.12
+
+
.. opcode:: COMPARE_OP (opname)
Performs a Boolean operation. The operation name can be found in
diff --git a/Doc/library/enum.rst b/Doc/library/enum.rst
index c690c837309ea5..582e06261afd72 100644
--- a/Doc/library/enum.rst
+++ b/Doc/library/enum.rst
@@ -119,7 +119,8 @@ Module Contents
:func:`~enum.property`
Allows :class:`Enum` members to have attributes without conflicting with
- member names.
+ member names. The ``value`` and ``name`` attributes are implemented this
+ way.
:func:`unique`
@@ -169,7 +170,7 @@ Data Types
final *enum*, as well as creating the enum members, properly handling
duplicates, providing iteration over the enum class, etc.
- .. method:: EnumType.__call__(cls, value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)
+ .. method:: EnumType.__call__(cls, value, names=None, \*, module=None, qualname=None, type=None, start=1, boundary=None)
This method is called in two different ways:
@@ -317,7 +318,7 @@ Data Types
>>> PowersOfThree.SECOND.value
9
- .. method:: Enum.__init_subclass__(cls, **kwds)
+ .. method:: Enum.__init_subclass__(cls, \**kwds)
A *classmethod* that is used to further configure subsequent subclasses.
By default, does nothing.
@@ -696,7 +697,8 @@ Data Types
.. attribute:: STRICT
- Out-of-range values cause a :exc:`ValueError` to be raised::
+ Out-of-range values cause a :exc:`ValueError` to be raised. This is the
+ default for :class:`Flag`::
>>> from enum import Flag, STRICT, auto
>>> class StrictFlag(Flag, boundary=STRICT):
@@ -714,7 +716,7 @@ Data Types
.. attribute:: CONFORM
Out-of-range values have invalid values removed, leaving a valid *Flag*
- value. This is the default for :class:`Flag`::
+ value::
>>> from enum import Flag, CONFORM, auto
>>> class ConformFlag(Flag, boundary=CONFORM):
diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 8797485cd05d83..7792e598c1155c 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -1681,7 +1681,7 @@ are always available. They are listed here in alphabetical order.
class C:
@staticmethod
- def f(arg1, arg2, ...): ...
+ def f(arg1, arg2, argN): ...
The ``@staticmethod`` form is a function :term:`decorator` -- see
:ref:`function` for details.
diff --git a/Doc/library/functools.rst b/Doc/library/functools.rst
index d467e50bc7a424..29cbc87bf66d12 100644
--- a/Doc/library/functools.rst
+++ b/Doc/library/functools.rst
@@ -49,8 +49,13 @@ The :mod:`functools` module defines the following functions:
>>> factorial(12) # makes two new recursive calls, the other 10 are cached
479001600
- The cache is threadsafe so the wrapped function can be used in multiple
- threads.
+ The cache is threadsafe so that the wrapped function can be used in
+ multiple threads. This means that the underlying data structure will
+ remain coherent during concurrent updates.
+
+ It is possible for the wrapped function to be called more than once if
+ another thread makes an additional call before the initial call has been
+ completed and cached.
.. versionadded:: 3.9
@@ -118,6 +123,7 @@ The :mod:`functools` module defines the following functions:
def stdev(self):
return statistics.stdev(self._data)
+ .. versionadded:: 3.8
.. versionchanged:: 3.12
Prior to Python 3.12, ``cached_property`` included an undocumented lock to
@@ -126,8 +132,6 @@ The :mod:`functools` module defines the following functions:
per-instance, which could result in unacceptably high lock contention. In
Python 3.12+ this locking is removed.
- .. versionadded:: 3.8
-
.. function:: cmp_to_key(func)
@@ -159,8 +163,13 @@ The :mod:`functools` module defines the following functions:
*maxsize* most recent calls. It can save time when an expensive or I/O bound
function is periodically called with the same arguments.
- The cache is threadsafe so the wrapped function can be used in multiple
- threads.
+ The cache is threadsafe so that the wrapped function can be used in
+ multiple threads. This means that the underlying data structure will
+ remain coherent during concurrent updates.
+
+ It is possible for the wrapped function to be called more than once if
+ another thread makes an additional call before the initial call has been
+ completed and cached.
Since a dictionary is used to cache results, the positional and keyword
arguments to the function must be :term:`hashable`.
@@ -233,7 +242,7 @@ The :mod:`functools` module defines the following functions:
@lru_cache(maxsize=32)
def get_pep(num):
'Retrieve text of a Python Enhancement Proposal'
- resource = 'https://peps.python.org/pep-%04d/' % num
+ resource = f'https://peps.python.org/pep-{num:04d}'
try:
with urllib.request.urlopen(resource) as s:
return s.read()
diff --git a/Doc/library/gc.rst b/Doc/library/gc.rst
index 832ebaf497f37a..6d5c64df1a1f3f 100644
--- a/Doc/library/gc.rst
+++ b/Doc/library/gc.rst
@@ -206,12 +206,17 @@ The :mod:`gc` module provides the following functions:
.. function:: freeze()
- Freeze all the objects tracked by gc - move them to a permanent generation
- and ignore all the future collections. This can be used before a POSIX
- fork() call to make the gc copy-on-write friendly or to speed up collection.
- Also collection before a POSIX fork() call may free pages for future
- allocation which can cause copy-on-write too so it's advised to disable gc
- in parent process and freeze before fork and enable gc in child process.
+ Freeze all the objects tracked by the garbage collector; move them to a
+ permanent generation and ignore them in all the future collections.
+
+ If a process will ``fork()`` without ``exec()``, avoiding unnecessary
+ copy-on-write in child processes will maximize memory sharing and reduce
+ overall memory usage. This requires both avoiding creation of freed "holes"
+ in memory pages in the parent process and ensuring that GC collections in
+ child processes won't touch the ``gc_refs`` counter of long-lived objects
+ originating in the parent process. To accomplish both, call ``gc.disable()``
+ early in the parent process, ``gc.freeze()`` right before ``fork()``, and
+ ``gc.enable()`` early in child processes.
.. versionadded:: 3.7
diff --git a/Doc/library/importlib.metadata.rst b/Doc/library/importlib.metadata.rst
index 6e084101995e25..b306d5f55a714f 100644
--- a/Doc/library/importlib.metadata.rst
+++ b/Doc/library/importlib.metadata.rst
@@ -308,6 +308,10 @@ Python module or `Import Package >> packages_distributions()
{'importlib_metadata': ['importlib-metadata'], 'yaml': ['PyYAML'], 'jaraco': ['jaraco.classes', 'jaraco.functools'], ...}
+Some editable installs, `do not supply top-level names
+`_, and thus this
+function is not reliable with such installs.
+
.. versionadded:: 3.10
.. _distributions:
diff --git a/Doc/library/itertools.rst b/Doc/library/itertools.rst
index 70e5b7905f20a9..e57c393a6b370b 100644
--- a/Doc/library/itertools.rst
+++ b/Doc/library/itertools.rst
@@ -769,8 +769,8 @@ well as with the built-in itertools such as ``map()``, ``filter()``,
A secondary purpose of the recipes is to serve as an incubator. The
``accumulate()``, ``compress()``, and ``pairwise()`` itertools started out as
-recipes. Currently, the ``iter_index()`` recipe is being tested to see
-whether it proves its worth.
+recipes. Currently, the ``sliding_window()`` and ``iter_index()`` recipes
+are being tested to see whether they prove their worth.
Substantially all of these recipes and many, many others can be installed from
the `more-itertools project `_ found
@@ -806,6 +806,23 @@ which incur interpreter overhead.
"Return function(0), function(1), ..."
return map(function, count(start))
+ def repeatfunc(func, times=None, *args):
+ """Repeat calls to func with specified arguments.
+
+ Example: repeatfunc(random.random)
+ """
+ if times is None:
+ return starmap(func, repeat(args))
+ return starmap(func, repeat(args, times))
+
+ def flatten(list_of_lists):
+ "Flatten one level of nesting"
+ return chain.from_iterable(list_of_lists)
+
+ def ncycles(iterable, n):
+ "Returns the sequence elements n times"
+ return chain.from_iterable(repeat(tuple(iterable), n))
+
def tail(n, iterable):
"Return an iterator over the last n items"
# tail(3, 'ABCDEFG') --> E F G
@@ -825,70 +842,27 @@ which incur interpreter overhead.
"Returns the nth item or a default value"
return next(islice(iterable, n, None), default)
- def all_equal(iterable):
- "Returns True if all the elements are equal to each other"
- g = groupby(iterable)
- return next(g, True) and not next(g, False)
-
def quantify(iterable, pred=bool):
"Count how many times the predicate is True"
return sum(map(pred, iterable))
- def ncycles(iterable, n):
- "Returns the sequence elements n times"
- return chain.from_iterable(repeat(tuple(iterable), n))
-
- def sum_of_squares(it):
- "Add up the squares of the input values."
- # sum_of_squares([10, 20, 30]) -> 1400
- return math.sumprod(*tee(it))
-
- def transpose(it):
- "Swap the rows and columns of the input."
- # transpose([(1, 2, 3), (11, 22, 33)]) --> (1, 11) (2, 22) (3, 33)
- return zip(*it, strict=True)
-
- def matmul(m1, m2):
- "Multiply two matrices."
- # matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]) --> (49, 80), (41, 60)
- n = len(m2[0])
- return batched(starmap(math.sumprod, product(m1, transpose(m2))), n)
-
- def convolve(signal, kernel):
- # See: https://betterexplained.com/articles/intuitive-convolution/
- # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
- # convolve(data, [1, -1]) --> 1st finite difference (1st derivative)
- # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative)
- kernel = tuple(kernel)[::-1]
- n = len(kernel)
- window = collections.deque([0], maxlen=n) * n
- for x in chain(signal, repeat(0, n-1)):
- window.append(x)
- yield math.sumprod(kernel, window)
+ def all_equal(iterable):
+ "Returns True if all the elements are equal to each other"
+ g = groupby(iterable)
+ return next(g, True) and not next(g, False)
- def polynomial_from_roots(roots):
- """Compute a polynomial's coefficients from its roots.
+ def first_true(iterable, default=False, pred=None):
+ """Returns the first true value in the iterable.
- (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60
- """
- # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60]
- expansion = [1]
- for r in roots:
- expansion = convolve(expansion, (1, -r))
- return list(expansion)
+ If no true value is found, returns *default*
- def polynomial_eval(coefficients, x):
- """Evaluate a polynomial at a specific value.
+ If *pred* is not None, returns the first item
+ for which pred(item) is true.
- Computes with better numeric stability than Horner's method.
"""
- # Evaluate x³ -4x² -17x + 60 at x = 2.5
- # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125
- n = len(coefficients)
- if n == 0:
- return x * 0 # coerce zero to the type of x
- powers = map(pow, repeat(x), reversed(range(n)))
- return math.sumprod(coefficients, powers)
+ # first_true([a,b,c], x) --> a or b or c or x
+ # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
+ return next(filter(pred, iterable), default)
def iter_index(iterable, value, start=0):
"Return indices where a value occurs in a sequence or iterable."
@@ -913,44 +887,28 @@ which incur interpreter overhead.
except ValueError:
pass
- def sieve(n):
- "Primes less than n"
- # sieve(30) --> 2 3 5 7 11 13 17 19 23 29
- data = bytearray((0, 1)) * (n // 2)
- data[:3] = 0, 0, 0
- limit = math.isqrt(n) + 1
- for p in compress(range(limit), data):
- data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))
- data[2] = 1
- return iter_index(data, 1) if n > 2 else iter([])
-
- def factor(n):
- "Prime factors of n."
- # factor(99) --> 3 3 11
- for prime in sieve(math.isqrt(n) + 1):
- while True:
- quotient, remainder = divmod(n, prime)
- if remainder:
- break
- yield prime
- n = quotient
- if n == 1:
- return
- if n > 1:
- yield n
+ def iter_except(func, exception, first=None):
+ """ Call a function repeatedly until an exception is raised.
- def flatten(list_of_lists):
- "Flatten one level of nesting"
- return chain.from_iterable(list_of_lists)
+ Converts a call-until-exception interface to an iterator interface.
+ Like builtins.iter(func, sentinel) but uses an exception instead
+ of a sentinel to end the loop.
- def repeatfunc(func, times=None, *args):
- """Repeat calls to func with specified arguments.
+ Examples:
+ iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator
+ iter_except(d.popitem, KeyError) # non-blocking dict iterator
+ iter_except(d.popleft, IndexError) # non-blocking deque iterator
+ iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue
+ iter_except(s.pop, KeyError) # non-blocking set iterator
- Example: repeatfunc(random.random)
"""
- if times is None:
- return starmap(func, repeat(args))
- return starmap(func, repeat(args, times))
+ try:
+ if first is not None:
+ yield first() # For database APIs needing an initial cast to db.first()
+ while True:
+ yield func()
+ except exception:
+ pass
def grouper(iterable, n, *, incomplete='fill', fillvalue=None):
"Collect data into non-overlapping fixed-length chunks or blocks"
@@ -967,12 +925,6 @@ which incur interpreter overhead.
else:
raise ValueError('Expected fill, strict, or ignore')
- def triplewise(iterable):
- "Return overlapping triplets from an iterable"
- # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG
- for (a, _), (b, c) in pairwise(pairwise(iterable)):
- yield a, b, c
-
def sliding_window(iterable, n):
# sliding_window('ABCDEFG', 4) --> ABCD BCDE CDEF DEFG
it = iter(iterable)
@@ -1003,6 +955,12 @@ which incur interpreter overhead.
t1, t2 = tee(iterable)
return filterfalse(pred, t1), filter(pred, t2)
+ def subslices(seq):
+ "Return all contiguous non-empty subslices of a sequence"
+ # subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
+ slices = starmap(slice, combinations(range(len(seq) + 1), 2))
+ return map(operator.getitem, repeat(seq), slices)
+
def before_and_after(predicate, it):
""" Variant of takewhile() that allows complete
access to the remainder of the iterator.
@@ -1032,17 +990,6 @@ which incur interpreter overhead.
yield from it
return true_iterator(), remainder_iterator()
- def subslices(seq):
- "Return all contiguous non-empty subslices of a sequence"
- # subslices('ABCD') --> A AB ABC ABCD B BC BCD C CD D
- slices = starmap(slice, combinations(range(len(seq) + 1), 2))
- return map(operator.getitem, repeat(seq), slices)
-
- def powerset(iterable):
- "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
- s = list(iterable)
- return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
-
def unique_everseen(iterable, key=None):
"List unique elements, preserving order. Remember all elements ever seen."
# unique_everseen('AAAABBBCCDAABBB') --> A B C D
@@ -1072,41 +1019,96 @@ which incur interpreter overhead.
# unique_justseen('ABBcCAD', str.lower) --> A B c A D
return map(next, map(operator.itemgetter(1), groupby(iterable, key)))
- def iter_except(func, exception, first=None):
- """ Call a function repeatedly until an exception is raised.
- Converts a call-until-exception interface to an iterator interface.
- Like builtins.iter(func, sentinel) but uses an exception instead
- of a sentinel to end the loop.
+The following recipes have a more mathematical flavor:
- Examples:
- iter_except(functools.partial(heappop, h), IndexError) # priority queue iterator
- iter_except(d.popitem, KeyError) # non-blocking dict iterator
- iter_except(d.popleft, IndexError) # non-blocking deque iterator
- iter_except(q.get_nowait, Queue.Empty) # loop over a producer Queue
- iter_except(s.pop, KeyError) # non-blocking set iterator
+.. testcode::
- """
- try:
- if first is not None:
- yield first() # For database APIs needing an initial cast to db.first()
+ def powerset(iterable):
+ "powerset([1,2,3]) --> () (1,) (2,) (3,) (1,2) (1,3) (2,3) (1,2,3)"
+ s = list(iterable)
+ return chain.from_iterable(combinations(s, r) for r in range(len(s)+1))
+
+ def sieve(n):
+ "Primes less than n"
+ # sieve(30) --> 2 3 5 7 11 13 17 19 23 29
+ data = bytearray((0, 1)) * (n // 2)
+ data[:3] = 0, 0, 0
+ limit = math.isqrt(n) + 1
+ for p in compress(range(limit), data):
+ data[p*p : n : p+p] = bytes(len(range(p*p, n, p+p)))
+ data[2] = 1
+ return iter_index(data, 1) if n > 2 else iter([])
+
+ def factor(n):
+ "Prime factors of n."
+ # factor(99) --> 3 3 11
+ for prime in sieve(math.isqrt(n) + 1):
while True:
- yield func()
- except exception:
- pass
+ quotient, remainder = divmod(n, prime)
+ if remainder:
+ break
+ yield prime
+ n = quotient
+ if n == 1:
+ return
+ if n > 1:
+ yield n
- def first_true(iterable, default=False, pred=None):
- """Returns the first true value in the iterable.
+ def sum_of_squares(it):
+ "Add up the squares of the input values."
+ # sum_of_squares([10, 20, 30]) -> 1400
+ return math.sumprod(*tee(it))
- If no true value is found, returns *default*
+ def transpose(it):
+ "Swap the rows and columns of the input."
+ # transpose([(1, 2, 3), (11, 22, 33)]) --> (1, 11) (2, 22) (3, 33)
+ return zip(*it, strict=True)
- If *pred* is not None, returns the first item
- for which pred(item) is true.
+ def matmul(m1, m2):
+ "Multiply two matrices."
+ # matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]) --> (49, 80), (41, 60)
+ n = len(m2[0])
+ return batched(starmap(math.sumprod, product(m1, transpose(m2))), n)
+
+ def convolve(signal, kernel):
+ """Linear convolution of two iterables.
+ Article: https://betterexplained.com/articles/intuitive-convolution/
+ Video: https://www.youtube.com/watch?v=KuXjwB4LzSA
"""
- # first_true([a,b,c], x) --> a or b or c or x
- # first_true([a,b], x, f) --> a if f(a) else b if f(b) else x
- return next(filter(pred, iterable), default)
+ # convolve(data, [0.25, 0.25, 0.25, 0.25]) --> Moving average (blur)
+ # convolve(data, [1, -1]) --> 1st finite difference (1st derivative)
+ # convolve(data, [1, -2, 1]) --> 2nd finite difference (2nd derivative)
+ kernel = tuple(kernel)[::-1]
+ n = len(kernel)
+ padded_signal = chain(repeat(0, n-1), signal, [0] * (n-1))
+ for window in sliding_window(padded_signal, n):
+ yield math.sumprod(kernel, window)
+
+ def polynomial_from_roots(roots):
+ """Compute a polynomial's coefficients from its roots.
+
+ (x - 5) (x + 4) (x - 3) expands to: x³ -4x² -17x + 60
+ """
+ # polynomial_from_roots([5, -4, 3]) --> [1, -4, -17, 60]
+ expansion = [1]
+ for r in roots:
+ expansion = convolve(expansion, (1, -r))
+ return list(expansion)
+
+ def polynomial_eval(coefficients, x):
+ """Evaluate a polynomial at a specific value.
+
+ Computes with better numeric stability than Horner's method.
+ """
+ # Evaluate x³ -4x² -17x + 60 at x = 2.5
+ # polynomial_eval([1, -4, -17, 60], x=2.5) --> 8.125
+ n = len(coefficients)
+ if n == 0:
+ return x * 0 # coerce zero to the type of x
+ powers = map(pow, repeat(x), reversed(range(n)))
+ return math.sumprod(coefficients, powers)
def nth_combination(iterable, r, index):
"Equivalent to list(combinations(iterable, r))[index]"
@@ -1126,6 +1128,7 @@ which incur interpreter overhead.
result.append(pool[-1-n])
return tuple(result)
+
.. doctest::
:hide:
@@ -1401,9 +1404,6 @@ which incur interpreter overhead.
>>> list(grouper('abcdefg', n=3, incomplete='ignore'))
[('a', 'b', 'c'), ('d', 'e', 'f')]
- >>> list(triplewise('ABCDEFG'))
- [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')]
-
>>> list(sliding_window('ABCDEFG', 4))
[('A', 'B', 'C', 'D'), ('B', 'C', 'D', 'E'), ('C', 'D', 'E', 'F'), ('D', 'E', 'F', 'G')]
@@ -1485,3 +1485,45 @@ which incur interpreter overhead.
>>> combos = list(combinations(iterable, r))
>>> all(nth_combination(iterable, r, i) == comb for i, comb in enumerate(combos))
True
+
+
+.. testcode::
+ :hide:
+
+ # Old recipes and their tests which are guaranteed to continue to work.
+
+ def sumprod(vec1, vec2):
+ "Compute a sum of products."
+ return sum(starmap(operator.mul, zip(vec1, vec2, strict=True)))
+
+ def dotproduct(vec1, vec2):
+ return sum(map(operator.mul, vec1, vec2))
+
+ def pad_none(iterable):
+ """Returns the sequence elements and then returns None indefinitely.
+
+ Useful for emulating the behavior of the built-in map() function.
+ """
+ return chain(iterable, repeat(None))
+
+ def triplewise(iterable):
+ "Return overlapping triplets from an iterable"
+ # triplewise('ABCDEFG') --> ABC BCD CDE DEF EFG
+ for (a, _), (b, c) in pairwise(pairwise(iterable)):
+ yield a, b, c
+
+
+.. doctest::
+ :hide:
+
+ >>> dotproduct([1,2,3], [4,5,6])
+ 32
+
+ >>> sumprod([1,2,3], [4,5,6])
+ 32
+
+ >>> list(islice(pad_none('abc'), 0, 6))
+ ['a', 'b', 'c', None, None, None]
+
+ >>> list(triplewise('ABCDEFG'))
+ [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E'), ('D', 'E', 'F'), ('E', 'F', 'G')]
diff --git a/Doc/library/logging.config.rst b/Doc/library/logging.config.rst
index 2daf2422ebd5b4..250246b5cd9adc 100644
--- a/Doc/library/logging.config.rst
+++ b/Doc/library/logging.config.rst
@@ -253,6 +253,7 @@ otherwise, the context is used to determine what to instantiate.
* ``datefmt``
* ``style``
* ``validate`` (since version >=3.8)
+ * ``defaults`` (since version >=3.12)
An optional ``class`` key indicates the name of the formatter's
class (as a dotted module and class name). The instantiation
@@ -953,16 +954,22 @@ Sections which specify formatter configuration are typified by the following.
.. code-block:: ini
[formatter_form01]
- format=F1 %(asctime)s %(levelname)s %(message)s
+ format=F1 %(asctime)s %(levelname)s %(message)s %(customfield)s
datefmt=
style=%
validate=True
+ defaults={'customfield': 'defaultvalue'}
class=logging.Formatter
The arguments for the formatter configuration are the same as the keys
in the dictionary schema :ref:`formatters section
`.
+The ``defaults`` entry, when :ref:`evaluated ` in the context of
+the ``logging`` package's namespace, is a dictionary of default values for
+custom formatting fields. If not provided, it defaults to ``None``.
+
+
.. note::
Due to the use of :func:`eval` as described above, there are
diff --git a/Doc/library/optparse.rst b/Doc/library/optparse.rst
index 3e29fed0175e04..5c02d8bc8835bf 100644
--- a/Doc/library/optparse.rst
+++ b/Doc/library/optparse.rst
@@ -954,7 +954,16 @@ The canonical way to create an :class:`Option` instance is with the
As you can see, most actions involve storing or updating a value somewhere.
:mod:`optparse` always creates a special object for this, conventionally called
-``options`` (it happens to be an instance of :class:`optparse.Values`). Option
+``options``, which is an instance of :class:`optparse.Values`.
+
+.. class:: Values
+
+ An object holding parsed argument names and values as attributes.
+ Normally created by calling when calling :meth:`OptionParser.parse_args`,
+ and can be overridden by a custom subclass passed to the *values* argument of
+ :meth:`OptionParser.parse_args` (as described in :ref:`optparse-parsing-arguments`).
+
+Option
arguments (and various other values) are stored as attributes of this object,
according to the :attr:`~Option.dest` (destination) option attribute.
@@ -991,6 +1000,14 @@ one that makes sense for *all* options.
Option attributes
^^^^^^^^^^^^^^^^^
+.. class:: Option
+
+ A single command line argument,
+ with various attributes passed by keyword to the constructor.
+ Normally created with :meth:`OptionParser.add_option` rather than directly,
+ and can be overridden by a custom class via the *option_class* argument
+ to :class:`OptionParser`.
+
The following option attributes may be passed as keyword arguments to
:meth:`OptionParser.add_option`. If you pass an option attribute that is not
relevant to a particular option, or fail to pass a required option attribute,
@@ -2027,7 +2044,7 @@ Features of note:
values.ensure_value(attr, value)
If the ``attr`` attribute of ``values`` doesn't exist or is ``None``, then
- ensure_value() first sets it to ``value``, and then returns 'value. This is
+ ensure_value() first sets it to ``value``, and then returns ``value``. This is
very handy for actions like ``"extend"``, ``"append"``, and ``"count"``, all
of which accumulate data in a variable and expect that variable to be of a
certain type (a list for the first two, an integer for the latter). Using
@@ -2035,3 +2052,27 @@ Features of note:
about setting a default value for the option destinations in question; they
can just leave the default as ``None`` and :meth:`ensure_value` will take care of
getting it right when it's needed.
+
+Exceptions
+----------
+
+.. exception:: OptionError
+
+ Raised if an :class:`Option` instance is created with invalid or
+ inconsistent arguments.
+
+.. exception:: OptionConflictError
+
+ Raised if conflicting options are added to an :class:`OptionParser`.
+
+.. exception:: OptionValueError
+
+ Raised if an invalid option value is encountered on the command line.
+
+.. exception:: BadOptionError
+
+ Raised if an invalid option is passed on the command line.
+
+.. exception:: AmbiguousOptionError
+
+ Raised if an ambiguous option is passed on the command line.
diff --git a/Doc/library/os.rst b/Doc/library/os.rst
index 7bb501c5946817..50e951c631fa88 100644
--- a/Doc/library/os.rst
+++ b/Doc/library/os.rst
@@ -3919,7 +3919,8 @@ to be ignored.
the :envvar:`PATH` variable. The other variants, :func:`execl`, :func:`execle`,
:func:`execv`, and :func:`execve`, will not use the :envvar:`PATH` variable to
locate the executable; *path* must contain an appropriate absolute or relative
- path.
+ path. Relative paths must include at least one slash, even on Windows, as
+ plain names will not be resolved.
For :func:`execle`, :func:`execlpe`, :func:`execve`, and :func:`execvpe` (note
that these all end in "e"), the *env* parameter must be a mapping which is
diff --git a/Doc/library/pdb.rst b/Doc/library/pdb.rst
index d80c5eebbf27a7..5bc48a6d5f77fd 100644
--- a/Doc/library/pdb.rst
+++ b/Doc/library/pdb.rst
@@ -36,73 +36,91 @@ extension interface uses the modules :mod:`bdb` and :mod:`cmd`.
Module :mod:`traceback`
Standard interface to extract, format and print stack traces of Python programs.
-The debugger's prompt is ``(Pdb)``. Typical usage to run a program under control
-of the debugger is::
+The typical usage to break into the debugger is to insert::
- >>> import pdb
- >>> import mymodule
- >>> pdb.run('mymodule.test()')
- > (0)?()
- (Pdb) continue
- > (1)?()
+ import pdb; pdb.set_trace()
+
+Or::
+
+ breakpoint()
+
+at the location you want to break into the debugger, and then run the program.
+You can then step through the code following this statement, and continue
+running without the debugger using the :pdbcmd:`continue` command.
+
+.. versionadded:: 3.7
+ The built-in :func:`breakpoint()`, when called with defaults, can be used
+ instead of ``import pdb; pdb.set_trace()``.
+
+::
+
+ def double(x):
+ breakpoint()
+ return x * 2
+ val = 3
+ print(f"{val} * 2 is {double(val)}")
+
+The debugger's prompt is ``(Pdb)``, which is the indicator that you are in debug mode::
+
+ > ...(3)double()
+ -> return x * 2
+ (Pdb) p x
+ 3
(Pdb) continue
- NameError: 'spam'
- > (1)?()
- (Pdb)
+ 3 * 2 is 6
.. versionchanged:: 3.3
Tab-completion via the :mod:`readline` module is available for commands and
command arguments, e.g. the current global and local names are offered as
arguments of the ``p`` command.
-:file:`pdb.py` can also be invoked as a script to debug other scripts. For
+
+You can also invoke :mod:`pdb` from the command line to debug other scripts. For
example::
python -m pdb myscript.py
-When invoked as a script, pdb will automatically enter post-mortem debugging if
+When invoked as a module, pdb will automatically enter post-mortem debugging if
the program being debugged exits abnormally. After post-mortem debugging (or
after normal exit of the program), pdb will restart the program. Automatic
restarting preserves pdb's state (such as breakpoints) and in most cases is more
useful than quitting the debugger upon program's exit.
.. versionadded:: 3.2
- :file:`pdb.py` now accepts a ``-c`` option that executes commands as if given
+ ``-c`` option is introduced to execute commands as if given
in a :file:`.pdbrc` file, see :ref:`debugger-commands`.
.. versionadded:: 3.7
- :file:`pdb.py` now accepts a ``-m`` option that execute modules similar to the way
+ ``-m`` option is introduced to execute modules similar to the way
``python -m`` does. As with a script, the debugger will pause execution just
before the first line of the module.
+Typical usage to execute a statement under control of the debugger is::
-The typical usage to break into the debugger is to insert::
-
- import pdb; pdb.set_trace()
-
-at the location you want to break into the debugger, and then run the program.
-You can then step through the code following this statement, and continue
-running without the debugger using the :pdbcmd:`continue` command.
-
-.. versionadded:: 3.7
- The built-in :func:`breakpoint()`, when called with defaults, can be used
- instead of ``import pdb; pdb.set_trace()``.
+ >>> import pdb
+ >>> def f(x):
+ ... print(1 / x)
+ >>> pdb.run("f(2)")
+ > (1)()
+ (Pdb) continue
+ 0.5
+ >>>
The typical usage to inspect a crashed program is::
>>> import pdb
- >>> import mymodule
- >>> mymodule.test()
+ >>> def f(x):
+ ... print(1 / x)
+ ...
+ >>> f(0)
Traceback (most recent call last):
File "", line 1, in
- File "./mymodule.py", line 4, in test
- test2()
- File "./mymodule.py", line 3, in test2
- print(spam)
- NameError: spam
+ File "", line 2, in f
+ ZeroDivisionError: division by zero
>>> pdb.pm()
- > ./mymodule.py(3)test2()
- -> print(spam)
+ > (2)f()
+ (Pdb) p x
+ 0
(Pdb)
@@ -275,7 +293,7 @@ can be overridden by the local file.
.. pdbcommand:: w(here)
- Print a stack trace, with the most recent frame at the bottom. An arrow
+ Print a stack trace, with the most recent frame at the bottom. An arrow (``>``)
indicates the current frame, which determines the context of most commands.
.. pdbcommand:: d(own) [count]
@@ -315,14 +333,14 @@ can be overridden by the local file.
With a space separated list of breakpoint numbers, clear those breakpoints.
Without argument, clear all breaks (but first ask confirmation).
-.. pdbcommand:: disable [bpnumber ...]
+.. pdbcommand:: disable bpnumber [bpnumber ...]
Disable the breakpoints given as a space separated list of breakpoint
numbers. Disabling a breakpoint means it cannot cause the program to stop
execution, but unlike clearing a breakpoint, it remains in the list of
breakpoints and can be (re-)enabled.
-.. pdbcommand:: enable [bpnumber ...]
+.. pdbcommand:: enable bpnumber [bpnumber ...]
Enable the breakpoints specified.
@@ -442,7 +460,7 @@ can be overridden by the local file.
.. pdbcommand:: a(rgs)
- Print the argument list of the current function.
+ Print the arguments of the current function and their current values.
.. pdbcommand:: p expression
@@ -476,6 +494,50 @@ can be overridden by the local file.
Without *expression*, list all display expressions for the current frame.
+ .. note::
+
+ Display evaluates *expression* and compares to the result of the previous
+ evaluation of *expression*, so when the result is mutable, display may not
+ be able to pick up the changes.
+
+ Example::
+
+ lst = []
+ breakpoint()
+ pass
+ lst.append(1)
+ print(lst)
+
+ Display won't realize ``lst`` has been changed because the result of evaluation
+ is modified in place by ``lst.append(1)`` before being compared::
+
+ > example.py(3)()
+ -> pass
+ (Pdb) display lst
+ display lst: []
+ (Pdb) n
+ > example.py(4)()
+ -> lst.append(1)
+ (Pdb) n
+ > example.py(5)()
+ -> print(lst)
+ (Pdb)
+
+ You can do some tricks with copy mechanism to make it work::
+
+ > example.py(3)()
+ -> pass
+ (Pdb) display lst[:]
+ display lst[:]: []
+ (Pdb) n
+ > example.py(4)()
+ -> lst.append(1)
+ (Pdb) n
+ > example.py(5)()
+ -> print(lst)
+ display lst[:]: [1] [old: []]
+ (Pdb)
+
.. versionadded:: 3.2
.. pdbcommand:: undisplay [expression]
@@ -552,7 +614,7 @@ can be overridden by the local file.
.. pdbcommand:: retval
- Print the return value for the last return of a function.
+ Print the return value for the last return of the current function.
.. rubric:: Footnotes
diff --git a/Doc/library/pkgutil.rst b/Doc/library/pkgutil.rst
index 788a02dcb8922f..64e617b82b48bc 100644
--- a/Doc/library/pkgutil.rst
+++ b/Doc/library/pkgutil.rst
@@ -25,9 +25,9 @@ support.
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
- This will add to the package's ``__path__`` all subdirectories of directories
- on :data:`sys.path` named after the package. This is useful if one wants to
- distribute different parts of a single logical package as multiple
+ For each directory on :data:`sys.path` that has a subdirectory that matches the
+ package name, add the subdirectory to the package's :attr:`__path__`. This is useful
+ if one wants to distribute different parts of a single logical package as multiple
directories.
It also looks for :file:`\*.pkg` files beginning where ``*`` matches the
@@ -82,7 +82,7 @@ support.
This is a backwards compatibility wrapper around
:func:`importlib.util.find_spec` that converts most failures to
:exc:`ImportError` and only returns the loader rather than the full
- :class:`ModuleSpec`.
+ :class:`importlib.machinery.ModuleSpec`.
.. versionchanged:: 3.3
Updated to be based directly on :mod:`importlib` rather than relying
diff --git a/Doc/library/readline.rst b/Doc/library/readline.rst
index 4d485d25b54020..8fb0eca8df74d8 100644
--- a/Doc/library/readline.rst
+++ b/Doc/library/readline.rst
@@ -19,7 +19,7 @@ function.
Readline keybindings may be configured via an initialization file, typically
``.inputrc`` in your home directory. See `Readline Init File
-`_
+`_
in the GNU Readline manual for information about the format and
allowable constructs of that file, and the capabilities of the
Readline library in general.
diff --git a/Doc/library/sched.rst b/Doc/library/sched.rst
index a051c65b97b05e..04215d31ba10ca 100644
--- a/Doc/library/sched.rst
+++ b/Doc/library/sched.rst
@@ -36,7 +36,7 @@ scheduler:
Example::
>>> import sched, time
- >>> s = sched.scheduler(time.time, time.sleep)
+ >>> s = sched.scheduler(time.monotonic, time.sleep)
>>> def print_time(a='default'):
... print("From print_time", time.time(), a)
...
diff --git a/Doc/library/shutil.rst b/Doc/library/shutil.rst
index 373cc7d6072031..7f408be2336824 100644
--- a/Doc/library/shutil.rst
+++ b/Doc/library/shutil.rst
@@ -662,7 +662,7 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
Remove the archive format *name* from the list of supported formats.
-.. function:: unpack_archive(filename[, extract_dir[, format]])
+.. function:: unpack_archive(filename[, extract_dir[, format[, filter]]])
Unpack an archive. *filename* is the full path of the archive.
@@ -676,6 +676,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
registered for that extension. In case none is found,
a :exc:`ValueError` is raised.
+ The keyword-only *filter* argument is passed to the underlying unpacking
+ function. For zip files, *filter* is not accepted.
+ For tar files, it is recommended to set it to ``'data'``,
+ unless using features specific to tar and UNIX-like filesystems.
+ (See :ref:`tarfile-extraction-filter` for details.)
+ The ``'data'`` filter will become the default for tar files
+ in Python 3.14.
+
.. audit-event:: shutil.unpack_archive filename,extract_dir,format shutil.unpack_archive
.. warning::
@@ -688,6 +696,9 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
.. versionchanged:: 3.7
Accepts a :term:`path-like object` for *filename* and *extract_dir*.
+ .. versionchanged:: 3.12
+ Added the *filter* argument.
+
.. function:: register_unpack_format(name, extensions, function[, extra_args[, description]])
Registers an unpack format. *name* is the name of the format and
@@ -695,11 +706,14 @@ provided. They rely on the :mod:`zipfile` and :mod:`tarfile` modules.
``.zip`` for Zip files.
*function* is the callable that will be used to unpack archives. The
- callable will receive the path of the archive, followed by the directory
- the archive must be extracted to.
-
- When provided, *extra_args* is a sequence of ``(name, value)`` tuples that
- will be passed as keywords arguments to the callable.
+ callable will receive:
+
+ - the path of the archive, as a positional argument;
+ - the directory the archive must be extracted to, as a positional argument;
+ - possibly a *filter* keyword argument, if it was given to
+ :func:`unpack_archive`;
+ - additional keyword arguments, specified by *extra_args* as a sequence
+ of ``(name, value)`` tuples.
*description* can be provided to describe the format, and will be returned
by the :func:`get_unpack_formats` function.
diff --git a/Doc/library/socketserver.rst b/Doc/library/socketserver.rst
index ceb962e860042d..d65e9fe81acf8b 100644
--- a/Doc/library/socketserver.rst
+++ b/Doc/library/socketserver.rst
@@ -140,9 +140,16 @@ server is the address family.
ForkingUDPServer
ThreadingTCPServer
ThreadingUDPServer
+ ForkingUnixStreamServer
+ ForkingUnixDatagramServer
+ ThreadingUnixStreamServer
+ ThreadingUnixDatagramServer
These classes are pre-defined using the mix-in classes.
+.. versionadded:: 3.12
+ The ``ForkingUnixStreamServer`` and ``ForkingUnixDatagramServer`` classes
+ were added.
To implement a service, you must derive a class from :class:`BaseRequestHandler`
and redefine its :meth:`~BaseRequestHandler.handle` method.
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index bcfc6e5cfce611..2360472b31f175 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -1605,8 +1605,8 @@ expression support in the :mod:`re` module).
converts it to ``"ss"``.
The casefolding algorithm is
- `described in section 3.13 of the Unicode Standard
- `__.
+ `described in section 3.13 'Default Case Folding' of the Unicode Standard
+ `__.
.. versionadded:: 3.3
@@ -1768,8 +1768,9 @@ expression support in the :mod:`re` module).
one character, ``False`` otherwise. Alphabetic characters are those characters defined
in the Unicode character database as "Letter", i.e., those with general category
property being one of "Lm", "Lt", "Lu", "Ll", or "Lo". Note that this is different
- from the `Alphabetic property defined in the Unicode Standard
- `_.
+ from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and
+ Ideographic' of the Unicode Standard
+ `_.
.. method:: str.isascii()
@@ -1904,8 +1905,8 @@ expression support in the :mod:`re` module).
lowercase.
The lowercasing algorithm used is
- `described in section 3.13 of the Unicode Standard
- `__.
+ `described in section 3.13 'Default Case Folding' of the Unicode Standard
+ `__.
.. method:: str.lstrip([chars])
@@ -2250,8 +2251,8 @@ expression support in the :mod:`re` module).
titlecase).
The uppercasing algorithm used is
- `described in section 3.13 of the Unicode Standard
- `__.
+ `described in section 3.13 'Default Case Folding' of the Unicode Standard
+ `__.
.. method:: str.zfill(width)
@@ -3714,12 +3715,15 @@ copying.
types such as :class:`bytes` and :class:`bytearray`, an element is a single
byte, but other types such as :class:`array.array` may have bigger elements.
- ``len(view)`` is equal to the length of :class:`~memoryview.tolist`.
- If ``view.ndim = 0``, the length is 1. If ``view.ndim = 1``, the length
- is equal to the number of elements in the view. For higher dimensions,
- the length is equal to the length of the nested list representation of
- the view. The :class:`~memoryview.itemsize` attribute will give you the
- number of bytes in a single element.
+ ``len(view)`` is equal to the length of :class:`~memoryview.tolist`, which
+ is the nested list representation of the view. If ``view.ndim = 1``,
+ this is equal to the number of elements in the view.
+
+ .. versionchanged:: 3.12
+ If ``view.ndim == 0``, ``len(view)`` now raises :exc:`TypeError` instead of returning 1.
+
+ The :class:`~memoryview.itemsize` attribute will give you the number of
+ bytes in a single element.
A :class:`memoryview` supports slicing and indexing to expose its data.
One-dimensional slicing will result in a subview::
diff --git a/Doc/library/string.rst b/Doc/library/string.rst
index 5ada827328188d..26b3f5000634f5 100644
--- a/Doc/library/string.rst
+++ b/Doc/library/string.rst
@@ -235,7 +235,7 @@ dictionary keys (e.g., the strings ``'10'`` or ``':-]'``) within a format string
The *arg_name* can be followed by any number of index or
attribute expressions. An expression of the form ``'.name'`` selects the named
attribute using :func:`getattr`, while an expression of the form ``'[index]'``
-does an index lookup using :func:`__getitem__`.
+does an index lookup using :meth:`~object.__getitem__`.
.. versionchanged:: 3.1
The positional argument specifiers can be omitted for :meth:`str.format`,
@@ -254,10 +254,10 @@ Some simple format string examples::
"Units destroyed: {players[0]}" # First element of keyword argument 'players'.
The *conversion* field causes a type coercion before formatting. Normally, the
-job of formatting a value is done by the :meth:`__format__` method of the value
+job of formatting a value is done by the :meth:`~object.__format__` method of the value
itself. However, in some cases it is desirable to force a type to be formatted
as a string, overriding its own definition of formatting. By converting the
-value to a string before calling :meth:`__format__`, the normal formatting logic
+value to a string before calling :meth:`~object.__format__`, the normal formatting logic
is bypassed.
Three conversion flags are currently supported: ``'!s'`` which calls :func:`str`
diff --git a/Doc/library/subprocess.rst b/Doc/library/subprocess.rst
index 2b5a82e0107fb6..53dfbf827260c9 100644
--- a/Doc/library/subprocess.rst
+++ b/Doc/library/subprocess.rst
@@ -919,9 +919,12 @@ Reassigning them to new values is unsupported:
.. attribute:: Popen.returncode
- The child return code, set by :meth:`poll` and :meth:`wait` (and indirectly
- by :meth:`communicate`). A ``None`` value indicates that the process
- hasn't terminated yet.
+ The child return code. Initially ``None``, :attr:`returncode` is set by
+ a call to the :meth:`poll`, :meth:`wait`, or :meth:`communicate` methods
+ if they detect that the process has terminated.
+
+ A ``None`` value indicates that the process hadn't yet terminated at the
+ time of the last method call.
A negative value ``-N`` indicates that the child was terminated by signal
``N`` (POSIX only).
diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst
index 00721efd1cf65e..7324f3113e0a08 100644
--- a/Doc/library/sys.rst
+++ b/Doc/library/sys.rst
@@ -220,6 +220,10 @@ always available.
.. audit-event:: sys._current_exceptions "" sys._current_exceptions
+ .. versionchanged:: 3.12
+ Each value in the dictionary is now a single exception instance, rather
+ than a 3-tuple as returned from ``sys.exc_info()``.
+
.. function:: breakpointhook()
This hook function is called by built-in :func:`breakpoint`. By default,
@@ -666,6 +670,13 @@ always available.
.. versionadded:: 3.4
+.. function:: getunicodeinternedsize()
+
+ Return the number of unicode objects that have been interned.
+
+ .. versionadded:: 3.12
+
+
.. function:: getandroidapilevel()
Return the build time API version of Android as an integer.
diff --git a/Doc/library/tarfile.rst b/Doc/library/tarfile.rst
index 741d40da152101..891af1bcf7edff 100644
--- a/Doc/library/tarfile.rst
+++ b/Doc/library/tarfile.rst
@@ -36,6 +36,13 @@ Some facts and figures:
.. versionchanged:: 3.3
Added support for :mod:`lzma` compression.
+.. versionchanged:: 3.12
+ Archives are extracted using a :ref:`filter `,
+ which makes it possible to either limit surprising/dangerous features,
+ or to acknowledge that they are expected and the archive is fully trusted.
+ By default, archives are fully trusted, but this default is deprecated
+ and slated to change in Python 3.14.
+
.. function:: open(name=None, mode='r', fileobj=None, bufsize=10240, **kwargs)
@@ -209,6 +216,38 @@ The :mod:`tarfile` module defines the following exceptions:
Is raised by :meth:`TarInfo.frombuf` if the buffer it gets is invalid.
+.. exception:: FilterError
+
+ Base class for members :ref:`refused ` by
+ filters.
+
+ .. attribute:: tarinfo
+
+ Information about the member that the filter refused to extract,
+ as :ref:`TarInfo `.
+
+.. exception:: AbsolutePathError
+
+ Raised to refuse extracting a member with an absolute path.
+
+.. exception:: OutsideDestinationError
+
+ Raised to refuse extracting a member outside the destination directory.
+
+.. exception:: SpecialFileError
+
+ Raised to refuse extracting a special file (e.g. a device or pipe).
+
+.. exception:: AbsoluteLinkError
+
+ Raised to refuse extracting a symbolic link with an absolute path.
+
+.. exception:: LinkOutsideDestinationError
+
+ Raised to refuse extracting a symbolic link pointing outside the destination
+ directory.
+
+
The following constants are available at the module level:
.. data:: ENCODING
@@ -319,11 +358,8 @@ be finalized; only the internally used file object will be closed. See the
*debug* can be set from ``0`` (no debug messages) up to ``3`` (all debug
messages). The messages are written to ``sys.stderr``.
- If *errorlevel* is ``0``, all errors are ignored when using :meth:`TarFile.extract`.
- Nevertheless, they appear as error messages in the debug output, when debugging
- is enabled. If ``1``, all *fatal* errors are raised as :exc:`OSError`
- exceptions. If ``2``, all *non-fatal* errors are raised as :exc:`TarError`
- exceptions as well.
+ *errorlevel* controls how extraction errors are handled,
+ see :attr:`the corresponding attribute <~TarFile.errorlevel>`.
The *encoding* and *errors* arguments define the character encoding to be
used for reading or writing the archive and how conversion errors are going
@@ -390,7 +426,7 @@ be finalized; only the internally used file object will be closed. See the
available.
-.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False)
+.. method:: TarFile.extractall(path=".", members=None, *, numeric_owner=False, filter=None)
Extract all members from the archive to the current working directory or
directory *path*. If optional *members* is given, it must be a subset of the
@@ -404,6 +440,12 @@ be finalized; only the internally used file object will be closed. See the
are used to set the owner/group for the extracted files. Otherwise, the named
values from the tarfile are used.
+ The *filter* argument specifies how ``members`` are modified or rejected
+ before extraction.
+ See :ref:`tarfile-extraction-filter` for details.
+ It is recommended to set this explicitly depending on which *tar* features
+ you need to support.
+
.. warning::
Never extract archives from untrusted sources without prior inspection.
@@ -411,14 +453,20 @@ be finalized; only the internally used file object will be closed. See the
that have absolute filenames starting with ``"/"`` or filenames with two
dots ``".."``.
+ Set ``filter='data'`` to prevent the most dangerous security issues,
+ and read the :ref:`tarfile-extraction-filter` section for details.
+
.. versionchanged:: 3.5
Added the *numeric_owner* parameter.
.. versionchanged:: 3.6
The *path* parameter accepts a :term:`path-like object`.
+ .. versionchanged:: 3.12
+ Added the *filter* parameter.
-.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False)
+
+.. method:: TarFile.extract(member, path="", set_attrs=True, *, numeric_owner=False, filter=None)
Extract a member from the archive to the current working directory, using its
full name. Its file information is extracted as accurately as possible. *member*
@@ -426,9 +474,8 @@ be finalized; only the internally used file object will be closed. See the
directory using *path*. *path* may be a :term:`path-like object`.
File attributes (owner, mtime, mode) are set unless *set_attrs* is false.
- If *numeric_owner* is :const:`True`, the uid and gid numbers from the tarfile
- are used to set the owner/group for the extracted files. Otherwise, the named
- values from the tarfile are used.
+ The *numeric_owner* and *filter* arguments are the same as
+ for :meth:`extractall`.
.. note::
@@ -439,6 +486,9 @@ be finalized; only the internally used file object will be closed. See the
See the warning for :meth:`extractall`.
+ Set ``filter='data'`` to prevent the most dangerous security issues,
+ and read the :ref:`tarfile-extraction-filter` section for details.
+
.. versionchanged:: 3.2
Added the *set_attrs* parameter.
@@ -448,6 +498,9 @@ be finalized; only the internally used file object will be closed. See the
.. versionchanged:: 3.6
The *path* parameter accepts a :term:`path-like object`.
+ .. versionchanged:: 3.12
+ Added the *filter* parameter.
+
.. method:: TarFile.extractfile(member)
@@ -460,6 +513,55 @@ be finalized; only the internally used file object will be closed. See the
.. versionchanged:: 3.3
Return an :class:`io.BufferedReader` object.
+.. attribute:: TarFile.errorlevel
+ :type: int
+
+ If *errorlevel* is ``0``, errors are ignored when using :meth:`TarFile.extract`
+ and :meth:`TarFile.extractall`.
+ Nevertheless, they appear as error messages in the debug output when
+ *debug* is greater than 0.
+ If ``1`` (the default), all *fatal* errors are raised as :exc:`OSError` or
+ :exc:`FilterError` exceptions. If ``2``, all *non-fatal* errors are raised
+ as :exc:`TarError` exceptions as well.
+
+ Some exceptions, e.g. ones caused by wrong argument types or data
+ corruption, are always raised.
+
+ Custom :ref:`extraction filters `
+ should raise :exc:`FilterError` for *fatal* errors
+ and :exc:`ExtractError` for *non-fatal* ones.
+
+ Note that when an exception is raised, the archive may be partially
+ extracted. It is the user’s responsibility to clean up.
+
+.. attribute:: TarFile.extraction_filter
+
+ .. versionadded:: 3.12
+
+ The :ref:`extraction filter ` used
+ as a default for the *filter* argument of :meth:`~TarFile.extract`
+ and :meth:`~TarFile.extractall`.
+
+ The attribute may be ``None`` or a callable.
+ String names are not allowed for this attribute, unlike the *filter*
+ argument to :meth:`~TarFile.extract`.
+
+ If ``extraction_filter`` is ``None`` (the default),
+ calling an extraction method without a *filter* argument will raise a
+ ``DeprecationWarning``,
+ and fall back to the :func:`fully_trusted ` filter,
+ whose dangerous behavior matches previous versions of Python.
+
+ In Python 3.14+, leaving ``extraction_filter=None`` will cause
+ extraction methods to use the :func:`data ` filter by default.
+
+ The attribute may be set on instances or overridden in subclasses.
+ It also is possible to set it on the ``TarFile`` class itself to set a
+ global default, although, since it affects all uses of *tarfile*,
+ it is best practice to only do so in top-level applications or
+ :mod:`site configuration `.
+ To set a global default this way, a filter function needs to be wrapped in
+ :func:`staticmethod()` to prevent injection of a ``self`` argument.
.. method:: TarFile.add(name, arcname=None, recursive=True, *, filter=None)
@@ -535,8 +637,23 @@ permissions, owner etc.), it provides some useful methods to determine its type.
It does *not* contain the file's data itself.
:class:`TarInfo` objects are returned by :class:`TarFile`'s methods
-:meth:`getmember`, :meth:`getmembers` and :meth:`gettarinfo`.
+:meth:`~TarFile.getmember`, :meth:`~TarFile.getmembers` and
+:meth:`~TarFile.gettarinfo`.
+Modifying the objects returned by :meth:`~!TarFile.getmember` or
+:meth:`~!TarFile.getmembers` will affect all subsequent
+operations on the archive.
+For cases where this is unwanted, you can use :mod:`copy.copy() ` or
+call the :meth:`~TarInfo.replace` method to create a modified copy in one step.
+
+Several attributes can be set to ``None`` to indicate that a piece of metadata
+is unused or unknown.
+Different :class:`TarInfo` methods handle ``None`` differently:
+
+- The :meth:`~TarFile.extract` or :meth:`~TarFile.extractall` methods will
+ ignore the corresponding metadata, leaving it set to a default.
+- :meth:`~TarFile.addfile` will fail.
+- :meth:`~TarFile.list` will print a placeholder string.
.. class:: TarInfo(name="")
@@ -569,24 +686,39 @@ A ``TarInfo`` object has the following public data attributes:
.. attribute:: TarInfo.name
+ :type: str
Name of the archive member.
.. attribute:: TarInfo.size
+ :type: int
Size in bytes.
.. attribute:: TarInfo.mtime
+ :type: int | float
- Time of last modification.
+ Time of last modification in seconds since the :ref:`epoch `,
+ as in :attr:`os.stat_result.st_mtime`.
+
+ .. versionchanged:: 3.12
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.mode
+ :type: int
- Permission bits.
+ Permission bits, as for :func:`os.chmod`.
+ .. versionchanged:: 3.12
+
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.type
@@ -598,35 +730,76 @@ A ``TarInfo`` object has the following public data attributes:
.. attribute:: TarInfo.linkname
+ :type: str
Name of the target file name, which is only present in :class:`TarInfo` objects
of type :const:`LNKTYPE` and :const:`SYMTYPE`.
.. attribute:: TarInfo.uid
+ :type: int
User ID of the user who originally stored this member.
+ .. versionchanged:: 3.12
+
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.gid
+ :type: int
Group ID of the user who originally stored this member.
+ .. versionchanged:: 3.12
+
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.uname
+ :type: str
User name.
+ .. versionchanged:: 3.12
+
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.gname
+ :type: str
Group name.
+ .. versionchanged:: 3.12
+
+ Can be set to ``None`` for :meth:`~TarFile.extract` and
+ :meth:`~TarFile.extractall`, causing extraction to skip applying this
+ attribute.
.. attribute:: TarInfo.pax_headers
+ :type: dict
A dictionary containing key-value pairs of an associated pax extended header.
+.. method:: TarInfo.replace(name=..., mtime=..., mode=..., linkname=...,
+ uid=..., gid=..., uname=..., gname=...,
+ deep=True)
+
+ .. versionadded:: 3.12
+
+ Return a *new* copy of the :class:`!TarInfo` object with the given attributes
+ changed. For example, to return a ``TarInfo`` with the group name set to
+ ``'staff'``, use::
+
+ new_tarinfo = old_tarinfo.replace(gname='staff')
+
+ By default, a deep copy is made.
+ If *deep* is false, the copy is shallow, i.e. ``pax_headers``
+ and any custom attributes are shared with the original ``TarInfo`` object.
A :class:`TarInfo` object also provides some convenient query methods:
@@ -676,9 +849,258 @@ A :class:`TarInfo` object also provides some convenient query methods:
Return :const:`True` if it is one of character device, block device or FIFO.
+.. _tarfile-extraction-filter:
+
+Extraction filters
+------------------
+
+.. versionadded:: 3.12
+
+The *tar* format is designed to capture all details of a UNIX-like filesystem,
+which makes it very powerful.
+Unfortunately, the features make it easy to create tar files that have
+unintended -- and possibly malicious -- effects when extracted.
+For example, extracting a tar file can overwrite arbitrary files in various
+ways (e.g. by using absolute paths, ``..`` path components, or symlinks that
+affect later members).
+
+In most cases, the full functionality is not needed.
+Therefore, *tarfile* supports extraction filters: a mechanism to limit
+functionality, and thus mitigate some of the security issues.
+
+.. seealso::
+
+ :pep:`706`
+ Contains further motivation and rationale behind the design.
+
+The *filter* argument to :meth:`TarFile.extract` or :meth:`~TarFile.extractall`
+can be:
+
+* the string ``'fully_trusted'``: Honor all metadata as specified in the
+ archive.
+ Should be used if the user trusts the archive completely, or implements
+ their own complex verification.
+
+* the string ``'tar'``: Honor most *tar*-specific features (i.e. features of
+ UNIX-like filesystems), but block features that are very likely to be
+ surprising or malicious. See :func:`tar_filter` for details.
+
+* the string ``'data'``: Ignore or block most features specific to UNIX-like
+ filesystems. Intended for extracting cross-platform data archives.
+ See :func:`data_filter` for details.
+
+* ``None`` (default): Use :attr:`TarFile.extraction_filter`.
+
+ If that is also ``None`` (the default), raise a ``DeprecationWarning``,
+ and fall back to the ``'fully_trusted'`` filter, whose dangerous behavior
+ matches previous versions of Python.
+
+ In Python 3.14, the ``'data'`` filter will become the default instead.
+ It's possible to switch earlier; see :attr:`TarFile.extraction_filter`.
+
+* A callable which will be called for each extracted member with a
+ :ref:`TarInfo ` describing the member and the destination
+ path to where the archive is extracted (i.e. the same path is used for all
+ members)::
+
+ filter(/, member: TarInfo, path: str) -> TarInfo | None
+
+ The callable is called just before each member is extracted, so it can
+ take the current state of the disk into account.
+ It can:
+
+ - return a :class:`TarInfo` object which will be used instead of the metadata
+ in the archive, or
+ - return ``None``, in which case the member will be skipped, or
+ - raise an exception to abort the operation or skip the member,
+ depending on :attr:`~TarFile.errorlevel`.
+ Note that when extraction is aborted, :meth:`~TarFile.extractall` may leave
+ the archive partially extracted. It does not attempt to clean up.
+
+Default named filters
+~~~~~~~~~~~~~~~~~~~~~
+
+The pre-defined, named filters are available as functions, so they can be
+reused in custom filters:
+
+.. function:: fully_trusted_filter(/, member, path)
+
+ Return *member* unchanged.
+
+ This implements the ``'fully_trusted'`` filter.
+
+.. function:: tar_filter(/, member, path)
+
+ Implements the ``'tar'`` filter.
+
+ - Strip leading slashes (``/`` and :attr:`os.sep`) from filenames.
+ - :ref:`Refuse ` to extract files with absolute
+ paths (in case the name is absolute
+ even after stripping slashes, e.g. ``C:/foo`` on Windows).
+ This raises :class:`~tarfile.AbsolutePathError`.
+ - :ref:`Refuse ` to extract files whose absolute
+ path (after following symlinks) would end up outside the destination.
+ This raises :class:`~tarfile.OutsideDestinationError`.
+ - Clear high mode bits (setuid, setgid, sticky) and group/other write bits
+ (:attr:`~stat.S_IWGRP`|:attr:`~stat.S_IWOTH`).
+
+ Return the modified ``TarInfo`` member.
+
+.. function:: data_filter(/, member, path)
+
+ Implements the ``'data'`` filter.
+ In addition to what ``tar_filter`` does:
+
+ - :ref:`Refuse ` to extract links (hard or soft)
+ that link to absolute paths, or ones that link outside the destination.
+
+ This raises :class:`~tarfile.AbsoluteLinkError` or
+ :class:`~tarfile.LinkOutsideDestinationError`.
+
+ Note that such files are refused even on platforms that do not support
+ symbolic links.
+
+ - :ref:`Refuse ` to extract device files
+ (including pipes).
+ This raises :class:`~tarfile.SpecialFileError`.
+
+ - For regular files, including hard links:
+
+ - Set the owner read and write permissions
+ (:attr:`~stat.S_IRUSR`|:attr:`~stat.S_IWUSR`).
+ - Remove the group & other executable permission
+ (:attr:`~stat.S_IXGRP`|:attr:`~stat.S_IXOTH`)
+ if the owner doesn’t have it (:attr:`~stat.S_IXUSR`).
+
+ - For other files (directories), set ``mode`` to ``None``, so
+ that extraction methods skip applying permission bits.
+ - Set user and group info (``uid``, ``gid``, ``uname``, ``gname``)
+ to ``None``, so that extraction methods skip setting it.
+
+ Return the modified ``TarInfo`` member.
+
+
+.. _tarfile-extraction-refuse:
+
+Filter errors
+~~~~~~~~~~~~~
+
+When a filter refuses to extract a file, it will raise an appropriate exception,
+a subclass of :class:`~tarfile.FilterError`.
+This will abort the extraction if :attr:`TarFile.errorlevel` is 1 or more.
+With ``errorlevel=0`` the error will be logged and the member will be skipped,
+but extraction will continue.
+
+
+Hints for further verification
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Even with ``filter='data'``, *tarfile* is not suited for extracting untrusted
+files without prior inspection.
+Among other issues, the pre-defined filters do not prevent denial-of-service
+attacks. Users should do additional checks.
+
+Here is an incomplete list of things to consider:
+
+* Extract to a :func:`new temporary directory `
+ to prevent e.g. exploiting pre-existing links, and to make it easier to
+ clean up after a failed extraction.
+* When working with untrusted data, use external (e.g. OS-level) limits on
+ disk, memory and CPU usage.
+* Check filenames against an allow-list of characters
+ (to filter out control characters, confusables, foreign path separators,
+ etc.).
+* Check that filenames have expected extensions (discouraging files that
+ execute when you “click on them”, or extension-less files like Windows special device names).
+* Limit the number of extracted files, total size of extracted data,
+ filename length (including symlink length), and size of individual files.
+* Check for files that would be shadowed on case-insensitive filesystems.
+
+Also note that:
+
+* Tar files may contain multiple versions of the same file.
+ Later ones are expected to overwrite any earlier ones.
+ This feature is crucial to allow updating tape archives, but can be abused
+ maliciously.
+* *tarfile* does not protect against issues with “live” data,
+ e.g. an attacker tinkering with the destination (or source) directory while
+ extraction (or archiving) is in progress.
+
+
+Supporting older Python versions
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Extraction filters were added to Python 3.12, but may be backported to older
+versions as security updates.
+To check whether the feature is available, use e.g.
+``hasattr(tarfile, 'data_filter')`` rather than checking the Python version.
+
+The following examples show how to support Python versions with and without
+the feature.
+Note that setting ``extraction_filter`` will affect any subsequent operations.
+
+* Fully trusted archive::
+
+ my_tarfile.extraction_filter = (lambda member, path: member)
+ my_tarfile.extractall()
+
+* Use the ``'data'`` filter if available, but revert to Python 3.11 behavior
+ (``'fully_trusted'``) if this feature is not available::
+
+ my_tarfile.extraction_filter = getattr(tarfile, 'data_filter',
+ (lambda member, path: member))
+ my_tarfile.extractall()
+
+* Use the ``'data'`` filter; *fail* if it is not available::
+
+ my_tarfile.extractall(filter=tarfile.data_filter)
+
+ or::
+
+ my_tarfile.extraction_filter = tarfile.data_filter
+ my_tarfile.extractall()
+
+* Use the ``'data'`` filter; *warn* if it is not available::
+
+ if hasattr(tarfile, 'data_filter'):
+ my_tarfile.extractall(filter='data')
+ else:
+ # remove this when no longer needed
+ warn_the_user('Extracting may be unsafe; consider updating Python')
+ my_tarfile.extractall()
+
+
+Stateful extraction filter example
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+While *tarfile*'s extraction methods take a simple *filter* callable,
+custom filters may be more complex objects with an internal state.
+It may be useful to write these as context managers, to be used like this::
+
+ with StatefulFilter() as filter_func:
+ tar.extractall(path, filter=filter_func)
+
+Such a filter can be written as, for example::
+
+ class StatefulFilter:
+ def __init__(self):
+ self.file_count = 0
+
+ def __enter__(self):
+ return self
+
+ def __call__(self, member, path):
+ self.file_count += 1
+ return member
+
+ def __exit__(self, *exc_info):
+ print(f'{self.file_count} files extracted')
+
+
.. _tarfile-commandline:
.. program:: tarfile
+
Command-Line Interface
----------------------
@@ -748,6 +1170,13 @@ Command-line options
Verbose output.
+.. cmdoption:: --filter
+
+ Specifies the *filter* for ``--extract``.
+ See :ref:`tarfile-extraction-filter` for details.
+ Only string names are accepted (that is, ``fully_trusted``, ``tar``,
+ and ``data``).
+
.. _tar-examples:
Examples
@@ -757,7 +1186,7 @@ How to extract an entire tar archive to the current working directory::
import tarfile
tar = tarfile.open("sample.tar.gz")
- tar.extractall()
+ tar.extractall(filter='data')
tar.close()
How to extract a subset of a tar archive with :meth:`TarFile.extractall` using
diff --git a/Doc/library/tempfile.rst b/Doc/library/tempfile.rst
index 61358eb76925b2..fd4c294613fd31 100644
--- a/Doc/library/tempfile.rst
+++ b/Doc/library/tempfile.rst
@@ -292,6 +292,9 @@ The module defines the following user-callable items:
.. versionchanged:: 3.6
The *dir* parameter now accepts a :term:`path-like object`.
+ .. versionchanged:: 3.12
+ :func:`mkdtemp` now always returns an absolute path, even if *dir* is relative.
+
.. function:: gettempdir()
diff --git a/Doc/library/token-list.inc b/Doc/library/token-list.inc
index 2739d5bfc1dfa2..3b345099bf54b5 100644
--- a/Doc/library/token-list.inc
+++ b/Doc/library/token-list.inc
@@ -201,6 +201,10 @@
Token value for ``":="``.
+.. data:: EXCLAMATION
+
+ Token value for ``"!"``.
+
.. data:: OP
.. data:: AWAIT
@@ -213,6 +217,12 @@
.. data:: SOFT_KEYWORD
+.. data:: FSTRING_START
+
+.. data:: FSTRING_MIDDLE
+
+.. data:: FSTRING_END
+
.. data:: ERRORTOKEN
.. data:: N_TOKENS
diff --git a/Doc/library/types.rst b/Doc/library/types.rst
index 747ba58bb225d4..a15fb5cfa49473 100644
--- a/Doc/library/types.rst
+++ b/Doc/library/types.rst
@@ -75,13 +75,53 @@ Dynamic Type Creation
This function looks for items in *bases* that are not instances of
:class:`type`, and returns a tuple where each such object that has
- an ``__mro_entries__`` method is replaced with an unpacked result of
+ an :meth:`~object.__mro_entries__` method is replaced with an unpacked result of
calling this method. If a *bases* item is an instance of :class:`type`,
- or it doesn't have an ``__mro_entries__`` method, then it is included in
+ or it doesn't have an :meth:`!__mro_entries__` method, then it is included in
the return tuple unchanged.
.. versionadded:: 3.7
+.. function:: get_original_bases(cls, /)
+
+ Return the tuple of objects originally given as the bases of *cls* before
+ the :meth:`~object.__mro_entries__` method has been called on any bases
+ (following the mechanisms laid out in :pep:`560`). This is useful for
+ introspecting :ref:`Generics `.
+
+ For classes that have an ``__orig_bases__`` attribute, this
+ function returns the value of ``cls.__orig_bases__``.
+ For classes without the ``__orig_bases__`` attribute, ``cls.__bases__`` is
+ returned.
+
+ Examples::
+
+ from typing import TypeVar, Generic, NamedTuple, TypedDict
+
+ T = TypeVar("T")
+ class Foo(Generic[T]): ...
+ class Bar(Foo[int], float): ...
+ class Baz(list[str]): ...
+ Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
+ Spam = TypedDict("Spam", {"a": int, "b": str})
+
+ assert Bar.__bases__ == (Foo, float)
+ assert get_original_bases(Bar) == (Foo[int], float)
+
+ assert Baz.__bases__ == (list,)
+ assert get_original_bases(Baz) == (list[str],)
+
+ assert Eggs.__bases__ == (tuple,)
+ assert get_original_bases(Eggs) == (NamedTuple,)
+
+ assert Spam.__bases__ == (dict,)
+ assert get_original_bases(Spam) == (TypedDict,)
+
+ assert int.__bases__ == (object,)
+ assert get_original_bases(int) == (object,)
+
+ .. versionadded:: 3.12
+
.. seealso::
:pep:`560` - Core support for typing module and generic types
@@ -311,6 +351,13 @@ Standard names are defined for the following types:
.. versionchanged:: 3.9.2
This type can now be subclassed.
+ .. seealso::
+
+ :ref:`Generic Alias Types`
+ In-depth documentation on instances of :class:`!types.GenericAlias`
+
+ :pep:`585` - Type Hinting Generics In Standard Collections
+ Introducing the :class:`!types.GenericAlias` class
.. class:: UnionType
diff --git a/Doc/library/typing.rst b/Doc/library/typing.rst
index 03ff259bbdf75f..15bab7775eadd8 100644
--- a/Doc/library/typing.rst
+++ b/Doc/library/typing.rst
@@ -423,7 +423,7 @@ to this is that a list of types can be used to substitute a :class:`ParamSpec`::
>>> class Z(Generic[T, P]): ...
...
>>> Z[int, [dict, float]]
- __main__.Z[int, (, )]
+ __main__.Z[int, [dict, float]]
Furthermore, a generic with only one parameter specification variable will accept
@@ -434,9 +434,9 @@ to the former, so the following are equivalent::
>>> class X(Generic[P]): ...
...
>>> X[int, str]
- __main__.X[(, )]
+ __main__.X[[int, str]]
>>> X[[int, str]]
- __main__.X[(, )]
+ __main__.X[[int, str]]
Do note that generics with :class:`ParamSpec` may not have correct
``__parameters__`` after substitution in some cases because they
diff --git a/Doc/library/unittest.rst b/Doc/library/unittest.rst
index d1a977fd7da6a5..a7c74cfa4fb477 100644
--- a/Doc/library/unittest.rst
+++ b/Doc/library/unittest.rst
@@ -2191,10 +2191,6 @@ Loading and running tests
.. versionadded:: 3.12
Added *durations* keyword argument.
- .. versionchanged:: 3.12
- Subclasses should accept ``**kwargs`` to ensure compatibility as the
- interface changes.
-
.. data:: defaultTestLoader
Instance of the :class:`TestLoader` class intended to be shared. If no
diff --git a/Doc/library/venv.rst b/Doc/library/venv.rst
index 240ab139838db9..52bf99e5bb0f67 100644
--- a/Doc/library/venv.rst
+++ b/Doc/library/venv.rst
@@ -284,11 +284,14 @@ creation according to their needs, the :class:`EnvBuilder` class.
.. method:: upgrade_dependencies(context)
- Upgrades the core venv dependency packages (currently ``pip`` and
- ``setuptools``) in the environment. This is done by shelling out to the
+ Upgrades the core venv dependency packages (currently ``pip``)
+ in the environment. This is done by shelling out to the
``pip`` executable in the environment.
.. versionadded:: 3.9
+ .. versionchanged:: 3.12
+
+ ``setuptools`` is no longer a core venv dependency.
.. method:: post_setup(context)
diff --git a/Doc/library/zipfile.rst b/Doc/library/zipfile.rst
index e2a085d6e98e67..6f4826cb065c64 100644
--- a/Doc/library/zipfile.rst
+++ b/Doc/library/zipfile.rst
@@ -7,7 +7,7 @@
.. moduleauthor:: James C. Ahlstrom
.. sectionauthor:: James C. Ahlstrom
-**Source code:** :source:`Lib/zipfile.py`
+**Source code:** :source:`Lib/zipfile/`
--------------
diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst
index ed9ebaba784bc2..55431f1951e50d 100644
--- a/Doc/reference/datamodel.rst
+++ b/Doc/reference/datamodel.rst
@@ -2089,16 +2089,25 @@ Resolving MRO entries
.. method:: object.__mro_entries__(self, bases)
If a base that appears in a class definition is not an instance of
- :class:`type`, then an ``__mro_entries__`` method is searched on the base.
- If an ``__mro_entries__`` method is found, the base is substituted with the
- result of a call to ``__mro_entries__`` when creating the class.
- The method is called with the original bases tuple, and must return a tuple
+ :class:`type`, then an :meth:`!__mro_entries__` method is searched on the base.
+ If an :meth:`!__mro_entries__` method is found, the base is substituted with the
+ result of a call to :meth:`!__mro_entries__` when creating the class.
+ The method is called with the original bases tuple
+ passed to the *bases* parameter, and must return a tuple
of classes that will be used instead of the base. The returned tuple may be
empty: in these cases, the original base is ignored.
.. seealso::
- :pep:`560` - Core support for typing module and generic types
+ :func:`types.resolve_bases`
+ Dynamically resolve bases that are not instances of :class:`type`.
+
+ :func:`types.get_original_bases`
+ Retrieve a class's "original bases" prior to modifications by
+ :meth:`~object.__mro_entries__`.
+
+ :pep:`560`
+ Core support for typing module and generic types.
Determining the appropriate metaclass
diff --git a/Doc/tools/.nitignore b/Doc/tools/.nitignore
index f6fe8df97810ff..f3350174f931aa 100644
--- a/Doc/tools/.nitignore
+++ b/Doc/tools/.nitignore
@@ -59,7 +59,6 @@ Doc/faq/gui.rst
Doc/faq/library.rst
Doc/faq/programming.rst
Doc/glossary.rst
-Doc/howto/argparse.rst
Doc/howto/curses.rst
Doc/howto/descriptor.rst
Doc/howto/enum.rst
@@ -78,7 +77,6 @@ Doc/library/__future__.rst
Doc/library/_thread.rst
Doc/library/abc.rst
Doc/library/aifc.rst
-Doc/library/argparse.rst
Doc/library/ast.rst
Doc/library/asyncio-dev.rst
Doc/library/asyncio-eventloop.rst
@@ -113,7 +111,6 @@ Doc/library/csv.rst
Doc/library/ctypes.rst
Doc/library/curses.ascii.rst
Doc/library/curses.rst
-Doc/library/dataclasses.rst
Doc/library/datetime.rst
Doc/library/dbm.rst
Doc/library/decimal.rst
@@ -180,7 +177,6 @@ Doc/library/os.rst
Doc/library/ossaudiodev.rst
Doc/library/pickle.rst
Doc/library/pickletools.rst
-Doc/library/pkgutil.rst
Doc/library/platform.rst
Doc/library/plistlib.rst
Doc/library/poplib.rst
diff --git a/Doc/using/cmdline.rst b/Doc/using/cmdline.rst
index 2a4d070ec057df..b35e8454fa2a1a 100644
--- a/Doc/using/cmdline.rst
+++ b/Doc/using/cmdline.rst
@@ -495,7 +495,8 @@ Miscellaneous options
Reserved for various implementation-specific options. CPython currently
defines the following possible values:
- * ``-X faulthandler`` to enable :mod:`faulthandler`;
+ * ``-X faulthandler`` to enable :mod:`faulthandler`.
+ See also :envvar:`PYTHONFAULTHANDLER`.
* ``-X showrefcount`` to output the total reference count and number of used
memory blocks when the program finishes or after each statement in the
interactive interpreter. This only works on :ref:`debug builds
@@ -503,8 +504,9 @@ Miscellaneous options
* ``-X tracemalloc`` to start tracing Python memory allocations using the
:mod:`tracemalloc` module. By default, only the most recent frame is
stored in a traceback of a trace. Use ``-X tracemalloc=NFRAME`` to start
- tracing with a traceback limit of *NFRAME* frames. See the
- :func:`tracemalloc.start` for more information.
+ tracing with a traceback limit of *NFRAME* frames.
+ See :func:`tracemalloc.start` and :envvar:`PYTHONTRACEMALLOC`
+ for more information.
* ``-X int_max_str_digits`` configures the :ref:`integer string conversion
length limitation `. See also
:envvar:`PYTHONINTMAXSTRDIGITS`.
@@ -519,6 +521,7 @@ Miscellaneous options
* ``-X utf8`` enables the :ref:`Python UTF-8 Mode `.
``-X utf8=0`` explicitly disables :ref:`Python UTF-8 Mode `
(even when it would otherwise activate automatically).
+ See also :envvar:`PYTHONUTF8`.
* ``-X pycache_prefix=PATH`` enables writing ``.pyc`` files to a parallel
tree rooted at the given directory instead of to the code tree. See also
:envvar:`PYTHONPYCACHEPREFIX`.
@@ -861,7 +864,9 @@ conflict.
Python memory allocations using the :mod:`tracemalloc` module. The value of
the variable is the maximum number of frames stored in a traceback of a
trace. For example, ``PYTHONTRACEMALLOC=1`` stores only the most recent
- frame. See the :func:`tracemalloc.start` for more information.
+ frame.
+ See the :func:`tracemalloc.start` function for more information.
+ This is equivalent to setting the :option:`-X` ``tracemalloc`` option.
.. versionadded:: 3.4
@@ -869,8 +874,8 @@ conflict.
.. envvar:: 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
- ``-X importtime`` on the command line.
+ show how long each import takes.
+ This is equivalent to setting the :option:`-X` ``importtime`` option.
.. versionadded:: 3.7
@@ -1012,6 +1017,7 @@ conflict.
If this environment variable is set to a non-empty string, enable
:ref:`Python Development Mode `, introducing additional runtime
checks that are too expensive to be enabled by default.
+ This is equivalent to setting the :option:`-X` ``dev`` option.
.. versionadded:: 3.7
diff --git a/Doc/using/unix.rst b/Doc/using/unix.rst
index 067ff4cce5e48d..0044eb07f56eec 100644
--- a/Doc/using/unix.rst
+++ b/Doc/using/unix.rst
@@ -54,13 +54,6 @@ On FreeBSD and OpenBSD
pkg_add ftp://ftp.openbsd.org/pub/OpenBSD/4.2/packages/i386/python-2.5.1p2.tgz
-On OpenSolaris
---------------
-
-You can get Python from `OpenCSW `_. Various versions
-of Python are available and can be installed with e.g. ``pkgutil -i python27``.
-
-
.. _building-python-on-unix:
Building Python
diff --git a/Doc/using/venv-create.inc b/Doc/using/venv-create.inc
index 43ee6b7807d57e..2fc90126482268 100644
--- a/Doc/using/venv-create.inc
+++ b/Doc/using/venv-create.inc
@@ -61,12 +61,16 @@ The command, if run with ``-h``, will show the available options::
environment (pip is bootstrapped by default)
--prompt PROMPT Provides an alternative prompt prefix for this
environment.
- --upgrade-deps Upgrade core dependencies: pip setuptools to the
+ --upgrade-deps Upgrade core dependencies (pip) to the
latest version in PyPI
Once an environment has been created, you may wish to activate it, e.g. by
sourcing an activate script in its bin directory.
+.. versionchanged:: 3.12
+
+ ``setuptools`` is no longer a core venv dependency.
+
.. versionchanged:: 3.9
Add ``--upgrade-deps`` option to upgrade pip + setuptools to the latest on PyPI
@@ -104,4 +108,3 @@ invoked to bootstrap ``pip`` into the virtual environment.
Multiple paths can be given to ``venv``, in which case an identical virtual
environment will be created, according to the given options, at each provided
path.
-
diff --git a/Doc/using/windows.rst b/Doc/using/windows.rst
index 1c4e41c0e0e239..380950eb507ffb 100644
--- a/Doc/using/windows.rst
+++ b/Doc/using/windows.rst
@@ -470,7 +470,7 @@ user's system, including environment variables, system registry settings, and
installed packages. The standard library is included as pre-compiled and
optimized ``.pyc`` files in a ZIP, and ``python3.dll``, ``python37.dll``,
``python.exe`` and ``pythonw.exe`` are all provided. Tcl/tk (including all
-dependants, such as Idle), pip and the Python documentation are not included.
+dependents, such as Idle), pip and the Python documentation are not included.
.. note::
diff --git a/Doc/whatsnew/2.6.rst b/Doc/whatsnew/2.6.rst
index 34f2656f765c7d..4ee2aacb108a36 100644
--- a/Doc/whatsnew/2.6.rst
+++ b/Doc/whatsnew/2.6.rst
@@ -172,7 +172,7 @@ this edition of "What's New in Python" links to the bug/patch
item for each change.
Hosting of the Python bug tracker is kindly provided by
-`Upfront Systems `__
+`Upfront Systems `__
of Stellenbosch, South Africa. Martin von Löwis put a
lot of effort into importing existing bugs and patches from
SourceForge; his scripts for this import operation are at
diff --git a/Doc/whatsnew/2.7.rst b/Doc/whatsnew/2.7.rst
index 810a2cd2537c34..36afcb163f1afc 100644
--- a/Doc/whatsnew/2.7.rst
+++ b/Doc/whatsnew/2.7.rst
@@ -2104,7 +2104,7 @@ Changes to Python's build process and to the C API include:
* The latest release of the GNU Debugger, GDB 7, can be `scripted
using Python
- `__.
+ `__.
When you begin debugging an executable program P, GDB will look for
a file named ``P-gdb.py`` and automatically read it. Dave Malcolm
contributed a :file:`python-gdb.py` that adds a number of
diff --git a/Doc/whatsnew/3.12.rst b/Doc/whatsnew/3.12.rst
index 66e40ef7326cc0..9a32f985c6a05a 100644
--- a/Doc/whatsnew/3.12.rst
+++ b/Doc/whatsnew/3.12.rst
@@ -137,6 +137,13 @@ New Features
(Design by Pablo Galindo. Contributed by Pablo Galindo and Christian Heimes
with contributions from Gregory P. Smith [Google] and Mark Shannon
in :gh:`96123`.)
+* The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`,
+ have a new a *filter* argument that allows limiting tar features than may be
+ surprising or dangerous, such as creating files outside the destination
+ directory.
+ See :ref:`tarfile-extraction-filter` for details.
+ In Python 3.14, the default will switch to ``'data'``.
+ (Contributed by Petr Viktorin in :pep:`706`.)
Other Language Changes
@@ -192,6 +199,10 @@ Other Language Changes
* :class:`slice` objects are now hashable, allowing them to be used as dict keys and
set items. (Contributed by Will Bradshaw and Furkan Onder in :gh:`101264`.)
+* Exceptions raised in a typeobject's ``__set_name__`` method are no longer
+ wrapped by a :exc:`RuntimeError`. Context information is added to the
+ exception as a :pep:`678` note. (Contributed by Irit Katriel in :gh:`77757`.)
+
New Modules
===========
@@ -210,6 +221,11 @@ array
asyncio
-------
+* The performance of writing to sockets in :mod:`asyncio` has been
+ significantly improved. ``asyncio`` now avoids unnecessary copying when
+ writing to sockets and uses :meth:`~socket.socket.sendmsg` if the platform
+ supports it. (Contributed by Kumar Aditya in :gh:`91166`.)
+
* On Linux, :mod:`asyncio` uses :class:`~asyncio.PidfdChildWatcher` by default
if :func:`os.pidfd_open` is available and functional instead of
:class:`~asyncio.ThreadedChildWatcher`.
@@ -241,9 +257,17 @@ asyncio
:mod:`asyncio` does not support legacy generator-based coroutines.
(Contributed by Kumar Aditya in :gh:`102748`.)
-* :func:`asyncio.wait` now accepts generators yielding tasks.
+* :func:`asyncio.wait` and :func:`asyncio.as_completed` now accepts generators
+ yielding tasks.
(Contributed by Kumar Aditya in :gh:`78530`.)
+csv
+---
+
+* Add :data:`~csv.QUOTE_NOTNULL` and :data:`~csv.QUOTE_STRINGS` flags to
+ provide finer grained control of ``None`` and empty strings by
+ :class:`~csv.writer` objects.
+
inspect
-------
@@ -292,6 +316,13 @@ fractions
* Objects of type :class:`fractions.Fraction` now support float-style
formatting. (Contributed by Mark Dickinson in :gh:`100161`.)
+itertools
+---------
+
+* Added :class:`itertools.batched()` for collecting into even-sized
+ tuples where the last batch may be shorter than the rest.
+ (Contributed by Raymond Hettinger in :gh:`98363`.)
+
math
----
@@ -383,6 +414,13 @@ threading
profiling functions in all running threads in addition to the calling one.
(Contributed by Pablo Galindo in :gh:`93503`.)
+types
+-----
+
+* Add :func:`types.get_original_bases` to allow for further introspection of
+ :ref:`user-defined-generics` when subclassed. (Contributed by
+ James Hilton-Balfe and Alex Waygood in :gh:`101827`.)
+
unicodedata
-----------
@@ -419,8 +457,10 @@ uuid
tempfile
--------
-The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter
-*delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.)
+* The :class:`tempfile.NamedTemporaryFile` function has a new optional parameter
+ *delete_on_close* (Contributed by Evgeny Zorin in :gh:`58451`.)
+* :func:`tempfile.mkdtemp` now always returns an absolute path, even if the
+ argument provided to the *dir* parameter is a relative path.
.. _whatsnew-typing-py312:
@@ -494,6 +534,10 @@ sys
:data:`sys.last_type`, :data:`sys.last_value` and :data:`sys.last_traceback`.
(Contributed by Irit Katriel in :gh:`102778`.)
+* :func:`sys._current_exceptions` now returns a mapping from thread-id to an
+ exception instance, rather than to a ``(typ, exc, tb)`` tuple.
+ (Contributed by Irit Katriel in :gh:`103176`.)
+
Optimizations
=============
@@ -595,6 +639,10 @@ Deprecated
* The *onerror* argument of :func:`shutil.rmtree` is deprecated as will be removed
in Python 3.14. Use *onexc* instead. (Contributed by Irit Katriel in :gh:`102828`.)
+* Extracting tar archives without specifying *filter* is deprecated until
+ Python 3.14, when ``'data'`` filter will become the default.
+ See :ref:`tarfile-extraction-filter` for details.
+
Pending Removal in Python 3.13
------------------------------
@@ -711,6 +759,24 @@ Removed
project can be installed: it still provides ``distutils``.
(Contributed by Victor Stinner in :gh:`92584`.)
+* Remove the bundled setuptools wheel from :mod:`ensurepip`,
+ and stop installing setuptools in environments created by :mod:`venv`.
+
+ ``pip (>= 22.1)`` does not require setuptools to be installed in the
+ environment. ``setuptools``-based (and ``distutils``-based) packages
+ can still be used with ``pip install``, since pip will provide
+ ``setuptools`` in the build environment it uses for building a
+ package.
+
+ ``easy_install``, ``pkg_resources``, ``setuptools`` and ``distutils``
+ are no longer provided by default in environments created with
+ ``venv`` or bootstrapped with ``ensurepip``, since they are part of
+ the ``setuptools`` package. For projects relying on these at runtime,
+ the ``setuptools`` project should be declared as a dependency and
+ installed separately (typically, using pip).
+
+ (Contributed by Pradyun Gedam in :gh:`95299`.)
+
* Removed many old deprecated :mod:`unittest` features:
- A number of :class:`~unittest.TestCase` method aliases:
@@ -935,6 +1001,14 @@ Changes in the Python API
synchronization is needed, implement locking within the cached property getter
function or around multi-threaded access points.
+* :func:`sys._current_exceptions` now returns a mapping from thread-id to an
+ exception instance, rather than to a ``(typ, exc, tb)`` tuple.
+ (Contributed by Irit Katriel in :gh:`103176`.)
+
+* When extracting tar files using :mod:`tarfile` or
+ :func:`shutil.unpack_archive`, pass the *filter* argument to limit features
+ that may be surprising or dangerous.
+ See :ref:`tarfile-extraction-filter` for details.
Build Changes
=============
@@ -1079,6 +1153,24 @@ New Features
to replace the legacy-api :c:func:`!PyErr_Display`. (Contributed by
Irit Katriel in :gh:`102755`).
+* :pep:`683`: Introduced Immortal Objects to Python which allows objects
+ to bypass reference counts and introduced changes to the C-API:
+
+ - ``_Py_IMMORTAL_REFCNT``: The reference count that defines an object
+ as immortal.
+ - ``_Py_IsImmortal`` Checks if an object has the immortal reference count.
+ - ``PyObject_HEAD_INIT`` This will now initialize reference count to
+ ``_Py_IMMORTAL_REFCNT`` when used with ``Py_BUILD_CORE``.
+ - ``SSTATE_INTERNED_IMMORTAL`` An identifier for interned unicode objects
+ that are immortal.
+ - ``SSTATE_INTERNED_IMMORTAL_STATIC`` An identifier for interned unicode
+ objects that are immortal and static
+ - ``sys.getunicodeinternedsize`` This returns the total number of unicode
+ objects that have been interned. This is now needed for refleak.py to
+ correctly track reference counts and allocated blocks
+
+ (Contributed by Eddie Elizondo in :gh:`84436`.)
+
Porting to Python 3.12
----------------------
@@ -1243,8 +1335,7 @@ Removed
* :c:func:`!PyUnicode_GetSize`
* :c:func:`!PyUnicode_GET_DATA_SIZE`
-* Remove the ``PyUnicode_InternImmortal()`` function and the
- ``SSTATE_INTERNED_IMMORTAL`` macro.
+* Remove the ``PyUnicode_InternImmortal()`` function macro.
(Contributed by Victor Stinner in :gh:`85858`.)
* Remove ``Jython`` compatibility hacks from several stdlib modules and tests.
diff --git a/Grammar/Tokens b/Grammar/Tokens
index 1f3e3b09913653..096876fdd130f8 100644
--- a/Grammar/Tokens
+++ b/Grammar/Tokens
@@ -53,6 +53,7 @@ ATEQUAL '@='
RARROW '->'
ELLIPSIS '...'
COLONEQUAL ':='
+EXCLAMATION '!'
OP
AWAIT
@@ -60,6 +61,9 @@ ASYNC
TYPE_IGNORE
TYPE_COMMENT
SOFT_KEYWORD
+FSTRING_START
+FSTRING_MIDDLE
+FSTRING_END
ERRORTOKEN
# These aren't used by the C tokenizer but are needed for tokenize.py
diff --git a/Grammar/python.gram b/Grammar/python.gram
index 6ab09de4fc149a..0851c7c8a8b8ba 100644
--- a/Grammar/python.gram
+++ b/Grammar/python.gram
@@ -195,7 +195,7 @@ yield_stmt[stmt_ty]: y=yield_expr { _PyAST_Expr(y, EXTRA) }
assert_stmt[stmt_ty]: 'assert' a=expression b=[',' z=expression { z }] { _PyAST_Assert(a, b, EXTRA) }
-import_stmt[stmt_ty]:
+import_stmt[stmt_ty]:
| invalid_import
| import_name
| import_from
@@ -416,8 +416,8 @@ try_stmt[stmt_ty]:
| invalid_try_stmt
| 'try' &&':' b=block f=finally_block { _PyAST_Try(b, NULL, NULL, f, EXTRA) }
| 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_block+ el=[else_block] f=[finally_block] { _PyAST_Try(b, ex, el, f, EXTRA) }
- | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] {
- CHECK_VERSION(stmt_ty, 11, "Exception groups are",
+ | 'try' &&':' b=block ex[asdl_excepthandler_seq*]=except_star_block+ el=[else_block] f=[finally_block] {
+ CHECK_VERSION(stmt_ty, 11, "Exception groups are",
_PyAST_TryStar(b, ex, el, f, EXTRA)) }
@@ -830,7 +830,7 @@ atom[expr_ty]:
| 'True' { _PyAST_Constant(Py_True, NULL, EXTRA) }
| 'False' { _PyAST_Constant(Py_False, NULL, EXTRA) }
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
- | &STRING strings
+ | &(STRING|FSTRING_START) strings
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
@@ -900,7 +900,26 @@ lambda_param[arg_ty]: a=NAME { _PyAST_arg(a->v.Name.id, NULL, NULL, EXTRA) }
# LITERALS
# ========
-strings[expr_ty] (memo): a=STRING+ { _PyPegen_concatenate_strings(p, a) }
+fstring_middle[expr_ty]:
+ | fstring_replacement_field
+ | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
+fstring_replacement_field[expr_ty]:
+ | '{' a=(yield_expr | star_expressions) debug_expr="="? conversion=[fstring_conversion] format=[fstring_full_format_spec] '}' {
+ _PyPegen_formatted_value(p, a, debug_expr, conversion, format, EXTRA)
+ }
+ | invalid_replacement_field
+fstring_conversion[expr_ty]:
+ | conv_token="!" conv=NAME { _PyPegen_check_fstring_conversion(p, conv_token, conv) }
+fstring_full_format_spec[expr_ty]:
+ | ':' spec=fstring_format_spec* { spec ? _PyAST_JoinedStr((asdl_expr_seq*)spec, EXTRA) : NULL }
+fstring_format_spec[expr_ty]:
+ | t=FSTRING_MIDDLE { _PyPegen_constant_from_token(p, t) }
+ | fstring_replacement_field
+fstring[expr_ty]:
+ | a=FSTRING_START b=fstring_middle* c=FSTRING_END { _PyPegen_joined_str(p, a, (asdl_expr_seq*)b, c) }
+
+string[expr_ty]: s[Token*]=STRING { _PyPegen_constant_from_string(p, s) }
+strings[expr_ty] (memo): a[asdl_expr_seq*]=(fstring|string)+ { _PyPegen_concatenate_strings(p, a, EXTRA) }
list[expr_ty]:
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
@@ -1141,6 +1160,8 @@ invalid_expression:
_PyPegen_check_legacy_stmt(p, a) ? NULL : p->tokens[p->mark-1]->level == 0 ? NULL :
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid syntax. Perhaps you forgot a comma?") }
| a=disjunction 'if' b=disjunction !('else'|':') { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "expected 'else' after 'if' expression") }
+ | a='lambda' [lambda_params] b=':' &(FSTRING_MIDDLE | fstring_replacement_field) {
+ RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "f-string: lambda expressions are not allowed without parentheses") }
invalid_named_expression(memo):
| a=expression ':=' expression {
@@ -1264,7 +1285,7 @@ invalid_group:
invalid_import:
| a='import' dotted_name 'from' dotted_name {
RAISE_SYNTAX_ERROR_STARTING_FROM(a, "Did you mean to use 'from ... import ...' instead?") }
-
+
invalid_import_from_targets:
| import_from_as_names ',' NEWLINE {
RAISE_SYNTAX_ERROR("trailing comma not allowed without surrounding parentheses") }
@@ -1358,3 +1379,24 @@ invalid_kvpair:
| expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_starred_expression:
| a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") }
+invalid_replacement_field:
+ | '{' a='=' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '='") }
+ | '{' a='!' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '!'") }
+ | '{' a=':' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before ':'") }
+ | '{' a='}' { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "f-string: valid expression required before '}'") }
+ | '{' !(yield_expr | star_expressions) { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting a valid expression after '{'")}
+ | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}') {
+ PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '=', or '!', or ':', or '}'") }
+ | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}') {
+ PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '!', or ':', or '}'") }
+ | '{' (yield_expr | star_expressions) '='? invalid_conversion_character
+ | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}') {
+ PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting ':' or '}'") }
+ | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}' {
+ PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}', or format specs") }
+ | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}' {
+ PyErr_Occurred() ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: expecting '}'") }
+
+invalid_conversion_character:
+ | '!' &(':' | '}') { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: missing conversion character") }
+ | '!' !NAME { RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN("f-string: invalid conversion character") }
diff --git a/Include/boolobject.h b/Include/boolobject.h
index ca21fbfad8e827..976fa35201d035 100644
--- a/Include/boolobject.h
+++ b/Include/boolobject.h
@@ -11,8 +11,7 @@ PyAPI_DATA(PyTypeObject) PyBool_Type;
#define PyBool_Check(x) Py_IS_TYPE((x), &PyBool_Type)
-/* Py_False and Py_True are the only two bools in existence.
-Don't forget to apply Py_INCREF() when returning either!!! */
+/* Py_False and Py_True are the only two bools in existence. */
/* Don't use these directly */
PyAPI_DATA(PyLongObject) _Py_FalseStruct;
@@ -31,8 +30,8 @@ PyAPI_FUNC(int) Py_IsFalse(PyObject *x);
#define Py_IsFalse(x) Py_Is((x), Py_False)
/* Macros for returning Py_True or Py_False, respectively */
-#define Py_RETURN_TRUE return Py_NewRef(Py_True)
-#define Py_RETURN_FALSE return Py_NewRef(Py_False)
+#define Py_RETURN_TRUE return Py_True
+#define Py_RETURN_FALSE return Py_False
/* Function to return a bool from a C long */
PyAPI_FUNC(PyObject *) PyBool_FromLong(long);
diff --git a/Include/cpython/code.h b/Include/cpython/code.h
index abcf1250603dfe..6bead361c79245 100644
--- a/Include/cpython/code.h
+++ b/Include/cpython/code.h
@@ -3,10 +3,22 @@
#ifndef Py_LIMITED_API
#ifndef Py_CODE_H
#define Py_CODE_H
+
#ifdef __cplusplus
extern "C" {
#endif
+
+/* Count of all "real" monitoring events (not derived from other events) */
+#define PY_MONITORING_UNGROUPED_EVENTS 14
+/* Count of all monitoring events */
+#define PY_MONITORING_EVENTS 16
+
+/* Table of which tools are active for each monitored event. */
+typedef struct _Py_Monitors {
+ uint8_t tools[PY_MONITORING_UNGROUPED_EVENTS];
+} _Py_Monitors;
+
/* Each instruction in a code object is a fixed-width value,
* currently 2 bytes: 1-byte opcode + 1-byte oparg. The EXTENDED_ARG
* opcode allows for larger values but the current limit is 3 uses
@@ -56,6 +68,35 @@ typedef struct {
PyObject *_co_freevars;
} _PyCoCached;
+/* Ancilliary data structure used for instrumentation.
+ Line instrumentation creates an array of
+ these. One entry per code unit.*/
+typedef struct {
+ uint8_t original_opcode;
+ int8_t line_delta;
+} _PyCoLineInstrumentationData;
+
+/* Main data structure used for instrumentation.
+ * This is allocated when needed for instrumentation
+ */
+typedef struct {
+ /* Monitoring specific to this code object */
+ _Py_Monitors local_monitors;
+ /* Monitoring that is active on this code object */
+ _Py_Monitors active_monitors;
+ /* The tools that are to be notified for events for the matching code unit */
+ uint8_t *tools;
+ /* Information to support line events */
+ _PyCoLineInstrumentationData *lines;
+ /* The tools that are to be notified for line events for the matching code unit */
+ uint8_t *line_tools;
+ /* Information to support instruction events */
+ /* The underlying instructions, which can themselves be instrumented */
+ uint8_t *per_instruction_opcodes;
+ /* The tools that are to be notified for instruction events for the matching code unit */
+ uint8_t *per_instruction_tools;
+} _PyCoMonitoringData;
+
// To avoid repeating ourselves in deepfreeze.py, all PyCodeObject members are
// defined in this macro:
#define _PyCode_DEF(SIZE) { \
@@ -87,7 +128,6 @@ typedef struct {
PyObject *co_exceptiontable; /* Byte string encoding exception handling \
table */ \
int co_flags; /* CO_..., see below */ \
- short _co_linearray_entry_size; /* Size of each entry in _co_linearray */ \
\
/* The rest are not so impactful on performance. */ \
int co_argcount; /* #arguments, except *args */ \
@@ -114,8 +154,9 @@ typedef struct {
PyObject *co_linetable; /* bytes object that holds location info */ \
PyObject *co_weakreflist; /* to support weakrefs to code objects */ \
_PyCoCached *_co_cached; /* cached co_* attributes */ \
+ uint64_t _co_instrumentation_version; /* current instrumentation version */ \
+ _PyCoMonitoringData *_co_monitoring; /* Monitoring data */ \
int _co_firsttraceable; /* index of first traceable instruction */ \
- char *_co_linearray; /* array of line offsets */ \
/* Scratch space for extra data relating to the code object. \
Type is a void* to keep the format private in codeobject.c to force \
people to go through the proper APIs. */ \
diff --git a/Include/cpython/initconfig.h b/Include/cpython/initconfig.h
index 8bc681b1a93f5c..79c1023baa9a0f 100644
--- a/Include/cpython/initconfig.h
+++ b/Include/cpython/initconfig.h
@@ -245,6 +245,8 @@ PyAPI_FUNC(PyStatus) PyConfig_SetWideStringList(PyConfig *config,
/* --- PyInterpreterConfig ------------------------------------ */
typedef struct {
+ // XXX "allow_object_sharing"? "own_objects"?
+ int use_main_obmalloc;
int allow_fork;
int allow_exec;
int allow_threads;
@@ -254,6 +256,7 @@ typedef struct {
#define _PyInterpreterConfig_INIT \
{ \
+ .use_main_obmalloc = 0, \
.allow_fork = 0, \
.allow_exec = 0, \
.allow_threads = 1, \
@@ -263,6 +266,7 @@ typedef struct {
#define _PyInterpreterConfig_LEGACY_INIT \
{ \
+ .use_main_obmalloc = 1, \
.allow_fork = 1, \
.allow_exec = 1, \
.allow_threads = 1, \
diff --git a/Include/cpython/object.h b/Include/cpython/object.h
index 98cc51cd7fee49..ce4d13cd9c28fe 100644
--- a/Include/cpython/object.h
+++ b/Include/cpython/object.h
@@ -564,3 +564,10 @@ PyAPI_FUNC(int) PyType_AddWatcher(PyType_WatchCallback callback);
PyAPI_FUNC(int) PyType_ClearWatcher(int watcher_id);
PyAPI_FUNC(int) PyType_Watch(int watcher_id, PyObject *type);
PyAPI_FUNC(int) PyType_Unwatch(int watcher_id, PyObject *type);
+
+/* Attempt to assign a version tag to the given type.
+ *
+ * Returns 1 if the type already had a valid version tag or a new one was
+ * assigned, or 0 if a new tag could not be assigned.
+ */
+PyAPI_FUNC(int) PyUnstable_Type_AssignVersionTag(PyTypeObject *type);
diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index 3efb241e8237e7..f33c72d4cf4d2a 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -11,6 +11,10 @@ is available in a given context. For example, forking the process
might not be allowed in the current interpreter (i.e. os.fork() would fail).
*/
+/* Set if the interpreter share obmalloc runtime state
+ with the main interpreter. */
+#define Py_RTFLAGS_USE_MAIN_OBMALLOC (1UL << 5)
+
/* Set if import should check a module for subinterpreter support. */
#define Py_RTFLAGS_MULTI_INTERP_EXTENSIONS (1UL << 8)
@@ -58,12 +62,6 @@ typedef int (*Py_tracefunc)(PyObject *, PyFrameObject *, int, PyObject *);
#define PyTrace_C_RETURN 6
#define PyTrace_OPCODE 7
-
-typedef struct {
- PyCodeObject *code; // The code object for the bounds. May be NULL.
- PyCodeAddressRange bounds; // Only valid if code != NULL.
-} PyTraceInfo;
-
// Internal structure: you should not use it directly, but use public functions
// like PyThreadState_EnterTracing() and PyThreadState_LeaveTracing().
typedef struct _PyCFrame {
@@ -77,7 +75,6 @@ typedef struct _PyCFrame {
* discipline and make sure that instances of this struct cannot
* accessed outside of their lifetime.
*/
- uint8_t use_tracing; // 0 or 255 (or'ed into opcode, hence 8-bit type)
/* Pointer to the currently executing frame (it can be NULL) */
struct _PyInterpreterFrame *current_frame;
struct _PyCFrame *previous;
@@ -157,7 +154,7 @@ struct _ts {
This is to prevent the actual trace/profile code from being recorded in
the trace/profile. */
int tracing;
- int tracing_what; /* The event currently being traced, if any. */
+ 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. */
@@ -228,8 +225,6 @@ struct _ts {
/* Unique thread state id. */
uint64_t id;
- PyTraceInfo trace_info;
-
_PyStackChunk *datastack_chunk;
PyObject **datastack_top;
PyObject **datastack_limit;
diff --git a/Include/cpython/unicodeobject.h b/Include/cpython/unicodeobject.h
index 75a74ffa2f9dff..3394726dfffd72 100644
--- a/Include/cpython/unicodeobject.h
+++ b/Include/cpython/unicodeobject.h
@@ -98,9 +98,16 @@ typedef struct {
Py_ssize_t length; /* Number of code points in the string */
Py_hash_t hash; /* Hash value; -1 if not set */
struct {
- /* If interned is set, the two references from the
- dictionary to this object are *not* counted in ob_refcnt. */
- unsigned int interned:1;
+ /* If interned is non-zero, the two references from the
+ dictionary to this object are *not* counted in ob_refcnt.
+ The possible values here are:
+ 0: Not Interned
+ 1: Interned
+ 2: Interned and Immortal
+ 3: Interned, Immortal, and Static
+ This categorization allows the runtime to determine the right
+ cleanup mechanism at runtime shutdown. */
+ unsigned int interned:2;
/* Character size:
- PyUnicode_1BYTE_KIND (1):
@@ -135,7 +142,7 @@ typedef struct {
unsigned int ascii:1;
/* Padding to ensure that PyUnicode_DATA() is always aligned to
4 bytes (see issue #19537 on m68k). */
- unsigned int :26;
+ unsigned int :25;
} state;
} PyASCIIObject;
@@ -183,6 +190,8 @@ PyAPI_FUNC(int) _PyUnicode_CheckConsistency(
/* Interning state. */
#define SSTATE_NOT_INTERNED 0
#define SSTATE_INTERNED_MORTAL 1
+#define SSTATE_INTERNED_IMMORTAL 2
+#define SSTATE_INTERNED_IMMORTAL_STATIC 3
/* Use only if you know it's a string */
static inline unsigned int PyUnicode_CHECK_INTERNED(PyObject *op) {
diff --git a/Include/internal/pycore_code.h b/Include/internal/pycore_code.h
index faf1be585e17ef..7d5d5e03de9e41 100644
--- a/Include/internal/pycore_code.h
+++ b/Include/internal/pycore_code.h
@@ -51,6 +51,15 @@ typedef struct {
#define INLINE_CACHE_ENTRIES_BINARY_SUBSCR CACHE_ENTRIES(_PyBinarySubscrCache)
+typedef struct {
+ uint16_t counter;
+ uint16_t class_version[2];
+ uint16_t self_type_version[2];
+ uint16_t method[4];
+} _PySuperAttrCache;
+
+#define INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR CACHE_ENTRIES(_PySuperAttrCache)
+
typedef struct {
uint16_t counter;
uint16_t version[2];
@@ -217,6 +226,8 @@ extern int _PyLineTable_PreviousAddressRange(PyCodeAddressRange *range);
/* Specialization functions */
+extern void _Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *class, PyObject *self,
+ _Py_CODEUNIT *instr, PyObject *name, int load_method);
extern void _Py_Specialize_LoadAttr(PyObject *owner, _Py_CODEUNIT *instr,
PyObject *name);
extern void _Py_Specialize_StoreAttr(PyObject *owner, _Py_CODEUNIT *instr,
@@ -441,32 +452,6 @@ adaptive_counter_backoff(uint16_t counter) {
/* Line array cache for tracing */
-extern int _PyCode_CreateLineArray(PyCodeObject *co);
-
-static inline int
-_PyCode_InitLineArray(PyCodeObject *co)
-{
- if (co->_co_linearray) {
- return 0;
- }
- return _PyCode_CreateLineArray(co);
-}
-
-static inline int
-_PyCode_LineNumberFromArray(PyCodeObject *co, int index)
-{
- assert(co->_co_linearray != NULL);
- assert(index >= 0);
- assert(index < Py_SIZE(co));
- if (co->_co_linearray_entry_size == 2) {
- return ((int16_t *)co->_co_linearray)[index];
- }
- else {
- assert(co->_co_linearray_entry_size == 4);
- return ((int32_t *)co->_co_linearray)[index];
- }
-}
-
typedef struct _PyShimCodeDef {
const uint8_t *code;
int codelen;
@@ -500,6 +485,10 @@ extern uint32_t _Py_next_func_version;
#define COMPARISON_NOT_EQUALS (COMPARISON_UNORDERED | COMPARISON_LESS_THAN | COMPARISON_GREATER_THAN)
+extern int _Py_Instrument(PyCodeObject *co, PyInterpreterState *interp);
+
+extern int _Py_GetBaseOpcode(PyCodeObject *code, int offset);
+
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_compile.h b/Include/internal/pycore_compile.h
index 6a1e02c0b895d7..f85240c48a89b0 100644
--- a/Include/internal/pycore_compile.h
+++ b/Include/internal/pycore_compile.h
@@ -33,6 +33,45 @@ extern int _PyAST_Optimize(
struct _arena *arena,
_PyASTOptimizeState *state);
+
+typedef struct {
+ int i_opcode;
+ int i_oparg;
+ _PyCompilerSrcLocation i_loc;
+} _PyCompilerInstruction;
+
+typedef struct {
+ _PyCompilerInstruction *s_instrs;
+ int s_allocated;
+ int s_used;
+
+ int *s_labelmap; /* label id --> instr offset */
+ int s_labelmap_size;
+ int s_next_free_label; /* next free label id */
+} _PyCompile_InstructionSequence;
+
+typedef struct {
+ PyObject *u_name;
+ PyObject *u_qualname; /* dot-separated qualified name (lazy) */
+
+ /* The following fields are dicts that map objects to
+ the index of them in co_XXX. The index is used as
+ the argument for opcodes that refer to those collections.
+ */
+ PyObject *u_consts; /* all constants */
+ PyObject *u_names; /* all names */
+ PyObject *u_varnames; /* local variables */
+ PyObject *u_cellvars; /* cell variables */
+ PyObject *u_freevars; /* free variables */
+
+ Py_ssize_t u_argcount; /* number of arguments for block */
+ Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */
+ Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
+
+ int u_firstlineno; /* the first lineno of the block */
+} _PyCompile_CodeUnitMetadata;
+
+
/* Utility for a number of growing arrays used in the compiler */
int _PyCompile_EnsureArrayLargeEnough(
int idx,
diff --git a/Include/internal/pycore_flowgraph.h b/Include/internal/pycore_flowgraph.h
index 7c0b8fe980c3c7..f470dad3aaa459 100644
--- a/Include/internal/pycore_flowgraph.h
+++ b/Include/internal/pycore_flowgraph.h
@@ -9,6 +9,7 @@ extern "C" {
#endif
#include "pycore_opcode_utils.h"
+#include "pycore_compile.h"
static const _PyCompilerSrcLocation NO_LOCATION = {-1, -1, -1, -1};
@@ -33,7 +34,8 @@ typedef struct {
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, not to be confused with b_next, which is next by control flow. */
+ 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;
@@ -91,10 +93,9 @@ void _PyCfgBuilder_Fini(_PyCfgBuilder *g);
_PyCfgInstruction* _PyCfg_BasicblockLastInstr(const _PyCfgBasicblock *b);
int _PyCfg_OptimizeCodeUnit(_PyCfgBuilder *g, PyObject *consts, PyObject *const_cache,
- int code_flags, int nlocals, int nparams);
+ int code_flags, int nlocals, int nparams, int firstlineno);
int _PyCfg_Stackdepth(_PyCfgBasicblock *entryblock, int code_flags);
void _PyCfg_ConvertExceptionHandlersToNops(_PyCfgBasicblock *entryblock);
-int _PyCfg_ResolveLineNumbers(_PyCfgBuilder *g, int firstlineno);
int _PyCfg_ResolveJumps(_PyCfgBuilder *g);
int _PyCfg_InstrSize(_PyCfgInstruction *instruction);
@@ -110,6 +111,10 @@ basicblock_nofallthrough(const _PyCfgBasicblock *b) {
#define BB_NO_FALLTHROUGH(B) (basicblock_nofallthrough(B))
#define BB_HAS_FALLTHROUGH(B) (!basicblock_nofallthrough(B))
+PyCodeObject *
+_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *u, PyObject *const_cache,
+ PyObject *consts, int maxdepth, _PyCfgBasicblock *entryblock,
+ int nlocalsplus, int code_flags, PyObject *filename);
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_frame.h b/Include/internal/pycore_frame.h
index 5806cf05f174a9..20d48d20362571 100644
--- a/Include/internal/pycore_frame.h
+++ b/Include/internal/pycore_frame.h
@@ -19,6 +19,7 @@ struct _frame {
struct _PyInterpreterFrame *f_frame; /* points to the frame data */
PyObject *f_trace; /* Trace function */
int f_lineno; /* Current line number. Only valid if non-zero */
+ int f_last_traced_line; /* The last line traced for this frame */
char f_trace_lines; /* Emit per-line trace events? */
char f_trace_opcodes; /* Emit per-opcode trace events? */
char f_fast_as_locals; /* Have the fast locals of this frame been converted to a dict? */
@@ -60,7 +61,13 @@ typedef struct _PyInterpreterFrame {
// over, or (in the case of a newly-created frame) a totally invalid value:
_Py_CODEUNIT *prev_instr;
int stacktop; /* Offset of TOS from localsplus */
- uint16_t yield_offset;
+ /* The return_offset determines where a `RETURN` should go in the caller,
+ * relative to `prev_instr`.
+ * It is only meaningful to the callee,
+ * so it needs to be set in any CALL (to a Python function)
+ * or SEND (to a coroutine or generator).
+ * If there is no callee, then it is meaningless. */
+ uint16_t return_offset;
char owner;
/* Locals and stack */
PyObject *localsplus[1];
@@ -120,7 +127,7 @@ _PyFrame_Initialize(
frame->stacktop = code->co_nlocalsplus;
frame->frame_obj = NULL;
frame->prev_instr = _PyCode_CODE(code) - 1;
- frame->yield_offset = 0;
+ frame->return_offset = 0;
frame->owner = FRAME_OWNED_BY_THREAD;
for (int i = null_locals_from; i < code->co_nlocalsplus; i++) {
@@ -137,10 +144,16 @@ _PyFrame_GetLocalsArray(_PyInterpreterFrame *frame)
return frame->localsplus;
}
+/* Fetches the stack pointer, and sets stacktop to -1.
+ Having stacktop <= 0 ensures that invalid
+ values are not visible to the cycle GC.
+ We choose -1 rather than 0 to assist debugging. */
static inline PyObject**
_PyFrame_GetStackPointer(_PyInterpreterFrame *frame)
{
- return frame->localsplus+frame->stacktop;
+ PyObject **sp = frame->localsplus + frame->stacktop;
+ frame->stacktop = -1;
+ return sp;
}
static inline void
diff --git a/Include/internal/pycore_global_objects_fini_generated.h b/Include/internal/pycore_global_objects_fini_generated.h
index 6474586ec4ab93..9afd78fdca8fa1 100644
--- a/Include/internal/pycore_global_objects_fini_generated.h
+++ b/Include/internal/pycore_global_objects_fini_generated.h
@@ -8,15 +8,13 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_object.h" // _PyObject_IMMORTAL_REFCNT
-
#ifdef Py_DEBUG
static inline void
_PyStaticObject_CheckRefcnt(PyObject *obj) {
- if (Py_REFCNT(obj) < _PyObject_IMMORTAL_REFCNT) {
+ if (Py_REFCNT(obj) < _Py_IMMORTAL_REFCNT) {
_PyObject_ASSERT_FAILED_MSG(obj,
"immortal object has less refcnt than expected "
- "_PyObject_IMMORTAL_REFCNT");
+ "_Py_IMMORTAL_REFCNT");
}
}
#endif
diff --git a/Include/internal/pycore_import.h b/Include/internal/pycore_import.h
index 7a78a91aa617e6..0a9f24efbdb908 100644
--- a/Include/internal/pycore_import.h
+++ b/Include/internal/pycore_import.h
@@ -19,6 +19,8 @@ struct _import_runtime_state {
used exclusively for when the extensions dict is access/modified
from an arbitrary thread. */
PyThreadState main_tstate;
+ /* A lock to guard the dict. */
+ PyThread_type_lock mutex;
/* A dict mapping (filename, name) to PyModuleDef for modules.
Only legacy (single-phase init) extension modules are added
and only if they support multiple initialization (m_size >- 0)
diff --git a/Include/internal/pycore_instruments.h b/Include/internal/pycore_instruments.h
new file mode 100644
index 00000000000000..e94d8755546efd
--- /dev/null
+++ b/Include/internal/pycore_instruments.h
@@ -0,0 +1,107 @@
+
+#ifndef Py_INTERNAL_INSTRUMENT_H
+#define Py_INTERNAL_INSTRUMENT_H
+
+
+#include "pycore_bitutils.h" // _Py_popcount32
+#include "pycore_frame.h"
+
+#include "cpython/code.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PY_MONITORING_TOOL_IDS 8
+
+/* Local events.
+ * These require bytecode instrumentation */
+
+#define PY_MONITORING_EVENT_PY_START 0
+#define PY_MONITORING_EVENT_PY_RESUME 1
+#define PY_MONITORING_EVENT_PY_RETURN 2
+#define PY_MONITORING_EVENT_PY_YIELD 3
+#define PY_MONITORING_EVENT_CALL 4
+#define PY_MONITORING_EVENT_LINE 5
+#define PY_MONITORING_EVENT_INSTRUCTION 6
+#define PY_MONITORING_EVENT_JUMP 7
+#define PY_MONITORING_EVENT_BRANCH 8
+#define PY_MONITORING_EVENT_STOP_ITERATION 9
+
+#define PY_MONITORING_INSTRUMENTED_EVENTS 10
+
+/* Other events, mainly exceptions */
+
+#define PY_MONITORING_EVENT_RAISE 10
+#define PY_MONITORING_EVENT_EXCEPTION_HANDLED 11
+#define PY_MONITORING_EVENT_PY_UNWIND 12
+#define PY_MONITORING_EVENT_PY_THROW 13
+
+
+/* Ancilliary events */
+
+#define PY_MONITORING_EVENT_C_RETURN 14
+#define PY_MONITORING_EVENT_C_RAISE 15
+
+
+typedef uint32_t _PyMonitoringEventSet;
+
+/* Tool IDs */
+
+/* These are defined in PEP 669 for convenience to avoid clashes */
+#define PY_MONITORING_DEBUGGER_ID 0
+#define PY_MONITORING_COVERAGE_ID 1
+#define PY_MONITORING_PROFILER_ID 2
+#define PY_MONITORING_OPTIMIZER_ID 5
+
+/* Internal IDs used to suuport sys.setprofile() and sys.settrace() */
+#define PY_MONITORING_SYS_PROFILE_ID 6
+#define PY_MONITORING_SYS_TRACE_ID 7
+
+
+PyObject *_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj);
+
+int _PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events);
+
+extern int
+_Py_call_instrumentation(PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr);
+
+extern int
+_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame,
+ _Py_CODEUNIT *instr);
+
+extern int
+_Py_call_instrumentation_instruction(
+ PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr);
+
+int
+_Py_call_instrumentation_jump(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target);
+
+extern int
+_Py_call_instrumentation_arg(PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg);
+
+extern int
+_Py_call_instrumentation_2args(PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1);
+
+extern void
+_Py_call_instrumentation_exc0(PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr);
+
+extern void
+_Py_call_instrumentation_exc2(PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1);
+
+extern int
+_Py_Instrumentation_GetLine(PyCodeObject *code, int index);
+
+extern PyObject _PyInstrumentation_MISSING;
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* !Py_INTERNAL_INSTRUMENT_H */
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index d64a68cd2da54e..7276ce35ba68f0 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -23,10 +23,12 @@ extern "C" {
#include "pycore_function.h" // FUNC_MAX_WATCHERS
#include "pycore_genobject.h" // struct _Py_async_gen_state
#include "pycore_gc.h" // struct _gc_runtime_state
+#include "pycore_global_objects.h" // struct _Py_interp_static_objects
#include "pycore_import.h" // struct _import_state
+#include "pycore_instruments.h" // PY_MONITORING_EVENTS
#include "pycore_list.h" // struct _Py_list_state
-#include "pycore_global_objects.h" // struct _Py_interp_static_objects
#include "pycore_object_state.h" // struct _py_object_state
+#include "pycore_obmalloc.h" // struct obmalloc_state
#include "pycore_tuple.h" // struct _Py_tuple_state
#include "pycore_typeobject.h" // struct type_cache
#include "pycore_unicodeobject.h" // struct _Py_unicode_state
@@ -37,7 +39,6 @@ struct _Py_long_state {
int max_str_digits;
};
-
/* interpreter state */
/* PyInterpreterState holds the global state for one of the runtime's
@@ -49,6 +50,9 @@ struct _is {
PyInterpreterState *next;
+ uint64_t monitoring_version;
+ uint64_t last_restart_version;
+
struct pythreads {
uint64_t next_unique_id;
/* The linked list of threads, newest first. */
@@ -79,6 +83,8 @@ struct _is {
int _initialized;
int finalizing;
+ struct _obmalloc_state obmalloc;
+
struct _ceval_state ceval;
struct _gc_runtime_state gc;
@@ -148,6 +154,15 @@ struct _is {
struct callable_cache callable_cache;
PyCodeObject *interpreter_trampoline;
+ _Py_Monitors monitors;
+ bool f_opcode_trace_set;
+ bool sys_profile_initialized;
+ bool sys_trace_initialized;
+ Py_ssize_t sys_profiling_threads; /* Count of threads with c_profilefunc set */
+ Py_ssize_t sys_tracing_threads; /* Count of threads with c_tracefunc set */
+ PyObject *monitoring_callables[PY_MONITORING_TOOL_IDS][PY_MONITORING_EVENTS];
+ PyObject *monitoring_tool_names[PY_MONITORING_TOOL_IDS];
+
struct _Py_interp_cached_objects cached_objects;
struct _Py_interp_static_objects static_objects;
diff --git a/Include/internal/pycore_long.h b/Include/internal/pycore_long.h
index 137a0465d5ec60..fe86581e81f6b5 100644
--- a/Include/internal/pycore_long.h
+++ b/Include/internal/pycore_long.h
@@ -245,7 +245,7 @@ _PyLong_FlipSign(PyLongObject *op) {
#define _PyLong_DIGIT_INIT(val) \
{ \
- .ob_base = _PyObject_IMMORTAL_INIT(&PyLong_Type), \
+ .ob_base = _PyObject_HEAD_INIT(&PyLong_Type) \
.long_value = { \
.lv_tag = TAG_FROM_SIGN_AND_SIZE( \
(val) == 0 ? 0 : ((val) < 0 ? -1 : 1), \
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index b3d496ed6fc240..2ca047846e0935 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -14,21 +14,25 @@ extern "C" {
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_runtime.h" // _PyRuntime
-/* This value provides *effective* immortality, meaning the object should never
- be deallocated (until runtime finalization). See PEP 683 for more details about
- immortality, as well as a proposed mechanism for proper immortality. */
-#define _PyObject_IMMORTAL_REFCNT 999999999
-
-#define _PyObject_IMMORTAL_INIT(type) \
- { \
- .ob_refcnt = _PyObject_IMMORTAL_REFCNT, \
- .ob_type = (type), \
- }
-#define _PyVarObject_IMMORTAL_INIT(type, size) \
- { \
- .ob_base = _PyObject_IMMORTAL_INIT(type), \
- .ob_size = size, \
- }
+/* We need to maintain an internal copy of Py{Var}Object_HEAD_INIT to avoid
+ designated initializer conflicts in C++20. If we use the deinition in
+ object.h, we will be mixing designated and non-designated initializers in
+ pycore objects which is forbiddent in C++20. However, if we then use
+ designated initializers in object.h then Extensions without designated break.
+ Furthermore, we can't use designated initializers in Extensions since these
+ are not supported pre-C++20. Thus, keeping an internal copy here is the most
+ backwards compatible solution */
+#define _PyObject_HEAD_INIT(type) \
+ { \
+ _PyObject_EXTRA_INIT \
+ .ob_refcnt = _Py_IMMORTAL_REFCNT, \
+ .ob_type = (type) \
+ },
+#define _PyVarObject_HEAD_INIT(type, size) \
+ { \
+ .ob_base = _PyObject_HEAD_INIT(type) \
+ .ob_size = size \
+ },
PyAPI_FUNC(void) _Py_NO_RETURN _Py_FatalRefcountErrorFunc(
const char *func,
@@ -61,9 +65,20 @@ static inline void _Py_RefcntAdd(PyObject* op, Py_ssize_t n)
}
#define _Py_RefcntAdd(op, n) _Py_RefcntAdd(_PyObject_CAST(op), n)
+static inline void _Py_SetImmortal(PyObject *op)
+{
+ if (op) {
+ op->ob_refcnt = _Py_IMMORTAL_REFCNT;
+ }
+}
+#define _Py_SetImmortal(op) _Py_SetImmortal(_PyObject_CAST(op))
+
static inline void
_Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
{
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_DEC_REFTOTAL(_PyInterpreterState_GET());
@@ -82,6 +97,9 @@ _Py_DECREF_SPECIALIZED(PyObject *op, const destructor destruct)
static inline void
_Py_DECREF_NO_DEALLOC(PyObject *op)
{
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
_Py_DECREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_DEC_REFTOTAL(_PyInterpreterState_GET());
diff --git a/Include/internal/pycore_obmalloc.h b/Include/internal/pycore_obmalloc.h
index a5c7f4528f9126..ca2a0419b4f038 100644
--- a/Include/internal/pycore_obmalloc.h
+++ b/Include/internal/pycore_obmalloc.h
@@ -657,8 +657,12 @@ struct _obmalloc_usage {
#endif /* WITH_PYMALLOC_RADIX_TREE */
-struct _obmalloc_state {
+struct _obmalloc_global_state {
int dump_debug_stats;
+ Py_ssize_t interpreter_leaks;
+};
+
+struct _obmalloc_state {
struct _obmalloc_pools pools;
struct _obmalloc_mgmt mgmt;
struct _obmalloc_usage usage;
@@ -675,7 +679,11 @@ void _PyObject_VirtualFree(void *, size_t size);
/* This function returns the number of allocated memory blocks, regardless of size */
-PyAPI_FUNC(Py_ssize_t) _Py_GetAllocatedBlocks(void);
+extern Py_ssize_t _Py_GetGlobalAllocatedBlocks(void);
+#define _Py_GetAllocatedBlocks() \
+ _Py_GetGlobalAllocatedBlocks()
+extern Py_ssize_t _PyInterpreterState_GetAllocatedBlocks(PyInterpreterState *);
+extern void _PyInterpreterState_FinalizeAllocatedBlocks(PyInterpreterState *);
#ifdef WITH_PYMALLOC
diff --git a/Include/internal/pycore_obmalloc_init.h b/Include/internal/pycore_obmalloc_init.h
index c9f197e72de9f5..8ee72ff2d4126f 100644
--- a/Include/internal/pycore_obmalloc_init.h
+++ b/Include/internal/pycore_obmalloc_init.h
@@ -54,9 +54,13 @@ extern "C" {
# error "NB_SMALL_SIZE_CLASSES should be less than 64"
#endif
-#define _obmalloc_state_INIT(obmalloc) \
+#define _obmalloc_global_state_INIT \
{ \
.dump_debug_stats = -1, \
+ }
+
+#define _obmalloc_state_INIT(obmalloc) \
+ { \
.pools = { \
.used = _obmalloc_pools_INIT(obmalloc.pools), \
}, \
diff --git a/Include/internal/pycore_opcode.h b/Include/internal/pycore_opcode.h
index 81ca91465950b7..a82885463ab2e9 100644
--- a/Include/internal/pycore_opcode.h
+++ b/Include/internal/pycore_opcode.h
@@ -12,8 +12,6 @@ extern "C" {
#include "opcode.h"
-extern const uint32_t _PyOpcode_RelativeJump[9];
-
extern const uint32_t _PyOpcode_Jump[9];
extern const uint8_t _PyOpcode_Caches[256];
@@ -21,17 +19,6 @@ extern const uint8_t _PyOpcode_Caches[256];
extern const uint8_t _PyOpcode_Deopt[256];
#ifdef NEED_OPCODE_TABLES
-const uint32_t _PyOpcode_RelativeJump[9] = {
- 0U,
- 0U,
- 536870912U,
- 135020544U,
- 4163U,
- 0U,
- 0U,
- 0U,
- 48U,
-};
const uint32_t _PyOpcode_Jump[9] = {
0U,
0U,
@@ -55,6 +42,7 @@ const uint8_t _PyOpcode_Caches[256] = {
[LOAD_GLOBAL] = 4,
[BINARY_OP] = 1,
[SEND] = 1,
+ [LOAD_SUPER_ATTR] = 9,
[CALL] = 3,
};
@@ -125,6 +113,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
[DICT_UPDATE] = DICT_UPDATE,
[END_ASYNC_FOR] = END_ASYNC_FOR,
[END_FOR] = END_FOR,
+ [END_SEND] = END_SEND,
[EXTENDED_ARG] = EXTENDED_ARG,
[FORMAT_VALUE] = FORMAT_VALUE,
[FOR_ITER] = FOR_ITER,
@@ -140,6 +129,23 @@ const uint8_t _PyOpcode_Deopt[256] = {
[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_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,
@@ -174,6 +180,8 @@ const uint8_t _PyOpcode_Deopt[256] = {
[LOAD_GLOBAL_BUILTIN] = LOAD_GLOBAL,
[LOAD_GLOBAL_MODULE] = LOAD_GLOBAL,
[LOAD_NAME] = LOAD_NAME,
+ [LOAD_SUPER_ATTR] = LOAD_SUPER_ATTR,
+ [LOAD_SUPER_ATTR_METHOD] = LOAD_SUPER_ATTR,
[MAKE_CELL] = MAKE_CELL,
[MAKE_FUNCTION] = MAKE_FUNCTION,
[MAP_ADD] = MAP_ADD,
@@ -192,6 +200,7 @@ const uint8_t _PyOpcode_Deopt[256] = {
[PUSH_NULL] = PUSH_NULL,
[RAISE_VARARGS] = RAISE_VARARGS,
[RERAISE] = RERAISE,
+ [RESERVED] = RESERVED,
[RESUME] = RESUME,
[RETURN_CONST] = RETURN_CONST,
[RETURN_GENERATOR] = RETURN_GENERATOR,
@@ -230,23 +239,25 @@ const uint8_t _PyOpcode_Deopt[256] = {
#endif // NEED_OPCODE_TABLES
#ifdef Py_DEBUG
-static const char *const _PyOpcode_OpName[263] = {
+static const char *const _PyOpcode_OpName[266] = {
[CACHE] = "CACHE",
[POP_TOP] = "POP_TOP",
[PUSH_NULL] = "PUSH_NULL",
[INTERPRETER_EXIT] = "INTERPRETER_EXIT",
[END_FOR] = "END_FOR",
+ [END_SEND] = "END_SEND",
[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",
[NOP] = "NOP",
- [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT",
+ [BINARY_OP_INPLACE_ADD_UNICODE] = "BINARY_OP_INPLACE_ADD_UNICODE",
[UNARY_NEGATIVE] = "UNARY_NEGATIVE",
[UNARY_NOT] = "UNARY_NOT",
+ [BINARY_OP_MULTIPLY_FLOAT] = "BINARY_OP_MULTIPLY_FLOAT",
[BINARY_OP_MULTIPLY_INT] = "BINARY_OP_MULTIPLY_INT",
- [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT",
[UNARY_INVERT] = "UNARY_INVERT",
+ [BINARY_OP_SUBTRACT_FLOAT] = "BINARY_OP_SUBTRACT_FLOAT",
+ [RESERVED] = "RESERVED",
[BINARY_OP_SUBTRACT_INT] = "BINARY_OP_SUBTRACT_INT",
[BINARY_SUBSCR_DICT] = "BINARY_SUBSCR_DICT",
[BINARY_SUBSCR_GETITEM] = "BINARY_SUBSCR_GETITEM",
@@ -254,21 +265,21 @@ static const char *const _PyOpcode_OpName[263] = {
[BINARY_SUBSCR_TUPLE_INT] = "BINARY_SUBSCR_TUPLE_INT",
[CALL_PY_EXACT_ARGS] = "CALL_PY_EXACT_ARGS",
[CALL_PY_WITH_DEFAULTS] = "CALL_PY_WITH_DEFAULTS",
- [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS",
- [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS",
[BINARY_SUBSCR] = "BINARY_SUBSCR",
[BINARY_SLICE] = "BINARY_SLICE",
[STORE_SLICE] = "STORE_SLICE",
- [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS",
- [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
+ [CALL_BOUND_METHOD_EXACT_ARGS] = "CALL_BOUND_METHOD_EXACT_ARGS",
+ [CALL_BUILTIN_CLASS] = "CALL_BUILTIN_CLASS",
[GET_LEN] = "GET_LEN",
[MATCH_MAPPING] = "MATCH_MAPPING",
[MATCH_SEQUENCE] = "MATCH_SEQUENCE",
[MATCH_KEYS] = "MATCH_KEYS",
- [CALL_NO_KW_BUILTIN_FAST] = "CALL_NO_KW_BUILTIN_FAST",
+ [CALL_BUILTIN_FAST_WITH_KEYWORDS] = "CALL_BUILTIN_FAST_WITH_KEYWORDS",
[PUSH_EXC_INFO] = "PUSH_EXC_INFO",
[CHECK_EXC_MATCH] = "CHECK_EXC_MATCH",
[CHECK_EG_MATCH] = "CHECK_EG_MATCH",
+ [CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = "CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS",
+ [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",
@@ -278,8 +289,6 @@ static const char *const _PyOpcode_OpName[263] = {
[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",
- [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT",
[WITH_EXCEPT_START] = "WITH_EXCEPT_START",
[GET_AITER] = "GET_AITER",
[GET_ANEXT] = "GET_ANEXT",
@@ -287,39 +296,39 @@ static const char *const _PyOpcode_OpName[263] = {
[BEFORE_WITH] = "BEFORE_WITH",
[END_ASYNC_FOR] = "END_ASYNC_FOR",
[CLEANUP_THROW] = "CLEANUP_THROW",
+ [CALL_NO_KW_TYPE_1] = "CALL_NO_KW_TYPE_1",
+ [COMPARE_OP_FLOAT] = "COMPARE_OP_FLOAT",
[COMPARE_OP_INT] = "COMPARE_OP_INT",
[COMPARE_OP_STR] = "COMPARE_OP_STR",
- [FOR_ITER_LIST] = "FOR_ITER_LIST",
- [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE",
[STORE_SUBSCR] = "STORE_SUBSCR",
[DELETE_SUBSCR] = "DELETE_SUBSCR",
+ [FOR_ITER_LIST] = "FOR_ITER_LIST",
+ [FOR_ITER_TUPLE] = "FOR_ITER_TUPLE",
[FOR_ITER_RANGE] = "FOR_ITER_RANGE",
[FOR_ITER_GEN] = "FOR_ITER_GEN",
+ [LOAD_SUPER_ATTR_METHOD] = "LOAD_SUPER_ATTR_METHOD",
[LOAD_ATTR_CLASS] = "LOAD_ATTR_CLASS",
+ [GET_ITER] = "GET_ITER",
+ [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER",
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = "LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN",
+ [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS",
[LOAD_ATTR_INSTANCE_VALUE] = "LOAD_ATTR_INSTANCE_VALUE",
[LOAD_ATTR_MODULE] = "LOAD_ATTR_MODULE",
- [GET_ITER] = "GET_ITER",
- [GET_YIELD_FROM_ITER] = "GET_YIELD_FROM_ITER",
+ [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR",
+ [RETURN_GENERATOR] = "RETURN_GENERATOR",
[LOAD_ATTR_PROPERTY] = "LOAD_ATTR_PROPERTY",
- [LOAD_BUILD_CLASS] = "LOAD_BUILD_CLASS",
[LOAD_ATTR_SLOT] = "LOAD_ATTR_SLOT",
[LOAD_ATTR_WITH_HINT] = "LOAD_ATTR_WITH_HINT",
- [LOAD_ASSERTION_ERROR] = "LOAD_ASSERTION_ERROR",
- [RETURN_GENERATOR] = "RETURN_GENERATOR",
[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_CONST__LOAD_FAST] = "LOAD_CONST__LOAD_FAST",
+ [RETURN_VALUE] = "RETURN_VALUE",
[LOAD_FAST__LOAD_CONST] = "LOAD_FAST__LOAD_CONST",
+ [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
[LOAD_FAST__LOAD_FAST] = "LOAD_FAST__LOAD_FAST",
[LOAD_GLOBAL_BUILTIN] = "LOAD_GLOBAL_BUILTIN",
- [RETURN_VALUE] = "RETURN_VALUE",
[LOAD_GLOBAL_MODULE] = "LOAD_GLOBAL_MODULE",
- [SETUP_ANNOTATIONS] = "SETUP_ANNOTATIONS",
- [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
- [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
- [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
[POP_EXCEPT] = "POP_EXCEPT",
[STORE_NAME] = "STORE_NAME",
[DELETE_NAME] = "DELETE_NAME",
@@ -342,9 +351,9 @@ static const char *const _PyOpcode_OpName[263] = {
[IMPORT_NAME] = "IMPORT_NAME",
[IMPORT_FROM] = "IMPORT_FROM",
[JUMP_FORWARD] = "JUMP_FORWARD",
- [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST",
- [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
- [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
+ [STORE_ATTR_INSTANCE_VALUE] = "STORE_ATTR_INSTANCE_VALUE",
+ [STORE_ATTR_SLOT] = "STORE_ATTR_SLOT",
+ [STORE_ATTR_WITH_HINT] = "STORE_ATTR_WITH_HINT",
[POP_JUMP_IF_FALSE] = "POP_JUMP_IF_FALSE",
[POP_JUMP_IF_TRUE] = "POP_JUMP_IF_TRUE",
[LOAD_GLOBAL] = "LOAD_GLOBAL",
@@ -372,9 +381,9 @@ static const char *const _PyOpcode_OpName[263] = {
[STORE_DEREF] = "STORE_DEREF",
[DELETE_DEREF] = "DELETE_DEREF",
[JUMP_BACKWARD] = "JUMP_BACKWARD",
- [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
+ [LOAD_SUPER_ATTR] = "LOAD_SUPER_ATTR",
[CALL_FUNCTION_EX] = "CALL_FUNCTION_EX",
- [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
+ [STORE_FAST__LOAD_FAST] = "STORE_FAST__LOAD_FAST",
[EXTENDED_ARG] = "EXTENDED_ARG",
[LIST_APPEND] = "LIST_APPEND",
[SET_ADD] = "SET_ADD",
@@ -384,20 +393,20 @@ static const char *const _PyOpcode_OpName[263] = {
[YIELD_VALUE] = "YIELD_VALUE",
[RESUME] = "RESUME",
[MATCH_CLASS] = "MATCH_CLASS",
- [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
- [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
+ [STORE_FAST__STORE_FAST] = "STORE_FAST__STORE_FAST",
+ [STORE_SUBSCR_DICT] = "STORE_SUBSCR_DICT",
[FORMAT_VALUE] = "FORMAT_VALUE",
[BUILD_CONST_KEY_MAP] = "BUILD_CONST_KEY_MAP",
[BUILD_STRING] = "BUILD_STRING",
- [SEND_GEN] = "SEND_GEN",
- [159] = "<159>",
- [160] = "<160>",
- [161] = "<161>",
+ [STORE_SUBSCR_LIST_INT] = "STORE_SUBSCR_LIST_INT",
+ [UNPACK_SEQUENCE_LIST] = "UNPACK_SEQUENCE_LIST",
+ [UNPACK_SEQUENCE_TUPLE] = "UNPACK_SEQUENCE_TUPLE",
+ [UNPACK_SEQUENCE_TWO_TUPLE] = "UNPACK_SEQUENCE_TWO_TUPLE",
[LIST_EXTEND] = "LIST_EXTEND",
[SET_UPDATE] = "SET_UPDATE",
[DICT_MERGE] = "DICT_MERGE",
[DICT_UPDATE] = "DICT_UPDATE",
- [166] = "<166>",
+ [SEND_GEN] = "SEND_GEN",
[167] = "<167>",
[168] = "<168>",
[169] = "<169>",
@@ -469,24 +478,24 @@ static const char *const _PyOpcode_OpName[263] = {
[235] = "<235>",
[236] = "<236>",
[237] = "<237>",
- [238] = "<238>",
- [239] = "<239>",
- [240] = "<240>",
- [241] = "<241>",
- [242] = "<242>",
- [243] = "<243>",
- [244] = "<244>",
- [245] = "<245>",
- [246] = "<246>",
- [247] = "<247>",
- [248] = "<248>",
- [249] = "<249>",
- [250] = "<250>",
- [251] = "<251>",
- [252] = "<252>",
- [253] = "<253>",
- [254] = "<254>",
- [DO_TRACING] = "DO_TRACING",
+ [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",
@@ -494,14 +503,13 @@ static const char *const _PyOpcode_OpName[263] = {
[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",
};
#endif
#define EXTRA_CASES \
- case 159: \
- case 160: \
- case 161: \
- case 166: \
case 167: \
case 168: \
case 169: \
@@ -569,23 +577,7 @@ static const char *const _PyOpcode_OpName[263] = {
case 235: \
case 236: \
case 237: \
- case 238: \
- case 239: \
- case 240: \
- case 241: \
- case 242: \
- case 243: \
- case 244: \
- case 245: \
- case 246: \
- case 247: \
- case 248: \
- case 249: \
- case 250: \
- case 251: \
- case 252: \
- case 253: \
- case 254: \
+ case 255: \
;
#ifdef __cplusplus
diff --git a/Include/internal/pycore_opcode_utils.h b/Include/internal/pycore_opcode_utils.h
index 96bb4d743bf29f..1d5ff988290bd4 100644
--- a/Include/internal/pycore_opcode_utils.h
+++ b/Include/internal/pycore_opcode_utils.h
@@ -8,7 +8,7 @@ extern "C" {
# error "this header requires Py_BUILD_CORE define"
#endif
-#include "pycore_opcode.h" // _PyOpcode_RelativeJump
+#include "pycore_opcode.h" // _PyOpcode_Jump
#define MAX_REAL_OPCODE 254
@@ -85,9 +85,6 @@ is_bit_set_in_table(const uint32_t *table, int bitindex) {
#undef LOG_BITS_PER_INT
#undef MASK_LOW_LOG_BITS
-#define IS_RELATIVE_JUMP(opcode) (is_bit_set_in_table(_PyOpcode_RelativeJump, opcode))
-
-
#ifdef __cplusplus
}
diff --git a/Include/internal/pycore_pyerrors.h b/Include/internal/pycore_pyerrors.h
index 1bb4a9aa103898..4620a269644917 100644
--- a/Include/internal/pycore_pyerrors.h
+++ b/Include/internal/pycore_pyerrors.h
@@ -109,6 +109,8 @@ extern PyObject* _Py_Offer_Suggestions(PyObject* exception);
PyAPI_FUNC(Py_ssize_t) _Py_UTF8_Edit_Cost(PyObject *str_a, PyObject *str_b,
Py_ssize_t max_cost);
+void _PyErr_FormatNote(const char *format, ...);
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index a899e848bb8b3c..f96261a650dac7 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -64,6 +64,7 @@ extern void _PyAtExit_Fini(PyInterpreterState *interp);
extern void _PyThread_FiniType(PyInterpreterState *interp);
extern void _Py_Deepfreeze_Fini(void);
extern void _PyArg_Fini(void);
+extern void _Py_FinalizeAllocatedBlocks(_PyRuntimeState *);
extern PyStatus _PyGILState_Init(PyInterpreterState *interp);
extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate);
diff --git a/Include/internal/pycore_pystate.h b/Include/internal/pycore_pystate.h
index b5408622d9d4b2..180ea676bc22eb 100644
--- a/Include/internal/pycore_pystate.h
+++ b/Include/internal/pycore_pystate.h
@@ -33,6 +33,13 @@ _Py_IsMainInterpreter(PyInterpreterState *interp)
return (interp == _PyInterpreterState_Main());
}
+static inline int
+_Py_IsMainInterpreterFinalizing(PyInterpreterState *interp)
+{
+ return (_PyRuntimeState_GetFinalizing(interp->runtime) != NULL &&
+ interp == &interp->runtime->_main_interpreter);
+}
+
static inline const PyConfig *
_Py_GetMainConfig(void)
@@ -64,17 +71,14 @@ _Py_ThreadCanHandlePendingCalls(void)
/* Variable and macro for in-line access to current thread
and interpreter state */
-static inline PyThreadState*
-_PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
-{
- return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
-}
+#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
+extern _Py_thread_local PyThreadState *_Py_tss_tstate;
+#endif
+PyAPI_DATA(PyThreadState *) _PyThreadState_GetCurrent(void);
/* Get the current Python thread state.
- Efficient macro reading directly the 'tstate_current' atomic
- variable. The macro is unsafe: it does not check for error and it can
- return NULL.
+ This function is unsafe: it does not check for error and it can return NULL.
The caller must hold the GIL.
@@ -82,9 +86,20 @@ _PyRuntimeState_GetThreadState(_PyRuntimeState *runtime)
static inline PyThreadState*
_PyThreadState_GET(void)
{
- return _PyRuntimeState_GetThreadState(&_PyRuntime);
+#if defined(HAVE_THREAD_LOCAL) && !defined(Py_BUILD_CORE_MODULE)
+ return _Py_tss_tstate;
+#else
+ return _PyThreadState_GetCurrent();
+#endif
}
+static inline PyThreadState*
+_PyRuntimeState_GetThreadState(_PyRuntimeState *Py_UNUSED(runtime))
+{
+ return _PyThreadState_GET();
+}
+
+
static inline void
_Py_EnsureFuncTstateNotNULL(const char *func, PyThreadState *tstate)
{
@@ -133,16 +148,6 @@ extern void _PyThreadState_BindDetached(PyThreadState *);
extern void _PyThreadState_UnbindDetached(PyThreadState *);
-static inline void
-_PyThreadState_UpdateTracingState(PyThreadState *tstate)
-{
- bool use_tracing =
- (tstate->tracing == 0) &&
- (tstate->c_tracefunc != NULL || tstate->c_profilefunc != NULL);
- tstate->cframe->use_tracing = (use_tracing ? 255 : 0);
-}
-
-
/* Other */
PyAPI_FUNC(PyThreadState *) _PyThreadState_Swap(
diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h
index 3ebe49926edda6..d1b165d0ab9c38 100644
--- a/Include/internal/pycore_runtime.h
+++ b/Include/internal/pycore_runtime.h
@@ -21,10 +21,10 @@ extern "C" {
#include "pycore_pymem.h" // struct _pymem_allocators
#include "pycore_pyhash.h" // struct pyhash_runtime_state
#include "pycore_pythread.h" // struct _pythread_runtime_state
-#include "pycore_obmalloc.h" // struct obmalloc_state
#include "pycore_signal.h" // struct _signals_runtime_state
#include "pycore_time.h" // struct _time_runtime_state
#include "pycore_tracemalloc.h" // struct _tracemalloc_runtime_state
+#include "pycore_typeobject.h" // struct types_runtime_state
#include "pycore_unicodeobject.h" // struct _Py_unicode_runtime_ids
struct _getargs_runtime_state {
@@ -87,7 +87,7 @@ typedef struct pyruntimestate {
_Py_atomic_address _finalizing;
struct _pymem_allocators allocators;
- struct _obmalloc_state obmalloc;
+ struct _obmalloc_global_state obmalloc;
struct pyhash_runtime_state pyhash_state;
struct _time_runtime_state time;
struct _pythread_runtime_state threads;
@@ -119,9 +119,6 @@ typedef struct pyruntimestate {
unsigned long main_thread;
- /* Assuming the current thread holds the GIL, this is the
- PyThreadState for the current thread. */
- _Py_atomic_address tstate_current;
/* Used for the thread state bound to the current thread. */
Py_tss_t autoTSSkey;
@@ -153,13 +150,7 @@ typedef struct pyruntimestate {
struct _py_object_runtime_state object_state;
struct _Py_float_runtime_state float_state;
struct _Py_unicode_runtime_state unicode_state;
-
- struct {
- /* Used to set PyTypeObject.tp_version_tag */
- // bpo-42745: next_version_tag remains shared by all interpreters
- // because of static types.
- unsigned int next_version_tag;
- } types;
+ struct _types_runtime_state types;
/* All the objects that are shared by the runtime's interpreters. */
struct _Py_static_objects static_objects;
diff --git a/Include/internal/pycore_runtime_init.h b/Include/internal/pycore_runtime_init.h
index 5b09a45e41cd84..a48461c0742872 100644
--- a/Include/internal/pycore_runtime_init.h
+++ b/Include/internal/pycore_runtime_init.h
@@ -29,7 +29,7 @@ extern PyTypeObject _PyExc_MemoryError;
_pymem_allocators_debug_INIT, \
_pymem_allocators_obj_arena_INIT, \
}, \
- .obmalloc = _obmalloc_state_INIT(runtime.obmalloc), \
+ .obmalloc = _obmalloc_global_state_INIT, \
.pyhash_state = pyhash_state_INIT, \
.signals = _signals_RUNTIME_INIT, \
.interpreters = { \
@@ -76,13 +76,13 @@ extern PyTypeObject _PyExc_MemoryError;
.latin1 = _Py_str_latin1_INIT, \
}, \
.tuple_empty = { \
- .ob_base = _PyVarObject_IMMORTAL_INIT(&PyTuple_Type, 0) \
+ .ob_base = _PyVarObject_HEAD_INIT(&PyTuple_Type, 0) \
}, \
.hamt_bitmap_node_empty = { \
- .ob_base = _PyVarObject_IMMORTAL_INIT(&_PyHamt_BitmapNode_Type, 0) \
+ .ob_base = _PyVarObject_HEAD_INIT(&_PyHamt_BitmapNode_Type, 0) \
}, \
.context_token_missing = { \
- .ob_base = _PyObject_IMMORTAL_INIT(&_PyContextTokenMissing_Type), \
+ .ob_base = _PyObject_HEAD_INIT(&_PyContextTokenMissing_Type) \
}, \
}, \
}, \
@@ -93,6 +93,7 @@ extern PyTypeObject _PyExc_MemoryError;
{ \
.id_refcount = -1, \
.imports = IMPORTS_INIT, \
+ .obmalloc = _obmalloc_state_INIT(INTERP.obmalloc), \
.ceval = { \
.recursion_limit = Py_DEFAULT_RECURSION_LIMIT, \
}, \
@@ -112,15 +113,18 @@ extern PyTypeObject _PyExc_MemoryError;
.func_state = { \
.next_version = 1, \
}, \
+ .types = { \
+ .next_version_tag = _Py_TYPE_BASE_VERSION_TAG, \
+ }, \
.static_objects = { \
.singletons = { \
._not_used = 1, \
.hamt_empty = { \
- .ob_base = _PyObject_IMMORTAL_INIT(&_PyHamt_Type), \
+ .ob_base = _PyObject_HEAD_INIT(&_PyHamt_Type) \
.h_root = (PyHamtNode*)&_Py_SINGLETON(hamt_bitmap_node_empty), \
}, \
.last_resort_memory_error = { \
- _PyObject_IMMORTAL_INIT(&_PyExc_MemoryError), \
+ _PyObject_HEAD_INIT(&_PyExc_MemoryError) \
}, \
}, \
}, \
@@ -138,7 +142,7 @@ extern PyTypeObject _PyExc_MemoryError;
#define _PyBytes_SIMPLE_INIT(CH, LEN) \
{ \
- _PyVarObject_IMMORTAL_INIT(&PyBytes_Type, (LEN)), \
+ _PyVarObject_HEAD_INIT(&PyBytes_Type, (LEN)) \
.ob_shash = -1, \
.ob_sval = { (CH) }, \
}
@@ -149,7 +153,7 @@ extern PyTypeObject _PyExc_MemoryError;
#define _PyUnicode_ASCII_BASE_INIT(LITERAL, ASCII) \
{ \
- .ob_base = _PyObject_IMMORTAL_INIT(&PyUnicode_Type), \
+ .ob_base = _PyObject_HEAD_INIT(&PyUnicode_Type) \
.length = sizeof(LITERAL) - 1, \
.hash = -1, \
.state = { \
diff --git a/Include/internal/pycore_token.h b/Include/internal/pycore_token.h
index 95459ab9f7d004..b9df8766736adf 100644
--- a/Include/internal/pycore_token.h
+++ b/Include/internal/pycore_token.h
@@ -67,14 +67,18 @@ extern "C" {
#define RARROW 51
#define ELLIPSIS 52
#define COLONEQUAL 53
-#define OP 54
-#define AWAIT 55
-#define ASYNC 56
-#define TYPE_IGNORE 57
-#define TYPE_COMMENT 58
-#define SOFT_KEYWORD 59
-#define ERRORTOKEN 60
-#define N_TOKENS 64
+#define EXCLAMATION 54
+#define OP 55
+#define AWAIT 56
+#define ASYNC 57
+#define TYPE_IGNORE 58
+#define TYPE_COMMENT 59
+#define SOFT_KEYWORD 60
+#define FSTRING_START 61
+#define FSTRING_MIDDLE 62
+#define FSTRING_END 63
+#define ERRORTOKEN 64
+#define N_TOKENS 68
#define NT_OFFSET 256
/* Special definitions for cooperation with parser */
@@ -86,6 +90,8 @@ extern "C" {
(x) == NEWLINE || \
(x) == INDENT || \
(x) == DEDENT)
+#define ISSTRINGLIT(x) ((x) == STRING || \
+ (x) == FSTRING_MIDDLE)
// Symbols exported for test_peg_generator
diff --git a/Include/internal/pycore_typeobject.h b/Include/internal/pycore_typeobject.h
index cc5ce2875101ea..76253fd5fd864c 100644
--- a/Include/internal/pycore_typeobject.h
+++ b/Include/internal/pycore_typeobject.h
@@ -11,22 +11,17 @@ extern "C" {
#endif
-/* runtime lifecycle */
+/* state */
-extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
-extern void _PyTypes_FiniTypes(PyInterpreterState *);
-extern void _PyTypes_Fini(PyInterpreterState *);
-
-
-/* other API */
-
-/* Length of array of slotdef pointers used to store slots with the
- same __name__. There should be at most MAX_EQUIV-1 slotdef entries with
- the same __name__, for any __name__. Since that's a static property, it is
- appropriate to declare fixed-size arrays for this. */
-#define MAX_EQUIV 10
+#define _Py_TYPE_BASE_VERSION_TAG (2<<16)
+#define _Py_MAX_GLOBAL_TYPE_VERSION_TAG (_Py_TYPE_BASE_VERSION_TAG - 1)
-typedef struct wrapperbase pytype_slotdef;
+struct _types_runtime_state {
+ /* Used to set PyTypeObject.tp_version_tag for core static types. */
+ // bpo-42745: next_version_tag remains shared by all interpreters
+ // because of static types.
+ unsigned int next_version_tag;
+};
// Type attribute lookup cache: speed up attribute and method lookups,
@@ -57,6 +52,36 @@ typedef struct {
PyObject *tp_weaklist;
} static_builtin_state;
+struct types_state {
+ /* Used to set PyTypeObject.tp_version_tag.
+ It starts at _Py_MAX_GLOBAL_TYPE_VERSION_TAG + 1,
+ where all those lower numbers are used for core static types. */
+ unsigned int next_version_tag;
+
+ struct type_cache type_cache;
+ size_t num_builtins_initialized;
+ static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
+};
+
+
+/* runtime lifecycle */
+
+extern PyStatus _PyTypes_InitTypes(PyInterpreterState *);
+extern void _PyTypes_FiniTypes(PyInterpreterState *);
+extern void _PyTypes_Fini(PyInterpreterState *);
+
+
+/* other API */
+
+/* Length of array of slotdef pointers used to store slots with the
+ same __name__. There should be at most MAX_EQUIV-1 slotdef entries with
+ the same __name__, for any __name__. Since that's a static property, it is
+ appropriate to declare fixed-size arrays for this. */
+#define MAX_EQUIV 10
+
+typedef struct wrapperbase pytype_slotdef;
+
+
static inline PyObject **
_PyStaticType_GET_WEAKREFS_LISTPTR(static_builtin_state *state)
{
@@ -78,12 +103,6 @@ _PyType_GetModuleState(PyTypeObject *type)
return mod->md_state;
}
-struct types_state {
- struct type_cache type_cache;
- size_t num_builtins_initialized;
- static_builtin_state builtins[_Py_MAX_STATIC_BUILTIN_TYPES];
-};
-
extern int _PyStaticType_InitBuiltin(PyTypeObject *type);
extern static_builtin_state * _PyStaticType_GetState(PyTypeObject *);
@@ -98,6 +117,11 @@ _Py_type_getattro(PyTypeObject *type, PyObject *name);
PyObject *_Py_slot_tp_getattro(PyObject *self, PyObject *name);
PyObject *_Py_slot_tp_getattr_hook(PyObject *self, PyObject *name);
+PyObject *
+_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *meth_found);
+PyObject *
+_PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name);
+
#ifdef __cplusplus
}
#endif
diff --git a/Include/internal/pycore_unicodeobject.h b/Include/internal/pycore_unicodeobject.h
index ff97b9a623d210..1bb0f366e78163 100644
--- a/Include/internal/pycore_unicodeobject.h
+++ b/Include/internal/pycore_unicodeobject.h
@@ -12,6 +12,7 @@ extern "C" {
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
void _PyUnicode_ExactDealloc(PyObject *op);
+Py_ssize_t _PyUnicode_InternedSize(void);
/* runtime lifecycle */
diff --git a/Include/object.h b/Include/object.h
index 2943a6066818cd..66c3df0d7f780a 100644
--- a/Include/object.h
+++ b/Include/object.h
@@ -78,12 +78,76 @@ whose size is determined when the object is allocated.
/* PyObject_HEAD defines the initial segment of every PyObject. */
#define PyObject_HEAD PyObject ob_base;
-#define PyObject_HEAD_INIT(type) \
- { _PyObject_EXTRA_INIT \
- 1, (type) },
+/*
+Immortalization:
+
+The following indicates the immortalization strategy depending on the amount
+of available bits in the reference count field. All strategies are backwards
+compatible but the specific reference count value or immortalization check
+might change depending on the specializations for the underlying system.
+
+Proper deallocation of immortal instances requires distinguishing between
+statically allocated immortal instances vs those promoted by the runtime to be
+immortal. The latter should be the only instances that require
+cleanup during runtime finalization.
+*/
+
+#if SIZEOF_VOID_P > 4
+/*
+In 64+ bit systems, an object will be marked as immortal by setting all of the
+lower 32 bits of the reference count field, which is equal to: 0xFFFFFFFF
+
+Using the lower 32 bits makes the value backwards compatible by allowing
+C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
+increase and decrease the objects reference count. The object would lose its
+immortality, but the execution would still be correct.
+
+Reference count increases will use saturated arithmetic, taking advantage of
+having all the lower 32 bits set, which will avoid the reference count to go
+beyond the refcount limit. Immortality checks for reference count decreases will
+be done by checking the bit sign flag in the lower 32 bits.
+*/
+#define _Py_IMMORTAL_REFCNT UINT_MAX
+
+#else
+/*
+In 32 bit systems, an object will be marked as immortal by setting all of the
+lower 30 bits of the reference count field, which is equal to: 0x3FFFFFFF
-#define PyVarObject_HEAD_INIT(type, size) \
- { PyObject_HEAD_INIT(type) (size) },
+Using the lower 30 bits makes the value backwards compatible by allowing
+C-Extensions without the updated checks in Py_INCREF and Py_DECREF to safely
+increase and decrease the objects reference count. The object would lose its
+immortality, but the execution would still be correct.
+
+Reference count increases and decreases will first go through an immortality
+check by comparing the reference count field to the immortality reference count.
+*/
+#define _Py_IMMORTAL_REFCNT (UINT_MAX >> 2)
+#endif
+
+// Make all internal uses of PyObject_HEAD_INIT immortal while preserving the
+// C-API expectation that the refcnt will be set to 1.
+#ifdef Py_BUILD_CORE
+#define PyObject_HEAD_INIT(type) \
+ { \
+ _PyObject_EXTRA_INIT \
+ { _Py_IMMORTAL_REFCNT }, \
+ (type) \
+ },
+#else
+#define PyObject_HEAD_INIT(type) \
+ { \
+ _PyObject_EXTRA_INIT \
+ { 1 }, \
+ (type) \
+ },
+#endif /* Py_BUILD_CORE */
+
+#define PyVarObject_HEAD_INIT(type, size) \
+ { \
+ PyObject_HEAD_INIT(type) \
+ (size) \
+ },
/* PyObject_VAR_HEAD defines the initial segment of all variable-size
* container objects. These end with a declaration of an array with 1
@@ -101,7 +165,12 @@ whose size is determined when the object is allocated.
*/
struct _object {
_PyObject_HEAD_EXTRA
- Py_ssize_t ob_refcnt;
+ union {
+ Py_ssize_t ob_refcnt;
+#if SIZEOF_VOID_P > 4
+ PY_UINT32_T ob_refcnt_split[2];
+#endif
+ };
PyTypeObject *ob_type;
};
@@ -152,6 +221,15 @@ static inline Py_ssize_t Py_SIZE(PyObject *ob) {
# define Py_SIZE(ob) Py_SIZE(_PyObject_CAST(ob))
#endif
+static inline Py_ALWAYS_INLINE int _Py_IsImmortal(PyObject *op)
+{
+#if SIZEOF_VOID_P > 4
+ return _Py_CAST(PY_INT32_T, op->ob_refcnt) < 0;
+#else
+ return op->ob_refcnt == _Py_IMMORTAL_REFCNT;
+#endif
+}
+#define _Py_IsImmortal(op) _Py_IsImmortal(_PyObject_CAST(op))
static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
return Py_TYPE(ob) == type;
@@ -162,6 +240,13 @@ static inline int Py_IS_TYPE(PyObject *ob, PyTypeObject *type) {
static inline void Py_SET_REFCNT(PyObject *ob, Py_ssize_t refcnt) {
+ // This immortal check is for code that is unaware of immortal objects.
+ // The runtime tracks these objects and we should avoid as much
+ // as possible having extensions inadvertently change the refcnt
+ // of an immortalized object.
+ if (_Py_IsImmortal(ob)) {
+ return;
+ }
ob->ob_refcnt = refcnt;
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
@@ -524,19 +609,33 @@ PyAPI_FUNC(void) Py_DecRef(PyObject *);
PyAPI_FUNC(void) _Py_IncRef(PyObject *);
PyAPI_FUNC(void) _Py_DecRef(PyObject *);
-static inline void Py_INCREF(PyObject *op)
+static inline Py_ALWAYS_INLINE void Py_INCREF(PyObject *op)
{
#if defined(Py_REF_DEBUG) && defined(Py_LIMITED_API) && Py_LIMITED_API+0 >= 0x030A0000
// Stable ABI for Python 3.10 built in debug mode.
_Py_IncRef(op);
#else
- _Py_INCREF_STAT_INC();
// Non-limited C API and limited C API for Python 3.9 and older access
// directly PyObject.ob_refcnt.
+#if SIZEOF_VOID_P > 4
+ // Portable saturated add, branching on the carry flag and set low bits
+ PY_UINT32_T cur_refcnt = op->ob_refcnt_split[PY_BIG_ENDIAN];
+ PY_UINT32_T new_refcnt = cur_refcnt + 1;
+ if (new_refcnt == 0) {
+ return;
+ }
+ op->ob_refcnt_split[PY_BIG_ENDIAN] = new_refcnt;
+#else
+ // Explicitly check immortality against the immortal value
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
+ op->ob_refcnt++;
+#endif
+ _Py_INCREF_STAT_INC();
#ifdef Py_REF_DEBUG
_Py_INC_REFTOTAL();
-#endif // Py_REF_DEBUG
- op->ob_refcnt++;
+#endif
#endif
}
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
@@ -553,6 +652,9 @@ static inline void Py_DECREF(PyObject *op) {
#elif defined(Py_REF_DEBUG)
static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
{
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
_Py_DECREF_STAT_INC();
_Py_DEC_REFTOTAL();
if (--op->ob_refcnt != 0) {
@@ -567,11 +669,14 @@ static inline void Py_DECREF(const char *filename, int lineno, PyObject *op)
#define Py_DECREF(op) Py_DECREF(__FILE__, __LINE__, _PyObject_CAST(op))
#else
-static inline void Py_DECREF(PyObject *op)
+static inline Py_ALWAYS_INLINE void Py_DECREF(PyObject *op)
{
- _Py_DECREF_STAT_INC();
// Non-limited C API and limited C API for Python 3.9 and older access
// directly PyObject.ob_refcnt.
+ if (_Py_IsImmortal(op)) {
+ return;
+ }
+ _Py_DECREF_STAT_INC();
if (--op->ob_refcnt == 0) {
_Py_Dealloc(op);
}
@@ -721,7 +826,7 @@ PyAPI_FUNC(int) Py_IsNone(PyObject *x);
#define Py_IsNone(x) Py_Is((x), Py_None)
/* Macro for returning Py_None from a function */
-#define Py_RETURN_NONE return Py_NewRef(Py_None)
+#define Py_RETURN_NONE return Py_None
/*
Py_NotImplemented is a singleton used to signal that an operation is
@@ -731,7 +836,7 @@ PyAPI_DATA(PyObject) _Py_NotImplementedStruct; /* Don't use this directly */
#define Py_NotImplemented (&_Py_NotImplementedStruct)
/* Macro for returning Py_NotImplemented from a function */
-#define Py_RETURN_NOTIMPLEMENTED return Py_NewRef(Py_NotImplemented)
+#define Py_RETURN_NOTIMPLEMENTED return Py_NotImplemented
/* Rich comparison opcodes */
#define Py_LT 0
diff --git a/Include/opcode.h b/Include/opcode.h
index 0ff84dc5a551a0..37a9e9bffa4cb7 100644
--- a/Include/opcode.h
+++ b/Include/opcode.h
@@ -13,10 +13,12 @@ extern "C" {
#define PUSH_NULL 2
#define INTERPRETER_EXIT 3
#define END_FOR 4
+#define END_SEND 5
#define NOP 9
#define UNARY_NEGATIVE 11
#define UNARY_NOT 12
#define UNARY_INVERT 15
+#define RESERVED 17
#define BINARY_SUBSCR 25
#define BINARY_SLICE 26
#define STORE_SLICE 27
@@ -93,6 +95,7 @@ extern "C" {
#define STORE_DEREF 138
#define DELETE_DEREF 139
#define JUMP_BACKWARD 140
+#define LOAD_SUPER_ATTR 141
#define CALL_FUNCTION_EX 142
#define EXTENDED_ARG 144
#define LIST_APPEND 145
@@ -114,6 +117,24 @@ extern "C" {
#define KW_NAMES 172
#define CALL_INTRINSIC_1 173
#define CALL_INTRINSIC_2 174
+#define MIN_INSTRUMENTED_OPCODE 238
+#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 MIN_PSEUDO_OPCODE 256
#define SETUP_FINALLY 256
#define SETUP_CLEANUP 257
@@ -122,75 +143,81 @@ extern "C" {
#define JUMP 260
#define JUMP_NO_INTERRUPT 261
#define LOAD_METHOD 262
-#define MAX_PSEUDO_OPCODE 262
-#define BINARY_OP_ADD_FLOAT 5
-#define BINARY_OP_ADD_INT 6
-#define BINARY_OP_ADD_UNICODE 7
-#define BINARY_OP_INPLACE_ADD_UNICODE 8
-#define BINARY_OP_MULTIPLY_FLOAT 10
-#define BINARY_OP_MULTIPLY_INT 13
-#define BINARY_OP_SUBTRACT_FLOAT 14
-#define BINARY_OP_SUBTRACT_INT 16
-#define BINARY_SUBSCR_DICT 17
-#define BINARY_SUBSCR_GETITEM 18
-#define BINARY_SUBSCR_LIST_INT 19
-#define BINARY_SUBSCR_TUPLE_INT 20
-#define CALL_PY_EXACT_ARGS 21
-#define CALL_PY_WITH_DEFAULTS 22
-#define CALL_BOUND_METHOD_EXACT_ARGS 23
-#define CALL_BUILTIN_CLASS 24
-#define CALL_BUILTIN_FAST_WITH_KEYWORDS 28
-#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 29
-#define CALL_NO_KW_BUILTIN_FAST 34
-#define CALL_NO_KW_BUILTIN_O 38
-#define CALL_NO_KW_ISINSTANCE 39
-#define CALL_NO_KW_LEN 40
-#define CALL_NO_KW_LIST_APPEND 41
-#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 42
-#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 43
-#define CALL_NO_KW_METHOD_DESCRIPTOR_O 44
-#define CALL_NO_KW_STR_1 45
-#define CALL_NO_KW_TUPLE_1 46
-#define CALL_NO_KW_TYPE_1 47
-#define COMPARE_OP_FLOAT 48
-#define COMPARE_OP_INT 56
-#define COMPARE_OP_STR 57
-#define FOR_ITER_LIST 58
-#define FOR_ITER_TUPLE 59
-#define FOR_ITER_RANGE 62
-#define FOR_ITER_GEN 63
-#define LOAD_ATTR_CLASS 64
-#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 65
-#define LOAD_ATTR_INSTANCE_VALUE 66
-#define LOAD_ATTR_MODULE 67
-#define LOAD_ATTR_PROPERTY 70
-#define LOAD_ATTR_SLOT 72
-#define LOAD_ATTR_WITH_HINT 73
-#define LOAD_ATTR_METHOD_LAZY_DICT 76
-#define LOAD_ATTR_METHOD_NO_DICT 77
-#define LOAD_ATTR_METHOD_WITH_VALUES 78
-#define LOAD_CONST__LOAD_FAST 79
-#define LOAD_FAST__LOAD_CONST 80
-#define LOAD_FAST__LOAD_FAST 81
-#define LOAD_GLOBAL_BUILTIN 82
-#define LOAD_GLOBAL_MODULE 84
-#define STORE_ATTR_INSTANCE_VALUE 86
-#define STORE_ATTR_SLOT 87
-#define STORE_ATTR_WITH_HINT 88
-#define STORE_FAST__LOAD_FAST 111
-#define STORE_FAST__STORE_FAST 112
-#define STORE_SUBSCR_DICT 113
-#define STORE_SUBSCR_LIST_INT 141
-#define UNPACK_SEQUENCE_LIST 143
-#define UNPACK_SEQUENCE_TUPLE 153
-#define UNPACK_SEQUENCE_TWO_TUPLE 154
-#define SEND_GEN 158
-#define DO_TRACING 255
+#define LOAD_SUPER_METHOD 263
+#define LOAD_ZERO_SUPER_METHOD 264
+#define LOAD_ZERO_SUPER_ATTR 265
+#define MAX_PSEUDO_OPCODE 265
+#define BINARY_OP_ADD_FLOAT 6
+#define BINARY_OP_ADD_INT 7
+#define BINARY_OP_ADD_UNICODE 8
+#define BINARY_OP_INPLACE_ADD_UNICODE 10
+#define BINARY_OP_MULTIPLY_FLOAT 13
+#define BINARY_OP_MULTIPLY_INT 14
+#define BINARY_OP_SUBTRACT_FLOAT 16
+#define BINARY_OP_SUBTRACT_INT 18
+#define BINARY_SUBSCR_DICT 19
+#define BINARY_SUBSCR_GETITEM 20
+#define BINARY_SUBSCR_LIST_INT 21
+#define BINARY_SUBSCR_TUPLE_INT 22
+#define CALL_PY_EXACT_ARGS 23
+#define CALL_PY_WITH_DEFAULTS 24
+#define CALL_BOUND_METHOD_EXACT_ARGS 28
+#define CALL_BUILTIN_CLASS 29
+#define CALL_BUILTIN_FAST_WITH_KEYWORDS 34
+#define CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS 38
+#define CALL_NO_KW_BUILTIN_FAST 39
+#define CALL_NO_KW_BUILTIN_O 40
+#define CALL_NO_KW_ISINSTANCE 41
+#define CALL_NO_KW_LEN 42
+#define CALL_NO_KW_LIST_APPEND 43
+#define CALL_NO_KW_METHOD_DESCRIPTOR_FAST 44
+#define CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS 45
+#define CALL_NO_KW_METHOD_DESCRIPTOR_O 46
+#define CALL_NO_KW_STR_1 47
+#define CALL_NO_KW_TUPLE_1 48
+#define CALL_NO_KW_TYPE_1 56
+#define COMPARE_OP_FLOAT 57
+#define COMPARE_OP_INT 58
+#define COMPARE_OP_STR 59
+#define FOR_ITER_LIST 62
+#define FOR_ITER_TUPLE 63
+#define FOR_ITER_RANGE 64
+#define FOR_ITER_GEN 65
+#define LOAD_SUPER_ATTR_METHOD 66
+#define LOAD_ATTR_CLASS 67
+#define LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN 70
+#define LOAD_ATTR_INSTANCE_VALUE 72
+#define LOAD_ATTR_MODULE 73
+#define LOAD_ATTR_PROPERTY 76
+#define LOAD_ATTR_SLOT 77
+#define LOAD_ATTR_WITH_HINT 78
+#define LOAD_ATTR_METHOD_LAZY_DICT 79
+#define LOAD_ATTR_METHOD_NO_DICT 80
+#define LOAD_ATTR_METHOD_WITH_VALUES 81
+#define LOAD_CONST__LOAD_FAST 82
+#define LOAD_FAST__LOAD_CONST 84
+#define LOAD_FAST__LOAD_FAST 86
+#define LOAD_GLOBAL_BUILTIN 87
+#define LOAD_GLOBAL_MODULE 88
+#define STORE_ATTR_INSTANCE_VALUE 111
+#define STORE_ATTR_SLOT 112
+#define STORE_ATTR_WITH_HINT 113
+#define STORE_FAST__LOAD_FAST 143
+#define STORE_FAST__STORE_FAST 153
+#define STORE_SUBSCR_DICT 154
+#define STORE_SUBSCR_LIST_INT 158
+#define UNPACK_SEQUENCE_LIST 159
+#define UNPACK_SEQUENCE_TUPLE 160
+#define UNPACK_SEQUENCE_TWO_TUPLE 161
+#define SEND_GEN 166
#define HAS_ARG(op) ((((op) >= HAVE_ARGUMENT) && (!IS_PSEUDO_OPCODE(op)))\
|| ((op) == JUMP) \
|| ((op) == JUMP_NO_INTERRUPT) \
|| ((op) == LOAD_METHOD) \
+ || ((op) == LOAD_SUPER_METHOD) \
+ || ((op) == LOAD_ZERO_SUPER_METHOD) \
+ || ((op) == LOAD_ZERO_SUPER_ATTR) \
)
#define HAS_CONST(op) (false\
diff --git a/Include/pyport.h b/Include/pyport.h
index eef0fe1bfd71d8..bd0ba6d0681b21 100644
--- a/Include/pyport.h
+++ b/Include/pyport.h
@@ -184,7 +184,6 @@ typedef Py_ssize_t Py_ssize_clean_t;
# define Py_LOCAL_INLINE(type) static inline type
#endif
-// bpo-28126: Py_MEMCPY is kept for backwards compatibility,
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 < 0x030b0000
# define Py_MEMCPY memcpy
#endif
@@ -663,6 +662,27 @@ extern char * _getpty(int *, int, mode_t, int);
# define WITH_THREAD
#endif
+#ifdef WITH_THREAD
+# ifdef Py_BUILD_CORE
+# ifdef HAVE_THREAD_LOCAL
+# error "HAVE_THREAD_LOCAL is already defined"
+# endif
+# define HAVE_THREAD_LOCAL 1
+# ifdef thread_local
+# define _Py_thread_local thread_local
+# elif __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_THREADS__)
+# define _Py_thread_local _Thread_local
+# elif defined(_MSC_VER) /* AKA NT_THREADS */
+# define _Py_thread_local __declspec(thread)
+# elif defined(__GNUC__) /* includes clang */
+# define _Py_thread_local __thread
+# else
+ // fall back to the PyThread_tss_*() API, or ignore.
+# undef HAVE_THREAD_LOCAL
+# endif
+# endif
+#endif
+
/* Check that ALT_SOABI is consistent with Py_TRACE_REFS:
./configure --with-trace-refs should must be used to define Py_TRACE_REFS */
#if defined(ALT_SOABI) && defined(Py_TRACE_REFS)
diff --git a/Include/pystats.h b/Include/pystats.h
index 25ed4bddc7240c..4b961bad2a43e4 100644
--- a/Include/pystats.h
+++ b/Include/pystats.h
@@ -72,8 +72,6 @@ typedef struct _object_stats {
uint64_t type_cache_collisions;
} ObjectStats;
-#
-
typedef struct _stats {
OpcodeStats opcode_stats[256];
CallStats call_stats;
diff --git a/Lib/abc.py b/Lib/abc.py
index 42048ddb855381..f8a4e11ce9c3b1 100644
--- a/Lib/abc.py
+++ b/Lib/abc.py
@@ -18,7 +18,7 @@ class that has a metaclass derived from ABCMeta cannot be
class C(metaclass=ABCMeta):
@abstractmethod
- def my_abstract_method(self, ...):
+ def my_abstract_method(self, arg1, arg2, argN):
...
"""
funcobj.__isabstractmethod__ = True
diff --git a/Lib/ast.py b/Lib/ast.py
index 93afa7d8035de8..06df9a77255d7a 100644
--- a/Lib/ast.py
+++ b/Lib/ast.py
@@ -25,6 +25,7 @@
:license: Python License.
"""
import sys
+import re
from _ast import *
from contextlib import contextmanager, nullcontext
from enum import IntEnum, auto, _simple_enum
@@ -305,28 +306,17 @@ def get_docstring(node, clean=True):
return text
-def _splitlines_no_ff(source):
+_line_pattern = re.compile(r"(.*?(?:\r\n|\n|\r|$))")
+def _splitlines_no_ff(source, maxlines=None):
"""Split a string into lines ignoring form feed and other chars.
This mimics how the Python parser splits source code.
"""
- idx = 0
lines = []
- next_line = ''
- while idx < len(source):
- c = source[idx]
- next_line += c
- idx += 1
- # Keep \r\n together
- if c == '\r' and idx < len(source) and source[idx] == '\n':
- next_line += '\n'
- idx += 1
- if c in '\r\n':
- lines.append(next_line)
- next_line = ''
-
- if next_line:
- lines.append(next_line)
+ for lineno, match in enumerate(_line_pattern.finditer(source), 1):
+ if maxlines is not None and lineno > maxlines:
+ break
+ lines.append(match[0])
return lines
@@ -360,7 +350,7 @@ def get_source_segment(source, node, *, padded=False):
except AttributeError:
return None
- lines = _splitlines_no_ff(source)
+ lines = _splitlines_no_ff(source, maxlines=end_lineno+1)
if end_lineno == lineno:
return lines[lineno].encode()[col_offset:end_col_offset].decode()
diff --git a/Lib/asyncio/selector_events.py b/Lib/asyncio/selector_events.py
index de5076a96218e0..3a697129e4c914 100644
--- a/Lib/asyncio/selector_events.py
+++ b/Lib/asyncio/selector_events.py
@@ -1176,6 +1176,9 @@ def writelines(self, list_of_data):
return
self._buffer.extend([memoryview(data) for data in list_of_data])
self._write_ready()
+ # If the entire buffer couldn't be written, register a write handler
+ if self._buffer:
+ self._loop._add_writer(self._sock_fd, self._write_ready)
def can_write_eof(self):
return True
diff --git a/Lib/bdb.py b/Lib/bdb.py
index 7f9b09514ffd00..0f3eec653baaad 100644
--- a/Lib/bdb.py
+++ b/Lib/bdb.py
@@ -574,6 +574,8 @@ def format_stack_entry(self, frame_lineno, lprefix=': '):
line = linecache.getline(filename, lineno, frame.f_globals)
if line:
s += lprefix + line.strip()
+ else:
+ s += f'{lprefix}Warning: lineno is None'
return s
# The following methods can be called by clients to use
diff --git a/Lib/calendar.py b/Lib/calendar.py
index 657396439c91fc..c219f0c218d9fa 100644
--- a/Lib/calendar.py
+++ b/Lib/calendar.py
@@ -7,6 +7,7 @@
import sys
import datetime
+from enum import IntEnum, global_enum
import locale as _locale
from itertools import repeat
@@ -16,6 +17,9 @@
"timegm", "month_name", "month_abbr", "day_name", "day_abbr",
"Calendar", "TextCalendar", "HTMLCalendar", "LocaleTextCalendar",
"LocaleHTMLCalendar", "weekheader",
+ "Day", "Month", "JANUARY", "FEBRUARY", "MARCH",
+ "APRIL", "MAY", "JUNE", "JULY",
+ "AUGUST", "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER",
"MONDAY", "TUESDAY", "WEDNESDAY", "THURSDAY", "FRIDAY",
"SATURDAY", "SUNDAY"]
@@ -37,9 +41,35 @@ def __str__(self):
return "bad weekday number %r; must be 0 (Monday) to 6 (Sunday)" % self.weekday
-# Constants for months referenced later
-January = 1
-February = 2
+# Constants for months
+@global_enum
+class Month(IntEnum):
+ JANUARY = 1
+ FEBRUARY = 2
+ MARCH = 3
+ APRIL = 4
+ MAY = 5
+ JUNE = 6
+ JULY = 7
+ AUGUST = 8
+ SEPTEMBER = 9
+ OCTOBER = 10
+ NOVEMBER = 11
+ DECEMBER = 12
+
+
+# Constants for days
+@global_enum
+class Day(IntEnum):
+ MONDAY = 0
+ TUESDAY = 1
+ WEDNESDAY = 2
+ THURSDAY = 3
+ FRIDAY = 4
+ SATURDAY = 5
+ SUNDAY = 6
+
+
# Number of days per month (except for February in leap years)
mdays = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
@@ -95,9 +125,6 @@ def __len__(self):
month_name = _localized_month('%B')
month_abbr = _localized_month('%b')
-# Constants for weekdays
-(MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7)
-
def isleap(year):
"""Return True for leap years, False for non-leap years."""
@@ -125,12 +152,12 @@ def monthrange(year, month):
if not 1 <= month <= 12:
raise IllegalMonthError(month)
day1 = weekday(year, month, 1)
- ndays = mdays[month] + (month == February and isleap(year))
+ ndays = mdays[month] + (month == FEBRUARY and isleap(year))
return day1, ndays
def _monthlen(year, month):
- return mdays[month] + (month == February and isleap(year))
+ return mdays[month] + (month == FEBRUARY and isleap(year))
def _prevmonth(year, month):
@@ -260,10 +287,7 @@ def yeardatescalendar(self, year, width=3):
Each month contains between 4 and 6 weeks and each week contains 1-7
days. Days are datetime.date objects.
"""
- months = [
- self.monthdatescalendar(year, i)
- for i in range(January, January+12)
- ]
+ months = [self.monthdatescalendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
def yeardays2calendar(self, year, width=3):
@@ -273,10 +297,7 @@ def yeardays2calendar(self, year, width=3):
(day number, weekday number) tuples. Day numbers outside this month are
zero.
"""
- months = [
- self.monthdays2calendar(year, i)
- for i in range(January, January+12)
- ]
+ months = [self.monthdays2calendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
def yeardayscalendar(self, year, width=3):
@@ -285,10 +306,7 @@ def yeardayscalendar(self, year, width=3):
yeardatescalendar()). Entries in the week lists are day numbers.
Day numbers outside this month are zero.
"""
- months = [
- self.monthdayscalendar(year, i)
- for i in range(January, January+12)
- ]
+ months = [self.monthdayscalendar(year, m) for m in Month]
return [months[i:i+width] for i in range(0, len(months), width) ]
@@ -509,7 +527,7 @@ def formatyear(self, theyear, width=3):
a('\n')
a('%s ' % (
width, self.cssclass_year_head, theyear))
- for i in range(January, January+12, width):
+ for i in range(JANUARY, JANUARY+12, width):
# months in this row
months = range(i, min(i+width, 13))
a('')
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index a5393aad4249c0..03ca2d7e18f6f0 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -45,6 +45,11 @@
else:
_collections_abc.MutableSequence.register(deque)
+try:
+ from _collections import _deque_iterator
+except ImportError:
+ pass
+
try:
from _collections import defaultdict
except ImportError:
diff --git a/Lib/contextlib.py b/Lib/contextlib.py
index 30d9ac25b2bbec..b5acbcb9e6d77c 100644
--- a/Lib/contextlib.py
+++ b/Lib/contextlib.py
@@ -441,7 +441,16 @@ def __exit__(self, exctype, excinst, exctb):
# exactly reproduce the limitations of the CPython interpreter.
#
# See http://bugs.python.org/issue12029 for more details
- return exctype is not None and issubclass(exctype, self._exceptions)
+ if exctype is None:
+ return
+ if issubclass(exctype, self._exceptions):
+ return True
+ if issubclass(exctype, ExceptionGroup):
+ match, rest = excinst.split(self._exceptions)
+ if rest is None:
+ return True
+ raise rest
+ return False
class _BaseExitStack:
diff --git a/Lib/csv.py b/Lib/csv.py
index 4ef8be45ca9e0a..77f30c8d2b1f61 100644
--- a/Lib/csv.py
+++ b/Lib/csv.py
@@ -9,12 +9,14 @@
unregister_dialect, get_dialect, list_dialects, \
field_size_limit, \
QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE, \
+ QUOTE_STRINGS, QUOTE_NOTNULL, \
__doc__
from _csv import Dialect as _Dialect
from io import StringIO
__all__ = ["QUOTE_MINIMAL", "QUOTE_ALL", "QUOTE_NONNUMERIC", "QUOTE_NONE",
+ "QUOTE_STRINGS", "QUOTE_NOTNULL",
"Error", "Dialect", "__doc__", "excel", "excel_tab",
"field_size_limit", "reader", "writer",
"register_dialect", "get_dialect", "list_dialects", "Sniffer",
diff --git a/Lib/dataclasses.py b/Lib/dataclasses.py
index 7558287bad449e..a73cdc22a5f4b3 100644
--- a/Lib/dataclasses.py
+++ b/Lib/dataclasses.py
@@ -222,6 +222,29 @@ def __repr__(self):
# https://bugs.python.org/issue33453 for details.
_MODULE_IDENTIFIER_RE = re.compile(r'^(?:\s*(\w+)\s*\.)?\s*(\w+)')
+# Atomic immutable types which don't require any recursive handling and for which deepcopy
+# returns the same object. We can provide a fast-path for these types in asdict and astuple.
+_ATOMIC_TYPES = frozenset({
+ # Common JSON Serializable types
+ types.NoneType,
+ bool,
+ int,
+ float,
+ str,
+ # Other common types
+ complex,
+ bytes,
+ # Other types that are also unaffected by deepcopy
+ types.EllipsisType,
+ types.NotImplementedType,
+ types.CodeType,
+ types.BuiltinFunctionType,
+ types.FunctionType,
+ type,
+ range,
+ property,
+})
+
# This function's logic is copied from "recursive_repr" function in
# reprlib module to avoid dependency.
def _recursive_repr(user_function):
@@ -1105,8 +1128,13 @@ def _process_class(cls, init, repr, eq, order, unsafe_hash, frozen,
if not getattr(cls, '__doc__'):
# Create a class doc-string.
- cls.__doc__ = (cls.__name__ +
- str(inspect.signature(cls)).replace(' -> None', ''))
+ try:
+ # In some cases fetching a signature is not possible.
+ # But, we surely should not fail in this case.
+ text_sig = str(inspect.signature(cls)).replace(' -> None', '')
+ except (TypeError, ValueError):
+ text_sig = ''
+ cls.__doc__ = (cls.__name__ + text_sig)
if match_args:
# I could probably compute this once
@@ -1291,7 +1319,9 @@ class C:
def _asdict_inner(obj, dict_factory):
- if _is_dataclass_instance(obj):
+ if type(obj) in _ATOMIC_TYPES:
+ return obj
+ elif _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _asdict_inner(getattr(obj, f.name), dict_factory)
@@ -1363,7 +1393,9 @@ class C:
def _astuple_inner(obj, tuple_factory):
- if _is_dataclass_instance(obj):
+ if type(obj) in _ATOMIC_TYPES:
+ return obj
+ elif _is_dataclass_instance(obj):
result = []
for f in fields(obj):
value = _astuple_inner(getattr(obj, f.name), tuple_factory)
diff --git a/Lib/datetime.py b/Lib/datetime.py
index 637144637485bc..09a2d2d5381c34 100644
--- a/Lib/datetime.py
+++ b/Lib/datetime.py
@@ -1965,6 +1965,11 @@ def replace(self, year=None, month=None, day=None, hour=None,
def _local_timezone(self):
if self.tzinfo is None:
ts = self._mktime()
+ # Detect gap
+ ts2 = self.replace(fold=1-self.fold)._mktime()
+ if ts2 != ts: # This happens in a gap or a fold
+ if (ts2 > ts) == self.fold:
+ ts = ts2
else:
ts = (self - _EPOCH) // timedelta(seconds=1)
localtm = _time.localtime(ts)
diff --git a/Lib/dis.py b/Lib/dis.py
index b39b2835330135..8af84c00d0cf64 100644
--- a/Lib/dis.py
+++ b/Lib/dis.py
@@ -41,6 +41,7 @@
FOR_ITER = opmap['FOR_ITER']
SEND = opmap['SEND']
LOAD_ATTR = opmap['LOAD_ATTR']
+LOAD_SUPER_ATTR = opmap['LOAD_SUPER_ATTR']
CACHE = opmap["CACHE"]
@@ -64,10 +65,10 @@ def _try_compile(source, name):
expect code objects
"""
try:
- c = compile(source, name, 'eval')
+ return compile(source, name, 'eval')
except SyntaxError:
- c = compile(source, name, 'exec')
- return c
+ pass
+ return compile(source, name, 'exec')
def dis(x=None, *, file=None, depth=None, show_caches=False, adaptive=False):
"""Disassemble classes, methods, functions, and other compiled objects.
@@ -475,6 +476,10 @@ def _get_instructions_bytes(code, varname_from_oparg=None,
argval, argrepr = _get_name_info(arg//2, get_name)
if (arg & 1) and argrepr:
argrepr = "NULL|self + " + argrepr
+ elif deop == LOAD_SUPER_ATTR:
+ argval, argrepr = _get_name_info(arg//4, get_name)
+ if (arg & 1) and argrepr:
+ argrepr = "NULL|self + " + argrepr
else:
argval, argrepr = _get_name_info(arg, get_name)
elif deop in hasjabs:
diff --git a/Lib/email/_header_value_parser.py b/Lib/email/_header_value_parser.py
index e637e6df06612d..0d6bd812475eea 100644
--- a/Lib/email/_header_value_parser.py
+++ b/Lib/email/_header_value_parser.py
@@ -1987,7 +1987,7 @@ def get_address_list(value):
try:
token, value = get_address(value)
address_list.append(token)
- except errors.HeaderParseError as err:
+ except errors.HeaderParseError:
leader = None
if value[0] in CFWS_LEADER:
leader, value = get_cfws(value)
@@ -2096,7 +2096,7 @@ def get_msg_id(value):
except errors.HeaderParseError:
try:
token, value = get_no_fold_literal(value)
- except errors.HeaderParseError as e:
+ except errors.HeaderParseError:
try:
token, value = get_domain(value)
msg_id.defects.append(errors.ObsoleteHeaderDefect(
@@ -2443,7 +2443,6 @@ def get_parameter(value):
raise errors.HeaderParseError("Parameter not followed by '='")
param.append(ValueTerminal('=', 'parameter-separator'))
value = value[1:]
- leader = None
if value and value[0] in CFWS_LEADER:
token, value = get_cfws(value)
param.append(token)
@@ -2568,7 +2567,7 @@ def parse_mime_parameters(value):
try:
token, value = get_parameter(value)
mime_parameters.append(token)
- except errors.HeaderParseError as err:
+ except errors.HeaderParseError:
leader = None
if value[0] in CFWS_LEADER:
leader, value = get_cfws(value)
@@ -2626,7 +2625,6 @@ def parse_content_type_header(value):
don't do that.
"""
ctype = ContentType()
- recover = False
if not value:
ctype.defects.append(errors.HeaderMissingRequiredValue(
"Missing content type specification"))
diff --git a/Lib/email/charset.py b/Lib/email/charset.py
index 9af269442fb8af..043801107b60e5 100644
--- a/Lib/email/charset.py
+++ b/Lib/email/charset.py
@@ -341,7 +341,6 @@ def header_encode_lines(self, string, maxlengths):
if not lines and not current_line:
lines.append(None)
else:
- separator = (' ' if lines else '')
joined_line = EMPTYSTRING.join(current_line)
header_bytes = _encode(joined_line, codec)
lines.append(encoder(header_bytes))
diff --git a/Lib/email/feedparser.py b/Lib/email/feedparser.py
index 6bc4e0c4e59895..885097c7dda067 100644
--- a/Lib/email/feedparser.py
+++ b/Lib/email/feedparser.py
@@ -264,7 +264,7 @@ def _parsegen(self):
yield NeedMoreData
continue
break
- msg = self._pop_message()
+ self._pop_message()
# We need to pop the EOF matcher in order to tell if we're at
# the end of the current file, not the end of the last block
# of message headers.
diff --git a/Lib/email/message.py b/Lib/email/message.py
index b540c33984a753..411118c74dabb4 100644
--- a/Lib/email/message.py
+++ b/Lib/email/message.py
@@ -14,7 +14,7 @@
# Intrapackage imports
from email import utils
from email import errors
-from email._policybase import Policy, compat32
+from email._policybase import compat32
from email import charset as _charset
from email._encoded_words import decode_b
Charset = _charset.Charset
diff --git a/Lib/email/mime/text.py b/Lib/email/mime/text.py
index dfe53c426b2ac4..7672b789138600 100644
--- a/Lib/email/mime/text.py
+++ b/Lib/email/mime/text.py
@@ -6,7 +6,6 @@
__all__ = ['MIMEText']
-from email.charset import Charset
from email.mime.nonmultipart import MIMENonMultipart
@@ -36,6 +35,6 @@ def __init__(self, _text, _subtype='plain', _charset=None, *, policy=None):
_charset = 'utf-8'
MIMENonMultipart.__init__(self, 'text', _subtype, policy=policy,
- **{'charset': str(_charset)})
+ charset=str(_charset))
self.set_payload(_text, _charset)
diff --git a/Lib/ensurepip/__init__.py b/Lib/ensurepip/__init__.py
index 00e77749e25e77..4278422dfacc9f 100644
--- a/Lib/ensurepip/__init__.py
+++ b/Lib/ensurepip/__init__.py
@@ -9,11 +9,9 @@
__all__ = ["version", "bootstrap"]
-_PACKAGE_NAMES = ('setuptools', 'pip')
-_SETUPTOOLS_VERSION = "65.5.0"
-_PIP_VERSION = "23.0.1"
+_PACKAGE_NAMES = ('pip',)
+_PIP_VERSION = "23.1.1"
_PROJECTS = [
- ("setuptools", _SETUPTOOLS_VERSION, "py3"),
("pip", _PIP_VERSION, "py3"),
]
@@ -153,17 +151,17 @@ def _bootstrap(*, root=None, upgrade=False, user=False,
_disable_pip_configuration_settings()
- # By default, installing pip and setuptools installs all of the
+ # By default, installing pip installs all of the
# following scripts (X.Y == running Python version):
#
- # pip, pipX, pipX.Y, easy_install, easy_install-X.Y
+ # pip, pipX, pipX.Y
#
# pip 1.5+ allows ensurepip to request that some of those be left out
if altinstall:
- # omit pip, pipX and easy_install
+ # omit pip, pipX
os.environ["ENSUREPIP_OPTIONS"] = "altinstall"
elif not default_pip:
- # omit pip and easy_install
+ # omit pip
os.environ["ENSUREPIP_OPTIONS"] = "install"
with tempfile.TemporaryDirectory() as tmpdir:
@@ -271,14 +269,14 @@ def _main(argv=None):
action="store_true",
default=False,
help=("Make an alternate install, installing only the X.Y versioned "
- "scripts (Default: pipX, pipX.Y, easy_install-X.Y)."),
+ "scripts (Default: pipX, pipX.Y)."),
)
parser.add_argument(
"--default-pip",
action="store_true",
default=False,
help=("Make a default pip install, installing the unqualified pip "
- "and easy_install in addition to the versioned scripts."),
+ "in addition to the versioned scripts."),
)
args = parser.parse_args(argv)
diff --git a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl b/Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl
similarity index 76%
rename from Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl
rename to Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl
index a855dc40e8630d..dee4c0304b2c36 100644
Binary files a/Lib/ensurepip/_bundled/pip-23.0.1-py3-none-any.whl and b/Lib/ensurepip/_bundled/pip-23.1.1-py3-none-any.whl differ
diff --git a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl b/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl
deleted file mode 100644
index 123a13e2c6b254..00000000000000
Binary files a/Lib/ensurepip/_bundled/setuptools-65.5.0-py3-none-any.whl and /dev/null differ
diff --git a/Lib/enum.py b/Lib/enum.py
index 10902c4b202a2d..6e497f7ef6a7de 100644
--- a/Lib/enum.py
+++ b/Lib/enum.py
@@ -190,6 +190,8 @@ class property(DynamicClassAttribute):
"""
member = None
+ _attr_type = None
+ _cls_type = None
def __get__(self, instance, ownerclass=None):
if instance is None:
@@ -199,33 +201,36 @@ def __get__(self, instance, ownerclass=None):
raise AttributeError(
'%r has no attribute %r' % (ownerclass, self.name)
)
- else:
- if self.fget is None:
- # look for a member by this name.
- try:
- return ownerclass._member_map_[self.name]
- except KeyError:
- raise AttributeError(
- '%r has no attribute %r' % (ownerclass, self.name)
- ) from None
- else:
- return self.fget(instance)
+ if self.fget is not None:
+ # use previous enum.property
+ return self.fget(instance)
+ elif self._attr_type == 'attr':
+ # look up previous attibute
+ return getattr(self._cls_type, self.name)
+ elif self._attr_type == 'desc':
+ # use previous descriptor
+ return getattr(instance._value_, self.name)
+ # look for a member by this name.
+ try:
+ return ownerclass._member_map_[self.name]
+ except KeyError:
+ raise AttributeError(
+ '%r has no attribute %r' % (ownerclass, self.name)
+ ) from None
def __set__(self, instance, value):
- if self.fset is None:
- raise AttributeError(
- " cannot set attribute %r" % (self.clsname, self.name)
- )
- else:
+ if self.fset is not None:
return self.fset(instance, value)
+ raise AttributeError(
+ " cannot set attribute %r" % (self.clsname, self.name)
+ )
def __delete__(self, instance):
- if self.fdel is None:
- raise AttributeError(
- " cannot delete attribute %r" % (self.clsname, self.name)
- )
- else:
+ if self.fdel is not None:
return self.fdel(instance)
+ raise AttributeError(
+ " cannot delete attribute %r" % (self.clsname, self.name)
+ )
def __set_name__(self, ownerclass, name):
self.name = name
@@ -275,6 +280,13 @@ def __set_name__(self, enum_class, member_name):
enum_member.__objclass__ = enum_class
enum_member.__init__(*args)
enum_member._sort_order_ = len(enum_class._member_names_)
+
+ if Flag is not None and issubclass(enum_class, Flag):
+ enum_class._flag_mask_ |= value
+ if _is_single_bit(value):
+ enum_class._singles_mask_ |= value
+ enum_class._all_bits_ = 2 ** ((enum_class._flag_mask_).bit_length()) - 1
+
# If another member with the same value was already defined, the
# new member becomes an alias to the existing one.
try:
@@ -306,27 +318,38 @@ def __set_name__(self, enum_class, member_name):
enum_class._member_names_.append(member_name)
# if necessary, get redirect in place and then add it to _member_map_
found_descriptor = None
+ descriptor_type = None
+ class_type = None
for base in enum_class.__mro__[1:]:
- descriptor = base.__dict__.get(member_name)
- if descriptor is not None:
- if isinstance(descriptor, (property, DynamicClassAttribute)):
- found_descriptor = descriptor
+ attr = base.__dict__.get(member_name)
+ if attr is not None:
+ if isinstance(attr, (property, DynamicClassAttribute)):
+ found_descriptor = attr
+ class_type = base
+ descriptor_type = 'enum'
break
- elif (
- hasattr(descriptor, 'fget') and
- hasattr(descriptor, 'fset') and
- hasattr(descriptor, 'fdel')
- ):
- found_descriptor = descriptor
+ elif _is_descriptor(attr):
+ found_descriptor = attr
+ descriptor_type = descriptor_type or 'desc'
+ class_type = class_type or base
continue
+ else:
+ descriptor_type = 'attr'
+ class_type = base
if found_descriptor:
redirect = property()
redirect.member = enum_member
redirect.__set_name__(enum_class, member_name)
- # earlier descriptor found; copy fget, fset, fdel to this one.
- redirect.fget = found_descriptor.fget
- redirect.fset = found_descriptor.fset
- redirect.fdel = found_descriptor.fdel
+ if descriptor_type in ('enum','desc'):
+ # earlier descriptor found; copy fget, fset, fdel to this one.
+ redirect.fget = getattr(found_descriptor, 'fget', None)
+ redirect._get = getattr(found_descriptor, '__get__', None)
+ redirect.fset = getattr(found_descriptor, 'fset', None)
+ redirect._set = getattr(found_descriptor, '__set__', None)
+ redirect.fdel = getattr(found_descriptor, 'fdel', None)
+ redirect._del = getattr(found_descriptor, '__delete__', None)
+ redirect._attr_type = descriptor_type
+ redirect._cls_type = class_type
setattr(enum_class, member_name, redirect)
else:
setattr(enum_class, member_name, enum_member)
@@ -532,12 +555,8 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
classdict['_use_args_'] = use_args
#
# convert future enum members into temporary _proto_members
- # and record integer values in case this will be a Flag
- flag_mask = 0
for name in member_names:
value = classdict[name]
- if isinstance(value, int):
- flag_mask |= value
classdict[name] = _proto_member(value)
#
# house-keeping structures
@@ -554,8 +573,9 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
boundary
or getattr(first_enum, '_boundary_', None)
)
- classdict['_flag_mask_'] = flag_mask
- classdict['_all_bits_'] = 2 ** ((flag_mask).bit_length()) - 1
+ classdict['_flag_mask_'] = 0
+ classdict['_singles_mask_'] = 0
+ classdict['_all_bits_'] = 0
classdict['_inverted_'] = None
try:
exc = None
@@ -644,21 +664,10 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k
):
delattr(enum_class, '_boundary_')
delattr(enum_class, '_flag_mask_')
+ delattr(enum_class, '_singles_mask_')
delattr(enum_class, '_all_bits_')
delattr(enum_class, '_inverted_')
elif Flag is not None and issubclass(enum_class, Flag):
- # ensure _all_bits_ is correct and there are no missing flags
- single_bit_total = 0
- multi_bit_total = 0
- for flag in enum_class._member_map_.values():
- flag_value = flag._value_
- if _is_single_bit(flag_value):
- single_bit_total |= flag_value
- else:
- # multi-bit flags are considered aliases
- multi_bit_total |= flag_value
- enum_class._flag_mask_ = single_bit_total
- #
# set correct __iter__
member_list = [m._value_ for m in enum_class]
if member_list != sorted(member_list):
@@ -974,6 +983,7 @@ def _find_data_repr_(mcls, class_name, bases):
@classmethod
def _find_data_type_(mcls, class_name, bases):
+ # a datatype has a __new__ method, or a __dataclass_fields__ attribute
data_types = set()
base_chain = set()
for chain in bases:
@@ -986,7 +996,7 @@ def _find_data_type_(mcls, class_name, bases):
if base._member_type_ is not object:
data_types.add(base._member_type_)
break
- elif '__new__' in base.__dict__ or '__init__' in base.__dict__:
+ elif '__new__' in base.__dict__ or '__dataclass_fields__' in base.__dict__:
data_types.add(candidate or base)
break
else:
@@ -1303,8 +1313,8 @@ def _reduce_ex_by_global_name(self, proto):
class FlagBoundary(StrEnum):
"""
control how out of range values are handled
- "strict" -> error is raised
- "conform" -> extra bits are discarded [default for Flag]
+ "strict" -> error is raised [default for Flag]
+ "conform" -> extra bits are discarded
"eject" -> lose flag status
"keep" -> keep flag status and all bits [default for IntFlag]
"""
@@ -1315,7 +1325,7 @@ class FlagBoundary(StrEnum):
STRICT, CONFORM, EJECT, KEEP = FlagBoundary
-class Flag(Enum, boundary=CONFORM):
+class Flag(Enum, boundary=STRICT):
"""
Support for flags
"""
@@ -1394,6 +1404,7 @@ def _missing_(cls, value):
# - value must not include any skipped flags (e.g. if bit 2 is not
# defined, then 0d10 is invalid)
flag_mask = cls._flag_mask_
+ singles_mask = cls._singles_mask_
all_bits = cls._all_bits_
neg_value = None
if (
@@ -1425,7 +1436,8 @@ def _missing_(cls, value):
value = all_bits + 1 + value
# get members and unknown
unknown = value & ~flag_mask
- member_value = value & flag_mask
+ aliases = value & ~singles_mask
+ member_value = value & singles_mask
if unknown and cls._boundary_ is not KEEP:
raise ValueError(
'%s(%r) --> unknown values %r [%s]'
@@ -1439,11 +1451,25 @@ def _missing_(cls, value):
pseudo_member = cls._member_type_.__new__(cls, value)
if not hasattr(pseudo_member, '_value_'):
pseudo_member._value_ = value
- if member_value:
- pseudo_member._name_ = '|'.join([
- m._name_ for m in cls._iter_member_(member_value)
- ])
- if unknown:
+ if member_value or aliases:
+ members = []
+ combined_value = 0
+ for m in cls._iter_member_(member_value):
+ members.append(m)
+ combined_value |= m._value_
+ if aliases:
+ value = member_value | aliases
+ for n, pm in cls._member_map_.items():
+ if pm not in members and pm._value_ and pm._value_ & value == pm._value_:
+ members.append(pm)
+ combined_value |= pm._value_
+ unknown = value ^ combined_value
+ pseudo_member._name_ = '|'.join([m._name_ for m in members])
+ if not combined_value:
+ pseudo_member._name_ = None
+ elif unknown and cls._boundary_ is STRICT:
+ raise ValueError('%r: no members with value %r' % (cls, unknown))
+ elif unknown:
pseudo_member._name_ += '|%s' % cls._numeric_repr_(unknown)
else:
pseudo_member._name_ = None
@@ -1675,6 +1701,7 @@ def convert_class(cls):
body['_boundary_'] = boundary or etype._boundary_
body['_flag_mask_'] = None
body['_all_bits_'] = None
+ body['_singles_mask_'] = None
body['_inverted_'] = None
body['__or__'] = Flag.__or__
body['__xor__'] = Flag.__xor__
@@ -1750,7 +1777,8 @@ def convert_class(cls):
else:
multi_bits |= value
gnv_last_values.append(value)
- enum_class._flag_mask_ = single_bits
+ enum_class._flag_mask_ = single_bits | multi_bits
+ enum_class._singles_mask_ = single_bits
enum_class._all_bits_ = 2 ** ((single_bits|multi_bits).bit_length()) - 1
# set correct __iter__
member_list = [m._value_ for m in enum_class]
diff --git a/Lib/idlelib/calltip_w.py b/Lib/idlelib/calltip_w.py
index 1e0404aa49f562..278546064adde2 100644
--- a/Lib/idlelib/calltip_w.py
+++ b/Lib/idlelib/calltip_w.py
@@ -25,7 +25,7 @@ def __init__(self, text_widget):
text_widget: a Text widget with code for which call-tips are desired
"""
# Note: The Text widget will be accessible as self.anchor_widget
- super(CalltipWindow, self).__init__(text_widget)
+ super().__init__(text_widget)
self.label = self.text = None
self.parenline = self.parencol = self.lastline = None
@@ -54,7 +54,7 @@ def position_window(self):
return
self.lastline = curline
self.anchor_widget.see("insert")
- super(CalltipWindow, self).position_window()
+ super().position_window()
def showtip(self, text, parenleft, parenright):
"""Show the call-tip, bind events which will close it and reposition it.
@@ -73,7 +73,7 @@ def showtip(self, text, parenleft, parenright):
self.parenline, self.parencol = map(
int, self.anchor_widget.index(parenleft).split("."))
- super(CalltipWindow, self).showtip()
+ super().showtip()
self._bind_events()
@@ -143,7 +143,7 @@ def hidetip(self):
# ValueError may be raised by MultiCall
pass
- super(CalltipWindow, self).hidetip()
+ super().hidetip()
def _bind_events(self):
"""Bind event handlers."""
diff --git a/Lib/idlelib/debugger.py b/Lib/idlelib/debugger.py
index ccd03e46e16147..452c62b42655b3 100644
--- a/Lib/idlelib/debugger.py
+++ b/Lib/idlelib/debugger.py
@@ -49,9 +49,9 @@ def __frame2message(self, frame):
filename = code.co_filename
lineno = frame.f_lineno
basename = os.path.basename(filename)
- message = "%s:%s" % (basename, lineno)
+ message = f"{basename}:{lineno}"
if code.co_name != "?":
- message = "%s: %s()" % (message, code.co_name)
+ message = f"{message}: {code.co_name}()"
return message
@@ -213,7 +213,8 @@ def interaction(self, message, frame, info=None):
m1 = "%s" % str(type)
if value is not None:
try:
- m1 = "%s: %s" % (m1, str(value))
+ # TODO redo entire section, tries not needed.
+ m1 = f"{m1}: {value}"
except:
pass
bg = "yellow"
diff --git a/Lib/idlelib/debugobj.py b/Lib/idlelib/debugobj.py
index 5a4c9978842035..71d01c7070df54 100644
--- a/Lib/idlelib/debugobj.py
+++ b/Lib/idlelib/debugobj.py
@@ -87,7 +87,7 @@ def GetSubList(self):
continue
def setfunction(value, key=key, object=self.object):
object[key] = value
- item = make_objecttreeitem("%r:" % (key,), value, setfunction)
+ item = make_objecttreeitem(f"{key!r}:", value, setfunction)
sublist.append(item)
return sublist
diff --git a/Lib/idlelib/editor.py b/Lib/idlelib/editor.py
index 08d6aa2efde22a..505815502600b1 100644
--- a/Lib/idlelib/editor.py
+++ b/Lib/idlelib/editor.py
@@ -38,12 +38,13 @@
def _sphinx_version():
"Format sys.version_info to produce the Sphinx version string used to install the chm docs"
major, minor, micro, level, serial = sys.version_info
- release = '%s%s' % (major, minor)
- release += '%s' % (micro,)
+ # TODO remove unneeded function since .chm no longer installed
+ release = f'{major}{minor}'
+ release += f'{micro}'
if level == 'candidate':
- release += 'rc%s' % (serial,)
+ release += f'rc{serial}'
elif level != 'final':
- release += '%s%s' % (level[0], serial)
+ release += f'{level[0]}{serial}'
return release
@@ -950,7 +951,7 @@ def update_recent_files_list(self, new_file=None):
rf_list = []
file_path = self.recent_files_path
if file_path and os.path.exists(file_path):
- with open(file_path, 'r',
+ with open(file_path,
encoding='utf_8', errors='replace') as rf_list_file:
rf_list = rf_list_file.readlines()
if new_file:
@@ -1458,7 +1459,7 @@ def newline_and_indent_event(self, event):
else:
self.reindent_to(y.compute_backslash_indent())
else:
- assert 0, "bogus continuation type %r" % (c,)
+ assert 0, f"bogus continuation type {c!r}"
return "break"
# This line starts a brand new statement; indent relative to
diff --git a/Lib/idlelib/filelist.py b/Lib/idlelib/filelist.py
index 254f5caf6b81b0..f87781d2570fe0 100644
--- a/Lib/idlelib/filelist.py
+++ b/Lib/idlelib/filelist.py
@@ -22,7 +22,7 @@ def open(self, filename, action=None):
# This can happen when bad filename is passed on command line:
messagebox.showerror(
"File Error",
- "%r is a directory." % (filename,),
+ f"{filename!r} is a directory.",
master=self.root)
return None
key = os.path.normcase(filename)
@@ -90,7 +90,7 @@ def filename_changed_edit(self, edit):
self.inversedict[conflict] = None
messagebox.showerror(
"Name Conflict",
- "You now have multiple edit windows open for %r" % (filename,),
+ f"You now have multiple edit windows open for {filename!r}",
master=self.root)
self.dict[newkey] = edit
self.inversedict[edit] = newkey
diff --git a/Lib/idlelib/idle_test/test_config.py b/Lib/idlelib/idle_test/test_config.py
index 697fda527968de..08ed76fe288294 100644
--- a/Lib/idlelib/idle_test/test_config.py
+++ b/Lib/idlelib/idle_test/test_config.py
@@ -191,7 +191,7 @@ def setUpClass(cls):
idle_dir = os.path.abspath(sys.path[0])
for ctype in conf.config_types:
config_path = os.path.join(idle_dir, '../config-%s.def' % ctype)
- with open(config_path, 'r') as f:
+ with open(config_path) as f:
cls.config_string[ctype] = f.read()
cls.orig_warn = config._warn
diff --git a/Lib/idlelib/idle_test/test_outwin.py b/Lib/idlelib/idle_test/test_outwin.py
index e347bfca7f191a..d6e85ad674417c 100644
--- a/Lib/idlelib/idle_test/test_outwin.py
+++ b/Lib/idlelib/idle_test/test_outwin.py
@@ -159,7 +159,7 @@ def test_file_line_helper(self, mock_open):
for line, expected_output in test_lines:
self.assertEqual(flh(line), expected_output)
if expected_output:
- mock_open.assert_called_with(expected_output[0], 'r')
+ mock_open.assert_called_with(expected_output[0])
if __name__ == '__main__':
diff --git a/Lib/idlelib/idle_test/test_sidebar.py b/Lib/idlelib/idle_test/test_sidebar.py
index 049531e66a414e..5506fd2b0e22a5 100644
--- a/Lib/idlelib/idle_test/test_sidebar.py
+++ b/Lib/idlelib/idle_test/test_sidebar.py
@@ -328,7 +328,7 @@ def test_scroll(self):
self.assertEqual(self.linenumber.sidebar_text.index('@0,0'), '11.0')
# Generate a mouse-wheel event and make sure it scrolled up or down.
- # The meaning of the "delta" is OS-dependant, so this just checks for
+ # The meaning of the "delta" is OS-dependent, so this just checks for
# any change.
self.linenumber.sidebar_text.event_generate('',
x=0, y=0,
@@ -691,7 +691,7 @@ def test_mousewheel(self):
self.assertIsNotNone(text.dlineinfo(text.index(f'{last_lineno}.0')))
# Scroll up using the event.
- # The meaning delta is platform-dependant.
+ # The meaning of delta is platform-dependent.
delta = -1 if sys.platform == 'darwin' else 120
sidebar.canvas.event_generate('', x=0, y=0, delta=delta)
yield
diff --git a/Lib/idlelib/multicall.py b/Lib/idlelib/multicall.py
index dc02001292fc14..0200f445cc9340 100644
--- a/Lib/idlelib/multicall.py
+++ b/Lib/idlelib/multicall.py
@@ -52,9 +52,9 @@
_modifier_masks = (MC_CONTROL, MC_ALT, MC_SHIFT, MC_META)
# a dictionary to map a modifier name into its number
-_modifier_names = dict([(name, number)
+_modifier_names = {name: number
for number in range(len(_modifiers))
- for name in _modifiers[number]])
+ for name in _modifiers[number]}
# In 3.4, if no shell window is ever open, the underlying Tk widget is
# destroyed before .__del__ methods here are called. The following
@@ -134,7 +134,7 @@ def nbits(n):
return nb
statelist = []
for state in states:
- substates = list(set(state & x for x in states))
+ substates = list({state & x for x in states})
substates.sort(key=nbits, reverse=True)
statelist.append(substates)
return statelist
@@ -258,9 +258,9 @@ def __del__(self):
_binder_classes = (_ComplexBinder,) * 4 + (_SimpleBinder,) * (len(_types)-4)
# A dictionary to map a type name into its number
-_type_names = dict([(name, number)
+_type_names = {name: number
for number in range(len(_types))
- for name in _types[number]])
+ for name in _types[number]}
_keysym_re = re.compile(r"^\w+$")
_button_re = re.compile(r"^[1-5]$")
diff --git a/Lib/idlelib/outwin.py b/Lib/idlelib/outwin.py
index 5ab08bbaf4bc95..ac67c904ab9797 100644
--- a/Lib/idlelib/outwin.py
+++ b/Lib/idlelib/outwin.py
@@ -42,7 +42,7 @@ def file_line_helper(line):
if match:
filename, lineno = match.group(1, 2)
try:
- f = open(filename, "r")
+ f = open(filename)
f.close()
break
except OSError:
diff --git a/Lib/idlelib/pyshell.py b/Lib/idlelib/pyshell.py
index e68233a5a4131e..bdde156166171b 100755
--- a/Lib/idlelib/pyshell.py
+++ b/Lib/idlelib/pyshell.py
@@ -249,7 +249,7 @@ def store_file_breaks(self):
breaks = self.breakpoints
filename = self.io.filename
try:
- with open(self.breakpointPath, "r") as fp:
+ with open(self.breakpointPath) as fp:
lines = fp.readlines()
except OSError:
lines = []
@@ -279,7 +279,7 @@ def restore_file_breaks(self):
if filename is None:
return
if os.path.isfile(self.breakpointPath):
- with open(self.breakpointPath, "r") as fp:
+ with open(self.breakpointPath) as fp:
lines = fp.readlines()
for line in lines:
if line.startswith(filename + '='):
@@ -441,7 +441,7 @@ def build_subprocess_arglist(self):
# run from the IDLE source directory.
del_exitf = idleConf.GetOption('main', 'General', 'delete-exitfunc',
default=False, type='bool')
- command = "__import__('idlelib.run').run.main(%r)" % (del_exitf,)
+ command = f"__import__('idlelib.run').run.main({del_exitf!r})"
return [sys.executable] + w + ["-c", command, str(self.port)]
def start_subprocess(self):
@@ -574,9 +574,9 @@ def transfer_path(self, with_cwd=False):
self.runcommand("""if 1:
import sys as _sys
- _sys.path = %r
+ _sys.path = {!r}
del _sys
- \n""" % (path,))
+ \n""".format(path))
active_seq = None
@@ -703,14 +703,14 @@ def stuffsource(self, source):
def prepend_syspath(self, filename):
"Prepend sys.path with file's directory if not already included"
self.runcommand("""if 1:
- _filename = %r
+ _filename = {!r}
import sys as _sys
from os.path import dirname as _dirname
_dir = _dirname(_filename)
if not _dir in _sys.path:
_sys.path.insert(0, _dir)
del _filename, _sys, _dirname, _dir
- \n""" % (filename,))
+ \n""".format(filename))
def showsyntaxerror(self, filename=None):
"""Override Interactive Interpreter method: Use Colorizing
@@ -1536,7 +1536,7 @@ def main():
try:
opts, args = getopt.getopt(sys.argv[1:], "c:deihnr:st:")
except getopt.error as msg:
- print("Error: %s\n%s" % (msg, usage_msg), file=sys.stderr)
+ print(f"Error: {msg}\n{usage_msg}", file=sys.stderr)
sys.exit(2)
for o, a in opts:
if o == '-c':
@@ -1668,9 +1668,9 @@ def main():
if cmd or script:
shell.interp.runcommand("""if 1:
import sys as _sys
- _sys.argv = %r
+ _sys.argv = {!r}
del _sys
- \n""" % (sys.argv,))
+ \n""".format(sys.argv))
if cmd:
shell.interp.execsource(cmd)
elif script:
diff --git a/Lib/idlelib/redirector.py b/Lib/idlelib/redirector.py
index 9ab34c5acfb22c..4928340e98df68 100644
--- a/Lib/idlelib/redirector.py
+++ b/Lib/idlelib/redirector.py
@@ -47,9 +47,8 @@ def __init__(self, widget):
tk.createcommand(w, self.dispatch)
def __repr__(self):
- return "%s(%s<%s>)" % (self.__class__.__name__,
- self.widget.__class__.__name__,
- self.widget._w)
+ w = self.widget
+ return f"{self.__class__.__name__,}({w.__class__.__name__}<{w._w}>)"
def close(self):
"Unregister operations and revert redirection created by .__init__."
@@ -143,8 +142,7 @@ def __init__(self, redir, operation):
self.orig_and_operation = (redir.orig, operation)
def __repr__(self):
- return "%s(%r, %r)" % (self.__class__.__name__,
- self.redir, self.operation)
+ return f"{self.__class__.__name__,}({self.redir!r}, {self.operation!r})"
def __call__(self, *args):
return self.tk_call(self.orig_and_operation + args)
diff --git a/Lib/idlelib/rpc.py b/Lib/idlelib/rpc.py
index 62eec84c9c8d09..b08b80c9004551 100644
--- a/Lib/idlelib/rpc.py
+++ b/Lib/idlelib/rpc.py
@@ -174,7 +174,7 @@ def localcall(self, seq, request):
except TypeError:
return ("ERROR", "Bad request format")
if oid not in self.objtable:
- return ("ERROR", "Unknown object id: %r" % (oid,))
+ return ("ERROR", f"Unknown object id: {oid!r}")
obj = self.objtable[oid]
if methodname == "__methods__":
methods = {}
@@ -185,7 +185,7 @@ def localcall(self, seq, request):
_getattributes(obj, attributes)
return ("OK", attributes)
if not hasattr(obj, methodname):
- return ("ERROR", "Unsupported method name: %r" % (methodname,))
+ return ("ERROR", f"Unsupported method name: {methodname!r}")
method = getattr(obj, methodname)
try:
if how == 'CALL':
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 577c49eb67b20d..84792a82b0022c 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -52,13 +52,13 @@ def idle_formatwarning(message, category, filename, lineno, line=None):
"""Format warnings the IDLE way."""
s = "\nWarning (from warnings module):\n"
- s += ' File \"%s\", line %s\n' % (filename, lineno)
+ s += f' File \"{filename}\", line {lineno}\n'
if line is None:
line = linecache.getline(filename, lineno)
line = line.strip()
if line:
s += " %s\n" % line
- s += "%s: %s\n" % (category.__name__, message)
+ s += f"{category.__name__}: {message}\n"
return s
def idle_showwarning_subproc(
@@ -239,6 +239,7 @@ def print_exception():
efile = sys.stderr
typ, val, tb = excinfo = sys.exc_info()
sys.last_type, sys.last_value, sys.last_traceback = excinfo
+ sys.last_exc = val
seen = set()
def print_exc(typ, exc, tb):
diff --git a/Lib/idlelib/textview.py b/Lib/idlelib/textview.py
index a66c1a4309a617..23f0f4cb5027ec 100644
--- a/Lib/idlelib/textview.py
+++ b/Lib/idlelib/textview.py
@@ -169,7 +169,7 @@ def view_file(parent, title, filename, encoding, modal=True, wrap='word',
with contents of the file.
"""
try:
- with open(filename, 'r', encoding=encoding) as file:
+ with open(filename, encoding=encoding) as file:
contents = file.read()
except OSError:
showerror(title='File Load Error',
diff --git a/Lib/idlelib/tooltip.py b/Lib/idlelib/tooltip.py
index d714318dae8ef1..3983690dd41177 100644
--- a/Lib/idlelib/tooltip.py
+++ b/Lib/idlelib/tooltip.py
@@ -92,7 +92,7 @@ def __init__(self, anchor_widget, hover_delay=1000):
e.g. after hovering over the anchor widget with the mouse for enough
time.
"""
- super(OnHoverTooltipBase, self).__init__(anchor_widget)
+ super().__init__(anchor_widget)
self.hover_delay = hover_delay
self._after_id = None
@@ -107,7 +107,7 @@ def __del__(self):
self.anchor_widget.unbind("", self._id3) # pragma: no cover
except TclError:
pass
- super(OnHoverTooltipBase, self).__del__()
+ super().__del__()
def _show_event(self, event=None):
"""event handler to display the tooltip"""
@@ -139,7 +139,7 @@ def hidetip(self):
self.unschedule()
except TclError: # pragma: no cover
pass
- super(OnHoverTooltipBase, self).hidetip()
+ super().hidetip()
class Hovertip(OnHoverTooltipBase):
@@ -154,7 +154,7 @@ def __init__(self, anchor_widget, text, hover_delay=1000):
e.g. after hovering over the anchor widget with the mouse for enough
time.
"""
- super(Hovertip, self).__init__(anchor_widget, hover_delay=hover_delay)
+ super().__init__(anchor_widget, hover_delay=hover_delay)
self.text = text
def showcontents(self):
diff --git a/Lib/idlelib/tree.py b/Lib/idlelib/tree.py
index 5947268f5c35ae..5f30f0f6092bfa 100644
--- a/Lib/idlelib/tree.py
+++ b/Lib/idlelib/tree.py
@@ -32,7 +32,7 @@
if os.path.isdir(_icondir):
ICONDIR = _icondir
elif not os.path.isdir(ICONDIR):
- raise RuntimeError("can't find icon directory (%r)" % (ICONDIR,))
+ raise RuntimeError(f"can't find icon directory ({ICONDIR!r})")
def listicons(icondir=ICONDIR):
"""Utility to display the available icons."""
diff --git a/Lib/idlelib/undo.py b/Lib/idlelib/undo.py
index 85ecffecb4cbcb..5f10c0f05c1acb 100644
--- a/Lib/idlelib/undo.py
+++ b/Lib/idlelib/undo.py
@@ -309,7 +309,7 @@ def __repr__(self):
s = self.__class__.__name__
strs = []
for cmd in self.cmds:
- strs.append(" %r" % (cmd,))
+ strs.append(f" {cmd!r}")
return s + "(\n" + ",\n".join(strs) + "\n)"
def __len__(self):
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index 22fa2469964ab3..e4fcaa61e6de29 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -1260,7 +1260,7 @@ def _find_and_load_unlocked(name, import_):
try:
path = parent_module.__path__
except AttributeError:
- msg = f'{_ERR_MSG_PREFIX} {name!r}; {parent!r} is not a package'
+ msg = f'{_ERR_MSG_PREFIX}{name!r}; {parent!r} is not a package'
raise ModuleNotFoundError(msg, name=name) from None
parent_spec = parent_module.__spec__
child = name.rpartition('.')[2]
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index de6c434450fc82..cb227373ca2fd4 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -439,6 +439,9 @@ def _write_atomic(path, data, mode=0o666):
# Python 3.12a7 3523 (Convert COMPARE_AND_BRANCH back to COMPARE_OP)
# Python 3.12a7 3524 (Shrink the BINARY_SUBSCR caches)
# Python 3.12b1 3525 (Shrink the CALL caches)
+# Python 3.12b1 3526 (Add instrumentation support)
+# Python 3.12b1 3527 (Add LOAD_SUPER_ATTR)
+# Python 3.12b1 3528 (Add LOAD_SUPER_ATTR_METHOD specialization)
# Python 3.13 will start with 3550
@@ -455,7 +458,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 = (3525).to_bytes(2, 'little') + b'\r\n'
+MAGIC_NUMBER = (3528).to_bytes(2, 'little') + b'\r\n'
_RAW_MAGIC_NUMBER = int.from_bytes(MAGIC_NUMBER, 'little') # For import.c
diff --git a/Lib/importlib/metadata/__init__.py b/Lib/importlib/metadata/__init__.py
index 40ab1a1aaac328..82e0ce1b281c54 100644
--- a/Lib/importlib/metadata/__init__.py
+++ b/Lib/importlib/metadata/__init__.py
@@ -12,7 +12,9 @@
import functools
import itertools
import posixpath
+import contextlib
import collections
+import inspect
from . import _adapters, _meta
from ._collections import FreezableDefaultDict, Pair
@@ -24,7 +26,7 @@
from importlib import import_module
from importlib.abc import MetaPathFinder
from itertools import starmap
-from typing import List, Mapping, Optional
+from typing import List, Mapping, Optional, cast
__all__ = [
@@ -341,11 +343,30 @@ def __repr__(self):
return f''
-class Distribution:
+class DeprecatedNonAbstract:
+ def __new__(cls, *args, **kwargs):
+ all_names = {
+ name for subclass in inspect.getmro(cls) for name in vars(subclass)
+ }
+ abstract = {
+ name
+ for name in all_names
+ if getattr(getattr(cls, name), '__isabstractmethod__', False)
+ }
+ if abstract:
+ warnings.warn(
+ f"Unimplemented abstract methods {abstract}",
+ DeprecationWarning,
+ stacklevel=2,
+ )
+ return super().__new__(cls)
+
+
+class Distribution(DeprecatedNonAbstract):
"""A Python distribution package."""
@abc.abstractmethod
- def read_text(self, filename):
+ def read_text(self, filename) -> Optional[str]:
"""Attempt to load metadata file given by the name.
:param filename: The name of the file in the distribution info.
@@ -419,7 +440,7 @@ def metadata(self) -> _meta.PackageMetadata:
The returned object will have keys that name the various bits of
metadata. See PEP 566 for details.
"""
- text = (
+ opt_text = (
self.read_text('METADATA')
or self.read_text('PKG-INFO')
# This last clause is here to support old egg-info files. Its
@@ -427,6 +448,7 @@ def metadata(self) -> _meta.PackageMetadata:
# (which points to the egg-info file) attribute unchanged.
or self.read_text('')
)
+ text = cast(str, opt_text)
return _adapters.Message(email.message_from_string(text))
@property
@@ -455,8 +477,8 @@ def files(self):
:return: List of PackagePath for this distribution or None
Result is `None` if the metadata file that enumerates files
- (i.e. RECORD for dist-info or SOURCES.txt for egg-info) is
- missing.
+ (i.e. RECORD for dist-info, or installed-files.txt or
+ SOURCES.txt for egg-info) is missing.
Result may be empty if the metadata exists but is empty.
"""
@@ -469,9 +491,19 @@ def make_file(name, hash=None, size_str=None):
@pass_none
def make_files(lines):
- return list(starmap(make_file, csv.reader(lines)))
+ return starmap(make_file, csv.reader(lines))
- return make_files(self._read_files_distinfo() or self._read_files_egginfo())
+ @pass_none
+ def skip_missing_files(package_paths):
+ return list(filter(lambda path: path.locate().exists(), package_paths))
+
+ return skip_missing_files(
+ make_files(
+ self._read_files_distinfo()
+ or self._read_files_egginfo_installed()
+ or self._read_files_egginfo_sources()
+ )
+ )
def _read_files_distinfo(self):
"""
@@ -480,10 +512,45 @@ def _read_files_distinfo(self):
text = self.read_text('RECORD')
return text and text.splitlines()
- def _read_files_egginfo(self):
+ def _read_files_egginfo_installed(self):
+ """
+ Read installed-files.txt and return lines in a similar
+ CSV-parsable format as RECORD: each file must be placed
+ relative to the site-packages directory and must also be
+ quoted (since file names can contain literal commas).
+
+ This file is written when the package is installed by pip,
+ but it might not be written for other installation methods.
+ Assume the file is accurate if it exists.
"""
- SOURCES.txt might contain literal commas, so wrap each line
- in quotes.
+ text = self.read_text('installed-files.txt')
+ # Prepend the .egg-info/ subdir to the lines in this file.
+ # But this subdir is only available from PathDistribution's
+ # self._path.
+ subdir = getattr(self, '_path', None)
+ if not text or not subdir:
+ return
+
+ paths = (
+ (subdir / name)
+ .resolve()
+ .relative_to(self.locate_file('').resolve())
+ .as_posix()
+ for name in text.splitlines()
+ )
+ return map('"{}"'.format, paths)
+
+ def _read_files_egginfo_sources(self):
+ """
+ Read SOURCES.txt and return lines in a similar CSV-parsable
+ format as RECORD: each file name must be quoted (since it
+ might contain literal commas).
+
+ Note that SOURCES.txt is not a reliable source for what
+ files are installed by a package. This file is generated
+ for a source archive, and the files that are present
+ there (e.g. setup.py) may not correctly reflect the files
+ that are present after the package has been installed.
"""
text = self.read_text('SOURCES.txt')
return text and map('"{}"'.format, text.splitlines())
@@ -886,8 +953,13 @@ def _top_level_declared(dist):
def _top_level_inferred(dist):
- return {
- f.parts[0] if len(f.parts) > 1 else f.with_suffix('').name
+ opt_names = {
+ f.parts[0] if len(f.parts) > 1 else inspect.getmodulename(f)
for f in always_iterable(dist.files)
- if f.suffix == ".py"
}
+
+ @pass_none
+ def importable_name(name):
+ return '.' not in name
+
+ return filter(importable_name, opt_names)
diff --git a/Lib/importlib/metadata/_adapters.py b/Lib/importlib/metadata/_adapters.py
index aa460d3eda50fb..6aed69a30857e4 100644
--- a/Lib/importlib/metadata/_adapters.py
+++ b/Lib/importlib/metadata/_adapters.py
@@ -1,3 +1,5 @@
+import functools
+import warnings
import re
import textwrap
import email.message
@@ -5,6 +7,15 @@
from ._text import FoldedCase
+# Do not remove prior to 2024-01-01 or Python 3.14
+_warn = functools.partial(
+ warnings.warn,
+ "Implicit None on return values is deprecated and will raise KeyErrors.",
+ DeprecationWarning,
+ stacklevel=2,
+)
+
+
class Message(email.message.Message):
multiple_use_keys = set(
map(
@@ -39,6 +50,16 @@ def __init__(self, *args, **kwargs):
def __iter__(self):
return super().__iter__()
+ def __getitem__(self, item):
+ """
+ Warn users that a ``KeyError`` can be expected when a
+ mising key is supplied. Ref python/importlib_metadata#371.
+ """
+ res = super().__getitem__(item)
+ if res is None:
+ _warn()
+ return res
+
def _repair_headers(self):
def redent(value):
"Correct for RFC822 indentation"
diff --git a/Lib/importlib/metadata/_meta.py b/Lib/importlib/metadata/_meta.py
index d5c0576194ece2..c9a7ef906a8a8c 100644
--- a/Lib/importlib/metadata/_meta.py
+++ b/Lib/importlib/metadata/_meta.py
@@ -1,4 +1,5 @@
-from typing import Any, Dict, Iterator, List, Protocol, TypeVar, Union
+from typing import Protocol
+from typing import Any, Dict, Iterator, List, Optional, TypeVar, Union, overload
_T = TypeVar("_T")
@@ -17,7 +18,21 @@ def __getitem__(self, key: str) -> str:
def __iter__(self) -> Iterator[str]:
... # pragma: no cover
- def get_all(self, name: str, failobj: _T = ...) -> Union[List[Any], _T]:
+ @overload
+ def get(self, name: str, failobj: None = None) -> Optional[str]:
+ ... # pragma: no cover
+
+ @overload
+ def get(self, name: str, failobj: _T) -> Union[str, _T]:
+ ... # pragma: no cover
+
+ # overload per python/importlib_metadata#435
+ @overload
+ def get_all(self, name: str, failobj: None = None) -> Optional[List[Any]]:
+ ... # pragma: no cover
+
+ @overload
+ def get_all(self, name: str, failobj: _T) -> Union[List[Any], _T]:
"""
Return all values associated with a possibly multi-valued key.
"""
@@ -29,18 +44,19 @@ def json(self) -> Dict[str, Union[str, List[str]]]:
"""
-class SimplePath(Protocol):
+class SimplePath(Protocol[_T]):
"""
A minimal subset of pathlib.Path required by PathDistribution.
"""
- def joinpath(self) -> 'SimplePath':
+ def joinpath(self) -> _T:
... # pragma: no cover
- def __truediv__(self) -> 'SimplePath':
+ def __truediv__(self, other: Union[str, _T]) -> _T:
... # pragma: no cover
- def parent(self) -> 'SimplePath':
+ @property
+ def parent(self) -> _T:
... # pragma: no cover
def read_text(self) -> str:
diff --git a/Lib/inspect.py b/Lib/inspect.py
index 4242b40c2a08df..6d1d7b766cb3bb 100644
--- a/Lib/inspect.py
+++ b/Lib/inspect.py
@@ -3006,7 +3006,7 @@ def __init__(self, parameters=None, *, return_annotation=_empty,
if __validate_parameters__:
params = OrderedDict()
top_kind = _POSITIONAL_ONLY
- kind_defaults = False
+ seen_default = False
for param in parameters:
kind = param.kind
@@ -3021,21 +3021,19 @@ def __init__(self, parameters=None, *, return_annotation=_empty,
kind.description)
raise ValueError(msg)
elif kind > top_kind:
- kind_defaults = False
top_kind = kind
if kind in (_POSITIONAL_ONLY, _POSITIONAL_OR_KEYWORD):
if param.default is _empty:
- if kind_defaults:
+ if seen_default:
# No default for this parameter, but the
- # previous parameter of the same kind had
- # a default
+ # previous parameter of had a default
msg = 'non-default argument follows default ' \
'argument'
raise ValueError(msg)
else:
# There is a default for this parameter.
- kind_defaults = True
+ seen_default = True
if name in params:
msg = 'duplicate parameter name: {!r}'.format(name)
diff --git a/Lib/ipaddress.py b/Lib/ipaddress.py
index 1cb71d8032e173..af1d5c4800cce8 100644
--- a/Lib/ipaddress.py
+++ b/Lib/ipaddress.py
@@ -1821,9 +1821,6 @@ def _string_from_ip_int(cls, ip_int=None):
def _explode_shorthand_ip_string(self):
"""Expand a shortened IPv6 address.
- Args:
- ip_str: A string, the IPv6 address.
-
Returns:
A string, the expanded IPv6 address.
diff --git a/Lib/logging/config.py b/Lib/logging/config.py
index 7cd16c643e9dad..16c54a6a4f7a2f 100644
--- a/Lib/logging/config.py
+++ b/Lib/logging/config.py
@@ -114,11 +114,18 @@ def _create_formatters(cp):
fs = cp.get(sectname, "format", raw=True, fallback=None)
dfs = cp.get(sectname, "datefmt", raw=True, fallback=None)
stl = cp.get(sectname, "style", raw=True, fallback='%')
+ defaults = cp.get(sectname, "defaults", raw=True, fallback=None)
+
c = logging.Formatter
class_name = cp[sectname].get("class")
if class_name:
c = _resolve(class_name)
- f = c(fs, dfs, stl)
+
+ if defaults is not None:
+ defaults = eval(defaults, vars(logging))
+ f = c(fs, dfs, stl, defaults=defaults)
+ else:
+ f = c(fs, dfs, stl)
formatters[form] = f
return formatters
@@ -668,18 +675,27 @@ def configure_formatter(self, config):
dfmt = config.get('datefmt', None)
style = config.get('style', '%')
cname = config.get('class', None)
+ defaults = config.get('defaults', None)
if not cname:
c = logging.Formatter
else:
c = _resolve(cname)
+ kwargs = {}
+
+ # Add defaults only if it exists.
+ # Prevents TypeError in custom formatter callables that do not
+ # accept it.
+ if defaults is not None:
+ kwargs['defaults'] = defaults
+
# A TypeError would be raised if "validate" key is passed in with a formatter callable
# that does not accept "validate" as a parameter
if 'validate' in config: # if user hasn't mentioned it, the default will be fine
- result = c(fmt, dfmt, style, config['validate'])
+ result = c(fmt, dfmt, style, config['validate'], **kwargs)
else:
- result = c(fmt, dfmt, style)
+ result = c(fmt, dfmt, style, **kwargs)
return result
diff --git a/Lib/ntpath.py b/Lib/ntpath.py
index 6e2da79c85d3f0..0f3674fe11eecd 100644
--- a/Lib/ntpath.py
+++ b/Lib/ntpath.py
@@ -142,7 +142,7 @@ def join(path, *paths):
result_path = result_path + p_path
## add separator between UNC and non-absolute path
if (result_path and not result_root and
- result_drive and result_drive[-1:] != colon):
+ result_drive and result_drive[-1:] not in colon + seps):
return result_drive + sep + result_path
return result_drive + result_root + result_path
except (TypeError, AttributeError, BytesWarning):
diff --git a/Lib/opcode.py b/Lib/opcode.py
index b62dfa1bcb42c5..aef8407948df15 100644
--- a/Lib/opcode.py
+++ b/Lib/opcode.py
@@ -83,6 +83,7 @@ def pseudo_op(name, op, real_ops):
def_op('INTERPRETER_EXIT', 3)
def_op('END_FOR', 4)
+def_op('END_SEND', 5)
def_op('NOP', 9)
@@ -91,6 +92,10 @@ def pseudo_op(name, op, real_ops):
def_op('UNARY_INVERT', 15)
+# 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('BINARY_SUBSCR', 25)
def_op('BINARY_SLICE', 26)
def_op('STORE_SLICE', 27)
@@ -191,7 +196,7 @@ def pseudo_op(name, op, real_ops):
def_op('DELETE_DEREF', 139)
hasfree.append(139)
jrel_op('JUMP_BACKWARD', 140) # Number of words to skip (backwards)
-
+name_op('LOAD_SUPER_ATTR', 141)
def_op('CALL_FUNCTION_EX', 142) # Flags
def_op('EXTENDED_ARG', 144)
@@ -221,6 +226,28 @@ def pseudo_op(name, op, real_ops):
def_op('CALL_INTRINSIC_1', 173)
def_op('CALL_INTRINSIC_2', 174)
+# Instrumented instructions
+MIN_INSTRUMENTED_OPCODE = 238
+
+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
+
hasarg.extend([op for op in opmap.values() if op >= HAVE_ARGUMENT])
MIN_PSEUDO_OPCODE = 256
@@ -237,6 +264,9 @@ def pseudo_op(name, op, real_ops):
pseudo_op('JUMP_NO_INTERRUPT', 261, ['JUMP_FORWARD', 'JUMP_BACKWARD_NO_INTERRUPT'])
pseudo_op('LOAD_METHOD', 262, ['LOAD_ATTR'])
+pseudo_op('LOAD_SUPER_METHOD', 263, ['LOAD_SUPER_ATTR'])
+pseudo_op('LOAD_ZERO_SUPER_METHOD', 264, ['LOAD_SUPER_ATTR'])
+pseudo_op('LOAD_ZERO_SUPER_ATTR', 265, ['LOAD_SUPER_ATTR'])
MAX_PSEUDO_OPCODE = MIN_PSEUDO_OPCODE + len(_pseudo_ops) - 1
@@ -323,6 +353,9 @@ def pseudo_op(name, op, real_ops):
"FOR_ITER_RANGE",
"FOR_ITER_GEN",
],
+ "LOAD_SUPER_ATTR": [
+ "LOAD_SUPER_ATTR_METHOD",
+ ],
"LOAD_ATTR": [
# These potentially push [NULL, bound method] onto the stack.
"LOAD_ATTR_CLASS",
@@ -396,6 +429,12 @@ def pseudo_op(name, op, real_ops):
"FOR_ITER": {
"counter": 1,
},
+ "LOAD_SUPER_ATTR": {
+ "counter": 1,
+ "class_version": 2,
+ "self_type_version": 2,
+ "method": 4,
+ },
"LOAD_ATTR": {
"counter": 1,
"version": 2,
diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 490f89f39d26d1..f43f01ef41a97f 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -210,20 +210,17 @@ def _select_from(self, parent_path, is_dir, exists, scandir, normcase):
class _PathParents(Sequence):
"""This object provides sequence-like access to the logical ancestors
of a path. Don't try to construct it yourself."""
- __slots__ = ('_pathcls', '_drv', '_root', '_parts')
+ __slots__ = ('_pathcls', '_drv', '_root', '_tail')
def __init__(self, path):
# We don't store the instance to avoid reference cycles
self._pathcls = type(path)
self._drv = path.drive
self._root = path.root
- self._parts = path._parts
+ self._tail = path._tail
def __len__(self):
- if self._drv or self._root:
- return len(self._parts) - 1
- else:
- return len(self._parts)
+ return len(self._tail)
def __getitem__(self, idx):
if isinstance(idx, slice):
@@ -234,7 +231,7 @@ def __getitem__(self, idx):
if idx < 0:
idx += len(self)
return self._pathcls._from_parsed_parts(self._drv, self._root,
- self._parts[:-idx - 1])
+ self._tail[:-idx - 1])
def __repr__(self):
return "<{}.parents>".format(self._pathcls.__name__)
@@ -249,9 +246,41 @@ class PurePath(object):
PureWindowsPath object. You can also instantiate either of these classes
directly, regardless of your system.
"""
+
__slots__ = (
- '_raw_path', '_drv', '_root', '_parts_cached',
- '_str', '_hash', '_parts_tuple', '_parts_normcase_cached',
+ # The `_raw_path` slot stores an unnormalized string path. This is set
+ # in the `__init__()` method.
+ '_raw_path',
+
+ # The `_drv`, `_root` and `_tail_cached` slots store parsed and
+ # normalized parts of the path. They are set when any of the `drive`,
+ # `root` or `_tail` properties are accessed for the first time. The
+ # three-part division corresponds to the result of
+ # `os.path.splitroot()`, except that the tail is further split on path
+ # separators (i.e. it is a list of strings), and that the root and
+ # tail are normalized.
+ '_drv', '_root', '_tail_cached',
+
+ # The `_str` slot stores the string representation of the path,
+ # computed from the drive, root and tail when `__str__()` is called
+ # for the first time. It's used to implement `_str_normcase`
+ '_str',
+
+ # The `_str_normcase_cached` slot stores the string path with
+ # normalized case. It is set when the `_str_normcase` property is
+ # accessed for the first time. It's used to implement `__eq__()`
+ # `__hash__()`, and `_parts_normcase`
+ '_str_normcase_cached',
+
+ # The `_parts_normcase_cached` slot stores the case-normalized
+ # string path after splitting on path separators. It's set when the
+ # `_parts_normcase` property is accessed for the first time. It's used
+ # to implement comparison methods like `__lt__()`.
+ '_parts_normcase_cached',
+
+ # The `_hash` slot stores the hash of the case-normalized string
+ # path. It's set when `__hash__()` is called for the first time.
+ '_hash',
)
_flavour = os.path
@@ -277,10 +306,7 @@ def __init__(self, *args):
path = os.fspath(args[0])
else:
path = self._flavour.join(*args)
- if isinstance(path, str):
- # Force-cast str subclasses to str (issue #21127)
- path = str(path)
- else:
+ if not isinstance(path, str):
raise TypeError(
"argument should be a str or an os.PathLike "
"object where __fspath__ returns a str, "
@@ -296,36 +322,40 @@ def _parse_path(cls, path):
if altsep:
path = path.replace(altsep, sep)
drv, root, rel = cls._flavour.splitroot(path)
- if drv.startswith(sep):
- # pathlib assumes that UNC paths always have a root.
- root = sep
- unfiltered_parsed = [drv + root] + rel.split(sep)
- parsed = [sys.intern(x) for x in unfiltered_parsed if x and x != '.']
+ if not root and drv.startswith(sep) and not drv.endswith(sep):
+ drv_parts = drv.split(sep)
+ if len(drv_parts) == 4 and drv_parts[2] not in '?.':
+ # e.g. //server/share
+ root = sep
+ elif len(drv_parts) == 6:
+ # e.g. //?/unc/server/share
+ root = sep
+ parsed = [sys.intern(str(x)) for x in rel.split(sep) if x and x != '.']
return drv, root, parsed
def _load_parts(self):
- drv, root, parts = self._parse_path(self._raw_path)
+ drv, root, tail = self._parse_path(self._raw_path)
self._drv = drv
self._root = root
- self._parts_cached = parts
+ self._tail_cached = tail
@classmethod
- def _from_parsed_parts(cls, drv, root, parts):
- path = cls._format_parsed_parts(drv, root, parts)
+ def _from_parsed_parts(cls, drv, root, tail):
+ path = cls._format_parsed_parts(drv, root, tail)
self = cls(path)
self._str = path or '.'
self._drv = drv
self._root = root
- self._parts_cached = parts
+ self._tail_cached = tail
return self
@classmethod
- def _format_parsed_parts(cls, drv, root, parts):
+ def _format_parsed_parts(cls, drv, root, tail):
if drv or root:
- return drv + root + cls._flavour.sep.join(parts[1:])
- elif parts and cls._flavour.splitdrive(parts[0])[0]:
- parts = ['.'] + parts
- return cls._flavour.sep.join(parts)
+ return drv + root + cls._flavour.sep.join(tail)
+ elif tail and cls._flavour.splitdrive(tail[0])[0]:
+ tail = ['.'] + tail
+ return cls._flavour.sep.join(tail)
def __str__(self):
"""Return the string representation of the path, suitable for
@@ -334,7 +364,7 @@ def __str__(self):
return self._str
except AttributeError:
self._str = self._format_parsed_parts(self.drive, self.root,
- self._parts) or '.'
+ self._tail) or '.'
return self._str
def __fspath__(self):
@@ -374,25 +404,34 @@ def as_uri(self):
path = str(self)
return prefix + urlquote_from_bytes(os.fsencode(path))
+ @property
+ def _str_normcase(self):
+ # String with normalized case, for hashing and equality checks
+ try:
+ return self._str_normcase_cached
+ except AttributeError:
+ self._str_normcase_cached = self._flavour.normcase(str(self))
+ return self._str_normcase_cached
+
@property
def _parts_normcase(self):
- # Cached parts with normalized case, for hashing and comparison.
+ # Cached parts with normalized case, for comparisons.
try:
return self._parts_normcase_cached
except AttributeError:
- self._parts_normcase_cached = [self._flavour.normcase(p) for p in self._parts]
+ self._parts_normcase_cached = self._str_normcase.split(self._flavour.sep)
return self._parts_normcase_cached
def __eq__(self, other):
if not isinstance(other, PurePath):
return NotImplemented
- return self._parts_normcase == other._parts_normcase and self._flavour is other._flavour
+ return self._str_normcase == other._str_normcase and self._flavour is other._flavour
def __hash__(self):
try:
return self._hash
except AttributeError:
- self._hash = hash(tuple(self._parts_normcase))
+ self._hash = hash(self._str_normcase)
return self._hash
def __lt__(self, other):
@@ -434,12 +473,12 @@ def root(self):
return self._root
@property
- def _parts(self):
+ def _tail(self):
try:
- return self._parts_cached
+ return self._tail_cached
except AttributeError:
self._load_parts()
- return self._parts_cached
+ return self._tail_cached
@property
def anchor(self):
@@ -450,10 +489,10 @@ def anchor(self):
@property
def name(self):
"""The final path component, if any."""
- parts = self._parts
- if len(parts) == (1 if (self.drive or self.root) else 0):
+ tail = self._tail
+ if not tail:
return ''
- return parts[-1]
+ return tail[-1]
@property
def suffix(self):
@@ -501,7 +540,7 @@ def with_name(self, name):
if drv or root or not tail or f.sep in tail or (f.altsep and f.altsep in tail):
raise ValueError("Invalid name %r" % (name))
return self._from_parsed_parts(self.drive, self.root,
- self._parts[:-1] + [name])
+ self._tail[:-1] + [name])
def with_stem(self, stem):
"""Return a new path with the stem changed."""
@@ -526,7 +565,7 @@ def with_suffix(self, suffix):
else:
name = name[:-len(old_suffix)] + suffix
return self._from_parsed_parts(self.drive, self.root,
- self._parts[:-1] + [name])
+ self._tail[:-1] + [name])
def relative_to(self, other, /, *_deprecated, walk_up=False):
"""Return the relative path to another path identified by the passed
@@ -551,7 +590,7 @@ def relative_to(self, other, /, *_deprecated, walk_up=False):
raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
if step and not walk_up:
raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
- parts = ('..',) * step + self.parts[len(path.parts):]
+ parts = ['..'] * step + self._tail[len(path._tail):]
return path_cls(*parts)
def is_relative_to(self, other, /, *_deprecated):
@@ -570,13 +609,10 @@ def is_relative_to(self, other, /, *_deprecated):
def parts(self):
"""An object providing sequence-like access to the
components in the filesystem path."""
- # We cache the tuple to avoid building a new one each time .parts
- # is accessed. XXX is this necessary?
- try:
- return self._parts_tuple
- except AttributeError:
- self._parts_tuple = tuple(self._parts)
- return self._parts_tuple
+ if self.drive or self.root:
+ return (self.drive + self.root,) + tuple(self._tail)
+ else:
+ return tuple(self._tail)
def joinpath(self, *args):
"""Combine this path with one or several arguments, and return a
@@ -603,10 +639,10 @@ def parent(self):
"""The logical parent of the path."""
drv = self.drive
root = self.root
- parts = self._parts
- if len(parts) == 1 and (drv or root):
+ tail = self._tail
+ if not tail:
return self
- return self._from_parsed_parts(drv, root, parts[:-1])
+ return self._from_parsed_parts(drv, root, tail[:-1])
@property
def parents(self):
@@ -624,29 +660,29 @@ def is_absolute(self):
def is_reserved(self):
"""Return True if the path contains one of the special names reserved
by the system, if any."""
- if self._flavour is posixpath or not self._parts:
+ if self._flavour is posixpath or not self._tail:
return False
# NOTE: the rules for reserved names seem somewhat complicated
# (e.g. r"..\NUL" is reserved but not r"foo\NUL" if "foo" does not
# exist). We err on the side of caution and return True for paths
# which are not considered reserved by Windows.
- if self._parts[0].startswith('\\\\'):
+ if self.drive.startswith('\\\\'):
# UNC paths are never reserved.
return False
- name = self._parts[-1].partition('.')[0].partition(':')[0].rstrip(' ')
+ name = self._tail[-1].partition('.')[0].partition(':')[0].rstrip(' ')
return name.upper() in _WIN_RESERVED_NAMES
def match(self, path_pattern):
"""
Return True if this path matches the given pattern.
"""
- path_pattern = self._flavour.normcase(path_pattern)
- drv, root, pat_parts = self._parse_path(path_pattern)
- if not pat_parts:
+ pat = type(self)(path_pattern)
+ if not pat.parts:
raise ValueError("empty pattern")
+ pat_parts = pat._parts_normcase
parts = self._parts_normcase
- if drv or root:
+ if pat.drive or pat.root:
if len(pat_parts) != len(parts):
return False
elif len(pat_parts) > len(parts):
@@ -707,11 +743,21 @@ def __new__(cls, *args, **kwargs):
cls = WindowsPath if os.name == 'nt' else PosixPath
return object.__new__(cls)
- def _make_child_relpath(self, part):
- # This is an optimization used for dir walking. `part` must be
- # a single part relative to this path.
- parts = self._parts + [part]
- return self._from_parsed_parts(self.drive, self.root, parts)
+ def _make_child_relpath(self, name):
+ path_str = str(self)
+ tail = self._tail
+ if tail:
+ path_str = f'{path_str}{self._flavour.sep}{name}'
+ elif path_str != '.':
+ path_str = f'{path_str}{name}'
+ else:
+ path_str = name
+ path = type(self)(path_str)
+ path._str = path_str
+ path._drv = self.drive
+ path._root = self.root
+ path._tail_cached = tail + [name]
+ return path
def __enter__(self):
# In previous versions of pathlib, __exit__() marked this path as
@@ -1196,12 +1242,12 @@ def expanduser(self):
(as returned by os.path.expanduser)
"""
if (not (self.drive or self.root) and
- self._parts and self._parts[0][:1] == '~'):
- homedir = self._flavour.expanduser(self._parts[0])
+ self._tail and self._tail[0][:1] == '~'):
+ homedir = self._flavour.expanduser(self._tail[0])
if homedir[:1] == "~":
raise RuntimeError("Could not determine home directory.")
- drv, root, parts = self._parse_path(homedir)
- return self._from_parsed_parts(drv, root, parts + self._parts[1:])
+ drv, root, tail = self._parse_path(homedir)
+ return self._from_parsed_parts(drv, root, tail + self._tail[1:])
return self
diff --git a/Lib/pdb.py b/Lib/pdb.py
index e043b0d46f7dd0..a3553b345a8dd3 100755
--- a/Lib/pdb.py
+++ b/Lib/pdb.py
@@ -586,7 +586,7 @@ def _complete_expression(self, text, line, begidx, endidx):
# Return true to exit from the command loop
def do_commands(self, arg):
- """commands [bpnumber]
+ """(Pdb) commands [bpnumber]
(com) ...
(com) end
(Pdb)
@@ -672,6 +672,7 @@ def do_commands(self, arg):
def do_break(self, arg, temporary = 0):
"""b(reak) [ ([filename:]lineno | function) [, condition] ]
+
Without argument, list all breaks.
With a line number argument, set a break at this line in the
@@ -780,6 +781,7 @@ def defaultFile(self):
def do_tbreak(self, arg):
"""tbreak [ ([filename:]lineno | function) [, condition] ]
+
Same arguments as break, but sets a temporary breakpoint: it
is automatically deleted when first hit.
"""
@@ -844,6 +846,7 @@ def checkline(self, filename, lineno):
def do_enable(self, arg):
"""enable bpnumber [bpnumber ...]
+
Enables the breakpoints given as a space separated list of
breakpoint numbers.
"""
@@ -861,6 +864,7 @@ def do_enable(self, arg):
def do_disable(self, arg):
"""disable bpnumber [bpnumber ...]
+
Disables the breakpoints given as a space separated list of
breakpoint numbers. Disabling a breakpoint means it cannot
cause the program to stop execution, but unlike clearing a
@@ -881,6 +885,7 @@ def do_disable(self, arg):
def do_condition(self, arg):
"""condition bpnumber [condition]
+
Set a new condition for the breakpoint, an expression which
must evaluate to true before the breakpoint is honored. If
condition is absent, any existing condition is removed; i.e.,
@@ -911,6 +916,7 @@ def do_condition(self, arg):
def do_ignore(self, arg):
"""ignore bpnumber [count]
+
Set the ignore count for the given breakpoint number. If
count is omitted, the ignore count is set to 0. A breakpoint
becomes active when the ignore count is zero. When non-zero,
@@ -945,7 +951,8 @@ def do_ignore(self, arg):
complete_ignore = _complete_bpnumber
def do_clear(self, arg):
- """cl(ear) filename:lineno\ncl(ear) [bpnumber [bpnumber...]]
+ """cl(ear) [filename:lineno | bpnumber ...]
+
With a space separated list of breakpoint numbers, clear
those breakpoints. Without argument, clear all breaks (but
first ask confirmation). With a filename:lineno argument,
@@ -997,6 +1004,7 @@ def do_clear(self, arg):
def do_where(self, arg):
"""w(here)
+
Print a stack trace, with the most recent frame at the bottom.
An arrow indicates the "current frame", which determines the
context of most commands. 'bt' is an alias for this command.
@@ -1015,6 +1023,7 @@ def _select_frame(self, number):
def do_up(self, arg):
"""u(p) [count]
+
Move the current frame count (default one) levels up in the
stack trace (to an older frame).
"""
@@ -1035,6 +1044,7 @@ def do_up(self, arg):
def do_down(self, arg):
"""d(own) [count]
+
Move the current frame count (default one) levels down in the
stack trace (to a newer frame).
"""
@@ -1055,6 +1065,7 @@ def do_down(self, arg):
def do_until(self, arg):
"""unt(il) [lineno]
+
Without argument, continue execution until the line with a
number greater than the current one is reached. With a line
number, continue execution until a line with a number greater
@@ -1079,6 +1090,7 @@ def do_until(self, arg):
def do_step(self, arg):
"""s(tep)
+
Execute the current line, stop at the first possible occasion
(either in a function that is called or in the current
function).
@@ -1089,6 +1101,7 @@ def do_step(self, arg):
def do_next(self, arg):
"""n(ext)
+
Continue execution until the next line in the current function
is reached or it returns.
"""
@@ -1098,6 +1111,7 @@ def do_next(self, arg):
def do_run(self, arg):
"""run [args...]
+
Restart the debugged python program. If a string is supplied
it is split with "shlex", and the result is used as the new
sys.argv. History, breakpoints, actions and debugger options
@@ -1119,6 +1133,7 @@ def do_run(self, arg):
def do_return(self, arg):
"""r(eturn)
+
Continue execution until the current function returns.
"""
self.set_return(self.curframe)
@@ -1127,6 +1142,7 @@ def do_return(self, arg):
def do_continue(self, arg):
"""c(ont(inue))
+
Continue execution, only stop when a breakpoint is encountered.
"""
if not self.nosigint:
@@ -1145,6 +1161,7 @@ def do_continue(self, arg):
def do_jump(self, arg):
"""j(ump) lineno
+
Set the next line that will be executed. Only available in
the bottom-most frame. This lets you jump back and execute
code again, or jump forward to skip code that you don't want
@@ -1174,6 +1191,7 @@ def do_jump(self, arg):
def do_debug(self, arg):
"""debug code
+
Enter a recursive debugger that steps through the code
argument (which is an arbitrary expression or statement to be
executed in the current environment).
@@ -1195,7 +1213,8 @@ def do_debug(self, arg):
complete_debug = _complete_expression
def do_quit(self, arg):
- """q(uit)\nexit
+ """q(uit) | exit
+
Quit from the debugger. The program being executed is aborted.
"""
self._user_requested_quit = True
@@ -1207,6 +1226,7 @@ def do_quit(self, arg):
def do_EOF(self, arg):
"""EOF
+
Handles the receipt of EOF as a command.
"""
self.message('')
@@ -1216,6 +1236,7 @@ def do_EOF(self, arg):
def do_args(self, arg):
"""a(rgs)
+
Print the argument list of the current function.
"""
co = self.curframe.f_code
@@ -1233,6 +1254,7 @@ def do_args(self, arg):
def do_retval(self, arg):
"""retval
+
Print the return value for the last return of a function.
"""
if '__return__' in self.curframe_locals:
@@ -1258,7 +1280,7 @@ def _getval_except(self, arg, frame=None):
return _rstr('** raised %s **' % self._format_exc(exc))
def _error_exc(self):
- exc = sys.exc_info()[1]
+ exc = sys.exception()
self.error(self._format_exc(exc))
def _msg_val_func(self, arg, func):
@@ -1273,12 +1295,14 @@ def _msg_val_func(self, arg, func):
def do_p(self, arg):
"""p expression
+
Print the value of the expression.
"""
self._msg_val_func(arg, repr)
def do_pp(self, arg):
"""pp expression
+
Pretty-print the value of the expression.
"""
self._msg_val_func(arg, pprint.pformat)
@@ -1288,7 +1312,7 @@ def do_pp(self, arg):
complete_pp = _complete_expression
def do_list(self, arg):
- """l(ist) [first [,last] | .]
+ """l(ist) [first[, last] | .]
List source code for the current file. Without arguments,
list 11 lines around the current line or continue the previous
@@ -1345,7 +1369,8 @@ def do_list(self, arg):
do_l = do_list
def do_longlist(self, arg):
- """longlist | ll
+ """ll | longlist
+
List the whole source code for the current function or frame.
"""
filename = self.curframe.f_code.co_filename
@@ -1360,6 +1385,7 @@ def do_longlist(self, arg):
def do_source(self, arg):
"""source expression
+
Try to get source code for the given object and display it.
"""
try:
@@ -1397,7 +1423,8 @@ def _print_lines(self, lines, start, breaks=(), frame=None):
self.message(s + '\t' + line.rstrip())
def do_whatis(self, arg):
- """whatis arg
+ """whatis expression
+
Print the type of the argument.
"""
try:
@@ -1485,7 +1512,8 @@ def do_interact(self, arg):
code.interact("*interactive*", local=ns)
def do_alias(self, arg):
- """alias [name [command [parameter parameter ...] ]]
+ """alias [name [command]]
+
Create an alias called 'name' that executes 'command'. The
command must *not* be enclosed in quotes. Replaceable
parameters can be indicated by %1, %2, and so on, while %* is
@@ -1521,6 +1549,7 @@ def do_alias(self, arg):
def do_unalias(self, arg):
"""unalias name
+
Delete the specified alias.
"""
args = arg.split()
@@ -1563,6 +1592,7 @@ def print_stack_entry(self, frame_lineno, prompt_prefix=line_prefix):
def do_help(self, arg):
"""h(elp)
+
Without argument, print the list of available commands.
With a command name as argument, print help about that command.
"help pdb" shows the full pdb documentation.
@@ -1586,12 +1616,13 @@ def do_help(self, arg):
if command.__doc__ is None:
self.error('No help for %r; __doc__ string missing' % arg)
return
- self.message(command.__doc__.rstrip())
+ self.message(self._help_message_from_doc(command.__doc__))
do_h = do_help
def help_exec(self):
"""(!) statement
+
Execute the (one-line) statement in the context of the current
stack frame. The exclamation point can be omitted unless the
first word of the statement resembles a debugger command. To
@@ -1672,6 +1703,26 @@ def _getsourcelines(self, obj):
lineno = max(1, lineno)
return lines, lineno
+ def _help_message_from_doc(self, doc):
+ lines = [line.strip() for line in doc.rstrip().splitlines()]
+ if not lines:
+ return "No help message found."
+ if "" in lines:
+ usage_end = lines.index("")
+ else:
+ usage_end = 1
+ formatted = []
+ indent = " " * len(self.prompt)
+ for i, line in enumerate(lines):
+ if i == 0:
+ prefix = "Usage: "
+ elif i < usage_end:
+ prefix = " "
+ else:
+ prefix = ""
+ formatted.append(indent + prefix + line)
+ return "\n".join(formatted)
+
# Collect all command help into docstring, if not run with -OO
if __doc__ is not None:
@@ -1755,9 +1806,10 @@ def post_mortem(t=None):
"""
# handling the default
if t is None:
- # sys.exc_info() returns (type, value, traceback) if an exception is
- # being handled, otherwise it returns None
- t = sys.exc_info()[2]
+ exc = sys.exception()
+ if exc is not None:
+ t = exc.__traceback__
+
if t is None:
raise ValueError("A valid traceback must be passed if no "
"exception is being handled")
@@ -1841,18 +1893,18 @@ def main():
except Restart:
print("Restarting", target, "with arguments:")
print("\t" + " ".join(sys.argv[1:]))
- except SystemExit:
+ except SystemExit as e:
# In most cases SystemExit does not warrant a post-mortem session.
print("The program exited via sys.exit(). Exit status:", end=' ')
- print(sys.exc_info()[1])
+ print(e)
except SyntaxError:
traceback.print_exc()
sys.exit(1)
- except:
+ except BaseException as e:
traceback.print_exc()
print("Uncaught exception. Entering post mortem debugging")
print("Running 'cont' or 'step' will restart the program")
- t = sys.exc_info()[2]
+ t = e.__traceback__
pdb.interaction(None, t)
print("Post mortem debugger finished. The " + target +
" will be restarted")
diff --git a/Lib/pkgutil.py b/Lib/pkgutil.py
index bdebfd2fc8ac32..56731de64af494 100644
--- a/Lib/pkgutil.py
+++ b/Lib/pkgutil.py
@@ -511,10 +511,10 @@ def extend_path(path, name):
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__)
- This will add to the package's __path__ all subdirectories of
- directories on sys.path named after the package. This is useful
- if one wants to distribute different parts of a single logical
- package as multiple directories.
+ For each directory on sys.path that has a subdirectory that
+ matches the package name, add the subdirectory to the package's
+ __path__. This is useful if one wants to distribute different
+ parts of a single logical package as multiple directories.
It also looks for *.pkg files beginning where * matches the name
argument. This feature is similar to *.pth files (see site.py),
diff --git a/Lib/shutil.py b/Lib/shutil.py
index 8b378645a5a375..7d1a3d00011f37 100644
--- a/Lib/shutil.py
+++ b/Lib/shutil.py
@@ -332,7 +332,7 @@ def _copyxattr(src, dst, *, follow_symlinks=True):
os.setxattr(dst, name, value, follow_symlinks=follow_symlinks)
except OSError as e:
if e.errno not in (errno.EPERM, errno.ENOTSUP, errno.ENODATA,
- errno.EINVAL):
+ errno.EINVAL, errno.EACCES):
raise
else:
def _copyxattr(*args, **kwargs):
@@ -699,7 +699,7 @@ def rmtree(path, ignore_errors=False, onerror=None, *, onexc=None, dir_fd=None):
if onerror is not None:
warnings.warn("onerror argument is deprecated, use onexc instead",
- DeprecationWarning)
+ DeprecationWarning, stacklevel=2)
sys.audit("shutil.rmtree", path, dir_fd)
if ignore_errors:
@@ -1245,7 +1245,7 @@ def _unpack_zipfile(filename, extract_dir):
finally:
zip.close()
-def _unpack_tarfile(filename, extract_dir):
+def _unpack_tarfile(filename, extract_dir, *, filter=None):
"""Unpack tar/tar.gz/tar.bz2/tar.xz `filename` to `extract_dir`
"""
import tarfile # late import for breaking circular dependency
@@ -1255,7 +1255,7 @@ def _unpack_tarfile(filename, extract_dir):
raise ReadError(
"%s is not a compressed or uncompressed tar file" % filename)
try:
- tarobj.extractall(extract_dir)
+ tarobj.extractall(extract_dir, filter=filter)
finally:
tarobj.close()
@@ -1288,7 +1288,7 @@ def _find_unpack_format(filename):
return name
return None
-def unpack_archive(filename, extract_dir=None, format=None):
+def unpack_archive(filename, extract_dir=None, format=None, *, filter=None):
"""Unpack an archive.
`filename` is the name of the archive.
@@ -1302,6 +1302,9 @@ def unpack_archive(filename, extract_dir=None, format=None):
was registered for that extension.
In case none is found, a ValueError is raised.
+
+ If `filter` is given, it is passed to the underlying
+ extraction function.
"""
sys.audit("shutil.unpack_archive", filename, extract_dir, format)
@@ -1311,6 +1314,10 @@ def unpack_archive(filename, extract_dir=None, format=None):
extract_dir = os.fspath(extract_dir)
filename = os.fspath(filename)
+ if filter is None:
+ filter_kwargs = {}
+ else:
+ filter_kwargs = {'filter': filter}
if format is not None:
try:
format_info = _UNPACK_FORMATS[format]
@@ -1318,7 +1325,7 @@ def unpack_archive(filename, extract_dir=None, format=None):
raise ValueError("Unknown unpack format '{0}'".format(format)) from None
func = format_info[1]
- func(filename, extract_dir, **dict(format_info[2]))
+ func(filename, extract_dir, **dict(format_info[2]), **filter_kwargs)
else:
# we need to look at the registered unpackers supported extensions
format = _find_unpack_format(filename)
@@ -1326,7 +1333,7 @@ def unpack_archive(filename, extract_dir=None, format=None):
raise ReadError("Unknown archive format '{0}'".format(filename))
func = _UNPACK_FORMATS[format][1]
- kwargs = dict(_UNPACK_FORMATS[format][2])
+ kwargs = dict(_UNPACK_FORMATS[format][2]) | filter_kwargs
func(filename, extract_dir, **kwargs)
diff --git a/Lib/socketserver.py b/Lib/socketserver.py
index 842d526b011911..cd028ef1c63b85 100644
--- a/Lib/socketserver.py
+++ b/Lib/socketserver.py
@@ -141,6 +141,8 @@ class will essentially render the service "deaf" while one request is
__all__.extend(["UnixStreamServer","UnixDatagramServer",
"ThreadingUnixStreamServer",
"ThreadingUnixDatagramServer"])
+ if hasattr(os, "fork"):
+ __all__.extend(["ForkingUnixStreamServer", "ForkingUnixDatagramServer"])
# poll/select have the advantage of not requiring any extra file descriptor,
# contrarily to epoll/kqueue (also, they require a single syscall).
@@ -727,6 +729,11 @@ class ThreadingUnixStreamServer(ThreadingMixIn, UnixStreamServer): pass
class ThreadingUnixDatagramServer(ThreadingMixIn, UnixDatagramServer): pass
+ if hasattr(os, "fork"):
+ class ForkingUnixStreamServer(ForkingMixIn, UnixStreamServer): pass
+
+ class ForkingUnixDatagramServer(ForkingMixIn, UnixDatagramServer): pass
+
class BaseRequestHandler:
"""Base class for request handler classes.
diff --git a/Lib/tarfile.py b/Lib/tarfile.py
index b733195c9c5636..7781a430839ea5 100755
--- a/Lib/tarfile.py
+++ b/Lib/tarfile.py
@@ -46,6 +46,7 @@
import struct
import copy
import re
+import warnings
try:
import pwd
@@ -65,7 +66,11 @@
__all__ = ["TarFile", "TarInfo", "is_tarfile", "TarError", "ReadError",
"CompressionError", "StreamError", "ExtractError", "HeaderError",
"ENCODING", "USTAR_FORMAT", "GNU_FORMAT", "PAX_FORMAT",
- "DEFAULT_FORMAT", "open"]
+ "DEFAULT_FORMAT", "open","fully_trusted_filter", "data_filter",
+ "tar_filter", "FilterError", "AbsoluteLinkError",
+ "OutsideDestinationError", "SpecialFileError", "AbsolutePathError",
+ "LinkOutsideDestinationError"]
+
#---------------------------------------------------------
# tar constants
@@ -154,6 +159,8 @@
def stn(s, length, encoding, errors):
"""Convert a string to a null-terminated bytes object.
"""
+ if s is None:
+ raise ValueError("metadata cannot contain None")
s = s.encode(encoding, errors)
return s[:length] + (length - len(s)) * NUL
@@ -707,9 +714,127 @@ def __init__(self, tarfile, tarinfo):
super().__init__(fileobj)
#class ExFileObject
+
+#-----------------------------
+# extraction filters (PEP 706)
+#-----------------------------
+
+class FilterError(TarError):
+ pass
+
+class AbsolutePathError(FilterError):
+ def __init__(self, tarinfo):
+ self.tarinfo = tarinfo
+ super().__init__(f'member {tarinfo.name!r} has an absolute path')
+
+class OutsideDestinationError(FilterError):
+ def __init__(self, tarinfo, path):
+ self.tarinfo = tarinfo
+ self._path = path
+ super().__init__(f'{tarinfo.name!r} would be extracted to {path!r}, '
+ + 'which is outside the destination')
+
+class SpecialFileError(FilterError):
+ def __init__(self, tarinfo):
+ self.tarinfo = tarinfo
+ super().__init__(f'{tarinfo.name!r} is a special file')
+
+class AbsoluteLinkError(FilterError):
+ def __init__(self, tarinfo):
+ self.tarinfo = tarinfo
+ super().__init__(f'{tarinfo.name!r} is a symlink to an absolute path')
+
+class LinkOutsideDestinationError(FilterError):
+ def __init__(self, tarinfo, path):
+ self.tarinfo = tarinfo
+ self._path = path
+ super().__init__(f'{tarinfo.name!r} would link to {path!r}, '
+ + 'which is outside the destination')
+
+def _get_filtered_attrs(member, dest_path, for_data=True):
+ new_attrs = {}
+ name = member.name
+ dest_path = os.path.realpath(dest_path)
+ # Strip leading / (tar's directory separator) from filenames.
+ # Include os.sep (target OS directory separator) as well.
+ if name.startswith(('/', os.sep)):
+ name = new_attrs['name'] = member.path.lstrip('/' + os.sep)
+ if os.path.isabs(name):
+ # Path is absolute even after stripping.
+ # For example, 'C:/foo' on Windows.
+ raise AbsolutePathError(member)
+ # Ensure we stay in the destination
+ target_path = os.path.realpath(os.path.join(dest_path, name))
+ if os.path.commonpath([target_path, dest_path]) != dest_path:
+ raise OutsideDestinationError(member, target_path)
+ # Limit permissions (no high bits, and go-w)
+ mode = member.mode
+ if mode is not None:
+ # Strip high bits & group/other write bits
+ mode = mode & 0o755
+ if for_data:
+ # For data, handle permissions & file types
+ if member.isreg() or member.islnk():
+ if not mode & 0o100:
+ # Clear executable bits if not executable by user
+ mode &= ~0o111
+ # Ensure owner can read & write
+ mode |= 0o600
+ elif member.isdir() or member.issym():
+ # Ignore mode for directories & symlinks
+ mode = None
+ else:
+ # Reject special files
+ raise SpecialFileError(member)
+ if mode != member.mode:
+ new_attrs['mode'] = mode
+ if for_data:
+ # Ignore ownership for 'data'
+ if member.uid is not None:
+ new_attrs['uid'] = None
+ if member.gid is not None:
+ new_attrs['gid'] = None
+ if member.uname is not None:
+ new_attrs['uname'] = None
+ if member.gname is not None:
+ new_attrs['gname'] = None
+ # Check link destination for 'data'
+ if member.islnk() or member.issym():
+ if os.path.isabs(member.linkname):
+ raise AbsoluteLinkError(member)
+ target_path = os.path.realpath(os.path.join(dest_path, member.linkname))
+ if os.path.commonpath([target_path, dest_path]) != dest_path:
+ raise LinkOutsideDestinationError(member, target_path)
+ return new_attrs
+
+def fully_trusted_filter(member, dest_path):
+ return member
+
+def tar_filter(member, dest_path):
+ new_attrs = _get_filtered_attrs(member, dest_path, False)
+ if new_attrs:
+ return member.replace(**new_attrs, deep=False)
+ return member
+
+def data_filter(member, dest_path):
+ new_attrs = _get_filtered_attrs(member, dest_path, True)
+ if new_attrs:
+ return member.replace(**new_attrs, deep=False)
+ return member
+
+_NAMED_FILTERS = {
+ "fully_trusted": fully_trusted_filter,
+ "tar": tar_filter,
+ "data": data_filter,
+}
+
#------------------
# Exported Classes
#------------------
+
+# Sentinel for replace() defaults, meaning "don't change the attribute"
+_KEEP = object()
+
class TarInfo(object):
"""Informational class which holds the details about an
archive member given by a tar header block.
@@ -790,12 +915,44 @@ def linkpath(self, linkname):
def __repr__(self):
return "<%s %r at %#x>" % (self.__class__.__name__,self.name,id(self))
+ def replace(self, *,
+ name=_KEEP, mtime=_KEEP, mode=_KEEP, linkname=_KEEP,
+ uid=_KEEP, gid=_KEEP, uname=_KEEP, gname=_KEEP,
+ deep=True, _KEEP=_KEEP):
+ """Return a deep copy of self with the given attributes replaced.
+ """
+ if deep:
+ result = copy.deepcopy(self)
+ else:
+ result = copy.copy(self)
+ if name is not _KEEP:
+ result.name = name
+ if mtime is not _KEEP:
+ result.mtime = mtime
+ if mode is not _KEEP:
+ result.mode = mode
+ if linkname is not _KEEP:
+ result.linkname = linkname
+ if uid is not _KEEP:
+ result.uid = uid
+ if gid is not _KEEP:
+ result.gid = gid
+ if uname is not _KEEP:
+ result.uname = uname
+ if gname is not _KEEP:
+ result.gname = gname
+ return result
+
def get_info(self):
"""Return the TarInfo's attributes as a dictionary.
"""
+ if self.mode is None:
+ mode = None
+ else:
+ mode = self.mode & 0o7777
info = {
"name": self.name,
- "mode": self.mode & 0o7777,
+ "mode": mode,
"uid": self.uid,
"gid": self.gid,
"size": self.size,
@@ -818,6 +975,9 @@ def tobuf(self, format=DEFAULT_FORMAT, encoding=ENCODING, errors="surrogateescap
"""Return a tar header as a string of 512 byte blocks.
"""
info = self.get_info()
+ for name, value in info.items():
+ if value is None:
+ raise ValueError("%s may not be None" % name)
if format == USTAR_FORMAT:
return self.create_ustar_header(info, encoding, errors)
@@ -948,6 +1108,12 @@ def _create_header(info, format, encoding, errors):
devmajor = stn("", 8, encoding, errors)
devminor = stn("", 8, encoding, errors)
+ # None values in metadata should cause ValueError.
+ # itn()/stn() do this for all fields except type.
+ filetype = info.get("type", REGTYPE)
+ if filetype is None:
+ raise ValueError("TarInfo.type must not be None")
+
parts = [
stn(info.get("name", ""), 100, encoding, errors),
itn(info.get("mode", 0) & 0o7777, 8, format),
@@ -956,7 +1122,7 @@ def _create_header(info, format, encoding, errors):
itn(info.get("size", 0), 12, format),
itn(info.get("mtime", 0), 12, format),
b" ", # checksum field
- info.get("type", REGTYPE),
+ filetype,
stn(info.get("linkname", ""), 100, encoding, errors),
info.get("magic", POSIX_MAGIC),
stn(info.get("uname", ""), 32, encoding, errors),
@@ -1462,6 +1628,8 @@ class TarFile(object):
fileobject = ExFileObject # The file-object for extractfile().
+ extraction_filter = None # The default filter for extraction.
+
def __init__(self, name=None, mode="r", fileobj=None, format=None,
tarinfo=None, dereference=None, ignore_zeros=None, encoding=None,
errors="surrogateescape", pax_headers=None, debug=None,
@@ -1936,7 +2104,10 @@ def list(self, verbose=True, *, members=None):
members = self
for tarinfo in members:
if verbose:
- _safe_print(stat.filemode(tarinfo.mode))
+ if tarinfo.mode is None:
+ _safe_print("??????????")
+ else:
+ _safe_print(stat.filemode(tarinfo.mode))
_safe_print("%s/%s" % (tarinfo.uname or tarinfo.uid,
tarinfo.gname or tarinfo.gid))
if tarinfo.ischr() or tarinfo.isblk():
@@ -1944,8 +2115,11 @@ def list(self, verbose=True, *, members=None):
("%d,%d" % (tarinfo.devmajor, tarinfo.devminor)))
else:
_safe_print("%10d" % tarinfo.size)
- _safe_print("%d-%02d-%02d %02d:%02d:%02d" \
- % time.localtime(tarinfo.mtime)[:6])
+ if tarinfo.mtime is None:
+ _safe_print("????-??-?? ??:??:??")
+ else:
+ _safe_print("%d-%02d-%02d %02d:%02d:%02d" \
+ % time.localtime(tarinfo.mtime)[:6])
_safe_print(tarinfo.name + ("/" if tarinfo.isdir() else ""))
@@ -2032,32 +2206,63 @@ def addfile(self, tarinfo, fileobj=None):
self.members.append(tarinfo)
- def extractall(self, path=".", members=None, *, numeric_owner=False):
+ def _get_filter_function(self, filter):
+ if filter is None:
+ filter = self.extraction_filter
+ if filter is None:
+ warnings.warn(
+ 'Python 3.14 will, by default, filter extracted tar '
+ + 'archives and reject files or modify their metadata. '
+ + 'Use the filter argument to control this behavior.',
+ DeprecationWarning)
+ return fully_trusted_filter
+ if isinstance(filter, str):
+ raise TypeError(
+ 'String names are not supported for '
+ + 'TarFile.extraction_filter. Use a function such as '
+ + 'tarfile.data_filter directly.')
+ return filter
+ if callable(filter):
+ return filter
+ try:
+ return _NAMED_FILTERS[filter]
+ except KeyError:
+ raise ValueError(f"filter {filter!r} not found") from None
+
+ def extractall(self, path=".", members=None, *, numeric_owner=False,
+ filter=None):
"""Extract all members from the archive to the current working
directory and set owner, modification time and permissions on
directories afterwards. `path' specifies a different directory
to extract to. `members' is optional and must be a subset of the
list returned by getmembers(). If `numeric_owner` is True, only
the numbers for user/group names are used and not the names.
+
+ The `filter` function will be called on each member just
+ before extraction.
+ It can return a changed TarInfo or None to skip the member.
+ String names of common filters are accepted.
"""
directories = []
+ filter_function = self._get_filter_function(filter)
if members is None:
members = self
- for tarinfo in members:
+ for member in members:
+ tarinfo = self._get_extract_tarinfo(member, filter_function, path)
+ if tarinfo is None:
+ continue
if tarinfo.isdir():
- # Extract directories with a safe mode.
+ # For directories, delay setting attributes until later,
+ # since permissions can interfere with extraction and
+ # extracting contents can reset mtime.
directories.append(tarinfo)
- tarinfo = copy.copy(tarinfo)
- tarinfo.mode = 0o700
- # Do not set_attrs directories, as we will do that further down
- self.extract(tarinfo, path, set_attrs=not tarinfo.isdir(),
- numeric_owner=numeric_owner)
+ self._extract_one(tarinfo, path, set_attrs=not tarinfo.isdir(),
+ numeric_owner=numeric_owner)
# Reverse sort directories.
- directories.sort(key=lambda a: a.name)
- directories.reverse()
+ directories.sort(key=lambda a: a.name, reverse=True)
# Set correct owner, mtime and filemode on directories.
for tarinfo in directories:
@@ -2067,12 +2272,10 @@ def extractall(self, path=".", members=None, *, numeric_owner=False):
self.utime(tarinfo, dirpath)
self.chmod(tarinfo, dirpath)
except ExtractError as e:
- if self.errorlevel > 1:
- raise
- else:
- self._dbg(1, "tarfile: %s" % e)
+ self._handle_nonfatal_error(e)
- def extract(self, member, path="", set_attrs=True, *, numeric_owner=False):
+ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False,
+ filter=None):
"""Extract a member from the archive to the current working directory,
using its full name. Its file information is extracted as accurately
as possible. `member' may be a filename or a TarInfo object. You can
@@ -2080,35 +2283,70 @@ def extract(self, member, path="", set_attrs=True, *, numeric_owner=False):
mtime, mode) are set unless `set_attrs' is False. If `numeric_owner`
is True, only the numbers for user/group names are used and not
the names.
+
+ The `filter` function will be called before extraction.
+ It can return a changed TarInfo or None to skip the member.
+ String names of common filters are accepted.
"""
- self._check("r")
+ filter_function = self._get_filter_function(filter)
+ tarinfo = self._get_extract_tarinfo(member, filter_function, path)
+ if tarinfo is not None:
+ self._extract_one(tarinfo, path, set_attrs, numeric_owner)
+ def _get_extract_tarinfo(self, member, filter_function, path):
+ """Get filtered TarInfo (or None) from member, which might be a str"""
if isinstance(member, str):
tarinfo = self.getmember(member)
else:
tarinfo = member
+ unfiltered = tarinfo
+ try:
+ tarinfo = filter_function(tarinfo, path)
+ except (OSError, FilterError) as e:
+ self._handle_fatal_error(e)
+ except ExtractError as e:
+ self._handle_nonfatal_error(e)
+ if tarinfo is None:
+ self._dbg(2, "tarfile: Excluded %r" % unfiltered.name)
+ return None
# Prepare the link target for makelink().
if tarinfo.islnk():
+ tarinfo = copy.copy(tarinfo)
tarinfo._link_target = os.path.join(path, tarinfo.linkname)
+ return tarinfo
+
+ def _extract_one(self, tarinfo, path, set_attrs, numeric_owner):
+ """Extract from filtered tarinfo to disk"""
+ self._check("r")
try:
self._extract_member(tarinfo, os.path.join(path, tarinfo.name),
set_attrs=set_attrs,
numeric_owner=numeric_owner)
except OSError as e:
- if self.errorlevel > 0:
- raise
- else:
- if e.filename is None:
- self._dbg(1, "tarfile: %s" % e.strerror)
- else:
- self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
+ self._handle_fatal_error(e)
except ExtractError as e:
- if self.errorlevel > 1:
- raise
+ self._handle_nonfatal_error(e)
+
+ def _handle_nonfatal_error(self, e):
+ """Handle non-fatal error (ExtractError) according to errorlevel"""
+ if self.errorlevel > 1:
+ raise
+ else:
+ self._dbg(1, "tarfile: %s" % e)
+
+ def _handle_fatal_error(self, e):
+ """Handle "fatal" error according to self.errorlevel"""
+ if self.errorlevel > 0:
+ raise
+ elif isinstance(e, OSError):
+ if e.filename is None:
+ self._dbg(1, "tarfile: %s" % e.strerror)
else:
- self._dbg(1, "tarfile: %s" % e)
+ self._dbg(1, "tarfile: %s %r" % (e.strerror, e.filename))
+ else:
+ self._dbg(1, "tarfile: %s %s" % (type(e).__name__, e))
def extractfile(self, member):
"""Extract a member from the archive as a file object. `member' may be
@@ -2195,9 +2433,13 @@ def makedir(self, tarinfo, targetpath):
"""Make a directory called targetpath.
"""
try:
- # Use a safe mode for the directory, the real mode is set
- # later in _extract_member().
- os.mkdir(targetpath, 0o700)
+ if tarinfo.mode is None:
+ # Use the system's default mode
+ os.mkdir(targetpath)
+ else:
+ # Use a safe mode for the directory, the real mode is set
+ # later in _extract_member().
+ os.mkdir(targetpath, 0o700)
except FileExistsError:
pass
@@ -2240,6 +2482,9 @@ def makedev(self, tarinfo, targetpath):
raise ExtractError("special devices not supported by system")
mode = tarinfo.mode
+ if mode is None:
+ # Use mknod's default
+ mode = 0o600
if tarinfo.isblk():
mode |= stat.S_IFBLK
else:
@@ -2261,7 +2506,6 @@ def makelink(self, tarinfo, targetpath):
os.unlink(targetpath)
os.symlink(tarinfo.linkname, targetpath)
else:
- # See extract().
if os.path.exists(tarinfo._link_target):
os.link(tarinfo._link_target, targetpath)
else:
@@ -2286,15 +2530,19 @@ def chown(self, tarinfo, targetpath, numeric_owner):
u = tarinfo.uid
if not numeric_owner:
try:
- if grp:
+ if grp and tarinfo.gname:
g = grp.getgrnam(tarinfo.gname)[2]
except KeyError:
pass
try:
- if pwd:
+ if pwd and tarinfo.uname:
u = pwd.getpwnam(tarinfo.uname)[2]
except KeyError:
pass
+ if g is None:
+ g = -1
+ if u is None:
+ u = -1
try:
if tarinfo.issym() and hasattr(os, "lchown"):
os.lchown(targetpath, u, g)
@@ -2306,6 +2554,8 @@ def chown(self, tarinfo, targetpath, numeric_owner):
def chmod(self, tarinfo, targetpath):
"""Set file permissions of targetpath according to tarinfo.
"""
+ if tarinfo.mode is None:
+ return
try:
os.chmod(targetpath, tarinfo.mode)
except OSError as e:
@@ -2314,10 +2564,13 @@ def chmod(self, tarinfo, targetpath):
def utime(self, tarinfo, targetpath):
"""Set modification time of targetpath according to tarinfo.
"""
+ mtime = tarinfo.mtime
+ if mtime is None:
+ return
if not hasattr(os, 'utime'):
return
try:
- os.utime(targetpath, (tarinfo.mtime, tarinfo.mtime))
+ os.utime(targetpath, (mtime, mtime))
except OSError as e:
raise ExtractError("could not change modification time") from e
@@ -2395,13 +2648,26 @@ def _getmember(self, name, tarinfo=None, normalize=False):
members = self.getmembers()
# Limit the member search list up to tarinfo.
+ skipping = False
if tarinfo is not None:
- members = members[:members.index(tarinfo)]
+ try:
+ index = members.index(tarinfo)
+ except ValueError:
+ # The given starting point might be a (modified) copy.
+ # We'll later skip members until we find an equivalent.
+ skipping = True
+ else:
+ # Happy fast path
+ members = members[:index]
if normalize:
name = os.path.normpath(name)
for member in reversed(members):
+ if skipping:
+ if tarinfo.offset == member.offset:
+ skipping = False
+ continue
if normalize:
member_name = os.path.normpath(member.name)
else:
@@ -2410,6 +2676,10 @@ def _getmember(self, name, tarinfo=None, normalize=False):
if name == member_name:
return member
+ if skipping:
+ # Starting point was not found
+ raise ValueError(tarinfo)
+
def _load(self):
"""Read through the entire archive file and look for readable
members.
@@ -2500,6 +2770,7 @@ def __exit__(self, type, value, traceback):
#--------------------
# exported functions
#--------------------
+
def is_tarfile(name):
"""Return True if name points to a tar archive that we
are able to handle, else return False.
@@ -2528,6 +2799,10 @@ def main():
parser = argparse.ArgumentParser(description=description)
parser.add_argument('-v', '--verbose', action='store_true', default=False,
help='Verbose output')
+ parser.add_argument('--filter', metavar='',
+ choices=_NAMED_FILTERS,
+ help='Filter for extraction')
+
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument('-l', '--list', metavar='',
help='Show listing of a tarfile')
@@ -2539,8 +2814,12 @@ def main():
help='Create tarfile from sources')
group.add_argument('-t', '--test', metavar='',
help='Test if a tarfile is valid')
+
args = parser.parse_args()
+ if args.filter and args.extract is None:
+ parser.exit(1, '--filter is only valid for extraction\n')
+
if args.test is not None:
src = args.test
if is_tarfile(src):
@@ -2571,7 +2850,7 @@ def main():
if is_tarfile(src):
with TarFile.open(src, 'r:*') as tf:
- tf.extractall(path=curdir)
+ tf.extractall(path=curdir, filter=args.filter)
if args.verbose:
if curdir == '.':
msg = '{!r} file is extracted.'.format(src)
diff --git a/Lib/tempfile.py b/Lib/tempfile.py
index 4732eb0efe1f76..2b4f4313247128 100644
--- a/Lib/tempfile.py
+++ b/Lib/tempfile.py
@@ -376,7 +376,7 @@ def mkdtemp(suffix=None, prefix=None, dir=None):
continue
else:
raise
- return file
+ return _os.path.abspath(file)
raise FileExistsError(_errno.EEXIST,
"No usable temporary directory name found")
diff --git a/Lib/test/_test_embed_structseq.py b/Lib/test/_test_embed_structseq.py
index 868f9f83e8be77..834daa4df55fec 100644
--- a/Lib/test/_test_embed_structseq.py
+++ b/Lib/test/_test_embed_structseq.py
@@ -1,27 +1,31 @@
import sys
import types
-import unittest
+# Note: This test file can't import `unittest` since the runtime can't
+# currently guarantee that it will not leak memory. Doing so will mark
+# the test as passing but with reference leaks. This can safely import
+# the `unittest` library once there's a strict guarantee of no leaks
+# during runtime shutdown.
# bpo-46417: Test that structseq types used by the sys module are still
# valid when Py_Finalize()/Py_Initialize() are called multiple times.
-class TestStructSeq(unittest.TestCase):
+class TestStructSeq:
# test PyTypeObject members
- def check_structseq(self, obj_type):
+ def _check_structseq(self, obj_type):
# ob_refcnt
- self.assertGreaterEqual(sys.getrefcount(obj_type), 1)
+ assert sys.getrefcount(obj_type) > 1
# tp_base
- self.assertTrue(issubclass(obj_type, tuple))
+ assert issubclass(obj_type, tuple)
# tp_bases
- self.assertEqual(obj_type.__bases__, (tuple,))
+ assert obj_type.__bases__ == (tuple,)
# tp_dict
- self.assertIsInstance(obj_type.__dict__, types.MappingProxyType)
+ assert isinstance(obj_type.__dict__, types.MappingProxyType)
# tp_mro
- self.assertEqual(obj_type.__mro__, (obj_type, tuple, object))
+ assert obj_type.__mro__ == (obj_type, tuple, object)
# tp_name
- self.assertIsInstance(type.__name__, str)
+ assert isinstance(type.__name__, str)
# tp_subclasses
- self.assertEqual(obj_type.__subclasses__(), [])
+ assert obj_type.__subclasses__() == []
def test_sys_attrs(self):
for attr_name in (
@@ -32,23 +36,23 @@ def test_sys_attrs(self):
'thread_info', # ThreadInfoType
'version_info', # VersionInfoType
):
- with self.subTest(attr=attr_name):
- attr = getattr(sys, attr_name)
- self.check_structseq(type(attr))
+ attr = getattr(sys, attr_name)
+ self._check_structseq(type(attr))
def test_sys_funcs(self):
func_names = ['get_asyncgen_hooks'] # AsyncGenHooksType
if hasattr(sys, 'getwindowsversion'):
func_names.append('getwindowsversion') # WindowsVersionType
for func_name in func_names:
- with self.subTest(func=func_name):
- func = getattr(sys, func_name)
- obj = func()
- self.check_structseq(type(obj))
+ func = getattr(sys, func_name)
+ obj = func()
+ self._check_structseq(type(obj))
try:
- unittest.main()
+ tests = TestStructSeq()
+ tests.test_sys_attrs()
+ tests.test_sys_funcs()
except SystemExit as exc:
if exc.args[0] != 0:
raise
diff --git a/Lib/test/datetimetester.py b/Lib/test/datetimetester.py
index 570f803918c1ef..477f16f1841f62 100644
--- a/Lib/test/datetimetester.py
+++ b/Lib/test/datetimetester.py
@@ -6212,6 +6212,10 @@ def test_system_transitions(self):
ts1 = dt.replace(fold=1).timestamp()
self.assertEqual(ts0, s0 + ss / 2)
self.assertEqual(ts1, s0 - ss / 2)
+ # gh-83861
+ utc0 = dt.astimezone(timezone.utc)
+ utc1 = dt.replace(fold=1).astimezone(timezone.utc)
+ self.assertEqual(utc0, utc1 + timedelta(0, ss))
finally:
if TZ is None:
del os.environ['TZ']
diff --git a/Lib/test/libregrtest/refleak.py b/Lib/test/libregrtest/refleak.py
index 4298fa806e1065..2de8c6cfbc61a1 100644
--- a/Lib/test/libregrtest/refleak.py
+++ b/Lib/test/libregrtest/refleak.py
@@ -73,9 +73,10 @@ def get_pooled_int(value):
fd_deltas = [0] * repcount
getallocatedblocks = sys.getallocatedblocks
gettotalrefcount = sys.gettotalrefcount
+ getunicodeinternedsize = sys.getunicodeinternedsize
fd_count = os_helper.fd_count
# initialize variables to make pyflakes quiet
- rc_before = alloc_before = fd_before = 0
+ rc_before = alloc_before = fd_before = interned_before = 0
if not ns.quiet:
print("beginning", repcount, "repetitions", file=sys.stderr)
@@ -91,9 +92,13 @@ def get_pooled_int(value):
dash_R_cleanup(fs, ps, pic, zdc, abcs)
support.gc_collect()
- # Read memory statistics immediately after the garbage collection
- alloc_after = getallocatedblocks()
- rc_after = gettotalrefcount()
+ # Read memory statistics immediately after the garbage collection.
+ # Also, readjust the reference counts and alloc blocks by ignoring
+ # any strings that might have been interned during test_func. These
+ # strings will be deallocated at runtime shutdown
+ interned_after = getunicodeinternedsize()
+ alloc_after = getallocatedblocks() - interned_after
+ rc_after = gettotalrefcount() - interned_after * 2
fd_after = fd_count()
if not ns.quiet:
@@ -106,6 +111,7 @@ def get_pooled_int(value):
alloc_before = alloc_after
rc_before = rc_after
fd_before = fd_after
+ interned_before = interned_after
if not ns.quiet:
print(file=sys.stderr)
diff --git a/Lib/test/setup_testcppext.py b/Lib/test/setup_testcppext.py
index c6b68104d1333c..22fe750085fd70 100644
--- a/Lib/test/setup_testcppext.py
+++ b/Lib/test/setup_testcppext.py
@@ -1,5 +1,6 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
+import os
import sys
from test import support
@@ -25,14 +26,8 @@
def main():
cppflags = list(CPPFLAGS)
- if '-std=c++03' in sys.argv:
- sys.argv.remove('-std=c++03')
- std = 'c++03'
- name = '_testcpp03ext'
- else:
- # Python currently targets C++11
- std = 'c++11'
- name = '_testcpp11ext'
+ std = os.environ["CPYTHON_TEST_CPP_STD"]
+ name = os.environ["CPYTHON_TEST_EXT_NAME"]
cppflags = [*CPPFLAGS, f'-std={std}']
diff --git a/Lib/test/setuptools-67.6.1-py3-none-any.whl b/Lib/test/setuptools-67.6.1-py3-none-any.whl
new file mode 100644
index 00000000000000..4b7ffd2e49e155
Binary files /dev/null and b/Lib/test/setuptools-67.6.1-py3-none-any.whl differ
diff --git a/Lib/test/shadowed_super.py b/Lib/test/shadowed_super.py
new file mode 100644
index 00000000000000..2a62f667e93818
--- /dev/null
+++ b/Lib/test/shadowed_super.py
@@ -0,0 +1,7 @@
+class super:
+ msg = "truly super"
+
+
+class C:
+ def method(self):
+ return super().msg
diff --git a/Lib/test/support/testcase.py b/Lib/test/support/testcase.py
new file mode 100644
index 00000000000000..1e4363b15783eb
--- /dev/null
+++ b/Lib/test/support/testcase.py
@@ -0,0 +1,25 @@
+class ExceptionIsLikeMixin:
+ def assertExceptionIsLike(self, exc, template):
+ """
+ Passes when the provided `exc` matches the structure of `template`.
+ Individual exceptions don't have to be the same objects or even pass
+ an equality test: they only need to be the same type and contain equal
+ `exc_obj.args`.
+ """
+ if exc is None and template is None:
+ return
+
+ if template is None:
+ self.fail(f"unexpected exception: {exc}")
+
+ if exc is None:
+ self.fail(f"expected an exception like {template!r}, got None")
+
+ if not isinstance(exc, ExceptionGroup):
+ self.assertEqual(exc.__class__, template.__class__)
+ self.assertEqual(exc.args[0], template.args[0])
+ else:
+ self.assertEqual(exc.message, template.message)
+ self.assertEqual(len(exc.exceptions), len(template.exceptions))
+ for e, t in zip(exc.exceptions, template.exceptions):
+ self.assertExceptionIsLike(e, t)
diff --git a/Lib/test/test__opcode.py b/Lib/test/test__opcode.py
index 31f3c53992db13..7640c6fb57d4f3 100644
--- a/Lib/test/test__opcode.py
+++ b/Lib/test/test__opcode.py
@@ -20,6 +20,8 @@ def test_stack_effect(self):
# All defined opcodes
has_arg = dis.hasarg
for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()):
+ if code >= opcode.MIN_INSTRUMENTED_OPCODE:
+ continue
with self.subTest(opname=name):
if code not in has_arg:
stack_effect(code)
@@ -47,6 +49,8 @@ def test_stack_effect_jump(self):
has_exc = dis.hasexc
has_jump = dis.hasjabs + dis.hasjrel
for name, code in filter(lambda item: item[0] not in dis.deoptmap, dis.opmap.items()):
+ if code >= opcode.MIN_INSTRUMENTED_OPCODE:
+ continue
with self.subTest(opname=name):
if code not in has_arg:
common = stack_effect(code)
diff --git a/Lib/test/test__xxinterpchannels.py b/Lib/test/test__xxinterpchannels.py
index b65281106f667c..750cd99b85e7a6 100644
--- a/Lib/test/test__xxinterpchannels.py
+++ b/Lib/test/test__xxinterpchannels.py
@@ -1469,19 +1469,19 @@ def _assert_closed_in_interp(self, fix, interp=None):
with self.assertRaises(channels.ChannelClosedError):
channels.close(fix.cid, force=True)
else:
- run_interp(interp.id, f"""
+ run_interp(interp.id, """
with helpers.expect_channel_closed():
channels.recv(cid)
""")
- run_interp(interp.id, f"""
+ run_interp(interp.id, """
with helpers.expect_channel_closed():
channels.send(cid, b'spam')
""")
- run_interp(interp.id, f"""
+ run_interp(interp.id, """
with helpers.expect_channel_closed():
channels.close(cid)
""")
- run_interp(interp.id, f"""
+ run_interp(interp.id, """
with helpers.expect_channel_closed():
channels.close(cid, force=True)
""")
diff --git a/Lib/test/test__xxsubinterpreters.py b/Lib/test/test__xxsubinterpreters.py
index 965967e3f2734b..1ee18774d17209 100644
--- a/Lib/test/test__xxsubinterpreters.py
+++ b/Lib/test/test__xxsubinterpreters.py
@@ -798,7 +798,7 @@ def test_shared_overwrites(self):
"""))
shared = {'spam': b'ham'}
- script = dedent(f"""
+ script = dedent("""
ns2 = dict(vars())
del ns2['__builtins__']
""")
@@ -902,7 +902,7 @@ def test_execution_namespace_is_main(self):
# XXX Fix this test!
@unittest.skip('blocking forever')
def test_still_running_at_exit(self):
- script = dedent(f"""
+ script = dedent("""
from textwrap import dedent
import threading
import _xxsubinterpreters as _interpreters
diff --git a/Lib/test/test_ast.py b/Lib/test/test_ast.py
index 1e6d0a07f694db..caf713bd9f333f 100644
--- a/Lib/test/test_ast.py
+++ b/Lib/test/test_ast.py
@@ -774,11 +774,6 @@ def test_parenthesized_with_feature_version(self):
ast.parse('with (CtxManager() as example): ...', feature_version=(3, 8))
ast.parse('with CtxManager() as example: ...', feature_version=(3, 8))
- def test_debug_f_string_feature_version(self):
- ast.parse('f"{x=}"', feature_version=(3, 8))
- with self.assertRaises(SyntaxError):
- ast.parse('f"{x=}"', feature_version=(3, 7))
-
def test_assignment_expression_feature_version(self):
ast.parse('(x := 0)', feature_version=(3, 8))
with self.assertRaises(SyntaxError):
@@ -2298,6 +2293,17 @@ class C:
cdef = ast.parse(s).body[0]
self.assertEqual(ast.get_source_segment(s, cdef.body[0], padded=True), s_method)
+ def test_source_segment_newlines(self):
+ s = 'def f():\n pass\ndef g():\r pass\r\ndef h():\r\n pass\r\n'
+ f, g, h = ast.parse(s).body
+ self._check_content(s, f, 'def f():\n pass')
+ self._check_content(s, g, 'def g():\r pass')
+ self._check_content(s, h, 'def h():\r\n pass')
+
+ s = 'def f():\n a = 1\r b = 2\r\n c = 3\n'
+ f = ast.parse(s).body[0]
+ self._check_content(s, f, s.rstrip())
+
def test_source_segment_missing_info(self):
s = 'v = 1\r\nw = 1\nx = 1\n\ry = 1\r\n'
v, w, x, y = ast.parse(s).body
diff --git a/Lib/test/test_asyncio/test_selector_events.py b/Lib/test/test_asyncio/test_selector_events.py
index 921c98a2702d76..e41341fd26e19e 100644
--- a/Lib/test/test_asyncio/test_selector_events.py
+++ b/Lib/test/test_asyncio/test_selector_events.py
@@ -747,6 +747,48 @@ def test_write_sendmsg_no_data(self):
self.assertFalse(self.sock.sendmsg.called)
self.assertEqual(list_to_buffer([b'data']), transport._buffer)
+ @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
+ def test_writelines_sendmsg_full(self):
+ data = memoryview(b'data')
+ self.sock.sendmsg = mock.Mock()
+ self.sock.sendmsg.return_value = len(data)
+
+ transport = self.socket_transport(sendmsg=True)
+ transport.writelines([data])
+ self.assertTrue(self.sock.sendmsg.called)
+ self.assertFalse(self.loop.writers)
+
+ @unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
+ def test_writelines_sendmsg_partial(self):
+ data = memoryview(b'data')
+ self.sock.sendmsg = mock.Mock()
+ self.sock.sendmsg.return_value = 2
+
+ transport = self.socket_transport(sendmsg=True)
+ transport.writelines([data])
+ self.assertTrue(self.sock.sendmsg.called)
+ self.assertTrue(self.loop.writers)
+
+ def test_writelines_send_full(self):
+ data = memoryview(b'data')
+ self.sock.send.return_value = len(data)
+ self.sock.send.fileno.return_value = 7
+
+ transport = self.socket_transport()
+ transport.writelines([data])
+ self.assertTrue(self.sock.send.called)
+ self.assertFalse(self.loop.writers)
+
+ def test_writelines_send_partial(self):
+ data = memoryview(b'data')
+ self.sock.send.return_value = 2
+ self.sock.send.fileno.return_value = 7
+
+ transport = self.socket_transport()
+ transport.writelines([data])
+ self.assertTrue(self.sock.send.called)
+ self.assertTrue(self.loop.writers)
+
@unittest.skipUnless(selector_events._HAS_SENDMSG, 'no sendmsg')
def test_write_sendmsg_full(self):
data = memoryview(b'data')
diff --git a/Lib/test/test_asyncio/test_unix_events.py b/Lib/test/test_asyncio/test_unix_events.py
index 96999470a7c69a..cdf3eaac68af15 100644
--- a/Lib/test/test_asyncio/test_unix_events.py
+++ b/Lib/test/test_asyncio/test_unix_events.py
@@ -1712,11 +1712,11 @@ class PolicyTests(unittest.TestCase):
def create_policy(self):
return asyncio.DefaultEventLoopPolicy()
- def test_get_default_child_watcher(self):
+ @mock.patch('asyncio.unix_events.can_use_pidfd')
+ def test_get_default_child_watcher(self, m_can_use_pidfd):
+ m_can_use_pidfd.return_value = False
policy = self.create_policy()
self.assertIsNone(policy._watcher)
- unix_events.can_use_pidfd = mock.Mock()
- unix_events.can_use_pidfd.return_value = False
with self.assertWarns(DeprecationWarning):
watcher = policy.get_child_watcher()
self.assertIsInstance(watcher, asyncio.ThreadedChildWatcher)
@@ -1725,10 +1725,9 @@ def test_get_default_child_watcher(self):
with self.assertWarns(DeprecationWarning):
self.assertIs(watcher, policy.get_child_watcher())
+ m_can_use_pidfd.return_value = True
policy = self.create_policy()
self.assertIsNone(policy._watcher)
- unix_events.can_use_pidfd = mock.Mock()
- unix_events.can_use_pidfd.return_value = True
with self.assertWarns(DeprecationWarning):
watcher = policy.get_child_watcher()
self.assertIsInstance(watcher, asyncio.PidfdChildWatcher)
diff --git a/Lib/test/test_bdb.py b/Lib/test/test_bdb.py
index 042c2daea7f797..568c88e326c087 100644
--- a/Lib/test/test_bdb.py
+++ b/Lib/test/test_bdb.py
@@ -433,8 +433,9 @@ def __exit__(self, type_=None, value=None, traceback=None):
not_empty = ''
if self.tracer.set_list:
not_empty += 'All paired tuples have not been processed, '
- not_empty += ('the last one was number %d' %
+ not_empty += ('the last one was number %d\n' %
self.tracer.expect_set_no)
+ not_empty += repr(self.tracer.set_list)
# Make a BdbNotExpectedError a unittest failure.
if type_ is not None and issubclass(BdbNotExpectedError, type_):
@@ -1206,7 +1207,8 @@ def main():
class TestRegressions(unittest.TestCase):
def test_format_stack_entry_no_lineno(self):
# See gh-101517
- Bdb().format_stack_entry((sys._getframe(), None))
+ self.assertIn('Warning: lineno is None',
+ Bdb().format_stack_entry((sys._getframe(), None)))
if __name__ == "__main__":
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 8ac3b7e7eb29d1..098d2d999643cb 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -965,8 +965,10 @@ def check_memoryview(m, expected_readonly=readonly):
self.assertEqual(m.strides, tuple(strides))
self.assertEqual(m.suboffsets, tuple(suboffsets))
- n = 1 if ndim == 0 else len(lst)
- self.assertEqual(len(m), n)
+ if ndim == 0:
+ self.assertRaises(TypeError, len, m)
+ else:
+ self.assertEqual(len(m), len(lst))
rep = result.tolist() if fmt else result.tobytes()
self.assertEqual(rep, lst)
diff --git a/Lib/test/test_builtin.py b/Lib/test/test_builtin.py
index e7a79bc13b7f3d..04dd8ff3070c99 100644
--- a/Lib/test/test_builtin.py
+++ b/Lib/test/test_builtin.py
@@ -28,7 +28,7 @@
from types import AsyncGeneratorType, FunctionType, CellType
from operator import neg
from test import support
-from test.support import (swap_attr, maybe_get_event_loop_policy)
+from test.support import (cpython_only, swap_attr, maybe_get_event_loop_policy)
from test.support.os_helper import (EnvironmentVarGuard, TESTFN, unlink)
from test.support.script_helper import assert_python_ok
from test.support.warnings_helper import check_warnings
@@ -2370,6 +2370,28 @@ def __del__(self):
self.assertEqual(["before", "after"], out.decode().splitlines())
+@cpython_only
+class ImmortalTests(unittest.TestCase):
+ def test_immortal(self):
+ none_refcount = sys.getrefcount(None)
+ true_refcount = sys.getrefcount(True)
+ false_refcount = sys.getrefcount(False)
+ smallint_refcount = sys.getrefcount(100)
+
+ # Assert that all of these immortal instances have large ref counts.
+ self.assertGreater(none_refcount, 2 ** 15)
+ self.assertGreater(true_refcount, 2 ** 15)
+ self.assertGreater(false_refcount, 2 ** 15)
+ self.assertGreater(smallint_refcount, 2 ** 15)
+
+ # Confirm that the refcount doesn't change even with a new ref to them.
+ l = [None, True, False, 100]
+ self.assertEqual(sys.getrefcount(None), none_refcount)
+ self.assertEqual(sys.getrefcount(True), true_refcount)
+ self.assertEqual(sys.getrefcount(False), false_refcount)
+ self.assertEqual(sys.getrefcount(100), smallint_refcount)
+
+
class TestType(unittest.TestCase):
def test_new_type(self):
A = type('A', (), {})
diff --git a/Lib/test/test_capi/test_misc.py b/Lib/test/test_capi/test_misc.py
index c34ee578b5c83f..9470cf12a7d1c4 100644
--- a/Lib/test/test_capi/test_misc.py
+++ b/Lib/test/test_capi/test_misc.py
@@ -21,7 +21,7 @@
from test.support import import_helper
from test.support import threading_helper
from test.support import warnings_helper
-from test.support.script_helper import assert_python_failure, assert_python_ok
+from test.support.script_helper import assert_python_failure, assert_python_ok, run_python_until_end
try:
import _posixsubprocess
except ImportError:
@@ -69,21 +69,17 @@ def test_instancemethod(self):
@support.requires_subprocess()
def test_no_FatalError_infinite_loop(self):
- with support.SuppressCrashReport():
- p = subprocess.Popen([sys.executable, "-c",
- 'import _testcapi;'
- '_testcapi.crash_no_current_thread()'],
- stdout=subprocess.PIPE,
- stderr=subprocess.PIPE,
- text=True)
- (out, err) = p.communicate()
- self.assertEqual(out, '')
+ run_result, _cmd_line = run_python_until_end(
+ '-c', 'import _testcapi; _testcapi.crash_no_current_thread()',
+ )
+ _rc, out, err = run_result
+ self.assertEqual(out, b'')
# This used to cause an infinite loop.
msg = ("Fatal Python error: PyThreadState_Get: "
"the function must be called with the GIL held, "
"after Python initialization and before Python finalization, "
"but the GIL is released "
- "(the current Python thread state is NULL)")
+ "(the current Python thread state is NULL)").encode()
self.assertTrue(err.rstrip().startswith(msg),
err)
@@ -1215,20 +1211,25 @@ def test_configured_settings(self):
"""
import json
+ OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
FORK = 1<<15
EXEC = 1<<16
- features = ['fork', 'exec', 'threads', 'daemon_threads', 'extensions']
+ features = ['obmalloc', 'fork', 'exec', 'threads', 'daemon_threads',
+ 'extensions']
kwlist = [f'allow_{n}' for n in features]
+ kwlist[0] = 'use_main_obmalloc'
kwlist[-1] = 'check_multi_interp_extensions'
+
+ # expected to work
for config, expected in {
- (True, True, True, True, True):
- FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS,
- (False, False, False, False, False): 0,
- (False, False, True, False, True): THREADS | EXTENSIONS,
+ (True, True, True, True, True, True):
+ OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS | EXTENSIONS,
+ (True, False, False, False, False, False): OBMALLOC,
+ (False, False, False, True, False, True): THREADS | EXTENSIONS,
}.items():
kwargs = dict(zip(kwlist, config))
expected = {
@@ -1250,6 +1251,20 @@ def test_configured_settings(self):
self.assertEqual(settings, expected)
+ # expected to fail
+ for config in [
+ (False, False, False, False, False, False),
+ ]:
+ kwargs = dict(zip(kwlist, config))
+ with self.subTest(config):
+ script = textwrap.dedent(f'''
+ import _testinternalcapi
+ _testinternalcapi.get_interp_settings()
+ raise NotImplementedError('unreachable')
+ ''')
+ with self.assertRaises(RuntimeError):
+ support.run_in_subinterp_with_config(script, **kwargs)
+
@unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
def test_overridden_setting_extensions_subinterp_check(self):
@@ -1261,13 +1276,15 @@ def test_overridden_setting_extensions_subinterp_check(self):
"""
import json
+ OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
FORK = 1<<15
EXEC = 1<<16
- BASE_FLAGS = FORK | EXEC | THREADS | DAEMON_THREADS
+ BASE_FLAGS = OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS
base_kwargs = {
+ 'use_main_obmalloc': True,
'allow_fork': True,
'allow_exec': True,
'allow_threads': True,
@@ -1404,7 +1421,7 @@ def callback():
@threading_helper.requires_working_threading()
def test_gilstate_ensure_no_deadlock(self):
# See https://github.com/python/cpython/issues/96071
- code = textwrap.dedent(f"""
+ code = textwrap.dedent("""
import _testcapi
def callback():
diff --git a/Lib/test/test_cmd_line_script.py b/Lib/test/test_cmd_line_script.py
index f10d72ea5547ee..d98e23855e0c19 100644
--- a/Lib/test/test_cmd_line_script.py
+++ b/Lib/test/test_cmd_line_script.py
@@ -636,9 +636,9 @@ def test_syntaxerror_multi_line_fstring(self):
self.assertEqual(
stderr.splitlines()[-3:],
[
- b' foo"""',
- b' ^',
- b'SyntaxError: f-string: empty expression not allowed',
+ b' foo = f"""{}',
+ b' ^',
+ b'SyntaxError: f-string: valid expression required before \'}\'',
],
)
diff --git a/Lib/test/test_code.py b/Lib/test/test_code.py
index 7543c9ab342119..ca06a39f5df142 100644
--- a/Lib/test/test_code.py
+++ b/Lib/test/test_code.py
@@ -349,14 +349,14 @@ def test_invalid_bytecode(self):
def foo():
pass
- # assert that opcode 238 is invalid
- self.assertEqual(opname[238], '<238>')
+ # assert that opcode 229 is invalid
+ self.assertEqual(opname[229], '<229>')
- # change first opcode to 0xee (=238)
+ # change first opcode to 0xeb (=229)
foo.__code__ = foo.__code__.replace(
- co_code=b'\xee' + foo.__code__.co_code[1:])
+ co_code=b'\xe5' + foo.__code__.co_code[1:])
- msg = f"unknown opcode 238"
+ msg = "unknown opcode 229"
with self.assertRaisesRegex(SystemError, msg):
foo()
diff --git a/Lib/test/test_codeop.py b/Lib/test/test_codeop.py
index 6966c2ffd811b8..e3c382266fa058 100644
--- a/Lib/test/test_codeop.py
+++ b/Lib/test/test_codeop.py
@@ -277,7 +277,7 @@ def test_filename(self):
def test_warning(self):
# Test that the warning is only returned once.
with warnings_helper.check_warnings(
- ('"is" with a literal', SyntaxWarning),
+ ('"is" with \'str\' literal', SyntaxWarning),
("invalid escape sequence", SyntaxWarning),
) as w:
compile_command(r"'\e' is 0")
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index bfe18c7fc50330..fb568a48396498 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -1626,7 +1626,7 @@ def test_Set_from_iterable(self):
class SetUsingInstanceFromIterable(MutableSet):
def __init__(self, values, created_by):
if not created_by:
- raise ValueError(f'created_by must be specified')
+ raise ValueError('created_by must be specified')
self.created_by = created_by
self._values = set(values)
diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py
index ec06785b5667a6..0f8351ab8108a6 100644
--- a/Lib/test/test_contextlib.py
+++ b/Lib/test/test_contextlib.py
@@ -10,6 +10,7 @@
from contextlib import * # Tests __all__
from test import support
from test.support import os_helper
+from test.support.testcase import ExceptionIsLikeMixin
import weakref
@@ -1148,7 +1149,7 @@ class TestRedirectStderr(TestRedirectStream, unittest.TestCase):
orig_stream = "stderr"
-class TestSuppress(unittest.TestCase):
+class TestSuppress(ExceptionIsLikeMixin, unittest.TestCase):
@support.requires_docstrings
def test_instance_docs(self):
@@ -1202,6 +1203,30 @@ def test_cm_is_reentrant(self):
1/0
self.assertTrue(outer_continued)
+ def test_exception_groups(self):
+ eg_ve = lambda: ExceptionGroup(
+ "EG with ValueErrors only",
+ [ValueError("ve1"), ValueError("ve2"), ValueError("ve3")],
+ )
+ eg_all = lambda: ExceptionGroup(
+ "EG with many types of exceptions",
+ [ValueError("ve1"), KeyError("ke1"), ValueError("ve2"), KeyError("ke2")],
+ )
+ with suppress(ValueError):
+ raise eg_ve()
+ with suppress(ValueError, KeyError):
+ raise eg_all()
+ with self.assertRaises(ExceptionGroup) as eg1:
+ with suppress(ValueError):
+ raise eg_all()
+ self.assertExceptionIsLike(
+ eg1.exception,
+ ExceptionGroup(
+ "EG with many types of exceptions",
+ [KeyError("ke1"), KeyError("ke2")],
+ ),
+ )
+
class TestChdir(unittest.TestCase):
def make_relative_path(self, *parts):
diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py
index 6ab19efcc588b8..47145782c0f04f 100644
--- a/Lib/test/test_coroutines.py
+++ b/Lib/test/test_coroutines.py
@@ -2365,15 +2365,15 @@ def check(depth, msg):
f"coroutine '{corofn.__qualname__}' was never awaited\n",
"Coroutine created at (most recent call last)\n",
f' File "{a1_filename}", line {a1_lineno}, in a1\n',
- f' return corofn() # comment in a1',
+ " return corofn() # comment in a1",
]))
check(2, "".join([
f"coroutine '{corofn.__qualname__}' was never awaited\n",
"Coroutine created at (most recent call last)\n",
f' File "{a2_filename}", line {a2_lineno}, in a2\n',
- f' return a1() # comment in a2\n',
+ " return a1() # comment in a2\n",
f' File "{a1_filename}", line {a1_lineno}, in a1\n',
- f' return corofn() # comment in a1',
+ " return corofn() # comment in a1",
]))
finally:
diff --git a/Lib/test/test_cppext.py b/Lib/test/test_cppext.py
index 465894d24e7dfc..4fb62d87e860fc 100644
--- a/Lib/test/test_cppext.py
+++ b/Lib/test/test_cppext.py
@@ -1,6 +1,7 @@
# gh-91321: Build a basic C++ test extension to check that the Python C API is
# compatible with C++ and does not emit C++ compiler warnings.
import os.path
+import shutil
import sys
import unittest
import subprocess
@@ -39,6 +40,10 @@ def check_build(self, std_cpp03, extension_name):
self._check_build(std_cpp03, extension_name)
def _check_build(self, std_cpp03, extension_name):
+ pkg_dir = 'pkg'
+ os.mkdir(pkg_dir)
+ shutil.copy(SETUP_TESTCPPEXT, os.path.join(pkg_dir, "setup.py"))
+
venv_dir = 'env'
verbose = support.verbose
@@ -59,11 +64,15 @@ def _check_build(self, std_cpp03, extension_name):
python = os.path.join(venv_dir, 'bin', python_exe)
def run_cmd(operation, cmd):
+ env = os.environ.copy()
+ env['CPYTHON_TEST_CPP_STD'] = 'c++03' if std_cpp03 else 'c++11'
+ env['CPYTHON_TEST_EXT_NAME'] = extension_name
if verbose:
print('Run:', ' '.join(cmd))
- subprocess.run(cmd, check=True)
+ subprocess.run(cmd, check=True, env=env)
else:
proc = subprocess.run(cmd,
+ env=env,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT,
text=True)
@@ -72,16 +81,16 @@ def run_cmd(operation, cmd):
self.fail(
f"{operation} failed with exit code {proc.returncode}")
- # Build the C++ extension
cmd = [python, '-X', 'dev',
- SETUP_TESTCPPEXT, 'build_ext', '--verbose']
- if std_cpp03:
- cmd.append('-std=c++03')
- run_cmd('Build', cmd)
+ '-m', 'pip', 'install',
+ support.findfile('setuptools-67.6.1-py3-none-any.whl'),
+ support.findfile('wheel-0.40.0-py3-none-any.whl')]
+ run_cmd('Install build dependencies', cmd)
- # Install the C++ extension
+ # Build and install the C++ extension
cmd = [python, '-X', 'dev',
- SETUP_TESTCPPEXT, 'install']
+ '-m', 'pip', 'install', '--no-build-isolation',
+ os.path.abspath(pkg_dir)]
run_cmd('Install', cmd)
# Do a reference run. Until we test that running python
diff --git a/Lib/test/test_csv.py b/Lib/test/test_csv.py
index 8289ddb1c3a54f..8fb97bc0c1a1a7 100644
--- a/Lib/test/test_csv.py
+++ b/Lib/test/test_csv.py
@@ -187,6 +187,10 @@ def test_write_quoting(self):
quoting = csv.QUOTE_ALL)
self._write_test(['a\nb',1], '"a\nb","1"',
quoting = csv.QUOTE_ALL)
+ self._write_test(['a','',None,1], '"a","",,1',
+ quoting = csv.QUOTE_STRINGS)
+ self._write_test(['a','',None,1], '"a","",,"1"',
+ quoting = csv.QUOTE_NOTNULL)
def test_write_escape(self):
self._write_test(['a',1,'p,q'], 'a,1,"p,q"',
diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py
index c8a70e3e335693..038161745df905 100644
--- a/Lib/test/test_ctypes/test_pep3118.py
+++ b/Lib/test/test_ctypes/test_pep3118.py
@@ -28,7 +28,7 @@ def test_native_types(self):
if shape:
self.assertEqual(len(v), shape[0])
else:
- self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
+ self.assertRaises(TypeError, len, v)
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851: PyCData_NewGetBuffer() must provide strides
@@ -39,11 +39,10 @@ def test_native_types(self):
# they are always read/write
self.assertFalse(v.readonly)
- if v.shape:
- n = 1
- for dim in v.shape:
- n = n * dim
- self.assertEqual(n * v.itemsize, len(v.tobytes()))
+ n = 1
+ for dim in v.shape:
+ n = n * dim
+ self.assertEqual(n * v.itemsize, len(v.tobytes()))
except:
# so that we can see the failing type
print(tp)
@@ -58,7 +57,7 @@ def test_endian_types(self):
if shape:
self.assertEqual(len(v), shape[0])
else:
- self.assertEqual(len(v) * sizeof(itemtp), sizeof(ob))
+ self.assertRaises(TypeError, len, v)
self.assertEqual(v.itemsize, sizeof(itemtp))
self.assertEqual(v.shape, shape)
# XXX Issue #12851
@@ -67,11 +66,10 @@ def test_endian_types(self):
# they are always read/write
self.assertFalse(v.readonly)
- if v.shape:
- n = 1
- for dim in v.shape:
- n = n * dim
- self.assertEqual(n, len(v))
+ n = 1
+ for dim in v.shape:
+ n = n * dim
+ self.assertEqual(n * v.itemsize, len(v.tobytes()))
except:
# so that we can see the failing type
print(tp)
@@ -243,7 +241,7 @@ class LEPoint(LittleEndianStructure):
#
endian_types = [
(BEPoint, "T{>l:x:>l:y:}".replace('l', s_long), (), BEPoint),
- (LEPoint, "T{l:x:>l:y:}".replace('l', s_long), (), POINTER(BEPoint)),
(POINTER(LEPoint), "&T{"
- ' for field z is not allowed'
+ "mutable default .*Subclass'>"
+ " for field z is not allowed"
):
@dataclass
class Point:
@@ -2297,6 +2297,19 @@ class C:
self.assertDocStrEqual(C.__doc__, "C(x:collections.deque=)")
+ def test_docstring_with_no_signature(self):
+ # See https://github.com/python/cpython/issues/103449
+ class Meta(type):
+ __call__ = dict
+ class Base(metaclass=Meta):
+ pass
+
+ @dataclass
+ class C(Base):
+ pass
+
+ self.assertDocStrEqual(C.__doc__, "C")
+
class TestInit(unittest.TestCase):
def test_base_has_init(self):
diff --git a/Lib/test/test_dis.py b/Lib/test/test_dis.py
index 4a2144743f6567..97960726991b76 100644
--- a/Lib/test/test_dis.py
+++ b/Lib/test/test_dis.py
@@ -479,8 +479,7 @@ async def _asyncwith(c):
YIELD_VALUE 2
RESUME 3
JUMP_BACKWARD_NO_INTERRUPT 5 (to 14)
- >> SWAP 2
- POP_TOP
+ >> END_SEND
POP_TOP
%3d LOAD_CONST 1 (1)
@@ -492,11 +491,11 @@ async def _asyncwith(c):
CALL 2
GET_AWAITABLE 2
LOAD_CONST 0 (None)
- >> SEND 3 (to 62)
+ >> SEND 3 (to 60)
YIELD_VALUE 2
RESUME 3
- JUMP_BACKWARD_NO_INTERRUPT 5 (to 52)
- >> POP_TOP
+ JUMP_BACKWARD_NO_INTERRUPT 5 (to 50)
+ >> END_SEND
POP_TOP
%3d LOAD_CONST 2 (2)
@@ -504,21 +503,20 @@ async def _asyncwith(c):
RETURN_CONST 0 (None)
%3d >> CLEANUP_THROW
- JUMP_BACKWARD 26 (to 24)
+ JUMP_BACKWARD 25 (to 24)
>> CLEANUP_THROW
- JUMP_BACKWARD 9 (to 62)
+ JUMP_BACKWARD 9 (to 60)
>> PUSH_EXC_INFO
WITH_EXCEPT_START
GET_AWAITABLE 2
LOAD_CONST 0 (None)
- >> SEND 4 (to 100)
+ >> SEND 4 (to 98)
YIELD_VALUE 3
RESUME 3
- JUMP_BACKWARD_NO_INTERRUPT 5 (to 88)
+ JUMP_BACKWARD_NO_INTERRUPT 5 (to 86)
>> CLEANUP_THROW
- >> SWAP 2
- POP_TOP
- POP_JUMP_IF_TRUE 1 (to 108)
+ >> END_SEND
+ POP_JUMP_IF_TRUE 1 (to 104)
RERAISE 2
>> POP_TOP
POP_EXCEPT
@@ -878,9 +876,9 @@ def test_boundaries(self):
def test_widths(self):
long_opcodes = set(['JUMP_BACKWARD_NO_INTERRUPT',
- ])
+ 'INSTRUMENTED_CALL_FUNCTION_EX'])
for opcode, opname in enumerate(dis.opname):
- if opname in long_opcodes:
+ if opname in long_opcodes or opname.startswith("INSTRUMENTED"):
continue
with self.subTest(opname=opname):
width = dis._OPNAME_WIDTH
@@ -1069,6 +1067,13 @@ def check(expected, **kwargs):
check(dis_nested_2, depth=None)
check(dis_nested_2)
+ def test__try_compile_no_context_exc_on_error(self):
+ # see gh-102114
+ try:
+ dis._try_compile(")", "")
+ except Exception as e:
+ self.assertIsNone(e.__context__)
+
@staticmethod
def code_quicken(f, times=ADAPTIVE_WARMUP_DELAY):
for _ in range(times):
@@ -1930,6 +1935,14 @@ def test_findlabels(self):
self.assertEqual(sorted(labels), sorted(jumps))
+ def test_findlinestarts(self):
+ def func():
+ pass
+
+ code = func.__code__
+ offsets = [linestart[0] for linestart in dis.findlinestarts(code)]
+ self.assertEqual(offsets, [0, 2])
+
class TestDisTraceback(DisTestBase):
def setUp(self) -> None:
diff --git a/Lib/test/test_embed.py b/Lib/test/test_embed.py
index e56d0db8627e91..c9691bbf304915 100644
--- a/Lib/test/test_embed.py
+++ b/Lib/test/test_embed.py
@@ -110,7 +110,7 @@ def run_embedded_interpreter(self, *args, env=None,
print(f"--- {cmd} failed ---")
print(f"stdout:\n{out}")
print(f"stderr:\n{err}")
- print(f"------")
+ print("------")
self.assertEqual(p.returncode, returncode,
"bad returncode %d, stderr is %r" %
@@ -1656,6 +1656,7 @@ def test_init_use_frozen_modules(self):
api=API_PYTHON, env=env)
def test_init_main_interpreter_settings(self):
+ OBMALLOC = 1<<5
EXTENSIONS = 1<<8
THREADS = 1<<10
DAEMON_THREADS = 1<<11
@@ -1664,7 +1665,7 @@ def test_init_main_interpreter_settings(self):
expected = {
# All optional features should be enabled.
'feature_flags':
- FORK | EXEC | THREADS | DAEMON_THREADS,
+ OBMALLOC | FORK | EXEC | THREADS | DAEMON_THREADS,
}
out, err = self.run_embedded_interpreter(
'test_init_main_interpreter_settings',
diff --git a/Lib/test/test_ensurepip.py b/Lib/test/test_ensurepip.py
index bfca0cd7fbe483..69ab2a4feaa938 100644
--- a/Lib/test/test_ensurepip.py
+++ b/Lib/test/test_ensurepip.py
@@ -20,7 +20,6 @@ def test_version(self):
# Test version()
with tempfile.TemporaryDirectory() as tmpdir:
self.touch(tmpdir, "pip-1.2.3b1-py2.py3-none-any.whl")
- self.touch(tmpdir, "setuptools-49.1.3-py3-none-any.whl")
with (unittest.mock.patch.object(ensurepip, '_PACKAGES', None),
unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)):
self.assertEqual(ensurepip.version(), '1.2.3b1')
@@ -36,15 +35,12 @@ def test_get_packages_no_dir(self):
# use bundled wheel packages
self.assertIsNotNone(packages['pip'].wheel_name)
- self.assertIsNotNone(packages['setuptools'].wheel_name)
def test_get_packages_with_dir(self):
# Test _get_packages() with a wheel package directory
- setuptools_filename = "setuptools-49.1.3-py3-none-any.whl"
pip_filename = "pip-20.2.2-py2.py3-none-any.whl"
with tempfile.TemporaryDirectory() as tmpdir:
- self.touch(tmpdir, setuptools_filename)
self.touch(tmpdir, pip_filename)
# not used, make sure that it's ignored
self.touch(tmpdir, "wheel-0.34.2-py2.py3-none-any.whl")
@@ -53,15 +49,12 @@ def test_get_packages_with_dir(self):
unittest.mock.patch.object(ensurepip, '_WHEEL_PKG_DIR', tmpdir)):
packages = ensurepip._get_packages()
- self.assertEqual(packages['setuptools'].version, '49.1.3')
- self.assertEqual(packages['setuptools'].wheel_path,
- os.path.join(tmpdir, setuptools_filename))
self.assertEqual(packages['pip'].version, '20.2.2')
self.assertEqual(packages['pip'].wheel_path,
os.path.join(tmpdir, pip_filename))
# wheel package is ignored
- self.assertEqual(sorted(packages), ['pip', 'setuptools'])
+ self.assertEqual(sorted(packages), ['pip'])
class EnsurepipMixin:
@@ -92,13 +85,13 @@ def test_basic_bootstrapping(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "setuptools", "pip",
+ unittest.mock.ANY, "pip",
],
unittest.mock.ANY,
)
additional_paths = self.run_pip.call_args[0][1]
- self.assertEqual(len(additional_paths), 2)
+ self.assertEqual(len(additional_paths), 1)
def test_bootstrapping_with_root(self):
ensurepip.bootstrap(root="/foo/bar/")
@@ -107,7 +100,7 @@ def test_bootstrapping_with_root(self):
[
"install", "--no-cache-dir", "--no-index", "--find-links",
unittest.mock.ANY, "--root", "/foo/bar/",
- "setuptools", "pip",
+ "pip",
],
unittest.mock.ANY,
)
@@ -118,7 +111,7 @@ def test_bootstrapping_with_user(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "--user", "setuptools", "pip",
+ unittest.mock.ANY, "--user", "pip",
],
unittest.mock.ANY,
)
@@ -129,7 +122,7 @@ def test_bootstrapping_with_upgrade(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "--upgrade", "setuptools", "pip",
+ unittest.mock.ANY, "--upgrade", "pip",
],
unittest.mock.ANY,
)
@@ -140,7 +133,7 @@ def test_bootstrapping_with_verbosity_1(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "-v", "setuptools", "pip",
+ unittest.mock.ANY, "-v", "pip",
],
unittest.mock.ANY,
)
@@ -151,7 +144,7 @@ def test_bootstrapping_with_verbosity_2(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "-vv", "setuptools", "pip",
+ unittest.mock.ANY, "-vv", "pip",
],
unittest.mock.ANY,
)
@@ -162,7 +155,7 @@ def test_bootstrapping_with_verbosity_3(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "-vvv", "setuptools", "pip",
+ unittest.mock.ANY, "-vvv", "pip",
],
unittest.mock.ANY,
)
@@ -239,7 +232,6 @@ def test_uninstall(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "pip",
- "setuptools",
]
)
@@ -250,7 +242,6 @@ def test_uninstall_with_verbosity_1(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-v", "pip",
- "setuptools",
]
)
@@ -261,7 +252,6 @@ def test_uninstall_with_verbosity_2(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-vv", "pip",
- "setuptools",
]
)
@@ -272,7 +262,7 @@ def test_uninstall_with_verbosity_3(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "-vvv",
- "pip", "setuptools",
+ "pip"
]
)
@@ -312,13 +302,13 @@ def test_basic_bootstrapping(self):
self.run_pip.assert_called_once_with(
[
"install", "--no-cache-dir", "--no-index", "--find-links",
- unittest.mock.ANY, "setuptools", "pip",
+ unittest.mock.ANY, "pip",
],
unittest.mock.ANY,
)
additional_paths = self.run_pip.call_args[0][1]
- self.assertEqual(len(additional_paths), 2)
+ self.assertEqual(len(additional_paths), 1)
self.assertEqual(exit_code, 0)
def test_bootstrapping_error_code(self):
@@ -344,7 +334,6 @@ def test_basic_uninstall(self):
self.run_pip.assert_called_once_with(
[
"uninstall", "-y", "--disable-pip-version-check", "pip",
- "setuptools",
]
)
diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py
index e4151bf9e6d9b3..fb7a016c9007f8 100644
--- a/Lib/test/test_enum.py
+++ b/Lib/test/test_enum.py
@@ -819,10 +819,27 @@ class TestPlainFlag(_EnumTests, _PlainOutputTests, _FlagTests, unittest.TestCase
class TestIntEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
enum_type = IntEnum
+ #
+ def test_shadowed_attr(self):
+ class Number(IntEnum):
+ divisor = 1
+ numerator = 2
+ #
+ self.assertEqual(Number.divisor.numerator, 1)
+ self.assertIs(Number.numerator.divisor, Number.divisor)
class TestStrEnum(_EnumTests, _MinimalOutputTests, unittest.TestCase):
enum_type = StrEnum
+ #
+ def test_shadowed_attr(self):
+ class Book(StrEnum):
+ author = 'author'
+ title = 'title'
+ #
+ self.assertEqual(Book.author.title(), 'Author')
+ self.assertEqual(Book.title.title(), 'Title')
+ self.assertIs(Book.title.author, Book.author)
class TestIntFlag(_EnumTests, _MinimalOutputTests, _FlagTests, unittest.TestCase):
@@ -2737,10 +2754,10 @@ def __repr__(self):
return 'ha hah!'
class Entries(Foo, Enum):
ENTRY1 = 1
+ self.assertEqual(repr(Entries.ENTRY1), '')
+ self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value)
self.assertTrue(isinstance(Entries.ENTRY1, Foo))
self.assertTrue(Entries._member_type_ is Foo, Entries._member_type_)
- self.assertTrue(Entries.ENTRY1.value == Foo(1), Entries.ENTRY1.value)
- self.assertEqual(repr(Entries.ENTRY1), '')
#
# check auto-generated dataclass __repr__ is not used
#
@@ -2787,8 +2804,7 @@ class Creature(CreatureDataMixin, Enum):
DOG = ('medium', 4)
self.assertRegex(repr(Creature.DOG), "")
- def test_repr_with_init_data_type_mixin(self):
- # non-data_type is a mixin that doesn't define __new__
+ def test_repr_with_init_mixin(self):
class Foo:
def __init__(self, a):
self.a = a
@@ -2797,9 +2813,9 @@ def __repr__(self):
class Entries(Foo, Enum):
ENTRY1 = 1
#
- self.assertEqual(repr(Entries.ENTRY1), '')
+ self.assertEqual(repr(Entries.ENTRY1), 'Foo(a=1)')
- def test_repr_and_str_with_non_data_type_mixin(self):
+ def test_repr_and_str_with_no_init_mixin(self):
# non-data_type is a mixin that doesn't define __new__
class Foo:
def __repr__(self):
@@ -2873,6 +2889,8 @@ def __new__(cls, c):
#
a = ord('a')
#
+ self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343)
+ self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672)
self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)
#
@@ -2887,6 +2905,8 @@ def __new__(cls, c):
a = ord('a')
z = 1
#
+ self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343)
+ self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900674)
self.assertEqual(FlagFromChar.a.value, 158456325028528675187087900672)
self.assertEqual((FlagFromChar.a|FlagFromChar.z).value, 158456325028528675187087900674)
#
@@ -2900,11 +2920,15 @@ def __new__(cls, c):
#
a = ord('a')
#
+ self.assertEqual(FlagFromChar._all_bits_, 316912650057057350374175801343)
+ self.assertEqual(FlagFromChar._flag_mask_, 158456325028528675187087900672)
self.assertEqual(FlagFromChar.a, 158456325028528675187087900672)
self.assertEqual(FlagFromChar.a|1, 158456325028528675187087900673)
def test_init_exception(self):
class Base:
+ def __new__(cls, *args):
+ return object.__new__(cls)
def __init__(self, x):
raise ValueError("I don't like", x)
with self.assertRaises(TypeError):
@@ -3077,18 +3101,18 @@ def test_bool(self):
self.assertEqual(bool(f.value), bool(f))
def test_boundary(self):
- self.assertIs(enum.Flag._boundary_, CONFORM)
- class Iron(Flag, boundary=STRICT):
+ self.assertIs(enum.Flag._boundary_, STRICT)
+ class Iron(Flag, boundary=CONFORM):
ONE = 1
TWO = 2
EIGHT = 8
- self.assertIs(Iron._boundary_, STRICT)
+ self.assertIs(Iron._boundary_, CONFORM)
#
- class Water(Flag, boundary=CONFORM):
+ class Water(Flag, boundary=STRICT):
ONE = 1
TWO = 2
EIGHT = 8
- self.assertIs(Water._boundary_, CONFORM)
+ self.assertIs(Water._boundary_, STRICT)
#
class Space(Flag, boundary=EJECT):
ONE = 1
@@ -3101,10 +3125,10 @@ class Bizarre(Flag, boundary=KEEP):
c = 4
d = 6
#
- self.assertRaisesRegex(ValueError, 'invalid value 7', Iron, 7)
+ self.assertRaisesRegex(ValueError, 'invalid value 7', Water, 7)
#
- self.assertIs(Water(7), Water.ONE|Water.TWO)
- self.assertIs(Water(~9), Water.TWO)
+ self.assertIs(Iron(7), Iron.ONE|Iron.TWO)
+ self.assertIs(Iron(~9), Iron.TWO)
#
self.assertEqual(Space(7), 7)
self.assertTrue(type(Space(7)) is int)
@@ -3112,6 +3136,31 @@ class Bizarre(Flag, boundary=KEEP):
self.assertEqual(list(Bizarre), [Bizarre.c])
self.assertIs(Bizarre(3), Bizarre.b)
self.assertIs(Bizarre(6), Bizarre.d)
+ #
+ class SkipFlag(enum.Flag):
+ A = 1
+ B = 2
+ C = 4 | B
+ #
+ self.assertTrue(SkipFlag.C in (SkipFlag.A|SkipFlag.C))
+ self.assertRaisesRegex(ValueError, 'SkipFlag.. invalid value 42', SkipFlag, 42)
+ #
+ class SkipIntFlag(enum.IntFlag):
+ A = 1
+ B = 2
+ C = 4 | B
+ #
+ self.assertTrue(SkipIntFlag.C in (SkipIntFlag.A|SkipIntFlag.C))
+ self.assertEqual(SkipIntFlag(42).value, 42)
+ #
+ class MethodHint(Flag):
+ HiddenText = 0x10
+ DigitsOnly = 0x01
+ LettersOnly = 0x02
+ OnlyMask = 0x0f
+ #
+ self.assertEqual(str(MethodHint.HiddenText|MethodHint.OnlyMask), 'MethodHint.HiddenText|DigitsOnly|LettersOnly|OnlyMask')
+
def test_iter(self):
Color = self.Color
diff --git a/Lib/test/test_eof.py b/Lib/test/test_eof.py
index abcbf046e2cc22..be4fd73bfdc36b 100644
--- a/Lib/test/test_eof.py
+++ b/Lib/test/test_eof.py
@@ -4,6 +4,7 @@
from test import support
from test.support import os_helper
from test.support import script_helper
+from test.support import warnings_helper
import unittest
class EOFTestCase(unittest.TestCase):
@@ -36,10 +37,11 @@ def test_EOFS_with_file(self):
rc, out, err = script_helper.assert_python_failure(file_name)
self.assertIn(b'unterminated triple-quoted string literal (detected at line 3)', err)
+ @warnings_helper.ignore_warnings(category=SyntaxWarning)
def test_eof_with_line_continuation(self):
expect = "unexpected EOF while parsing (, line 1)"
try:
- compile('"\\xhh" \\', '', 'exec', dont_inherit=True)
+ compile('"\\Xhh" \\', '', 'exec')
except SyntaxError as msg:
self.assertEqual(str(msg), expect)
else:
diff --git a/Lib/test/test_except_star.py b/Lib/test/test_except_star.py
index c5167c5bba38af..bc66f90b9cad45 100644
--- a/Lib/test/test_except_star.py
+++ b/Lib/test/test_except_star.py
@@ -1,6 +1,7 @@
import sys
import unittest
import textwrap
+from test.support.testcase import ExceptionIsLikeMixin
class TestInvalidExceptStar(unittest.TestCase):
def test_mixed_except_and_except_star_is_syntax_error(self):
@@ -169,26 +170,7 @@ def f(x):
self.assertIsInstance(exc, ExceptionGroup)
-class ExceptStarTest(unittest.TestCase):
- def assertExceptionIsLike(self, exc, template):
- if exc is None and template is None:
- return
-
- if template is None:
- self.fail(f"unexpected exception: {exc}")
-
- if exc is None:
- self.fail(f"expected an exception like {template!r}, got None")
-
- if not isinstance(exc, ExceptionGroup):
- self.assertEqual(exc.__class__, template.__class__)
- self.assertEqual(exc.args[0], template.args[0])
- else:
- self.assertEqual(exc.message, template.message)
- self.assertEqual(len(exc.exceptions), len(template.exceptions))
- for e, t in zip(exc.exceptions, template.exceptions):
- self.assertExceptionIsLike(e, t)
-
+class ExceptStarTest(ExceptionIsLikeMixin, unittest.TestCase):
def assertMetadataEqual(self, e1, e2):
if e1 is None or e2 is None:
self.assertTrue(e1 is None and e2 is None)
diff --git a/Lib/test/test_exception_group.py b/Lib/test/test_exception_group.py
index b11524e778e665..fa159a76ec1aff 100644
--- a/Lib/test/test_exception_group.py
+++ b/Lib/test/test_exception_group.py
@@ -102,6 +102,20 @@ class MyEG(BaseExceptionGroup, ValueError):
with self.assertRaisesRegex(TypeError, msg):
MyEG("eg", [ValueError(12), KeyboardInterrupt(42)])
+ def test_EG_and_specific_subclass_can_wrap_any_nonbase_exception(self):
+ class MyEG(ExceptionGroup, ValueError):
+ pass
+
+ # The restriction is specific to Exception, not "the other base class"
+ MyEG("eg", [ValueError(12), Exception()])
+
+ def test_BEG_and_specific_subclass_can_wrap_any_nonbase_exception(self):
+ class MyEG(BaseExceptionGroup, ValueError):
+ pass
+
+ # The restriction is specific to Exception, not "the other base class"
+ MyEG("eg", [ValueError(12), Exception()])
+
def test_BEG_subclass_wraps_anything(self):
class MyBEG(BaseExceptionGroup):
diff --git a/Lib/test/test_exceptions.py b/Lib/test/test_exceptions.py
index 684e888f08c778..4ef7decfbc263e 100644
--- a/Lib/test/test_exceptions.py
+++ b/Lib/test/test_exceptions.py
@@ -155,6 +155,7 @@ def ckmsg(src, msg):
ckmsg(s, "'continue' not properly in loop")
ckmsg("continue\n", "'continue' not properly in loop")
+ ckmsg("f'{6 0}'", "invalid syntax. Perhaps you forgot a comma?")
def testSyntaxErrorMissingParens(self):
def ckmsg(src, msg, exception=SyntaxError):
@@ -227,7 +228,7 @@ def testSyntaxErrorOffset(self):
check('Python = "\u1e54\xfd\u0163\u0125\xf2\xf1" +', 1, 20)
check(b'# -*- coding: cp1251 -*-\nPython = "\xcf\xb3\xf2\xee\xed" +',
2, 19, encoding='cp1251')
- check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 18)
+ check(b'Python = "\xcf\xb3\xf2\xee\xed" +', 1, 10)
check('x = "a', 1, 5)
check('lambda x: x = 2', 1, 1)
check('f{a + b + c}', 1, 2)
diff --git a/Lib/test/test_fstring.py b/Lib/test/test_fstring.py
index b3f6ef41d77b8f..9d5e16628f04b6 100644
--- a/Lib/test/test_fstring.py
+++ b/Lib/test/test_fstring.py
@@ -13,6 +13,7 @@
import types
import decimal
import unittest
+from test import support
from test.support.os_helper import temp_cwd
from test.support.script_helper import assert_python_failure
@@ -329,13 +330,13 @@ def test_ast_line_numbers_multiline_fstring(self):
self.assertEqual(t.body[1].lineno, 3)
self.assertEqual(t.body[1].value.lineno, 3)
self.assertEqual(t.body[1].value.values[0].lineno, 3)
- self.assertEqual(t.body[1].value.values[1].lineno, 3)
- self.assertEqual(t.body[1].value.values[2].lineno, 3)
+ self.assertEqual(t.body[1].value.values[1].lineno, 4)
+ self.assertEqual(t.body[1].value.values[2].lineno, 6)
self.assertEqual(t.body[1].col_offset, 0)
self.assertEqual(t.body[1].value.col_offset, 0)
- self.assertEqual(t.body[1].value.values[0].col_offset, 0)
- self.assertEqual(t.body[1].value.values[1].col_offset, 0)
- self.assertEqual(t.body[1].value.values[2].col_offset, 0)
+ self.assertEqual(t.body[1].value.values[0].col_offset, 4)
+ self.assertEqual(t.body[1].value.values[1].col_offset, 2)
+ self.assertEqual(t.body[1].value.values[2].col_offset, 11)
# NOTE: the following lineno information and col_offset is correct for
# expressions within FormattedValues.
binop = t.body[1].value.values[1].value
@@ -366,13 +367,13 @@ def test_ast_line_numbers_multiline_fstring(self):
self.assertEqual(t.body[0].lineno, 2)
self.assertEqual(t.body[0].value.lineno, 2)
self.assertEqual(t.body[0].value.values[0].lineno, 2)
- self.assertEqual(t.body[0].value.values[1].lineno, 2)
- self.assertEqual(t.body[0].value.values[2].lineno, 2)
+ self.assertEqual(t.body[0].value.values[1].lineno, 3)
+ self.assertEqual(t.body[0].value.values[2].lineno, 3)
self.assertEqual(t.body[0].col_offset, 0)
self.assertEqual(t.body[0].value.col_offset, 4)
- self.assertEqual(t.body[0].value.values[0].col_offset, 4)
- self.assertEqual(t.body[0].value.values[1].col_offset, 4)
- self.assertEqual(t.body[0].value.values[2].col_offset, 4)
+ self.assertEqual(t.body[0].value.values[0].col_offset, 8)
+ self.assertEqual(t.body[0].value.values[1].col_offset, 10)
+ self.assertEqual(t.body[0].value.values[2].col_offset, 17)
# Check {blech}
self.assertEqual(t.body[0].value.values[1].value.lineno, 3)
self.assertEqual(t.body[0].value.values[1].value.end_lineno, 3)
@@ -387,6 +388,20 @@ def test_ast_line_numbers_with_parentheses(self):
t = ast.parse(expr)
self.assertEqual(type(t), ast.Module)
self.assertEqual(len(t.body), 1)
+ # check the joinedstr location
+ joinedstr = t.body[0].value
+ self.assertEqual(type(joinedstr), ast.JoinedStr)
+ self.assertEqual(joinedstr.lineno, 3)
+ self.assertEqual(joinedstr.end_lineno, 3)
+ self.assertEqual(joinedstr.col_offset, 4)
+ self.assertEqual(joinedstr.end_col_offset, 17)
+ # check the formatted value location
+ fv = t.body[0].value.values[1]
+ self.assertEqual(type(fv), ast.FormattedValue)
+ self.assertEqual(fv.lineno, 3)
+ self.assertEqual(fv.end_lineno, 3)
+ self.assertEqual(fv.col_offset, 7)
+ self.assertEqual(fv.end_col_offset, 16)
# check the test(t) location
call = t.body[0].value.values[1].value
self.assertEqual(type(call), ast.Call)
@@ -397,6 +412,50 @@ def test_ast_line_numbers_with_parentheses(self):
expr = """
x = (
+ u'wat',
+ u"wat",
+ b'wat',
+ b"wat",
+ f'wat',
+ f"wat",
+)
+
+y = (
+ u'''wat''',
+ u\"\"\"wat\"\"\",
+ b'''wat''',
+ b\"\"\"wat\"\"\",
+ f'''wat''',
+ f\"\"\"wat\"\"\",
+)
+ """
+ t = ast.parse(expr)
+ self.assertEqual(type(t), ast.Module)
+ self.assertEqual(len(t.body), 2)
+ x, y = t.body
+
+ # Check the single quoted string offsets first.
+ offsets = [
+ (elt.col_offset, elt.end_col_offset)
+ for elt in x.value.elts
+ ]
+ self.assertTrue(all(
+ offset == (4, 10)
+ for offset in offsets
+ ))
+
+ # Check the triple quoted string offsets.
+ offsets = [
+ (elt.col_offset, elt.end_col_offset)
+ for elt in y.value.elts
+ ]
+ self.assertTrue(all(
+ offset == (4, 14)
+ for offset in offsets
+ ))
+
+ expr = """
+x = (
'PERL_MM_OPT', (
f'wat'
f'some_string={f(x)} '
@@ -415,9 +474,9 @@ def test_ast_line_numbers_with_parentheses(self):
# check the first wat
self.assertEqual(type(wat1), ast.Constant)
self.assertEqual(wat1.lineno, 4)
- self.assertEqual(wat1.end_lineno, 6)
- self.assertEqual(wat1.col_offset, 12)
- self.assertEqual(wat1.end_col_offset, 18)
+ self.assertEqual(wat1.end_lineno, 5)
+ self.assertEqual(wat1.col_offset, 14)
+ self.assertEqual(wat1.end_col_offset, 26)
# check the call
call = middle.value
self.assertEqual(type(call), ast.Call)
@@ -427,10 +486,14 @@ def test_ast_line_numbers_with_parentheses(self):
self.assertEqual(call.end_col_offset, 31)
# check the second wat
self.assertEqual(type(wat2), ast.Constant)
- self.assertEqual(wat2.lineno, 4)
+ self.assertEqual(wat2.lineno, 5)
self.assertEqual(wat2.end_lineno, 6)
- self.assertEqual(wat2.col_offset, 12)
- self.assertEqual(wat2.end_col_offset, 18)
+ self.assertEqual(wat2.col_offset, 32)
+ # wat ends at the offset 17, but the whole f-string
+ # ends at the offset 18 (since the quote is part of the
+ # f-string but not the wat string)
+ self.assertEqual(wat2.end_col_offset, 17)
+ self.assertEqual(fstring.end_col_offset, 18)
def test_docstring(self):
def f():
@@ -467,36 +530,42 @@ def test_literal(self):
self.assertEqual(f' ', ' ')
def test_unterminated_string(self):
- self.assertAllRaise(SyntaxError, 'f-string: unterminated string',
+ self.assertAllRaise(SyntaxError, 'unterminated string',
[r"""f'{"x'""",
r"""f'{"x}'""",
r"""f'{("x'""",
r"""f'{("x}'""",
])
+ @unittest.skipIf(support.is_wasi, "exhausts limited stack on WASI")
def test_mismatched_parens(self):
- self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
+ self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' "
r"does not match opening parenthesis '\('",
["f'{((}'",
])
- self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\)' "
+ self.assertAllRaise(SyntaxError, r"closing parenthesis '\)' "
r"does not match opening parenthesis '\['",
["f'{a[4)}'",
])
- self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\]' "
+ self.assertAllRaise(SyntaxError, r"closing parenthesis '\]' "
r"does not match opening parenthesis '\('",
["f'{a(4]}'",
])
- self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
+ self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' "
r"does not match opening parenthesis '\['",
["f'{a[4}'",
])
- self.assertAllRaise(SyntaxError, r"f-string: closing parenthesis '\}' "
+ self.assertAllRaise(SyntaxError, r"closing parenthesis '\}' "
r"does not match opening parenthesis '\('",
["f'{a(4}'",
])
self.assertRaises(SyntaxError, eval, "f'{" + "("*500 + "}'")
+ def test_fstring_nested_too_deeply(self):
+ self.assertAllRaise(SyntaxError,
+ "f-string: expressions nested too deeply",
+ ['f"{1+2:{1+2:{1+1:{1}}}}"'])
+
def test_double_braces(self):
self.assertEqual(f'{{', '{')
self.assertEqual(f'a{{', 'a{')
@@ -559,8 +628,14 @@ def test_compile_time_concat(self):
self.assertEqual(f'' '' f'', '')
self.assertEqual(f'' '' f'' '', '')
- self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
- ["f'{3' f'}'", # can't concat to get a valid f-string
+ # This is not really [f'{'] + [f'}'] since we treat the inside
+ # of braces as a purely new context, so it is actually f'{ and
+ # then eval(' f') (a valid expression) and then }' which would
+ # constitute a valid f-string.
+ self.assertEqual(f'{' f'}', ' f')
+
+ self.assertAllRaise(SyntaxError, "expecting '}'",
+ ['''f'{3' f"}"''', # can't concat to get a valid f-string
])
def test_comments(self):
@@ -618,25 +693,19 @@ def test_format_specifier_expressions(self):
self.assertEqual(f'{-10:-{"#"}1{0}x}', ' -0xa')
self.assertEqual(f'{-10:{"-"}#{1}0{"x"}}', ' -0xa')
self.assertEqual(f'{10:#{3 != {4:5} and width}x}', ' 0xa')
+ self.assertEqual(f'result: {value:{width:{0}}.{precision:1}}', 'result: 12.35')
- self.assertAllRaise(SyntaxError,
- """f-string: invalid conversion character 'r{"': """
- """expected 's', 'r', or 'a'""",
+ self.assertAllRaise(SyntaxError, "f-string: expecting ':' or '}'",
["""f'{"s"!r{":10"}}'""",
-
# This looks like a nested format spec.
])
- self.assertAllRaise(SyntaxError, "f-string: invalid syntax",
+ self.assertAllRaise(SyntaxError,
+ "f-string: expecting a valid expression after '{'",
[# Invalid syntax inside a nested spec.
"f'{4:{/5}}'",
])
- self.assertAllRaise(SyntaxError, "f-string: expressions nested too deeply",
- [# Can't nest format specifiers.
- "f'result: {value:{width:{0}}.{precision:1}}'",
- ])
-
self.assertAllRaise(SyntaxError, 'f-string: invalid conversion character',
[# No expansion inside conversion or for
# the : or ! itself.
@@ -655,7 +724,8 @@ def __format__(self, spec):
self.assertEqual(f'{x} {x}', '1 2')
def test_missing_expression(self):
- self.assertAllRaise(SyntaxError, 'f-string: empty expression not allowed',
+ self.assertAllRaise(SyntaxError,
+ "f-string: valid expression required before '}'",
["f'{}'",
"f'{ }'"
"f' {} '",
@@ -667,8 +737,8 @@ def test_missing_expression(self):
"f'''{\t\f\r\n}'''",
])
- # Different error messages are raised when a specifier ('!', ':' or '=') is used after an empty expression
- self.assertAllRaise(SyntaxError, "f-string: expression required before '!'",
+ self.assertAllRaise(SyntaxError,
+ "f-string: valid expression required before '!'",
["f'{!r}'",
"f'{ !r}'",
"f'{!}'",
@@ -689,7 +759,8 @@ def test_missing_expression(self):
"f'{ !xr:a}'",
])
- self.assertAllRaise(SyntaxError, "f-string: expression required before ':'",
+ self.assertAllRaise(SyntaxError,
+ "f-string: valid expression required before ':'",
["f'{:}'",
"f'{ :!}'",
"f'{:2}'",
@@ -697,7 +768,8 @@ def test_missing_expression(self):
"f'{:'",
])
- self.assertAllRaise(SyntaxError, "f-string: expression required before '='",
+ self.assertAllRaise(SyntaxError,
+ "f-string: valid expression required before '='",
["f'{=}'",
"f'{ =}'",
"f'{ =:}'",
@@ -715,24 +787,18 @@ def test_missing_expression(self):
def test_parens_in_expressions(self):
self.assertEqual(f'{3,}', '(3,)')
- # Add these because when an expression is evaluated, parens
- # are added around it. But we shouldn't go from an invalid
- # expression to a valid one. The added parens are just
- # supposed to allow whitespace (including newlines).
- self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
+ self.assertAllRaise(SyntaxError,
+ "f-string: expecting a valid expression after '{'",
["f'{,}'",
- "f'{,}'", # this is (,), which is an error
])
self.assertAllRaise(SyntaxError, r"f-string: unmatched '\)'",
["f'{3)+(4}'",
])
- self.assertAllRaise(SyntaxError, 'unterminated string literal',
- ["f'{\n}'",
- ])
def test_newlines_before_syntax_error(self):
- self.assertAllRaise(SyntaxError, "invalid syntax",
+ self.assertAllRaise(SyntaxError,
+ "f-string: expecting a valid expression after '{'",
["f'{.}'", "\nf'{.}'", "\n\nf'{.}'"])
def test_backslashes_in_string_part(self):
@@ -776,7 +842,7 @@ def test_backslashes_in_string_part(self):
self.assertEqual(f'2\x203', '2 3')
self.assertEqual(f'\x203', ' 3')
- with self.assertWarns(SyntaxWarning): # invalid escape sequence
+ with self.assertWarns(DeprecationWarning): # invalid escape sequence
value = eval(r"f'\{6*7}'")
self.assertEqual(value, '\\42')
self.assertEqual(f'\\{6*7}', '\\42')
@@ -809,18 +875,40 @@ def test_misformed_unicode_character_name(self):
r"'\N{GREEK CAPITAL LETTER DELTA'",
])
- def test_no_backslashes_in_expression_part(self):
- self.assertAllRaise(SyntaxError, 'f-string expression part cannot include a backslash',
- [r"f'{\'a\'}'",
- r"f'{\t3}'",
- r"f'{\}'",
- r"rf'{\'a\'}'",
- r"rf'{\t3}'",
- r"rf'{\}'",
- r"""rf'{"\N{LEFT CURLY BRACKET}"}'""",
- r"f'{\n}'",
+ def test_backslashes_in_expression_part(self):
+ self.assertEqual(f"{(
+ 1 +
+ 2
+ )}", "3")
+
+ self.assertEqual("\N{LEFT CURLY BRACKET}", '{')
+ self.assertEqual(f'{"\N{LEFT CURLY BRACKET}"}', '{')
+ self.assertEqual(rf'{"\N{LEFT CURLY BRACKET}"}', '{')
+
+ self.assertAllRaise(SyntaxError,
+ "f-string: valid expression required before '}'",
+ ["f'{\n}'",
])
+ def test_invalid_backslashes_inside_fstring_context(self):
+ # All of these variations are invalid python syntax,
+ # so they are also invalid in f-strings as well.
+ cases = [
+ formatting.format(expr=expr)
+ for formatting in [
+ "{expr}",
+ "f'{{{expr}}}'",
+ "rf'{{{expr}}}'",
+ ]
+ for expr in [
+ r"\'a\'",
+ r"\t3",
+ r"\\"[0],
+ ]
+ ]
+ self.assertAllRaise(SyntaxError, 'unexpected character after line continuation',
+ cases)
+
def test_no_escapes_for_braces(self):
"""
Only literal curly braces begin an expression.
@@ -843,11 +931,67 @@ def test_lambda(self):
self.assertEqual(f'{(lambda y:x*y)("8"):10}', "88888 ")
# lambda doesn't work without parens, because the colon
- # makes the parser think it's a format_spec
- self.assertAllRaise(SyntaxError, 'f-string: invalid syntax',
+ # makes the parser think it's a format_spec
+ # emit warning if we can match a format_spec
+ self.assertAllRaise(SyntaxError,
+ "f-string: lambda expressions are not allowed "
+ "without parentheses",
["f'{lambda x:x}'",
+ "f'{lambda :x}'",
+ "f'{lambda *arg, :x}'",
+ "f'{1, lambda:x}'",
+ "f'{lambda x:}'",
+ "f'{lambda :}'",
])
+ # but don't emit the paren warning in general cases
+ with self.assertRaisesRegex(SyntaxError, "f-string: expecting a valid expression after '{'"):
+ eval("f'{+ lambda:None}'")
+
+ def test_valid_prefixes(self):
+ self.assertEqual(F'{1}', "1")
+ self.assertEqual(FR'{2}', "2")
+ self.assertEqual(fR'{3}', "3")
+
+ def test_roundtrip_raw_quotes(self):
+ self.assertEqual(fr"\'", "\\'")
+ self.assertEqual(fr'\"', '\\"')
+ self.assertEqual(fr'\"\'', '\\"\\\'')
+ self.assertEqual(fr'\'\"', '\\\'\\"')
+ self.assertEqual(fr'\"\'\"', '\\"\\\'\\"')
+ self.assertEqual(fr'\'\"\'', '\\\'\\"\\\'')
+ self.assertEqual(fr'\"\'\"\'', '\\"\\\'\\"\\\'')
+
+ def test_fstring_backslash_before_double_bracket(self):
+ self.assertEqual(f'\{{\}}', '\\{\\}')
+ self.assertEqual(f'\{{', '\\{')
+ self.assertEqual(f'\{{{1+1}', '\\{2')
+ self.assertEqual(f'\}}{1+1}', '\\}2')
+ self.assertEqual(f'{1+1}\}}', '2\\}')
+ self.assertEqual(fr'\{{\}}', '\\{\\}')
+ self.assertEqual(fr'\{{', '\\{')
+ self.assertEqual(fr'\{{{1+1}', '\\{2')
+ self.assertEqual(fr'\}}{1+1}', '\\}2')
+ self.assertEqual(fr'{1+1}\}}', '2\\}')
+
+ def test_fstring_backslash_prefix_raw(self):
+ self.assertEqual(f'\\', '\\')
+ self.assertEqual(f'\\\\', '\\\\')
+ self.assertEqual(fr'\\', r'\\')
+ self.assertEqual(fr'\\\\', r'\\\\')
+ self.assertEqual(rf'\\', r'\\')
+ self.assertEqual(rf'\\\\', r'\\\\')
+ self.assertEqual(Rf'\\', R'\\')
+ self.assertEqual(Rf'\\\\', R'\\\\')
+ self.assertEqual(fR'\\', R'\\')
+ self.assertEqual(fR'\\\\', R'\\\\')
+ self.assertEqual(FR'\\', R'\\')
+ self.assertEqual(FR'\\\\', R'\\\\')
+
+ def test_fstring_format_spec_greedy_matching(self):
+ self.assertEqual(f"{1:}}}", "1}")
+ self.assertEqual(f"{1:>3{5}}}}", " 1}")
+
def test_yield(self):
# Not terribly useful, but make sure the yield turns
# a function into a generator
@@ -1037,6 +1181,11 @@ def test_conversions(self):
self.assertEqual(f'{"a"!r}', "'a'")
self.assertEqual(f'{"a"!a}', "'a'")
+ # Conversions can have trailing whitespace after them since it
+ # does not provide any significance
+ self.assertEqual(f"{3!s }", "3")
+ self.assertEqual(f'{3.14!s :10.10}', '3.14 ')
+
# Not a conversion.
self.assertEqual(f'{"a!r"}', "a!r")
@@ -1049,16 +1198,27 @@ def test_conversions(self):
"f'{3!g'",
])
- self.assertAllRaise(SyntaxError, 'f-string: missed conversion character',
+ self.assertAllRaise(SyntaxError, 'f-string: missing conversion character',
["f'{3!}'",
"f'{3!:'",
"f'{3!:}'",
])
- for conv in 'g', 'A', '3', 'G', '!', ' s', 's ', ' s ', 'ä', 'ɐ', 'ª':
+ for conv_identifier in 'g', 'A', 'G', 'ä', 'ɐ':
self.assertAllRaise(SyntaxError,
"f-string: invalid conversion character %r: "
- "expected 's', 'r', or 'a'" % conv,
+ "expected 's', 'r', or 'a'" % conv_identifier,
+ ["f'{3!" + conv_identifier + "}'"])
+
+ for conv_non_identifier in '3', '!':
+ self.assertAllRaise(SyntaxError,
+ "f-string: invalid conversion character",
+ ["f'{3!" + conv_non_identifier + "}'"])
+
+ for conv in ' s', ' s ':
+ self.assertAllRaise(SyntaxError,
+ "f-string: conversion type must come right after the"
+ " exclamanation mark",
["f'{3!" + conv + "}'"])
self.assertAllRaise(SyntaxError,
@@ -1097,8 +1257,7 @@ def test_mismatched_braces(self):
])
self.assertAllRaise(SyntaxError, "f-string: expecting '}'",
- ["f'{3:{{>10}'",
- "f'{3'",
+ ["f'{3'",
"f'{3!'",
"f'{3:'",
"f'{3!s'",
@@ -1111,11 +1270,14 @@ def test_mismatched_braces(self):
"f'{{{'",
"f'{{}}{'",
"f'{'",
- "f'x{<'", # See bpo-46762.
- "f'x{>'",
"f'{i='", # See gh-93418.
])
+ self.assertAllRaise(SyntaxError,
+ "f-string: expecting a valid expression after '{'",
+ ["f'{3:{{>10}'",
+ ])
+
# But these are just normal strings.
self.assertEqual(f'{"{"}', '{')
self.assertEqual(f'{"}"}', '}')
@@ -1314,6 +1476,7 @@ def __repr__(self):
self.assertEqual(f'X{x =}Y', 'Xx ='+repr(x)+'Y')
self.assertEqual(f'X{x= }Y', 'Xx= '+repr(x)+'Y')
self.assertEqual(f'X{x = }Y', 'Xx = '+repr(x)+'Y')
+ self.assertEqual(f"sadsd {1 + 1 = :{1 + 1:1d}f}", "sadsd 1 + 1 = 2.000000")
# These next lines contains tabs. Backslash escapes don't
# work in f-strings.
@@ -1335,7 +1498,8 @@ def test_walrus(self):
self.assertEqual(x, 10)
def test_invalid_syntax_error_message(self):
- with self.assertRaisesRegex(SyntaxError, "f-string: invalid syntax"):
+ with self.assertRaisesRegex(SyntaxError,
+ "f-string: expecting '=', or '!', or ':', or '}'"):
compile("f'{a $ b}'", "?", "exec")
def test_with_two_commas_in_format_specifier(self):
@@ -1359,13 +1523,17 @@ def test_with_an_underscore_and_a_comma_in_format_specifier(self):
f'{1:_,}'
def test_syntax_error_for_starred_expressions(self):
- error_msg = re.escape("cannot use starred expression here")
- with self.assertRaisesRegex(SyntaxError, error_msg):
+ with self.assertRaisesRegex(SyntaxError, "can't use starred expression here"):
compile("f'{*a}'", "?", "exec")
- error_msg = re.escape("cannot use double starred expression here")
- with self.assertRaisesRegex(SyntaxError, error_msg):
+ with self.assertRaisesRegex(SyntaxError,
+ "f-string: expecting a valid expression after '{'"):
compile("f'{**a}'", "?", "exec")
+ def test_not_closing_quotes(self):
+ self.assertAllRaise(SyntaxError, "unterminated f-string literal", ['f"', "f'"])
+ self.assertAllRaise(SyntaxError, "unterminated triple-quoted f-string literal",
+ ['f"""', "f'''"])
+
if __name__ == '__main__':
unittest.main()
diff --git a/Lib/test/test_functools.py b/Lib/test/test_functools.py
index 57db96d37ee369..af286052a7d560 100644
--- a/Lib/test/test_functools.py
+++ b/Lib/test/test_functools.py
@@ -2980,7 +2980,7 @@ class MyClass(metaclass=MyMeta):
def test_reuse_different_names(self):
"""Disallow this case because decorated function a would not be cached."""
- with self.assertRaises(RuntimeError) as ctx:
+ with self.assertRaises(TypeError) as ctx:
class ReusedCachedProperty:
@py_functools.cached_property
def a(self):
@@ -2989,7 +2989,7 @@ def a(self):
b = a
self.assertEqual(
- str(ctx.exception.__context__),
+ str(ctx.exception),
str(TypeError("Cannot assign the same cached_property to two different names ('a' and 'b')."))
)
diff --git a/Lib/test/test_gdb.py b/Lib/test/test_gdb.py
index 0f39b8f45714ad..311a864a52387d 100644
--- a/Lib/test/test_gdb.py
+++ b/Lib/test/test_gdb.py
@@ -962,7 +962,7 @@ def test_wrapper_call(self):
cmd = textwrap.dedent('''
class MyList(list):
def __init__(self):
- super().__init__() # wrapper_call()
+ super(*[]).__init__() # wrapper_call()
id("first break point")
l = MyList()
diff --git a/Lib/test/test_generators.py b/Lib/test/test_generators.py
index a5949dec70d176..cc782ea1ee5dff 100644
--- a/Lib/test/test_generators.py
+++ b/Lib/test/test_generators.py
@@ -225,7 +225,22 @@ def f():
gi = f()
self.assertIsNone(gi.gi_frame.f_back)
+ def test_issue103488(self):
+ def gen_raises():
+ yield
+ raise ValueError()
+
+ def loop():
+ try:
+ for _ in gen_raises():
+ if True is False:
+ return
+ except ValueError:
+ pass
+
+ #This should not raise
+ loop()
class ExceptionTest(unittest.TestCase):
# Tests for the issue #23353: check that the currently handled exception
diff --git a/Lib/test/test_grammar.py b/Lib/test/test_grammar.py
index ced9000f75f2e5..ee105a3de17f8a 100644
--- a/Lib/test/test_grammar.py
+++ b/Lib/test/test_grammar.py
@@ -236,12 +236,9 @@ def check(test, error=False):
check(f"[{num}for x in ()]")
check(f"{num}spam", error=True)
+ with self.assertWarnsRegex(SyntaxWarning, r'invalid \w+ literal'):
+ compile(f"{num}is x", "", "eval")
with warnings.catch_warnings():
- warnings.filterwarnings('ignore', '"is" with a literal',
- SyntaxWarning)
- with self.assertWarnsRegex(SyntaxWarning,
- r'invalid \w+ literal'):
- compile(f"{num}is x", "", "eval")
warnings.simplefilter('error', SyntaxWarning)
with self.assertRaisesRegex(SyntaxError,
r'invalid \w+ literal'):
@@ -1467,14 +1464,22 @@ def test_comparison(self):
if 1 < 1 > 1 == 1 >= 1 <= 1 != 1 in 1 not in x is x is not x: pass
def test_comparison_is_literal(self):
- def check(test, msg='"is" with a literal'):
+ def check(test, msg):
self.check_syntax_warning(test, msg)
- check('x is 1')
- check('x is "thing"')
- check('1 is x')
- check('x is y is 1')
- check('x is not 1', '"is not" with a literal')
+ check('x is 1', '"is" with \'int\' literal')
+ check('x is "thing"', '"is" with \'str\' literal')
+ check('1 is x', '"is" with \'int\' literal')
+ check('x is y is 1', '"is" with \'int\' literal')
+ check('x is not 1', '"is not" with \'int\' literal')
+ check('x is not (1, 2)', '"is not" with \'tuple\' literal')
+ check('(1, 2) is not x', '"is not" with \'tuple\' literal')
+
+ check('None is 1', '"is" with \'int\' literal')
+ check('1 is None', '"is" with \'int\' literal')
+
+ check('x == 3 is y', '"is" with \'int\' literal')
+ check('x == "thing" is y', '"is" with \'str\' literal')
with warnings.catch_warnings():
warnings.simplefilter('error', SyntaxWarning)
@@ -1482,6 +1487,10 @@ def check(test, msg='"is" with a literal'):
compile('x is False', '', 'exec')
compile('x is True', '', 'exec')
compile('x is ...', '', 'exec')
+ compile('None is x', '', 'exec')
+ compile('False is x', '', 'exec')
+ compile('True is x', '', 'exec')
+ compile('... is x', '', 'exec')
def test_warn_missed_comma(self):
def check(test):
diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py
index 03e3adba221e57..80abc720c3251a 100644
--- a/Lib/test/test_imp.py
+++ b/Lib/test/test_imp.py
@@ -1,5 +1,4 @@
import gc
-import json
import importlib
import importlib.util
import os
@@ -11,28 +10,15 @@
from test.support import os_helper
from test.support import script_helper
from test.support import warnings_helper
-import textwrap
-import types
import unittest
import warnings
imp = warnings_helper.import_deprecated('imp')
import _imp
-import _testinternalcapi
-try:
- import _xxsubinterpreters as _interpreters
-except ModuleNotFoundError:
- _interpreters = None
OS_PATH_NAME = os.path.__name__
-def requires_subinterpreters(meth):
- """Decorator to skip a test if subinterpreters are not supported."""
- return unittest.skipIf(_interpreters is None,
- 'subinterpreters required')(meth)
-
-
def requires_load_dynamic(meth):
"""Decorator to skip a test if not running under CPython or lacking
imp.load_dynamic()."""
@@ -41,169 +27,6 @@ def requires_load_dynamic(meth):
'imp.load_dynamic() required')(meth)
-class ModuleSnapshot(types.SimpleNamespace):
- """A representation of a module for testing.
-
- Fields:
-
- * id - the module's object ID
- * module - the actual module or an adequate substitute
- * __file__
- * __spec__
- * name
- * origin
- * ns - a copy (dict) of the module's __dict__ (or None)
- * ns_id - the object ID of the module's __dict__
- * cached - the sys.modules[mod.__spec__.name] entry (or None)
- * cached_id - the object ID of the sys.modules entry (or None)
-
- In cases where the value is not available (e.g. due to serialization),
- the value will be None.
- """
- _fields = tuple('id module ns ns_id cached cached_id'.split())
-
- @classmethod
- def from_module(cls, mod):
- name = mod.__spec__.name
- cached = sys.modules.get(name)
- return cls(
- id=id(mod),
- module=mod,
- ns=types.SimpleNamespace(**mod.__dict__),
- ns_id=id(mod.__dict__),
- cached=cached,
- cached_id=id(cached),
- )
-
- SCRIPT = textwrap.dedent('''
- {imports}
-
- name = {name!r}
-
- {prescript}
-
- mod = {name}
-
- {body}
-
- {postscript}
- ''')
- IMPORTS = textwrap.dedent('''
- import sys
- ''').strip()
- SCRIPT_BODY = textwrap.dedent('''
- # Capture the snapshot data.
- cached = sys.modules.get(name)
- snapshot = dict(
- id=id(mod),
- module=dict(
- __file__=mod.__file__,
- __spec__=dict(
- name=mod.__spec__.name,
- origin=mod.__spec__.origin,
- ),
- ),
- ns=None,
- ns_id=id(mod.__dict__),
- cached=None,
- cached_id=id(cached) if cached else None,
- )
- ''').strip()
- CLEANUP_SCRIPT = textwrap.dedent('''
- # Clean up the module.
- sys.modules.pop(name, None)
- ''').strip()
-
- @classmethod
- def build_script(cls, name, *,
- prescript=None,
- import_first=False,
- postscript=None,
- postcleanup=False,
- ):
- if postcleanup is True:
- postcleanup = cls.CLEANUP_SCRIPT
- elif isinstance(postcleanup, str):
- postcleanup = textwrap.dedent(postcleanup).strip()
- postcleanup = cls.CLEANUP_SCRIPT + os.linesep + postcleanup
- else:
- postcleanup = ''
- prescript = textwrap.dedent(prescript).strip() if prescript else ''
- postscript = textwrap.dedent(postscript).strip() if postscript else ''
-
- if postcleanup:
- if postscript:
- postscript = postscript + os.linesep * 2 + postcleanup
- else:
- postscript = postcleanup
-
- if import_first:
- prescript += textwrap.dedent(f'''
-
- # Now import the module.
- assert name not in sys.modules
- import {name}''')
-
- return cls.SCRIPT.format(
- imports=cls.IMPORTS.strip(),
- name=name,
- prescript=prescript.strip(),
- body=cls.SCRIPT_BODY.strip(),
- postscript=postscript,
- )
-
- @classmethod
- def parse(cls, text):
- raw = json.loads(text)
- mod = raw['module']
- mod['__spec__'] = types.SimpleNamespace(**mod['__spec__'])
- raw['module'] = types.SimpleNamespace(**mod)
- return cls(**raw)
-
- @classmethod
- def from_subinterp(cls, name, interpid=None, *, pipe=None, **script_kwds):
- if pipe is not None:
- return cls._from_subinterp(name, interpid, pipe, script_kwds)
- pipe = os.pipe()
- try:
- return cls._from_subinterp(name, interpid, pipe, script_kwds)
- finally:
- r, w = pipe
- os.close(r)
- os.close(w)
-
- @classmethod
- def _from_subinterp(cls, name, interpid, pipe, script_kwargs):
- r, w = pipe
-
- # Build the script.
- postscript = textwrap.dedent(f'''
- # Send the result over the pipe.
- import json
- import os
- os.write({w}, json.dumps(snapshot).encode())
-
- ''')
- _postscript = script_kwargs.get('postscript')
- if _postscript:
- _postscript = textwrap.dedent(_postscript).lstrip()
- postscript += _postscript
- script_kwargs['postscript'] = postscript.strip()
- script = cls.build_script(name, **script_kwargs)
-
- # Run the script.
- if interpid is None:
- ret = support.run_in_subinterp(script)
- if ret != 0:
- raise AssertionError(f'{ret} != 0')
- else:
- _interpreters.run_string(interpid, script)
-
- # Parse the results.
- text = os.read(r, 1000)
- return cls.parse(text.decode())
-
-
class LockTests(unittest.TestCase):
"""Very basic test of import lock functions."""
@@ -620,669 +443,6 @@ def check_get_builtins():
check_get_builtins()
-class TestSinglePhaseSnapshot(ModuleSnapshot):
-
- @classmethod
- def from_module(cls, mod):
- self = super().from_module(mod)
- self.summed = mod.sum(1, 2)
- self.lookedup = mod.look_up_self()
- self.lookedup_id = id(self.lookedup)
- self.state_initialized = mod.state_initialized()
- if hasattr(mod, 'initialized_count'):
- self.init_count = mod.initialized_count()
- return self
-
- SCRIPT_BODY = ModuleSnapshot.SCRIPT_BODY + textwrap.dedent(f'''
- snapshot['module'].update(dict(
- int_const=mod.int_const,
- str_const=mod.str_const,
- _module_initialized=mod._module_initialized,
- ))
- snapshot.update(dict(
- summed=mod.sum(1, 2),
- lookedup_id=id(mod.look_up_self()),
- state_initialized=mod.state_initialized(),
- init_count=mod.initialized_count(),
- has_spam=hasattr(mod, 'spam'),
- spam=getattr(mod, 'spam', None),
- ))
- ''').rstrip()
-
- @classmethod
- def parse(cls, text):
- self = super().parse(text)
- if not self.has_spam:
- del self.spam
- del self.has_spam
- return self
-
-
-@requires_load_dynamic
-class SinglephaseInitTests(unittest.TestCase):
-
- NAME = '_testsinglephase'
-
- @classmethod
- def setUpClass(cls):
- if '-R' in sys.argv or '--huntrleaks' in sys.argv:
- # https://github.com/python/cpython/issues/102251
- raise unittest.SkipTest('unresolved refleaks (see gh-102251)')
- fileobj, filename, _ = imp.find_module(cls.NAME)
- fileobj.close()
- cls.FILE = filename
-
- # Start fresh.
- cls.clean_up()
-
- def tearDown(self):
- # Clean up the module.
- self.clean_up()
-
- @classmethod
- def clean_up(cls):
- name = cls.NAME
- filename = cls.FILE
- if name in sys.modules:
- if hasattr(sys.modules[name], '_clear_globals'):
- assert sys.modules[name].__file__ == filename
- sys.modules[name]._clear_globals()
- del sys.modules[name]
- # Clear all internally cached data for the extension.
- _testinternalcapi.clear_extension(name, filename)
-
- #########################
- # helpers
-
- def add_module_cleanup(self, name):
- def clean_up():
- # Clear all internally cached data for the extension.
- _testinternalcapi.clear_extension(name, self.FILE)
- self.addCleanup(clean_up)
-
- def load(self, name):
- try:
- already_loaded = self.already_loaded
- except AttributeError:
- already_loaded = self.already_loaded = {}
- assert name not in already_loaded
- mod = imp.load_dynamic(name, self.FILE)
- self.assertNotIn(mod, already_loaded.values())
- already_loaded[name] = mod
- return types.SimpleNamespace(
- name=name,
- module=mod,
- snapshot=TestSinglePhaseSnapshot.from_module(mod),
- )
-
- def re_load(self, name, mod):
- assert sys.modules[name] is mod
- assert mod.__dict__ == mod.__dict__
- reloaded = imp.load_dynamic(name, self.FILE)
- return types.SimpleNamespace(
- name=name,
- module=reloaded,
- snapshot=TestSinglePhaseSnapshot.from_module(reloaded),
- )
-
- # subinterpreters
-
- def add_subinterpreter(self):
- interpid = _interpreters.create(isolated=False)
- _interpreters.run_string(interpid, textwrap.dedent('''
- import sys
- import _testinternalcapi
- '''))
- def clean_up():
- _interpreters.run_string(interpid, textwrap.dedent(f'''
- name = {self.NAME!r}
- if name in sys.modules:
- sys.modules[name]._clear_globals()
- _testinternalcapi.clear_extension(name, {self.FILE!r})
- '''))
- _interpreters.destroy(interpid)
- self.addCleanup(clean_up)
- return interpid
-
- def import_in_subinterp(self, interpid=None, *,
- postscript=None,
- postcleanup=False,
- ):
- name = self.NAME
-
- if postcleanup:
- import_ = 'import _testinternalcapi' if interpid is None else ''
- postcleanup = f'''
- {import_}
- mod._clear_globals()
- _testinternalcapi.clear_extension(name, {self.FILE!r})
- '''
-
- try:
- pipe = self._pipe
- except AttributeError:
- r, w = pipe = self._pipe = os.pipe()
- self.addCleanup(os.close, r)
- self.addCleanup(os.close, w)
-
- snapshot = TestSinglePhaseSnapshot.from_subinterp(
- name,
- interpid,
- pipe=pipe,
- import_first=True,
- postscript=postscript,
- postcleanup=postcleanup,
- )
-
- return types.SimpleNamespace(
- name=name,
- module=None,
- snapshot=snapshot,
- )
-
- # checks
-
- def check_common(self, loaded):
- isolated = False
-
- mod = loaded.module
- if not mod:
- # It came from a subinterpreter.
- isolated = True
- mod = loaded.snapshot.module
- # mod.__name__ might not match, but the spec will.
- self.assertEqual(mod.__spec__.name, loaded.name)
- self.assertEqual(mod.__file__, self.FILE)
- self.assertEqual(mod.__spec__.origin, self.FILE)
- if not isolated:
- self.assertTrue(issubclass(mod.error, Exception))
- self.assertEqual(mod.int_const, 1969)
- self.assertEqual(mod.str_const, 'something different')
- self.assertIsInstance(mod._module_initialized, float)
- self.assertGreater(mod._module_initialized, 0)
-
- snap = loaded.snapshot
- self.assertEqual(snap.summed, 3)
- if snap.state_initialized is not None:
- self.assertIsInstance(snap.state_initialized, float)
- self.assertGreater(snap.state_initialized, 0)
- if isolated:
- # The "looked up" module is interpreter-specific
- # (interp->imports.modules_by_index was set for the module).
- self.assertEqual(snap.lookedup_id, snap.id)
- self.assertEqual(snap.cached_id, snap.id)
- with self.assertRaises(AttributeError):
- snap.spam
- else:
- self.assertIs(snap.lookedup, mod)
- self.assertIs(snap.cached, mod)
-
- def check_direct(self, loaded):
- # The module has its own PyModuleDef, with a matching name.
- self.assertEqual(loaded.module.__name__, loaded.name)
- self.assertIs(loaded.snapshot.lookedup, loaded.module)
-
- def check_indirect(self, loaded, orig):
- # The module re-uses another's PyModuleDef, with a different name.
- assert orig is not loaded.module
- assert orig.__name__ != loaded.name
- self.assertNotEqual(loaded.module.__name__, loaded.name)
- self.assertIs(loaded.snapshot.lookedup, loaded.module)
-
- def check_basic(self, loaded, expected_init_count):
- # m_size == -1
- # The module loads fresh the first time and copies m_copy after.
- snap = loaded.snapshot
- self.assertIsNot(snap.state_initialized, None)
- self.assertIsInstance(snap.init_count, int)
- self.assertGreater(snap.init_count, 0)
- self.assertEqual(snap.init_count, expected_init_count)
-
- def check_with_reinit(self, loaded):
- # m_size >= 0
- # The module loads fresh every time.
- pass
-
- def check_fresh(self, loaded):
- """
- The module had not been loaded before (at least since fully reset).
- """
- snap = loaded.snapshot
- # The module's init func was run.
- # A copy of the module's __dict__ was stored in def->m_base.m_copy.
- # The previous m_copy was deleted first.
- # _PyRuntime.imports.extensions was set.
- self.assertEqual(snap.init_count, 1)
- # The global state was initialized.
- # The module attrs were initialized from that state.
- self.assertEqual(snap.module._module_initialized,
- snap.state_initialized)
-
- def check_semi_fresh(self, loaded, base, prev):
- """
- The module had been loaded before and then reset
- (but the module global state wasn't).
- """
- snap = loaded.snapshot
- # The module's init func was run again.
- # A copy of the module's __dict__ was stored in def->m_base.m_copy.
- # The previous m_copy was deleted first.
- # The module globals did not get reset.
- self.assertNotEqual(snap.id, base.snapshot.id)
- self.assertNotEqual(snap.id, prev.snapshot.id)
- self.assertEqual(snap.init_count, prev.snapshot.init_count + 1)
- # The global state was updated.
- # The module attrs were initialized from that state.
- self.assertEqual(snap.module._module_initialized,
- snap.state_initialized)
- self.assertNotEqual(snap.state_initialized,
- base.snapshot.state_initialized)
- self.assertNotEqual(snap.state_initialized,
- prev.snapshot.state_initialized)
-
- def check_copied(self, loaded, base):
- """
- The module had been loaded before and never reset.
- """
- snap = loaded.snapshot
- # The module's init func was not run again.
- # The interpreter copied m_copy, as set by the other interpreter,
- # with objects owned by the other interpreter.
- # The module globals did not get reset.
- self.assertNotEqual(snap.id, base.snapshot.id)
- self.assertEqual(snap.init_count, base.snapshot.init_count)
- # The global state was not updated since the init func did not run.
- # The module attrs were not directly initialized from that state.
- # The state and module attrs still match the previous loading.
- self.assertEqual(snap.module._module_initialized,
- snap.state_initialized)
- self.assertEqual(snap.state_initialized,
- base.snapshot.state_initialized)
-
- #########################
- # the tests
-
- def test_cleared_globals(self):
- loaded = self.load(self.NAME)
- _testsinglephase = loaded.module
- init_before = _testsinglephase.state_initialized()
-
- _testsinglephase._clear_globals()
- init_after = _testsinglephase.state_initialized()
- init_count = _testsinglephase.initialized_count()
-
- self.assertGreater(init_before, 0)
- self.assertEqual(init_after, 0)
- self.assertEqual(init_count, -1)
-
- def test_variants(self):
- # Exercise the most meaningful variants described in Python/import.c.
- self.maxDiff = None
-
- # Check the "basic" module.
-
- name = self.NAME
- expected_init_count = 1
- with self.subTest(name):
- loaded = self.load(name)
-
- self.check_common(loaded)
- self.check_direct(loaded)
- self.check_basic(loaded, expected_init_count)
- basic = loaded.module
-
- # Check its indirect variants.
-
- name = f'{self.NAME}_basic_wrapper'
- self.add_module_cleanup(name)
- expected_init_count += 1
- with self.subTest(name):
- loaded = self.load(name)
-
- self.check_common(loaded)
- self.check_indirect(loaded, basic)
- self.check_basic(loaded, expected_init_count)
-
- # Currently PyState_AddModule() always replaces the cached module.
- self.assertIs(basic.look_up_self(), loaded.module)
- self.assertEqual(basic.initialized_count(), expected_init_count)
-
- # The cached module shouldn't change after this point.
- basic_lookedup = loaded.module
-
- # Check its direct variant.
-
- name = f'{self.NAME}_basic_copy'
- self.add_module_cleanup(name)
- expected_init_count += 1
- with self.subTest(name):
- loaded = self.load(name)
-
- self.check_common(loaded)
- self.check_direct(loaded)
- self.check_basic(loaded, expected_init_count)
-
- # This should change the cached module for _testsinglephase.
- self.assertIs(basic.look_up_self(), basic_lookedup)
- self.assertEqual(basic.initialized_count(), expected_init_count)
-
- # Check the non-basic variant that has no state.
-
- name = f'{self.NAME}_with_reinit'
- self.add_module_cleanup(name)
- with self.subTest(name):
- loaded = self.load(name)
-
- self.check_common(loaded)
- self.assertIs(loaded.snapshot.state_initialized, None)
- self.check_direct(loaded)
- self.check_with_reinit(loaded)
-
- # This should change the cached module for _testsinglephase.
- self.assertIs(basic.look_up_self(), basic_lookedup)
- self.assertEqual(basic.initialized_count(), expected_init_count)
-
- # Check the basic variant that has state.
-
- name = f'{self.NAME}_with_state'
- self.add_module_cleanup(name)
- with self.subTest(name):
- loaded = self.load(name)
-
- self.check_common(loaded)
- self.assertIsNot(loaded.snapshot.state_initialized, None)
- self.check_direct(loaded)
- self.check_with_reinit(loaded)
-
- # This should change the cached module for _testsinglephase.
- self.assertIs(basic.look_up_self(), basic_lookedup)
- self.assertEqual(basic.initialized_count(), expected_init_count)
-
- def test_basic_reloaded(self):
- # m_copy is copied into the existing module object.
- # Global state is not changed.
- self.maxDiff = None
-
- for name in [
- self.NAME, # the "basic" module
- f'{self.NAME}_basic_wrapper', # the indirect variant
- f'{self.NAME}_basic_copy', # the direct variant
- ]:
- self.add_module_cleanup(name)
- with self.subTest(name):
- loaded = self.load(name)
- reloaded = self.re_load(name, loaded.module)
-
- self.check_common(loaded)
- self.check_common(reloaded)
-
- # Make sure the original __dict__ did not get replaced.
- self.assertEqual(id(loaded.module.__dict__),
- loaded.snapshot.ns_id)
- self.assertEqual(loaded.snapshot.ns.__dict__,
- loaded.module.__dict__)
-
- self.assertEqual(reloaded.module.__spec__.name, reloaded.name)
- self.assertEqual(reloaded.module.__name__,
- reloaded.snapshot.ns.__name__)
-
- self.assertIs(reloaded.module, loaded.module)
- self.assertIs(reloaded.module.__dict__, loaded.module.__dict__)
- # It only happens to be the same but that's good enough here.
- # We really just want to verify that the re-loaded attrs
- # didn't change.
- self.assertIs(reloaded.snapshot.lookedup,
- loaded.snapshot.lookedup)
- self.assertEqual(reloaded.snapshot.state_initialized,
- loaded.snapshot.state_initialized)
- self.assertEqual(reloaded.snapshot.init_count,
- loaded.snapshot.init_count)
-
- self.assertIs(reloaded.snapshot.cached, reloaded.module)
-
- def test_with_reinit_reloaded(self):
- # The module's m_init func is run again.
- self.maxDiff = None
-
- # Keep a reference around.
- basic = self.load(self.NAME)
-
- for name in [
- f'{self.NAME}_with_reinit', # m_size == 0
- f'{self.NAME}_with_state', # m_size > 0
- ]:
- self.add_module_cleanup(name)
- with self.subTest(name):
- loaded = self.load(name)
- reloaded = self.re_load(name, loaded.module)
-
- self.check_common(loaded)
- self.check_common(reloaded)
-
- # Make sure the original __dict__ did not get replaced.
- self.assertEqual(id(loaded.module.__dict__),
- loaded.snapshot.ns_id)
- self.assertEqual(loaded.snapshot.ns.__dict__,
- loaded.module.__dict__)
-
- self.assertEqual(reloaded.module.__spec__.name, reloaded.name)
- self.assertEqual(reloaded.module.__name__,
- reloaded.snapshot.ns.__name__)
-
- self.assertIsNot(reloaded.module, loaded.module)
- self.assertNotEqual(reloaded.module.__dict__,
- loaded.module.__dict__)
- self.assertIs(reloaded.snapshot.lookedup, reloaded.module)
- if loaded.snapshot.state_initialized is None:
- self.assertIs(reloaded.snapshot.state_initialized, None)
- else:
- self.assertGreater(reloaded.snapshot.state_initialized,
- loaded.snapshot.state_initialized)
-
- self.assertIs(reloaded.snapshot.cached, reloaded.module)
-
- # Currently, for every single-phrase init module loaded
- # in multiple interpreters, those interpreters share a
- # PyModuleDef for that object, which can be a problem.
- # Also, we test with a single-phase module that has global state,
- # which is shared by all interpreters.
-
- @requires_subinterpreters
- def test_basic_multiple_interpreters_main_no_reset(self):
- # without resetting; already loaded in main interpreter
-
- # At this point:
- # * alive in 0 interpreters
- # * module def may or may not be loaded already
- # * module def not in _PyRuntime.imports.extensions
- # * mod init func has not run yet (since reset, at least)
- # * m_copy not set (hasn't been loaded yet or already cleared)
- # * module's global state has not been initialized yet
- # (or already cleared)
-
- main_loaded = self.load(self.NAME)
- _testsinglephase = main_loaded.module
- # Attrs set after loading are not in m_copy.
- _testsinglephase.spam = 'spam, spam, spam, spam, eggs, and spam'
-
- self.check_common(main_loaded)
- self.check_fresh(main_loaded)
-
- interpid1 = self.add_subinterpreter()
- interpid2 = self.add_subinterpreter()
-
- # At this point:
- # * alive in 1 interpreter (main)
- # * module def in _PyRuntime.imports.extensions
- # * mod init func ran for the first time (since reset, at least)
- # * m_copy was copied from the main interpreter (was NULL)
- # * module's global state was initialized
-
- # Use an interpreter that gets destroyed right away.
- loaded = self.import_in_subinterp()
- self.check_common(loaded)
- self.check_copied(loaded, main_loaded)
-
- # At this point:
- # * alive in 1 interpreter (main)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy is NULL (claered when the interpreter was destroyed)
- # (was from main interpreter)
- # * module's global state was updated, not reset
-
- # Use a subinterpreter that sticks around.
- loaded = self.import_in_subinterp(interpid1)
- self.check_common(loaded)
- self.check_copied(loaded, main_loaded)
-
- # At this point:
- # * alive in 2 interpreters (main, interp1)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp1
- # * module's global state was updated, not reset
-
- # Use a subinterpreter while the previous one is still alive.
- loaded = self.import_in_subinterp(interpid2)
- self.check_common(loaded)
- self.check_copied(loaded, main_loaded)
-
- # At this point:
- # * alive in 3 interpreters (main, interp1, interp2)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp2 (was from interp1)
- # * module's global state was updated, not reset
-
- @requires_subinterpreters
- def test_basic_multiple_interpreters_deleted_no_reset(self):
- # without resetting; already loaded in a deleted interpreter
-
- # At this point:
- # * alive in 0 interpreters
- # * module def may or may not be loaded already
- # * module def not in _PyRuntime.imports.extensions
- # * mod init func has not run yet (since reset, at least)
- # * m_copy not set (hasn't been loaded yet or already cleared)
- # * module's global state has not been initialized yet
- # (or already cleared)
-
- interpid1 = self.add_subinterpreter()
- interpid2 = self.add_subinterpreter()
-
- # First, load in the main interpreter but then completely clear it.
- loaded_main = self.load(self.NAME)
- loaded_main.module._clear_globals()
- _testinternalcapi.clear_extension(self.NAME, self.FILE)
-
- # At this point:
- # * alive in 0 interpreters
- # * module def loaded already
- # * module def was in _PyRuntime.imports.extensions, but cleared
- # * mod init func ran for the first time (since reset, at least)
- # * m_copy was set, but cleared (was NULL)
- # * module's global state was initialized but cleared
-
- # Start with an interpreter that gets destroyed right away.
- base = self.import_in_subinterp(postscript='''
- # Attrs set after loading are not in m_copy.
- mod.spam = 'spam, spam, mash, spam, eggs, and spam'
- ''')
- self.check_common(base)
- self.check_fresh(base)
-
- # At this point:
- # * alive in 0 interpreters
- # * module def in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy is NULL (claered when the interpreter was destroyed)
- # * module's global state was initialized, not reset
-
- # Use a subinterpreter that sticks around.
- loaded_interp1 = self.import_in_subinterp(interpid1)
- self.check_common(loaded_interp1)
- self.check_semi_fresh(loaded_interp1, loaded_main, base)
-
- # At this point:
- # * alive in 1 interpreter (interp1)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp1 (was NULL)
- # * module's global state was updated, not reset
-
- # Use a subinterpreter while the previous one is still alive.
- loaded_interp2 = self.import_in_subinterp(interpid2)
- self.check_common(loaded_interp2)
- self.check_copied(loaded_interp2, loaded_interp1)
-
- # At this point:
- # * alive in 2 interpreters (interp1, interp2)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp2 (was from interp1)
- # * module's global state was updated, not reset
-
- @requires_subinterpreters
- @requires_load_dynamic
- def test_basic_multiple_interpreters_reset_each(self):
- # resetting between each interpreter
-
- # At this point:
- # * alive in 0 interpreters
- # * module def may or may not be loaded already
- # * module def not in _PyRuntime.imports.extensions
- # * mod init func has not run yet (since reset, at least)
- # * m_copy not set (hasn't been loaded yet or already cleared)
- # * module's global state has not been initialized yet
- # (or already cleared)
-
- interpid1 = self.add_subinterpreter()
- interpid2 = self.add_subinterpreter()
-
- # Use an interpreter that gets destroyed right away.
- loaded = self.import_in_subinterp(
- postscript='''
- # Attrs set after loading are not in m_copy.
- mod.spam = 'spam, spam, mash, spam, eggs, and spam'
- ''',
- postcleanup=True,
- )
- self.check_common(loaded)
- self.check_fresh(loaded)
-
- # At this point:
- # * alive in 0 interpreters
- # * module def in _PyRuntime.imports.extensions
- # * mod init func ran for the first time (since reset, at least)
- # * m_copy is NULL (claered when the interpreter was destroyed)
- # * module's global state was initialized, not reset
-
- # Use a subinterpreter that sticks around.
- loaded = self.import_in_subinterp(interpid1, postcleanup=True)
- self.check_common(loaded)
- self.check_fresh(loaded)
-
- # At this point:
- # * alive in 1 interpreter (interp1)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp1 (was NULL)
- # * module's global state was initialized, not reset
-
- # Use a subinterpreter while the previous one is still alive.
- loaded = self.import_in_subinterp(interpid2, postcleanup=True)
- self.check_common(loaded)
- self.check_fresh(loaded)
-
- # At this point:
- # * alive in 2 interpreters (interp2, interp2)
- # * module def still in _PyRuntime.imports.extensions
- # * mod init func ran again
- # * m_copy was copied from interp2 (was from interp1)
- # * module's global state was initialized, not reset
-
-
class ReloadTests(unittest.TestCase):
"""Very basic tests to make sure that imp.reload() operates just like
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index 3ef07203c46c7e..41dfdaabe24664 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -2,6 +2,7 @@
import contextlib
import errno
import glob
+import json
import importlib.util
from importlib._bootstrap_external import _get_sourcefile
from importlib.machinery import (
@@ -18,13 +19,15 @@
import textwrap
import threading
import time
+import types
import unittest
from unittest import mock
+import _testinternalcapi
from test.support import os_helper
from test.support import (
STDLIB_DIR, swap_attr, swap_item, cpython_only, is_emscripten,
- is_wasi, run_in_subinterp_with_config)
+ is_wasi, run_in_subinterp, run_in_subinterp_with_config)
from test.support.import_helper import (
forget, make_legacy_pyc, unlink, unload, DirsOnSysPath, CleanImport)
from test.support.os_helper import (
@@ -41,6 +44,10 @@
import _testmultiphase
except ImportError:
_testmultiphase = None
+try:
+ import _xxsubinterpreters as _interpreters
+except ModuleNotFoundError:
+ _interpreters = None
skip_if_dont_write_bytecode = unittest.skipIf(
@@ -120,6 +127,182 @@ def _ready_to_import(name=None, source=""):
del sys.modules[name]
+def requires_subinterpreters(meth):
+ """Decorator to skip a test if subinterpreters are not supported."""
+ return unittest.skipIf(_interpreters is None,
+ 'subinterpreters required')(meth)
+
+
+def requires_singlephase_init(meth):
+ """Decorator to skip if single-phase init modules are not supported."""
+ meth = cpython_only(meth)
+ return unittest.skipIf(_testsinglephase is None,
+ 'test requires _testsinglephase module')(meth)
+
+
+class ModuleSnapshot(types.SimpleNamespace):
+ """A representation of a module for testing.
+
+ Fields:
+
+ * id - the module's object ID
+ * module - the actual module or an adequate substitute
+ * __file__
+ * __spec__
+ * name
+ * origin
+ * ns - a copy (dict) of the module's __dict__ (or None)
+ * ns_id - the object ID of the module's __dict__
+ * cached - the sys.modules[mod.__spec__.name] entry (or None)
+ * cached_id - the object ID of the sys.modules entry (or None)
+
+ In cases where the value is not available (e.g. due to serialization),
+ the value will be None.
+ """
+ _fields = tuple('id module ns ns_id cached cached_id'.split())
+
+ @classmethod
+ def from_module(cls, mod):
+ name = mod.__spec__.name
+ cached = sys.modules.get(name)
+ return cls(
+ id=id(mod),
+ module=mod,
+ ns=types.SimpleNamespace(**mod.__dict__),
+ ns_id=id(mod.__dict__),
+ cached=cached,
+ cached_id=id(cached),
+ )
+
+ SCRIPT = textwrap.dedent('''
+ {imports}
+
+ name = {name!r}
+
+ {prescript}
+
+ mod = {name}
+
+ {body}
+
+ {postscript}
+ ''')
+ IMPORTS = textwrap.dedent('''
+ import sys
+ ''').strip()
+ SCRIPT_BODY = textwrap.dedent('''
+ # Capture the snapshot data.
+ cached = sys.modules.get(name)
+ snapshot = dict(
+ id=id(mod),
+ module=dict(
+ __file__=mod.__file__,
+ __spec__=dict(
+ name=mod.__spec__.name,
+ origin=mod.__spec__.origin,
+ ),
+ ),
+ ns=None,
+ ns_id=id(mod.__dict__),
+ cached=None,
+ cached_id=id(cached) if cached else None,
+ )
+ ''').strip()
+ CLEANUP_SCRIPT = textwrap.dedent('''
+ # Clean up the module.
+ sys.modules.pop(name, None)
+ ''').strip()
+
+ @classmethod
+ def build_script(cls, name, *,
+ prescript=None,
+ import_first=False,
+ postscript=None,
+ postcleanup=False,
+ ):
+ if postcleanup is True:
+ postcleanup = cls.CLEANUP_SCRIPT
+ elif isinstance(postcleanup, str):
+ postcleanup = textwrap.dedent(postcleanup).strip()
+ postcleanup = cls.CLEANUP_SCRIPT + os.linesep + postcleanup
+ else:
+ postcleanup = ''
+ prescript = textwrap.dedent(prescript).strip() if prescript else ''
+ postscript = textwrap.dedent(postscript).strip() if postscript else ''
+
+ if postcleanup:
+ if postscript:
+ postscript = postscript + os.linesep * 2 + postcleanup
+ else:
+ postscript = postcleanup
+
+ if import_first:
+ prescript += textwrap.dedent(f'''
+
+ # Now import the module.
+ assert name not in sys.modules
+ import {name}''')
+
+ return cls.SCRIPT.format(
+ imports=cls.IMPORTS.strip(),
+ name=name,
+ prescript=prescript.strip(),
+ body=cls.SCRIPT_BODY.strip(),
+ postscript=postscript,
+ )
+
+ @classmethod
+ def parse(cls, text):
+ raw = json.loads(text)
+ mod = raw['module']
+ mod['__spec__'] = types.SimpleNamespace(**mod['__spec__'])
+ raw['module'] = types.SimpleNamespace(**mod)
+ return cls(**raw)
+
+ @classmethod
+ def from_subinterp(cls, name, interpid=None, *, pipe=None, **script_kwds):
+ if pipe is not None:
+ return cls._from_subinterp(name, interpid, pipe, script_kwds)
+ pipe = os.pipe()
+ try:
+ return cls._from_subinterp(name, interpid, pipe, script_kwds)
+ finally:
+ r, w = pipe
+ os.close(r)
+ os.close(w)
+
+ @classmethod
+ def _from_subinterp(cls, name, interpid, pipe, script_kwargs):
+ r, w = pipe
+
+ # Build the script.
+ postscript = textwrap.dedent(f'''
+ # Send the result over the pipe.
+ import json
+ import os
+ os.write({w}, json.dumps(snapshot).encode())
+
+ ''')
+ _postscript = script_kwargs.get('postscript')
+ if _postscript:
+ _postscript = textwrap.dedent(_postscript).lstrip()
+ postscript += _postscript
+ script_kwargs['postscript'] = postscript.strip()
+ script = cls.build_script(name, **script_kwargs)
+
+ # Run the script.
+ if interpid is None:
+ ret = run_in_subinterp(script)
+ if ret != 0:
+ raise AssertionError(f'{ret} != 0')
+ else:
+ _interpreters.run_string(interpid, script)
+
+ # Parse the results.
+ text = os.read(r, 1000)
+ return cls.parse(text.decode())
+
+
class ImportTests(unittest.TestCase):
def setUp(self):
@@ -1453,7 +1636,12 @@ class SubinterpImportTests(unittest.TestCase):
allow_exec=False,
allow_threads=True,
allow_daemon_threads=False,
+ # Isolation-related config values aren't included here.
+ )
+ ISOLATED = dict(
+ use_main_obmalloc=False,
)
+ NOT_ISOLATED = {k: not v for k, v in ISOLATED.items()}
@unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
def pipe(self):
@@ -1486,6 +1674,7 @@ def import_script(self, name, fd, check_override=None):
def run_here(self, name, *,
check_singlephase_setting=False,
check_singlephase_override=None,
+ isolated=False,
):
"""
Try importing the named module in a subinterpreter.
@@ -1506,6 +1695,7 @@ def run_here(self, name, *,
kwargs = dict(
**self.RUN_KWARGS,
+ **(self.ISOLATED if isolated else self.NOT_ISOLATED),
check_multi_interp_extensions=check_singlephase_setting,
)
@@ -1516,33 +1706,36 @@ def run_here(self, name, *,
self.assertEqual(ret, 0)
return os.read(r, 100)
- def check_compatible_here(self, name, *, strict=False):
+ def check_compatible_here(self, name, *, strict=False, isolated=False):
# Verify that the named module may be imported in a subinterpreter.
# (See run_here() for more info.)
out = self.run_here(name,
check_singlephase_setting=strict,
+ isolated=isolated,
)
self.assertEqual(out, b'okay')
- def check_incompatible_here(self, name):
+ def check_incompatible_here(self, name, *, isolated=False):
# Differences from check_compatible_here():
# * verify that import fails
# * "strict" is always True
out = self.run_here(name,
check_singlephase_setting=True,
+ isolated=isolated,
)
self.assertEqual(
out.decode('utf-8'),
f'ImportError: module {name} does not support loading in subinterpreters',
)
- def check_compatible_fresh(self, name, *, strict=False):
+ def check_compatible_fresh(self, name, *, strict=False, isolated=False):
# Differences from check_compatible_here():
# * subinterpreter in a new process
# * module has never been imported before in that process
# * this tests importing the module for the first time
kwargs = dict(
**self.RUN_KWARGS,
+ **(self.ISOLATED if isolated else self.NOT_ISOLATED),
check_multi_interp_extensions=strict,
)
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
@@ -1560,12 +1753,13 @@ def check_compatible_fresh(self, name, *, strict=False):
self.assertEqual(err, b'')
self.assertEqual(out, b'okay')
- def check_incompatible_fresh(self, name):
+ def check_incompatible_fresh(self, name, *, isolated=False):
# Differences from check_compatible_fresh():
# * verify that import fails
# * "strict" is always True
kwargs = dict(
**self.RUN_KWARGS,
+ **(self.ISOLATED if isolated else self.NOT_ISOLATED),
check_multi_interp_extensions=True,
)
_, out, err = script_helper.assert_python_ok('-c', textwrap.dedent(f'''
@@ -1604,7 +1798,7 @@ def test_frozen_compat(self):
with self.subTest(f'{module}: strict, not fresh'):
self.check_compatible_here(module, strict=True)
- @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
+ @requires_singlephase_init
def test_single_init_extension_compat(self):
module = '_testsinglephase'
require_extension(module)
@@ -1636,7 +1830,7 @@ def test_python_compat(self):
with self.subTest(f'{module}: strict, fresh'):
self.check_compatible_fresh(module, strict=True)
- @unittest.skipIf(_testsinglephase is None, "test requires _testsinglephase module")
+ @requires_singlephase_init
def test_singlephase_check_with_setting_and_override(self):
module = '_testsinglephase'
require_extension(module)
@@ -1671,6 +1865,693 @@ def check_incompatible(setting, override):
with self.subTest('config: check disabled; override: disabled'):
check_compatible(False, -1)
+ def test_isolated_config(self):
+ module = 'threading'
+ require_pure_python(module)
+ with self.subTest(f'{module}: strict, not fresh'):
+ self.check_compatible_here(module, strict=True, isolated=True)
+ with self.subTest(f'{module}: strict, fresh'):
+ self.check_compatible_fresh(module, strict=True, isolated=True)
+
+
+class TestSinglePhaseSnapshot(ModuleSnapshot):
+
+ @classmethod
+ def from_module(cls, mod):
+ self = super().from_module(mod)
+ self.summed = mod.sum(1, 2)
+ self.lookedup = mod.look_up_self()
+ self.lookedup_id = id(self.lookedup)
+ self.state_initialized = mod.state_initialized()
+ if hasattr(mod, 'initialized_count'):
+ self.init_count = mod.initialized_count()
+ return self
+
+ SCRIPT_BODY = ModuleSnapshot.SCRIPT_BODY + textwrap.dedent('''
+ snapshot['module'].update(dict(
+ int_const=mod.int_const,
+ str_const=mod.str_const,
+ _module_initialized=mod._module_initialized,
+ ))
+ snapshot.update(dict(
+ summed=mod.sum(1, 2),
+ lookedup_id=id(mod.look_up_self()),
+ state_initialized=mod.state_initialized(),
+ init_count=mod.initialized_count(),
+ has_spam=hasattr(mod, 'spam'),
+ spam=getattr(mod, 'spam', None),
+ ))
+ ''').rstrip()
+
+ @classmethod
+ def parse(cls, text):
+ self = super().parse(text)
+ if not self.has_spam:
+ del self.spam
+ del self.has_spam
+ return self
+
+
+@requires_singlephase_init
+class SinglephaseInitTests(unittest.TestCase):
+
+ NAME = '_testsinglephase'
+
+ @classmethod
+ def setUpClass(cls):
+ if '-R' in sys.argv or '--huntrleaks' in sys.argv:
+ # https://github.com/python/cpython/issues/102251
+ raise unittest.SkipTest('unresolved refleaks (see gh-102251)')
+
+ spec = importlib.util.find_spec(cls.NAME)
+ from importlib.machinery import ExtensionFileLoader
+ cls.FILE = spec.origin
+ cls.LOADER = type(spec.loader)
+ assert cls.LOADER is ExtensionFileLoader
+
+ # Start fresh.
+ cls.clean_up()
+
+ def tearDown(self):
+ # Clean up the module.
+ self.clean_up()
+
+ @classmethod
+ def clean_up(cls):
+ name = cls.NAME
+ filename = cls.FILE
+ if name in sys.modules:
+ if hasattr(sys.modules[name], '_clear_globals'):
+ assert sys.modules[name].__file__ == filename
+ sys.modules[name]._clear_globals()
+ del sys.modules[name]
+ # Clear all internally cached data for the extension.
+ _testinternalcapi.clear_extension(name, filename)
+
+ #########################
+ # helpers
+
+ def add_module_cleanup(self, name):
+ def clean_up():
+ # Clear all internally cached data for the extension.
+ _testinternalcapi.clear_extension(name, self.FILE)
+ self.addCleanup(clean_up)
+
+ def _load_dynamic(self, name, path):
+ """
+ Load an extension module.
+ """
+ # This is essentially copied from the old imp module.
+ from importlib._bootstrap import _load
+ loader = self.LOADER(name, path)
+
+ # Issue bpo-24748: Skip the sys.modules check in _load_module_shim;
+ # always load new extension.
+ spec = importlib.util.spec_from_file_location(name, path,
+ loader=loader)
+ return _load(spec)
+
+ def load(self, name):
+ try:
+ already_loaded = self.already_loaded
+ except AttributeError:
+ already_loaded = self.already_loaded = {}
+ assert name not in already_loaded
+ mod = self._load_dynamic(name, self.FILE)
+ self.assertNotIn(mod, already_loaded.values())
+ already_loaded[name] = mod
+ return types.SimpleNamespace(
+ name=name,
+ module=mod,
+ snapshot=TestSinglePhaseSnapshot.from_module(mod),
+ )
+
+ def re_load(self, name, mod):
+ assert sys.modules[name] is mod
+ assert mod.__dict__ == mod.__dict__
+ reloaded = self._load_dynamic(name, self.FILE)
+ return types.SimpleNamespace(
+ name=name,
+ module=reloaded,
+ snapshot=TestSinglePhaseSnapshot.from_module(reloaded),
+ )
+
+ # subinterpreters
+
+ def add_subinterpreter(self):
+ interpid = _interpreters.create(isolated=False)
+ _interpreters.run_string(interpid, textwrap.dedent('''
+ import sys
+ import _testinternalcapi
+ '''))
+ def clean_up():
+ _interpreters.run_string(interpid, textwrap.dedent(f'''
+ name = {self.NAME!r}
+ if name in sys.modules:
+ sys.modules[name]._clear_globals()
+ _testinternalcapi.clear_extension(name, {self.FILE!r})
+ '''))
+ _interpreters.destroy(interpid)
+ self.addCleanup(clean_up)
+ return interpid
+
+ def import_in_subinterp(self, interpid=None, *,
+ postscript=None,
+ postcleanup=False,
+ ):
+ name = self.NAME
+
+ if postcleanup:
+ import_ = 'import _testinternalcapi' if interpid is None else ''
+ postcleanup = f'''
+ {import_}
+ mod._clear_globals()
+ _testinternalcapi.clear_extension(name, {self.FILE!r})
+ '''
+
+ try:
+ pipe = self._pipe
+ except AttributeError:
+ r, w = pipe = self._pipe = os.pipe()
+ self.addCleanup(os.close, r)
+ self.addCleanup(os.close, w)
+
+ snapshot = TestSinglePhaseSnapshot.from_subinterp(
+ name,
+ interpid,
+ pipe=pipe,
+ import_first=True,
+ postscript=postscript,
+ postcleanup=postcleanup,
+ )
+
+ return types.SimpleNamespace(
+ name=name,
+ module=None,
+ snapshot=snapshot,
+ )
+
+ # checks
+
+ def check_common(self, loaded):
+ isolated = False
+
+ mod = loaded.module
+ if not mod:
+ # It came from a subinterpreter.
+ isolated = True
+ mod = loaded.snapshot.module
+ # mod.__name__ might not match, but the spec will.
+ self.assertEqual(mod.__spec__.name, loaded.name)
+ self.assertEqual(mod.__file__, self.FILE)
+ self.assertEqual(mod.__spec__.origin, self.FILE)
+ if not isolated:
+ self.assertTrue(issubclass(mod.error, Exception))
+ self.assertEqual(mod.int_const, 1969)
+ self.assertEqual(mod.str_const, 'something different')
+ self.assertIsInstance(mod._module_initialized, float)
+ self.assertGreater(mod._module_initialized, 0)
+
+ snap = loaded.snapshot
+ self.assertEqual(snap.summed, 3)
+ if snap.state_initialized is not None:
+ self.assertIsInstance(snap.state_initialized, float)
+ self.assertGreater(snap.state_initialized, 0)
+ if isolated:
+ # The "looked up" module is interpreter-specific
+ # (interp->imports.modules_by_index was set for the module).
+ self.assertEqual(snap.lookedup_id, snap.id)
+ self.assertEqual(snap.cached_id, snap.id)
+ with self.assertRaises(AttributeError):
+ snap.spam
+ else:
+ self.assertIs(snap.lookedup, mod)
+ self.assertIs(snap.cached, mod)
+
+ def check_direct(self, loaded):
+ # The module has its own PyModuleDef, with a matching name.
+ self.assertEqual(loaded.module.__name__, loaded.name)
+ self.assertIs(loaded.snapshot.lookedup, loaded.module)
+
+ def check_indirect(self, loaded, orig):
+ # The module re-uses another's PyModuleDef, with a different name.
+ assert orig is not loaded.module
+ assert orig.__name__ != loaded.name
+ self.assertNotEqual(loaded.module.__name__, loaded.name)
+ self.assertIs(loaded.snapshot.lookedup, loaded.module)
+
+ def check_basic(self, loaded, expected_init_count):
+ # m_size == -1
+ # The module loads fresh the first time and copies m_copy after.
+ snap = loaded.snapshot
+ self.assertIsNot(snap.state_initialized, None)
+ self.assertIsInstance(snap.init_count, int)
+ self.assertGreater(snap.init_count, 0)
+ self.assertEqual(snap.init_count, expected_init_count)
+
+ def check_with_reinit(self, loaded):
+ # m_size >= 0
+ # The module loads fresh every time.
+ pass
+
+ def check_fresh(self, loaded):
+ """
+ The module had not been loaded before (at least since fully reset).
+ """
+ snap = loaded.snapshot
+ # The module's init func was run.
+ # A copy of the module's __dict__ was stored in def->m_base.m_copy.
+ # The previous m_copy was deleted first.
+ # _PyRuntime.imports.extensions was set.
+ self.assertEqual(snap.init_count, 1)
+ # The global state was initialized.
+ # The module attrs were initialized from that state.
+ self.assertEqual(snap.module._module_initialized,
+ snap.state_initialized)
+
+ def check_semi_fresh(self, loaded, base, prev):
+ """
+ The module had been loaded before and then reset
+ (but the module global state wasn't).
+ """
+ snap = loaded.snapshot
+ # The module's init func was run again.
+ # A copy of the module's __dict__ was stored in def->m_base.m_copy.
+ # The previous m_copy was deleted first.
+ # The module globals did not get reset.
+ self.assertNotEqual(snap.id, base.snapshot.id)
+ self.assertNotEqual(snap.id, prev.snapshot.id)
+ self.assertEqual(snap.init_count, prev.snapshot.init_count + 1)
+ # The global state was updated.
+ # The module attrs were initialized from that state.
+ self.assertEqual(snap.module._module_initialized,
+ snap.state_initialized)
+ self.assertNotEqual(snap.state_initialized,
+ base.snapshot.state_initialized)
+ self.assertNotEqual(snap.state_initialized,
+ prev.snapshot.state_initialized)
+
+ def check_copied(self, loaded, base):
+ """
+ The module had been loaded before and never reset.
+ """
+ snap = loaded.snapshot
+ # The module's init func was not run again.
+ # The interpreter copied m_copy, as set by the other interpreter,
+ # with objects owned by the other interpreter.
+ # The module globals did not get reset.
+ self.assertNotEqual(snap.id, base.snapshot.id)
+ self.assertEqual(snap.init_count, base.snapshot.init_count)
+ # The global state was not updated since the init func did not run.
+ # The module attrs were not directly initialized from that state.
+ # The state and module attrs still match the previous loading.
+ self.assertEqual(snap.module._module_initialized,
+ snap.state_initialized)
+ self.assertEqual(snap.state_initialized,
+ base.snapshot.state_initialized)
+
+ #########################
+ # the tests
+
+ def test_cleared_globals(self):
+ loaded = self.load(self.NAME)
+ _testsinglephase = loaded.module
+ init_before = _testsinglephase.state_initialized()
+
+ _testsinglephase._clear_globals()
+ init_after = _testsinglephase.state_initialized()
+ init_count = _testsinglephase.initialized_count()
+
+ self.assertGreater(init_before, 0)
+ self.assertEqual(init_after, 0)
+ self.assertEqual(init_count, -1)
+
+ def test_variants(self):
+ # Exercise the most meaningful variants described in Python/import.c.
+ self.maxDiff = None
+
+ # Check the "basic" module.
+
+ name = self.NAME
+ expected_init_count = 1
+ with self.subTest(name):
+ loaded = self.load(name)
+
+ self.check_common(loaded)
+ self.check_direct(loaded)
+ self.check_basic(loaded, expected_init_count)
+ basic = loaded.module
+
+ # Check its indirect variants.
+
+ name = f'{self.NAME}_basic_wrapper'
+ self.add_module_cleanup(name)
+ expected_init_count += 1
+ with self.subTest(name):
+ loaded = self.load(name)
+
+ self.check_common(loaded)
+ self.check_indirect(loaded, basic)
+ self.check_basic(loaded, expected_init_count)
+
+ # Currently PyState_AddModule() always replaces the cached module.
+ self.assertIs(basic.look_up_self(), loaded.module)
+ self.assertEqual(basic.initialized_count(), expected_init_count)
+
+ # The cached module shouldn't change after this point.
+ basic_lookedup = loaded.module
+
+ # Check its direct variant.
+
+ name = f'{self.NAME}_basic_copy'
+ self.add_module_cleanup(name)
+ expected_init_count += 1
+ with self.subTest(name):
+ loaded = self.load(name)
+
+ self.check_common(loaded)
+ self.check_direct(loaded)
+ self.check_basic(loaded, expected_init_count)
+
+ # This should change the cached module for _testsinglephase.
+ self.assertIs(basic.look_up_self(), basic_lookedup)
+ self.assertEqual(basic.initialized_count(), expected_init_count)
+
+ # Check the non-basic variant that has no state.
+
+ name = f'{self.NAME}_with_reinit'
+ self.add_module_cleanup(name)
+ with self.subTest(name):
+ loaded = self.load(name)
+
+ self.check_common(loaded)
+ self.assertIs(loaded.snapshot.state_initialized, None)
+ self.check_direct(loaded)
+ self.check_with_reinit(loaded)
+
+ # This should change the cached module for _testsinglephase.
+ self.assertIs(basic.look_up_self(), basic_lookedup)
+ self.assertEqual(basic.initialized_count(), expected_init_count)
+
+ # Check the basic variant that has state.
+
+ name = f'{self.NAME}_with_state'
+ self.add_module_cleanup(name)
+ with self.subTest(name):
+ loaded = self.load(name)
+
+ self.check_common(loaded)
+ self.assertIsNot(loaded.snapshot.state_initialized, None)
+ self.check_direct(loaded)
+ self.check_with_reinit(loaded)
+
+ # This should change the cached module for _testsinglephase.
+ self.assertIs(basic.look_up_self(), basic_lookedup)
+ self.assertEqual(basic.initialized_count(), expected_init_count)
+
+ def test_basic_reloaded(self):
+ # m_copy is copied into the existing module object.
+ # Global state is not changed.
+ self.maxDiff = None
+
+ for name in [
+ self.NAME, # the "basic" module
+ f'{self.NAME}_basic_wrapper', # the indirect variant
+ f'{self.NAME}_basic_copy', # the direct variant
+ ]:
+ self.add_module_cleanup(name)
+ with self.subTest(name):
+ loaded = self.load(name)
+ reloaded = self.re_load(name, loaded.module)
+
+ self.check_common(loaded)
+ self.check_common(reloaded)
+
+ # Make sure the original __dict__ did not get replaced.
+ self.assertEqual(id(loaded.module.__dict__),
+ loaded.snapshot.ns_id)
+ self.assertEqual(loaded.snapshot.ns.__dict__,
+ loaded.module.__dict__)
+
+ self.assertEqual(reloaded.module.__spec__.name, reloaded.name)
+ self.assertEqual(reloaded.module.__name__,
+ reloaded.snapshot.ns.__name__)
+
+ self.assertIs(reloaded.module, loaded.module)
+ self.assertIs(reloaded.module.__dict__, loaded.module.__dict__)
+ # It only happens to be the same but that's good enough here.
+ # We really just want to verify that the re-loaded attrs
+ # didn't change.
+ self.assertIs(reloaded.snapshot.lookedup,
+ loaded.snapshot.lookedup)
+ self.assertEqual(reloaded.snapshot.state_initialized,
+ loaded.snapshot.state_initialized)
+ self.assertEqual(reloaded.snapshot.init_count,
+ loaded.snapshot.init_count)
+
+ self.assertIs(reloaded.snapshot.cached, reloaded.module)
+
+ def test_with_reinit_reloaded(self):
+ # The module's m_init func is run again.
+ self.maxDiff = None
+
+ # Keep a reference around.
+ basic = self.load(self.NAME)
+
+ for name in [
+ f'{self.NAME}_with_reinit', # m_size == 0
+ f'{self.NAME}_with_state', # m_size > 0
+ ]:
+ self.add_module_cleanup(name)
+ with self.subTest(name):
+ loaded = self.load(name)
+ reloaded = self.re_load(name, loaded.module)
+
+ self.check_common(loaded)
+ self.check_common(reloaded)
+
+ # Make sure the original __dict__ did not get replaced.
+ self.assertEqual(id(loaded.module.__dict__),
+ loaded.snapshot.ns_id)
+ self.assertEqual(loaded.snapshot.ns.__dict__,
+ loaded.module.__dict__)
+
+ self.assertEqual(reloaded.module.__spec__.name, reloaded.name)
+ self.assertEqual(reloaded.module.__name__,
+ reloaded.snapshot.ns.__name__)
+
+ self.assertIsNot(reloaded.module, loaded.module)
+ self.assertNotEqual(reloaded.module.__dict__,
+ loaded.module.__dict__)
+ self.assertIs(reloaded.snapshot.lookedup, reloaded.module)
+ if loaded.snapshot.state_initialized is None:
+ self.assertIs(reloaded.snapshot.state_initialized, None)
+ else:
+ self.assertGreater(reloaded.snapshot.state_initialized,
+ loaded.snapshot.state_initialized)
+
+ self.assertIs(reloaded.snapshot.cached, reloaded.module)
+
+ # Currently, for every single-phrase init module loaded
+ # in multiple interpreters, those interpreters share a
+ # PyModuleDef for that object, which can be a problem.
+ # Also, we test with a single-phase module that has global state,
+ # which is shared by all interpreters.
+
+ @requires_subinterpreters
+ def test_basic_multiple_interpreters_main_no_reset(self):
+ # without resetting; already loaded in main interpreter
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def may or may not be loaded already
+ # * module def not in _PyRuntime.imports.extensions
+ # * mod init func has not run yet (since reset, at least)
+ # * m_copy not set (hasn't been loaded yet or already cleared)
+ # * module's global state has not been initialized yet
+ # (or already cleared)
+
+ main_loaded = self.load(self.NAME)
+ _testsinglephase = main_loaded.module
+ # Attrs set after loading are not in m_copy.
+ _testsinglephase.spam = 'spam, spam, spam, spam, eggs, and spam'
+
+ self.check_common(main_loaded)
+ self.check_fresh(main_loaded)
+
+ interpid1 = self.add_subinterpreter()
+ interpid2 = self.add_subinterpreter()
+
+ # At this point:
+ # * alive in 1 interpreter (main)
+ # * module def in _PyRuntime.imports.extensions
+ # * mod init func ran for the first time (since reset, at least)
+ # * m_copy was copied from the main interpreter (was NULL)
+ # * module's global state was initialized
+
+ # Use an interpreter that gets destroyed right away.
+ loaded = self.import_in_subinterp()
+ self.check_common(loaded)
+ self.check_copied(loaded, main_loaded)
+
+ # At this point:
+ # * alive in 1 interpreter (main)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy is NULL (claered when the interpreter was destroyed)
+ # (was from main interpreter)
+ # * module's global state was updated, not reset
+
+ # Use a subinterpreter that sticks around.
+ loaded = self.import_in_subinterp(interpid1)
+ self.check_common(loaded)
+ self.check_copied(loaded, main_loaded)
+
+ # At this point:
+ # * alive in 2 interpreters (main, interp1)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp1
+ # * module's global state was updated, not reset
+
+ # Use a subinterpreter while the previous one is still alive.
+ loaded = self.import_in_subinterp(interpid2)
+ self.check_common(loaded)
+ self.check_copied(loaded, main_loaded)
+
+ # At this point:
+ # * alive in 3 interpreters (main, interp1, interp2)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp2 (was from interp1)
+ # * module's global state was updated, not reset
+
+ @requires_subinterpreters
+ def test_basic_multiple_interpreters_deleted_no_reset(self):
+ # without resetting; already loaded in a deleted interpreter
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def may or may not be loaded already
+ # * module def not in _PyRuntime.imports.extensions
+ # * mod init func has not run yet (since reset, at least)
+ # * m_copy not set (hasn't been loaded yet or already cleared)
+ # * module's global state has not been initialized yet
+ # (or already cleared)
+
+ interpid1 = self.add_subinterpreter()
+ interpid2 = self.add_subinterpreter()
+
+ # First, load in the main interpreter but then completely clear it.
+ loaded_main = self.load(self.NAME)
+ loaded_main.module._clear_globals()
+ _testinternalcapi.clear_extension(self.NAME, self.FILE)
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def loaded already
+ # * module def was in _PyRuntime.imports.extensions, but cleared
+ # * mod init func ran for the first time (since reset, at least)
+ # * m_copy was set, but cleared (was NULL)
+ # * module's global state was initialized but cleared
+
+ # Start with an interpreter that gets destroyed right away.
+ base = self.import_in_subinterp(postscript='''
+ # Attrs set after loading are not in m_copy.
+ mod.spam = 'spam, spam, mash, spam, eggs, and spam'
+ ''')
+ self.check_common(base)
+ self.check_fresh(base)
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy is NULL (claered when the interpreter was destroyed)
+ # * module's global state was initialized, not reset
+
+ # Use a subinterpreter that sticks around.
+ loaded_interp1 = self.import_in_subinterp(interpid1)
+ self.check_common(loaded_interp1)
+ self.check_semi_fresh(loaded_interp1, loaded_main, base)
+
+ # At this point:
+ # * alive in 1 interpreter (interp1)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp1 (was NULL)
+ # * module's global state was updated, not reset
+
+ # Use a subinterpreter while the previous one is still alive.
+ loaded_interp2 = self.import_in_subinterp(interpid2)
+ self.check_common(loaded_interp2)
+ self.check_copied(loaded_interp2, loaded_interp1)
+
+ # At this point:
+ # * alive in 2 interpreters (interp1, interp2)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp2 (was from interp1)
+ # * module's global state was updated, not reset
+
+ @requires_subinterpreters
+ def test_basic_multiple_interpreters_reset_each(self):
+ # resetting between each interpreter
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def may or may not be loaded already
+ # * module def not in _PyRuntime.imports.extensions
+ # * mod init func has not run yet (since reset, at least)
+ # * m_copy not set (hasn't been loaded yet or already cleared)
+ # * module's global state has not been initialized yet
+ # (or already cleared)
+
+ interpid1 = self.add_subinterpreter()
+ interpid2 = self.add_subinterpreter()
+
+ # Use an interpreter that gets destroyed right away.
+ loaded = self.import_in_subinterp(
+ postscript='''
+ # Attrs set after loading are not in m_copy.
+ mod.spam = 'spam, spam, mash, spam, eggs, and spam'
+ ''',
+ postcleanup=True,
+ )
+ self.check_common(loaded)
+ self.check_fresh(loaded)
+
+ # At this point:
+ # * alive in 0 interpreters
+ # * module def in _PyRuntime.imports.extensions
+ # * mod init func ran for the first time (since reset, at least)
+ # * m_copy is NULL (claered when the interpreter was destroyed)
+ # * module's global state was initialized, not reset
+
+ # Use a subinterpreter that sticks around.
+ loaded = self.import_in_subinterp(interpid1, postcleanup=True)
+ self.check_common(loaded)
+ self.check_fresh(loaded)
+
+ # At this point:
+ # * alive in 1 interpreter (interp1)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp1 (was NULL)
+ # * module's global state was initialized, not reset
+
+ # Use a subinterpreter while the previous one is still alive.
+ loaded = self.import_in_subinterp(interpid2, postcleanup=True)
+ self.check_common(loaded)
+ self.check_fresh(loaded)
+
+ # At this point:
+ # * alive in 2 interpreters (interp2, interp2)
+ # * module def still in _PyRuntime.imports.extensions
+ # * mod init func ran again
+ # * m_copy was copied from interp2 (was from interp1)
+ # * module's global state was initialized, not reset
+
if __name__ == '__main__':
# Test needs to be a package, so we can do relative imports.
diff --git a/Lib/test/test_importlib/_context.py b/Lib/test/test_importlib/_context.py
new file mode 100644
index 00000000000000..8a53eb55d1503b
--- /dev/null
+++ b/Lib/test/test_importlib/_context.py
@@ -0,0 +1,13 @@
+import contextlib
+
+
+# from jaraco.context 4.3
+class suppress(contextlib.suppress, contextlib.ContextDecorator):
+ """
+ A version of contextlib.suppress with decorator support.
+
+ >>> @suppress(KeyError)
+ ... def key_error():
+ ... {}['']
+ >>> key_error()
+ """
diff --git a/Lib/test/test_importlib/_path.py b/Lib/test/test_importlib/_path.py
new file mode 100644
index 00000000000000..71a704389b986e
--- /dev/null
+++ b/Lib/test/test_importlib/_path.py
@@ -0,0 +1,109 @@
+# from jaraco.path 3.5
+
+import functools
+import pathlib
+from typing import Dict, Union
+
+try:
+ from typing import Protocol, runtime_checkable
+except ImportError: # pragma: no cover
+ # Python 3.7
+ from typing_extensions import Protocol, runtime_checkable # type: ignore
+
+
+FilesSpec = Dict[str, Union[str, bytes, 'FilesSpec']] # type: ignore
+
+
+@runtime_checkable
+class TreeMaker(Protocol):
+ def __truediv__(self, *args, **kwargs):
+ ... # pragma: no cover
+
+ def mkdir(self, **kwargs):
+ ... # pragma: no cover
+
+ def write_text(self, content, **kwargs):
+ ... # pragma: no cover
+
+ def write_bytes(self, content):
+ ... # pragma: no cover
+
+
+def _ensure_tree_maker(obj: Union[str, TreeMaker]) -> TreeMaker:
+ return obj if isinstance(obj, TreeMaker) else pathlib.Path(obj) # type: ignore
+
+
+def build(
+ spec: FilesSpec,
+ prefix: Union[str, TreeMaker] = pathlib.Path(), # type: ignore
+):
+ """
+ Build a set of files/directories, as described by the spec.
+
+ Each key represents a pathname, and the value represents
+ the content. Content may be a nested directory.
+
+ >>> spec = {
+ ... 'README.txt': "A README file",
+ ... "foo": {
+ ... "__init__.py": "",
+ ... "bar": {
+ ... "__init__.py": "",
+ ... },
+ ... "baz.py": "# Some code",
+ ... }
+ ... }
+ >>> target = getfixture('tmp_path')
+ >>> build(spec, target)
+ >>> target.joinpath('foo/baz.py').read_text(encoding='utf-8')
+ '# Some code'
+ """
+ for name, contents in spec.items():
+ create(contents, _ensure_tree_maker(prefix) / name)
+
+
+@functools.singledispatch
+def create(content: Union[str, bytes, FilesSpec], path):
+ path.mkdir(exist_ok=True)
+ build(content, prefix=path) # type: ignore
+
+
+@create.register
+def _(content: bytes, path):
+ path.write_bytes(content)
+
+
+@create.register
+def _(content: str, path):
+ path.write_text(content, encoding='utf-8')
+
+
+@create.register
+def _(content: str, path):
+ path.write_text(content, encoding='utf-8')
+
+
+class Recording:
+ """
+ A TreeMaker object that records everything that would be written.
+
+ >>> r = Recording()
+ >>> build({'foo': {'foo1.txt': 'yes'}, 'bar.txt': 'abc'}, r)
+ >>> r.record
+ ['foo/foo1.txt', 'bar.txt']
+ """
+
+ def __init__(self, loc=pathlib.PurePosixPath(), record=None):
+ self.loc = loc
+ self.record = record if record is not None else []
+
+ def __truediv__(self, other):
+ return Recording(self.loc / other, self.record)
+
+ def write_text(self, content, **kwargs):
+ self.record.append(str(self.loc))
+
+ write_bytes = write_text
+
+ def mkdir(self, **kwargs):
+ return
diff --git a/Lib/test/test_importlib/fixtures.py b/Lib/test/test_importlib/fixtures.py
index e7be77b3957c67..a364a977bce781 100644
--- a/Lib/test/test_importlib/fixtures.py
+++ b/Lib/test/test_importlib/fixtures.py
@@ -10,7 +10,10 @@
from test.support.os_helper import FS_NONASCII
from test.support import requires_zlib
-from typing import Dict, Union
+
+from . import _path
+from ._path import FilesSpec
+
try:
from importlib import resources # type: ignore
@@ -83,13 +86,8 @@ def setUp(self):
self.fixtures.enter_context(self.add_sys_path(self.site_dir))
-# Except for python/mypy#731, prefer to define
-# FilesDef = Dict[str, Union['FilesDef', str]]
-FilesDef = Dict[str, Union[Dict[str, Union[Dict[str, str], str]], str]]
-
-
class DistInfoPkg(OnSysPath, SiteDir):
- files: FilesDef = {
+ files: FilesSpec = {
"distinfo_pkg-1.0.0.dist-info": {
"METADATA": """
Name: distinfo-pkg
@@ -131,7 +129,7 @@ def make_uppercase(self):
class DistInfoPkgWithDot(OnSysPath, SiteDir):
- files: FilesDef = {
+ files: FilesSpec = {
"pkg_dot-1.0.0.dist-info": {
"METADATA": """
Name: pkg.dot
@@ -146,7 +144,7 @@ def setUp(self):
class DistInfoPkgWithDotLegacy(OnSysPath, SiteDir):
- files: FilesDef = {
+ files: FilesSpec = {
"pkg.dot-1.0.0.dist-info": {
"METADATA": """
Name: pkg.dot
@@ -173,7 +171,7 @@ def setUp(self):
class EggInfoPkg(OnSysPath, SiteDir):
- files: FilesDef = {
+ files: FilesSpec = {
"egginfo_pkg.egg-info": {
"PKG-INFO": """
Name: egginfo-pkg
@@ -212,8 +210,99 @@ def setUp(self):
build_files(EggInfoPkg.files, prefix=self.site_dir)
+class EggInfoPkgPipInstalledNoToplevel(OnSysPath, SiteDir):
+ files: FilesSpec = {
+ "egg_with_module_pkg.egg-info": {
+ "PKG-INFO": "Name: egg_with_module-pkg",
+ # SOURCES.txt is made from the source archive, and contains files
+ # (setup.py) that are not present after installation.
+ "SOURCES.txt": """
+ egg_with_module.py
+ setup.py
+ egg_with_module_pkg.egg-info/PKG-INFO
+ egg_with_module_pkg.egg-info/SOURCES.txt
+ egg_with_module_pkg.egg-info/top_level.txt
+ """,
+ # installed-files.txt is written by pip, and is a strictly more
+ # accurate source than SOURCES.txt as to the installed contents of
+ # the package.
+ "installed-files.txt": """
+ ../egg_with_module.py
+ PKG-INFO
+ SOURCES.txt
+ top_level.txt
+ """,
+ # missing top_level.txt (to trigger fallback to installed-files.txt)
+ },
+ "egg_with_module.py": """
+ def main():
+ print("hello world")
+ """,
+ }
+
+ def setUp(self):
+ super().setUp()
+ build_files(EggInfoPkgPipInstalledNoToplevel.files, prefix=self.site_dir)
+
+
+class EggInfoPkgPipInstalledNoModules(OnSysPath, SiteDir):
+ files: FilesSpec = {
+ "egg_with_no_modules_pkg.egg-info": {
+ "PKG-INFO": "Name: egg_with_no_modules-pkg",
+ # SOURCES.txt is made from the source archive, and contains files
+ # (setup.py) that are not present after installation.
+ "SOURCES.txt": """
+ setup.py
+ egg_with_no_modules_pkg.egg-info/PKG-INFO
+ egg_with_no_modules_pkg.egg-info/SOURCES.txt
+ egg_with_no_modules_pkg.egg-info/top_level.txt
+ """,
+ # installed-files.txt is written by pip, and is a strictly more
+ # accurate source than SOURCES.txt as to the installed contents of
+ # the package.
+ "installed-files.txt": """
+ PKG-INFO
+ SOURCES.txt
+ top_level.txt
+ """,
+ # top_level.txt correctly reflects that no modules are installed
+ "top_level.txt": b"\n",
+ },
+ }
+
+ def setUp(self):
+ super().setUp()
+ build_files(EggInfoPkgPipInstalledNoModules.files, prefix=self.site_dir)
+
+
+class EggInfoPkgSourcesFallback(OnSysPath, SiteDir):
+ files: FilesSpec = {
+ "sources_fallback_pkg.egg-info": {
+ "PKG-INFO": "Name: sources_fallback-pkg",
+ # SOURCES.txt is made from the source archive, and contains files
+ # (setup.py) that are not present after installation.
+ "SOURCES.txt": """
+ sources_fallback.py
+ setup.py
+ sources_fallback_pkg.egg-info/PKG-INFO
+ sources_fallback_pkg.egg-info/SOURCES.txt
+ """,
+ # missing installed-files.txt (i.e. not installed by pip) and
+ # missing top_level.txt (to trigger fallback to SOURCES.txt)
+ },
+ "sources_fallback.py": """
+ def main():
+ print("hello world")
+ """,
+ }
+
+ def setUp(self):
+ super().setUp()
+ build_files(EggInfoPkgSourcesFallback.files, prefix=self.site_dir)
+
+
class EggInfoFile(OnSysPath, SiteDir):
- files: FilesDef = {
+ files: FilesSpec = {
"egginfo_file.egg-info": """
Metadata-Version: 1.0
Name: egginfo_file
@@ -233,38 +322,22 @@ def setUp(self):
build_files(EggInfoFile.files, prefix=self.site_dir)
-def build_files(file_defs, prefix=pathlib.Path()):
- """Build a set of files/directories, as described by the
+# dedent all text strings before writing
+orig = _path.create.registry[str]
+_path.create.register(str, lambda content, path: orig(DALS(content), path))
- file_defs dictionary. Each key/value pair in the dictionary is
- interpreted as a filename/contents pair. If the contents value is a
- dictionary, a directory is created, and the dictionary interpreted
- as the files within it, recursively.
- For example:
+build_files = _path.build
- {"README.txt": "A README file",
- "foo": {
- "__init__.py": "",
- "bar": {
- "__init__.py": "",
- },
- "baz.py": "# Some code",
- }
- }
- """
- for name, contents in file_defs.items():
- full_name = prefix / name
- if isinstance(contents, dict):
- full_name.mkdir()
- build_files(contents, prefix=full_name)
- else:
- if isinstance(contents, bytes):
- with full_name.open('wb') as f:
- f.write(contents)
- else:
- with full_name.open('w', encoding='utf-8') as f:
- f.write(DALS(contents))
+
+def build_record(file_defs):
+ return ''.join(f'{name},,\n' for name in record_names(file_defs))
+
+
+def record_names(file_defs):
+ recording = _path.Recording()
+ _path.build(file_defs, recording)
+ return recording.record
class FileBuilder:
diff --git a/Lib/test/test_importlib/test_main.py b/Lib/test/test_importlib/test_main.py
index 30b68b6ae7d86e..46cd2b696d4cc8 100644
--- a/Lib/test/test_importlib/test_main.py
+++ b/Lib/test/test_importlib/test_main.py
@@ -1,7 +1,10 @@
import re
import pickle
import unittest
+import warnings
import importlib.metadata
+import contextlib
+import itertools
try:
import pyfakefs.fake_filesystem_unittest as ffs
@@ -9,6 +12,7 @@
from .stubs import fake_filesystem_unittest as ffs
from . import fixtures
+from ._context import suppress
from importlib.metadata import (
Distribution,
EntryPoint,
@@ -22,6 +26,13 @@
)
+@contextlib.contextmanager
+def suppress_known_deprecation():
+ with warnings.catch_warnings(record=True) as ctx:
+ warnings.simplefilter('default', category=DeprecationWarning)
+ yield ctx
+
+
class BasicTests(fixtures.DistInfoPkg, unittest.TestCase):
version_pattern = r'\d+\.\d+(\.\d)?'
@@ -37,7 +48,7 @@ def test_for_name_does_not_exist(self):
def test_package_not_found_mentions_metadata(self):
"""
When a package is not found, that could indicate that the
- packgae is not installed or that it is installed without
+ package is not installed or that it is installed without
metadata. Ensure the exception mentions metadata to help
guide users toward the cause. See #124.
"""
@@ -46,8 +57,12 @@ def test_package_not_found_mentions_metadata(self):
assert "metadata" in str(ctx.exception)
- def test_new_style_classes(self):
- self.assertIsInstance(Distribution, type)
+ # expected to fail until ABC is enforced
+ @suppress(AssertionError)
+ @suppress_known_deprecation()
+ def test_abc_enforced(self):
+ with self.assertRaises(TypeError):
+ type('DistributionSubclass', (Distribution,), {})()
@fixtures.parameterize(
dict(name=None),
@@ -172,11 +187,21 @@ def test_metadata_loads_egg_info(self):
assert meta['Description'] == 'pôrˈtend'
-class DiscoveryTests(fixtures.EggInfoPkg, fixtures.DistInfoPkg, unittest.TestCase):
+class DiscoveryTests(
+ fixtures.EggInfoPkg,
+ fixtures.EggInfoPkgPipInstalledNoToplevel,
+ fixtures.EggInfoPkgPipInstalledNoModules,
+ fixtures.EggInfoPkgSourcesFallback,
+ fixtures.DistInfoPkg,
+ unittest.TestCase,
+):
def test_package_discovery(self):
dists = list(distributions())
assert all(isinstance(dist, Distribution) for dist in dists)
assert any(dist.metadata['Name'] == 'egginfo-pkg' for dist in dists)
+ assert any(dist.metadata['Name'] == 'egg_with_module-pkg' for dist in dists)
+ assert any(dist.metadata['Name'] == 'egg_with_no_modules-pkg' for dist in dists)
+ assert any(dist.metadata['Name'] == 'sources_fallback-pkg' for dist in dists)
assert any(dist.metadata['Name'] == 'distinfo-pkg' for dist in dists)
def test_invalid_usage(self):
@@ -324,3 +349,79 @@ def test_packages_distributions_neither_toplevel_nor_files(self):
prefix=self.site_dir,
)
packages_distributions()
+
+ def test_packages_distributions_all_module_types(self):
+ """
+ Test top-level modules detected on a package without 'top-level.txt'.
+ """
+ suffixes = importlib.machinery.all_suffixes()
+ metadata = dict(
+ METADATA="""
+ Name: all_distributions
+ Version: 1.0.0
+ """,
+ )
+ files = {
+ 'all_distributions-1.0.0.dist-info': metadata,
+ }
+ for i, suffix in enumerate(suffixes):
+ files.update(
+ {
+ f'importable-name {i}{suffix}': '',
+ f'in_namespace_{i}': {
+ f'mod{suffix}': '',
+ },
+ f'in_package_{i}': {
+ '__init__.py': '',
+ f'mod{suffix}': '',
+ },
+ }
+ )
+ metadata.update(RECORD=fixtures.build_record(files))
+ fixtures.build_files(files, prefix=self.site_dir)
+
+ distributions = packages_distributions()
+
+ for i in range(len(suffixes)):
+ assert distributions[f'importable-name {i}'] == ['all_distributions']
+ assert distributions[f'in_namespace_{i}'] == ['all_distributions']
+ assert distributions[f'in_package_{i}'] == ['all_distributions']
+
+ assert not any(name.endswith('.dist-info') for name in distributions)
+
+
+class PackagesDistributionsEggTest(
+ fixtures.EggInfoPkg,
+ fixtures.EggInfoPkgPipInstalledNoToplevel,
+ fixtures.EggInfoPkgPipInstalledNoModules,
+ fixtures.EggInfoPkgSourcesFallback,
+ unittest.TestCase,
+):
+ def test_packages_distributions_on_eggs(self):
+ """
+ Test old-style egg packages with a variation of 'top_level.txt',
+ 'SOURCES.txt', and 'installed-files.txt', available.
+ """
+ distributions = packages_distributions()
+
+ def import_names_from_package(package_name):
+ return {
+ import_name
+ for import_name, package_names in distributions.items()
+ if package_name in package_names
+ }
+
+ # egginfo-pkg declares one import ('mod') via top_level.txt
+ assert import_names_from_package('egginfo-pkg') == {'mod'}
+
+ # egg_with_module-pkg has one import ('egg_with_module') inferred from
+ # installed-files.txt (top_level.txt is missing)
+ assert import_names_from_package('egg_with_module-pkg') == {'egg_with_module'}
+
+ # egg_with_no_modules-pkg should not be associated with any import names
+ # (top_level.txt is empty, and installed-files.txt has no .py files)
+ assert import_names_from_package('egg_with_no_modules-pkg') == set()
+
+ # sources_fallback-pkg has one import ('sources_fallback') inferred from
+ # SOURCES.txt (top_level.txt and installed-files.txt is missing)
+ assert import_names_from_package('sources_fallback-pkg') == {'sources_fallback'}
diff --git a/Lib/test/test_importlib/test_metadata_api.py b/Lib/test/test_importlib/test_metadata_api.py
index 71c47e62d27124..33c6e85ee94753 100644
--- a/Lib/test/test_importlib/test_metadata_api.py
+++ b/Lib/test/test_importlib/test_metadata_api.py
@@ -27,12 +27,14 @@ def suppress_known_deprecation():
class APITests(
fixtures.EggInfoPkg,
+ fixtures.EggInfoPkgPipInstalledNoToplevel,
+ fixtures.EggInfoPkgPipInstalledNoModules,
+ fixtures.EggInfoPkgSourcesFallback,
fixtures.DistInfoPkg,
fixtures.DistInfoPkgWithDot,
fixtures.EggInfoFile,
unittest.TestCase,
):
-
version_pattern = r'\d+\.\d+(\.\d)?'
def test_retrieves_version_of_self(self):
@@ -63,15 +65,28 @@ def test_prefix_not_matched(self):
distribution(prefix)
def test_for_top_level(self):
- self.assertEqual(
- distribution('egginfo-pkg').read_text('top_level.txt').strip(), 'mod'
- )
+ tests = [
+ ('egginfo-pkg', 'mod'),
+ ('egg_with_no_modules-pkg', ''),
+ ]
+ for pkg_name, expect_content in tests:
+ with self.subTest(pkg_name):
+ self.assertEqual(
+ distribution(pkg_name).read_text('top_level.txt').strip(),
+ expect_content,
+ )
def test_read_text(self):
- top_level = [
- path for path in files('egginfo-pkg') if path.name == 'top_level.txt'
- ][0]
- self.assertEqual(top_level.read_text(), 'mod\n')
+ tests = [
+ ('egginfo-pkg', 'mod\n'),
+ ('egg_with_no_modules-pkg', '\n'),
+ ]
+ for pkg_name, expect_content in tests:
+ with self.subTest(pkg_name):
+ top_level = [
+ path for path in files(pkg_name) if path.name == 'top_level.txt'
+ ][0]
+ self.assertEqual(top_level.read_text(), expect_content)
def test_entry_points(self):
eps = entry_points()
@@ -137,6 +152,28 @@ def test_metadata_for_this_package(self):
classifiers = md.get_all('Classifier')
assert 'Topic :: Software Development :: Libraries' in classifiers
+ def test_missing_key_legacy(self):
+ """
+ Requesting a missing key will still return None, but warn.
+ """
+ md = metadata('distinfo-pkg')
+ with suppress_known_deprecation():
+ assert md['does-not-exist'] is None
+
+ def test_get_key(self):
+ """
+ Getting a key gets the key.
+ """
+ md = metadata('egginfo-pkg')
+ assert md.get('Name') == 'egginfo-pkg'
+
+ def test_get_missing_key(self):
+ """
+ Requesting a missing key will return None.
+ """
+ md = metadata('distinfo-pkg')
+ assert md.get('does-not-exist') is None
+
@staticmethod
def _test_files(files):
root = files[0].root
@@ -159,6 +196,9 @@ def test_files_dist_info(self):
def test_files_egg_info(self):
self._test_files(files('egginfo-pkg'))
+ self._test_files(files('egg_with_module-pkg'))
+ self._test_files(files('egg_with_no_modules-pkg'))
+ self._test_files(files('sources_fallback-pkg'))
def test_version_egg_info_file(self):
self.assertEqual(version('egginfo-file'), '0.1')
diff --git a/Lib/test/test_inspect.py b/Lib/test/test_inspect.py
index 3a3646f1861e80..42e3d709bd683f 100644
--- a/Lib/test/test_inspect.py
+++ b/Lib/test/test_inspect.py
@@ -1820,8 +1820,7 @@ def test_errors(self):
self.assertEqualException(f, '2, 3, 4')
self.assertEqualException(f, '1, 2, 3, a=1')
self.assertEqualException(f, '2, 3, 4, c=5')
- # XXX: success of this one depends on dict order
- ## self.assertEqualException(f, '2, 3, 4, a=1, c=5')
+ self.assertEqualException(f, '2, 3, 4, a=1, c=5')
# f got an unexpected keyword argument
self.assertEqualException(f, 'c=2')
self.assertEqualException(f, '2, c=3')
@@ -1832,17 +1831,19 @@ def test_errors(self):
self.assertEqualException(f, '1, a=2')
self.assertEqualException(f, '1, **{"a":2}')
self.assertEqualException(f, '1, 2, b=3')
- # XXX: Python inconsistency
- # - for functions and bound methods: unexpected keyword 'c'
- # - for unbound methods: multiple values for keyword 'a'
- #self.assertEqualException(f, '1, c=3, a=2')
+ self.assertEqualException(f, '1, c=3, a=2')
# issue11256:
f3 = self.makeCallable('**c')
self.assertEqualException(f3, '1, 2')
self.assertEqualException(f3, '1, 2, a=1, b=2')
f4 = self.makeCallable('*, a, b=0')
- self.assertEqualException(f3, '1, 2')
- self.assertEqualException(f3, '1, 2, a=1, b=2')
+ self.assertEqualException(f4, '1, 2')
+ self.assertEqualException(f4, '1, 2, a=1, b=2')
+ self.assertEqualException(f4, 'a=1, a=3')
+ self.assertEqualException(f4, 'a=1, c=3')
+ self.assertEqualException(f4, 'a=1, a=3, b=4')
+ self.assertEqualException(f4, 'a=1, b=2, a=3, b=4')
+ self.assertEqualException(f4, 'a=1, a=2, a=3, b=4')
# issue #20816: getcallargs() fails to iterate over non-existent
# kwonlydefaults and raises a wrong TypeError
@@ -2462,18 +2463,43 @@ def test_signature_object(self):
self.assertEqual(str(S()), '()')
self.assertEqual(repr(S().parameters), 'mappingproxy(OrderedDict())')
- def test(po, pk, pod=42, pkd=100, *args, ko, **kwargs):
+ def test(po, /, pk, pkd=100, *args, ko, kod=10, **kwargs):
pass
+
sig = inspect.signature(test)
- po = sig.parameters['po'].replace(kind=P.POSITIONAL_ONLY)
- pod = sig.parameters['pod'].replace(kind=P.POSITIONAL_ONLY)
+ self.assertTrue(repr(sig).startswith(' {42:'ham'}: pass
foo_partial = functools.partial(foo, a=1)
@@ -2872,8 +2901,6 @@ def foo(cls, *, arg):
def test_signature_on_partial(self):
from functools import partial
- Parameter = inspect.Parameter
-
def test():
pass
@@ -2988,8 +3015,6 @@ def test(a, b, c:int) -> 42:
((('c', ..., int, "positional_or_keyword"),),
42))
- psig = inspect.signature(partial(partial(test, 1), 2))
-
def foo(a):
return a
_foo = partial(partial(foo, a=10), a=20)
@@ -3044,14 +3069,9 @@ def foo(a=1, b=2, c=3):
self.assertEqual(_foo(*ba.args, **ba.kwargs), (12, 10, 20))
- def foo(a, b, c, d, **kwargs):
+ def foo(a, b, /, c, d, **kwargs):
pass
sig = inspect.signature(foo)
- params = sig.parameters.copy()
- params['a'] = params['a'].replace(kind=Parameter.POSITIONAL_ONLY)
- params['b'] = params['b'].replace(kind=Parameter.POSITIONAL_ONLY)
- foo.__signature__ = inspect.Signature(params.values())
- sig = inspect.signature(foo)
self.assertEqual(str(sig), '(a, b, /, c, d, **kwargs)')
self.assertEqual(self.signature(partial(foo, 1)),
@@ -3556,14 +3576,9 @@ def test_signature_str_positional_only(self):
P = inspect.Parameter
S = inspect.Signature
- def test(a_po, *, b, **kwargs):
+ def test(a_po, /, *, b, **kwargs):
return a_po, kwargs
- sig = inspect.signature(test)
- new_params = list(sig.parameters.values())
- new_params[0] = new_params[0].replace(kind=P.POSITIONAL_ONLY)
- test.__signature__ = sig.replace(parameters=new_params)
-
self.assertEqual(str(inspect.signature(test)),
'(a_po, /, *, b, **kwargs)')
@@ -3593,6 +3608,14 @@ def test() -> 42:
self.assertEqual(sig.return_annotation, 42)
self.assertEqual(sig, inspect.signature(test))
+ def test_signature_replaced(self):
+ def test():
+ pass
+
+ spam_param = inspect.Parameter('spam', inspect.Parameter.POSITIONAL_ONLY)
+ sig = test.__signature__ = inspect.Signature(parameters=(spam_param,))
+ self.assertEqual(sig, inspect.signature(test))
+
def test_signature_on_mangled_parameters(self):
class Spam:
def foo(self, __p1:1=2, *, __p2:2=3):
@@ -4155,18 +4178,9 @@ def test(a, *args, b, z=100, **kwargs):
self.assertEqual(ba.args, (10, 20))
def test_signature_bind_positional_only(self):
- P = inspect.Parameter
-
- def test(a_po, b_po, c_po=3, foo=42, *, bar=50, **kwargs):
+ def test(a_po, b_po, c_po=3, /, foo=42, *, bar=50, **kwargs):
return a_po, b_po, c_po, foo, bar, kwargs
- sig = inspect.signature(test)
- new_params = collections.OrderedDict(tuple(sig.parameters.items()))
- for name in ('a_po', 'b_po', 'c_po'):
- new_params[name] = new_params[name].replace(kind=P.POSITIONAL_ONLY)
- new_sig = sig.replace(parameters=new_params.values())
- test.__signature__ = new_sig
-
self.assertEqual(self.call(test, 1, 2, 4, 5, bar=6),
(1, 2, 4, 5, 6, {}))
@@ -4587,7 +4601,6 @@ def test_qualname_source(self):
self.assertEqual(err, b'')
def test_builtins(self):
- module = importlib.import_module('unittest')
_, out, err = assert_python_failure('-m', 'inspect',
'sys')
lines = err.decode().splitlines()
diff --git a/Lib/test/test_launcher.py b/Lib/test/test_launcher.py
index 2f35eaf08a2dc9..362b507d158288 100644
--- a/Lib/test/test_launcher.py
+++ b/Lib/test/test_launcher.py
@@ -394,17 +394,17 @@ def test_filter_to_company_with_default(self):
def test_filter_to_tag(self):
company = "PythonTestSuite"
- data = self.run_py([f"-V:3.100"])
+ data = self.run_py(["-V:3.100"])
self.assertEqual("X.Y.exe", data["LaunchCommand"])
self.assertEqual(company, data["env.company"])
self.assertEqual("3.100", data["env.tag"])
- data = self.run_py([f"-V:3.100-32"])
+ data = self.run_py(["-V:3.100-32"])
self.assertEqual("X.Y-32.exe", data["LaunchCommand"])
self.assertEqual(company, data["env.company"])
self.assertEqual("3.100-32", data["env.tag"])
- data = self.run_py([f"-V:3.100-arm64"])
+ data = self.run_py(["-V:3.100-arm64"])
self.assertEqual("X.Y-arm64.exe -X fake_arg_for_test", data["LaunchCommand"])
self.assertEqual(company, data["env.company"])
self.assertEqual("3.100-arm64", data["env.tag"])
@@ -421,7 +421,7 @@ def test_filter_to_company_and_tag(self):
def test_filter_with_single_install(self):
company = "PythonTestSuite1"
data = self.run_py(
- [f"-V:Nonexistent"],
+ ["-V:Nonexistent"],
env={"PYLAUNCHER_LIMIT_TO_COMPANY": company},
expect_returncode=103,
)
@@ -500,7 +500,7 @@ def test_py_default_short_argv0(self):
data = self.run_py(["--version"], argv=f'{argv0} --version')
self.assertEqual("PythonTestSuite", data["SearchInfo.company"])
self.assertEqual("3.100", data["SearchInfo.tag"])
- self.assertEqual(f'X.Y.exe --version', data["stdout"].strip())
+ self.assertEqual("X.Y.exe --version", data["stdout"].strip())
def test_py_default_in_list(self):
data = self.run_py(["-0"], env=TEST_PY_ENV)
@@ -662,7 +662,7 @@ def test_install(self):
self.assertIn("9PJPW5LDXLZ5", cmd)
def test_literal_shebang_absolute(self):
- with self.script(f"#! C:/some_random_app -witharg") as script:
+ with self.script("#! C:/some_random_app -witharg") as script:
data = self.run_py([script])
self.assertEqual(
f"C:\\some_random_app -witharg {script}",
@@ -670,7 +670,7 @@ def test_literal_shebang_absolute(self):
)
def test_literal_shebang_relative(self):
- with self.script(f"#! ..\\some_random_app -witharg") as script:
+ with self.script("#! ..\\some_random_app -witharg") as script:
data = self.run_py([script])
self.assertEqual(
f"{script.parent.parent}\\some_random_app -witharg {script}",
@@ -678,14 +678,14 @@ def test_literal_shebang_relative(self):
)
def test_literal_shebang_quoted(self):
- with self.script(f'#! "some random app" -witharg') as script:
+ with self.script('#! "some random app" -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some random app" -witharg {script}',
data["stdout"].strip(),
)
- with self.script(f'#! some" random "app -witharg') as script:
+ with self.script('#! some" random "app -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some random app" -witharg {script}',
@@ -693,7 +693,7 @@ def test_literal_shebang_quoted(self):
)
def test_literal_shebang_quoted_escape(self):
- with self.script(f'#! some\\" random "app -witharg') as script:
+ with self.script('#! some\\" random "app -witharg') as script:
data = self.run_py([script])
self.assertEqual(
f'"{script.parent}\\some\\ random app" -witharg {script}',
diff --git a/Lib/test/test_logging.py b/Lib/test/test_logging.py
index c6de34e9dbdc8f..9176d8eeb56d01 100644
--- a/Lib/test/test_logging.py
+++ b/Lib/test/test_logging.py
@@ -1524,6 +1524,32 @@ class ConfigFileTest(BaseTest):
kwargs={{"encoding": "utf-8"}}
"""
+
+ config9 = """
+ [loggers]
+ keys=root
+
+ [handlers]
+ keys=hand1
+
+ [formatters]
+ keys=form1
+
+ [logger_root]
+ level=WARNING
+ handlers=hand1
+
+ [handler_hand1]
+ class=StreamHandler
+ level=NOTSET
+ formatter=form1
+ args=(sys.stdout,)
+
+ [formatter_form1]
+ format=%(message)s ++ %(customfield)s
+ defaults={"customfield": "defaultvalue"}
+ """
+
disable_test = """
[loggers]
keys=root
@@ -1687,6 +1713,16 @@ def test_config8_ok(self):
handler = logging.root.handlers[0]
self.addCleanup(closeFileHandler, handler, fn)
+ def test_config9_ok(self):
+ self.apply_config(self.config9)
+ formatter = logging.root.handlers[0].formatter
+ result = formatter.format(logging.makeLogRecord({'msg': 'test'}))
+ self.assertEqual(result, 'test ++ defaultvalue')
+ result = formatter.format(logging.makeLogRecord(
+ {'msg': 'test', 'customfield': "customvalue"}))
+ self.assertEqual(result, 'test ++ customvalue')
+
+
def test_logger_disabling(self):
self.apply_config(self.disable_test)
logger = logging.getLogger('some_pristine_logger')
@@ -2909,6 +2945,30 @@ class ConfigDictTest(BaseTest):
},
}
+ # config0 but with default values for formatter. Skipped 15, it is defined
+ # in the test code.
+ config16 = {
+ 'version': 1,
+ 'formatters': {
+ 'form1' : {
+ 'format' : '%(message)s ++ %(customfield)s',
+ 'defaults': {"customfield": "defaultvalue"}
+ },
+ },
+ 'handlers' : {
+ 'hand1' : {
+ 'class' : 'logging.StreamHandler',
+ 'formatter' : 'form1',
+ 'level' : 'NOTSET',
+ 'stream' : 'ext://sys.stdout',
+ },
+ },
+ 'root' : {
+ 'level' : 'WARNING',
+ 'handlers' : ['hand1'],
+ },
+ }
+
bad_format = {
"version": 1,
"formatters": {
@@ -3021,7 +3081,7 @@ class ConfigDictTest(BaseTest):
}
}
- # Configuration with custom function and 'validate' set to False
+ # Configuration with custom function, 'validate' set to False and no defaults
custom_formatter_with_function = {
'version': 1,
'formatters': {
@@ -3048,6 +3108,33 @@ class ConfigDictTest(BaseTest):
}
}
+ # Configuration with custom function, and defaults
+ custom_formatter_with_defaults = {
+ 'version': 1,
+ 'formatters': {
+ 'form1': {
+ '()': formatFunc,
+ 'format': '%(levelname)s:%(name)s:%(message)s:%(customfield)s',
+ 'defaults': {"customfield": "myvalue"}
+ },
+ },
+ 'handlers' : {
+ 'hand1' : {
+ 'class': 'logging.StreamHandler',
+ 'formatter': 'form1',
+ 'level': 'NOTSET',
+ 'stream': 'ext://sys.stdout',
+ },
+ },
+ "loggers": {
+ "my_test_logger_custom_formatter": {
+ "level": "DEBUG",
+ "handlers": ["hand1"],
+ "propagate": "true"
+ }
+ }
+ }
+
config_queue_handler = {
'version': 1,
'handlers' : {
@@ -3349,6 +3436,22 @@ def test_config15_ok(self):
handler = logging.root.handlers[0]
self.addCleanup(closeFileHandler, handler, fn)
+ def test_config16_ok(self):
+ self.apply_config(self.config16)
+ h = logging._handlers['hand1']
+
+ # Custom value
+ result = h.formatter.format(logging.makeLogRecord(
+ {'msg': 'Hello', 'customfield': 'customvalue'}))
+ self.assertEqual(result, 'Hello ++ customvalue')
+
+ # Default value
+ result = h.formatter.format(logging.makeLogRecord(
+ {'msg': 'Hello'}))
+ self.assertEqual(result, 'Hello ++ defaultvalue')
+
+
+
def setup_via_listener(self, text, verify=None):
text = text.encode("utf-8")
# Ask for a randomly assigned port (by using port 0)
@@ -3516,6 +3619,9 @@ def test_custom_formatter_class_with_validate3(self):
def test_custom_formatter_function_with_validate(self):
self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_function)
+ def test_custom_formatter_function_with_defaults(self):
+ self.assertRaises(ValueError, self.apply_config, self.custom_formatter_with_defaults)
+
def test_baseconfig(self):
d = {
'atuple': (1, 2, 3),
diff --git a/Lib/test/test_monitoring.py b/Lib/test/test_monitoring.py
new file mode 100644
index 00000000000000..738ace923cc523
--- /dev/null
+++ b/Lib/test/test_monitoring.py
@@ -0,0 +1,1115 @@
+"""Test suite for the sys.monitoring."""
+
+import collections
+import functools
+import operator
+import sys
+import types
+import unittest
+
+
+PAIR = (0,1)
+
+def f1():
+ pass
+
+def f2():
+ len([])
+ sys.getsizeof(0)
+
+def floop():
+ for item in PAIR:
+ pass
+
+def gen():
+ yield
+ yield
+
+def g1():
+ for _ in gen():
+ pass
+
+TEST_TOOL = 2
+TEST_TOOL2 = 3
+TEST_TOOL3 = 4
+
+class MonitoringBasicTest(unittest.TestCase):
+
+ def test_has_objects(self):
+ m = sys.monitoring
+ m.events
+ m.use_tool_id
+ m.free_tool_id
+ m.get_tool
+ m.get_events
+ m.set_events
+ m.get_local_events
+ m.set_local_events
+ m.register_callback
+ m.restart_events
+ m.DISABLE
+ m.MISSING
+ m.events.NO_EVENTS
+
+ def test_tool(self):
+ sys.monitoring.use_tool_id(TEST_TOOL, "MonitoringTest.Tool")
+ self.assertEqual(sys.monitoring.get_tool(TEST_TOOL), "MonitoringTest.Tool")
+ sys.monitoring.set_events(TEST_TOOL, 15)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 15)
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ with self.assertRaises(ValueError):
+ sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.C_RETURN)
+ with self.assertRaises(ValueError):
+ sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.C_RAISE)
+ sys.monitoring.free_tool_id(TEST_TOOL)
+ self.assertEqual(sys.monitoring.get_tool(TEST_TOOL), None)
+ with self.assertRaises(ValueError):
+ sys.monitoring.set_events(TEST_TOOL, sys.monitoring.events.CALL)
+
+
+class MonitoringTestBase:
+
+ def setUp(self):
+ # Check that a previous test hasn't left monitoring on.
+ for tool in range(6):
+ self.assertEqual(sys.monitoring.get_events(tool), 0)
+ self.assertIs(sys.monitoring.get_tool(TEST_TOOL), None)
+ self.assertIs(sys.monitoring.get_tool(TEST_TOOL2), None)
+ self.assertIs(sys.monitoring.get_tool(TEST_TOOL3), None)
+ sys.monitoring.use_tool_id(TEST_TOOL, "test " + self.__class__.__name__)
+ sys.monitoring.use_tool_id(TEST_TOOL2, "test2 " + self.__class__.__name__)
+ sys.monitoring.use_tool_id(TEST_TOOL3, "test3 " + self.__class__.__name__)
+
+ def tearDown(self):
+ # Check that test hasn't left monitoring on.
+ for tool in range(6):
+ self.assertEqual(sys.monitoring.get_events(tool), 0)
+ sys.monitoring.free_tool_id(TEST_TOOL)
+ sys.monitoring.free_tool_id(TEST_TOOL2)
+ sys.monitoring.free_tool_id(TEST_TOOL3)
+
+
+class MonitoringCountTest(MonitoringTestBase, unittest.TestCase):
+
+ def check_event_count(self, func, event, expected):
+
+ class Counter:
+ def __init__(self):
+ self.count = 0
+ def __call__(self, *args):
+ self.count += 1
+
+ counter = Counter()
+ sys.monitoring.register_callback(TEST_TOOL, event, counter)
+ if event == E.C_RETURN or event == E.C_RAISE:
+ sys.monitoring.set_events(TEST_TOOL, E.CALL)
+ else:
+ sys.monitoring.set_events(TEST_TOOL, event)
+ self.assertEqual(counter.count, 0)
+ counter.count = 0
+ func()
+ self.assertEqual(counter.count, expected)
+ prev = sys.monitoring.register_callback(TEST_TOOL, event, None)
+ counter.count = 0
+ func()
+ self.assertEqual(counter.count, 0)
+ self.assertEqual(prev, counter)
+ sys.monitoring.set_events(TEST_TOOL, 0)
+
+ def test_start_count(self):
+ self.check_event_count(f1, E.PY_START, 1)
+
+ def test_resume_count(self):
+ self.check_event_count(g1, E.PY_RESUME, 2)
+
+ def test_return_count(self):
+ self.check_event_count(f1, E.PY_RETURN, 1)
+
+ def test_call_count(self):
+ self.check_event_count(f2, E.CALL, 3)
+
+ def test_c_return_count(self):
+ self.check_event_count(f2, E.C_RETURN, 2)
+
+
+E = sys.monitoring.events
+
+SIMPLE_EVENTS = [
+ (E.PY_START, "start"),
+ (E.PY_RESUME, "resume"),
+ (E.PY_RETURN, "return"),
+ (E.PY_YIELD, "yield"),
+ (E.JUMP, "jump"),
+ (E.BRANCH, "branch"),
+ (E.RAISE, "raise"),
+ (E.PY_UNWIND, "unwind"),
+ (E.EXCEPTION_HANDLED, "exception_handled"),
+ (E.C_RAISE, "c_raise"),
+ (E.C_RETURN, "c_return"),
+]
+
+SIMPLE_EVENT_SET = functools.reduce(operator.or_, [ev for (ev, _) in SIMPLE_EVENTS], 0) | E.CALL
+
+
+def just_pass():
+ pass
+
+just_pass.events = [
+ "py_call",
+ "start",
+ "return",
+]
+
+def just_raise():
+ raise Exception
+
+just_raise.events = [
+ 'py_call',
+ "start",
+ "raise",
+ "unwind",
+]
+
+def just_call():
+ len([])
+
+just_call.events = [
+ 'py_call',
+ "start",
+ "c_call",
+ "c_return",
+ "return",
+]
+
+def caught():
+ try:
+ 1/0
+ except Exception:
+ pass
+
+caught.events = [
+ 'py_call',
+ "start",
+ "raise",
+ "exception_handled",
+ "branch",
+ "return",
+]
+
+def nested_call():
+ just_pass()
+
+nested_call.events = [
+ "py_call",
+ "start",
+ "py_call",
+ "start",
+ "return",
+ "return",
+]
+
+PY_CALLABLES = (types.FunctionType, types.MethodType)
+
+class MonitoringEventsBase(MonitoringTestBase):
+
+ def gather_events(self, func):
+ events = []
+ for event, event_name in SIMPLE_EVENTS:
+ def record(*args, event_name=event_name):
+ events.append(event_name)
+ sys.monitoring.register_callback(TEST_TOOL, event, record)
+ def record_call(code, offset, obj, arg):
+ if isinstance(obj, PY_CALLABLES):
+ events.append("py_call")
+ else:
+ events.append("c_call")
+ sys.monitoring.register_callback(TEST_TOOL, E.CALL, record_call)
+ sys.monitoring.set_events(TEST_TOOL, SIMPLE_EVENT_SET)
+ events = []
+ try:
+ func()
+ except:
+ pass
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ #Remove the final event, the call to `sys.monitoring.set_events`
+ events = events[:-1]
+ return events
+
+ def check_events(self, func, expected=None):
+ events = self.gather_events(func)
+ if expected is None:
+ expected = func.events
+ self.assertEqual(events, expected)
+
+
+class MonitoringEventsTest(MonitoringEventsBase, unittest.TestCase):
+
+ def test_just_pass(self):
+ self.check_events(just_pass)
+
+ def test_just_raise(self):
+ try:
+ self.check_events(just_raise)
+ except Exception:
+ pass
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 0)
+
+ def test_just_call(self):
+ self.check_events(just_call)
+
+ def test_caught(self):
+ self.check_events(caught)
+
+ def test_nested_call(self):
+ self.check_events(nested_call)
+
+UP_EVENTS = (E.C_RETURN, E.C_RAISE, E.PY_RETURN, E.PY_UNWIND, E.PY_YIELD)
+DOWN_EVENTS = (E.PY_START, E.PY_RESUME)
+
+from test.profilee import testfunc
+
+class SimulateProfileTest(MonitoringEventsBase, unittest.TestCase):
+
+ def test_balanced(self):
+ events = self.gather_events(testfunc)
+ c = collections.Counter(events)
+ self.assertEqual(c["c_call"], c["c_return"])
+ self.assertEqual(c["start"], c["return"] + c["unwind"])
+ self.assertEqual(c["raise"], c["exception_handled"] + c["unwind"])
+
+ def test_frame_stack(self):
+ self.maxDiff = None
+ stack = []
+ errors = []
+ seen = set()
+ def up(*args):
+ frame = sys._getframe(1)
+ if not stack:
+ errors.append("empty")
+ else:
+ expected = stack.pop()
+ if frame != expected:
+ errors.append(f" Popping {frame} expected {expected}")
+ def down(*args):
+ frame = sys._getframe(1)
+ stack.append(frame)
+ seen.add(frame.f_code)
+ def call(code, offset, callable, arg):
+ if not isinstance(callable, PY_CALLABLES):
+ stack.append(sys._getframe(1))
+ for event in UP_EVENTS:
+ sys.monitoring.register_callback(TEST_TOOL, event, up)
+ for event in DOWN_EVENTS:
+ sys.monitoring.register_callback(TEST_TOOL, event, down)
+ sys.monitoring.register_callback(TEST_TOOL, E.CALL, call)
+ sys.monitoring.set_events(TEST_TOOL, SIMPLE_EVENT_SET)
+ testfunc()
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ self.assertEqual(errors, [])
+ self.assertEqual(stack, [sys._getframe()])
+ self.assertEqual(len(seen), 9)
+
+
+class CounterWithDisable:
+
+ def __init__(self):
+ self.disable = False
+ self.count = 0
+
+ def __call__(self, *args):
+ self.count += 1
+ if self.disable:
+ return sys.monitoring.DISABLE
+
+
+class RecorderWithDisable:
+
+ def __init__(self, events):
+ self.disable = False
+ self.events = events
+
+ def __call__(self, code, event):
+ self.events.append(event)
+ if self.disable:
+ return sys.monitoring.DISABLE
+
+
+class MontoringDisableAndRestartTest(MonitoringTestBase, unittest.TestCase):
+
+ def test_disable(self):
+ try:
+ counter = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ self.assertEqual(counter.count, 0)
+ counter.count = 0
+ f1()
+ self.assertEqual(counter.count, 1)
+ counter.disable = True
+ counter.count = 0
+ f1()
+ self.assertEqual(counter.count, 1)
+ counter.count = 0
+ f1()
+ self.assertEqual(counter.count, 0)
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ finally:
+ sys.monitoring.restart_events()
+
+ def test_restart(self):
+ try:
+ counter = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ counter.disable = True
+ f1()
+ counter.count = 0
+ f1()
+ self.assertEqual(counter.count, 0)
+ sys.monitoring.restart_events()
+ counter.count = 0
+ f1()
+ self.assertEqual(counter.count, 1)
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ finally:
+ sys.monitoring.restart_events()
+
+
+class MultipleMonitorsTest(MonitoringTestBase, unittest.TestCase):
+
+ def test_two_same(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ counter1 = CounterWithDisable()
+ counter2 = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL2, E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START)
+ self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2)})
+ counter1.count = 0
+ counter2.count = 0
+ f1()
+ count1 = counter1.count
+ count2 = counter2.count
+ self.assertEqual((count1, count2), (1, 1))
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+
+ def test_three_same(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ counter1 = CounterWithDisable()
+ counter2 = CounterWithDisable()
+ counter3 = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2)
+ sys.monitoring.register_callback(TEST_TOOL3, E.PY_START, counter3)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL2, E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL3, E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL3), E.PY_START)
+ self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2) | (1 << TEST_TOOL3)})
+ counter1.count = 0
+ counter2.count = 0
+ counter3.count = 0
+ f1()
+ count1 = counter1.count
+ count2 = counter2.count
+ count3 = counter3.count
+ self.assertEqual((count1, count2, count3), (1, 1, 1))
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.set_events(TEST_TOOL3, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None)
+ sys.monitoring.register_callback(TEST_TOOL3, E.PY_START, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+
+ def test_two_different(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ counter1 = CounterWithDisable()
+ counter2 = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_RETURN, counter2)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL2, E.PY_RETURN)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_RETURN)
+ self.assertEqual(sys.monitoring._all_events(), {'PY_START': 1 << TEST_TOOL, 'PY_RETURN': 1 << TEST_TOOL2})
+ counter1.count = 0
+ counter2.count = 0
+ f1()
+ count1 = counter1.count
+ count2 = counter2.count
+ self.assertEqual((count1, count2), (1, 1))
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_RETURN, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+
+ def test_two_with_disable(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ counter1 = CounterWithDisable()
+ counter2 = CounterWithDisable()
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, counter1)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, counter2)
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL2, E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START)
+ self.assertEqual(sys.monitoring._all_events(), {'PY_START': (1 << TEST_TOOL) | (1 << TEST_TOOL2)})
+ counter1.count = 0
+ counter2.count = 0
+ counter1.disable = True
+ f1()
+ count1 = counter1.count
+ count2 = counter2.count
+ self.assertEqual((count1, count2), (1, 1))
+ counter1.count = 0
+ counter2.count = 0
+ f1()
+ count1 = counter1.count
+ count2 = counter2.count
+ self.assertEqual((count1, count2), (0, 1))
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.PY_START, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.PY_START, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+ sys.monitoring.restart_events()
+
+class LineMonitoringTest(MonitoringTestBase, unittest.TestCase):
+
+ def test_lines_single(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ events = []
+ recorder = RecorderWithDisable(events)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder)
+ sys.monitoring.set_events(TEST_TOOL, E.LINE)
+ f1()
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ start = LineMonitoringTest.test_lines_single.__code__.co_firstlineno
+ self.assertEqual(events, [start+7, 14, start+8])
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+ sys.monitoring.restart_events()
+
+ def test_lines_loop(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ events = []
+ recorder = RecorderWithDisable(events)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder)
+ sys.monitoring.set_events(TEST_TOOL, E.LINE)
+ floop()
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ start = LineMonitoringTest.test_lines_loop.__code__.co_firstlineno
+ self.assertEqual(events, [start+7, 21, 22, 22, 21, start+8])
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+ sys.monitoring.restart_events()
+
+ def test_lines_two(self):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ events = []
+ recorder = RecorderWithDisable(events)
+ events2 = []
+ recorder2 = RecorderWithDisable(events2)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, recorder)
+ sys.monitoring.register_callback(TEST_TOOL2, E.LINE, recorder2)
+ sys.monitoring.set_events(TEST_TOOL, E.LINE); sys.monitoring.set_events(TEST_TOOL2, E.LINE)
+ f1()
+ sys.monitoring.set_events(TEST_TOOL, 0); sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None)
+ start = LineMonitoringTest.test_lines_two.__code__.co_firstlineno
+ expected = [start+10, 14, start+11]
+ self.assertEqual(events, expected)
+ self.assertEqual(events2, expected)
+ finally:
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ sys.monitoring.set_events(TEST_TOOL2, 0)
+ sys.monitoring.register_callback(TEST_TOOL, E.LINE, None)
+ sys.monitoring.register_callback(TEST_TOOL2, E.LINE, None)
+ self.assertEqual(sys.monitoring._all_events(), {})
+ sys.monitoring.restart_events()
+
+ def check_lines(self, func, expected, tool=TEST_TOOL):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ events = []
+ recorder = RecorderWithDisable(events)
+ sys.monitoring.register_callback(tool, E.LINE, recorder)
+ sys.monitoring.set_events(tool, E.LINE)
+ func()
+ sys.monitoring.set_events(tool, 0)
+ sys.monitoring.register_callback(tool, E.LINE, None)
+ lines = [ line - func.__code__.co_firstlineno for line in events[1:-1] ]
+ self.assertEqual(lines, expected)
+ finally:
+ sys.monitoring.set_events(tool, 0)
+
+
+ def test_linear(self):
+
+ def func():
+ line = 1
+ line = 2
+ line = 3
+ line = 4
+ line = 5
+
+ self.check_lines(func, [1,2,3,4,5])
+
+ def test_branch(self):
+ def func():
+ if "true".startswith("t"):
+ line = 2
+ line = 3
+ else:
+ line = 5
+ line = 6
+
+ self.check_lines(func, [1,2,3,6])
+
+ def test_try_except(self):
+
+ def func1():
+ try:
+ line = 2
+ line = 3
+ except:
+ line = 5
+ line = 6
+
+ self.check_lines(func1, [1,2,3,6])
+
+ def func2():
+ try:
+ line = 2
+ raise 3
+ except:
+ line = 5
+ line = 6
+
+ self.check_lines(func2, [1,2,3,4,5,6])
+
+
+class ExceptionRecorder:
+
+ event_type = E.RAISE
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, offset, exc):
+ self.events.append(("raise", type(exc)))
+
+class CheckEvents(MonitoringTestBase, unittest.TestCase):
+
+ def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ event_list = []
+ all_events = 0
+ for recorder in recorders:
+ ev = recorder.event_type
+ sys.monitoring.register_callback(tool, ev, recorder(event_list))
+ all_events |= ev
+ sys.monitoring.set_events(tool, all_events)
+ func()
+ sys.monitoring.set_events(tool, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+ self.assertEqual(event_list, expected)
+ finally:
+ sys.monitoring.set_events(tool, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+
+class StopiterationRecorder(ExceptionRecorder):
+
+ event_type = E.STOP_ITERATION
+
+class ExceptionMontoringTest(CheckEvents):
+
+ recorder = ExceptionRecorder
+
+ def test_simple_try_except(self):
+
+ def func1():
+ try:
+ line = 2
+ raise KeyError
+ except:
+ line = 5
+ line = 6
+
+ self.check_events(func1, [("raise", KeyError)])
+
+ def gen():
+ yield 1
+ return 2
+
+ def implicit_stop_iteration():
+ for _ in gen():
+ pass
+
+ self.check_events(implicit_stop_iteration, [("raise", StopIteration)], recorders=(StopiterationRecorder,))
+
+class LineRecorder:
+
+ event_type = E.LINE
+
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, line):
+ self.events.append(("line", code.co_name, line - code.co_firstlineno))
+
+class CallRecorder:
+
+ event_type = E.CALL
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, offset, func, arg):
+ self.events.append(("call", func.__name__, arg))
+
+class CEventRecorder:
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, offset, func, arg):
+ self.events.append((self.event_name, func.__name__, arg))
+
+class CReturnRecorder(CEventRecorder):
+
+ event_type = E.C_RETURN
+ event_name = "C return"
+
+class CRaiseRecorder(CEventRecorder):
+
+ event_type = E.C_RAISE
+ event_name = "C raise"
+
+MANY_RECORDERS = ExceptionRecorder, CallRecorder, LineRecorder, CReturnRecorder, CRaiseRecorder
+
+class TestManyEvents(CheckEvents):
+
+ def test_simple(self):
+
+ def func1():
+ line1 = 1
+ line2 = 2
+ line3 = 3
+
+ self.check_events(func1, recorders = MANY_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('call', 'func1', sys.monitoring.MISSING),
+ ('line', 'func1', 1),
+ ('line', 'func1', 2),
+ ('line', 'func1', 3),
+ ('line', 'check_events', 11),
+ ('call', 'set_events', 2)])
+
+ def test_c_call(self):
+
+ def func2():
+ line1 = 1
+ [].append(2)
+ line3 = 3
+
+ self.check_events(func2, recorders = MANY_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('call', 'func2', sys.monitoring.MISSING),
+ ('line', 'func2', 1),
+ ('line', 'func2', 2),
+ ('call', 'append', [2]),
+ ('C return', 'append', [2]),
+ ('line', 'func2', 3),
+ ('line', 'check_events', 11),
+ ('call', 'set_events', 2)])
+
+ def test_try_except(self):
+
+ def func3():
+ try:
+ line = 2
+ raise KeyError
+ except:
+ line = 5
+ line = 6
+
+ self.check_events(func3, recorders = MANY_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('call', 'func3', sys.monitoring.MISSING),
+ ('line', 'func3', 1),
+ ('line', 'func3', 2),
+ ('line', 'func3', 3),
+ ('raise', KeyError),
+ ('line', 'func3', 4),
+ ('line', 'func3', 5),
+ ('line', 'func3', 6),
+ ('line', 'check_events', 11),
+ ('call', 'set_events', 2)])
+
+class InstructionRecorder:
+
+ event_type = E.INSTRUCTION
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, offset):
+ # Filter out instructions in check_events to lower noise
+ if code.co_name != "check_events":
+ self.events.append(("instruction", code.co_name, offset))
+
+
+LINE_AND_INSTRUCTION_RECORDERS = InstructionRecorder, LineRecorder
+
+class TestLineAndInstructionEvents(CheckEvents):
+ maxDiff = None
+
+ def test_simple(self):
+
+ def func1():
+ line1 = 1
+ line2 = 2
+ line3 = 3
+
+ self.check_events(func1, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('line', 'func1', 1),
+ ('instruction', 'func1', 2),
+ ('instruction', 'func1', 4),
+ ('line', 'func1', 2),
+ ('instruction', 'func1', 6),
+ ('instruction', 'func1', 8),
+ ('line', 'func1', 3),
+ ('instruction', 'func1', 10),
+ ('instruction', 'func1', 12),
+ ('instruction', 'func1', 14),
+ ('line', 'check_events', 11)])
+
+ def test_c_call(self):
+
+ def func2():
+ line1 = 1
+ [].append(2)
+ line3 = 3
+
+ self.check_events(func2, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('line', 'func2', 1),
+ ('instruction', 'func2', 2),
+ ('instruction', 'func2', 4),
+ ('line', 'func2', 2),
+ ('instruction', 'func2', 6),
+ ('instruction', 'func2', 8),
+ ('instruction', 'func2', 28),
+ ('instruction', 'func2', 30),
+ ('instruction', 'func2', 38),
+ ('line', 'func2', 3),
+ ('instruction', 'func2', 40),
+ ('instruction', 'func2', 42),
+ ('instruction', 'func2', 44),
+ ('line', 'check_events', 11)])
+
+ def test_try_except(self):
+
+ def func3():
+ try:
+ line = 2
+ raise KeyError
+ except:
+ line = 5
+ line = 6
+
+ self.check_events(func3, recorders = LINE_AND_INSTRUCTION_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('line', 'func3', 1),
+ ('instruction', 'func3', 2),
+ ('line', 'func3', 2),
+ ('instruction', 'func3', 4),
+ ('instruction', 'func3', 6),
+ ('line', 'func3', 3),
+ ('instruction', 'func3', 8),
+ ('instruction', 'func3', 18),
+ ('instruction', 'func3', 20),
+ ('line', 'func3', 4),
+ ('instruction', 'func3', 22),
+ ('line', 'func3', 5),
+ ('instruction', 'func3', 24),
+ ('instruction', 'func3', 26),
+ ('instruction', 'func3', 28),
+ ('line', 'func3', 6),
+ ('instruction', 'func3', 30),
+ ('instruction', 'func3', 32),
+ ('instruction', 'func3', 34),
+ ('line', 'check_events', 11)])
+
+class TestInstallIncrementallly(MonitoringTestBase, unittest.TestCase):
+
+ def check_events(self, func, must_include, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ event_list = []
+ all_events = 0
+ for recorder in recorders:
+ all_events |= recorder.event_type
+ sys.monitoring.set_events(tool, all_events)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, recorder(event_list))
+ func()
+ sys.monitoring.set_events(tool, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+ for line in must_include:
+ self.assertIn(line, event_list)
+ finally:
+ sys.monitoring.set_events(tool, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+
+ @staticmethod
+ def func1():
+ line1 = 1
+
+ MUST_INCLUDE_LI = [
+ ('instruction', 'func1', 2),
+ ('line', 'func1', 1),
+ ('instruction', 'func1', 4),
+ ('instruction', 'func1', 6)]
+
+ def test_line_then_instruction(self):
+ recorders = [ LineRecorder, InstructionRecorder ]
+ self.check_events(self.func1,
+ recorders = recorders, must_include = self.EXPECTED_LI)
+
+ def test_instruction_then_line(self):
+ recorders = [ InstructionRecorder, LineRecorderLowNoise ]
+ self.check_events(self.func1,
+ recorders = recorders, must_include = self.EXPECTED_LI)
+
+ @staticmethod
+ def func2():
+ len(())
+
+ MUST_INCLUDE_CI = [
+ ('instruction', 'func2', 2),
+ ('call', 'func2', sys.monitoring.MISSING),
+ ('call', 'len', ()),
+ ('instruction', 'func2', 12),
+ ('instruction', 'func2', 14)]
+
+
+
+ def test_line_then_instruction(self):
+ recorders = [ CallRecorder, InstructionRecorder ]
+ self.check_events(self.func2,
+ recorders = recorders, must_include = self.MUST_INCLUDE_CI)
+
+ def test_instruction_then_line(self):
+ recorders = [ InstructionRecorder, CallRecorder ]
+ self.check_events(self.func2,
+ recorders = recorders, must_include = self.MUST_INCLUDE_CI)
+
+class TestLocalEvents(MonitoringTestBase, unittest.TestCase):
+
+ def check_events(self, func, expected, tool=TEST_TOOL, recorders=(ExceptionRecorder,)):
+ try:
+ self.assertEqual(sys.monitoring._all_events(), {})
+ event_list = []
+ all_events = 0
+ for recorder in recorders:
+ ev = recorder.event_type
+ sys.monitoring.register_callback(tool, ev, recorder(event_list))
+ all_events |= ev
+ sys.monitoring.set_local_events(tool, func.__code__, all_events)
+ func()
+ sys.monitoring.set_local_events(tool, func.__code__, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+ self.assertEqual(event_list, expected)
+ finally:
+ sys.monitoring.set_local_events(tool, func.__code__, 0)
+ for recorder in recorders:
+ sys.monitoring.register_callback(tool, recorder.event_type, None)
+
+
+ def test_simple(self):
+
+ def func1():
+ line1 = 1
+ line2 = 2
+ line3 = 3
+
+ self.check_events(func1, recorders = MANY_RECORDERS, expected = [
+ ('line', 'func1', 1),
+ ('line', 'func1', 2),
+ ('line', 'func1', 3)])
+
+ def test_c_call(self):
+
+ def func2():
+ line1 = 1
+ [].append(2)
+ line3 = 3
+
+ self.check_events(func2, recorders = MANY_RECORDERS, expected = [
+ ('line', 'func2', 1),
+ ('line', 'func2', 2),
+ ('call', 'append', [2]),
+ ('C return', 'append', [2]),
+ ('line', 'func2', 3)])
+
+ def test_try_except(self):
+
+ def func3():
+ try:
+ line = 2
+ raise KeyError
+ except:
+ line = 5
+ line = 6
+
+ self.check_events(func3, recorders = MANY_RECORDERS, expected = [
+ ('line', 'func3', 1),
+ ('line', 'func3', 2),
+ ('line', 'func3', 3),
+ ('raise', KeyError),
+ ('line', 'func3', 4),
+ ('line', 'func3', 5),
+ ('line', 'func3', 6)])
+
+
+def line_from_offset(code, offset):
+ for start, end, line in code.co_lines():
+ if start <= offset < end:
+ return line - code.co_firstlineno
+ return -1
+
+class JumpRecorder:
+
+ event_type = E.JUMP
+ name = "jump"
+
+ def __init__(self, events):
+ self.events = events
+
+ def __call__(self, code, from_, to):
+ from_line = line_from_offset(code, from_)
+ to_line = line_from_offset(code, to)
+ self.events.append((self.name, code.co_name, from_line, to_line))
+
+
+class BranchRecorder(JumpRecorder):
+
+ event_type = E.BRANCH
+ name = "branch"
+
+
+JUMP_AND_BRANCH_RECORDERS = JumpRecorder, BranchRecorder
+JUMP_BRANCH_AND_LINE_RECORDERS = JumpRecorder, BranchRecorder, LineRecorder
+
+class TestBranchAndJumpEvents(CheckEvents):
+ maxDiff = None
+
+ def test_loop(self):
+
+ def func():
+ x = 1
+ for a in range(2):
+ if a:
+ x = 4
+ else:
+ x = 6
+
+ self.check_events(func, recorders = JUMP_AND_BRANCH_RECORDERS, expected = [
+ ('branch', 'func', 2, 2),
+ ('branch', 'func', 3, 6),
+ ('jump', 'func', 6, 2),
+ ('branch', 'func', 2, 2),
+ ('branch', 'func', 3, 4),
+ ('jump', 'func', 4, 2),
+ ('branch', 'func', 2, 2)])
+
+
+ self.check_events(func, recorders = JUMP_BRANCH_AND_LINE_RECORDERS, expected = [
+ ('line', 'check_events', 10),
+ ('line', 'func', 1),
+ ('line', 'func', 2),
+ ('branch', 'func', 2, 2),
+ ('line', 'func', 3),
+ ('branch', 'func', 3, 6),
+ ('line', 'func', 6),
+ ('jump', 'func', 6, 2),
+ ('branch', 'func', 2, 2),
+ ('line', 'func', 3),
+ ('branch', 'func', 3, 4),
+ ('line', 'func', 4),
+ ('jump', 'func', 4, 2),
+ ('branch', 'func', 2, 2),
+ ('line', 'func', 2),
+ ('line', 'check_events', 11)])
+
+
+class TestSetGetEvents(MonitoringTestBase, unittest.TestCase):
+
+ def test_global(self):
+ sys.monitoring.set_events(TEST_TOOL, E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL2, E.PY_START)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), E.PY_START)
+ sys.monitoring.set_events(TEST_TOOL, 0)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL), 0)
+ sys.monitoring.set_events(TEST_TOOL2,0)
+ self.assertEqual(sys.monitoring.get_events(TEST_TOOL2), 0)
+
+ def test_local(self):
+ code = f1.__code__
+ sys.monitoring.set_local_events(TEST_TOOL, code, E.PY_START)
+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), E.PY_START)
+ sys.monitoring.set_local_events(TEST_TOOL2, code, E.PY_START)
+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), E.PY_START)
+ sys.monitoring.set_local_events(TEST_TOOL, code, 0)
+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, code), 0)
+ sys.monitoring.set_local_events(TEST_TOOL2, code, 0)
+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL2, code), 0)
+
+class TestUninitialized(unittest.TestCase, MonitoringTestBase):
+
+ @staticmethod
+ def f():
+ pass
+
+ def test_get_local_events_uninitialized(self):
+ self.assertEqual(sys.monitoring.get_local_events(TEST_TOOL, self.f.__code__), 0)
diff --git a/Lib/test/test_ntpath.py b/Lib/test/test_ntpath.py
index 4e755d15403916..0e57c165ca98ea 100644
--- a/Lib/test/test_ntpath.py
+++ b/Lib/test/test_ntpath.py
@@ -169,6 +169,7 @@ def test_splitroot(self):
# gh-81790: support device namespace, including UNC drives.
tester('ntpath.splitroot("//?/c:")', ("//?/c:", "", ""))
+ tester('ntpath.splitroot("//./c:")', ("//./c:", "", ""))
tester('ntpath.splitroot("//?/c:/")', ("//?/c:", "/", ""))
tester('ntpath.splitroot("//?/c:/dir")', ("//?/c:", "/", "dir"))
tester('ntpath.splitroot("//?/UNC")', ("//?/UNC", "", ""))
@@ -179,8 +180,12 @@ def test_splitroot(self):
tester('ntpath.splitroot("//?/VOLUME{00000000-0000-0000-0000-000000000000}/spam")',
('//?/VOLUME{00000000-0000-0000-0000-000000000000}', '/', 'spam'))
tester('ntpath.splitroot("//?/BootPartition/")', ("//?/BootPartition", "/", ""))
+ tester('ntpath.splitroot("//./BootPartition/")', ("//./BootPartition", "/", ""))
+ tester('ntpath.splitroot("//./PhysicalDrive0")', ("//./PhysicalDrive0", "", ""))
+ tester('ntpath.splitroot("//./nul")', ("//./nul", "", ""))
tester('ntpath.splitroot("\\\\?\\c:")', ("\\\\?\\c:", "", ""))
+ tester('ntpath.splitroot("\\\\.\\c:")', ("\\\\.\\c:", "", ""))
tester('ntpath.splitroot("\\\\?\\c:\\")', ("\\\\?\\c:", "\\", ""))
tester('ntpath.splitroot("\\\\?\\c:\\dir")', ("\\\\?\\c:", "\\", "dir"))
tester('ntpath.splitroot("\\\\?\\UNC")', ("\\\\?\\UNC", "", ""))
@@ -193,6 +198,9 @@ def test_splitroot(self):
tester('ntpath.splitroot("\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}\\spam")',
('\\\\?\\VOLUME{00000000-0000-0000-0000-000000000000}', '\\', 'spam'))
tester('ntpath.splitroot("\\\\?\\BootPartition\\")', ("\\\\?\\BootPartition", "\\", ""))
+ tester('ntpath.splitroot("\\\\.\\BootPartition\\")', ("\\\\.\\BootPartition", "\\", ""))
+ tester('ntpath.splitroot("\\\\.\\PhysicalDrive0")', ("\\\\.\\PhysicalDrive0", "", ""))
+ tester('ntpath.splitroot("\\\\.\\nul")', ("\\\\.\\nul", "", ""))
# gh-96290: support partial/invalid UNC drives
tester('ntpath.splitroot("//")', ("//", "", "")) # empty server & missing share
@@ -300,6 +308,11 @@ def test_join(self):
tester("ntpath.join('//computer/share', 'a', 'b')", '//computer/share\\a\\b')
tester("ntpath.join('//computer/share', 'a/b')", '//computer/share\\a/b')
+ tester("ntpath.join('\\\\', 'computer')", '\\\\computer')
+ tester("ntpath.join('\\\\computer\\', 'share')", '\\\\computer\\share')
+ tester("ntpath.join('\\\\computer\\share\\', 'a')", '\\\\computer\\share\\a')
+ tester("ntpath.join('\\\\computer\\share\\a\\', 'b')", '\\\\computer\\share\\a\\b')
+
def test_normpath(self):
tester("ntpath.normpath('A//////././//.//B')", r'A\B')
tester("ntpath.normpath('A/./B')", r'A\B')
diff --git a/Lib/test/test_opcache.py b/Lib/test/test_opcache.py
index e39b7260624899..57fed5d09fd7b8 100644
--- a/Lib/test/test_opcache.py
+++ b/Lib/test/test_opcache.py
@@ -1,6 +1,29 @@
import unittest
+class TestLoadSuperAttrCache(unittest.TestCase):
+ def test_descriptor_not_double_executed_on_spec_fail(self):
+ calls = []
+ class Descriptor:
+ def __get__(self, instance, owner):
+ calls.append((instance, owner))
+ return lambda: 1
+
+ class C:
+ d = Descriptor()
+
+ class D(C):
+ def f(self):
+ return super().d()
+
+ d = D()
+
+ self.assertEqual(d.f(), 1) # warmup
+ calls.clear()
+ self.assertEqual(d.f(), 1) # try to specialize
+ self.assertEqual(calls, [(d, D)])
+
+
class TestLoadAttrCache(unittest.TestCase):
def test_descriptor_added_after_optimization(self):
class Descriptor:
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index 8b6e012b730d75..76cfadeedcea84 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -24,116 +24,6 @@
grp = pwd = None
-class _BaseFlavourTest(object):
-
- def _check_parse_parts(self, arg, expected):
- def f(parts):
- path = self.cls(*parts)._raw_path
- return self.cls._parse_path(path)
- sep = self.flavour.sep
- altsep = self.flavour.altsep
- actual = f([x.replace('/', sep) for x in arg])
- self.assertEqual(actual, expected)
- if altsep:
- actual = f([x.replace('/', altsep) for x in arg])
- self.assertEqual(actual, expected)
-
- def test_parse_parts_common(self):
- check = self._check_parse_parts
- sep = self.flavour.sep
- # Unanchored parts.
- check([], ('', '', []))
- check(['a'], ('', '', ['a']))
- check(['a/'], ('', '', ['a']))
- check(['a', 'b'], ('', '', ['a', 'b']))
- # Expansion.
- check(['a/b'], ('', '', ['a', 'b']))
- check(['a/b/'], ('', '', ['a', 'b']))
- check(['a', 'b/c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
- # Collapsing and stripping excess slashes.
- check(['a', 'b//c', 'd'], ('', '', ['a', 'b', 'c', 'd']))
- check(['a', 'b/c/', 'd'], ('', '', ['a', 'b', 'c', 'd']))
- # Eliminating standalone dots.
- check(['.'], ('', '', []))
- check(['.', '.', 'b'], ('', '', ['b']))
- check(['a', '.', 'b'], ('', '', ['a', 'b']))
- check(['a', '.', '.'], ('', '', ['a']))
- # The first part is anchored.
- check(['/a/b'], ('', sep, [sep, 'a', 'b']))
- check(['/a', 'b'], ('', sep, [sep, 'a', 'b']))
- check(['/a/', 'b'], ('', sep, [sep, 'a', 'b']))
- # Ignoring parts before an anchored part.
- check(['a', '/b', 'c'], ('', sep, [sep, 'b', 'c']))
- check(['a', '/b', '/c'], ('', sep, [sep, 'c']))
-
-
-class PosixFlavourTest(_BaseFlavourTest, unittest.TestCase):
- cls = pathlib.PurePosixPath
- flavour = pathlib.PurePosixPath._flavour
-
- def test_parse_parts(self):
- check = self._check_parse_parts
- # Collapsing of excess leading slashes, except for the double-slash
- # special case.
- check(['//a', 'b'], ('', '//', ['//', 'a', 'b']))
- check(['///a', 'b'], ('', '/', ['/', 'a', 'b']))
- check(['////a', 'b'], ('', '/', ['/', 'a', 'b']))
- # Paths which look like NT paths aren't treated specially.
- check(['c:a'], ('', '', ['c:a']))
- check(['c:\\a'], ('', '', ['c:\\a']))
- check(['\\a'], ('', '', ['\\a']))
-
-
-class NTFlavourTest(_BaseFlavourTest, unittest.TestCase):
- cls = pathlib.PureWindowsPath
- flavour = pathlib.PureWindowsPath._flavour
-
- def test_parse_parts(self):
- check = self._check_parse_parts
- # First part is anchored.
- check(['c:'], ('c:', '', ['c:']))
- check(['c:/'], ('c:', '\\', ['c:\\']))
- check(['/'], ('', '\\', ['\\']))
- check(['c:a'], ('c:', '', ['c:', 'a']))
- check(['c:/a'], ('c:', '\\', ['c:\\', 'a']))
- check(['/a'], ('', '\\', ['\\', 'a']))
- # UNC paths.
- check(['//a/b'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
- check(['//a/b/'], ('\\\\a\\b', '\\', ['\\\\a\\b\\']))
- check(['//a/b/c'], ('\\\\a\\b', '\\', ['\\\\a\\b\\', 'c']))
- # Second part is anchored, so that the first part is ignored.
- check(['a', 'Z:b', 'c'], ('Z:', '', ['Z:', 'b', 'c']))
- check(['a', 'Z:/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
- # UNC paths.
- check(['a', '//b/c', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
- # Collapsing and stripping excess slashes.
- check(['a', 'Z://b//c/', 'd/'], ('Z:', '\\', ['Z:\\', 'b', 'c', 'd']))
- # UNC paths.
- check(['a', '//b/c//', 'd'], ('\\\\b\\c', '\\', ['\\\\b\\c\\', 'd']))
- # Extended paths.
- check(['//?/c:/'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\']))
- check(['//?/c:/a'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'a']))
- check(['//?/c:/a', '/b'], ('\\\\?\\c:', '\\', ['\\\\?\\c:\\', 'b']))
- # Extended UNC paths (format is "\\?\UNC\server\share").
- check(['//?/UNC/b/c'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\']))
- check(['//?/UNC/b/c/d'], ('\\\\?\\UNC\\b\\c', '\\', ['\\\\?\\UNC\\b\\c\\', 'd']))
- # Second part has a root but not drive.
- check(['a', '/b', 'c'], ('', '\\', ['\\', 'b', 'c']))
- check(['Z:/a', '/b', 'c'], ('Z:', '\\', ['Z:\\', 'b', 'c']))
- check(['//?/Z:/a', '/b', 'c'], ('\\\\?\\Z:', '\\', ['\\\\?\\Z:\\', 'b', 'c']))
- # Joining with the same drive => the first path is appended to if
- # the second path is relative.
- check(['c:/a/b', 'c:x/y'], ('c:', '\\', ['c:\\', 'a', 'b', 'x', 'y']))
- check(['c:/a/b', 'c:/x/y'], ('c:', '\\', ['c:\\', 'x', 'y']))
- # Paths to files with NTFS alternate data streams
- check(['./c:s'], ('', '', ['c:s']))
- check(['cc:s'], ('', '', ['cc:s']))
- check(['C:c:s'], ('C:', '', ['C:', 'c:s']))
- check(['C:/c:s'], ('C:', '\\', ['C:\\', 'c:s']))
- check(['D:a', './c:b'], ('D:', '', ['D:', 'a', 'c:b']))
- check(['D:/a', './c:b'], ('D:', '\\', ['D:\\', 'a', 'c:b']))
-
-
#
# Tests for the pure classes.
#
@@ -246,6 +136,46 @@ class P(_BasePurePathSubclass, self.cls):
for parent in p.parents:
self.assertTrue(parent.init_called)
+ def _get_drive_root_parts(self, parts):
+ path = self.cls(*parts)
+ return path.drive, path.root, path.parts
+
+ def _check_drive_root_parts(self, arg, *expected):
+ sep = self.flavour.sep
+ actual = self._get_drive_root_parts([x.replace('/', sep) for x in arg])
+ self.assertEqual(actual, expected)
+ if altsep := self.flavour.altsep:
+ actual = self._get_drive_root_parts([x.replace('/', altsep) for x in arg])
+ self.assertEqual(actual, expected)
+
+ def test_drive_root_parts_common(self):
+ check = self._check_drive_root_parts
+ sep = self.flavour.sep
+ # Unanchored parts.
+ check((), '', '', ())
+ check(('a',), '', '', ('a',))
+ check(('a/',), '', '', ('a',))
+ check(('a', 'b'), '', '', ('a', 'b'))
+ # Expansion.
+ check(('a/b',), '', '', ('a', 'b'))
+ check(('a/b/',), '', '', ('a', 'b'))
+ check(('a', 'b/c', 'd'), '', '', ('a', 'b', 'c', 'd'))
+ # Collapsing and stripping excess slashes.
+ check(('a', 'b//c', 'd'), '', '', ('a', 'b', 'c', 'd'))
+ check(('a', 'b/c/', 'd'), '', '', ('a', 'b', 'c', 'd'))
+ # Eliminating standalone dots.
+ check(('.',), '', '', ())
+ check(('.', '.', 'b'), '', '', ('b',))
+ check(('a', '.', 'b'), '', '', ('a', 'b'))
+ check(('a', '.', '.'), '', '', ('a',))
+ # The first part is anchored.
+ check(('/a/b',), '', sep, (sep, 'a', 'b'))
+ check(('/a', 'b'), '', sep, (sep, 'a', 'b'))
+ check(('/a/', 'b'), '', sep, (sep, 'a', 'b'))
+ # Ignoring parts before an anchored part.
+ check(('a', '/b', 'c'), '', sep, (sep, 'b', 'c'))
+ check(('a', '/b', '/c'), '', sep, (sep, 'c'))
+
def test_join_common(self):
P = self.cls
p = P('a/b')
@@ -416,8 +346,6 @@ def test_parts_common(self):
p = P('a/b')
parts = p.parts
self.assertEqual(parts, ('a', 'b'))
- # The object gets reused.
- self.assertIs(parts, p.parts)
# When the path is absolute, the anchor is a separate part.
p = P('/a/b')
parts = p.parts
@@ -770,6 +698,18 @@ def test_pickling_common(self):
class PurePosixPathTest(_BasePurePathTest, unittest.TestCase):
cls = pathlib.PurePosixPath
+ def test_drive_root_parts(self):
+ check = self._check_drive_root_parts
+ # Collapsing of excess leading slashes, except for the double-slash
+ # special case.
+ check(('//a', 'b'), '', '//', ('//', 'a', 'b'))
+ check(('///a', 'b'), '', '/', ('/', 'a', 'b'))
+ check(('////a', 'b'), '', '/', ('/', 'a', 'b'))
+ # Paths which look like NT paths aren't treated specially.
+ check(('c:a',), '', '', ('c:a',))
+ check(('c:\\a',), '', '', ('c:\\a',))
+ check(('\\a',), '', '', ('\\a',))
+
def test_root(self):
P = self.cls
self.assertEqual(P('/a/b').root, '/')
@@ -860,6 +800,68 @@ class PureWindowsPathTest(_BasePurePathTest, unittest.TestCase):
],
})
+ def test_drive_root_parts(self):
+ check = self._check_drive_root_parts
+ # First part is anchored.
+ check(('c:',), 'c:', '', ('c:',))
+ check(('c:/',), 'c:', '\\', ('c:\\',))
+ check(('/',), '', '\\', ('\\',))
+ check(('c:a',), 'c:', '', ('c:', 'a'))
+ check(('c:/a',), 'c:', '\\', ('c:\\', 'a'))
+ check(('/a',), '', '\\', ('\\', 'a'))
+ # UNC paths.
+ check(('//',), '\\\\', '', ('\\\\',))
+ check(('//a',), '\\\\a', '', ('\\\\a',))
+ check(('//a/',), '\\\\a\\', '', ('\\\\a\\',))
+ check(('//a/b',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
+ check(('//a/b/',), '\\\\a\\b', '\\', ('\\\\a\\b\\',))
+ check(('//a/b/c',), '\\\\a\\b', '\\', ('\\\\a\\b\\', 'c'))
+ # Second part is anchored, so that the first part is ignored.
+ check(('a', 'Z:b', 'c'), 'Z:', '', ('Z:', 'b', 'c'))
+ check(('a', 'Z:/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c'))
+ # UNC paths.
+ check(('a', '//b/c', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd'))
+ # Collapsing and stripping excess slashes.
+ check(('a', 'Z://b//c/', 'd/'), 'Z:', '\\', ('Z:\\', 'b', 'c', 'd'))
+ # UNC paths.
+ check(('a', '//b/c//', 'd'), '\\\\b\\c', '\\', ('\\\\b\\c\\', 'd'))
+ # Extended paths.
+ check(('//./c:',), '\\\\.\\c:', '', ('\\\\.\\c:',))
+ check(('//?/c:/',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\',))
+ check(('//?/c:/a',), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'a'))
+ check(('//?/c:/a', '/b'), '\\\\?\\c:', '\\', ('\\\\?\\c:\\', 'b'))
+ # Extended UNC paths (format is "\\?\UNC\server\share").
+ check(('//?',), '\\\\?', '', ('\\\\?',))
+ check(('//?/',), '\\\\?\\', '', ('\\\\?\\',))
+ check(('//?/UNC',), '\\\\?\\UNC', '', ('\\\\?\\UNC',))
+ check(('//?/UNC/',), '\\\\?\\UNC\\', '', ('\\\\?\\UNC\\',))
+ check(('//?/UNC/b',), '\\\\?\\UNC\\b', '', ('\\\\?\\UNC\\b',))
+ check(('//?/UNC/b/',), '\\\\?\\UNC\\b\\', '', ('\\\\?\\UNC\\b\\',))
+ check(('//?/UNC/b/c',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
+ check(('//?/UNC/b/c/',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\',))
+ check(('//?/UNC/b/c/d',), '\\\\?\\UNC\\b\\c', '\\', ('\\\\?\\UNC\\b\\c\\', 'd'))
+ # UNC device paths
+ check(('//./BootPartition/',), '\\\\.\\BootPartition', '\\', ('\\\\.\\BootPartition\\',))
+ check(('//?/BootPartition/',), '\\\\?\\BootPartition', '\\', ('\\\\?\\BootPartition\\',))
+ check(('//./PhysicalDrive0',), '\\\\.\\PhysicalDrive0', '', ('\\\\.\\PhysicalDrive0',))
+ check(('//?/Volume{}/',), '\\\\?\\Volume{}', '\\', ('\\\\?\\Volume{}\\',))
+ check(('//./nul',), '\\\\.\\nul', '', ('\\\\.\\nul',))
+ # Second part has a root but not drive.
+ check(('a', '/b', 'c'), '', '\\', ('\\', 'b', 'c'))
+ check(('Z:/a', '/b', 'c'), 'Z:', '\\', ('Z:\\', 'b', 'c'))
+ check(('//?/Z:/a', '/b', 'c'), '\\\\?\\Z:', '\\', ('\\\\?\\Z:\\', 'b', 'c'))
+ # Joining with the same drive => the first path is appended to if
+ # the second path is relative.
+ check(('c:/a/b', 'c:x/y'), 'c:', '\\', ('c:\\', 'a', 'b', 'x', 'y'))
+ check(('c:/a/b', 'c:/x/y'), 'c:', '\\', ('c:\\', 'x', 'y'))
+ # Paths to files with NTFS alternate data streams
+ check(('./c:s',), '', '', ('c:s',))
+ check(('cc:s',), '', '', ('cc:s',))
+ check(('C:c:s',), 'C:', '', ('C:', 'c:s'))
+ check(('C:/c:s',), 'C:', '\\', ('C:\\', 'c:s'))
+ check(('D:a', './c:b'), 'D:', '', ('D:', 'a', 'c:b'))
+ check(('D:/a', './c:b'), 'D:', '\\', ('D:\\', 'a', 'c:b'))
+
def test_str(self):
p = self.cls('a/b/c')
self.assertEqual(str(p), 'a\\b\\c')
@@ -1386,6 +1388,13 @@ def test_join(self):
self.assertEqual(pp, P('C:/a/b/dd:s'))
pp = p.joinpath(P('E:d:s'))
self.assertEqual(pp, P('E:d:s'))
+ # Joining onto a UNC path with no root
+ pp = P('//').joinpath('server')
+ self.assertEqual(pp, P('//server'))
+ pp = P('//server').joinpath('share')
+ self.assertEqual(pp, P('//server/share'))
+ pp = P('//./BootPartition').joinpath('Windows')
+ self.assertEqual(pp, P('//./BootPartition/Windows'))
def test_div(self):
# Basically the same as joinpath().
@@ -2693,20 +2702,20 @@ def setUp(self):
del self.sub2_tree[1][:1]
def test_walk_topdown(self):
- all = list(self.walk_path.walk())
-
- self.assertEqual(len(all), 4)
- # We can't know which order SUB1 and SUB2 will appear in.
- # Not flipped: TESTFN, SUB1, SUB11, SUB2
- # flipped: TESTFN, SUB2, SUB1, SUB11
- flipped = all[0][1][0] != "SUB1"
- all[0][1].sort()
- all[3 - 2 * flipped][-1].sort()
- all[3 - 2 * flipped][1].sort()
- self.assertEqual(all[0], (self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
- self.assertEqual(all[1 + flipped], (self.sub1_path, ["SUB11"], ["tmp2"]))
- self.assertEqual(all[2 + flipped], (self.sub11_path, [], []))
- self.assertEqual(all[3 - 2 * flipped], self.sub2_tree)
+ walker = self.walk_path.walk()
+ entry = next(walker)
+ entry[1].sort() # Ensure we visit SUB1 before SUB2
+ self.assertEqual(entry, (self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
+ entry = next(walker)
+ self.assertEqual(entry, (self.sub1_path, ["SUB11"], ["tmp2"]))
+ entry = next(walker)
+ self.assertEqual(entry, (self.sub11_path, [], []))
+ entry = next(walker)
+ entry[1].sort()
+ entry[2].sort()
+ self.assertEqual(entry, self.sub2_tree)
+ with self.assertRaises(StopIteration):
+ next(walker)
def test_walk_prune(self, walk_path=None):
if walk_path is None:
@@ -2730,24 +2739,37 @@ def test_file_like_path(self):
self.test_walk_prune(FakePath(self.walk_path).__fspath__())
def test_walk_bottom_up(self):
- all = list(self.walk_path.walk( top_down=False))
-
- self.assertEqual(len(all), 4, all)
- # We can't know which order SUB1 and SUB2 will appear in.
- # Not flipped: SUB11, SUB1, SUB2, TESTFN
- # flipped: SUB2, SUB11, SUB1, TESTFN
- flipped = all[3][1][0] != "SUB1"
- all[3][1].sort()
- all[2 - 2 * flipped][-1].sort()
- all[2 - 2 * flipped][1].sort()
- self.assertEqual(all[3],
- (self.walk_path, ["SUB1", "SUB2"], ["tmp1"]))
- self.assertEqual(all[flipped],
- (self.sub11_path, [], []))
- self.assertEqual(all[flipped + 1],
- (self.sub1_path, ["SUB11"], ["tmp2"]))
- self.assertEqual(all[2 - 2 * flipped],
- self.sub2_tree)
+ seen_testfn = seen_sub1 = seen_sub11 = seen_sub2 = False
+ for path, dirnames, filenames in self.walk_path.walk(top_down=False):
+ if path == self.walk_path:
+ self.assertFalse(seen_testfn)
+ self.assertTrue(seen_sub1)
+ self.assertTrue(seen_sub2)
+ self.assertEqual(sorted(dirnames), ["SUB1", "SUB2"])
+ self.assertEqual(filenames, ["tmp1"])
+ seen_testfn = True
+ elif path == self.sub1_path:
+ self.assertFalse(seen_testfn)
+ self.assertFalse(seen_sub1)
+ self.assertTrue(seen_sub11)
+ self.assertEqual(dirnames, ["SUB11"])
+ self.assertEqual(filenames, ["tmp2"])
+ seen_sub1 = True
+ elif path == self.sub11_path:
+ self.assertFalse(seen_sub1)
+ self.assertFalse(seen_sub11)
+ self.assertEqual(dirnames, [])
+ self.assertEqual(filenames, [])
+ seen_sub11 = True
+ elif path == self.sub2_path:
+ self.assertFalse(seen_testfn)
+ self.assertFalse(seen_sub2)
+ self.assertEqual(sorted(dirnames), sorted(self.sub2_tree[1]))
+ self.assertEqual(sorted(filenames), sorted(self.sub2_tree[2]))
+ seen_sub2 = True
+ else:
+ raise AssertionError(f"Unexpected path: {path}")
+ self.assertTrue(seen_testfn)
@os_helper.skip_unless_symlink
def test_walk_follow_symlinks(self):
diff --git a/Lib/test/test_pdb.py b/Lib/test/test_pdb.py
index 9ad9a1c52ac102..b5c413af344c93 100644
--- a/Lib/test/test_pdb.py
+++ b/Lib/test/test_pdb.py
@@ -1700,6 +1700,26 @@ def test_pdb_issue_gh_103225():
(Pdb) continue
"""
+def test_pdb_issue_gh_101517():
+ """See GH-101517
+
+ Make sure pdb doesn't crash when the exception is caught in a try/except* block
+
+ >>> def test_function():
+ ... try:
+ ... raise KeyError
+ ... except* Exception as e:
+ ... import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
+
+ >>> with PdbTestInput([ # doctest: +NORMALIZE_WHITESPACE
+ ... 'continue'
+ ... ]):
+ ... test_function()
+ > (5)test_function()
+ -> import pdb; pdb.Pdb(nosigint=True, readrc=False).set_trace()
+ (Pdb) continue
+ """
+
@support.requires_subprocess()
class PdbTestCase(unittest.TestCase):
diff --git a/Lib/test/test_peepholer.py b/Lib/test/test_peepholer.py
index 01eb04b53060e9..bf7fc421a9df0a 100644
--- a/Lib/test/test_peepholer.py
+++ b/Lib/test/test_peepholer.py
@@ -810,7 +810,7 @@ def f():
self.assertInBytecode(f, 'LOAD_FAST', "a73")
def test_setting_lineno_no_undefined(self):
- code = textwrap.dedent(f"""\
+ code = textwrap.dedent("""\
def f():
x = y = 2
if not x:
@@ -842,7 +842,7 @@ def trace(frame, event, arg):
self.assertEqual(f.__code__.co_code, co_code)
def test_setting_lineno_one_undefined(self):
- code = textwrap.dedent(f"""\
+ code = textwrap.dedent("""\
def f():
x = y = 2
if not x:
@@ -876,7 +876,7 @@ def trace(frame, event, arg):
self.assertEqual(f.__code__.co_code, co_code)
def test_setting_lineno_two_undefined(self):
- code = textwrap.dedent(f"""\
+ code = textwrap.dedent("""\
def f():
x = y = 2
if not x:
diff --git a/Lib/test/test_posix.py b/Lib/test/test_posix.py
index 77f42f7f9c937b..444f8abe4607b7 100644
--- a/Lib/test/test_posix.py
+++ b/Lib/test/test_posix.py
@@ -231,6 +231,9 @@ def test_register_at_fork(self):
with self.assertRaises(TypeError, msg="Invalid arg was allowed"):
# Ensure a combination of valid and invalid is an error.
os.register_at_fork(before=None, after_in_parent=lambda: 3)
+ with self.assertRaises(TypeError, msg="At least one argument is required"):
+ # when no arg is passed
+ os.register_at_fork()
with self.assertRaises(TypeError, msg="Invalid arg was allowed"):
# Ensure a combination of valid and invalid is an error.
os.register_at_fork(before=lambda: None, after_in_child='')
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 9eaf167a9fa3c9..36f0b8a31a3715 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -33,6 +33,7 @@
from test import support
from test.support import os_helper
from test.support.os_helper import TESTFN, FakePath
+from test.support import warnings_helper
TESTFN2 = TESTFN + "2"
TESTFN_SRC = TESTFN + "_SRC"
@@ -1841,12 +1842,14 @@ def test_register_archive_format(self):
### shutil.unpack_archive
- def check_unpack_archive(self, format):
- self.check_unpack_archive_with_converter(format, lambda path: path)
- self.check_unpack_archive_with_converter(format, pathlib.Path)
- self.check_unpack_archive_with_converter(format, FakePath)
+ def check_unpack_archive(self, format, **kwargs):
+ self.check_unpack_archive_with_converter(
+ format, lambda path: path, **kwargs)
+ self.check_unpack_archive_with_converter(
+ format, pathlib.Path, **kwargs)
+ self.check_unpack_archive_with_converter(format, FakePath, **kwargs)
- def check_unpack_archive_with_converter(self, format, converter):
+ def check_unpack_archive_with_converter(self, format, converter, **kwargs):
root_dir, base_dir = self._create_files()
expected = rlistdir(root_dir)
expected.remove('outer')
@@ -1856,36 +1859,48 @@ def check_unpack_archive_with_converter(self, format, converter):
# let's try to unpack it now
tmpdir2 = self.mkdtemp()
- unpack_archive(converter(filename), converter(tmpdir2))
+ unpack_archive(converter(filename), converter(tmpdir2), **kwargs)
self.assertEqual(rlistdir(tmpdir2), expected)
# and again, this time with the format specified
tmpdir3 = self.mkdtemp()
- unpack_archive(converter(filename), converter(tmpdir3), format=format)
+ unpack_archive(converter(filename), converter(tmpdir3), format=format,
+ **kwargs)
self.assertEqual(rlistdir(tmpdir3), expected)
- self.assertRaises(shutil.ReadError, unpack_archive, converter(TESTFN))
- self.assertRaises(ValueError, unpack_archive, converter(TESTFN), format='xxx')
+ with self.assertRaises(shutil.ReadError):
+ unpack_archive(converter(TESTFN), **kwargs)
+ with self.assertRaises(ValueError):
+ unpack_archive(converter(TESTFN), format='xxx', **kwargs)
+
+ def check_unpack_tarball(self, format):
+ self.check_unpack_archive(format, filter='fully_trusted')
+ self.check_unpack_archive(format, filter='data')
+ with warnings_helper.check_warnings(
+ ('Python 3.14', DeprecationWarning)):
+ self.check_unpack_archive(format)
def test_unpack_archive_tar(self):
- self.check_unpack_archive('tar')
+ self.check_unpack_tarball('tar')
@support.requires_zlib()
def test_unpack_archive_gztar(self):
- self.check_unpack_archive('gztar')
+ self.check_unpack_tarball('gztar')
@support.requires_bz2()
def test_unpack_archive_bztar(self):
- self.check_unpack_archive('bztar')
+ self.check_unpack_tarball('bztar')
@support.requires_lzma()
@unittest.skipIf(AIX and not _maxdataOK(), "AIX MAXDATA must be 0x20000000 or larger")
def test_unpack_archive_xztar(self):
- self.check_unpack_archive('xztar')
+ self.check_unpack_tarball('xztar')
@support.requires_zlib()
def test_unpack_archive_zip(self):
self.check_unpack_archive('zip')
+ with self.assertRaises(TypeError):
+ self.check_unpack_archive('zip', filter='data')
def test_unpack_registry(self):
diff --git a/Lib/test/test_socket.py b/Lib/test/test_socket.py
index 32252f7b741fda..bb7bf436d2d721 100644
--- a/Lib/test/test_socket.py
+++ b/Lib/test/test_socket.py
@@ -8,6 +8,7 @@
import array
import contextlib
import errno
+import gc
import io
import itertools
import math
@@ -836,6 +837,12 @@ def requireSocket(*args):
class GeneralModuleTests(unittest.TestCase):
+ @unittest.skipUnless(_socket is not None, 'need _socket module')
+ def test_socket_type(self):
+ self.assertTrue(gc.is_tracked(_socket.socket))
+ with self.assertRaisesRegex(TypeError, "immutable"):
+ _socket.socket.foo = 1
+
def test_SocketType_is_socketobject(self):
import _socket
self.assertTrue(socket.SocketType is _socket.socket)
diff --git a/Lib/test/test_socketserver.py b/Lib/test/test_socketserver.py
index 2fa5069423327a..c81d559cde315d 100644
--- a/Lib/test/test_socketserver.py
+++ b/Lib/test/test_socketserver.py
@@ -47,16 +47,8 @@ def receive(sock, n, timeout=test.support.SHORT_TIMEOUT):
else:
raise RuntimeError("timed out on %r" % (sock,))
-if HAVE_UNIX_SOCKETS and HAVE_FORKING:
- class ForkingUnixStreamServer(socketserver.ForkingMixIn,
- socketserver.UnixStreamServer):
- pass
-
- class ForkingUnixDatagramServer(socketserver.ForkingMixIn,
- socketserver.UnixDatagramServer):
- pass
-
+@test.support.requires_fork()
@contextlib.contextmanager
def simple_subprocess(testcase):
"""Tests that a custom child process is not waited on (Issue 1540386)"""
@@ -211,7 +203,7 @@ def test_ThreadingUnixStreamServer(self):
@requires_forking
def test_ForkingUnixStreamServer(self):
with simple_subprocess(self):
- self.run_server(ForkingUnixStreamServer,
+ self.run_server(socketserver.ForkingUnixStreamServer,
socketserver.StreamRequestHandler,
self.stream_examine)
@@ -247,7 +239,7 @@ def test_ThreadingUnixDatagramServer(self):
@requires_unix_sockets
@requires_forking
def test_ForkingUnixDatagramServer(self):
- self.run_server(ForkingUnixDatagramServer,
+ self.run_server(socketserver.ForkingUnixDatagramServer,
socketserver.DatagramRequestHandler,
self.dgram_examine)
diff --git a/Lib/test/test_sqlite3/test_regression.py b/Lib/test/test_sqlite3/test_regression.py
index ad83a97c8c40d6..7e8221e7227e6e 100644
--- a/Lib/test/test_sqlite3/test_regression.py
+++ b/Lib/test/test_sqlite3/test_regression.py
@@ -491,21 +491,21 @@ def tearDown(self):
def test_recursive_cursor_init(self):
conv = lambda x: self.cur.__init__(self.con)
with patch.dict(sqlite.converters, {"INIT": conv}):
- self.cur.execute(f'select x as "x [INIT]", x from test')
+ self.cur.execute('select x as "x [INIT]", x from test')
self.assertRaisesRegex(sqlite.ProgrammingError, self.msg,
self.cur.fetchall)
def test_recursive_cursor_close(self):
conv = lambda x: self.cur.close()
with patch.dict(sqlite.converters, {"CLOSE": conv}):
- self.cur.execute(f'select x as "x [CLOSE]", x from test')
+ self.cur.execute('select x as "x [CLOSE]", x from test')
self.assertRaisesRegex(sqlite.ProgrammingError, self.msg,
self.cur.fetchall)
def test_recursive_cursor_iter(self):
conv = lambda x, l=[]: self.cur.fetchone() if l else l.append(None)
with patch.dict(sqlite.converters, {"ITER": conv}):
- self.cur.execute(f'select x as "x [ITER]", x from test')
+ self.cur.execute('select x as "x [ITER]", x from test')
self.assertRaisesRegex(sqlite.ProgrammingError, self.msg,
self.cur.fetchall)
diff --git a/Lib/test/test_sqlite3/test_userfunctions.py b/Lib/test/test_sqlite3/test_userfunctions.py
index 0970b0378ad615..632d657d416fd4 100644
--- a/Lib/test/test_sqlite3/test_userfunctions.py
+++ b/Lib/test/test_sqlite3/test_userfunctions.py
@@ -562,7 +562,7 @@ def test_win_exception_in_finalize(self):
# callback errors to sqlite3_step(); this implies that OperationalError
# is _not_ raised.
with patch.object(WindowSumInt, "finalize", side_effect=BadWindow):
- name = f"exception_in_finalize"
+ name = "exception_in_finalize"
self.con.create_window_function(name, 1, WindowSumInt)
self.cur.execute(self.query % name)
self.cur.fetchall()
diff --git a/Lib/test/test_subclassinit.py b/Lib/test/test_subclassinit.py
index 0ad7d17fbd4ddd..310473a4a2fe58 100644
--- a/Lib/test/test_subclassinit.py
+++ b/Lib/test/test_subclassinit.py
@@ -134,30 +134,28 @@ class Descriptor:
def __set_name__(self, owner, name):
1/0
- with self.assertRaises(RuntimeError) as cm:
+ with self.assertRaises(ZeroDivisionError) as cm:
class NotGoingToWork:
attr = Descriptor()
- exc = cm.exception
- self.assertRegex(str(exc), r'\bNotGoingToWork\b')
- self.assertRegex(str(exc), r'\battr\b')
- self.assertRegex(str(exc), r'\bDescriptor\b')
- self.assertIsInstance(exc.__cause__, ZeroDivisionError)
+ notes = cm.exception.__notes__
+ self.assertRegex(str(notes), r'\bNotGoingToWork\b')
+ self.assertRegex(str(notes), r'\battr\b')
+ self.assertRegex(str(notes), r'\bDescriptor\b')
def test_set_name_wrong(self):
class Descriptor:
def __set_name__(self):
pass
- with self.assertRaises(RuntimeError) as cm:
+ with self.assertRaises(TypeError) as cm:
class NotGoingToWork:
attr = Descriptor()
- exc = cm.exception
- self.assertRegex(str(exc), r'\bNotGoingToWork\b')
- self.assertRegex(str(exc), r'\battr\b')
- self.assertRegex(str(exc), r'\bDescriptor\b')
- self.assertIsInstance(exc.__cause__, TypeError)
+ notes = cm.exception.__notes__
+ self.assertRegex(str(notes), r'\bNotGoingToWork\b')
+ self.assertRegex(str(notes), r'\battr\b')
+ self.assertRegex(str(notes), r'\bDescriptor\b')
def test_set_name_lookup(self):
resolved = []
diff --git a/Lib/test/test_super.py b/Lib/test/test_super.py
index a68b38cf79d537..ed773a3cff2a6d 100644
--- a/Lib/test/test_super.py
+++ b/Lib/test/test_super.py
@@ -1,6 +1,8 @@
"""Unit tests for zero-argument super() & related machinery."""
import unittest
+from unittest.mock import patch
+from test import shadowed_super
class A:
@@ -283,17 +285,28 @@ def f(self):
def test_obscure_super_errors(self):
def f():
super()
- self.assertRaises(RuntimeError, f)
+ with self.assertRaisesRegex(RuntimeError, r"no arguments"):
+ f()
+
+ class C:
+ def f():
+ super()
+ with self.assertRaisesRegex(RuntimeError, r"no arguments"):
+ C.f()
+
def f(x):
del x
super()
- self.assertRaises(RuntimeError, f, None)
+ with self.assertRaisesRegex(RuntimeError, r"arg\[0\] deleted"):
+ f(None)
+
class X:
def f(x):
nonlocal __class__
del __class__
super()
- self.assertRaises(RuntimeError, X().f)
+ with self.assertRaisesRegex(RuntimeError, r"empty __class__ cell"):
+ X().f()
def test_cell_as_self(self):
class X:
@@ -325,6 +338,78 @@ def test_super_argtype(self):
with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
super(1, int)
+ def test_shadowed_global(self):
+ self.assertEqual(shadowed_super.C().method(), "truly super")
+
+ def test_shadowed_local(self):
+ class super:
+ msg = "quite super"
+
+ class C:
+ def method(self):
+ return super().msg
+
+ self.assertEqual(C().method(), "quite super")
+
+ def test_shadowed_dynamic(self):
+ class MySuper:
+ msg = "super super"
+
+ class C:
+ def method(self):
+ return super().msg
+
+ with patch("test.test_super.super", MySuper) as m:
+ self.assertEqual(C().method(), "super super")
+
+ def test_shadowed_dynamic_two_arg(self):
+ call_args = []
+ class MySuper:
+ def __init__(self, *args):
+ call_args.append(args)
+ msg = "super super"
+
+ class C:
+ def method(self):
+ return super(1, 2).msg
+
+ with patch("test.test_super.super", MySuper) as m:
+ self.assertEqual(C().method(), "super super")
+ self.assertEqual(call_args, [(1, 2)])
+
+ def test_attribute_error(self):
+ class C:
+ def method(self):
+ return super().msg
+
+ with self.assertRaisesRegex(AttributeError, "'super' object has no attribute 'msg'"):
+ C().method()
+
+ def test_bad_first_arg(self):
+ class C:
+ def method(self):
+ return super(1, self).method()
+
+ with self.assertRaisesRegex(TypeError, "argument 1 must be a type"):
+ C().method()
+
+ def test_super___class__(self):
+ class C:
+ def method(self):
+ return super().__class__
+
+ self.assertEqual(C().method(), super)
+
+ def test_super_subclass___class__(self):
+ class mysuper(super):
+ pass
+
+ class C:
+ def method(self):
+ return mysuper(C, self).__class__
+
+ self.assertEqual(C().method(), mysuper)
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_syntax.py b/Lib/test/test_syntax.py
index f23653558a9119..f959bbb4400702 100644
--- a/Lib/test/test_syntax.py
+++ b/Lib/test/test_syntax.py
@@ -1853,6 +1853,30 @@ def f(x: *b)
Traceback (most recent call last):
...
SyntaxError: invalid syntax
+
+Invalid bytes literals:
+
+ >>> b"Ā"
+ Traceback (most recent call last):
+ ...
+ b"Ā"
+ ^^^
+ SyntaxError: bytes can only contain ASCII literal characters
+
+ >>> b"абвгде"
+ Traceback (most recent call last):
+ ...
+ b"абвгде"
+ ^^^^^^^^
+ SyntaxError: bytes can only contain ASCII literal characters
+
+ >>> b"abc ъющый" # first 3 letters are ascii
+ Traceback (most recent call last):
+ ...
+ b"abc ъющый"
+ ^^^^^^^^^^^
+ SyntaxError: bytes can only contain ASCII literal characters
+
"""
import re
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 4d172b742b934a..64af630aa26f34 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -385,7 +385,8 @@ def test_refcount(self):
self.assertRaises(TypeError, sys.getrefcount)
c = sys.getrefcount(None)
n = None
- self.assertEqual(sys.getrefcount(None), c+1)
+ # Singleton refcnts don't change
+ self.assertEqual(sys.getrefcount(None), c)
del n
self.assertEqual(sys.getrefcount(None), c)
if hasattr(sys, "gettotalrefcount"):
@@ -532,13 +533,13 @@ def g456():
main_id = threading.get_ident()
self.assertIn(main_id, d)
self.assertIn(thread_id, d)
- self.assertEqual((None, None, None), d.pop(main_id))
+ self.assertEqual(None, d.pop(main_id))
# Verify that the captured thread frame is blocked in g456, called
# from f123. This is a little tricky, since various bits of
# threading.py are also in the thread's call stack.
- exc_type, exc_value, exc_tb = d.pop(thread_id)
- stack = traceback.extract_stack(exc_tb.tb_frame)
+ exc_value = d.pop(thread_id)
+ stack = traceback.extract_stack(exc_value.__traceback__.tb_frame)
for i, (filename, lineno, funcname, sourceline) in enumerate(stack):
if funcname == "f123":
break
@@ -1445,7 +1446,7 @@ class C(object): pass
def func():
return sys._getframe()
x = func()
- check(x, size('3Pi3c7P2ic??2P'))
+ check(x, size('3Pii3c7P2ic??2P'))
# function
def func(): pass
check(func, size('15Pi'))
diff --git a/Lib/test/test_sys_settrace.py b/Lib/test/test_sys_settrace.py
index 4907c930e143d5..980321e169b9e5 100644
--- a/Lib/test/test_sys_settrace.py
+++ b/Lib/test/test_sys_settrace.py
@@ -2808,5 +2808,65 @@ def foo(*args):
sys.settrace(sys.gettrace())
+class TestLinesAfterTraceStarted(TraceTestCase):
+
+ def test_events(self):
+ tracer = Tracer()
+ sys._getframe().f_trace = tracer.trace
+ sys.settrace(tracer.trace)
+ line = 4
+ line = 5
+ sys.settrace(None)
+ self.compare_events(
+ TestLinesAfterTraceStarted.test_events.__code__.co_firstlineno,
+ tracer.events, [
+ (4, 'line'),
+ (5, 'line'),
+ (6, 'line')])
+
+
+class TestSetLocalTrace(TraceTestCase):
+
+ def test_with_branches(self):
+
+ def tracefunc(frame, event, arg):
+ if frame.f_code.co_name == "func":
+ frame.f_trace = tracefunc
+ line = frame.f_lineno - frame.f_code.co_firstlineno
+ events.append((line, event))
+ return tracefunc
+
+ def func(arg = 1):
+ N = 1
+ if arg >= 2:
+ not_reached = 3
+ else:
+ reached = 5
+ if arg >= 3:
+ not_reached = 7
+ else:
+ reached = 9
+ the_end = 10
+
+ EXPECTED_EVENTS = [
+ (0, 'call'),
+ (1, 'line'),
+ (2, 'line'),
+ (5, 'line'),
+ (6, 'line'),
+ (9, 'line'),
+ (10, 'line'),
+ (10, 'return'),
+ ]
+
+ events = []
+ sys.settrace(tracefunc)
+ sys._getframe().f_trace = tracefunc
+ func()
+ self.assertEqual(events, EXPECTED_EVENTS)
+ sys.settrace(None)
+
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Lib/test/test_tarfile.py b/Lib/test/test_tarfile.py
index 39f6f499c818ef..e8d322d20a5a8e 100644
--- a/Lib/test/test_tarfile.py
+++ b/Lib/test/test_tarfile.py
@@ -2,9 +2,13 @@
import os
import io
from hashlib import sha256
-from contextlib import contextmanager
+from contextlib import contextmanager, ExitStack
from random import Random
import pathlib
+import shutil
+import re
+import warnings
+import stat
import unittest
import unittest.mock
@@ -13,6 +17,7 @@
from test import support
from test.support import os_helper
from test.support import script_helper
+from test.support import warnings_helper
# Check for our compression modules.
try:
@@ -108,7 +113,7 @@ def test_fileobj_regular_file(self):
"regular file extraction failed")
def test_fileobj_readlines(self):
- self.tar.extract("ustar/regtype", TEMPDIR)
+ self.tar.extract("ustar/regtype", TEMPDIR, filter='data')
tarinfo = self.tar.getmember("ustar/regtype")
with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1:
lines1 = fobj1.readlines()
@@ -126,7 +131,7 @@ def test_fileobj_readlines(self):
"fileobj.readlines() failed")
def test_fileobj_iter(self):
- self.tar.extract("ustar/regtype", TEMPDIR)
+ self.tar.extract("ustar/regtype", TEMPDIR, filter='data')
tarinfo = self.tar.getmember("ustar/regtype")
with open(os.path.join(TEMPDIR, "ustar/regtype"), "r") as fobj1:
lines1 = fobj1.readlines()
@@ -136,7 +141,8 @@ def test_fileobj_iter(self):
"fileobj.__iter__() failed")
def test_fileobj_seek(self):
- self.tar.extract("ustar/regtype", TEMPDIR)
+ self.tar.extract("ustar/regtype", TEMPDIR,
+ filter='data')
with open(os.path.join(TEMPDIR, "ustar/regtype"), "rb") as fobj:
data = fobj.read()
@@ -467,7 +473,7 @@ def test_premature_end_of_archive(self):
t = tar.next()
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
- tar.extract(t, TEMPDIR)
+ tar.extract(t, TEMPDIR, filter='data')
with self.assertRaisesRegex(tarfile.ReadError, "unexpected end of data"):
tar.extractfile(t).read()
@@ -629,16 +635,16 @@ def test_find_members(self):
def test_extract_hardlink(self):
# Test hardlink extraction (e.g. bug #857297).
with tarfile.open(tarname, errorlevel=1, encoding="iso8859-1") as tar:
- tar.extract("ustar/regtype", TEMPDIR)
+ tar.extract("ustar/regtype", TEMPDIR, filter='data')
self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/regtype"))
- tar.extract("ustar/lnktype", TEMPDIR)
+ tar.extract("ustar/lnktype", TEMPDIR, filter='data')
self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/lnktype"))
with open(os.path.join(TEMPDIR, "ustar/lnktype"), "rb") as f:
data = f.read()
self.assertEqual(sha256sum(data), sha256_regtype)
- tar.extract("ustar/symtype", TEMPDIR)
+ tar.extract("ustar/symtype", TEMPDIR, filter='data')
self.addCleanup(os_helper.unlink, os.path.join(TEMPDIR, "ustar/symtype"))
with open(os.path.join(TEMPDIR, "ustar/symtype"), "rb") as f:
data = f.read()
@@ -653,13 +659,14 @@ def test_extractall(self):
os.mkdir(DIR)
try:
directories = [t for t in tar if t.isdir()]
- tar.extractall(DIR, directories)
+ tar.extractall(DIR, directories, filter='fully_trusted')
for tarinfo in directories:
path = os.path.join(DIR, tarinfo.name)
if sys.platform != "win32":
# Win32 has no support for fine grained permissions.
self.assertEqual(tarinfo.mode & 0o777,
- os.stat(path).st_mode & 0o777)
+ os.stat(path).st_mode & 0o777,
+ tarinfo.name)
def format_mtime(mtime):
if isinstance(mtime, float):
return "{} ({})".format(mtime, mtime.hex())
@@ -683,7 +690,7 @@ def test_extract_directory(self):
try:
with tarfile.open(tarname, encoding="iso8859-1") as tar:
tarinfo = tar.getmember(dirtype)
- tar.extract(tarinfo, path=DIR)
+ tar.extract(tarinfo, path=DIR, filter='fully_trusted')
extracted = os.path.join(DIR, dirtype)
self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
if sys.platform != "win32":
@@ -696,7 +703,7 @@ def test_extractall_pathlike_name(self):
with os_helper.temp_dir(DIR), \
tarfile.open(tarname, encoding="iso8859-1") as tar:
directories = [t for t in tar if t.isdir()]
- tar.extractall(DIR, directories)
+ tar.extractall(DIR, directories, filter='fully_trusted')
for tarinfo in directories:
path = DIR / tarinfo.name
self.assertEqual(os.path.getmtime(path), tarinfo.mtime)
@@ -707,7 +714,7 @@ def test_extract_pathlike_name(self):
with os_helper.temp_dir(DIR), \
tarfile.open(tarname, encoding="iso8859-1") as tar:
tarinfo = tar.getmember(dirtype)
- tar.extract(tarinfo, path=DIR)
+ tar.extract(tarinfo, path=DIR, filter='fully_trusted')
extracted = DIR / dirtype
self.assertEqual(os.path.getmtime(extracted), tarinfo.mtime)
@@ -1075,7 +1082,7 @@ class GNUReadTest(LongnameTest, ReadTest, unittest.TestCase):
# an all platforms, and after that a test that will work only on
# platforms/filesystems that prove to support sparse files.
def _test_sparse_file(self, name):
- self.tar.extract(name, TEMPDIR)
+ self.tar.extract(name, TEMPDIR, filter='data')
filename = os.path.join(TEMPDIR, name)
with open(filename, "rb") as fobj:
data = fobj.read()
@@ -1442,7 +1449,8 @@ def test_extractall_symlinks(self):
with tarfile.open(temparchive, errorlevel=2) as tar:
# this should not raise OSError: [Errno 17] File exists
try:
- tar.extractall(path=tempdir)
+ tar.extractall(path=tempdir,
+ filter='fully_trusted')
except OSError:
self.fail("extractall failed with symlinked files")
finally:
@@ -2547,6 +2555,15 @@ def make_simple_tarfile(self, tar_name):
for tardata in files:
tf.add(tardata, arcname=os.path.basename(tardata))
+ def make_evil_tarfile(self, tar_name):
+ files = [support.findfile('tokenize_tests.txt')]
+ self.addCleanup(os_helper.unlink, tar_name)
+ with tarfile.open(tar_name, 'w') as tf:
+ benign = tarfile.TarInfo('benign')
+ tf.addfile(benign, fileobj=io.BytesIO(b''))
+ evil = tarfile.TarInfo('../evil')
+ tf.addfile(evil, fileobj=io.BytesIO(b''))
+
def test_bad_use(self):
rc, out, err = self.tarfilecmd_failure()
self.assertEqual(out, b'')
@@ -2703,6 +2720,25 @@ def test_extract_command_verbose(self):
finally:
os_helper.rmtree(tarextdir)
+ def test_extract_command_filter(self):
+ self.make_evil_tarfile(tmpname)
+ # Make an inner directory, so the member named '../evil'
+ # is still extracted into `tarextdir`
+ destdir = os.path.join(tarextdir, 'dest')
+ os.mkdir(tarextdir)
+ try:
+ with os_helper.temp_cwd(destdir):
+ self.tarfilecmd_failure('-e', tmpname,
+ '-v',
+ '--filter', 'data')
+ out = self.tarfilecmd('-e', tmpname,
+ '-v',
+ '--filter', 'fully_trusted',
+ PYTHONIOENCODING='utf-8')
+ self.assertIn(b' file is extracted.', out)
+ finally:
+ os_helper.rmtree(tarextdir)
+
def test_extract_command_different_directory(self):
self.make_simple_tarfile(tmpname)
try:
@@ -2786,7 +2822,7 @@ class LinkEmulationTest(ReadTest, unittest.TestCase):
# symbolic or hard links tarfile tries to extract these types of members
# as the regular files they point to.
def _test_link_extraction(self, name):
- self.tar.extract(name, TEMPDIR)
+ self.tar.extract(name, TEMPDIR, filter='fully_trusted')
with open(os.path.join(TEMPDIR, name), "rb") as f:
data = f.read()
self.assertEqual(sha256sum(data), sha256_regtype)
@@ -2918,8 +2954,10 @@ def test_extract_with_numeric_owner(self, mock_geteuid, mock_chmod,
mock_chown):
with self._setup_test(mock_geteuid) as (tarfl, filename_1, _,
filename_2):
- tarfl.extract(filename_1, TEMPDIR, numeric_owner=True)
- tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True)
+ tarfl.extract(filename_1, TEMPDIR, numeric_owner=True,
+ filter='fully_trusted')
+ tarfl.extract(filename_2 , TEMPDIR, numeric_owner=True,
+ filter='fully_trusted')
# convert to filesystem paths
f_filename_1 = os.path.join(TEMPDIR, filename_1)
@@ -2937,7 +2975,8 @@ def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
mock_chown):
with self._setup_test(mock_geteuid) as (tarfl, filename_1, dirname_1,
filename_2):
- tarfl.extractall(TEMPDIR, numeric_owner=True)
+ tarfl.extractall(TEMPDIR, numeric_owner=True,
+ filter='fully_trusted')
# convert to filesystem paths
f_filename_1 = os.path.join(TEMPDIR, filename_1)
@@ -2962,7 +3001,8 @@ def test_extractall_with_numeric_owner(self, mock_geteuid, mock_chmod,
def test_extract_without_numeric_owner(self, mock_geteuid, mock_chmod,
mock_chown):
with self._setup_test(mock_geteuid) as (tarfl, filename_1, _, _):
- tarfl.extract(filename_1, TEMPDIR, numeric_owner=False)
+ tarfl.extract(filename_1, TEMPDIR, numeric_owner=False,
+ filter='fully_trusted')
# convert to filesystem paths
f_filename_1 = os.path.join(TEMPDIR, filename_1)
@@ -2976,6 +3016,910 @@ def test_keyword_only(self, mock_geteuid):
tarfl.extract, filename_1, TEMPDIR, False, True)
+class ReplaceTests(ReadTest, unittest.TestCase):
+ def test_replace_name(self):
+ member = self.tar.getmember('ustar/regtype')
+ replaced = member.replace(name='misc/other')
+ self.assertEqual(replaced.name, 'misc/other')
+ self.assertEqual(member.name, 'ustar/regtype')
+ self.assertEqual(self.tar.getmember('ustar/regtype').name,
+ 'ustar/regtype')
+
+ def test_replace_deep(self):
+ member = self.tar.getmember('pax/regtype1')
+ replaced = member.replace()
+ replaced.pax_headers['gname'] = 'not-bar'
+ self.assertEqual(member.pax_headers['gname'], 'bar')
+ self.assertEqual(
+ self.tar.getmember('pax/regtype1').pax_headers['gname'], 'bar')
+
+ def test_replace_shallow(self):
+ member = self.tar.getmember('pax/regtype1')
+ replaced = member.replace(deep=False)
+ replaced.pax_headers['gname'] = 'not-bar'
+ self.assertEqual(member.pax_headers['gname'], 'not-bar')
+ self.assertEqual(
+ self.tar.getmember('pax/regtype1').pax_headers['gname'], 'not-bar')
+
+ def test_replace_all(self):
+ member = self.tar.getmember('ustar/regtype')
+ for attr_name in ('name', 'mtime', 'mode', 'linkname',
+ 'uid', 'gid', 'uname', 'gname'):
+ with self.subTest(attr_name=attr_name):
+ replaced = member.replace(**{attr_name: None})
+ self.assertEqual(getattr(replaced, attr_name), None)
+ self.assertNotEqual(getattr(member, attr_name), None)
+
+ def test_replace_internal(self):
+ member = self.tar.getmember('ustar/regtype')
+ with self.assertRaises(TypeError):
+ member.replace(offset=123456789)
+
+
+class NoneInfoExtractTests(ReadTest):
+ # These mainly check that all kinds of members are extracted successfully
+ # if some metadata is None.
+ # Some of the methods do additional spot checks.
+
+ # We also test that the default filters can deal with None.
+
+ extraction_filter = None
+
+ @classmethod
+ def setUpClass(cls):
+ tar = tarfile.open(tarname, mode='r', encoding="iso8859-1")
+ cls.control_dir = pathlib.Path(TEMPDIR) / "extractall_ctrl"
+ tar.errorlevel = 0
+ with ExitStack() as cm:
+ if cls.extraction_filter is None:
+ cm.enter_context(warnings.catch_warnings(
+ action="ignore", category=DeprecationWarning))
+ tar.extractall(cls.control_dir, filter=cls.extraction_filter)
+ tar.close()
+ cls.control_paths = set(
+ p.relative_to(cls.control_dir)
+ for p in pathlib.Path(cls.control_dir).glob('**/*'))
+
+ @classmethod
+ def tearDownClass(cls):
+ shutil.rmtree(cls.control_dir)
+
+ def check_files_present(self, directory):
+ got_paths = set(
+ p.relative_to(directory)
+ for p in pathlib.Path(directory).glob('**/*'))
+ self.assertEqual(self.control_paths, got_paths)
+
+ @contextmanager
+ def extract_with_none(self, *attr_names):
+ DIR = pathlib.Path(TEMPDIR) / "extractall_none"
+ self.tar.errorlevel = 0
+ for member in self.tar.getmembers():
+ for attr_name in attr_names:
+ setattr(member, attr_name, None)
+ with os_helper.temp_dir(DIR):
+ self.tar.extractall(DIR, filter='fully_trusted')
+ self.check_files_present(DIR)
+ yield DIR
+
+ def test_extractall_none_mtime(self):
+ # mtimes of extracted files should be later than 'now' -- the mtime
+ # of a previously created directory.
+ now = pathlib.Path(TEMPDIR).stat().st_mtime
+ with self.extract_with_none('mtime') as DIR:
+ for path in pathlib.Path(DIR).glob('**/*'):
+ with self.subTest(path=path):
+ try:
+ mtime = path.stat().st_mtime
+ except OSError:
+ # Some systems can't stat symlinks, ignore those
+ if not path.is_symlink():
+ raise
+ else:
+ self.assertGreaterEqual(path.stat().st_mtime, now)
+
+ def test_extractall_none_mode(self):
+ # modes of directories and regular files should match the mode
+ # of a "normally" created directory or regular file
+ dir_mode = pathlib.Path(TEMPDIR).stat().st_mode
+ regular_file = pathlib.Path(TEMPDIR) / 'regular_file'
+ regular_file.write_text('')
+ regular_file_mode = regular_file.stat().st_mode
+ with self.extract_with_none('mode') as DIR:
+ for path in pathlib.Path(DIR).glob('**/*'):
+ with self.subTest(path=path):
+ if path.is_dir():
+ self.assertEqual(path.stat().st_mode, dir_mode)
+ elif path.is_file():
+ self.assertEqual(path.stat().st_mode,
+ regular_file_mode)
+
+ def test_extractall_none_uid(self):
+ with self.extract_with_none('uid'):
+ pass
+
+ def test_extractall_none_gid(self):
+ with self.extract_with_none('gid'):
+ pass
+
+ def test_extractall_none_uname(self):
+ with self.extract_with_none('uname'):
+ pass
+
+ def test_extractall_none_gname(self):
+ with self.extract_with_none('gname'):
+ pass
+
+ def test_extractall_none_ownership(self):
+ with self.extract_with_none('uid', 'gid', 'uname', 'gname'):
+ pass
+
+class NoneInfoExtractTests_Data(NoneInfoExtractTests, unittest.TestCase):
+ extraction_filter = 'data'
+
+class NoneInfoExtractTests_FullyTrusted(NoneInfoExtractTests,
+ unittest.TestCase):
+ extraction_filter = 'fully_trusted'
+
+class NoneInfoExtractTests_Tar(NoneInfoExtractTests, unittest.TestCase):
+ extraction_filter = 'tar'
+
+class NoneInfoExtractTests_Default(NoneInfoExtractTests,
+ unittest.TestCase):
+ extraction_filter = None
+
+class NoneInfoTests_Misc(unittest.TestCase):
+ def test_add(self):
+ # When addfile() encounters None metadata, it raises a ValueError
+ bio = io.BytesIO()
+ for tarformat in (tarfile.USTAR_FORMAT, tarfile.GNU_FORMAT,
+ tarfile.PAX_FORMAT):
+ with self.subTest(tarformat=tarformat):
+ tar = tarfile.open(fileobj=bio, mode='w', format=tarformat)
+ tarinfo = tar.gettarinfo(tarname)
+ try:
+ tar.addfile(tarinfo)
+ except Exception:
+ if tarformat == tarfile.USTAR_FORMAT:
+ # In the old, limited format, adding might fail for
+ # reasons like the UID being too large
+ pass
+ else:
+ raise
+ else:
+ for attr_name in ('mtime', 'mode', 'uid', 'gid',
+ 'uname', 'gname'):
+ with self.subTest(attr_name=attr_name):
+ replaced = tarinfo.replace(**{attr_name: None})
+ with self.assertRaisesRegex(ValueError,
+ f"{attr_name}"):
+ tar.addfile(replaced)
+
+ def test_list(self):
+ # Change some metadata to None, then compare list() output
+ # word-for-word. We want list() to not raise, and to only change
+ # printout for the affected piece of metadata.
+ # (n.b.: some contents of the test archive are hardcoded.)
+ for attr_names in ({'mtime'}, {'mode'}, {'uid'}, {'gid'},
+ {'uname'}, {'gname'},
+ {'uid', 'uname'}, {'gid', 'gname'}):
+ with (self.subTest(attr_names=attr_names),
+ tarfile.open(tarname, encoding="iso8859-1") as tar):
+ tio_prev = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
+ with support.swap_attr(sys, 'stdout', tio_prev):
+ tar.list()
+ for member in tar.getmembers():
+ for attr_name in attr_names:
+ setattr(member, attr_name, None)
+ tio_new = io.TextIOWrapper(io.BytesIO(), 'ascii', newline='\n')
+ with support.swap_attr(sys, 'stdout', tio_new):
+ tar.list()
+ for expected, got in zip(tio_prev.detach().getvalue().split(),
+ tio_new.detach().getvalue().split()):
+ if attr_names == {'mtime'} and re.match(rb'2003-01-\d\d', expected):
+ self.assertEqual(got, b'????-??-??')
+ elif attr_names == {'mtime'} and re.match(rb'\d\d:\d\d:\d\d', expected):
+ self.assertEqual(got, b'??:??:??')
+ elif attr_names == {'mode'} and re.match(
+ rb'.([r-][w-][x-]){3}', expected):
+ self.assertEqual(got, b'??????????')
+ elif attr_names == {'uname'} and expected.startswith(
+ (b'tarfile/', b'lars/', b'foo/')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_group, exp_group)
+ self.assertRegex(got_user, b'[0-9]+')
+ elif attr_names == {'gname'} and expected.endswith(
+ (b'/tarfile', b'/users', b'/bar')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_user, exp_user)
+ self.assertRegex(got_group, b'[0-9]+')
+ elif attr_names == {'uid'} and expected.startswith(
+ (b'1000/')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_group, exp_group)
+ self.assertEqual(got_user, b'None')
+ elif attr_names == {'gid'} and expected.endswith((b'/100')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_user, exp_user)
+ self.assertEqual(got_group, b'None')
+ elif attr_names == {'uid', 'uname'} and expected.startswith(
+ (b'tarfile/', b'lars/', b'foo/', b'1000/')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_group, exp_group)
+ self.assertEqual(got_user, b'None')
+ elif attr_names == {'gname', 'gid'} and expected.endswith(
+ (b'/tarfile', b'/users', b'/bar', b'/100')):
+ exp_user, exp_group = expected.split(b'/')
+ got_user, got_group = got.split(b'/')
+ self.assertEqual(got_user, exp_user)
+ self.assertEqual(got_group, b'None')
+ else:
+ # In other cases the output should be the same
+ self.assertEqual(expected, got)
+
+def _filemode_to_int(mode):
+ """Inverse of `stat.filemode` (for permission bits)
+
+ Using mode strings rather than numbers makes the later tests more readable.
+ """
+ str_mode = mode[1:]
+ result = (
+ {'r': stat.S_IRUSR, '-': 0}[str_mode[0]]
+ | {'w': stat.S_IWUSR, '-': 0}[str_mode[1]]
+ | {'x': stat.S_IXUSR, '-': 0,
+ 's': stat.S_IXUSR | stat.S_ISUID,
+ 'S': stat.S_ISUID}[str_mode[2]]
+ | {'r': stat.S_IRGRP, '-': 0}[str_mode[3]]
+ | {'w': stat.S_IWGRP, '-': 0}[str_mode[4]]
+ | {'x': stat.S_IXGRP, '-': 0,
+ 's': stat.S_IXGRP | stat.S_ISGID,
+ 'S': stat.S_ISGID}[str_mode[5]]
+ | {'r': stat.S_IROTH, '-': 0}[str_mode[6]]
+ | {'w': stat.S_IWOTH, '-': 0}[str_mode[7]]
+ | {'x': stat.S_IXOTH, '-': 0,
+ 't': stat.S_IXOTH | stat.S_ISVTX,
+ 'T': stat.S_ISVTX}[str_mode[8]]
+ )
+ # check we did this right
+ assert stat.filemode(result)[1:] == mode[1:]
+
+ return result
+
+class ArchiveMaker:
+ """Helper to create a tar file with specific contents
+
+ Usage:
+
+ with ArchiveMaker() as t:
+ t.add('filename', ...)
+
+ with t.open() as tar:
+ ... # `tar` is now a TarFile with 'filename' in it!
+ """
+ def __init__(self):
+ self.bio = io.BytesIO()
+
+ def __enter__(self):
+ self.tar_w = tarfile.TarFile(mode='w', fileobj=self.bio)
+ return self
+
+ def __exit__(self, *exc):
+ self.tar_w.close()
+ self.contents = self.bio.getvalue()
+ self.bio = None
+
+ def add(self, name, *, type=None, symlink_to=None, hardlink_to=None,
+ mode=None, **kwargs):
+ """Add a member to the test archive. Call within `with`."""
+ name = str(name)
+ tarinfo = tarfile.TarInfo(name).replace(**kwargs)
+ if mode:
+ tarinfo.mode = _filemode_to_int(mode)
+ if symlink_to is not None:
+ type = tarfile.SYMTYPE
+ tarinfo.linkname = str(symlink_to)
+ if hardlink_to is not None:
+ type = tarfile.LNKTYPE
+ tarinfo.linkname = str(hardlink_to)
+ if name.endswith('/') and type is None:
+ type = tarfile.DIRTYPE
+ if type is not None:
+ tarinfo.type = type
+ if tarinfo.isreg():
+ fileobj = io.BytesIO(bytes(tarinfo.size))
+ else:
+ fileobj = None
+ self.tar_w.addfile(tarinfo, fileobj)
+
+ def open(self, **kwargs):
+ """Open the resulting archive as TarFile. Call after `with`."""
+ bio = io.BytesIO(self.contents)
+ return tarfile.open(fileobj=bio, **kwargs)
+
+# Under WASI, `os_helper.can_symlink` is False to make
+# `skip_unless_symlink` skip symlink tests. "
+# But in the following tests we use can_symlink to *determine* which
+# behavior is expected.
+# Like other symlink tests, skip these on WASI for now.
+if support.is_wasi:
+ def symlink_test(f):
+ return unittest.skip("WASI: Skip symlink test for now")(f)
+else:
+ def symlink_test(f):
+ return f
+
+
+class TestExtractionFilters(unittest.TestCase):
+
+ # A temporary directory for the extraction results.
+ # All files that "escape" the destination path should still end
+ # up in this directory.
+ outerdir = pathlib.Path(TEMPDIR) / 'outerdir'
+
+ # The destination for the extraction, within `outerdir`
+ destdir = outerdir / 'dest'
+
+ @contextmanager
+ def check_context(self, tar, filter):
+ """Extracts `tar` to `self.destdir` and allows checking the result
+
+ If an error occurs, it must be checked using `expect_exception`
+
+ Otherwise, all resulting files must be checked using `expect_file`,
+ except the destination directory itself and parent directories of
+ other files.
+ When checking directories, do so before their contents.
+ """
+ with os_helper.temp_dir(self.outerdir):
+ try:
+ tar.extractall(self.destdir, filter=filter)
+ except Exception as exc:
+ self.raised_exception = exc
+ self.expected_paths = set()
+ else:
+ self.raised_exception = None
+ self.expected_paths = set(self.outerdir.glob('**/*'))
+ self.expected_paths.discard(self.destdir)
+ try:
+ yield
+ finally:
+ tar.close()
+ if self.raised_exception:
+ raise self.raised_exception
+ self.assertEqual(self.expected_paths, set())
+
+ def expect_file(self, name, type=None, symlink_to=None, mode=None):
+ """Check a single file. See check_context."""
+ if self.raised_exception:
+ raise self.raised_exception
+ # use normpath() rather than resolve() so we don't follow symlinks
+ path = pathlib.Path(os.path.normpath(self.destdir / name))
+ self.assertIn(path, self.expected_paths)
+ self.expected_paths.remove(path)
+ if mode is not None and os_helper.can_chmod():
+ got = stat.filemode(stat.S_IMODE(path.stat().st_mode))
+ self.assertEqual(got, mode)
+ if type is None and isinstance(name, str) and name.endswith('/'):
+ type = tarfile.DIRTYPE
+ if symlink_to is not None:
+ got = (self.destdir / name).readlink()
+ expected = pathlib.Path(symlink_to)
+ # The symlink might be the same (textually) as what we expect,
+ # but some systems change the link to an equivalent path, so
+ # we fall back to samefile().
+ if expected != got:
+ self.assertTrue(got.samefile(expected))
+ elif type == tarfile.REGTYPE or type is None:
+ self.assertTrue(path.is_file())
+ elif type == tarfile.DIRTYPE:
+ self.assertTrue(path.is_dir())
+ elif type == tarfile.FIFOTYPE:
+ self.assertTrue(path.is_fifo())
+ else:
+ raise NotImplementedError(type)
+ for parent in path.parents:
+ self.expected_paths.discard(parent)
+
+ def expect_exception(self, exc_type, message_re='.'):
+ with self.assertRaisesRegex(exc_type, message_re):
+ if self.raised_exception is not None:
+ raise self.raised_exception
+ self.raised_exception = None
+
+ def test_benign_file(self):
+ with ArchiveMaker() as arc:
+ arc.add('benign.txt')
+ for filter in 'fully_trusted', 'tar', 'data':
+ with self.check_context(arc.open(), filter):
+ self.expect_file('benign.txt')
+
+ def test_absolute(self):
+ # Test handling a member with an absolute path
+ # Inspired by 'absolute1' in https://github.com/jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add(self.outerdir / 'escaped.evil')
+
+ with self.check_context(arc.open(), 'fully_trusted'):
+ self.expect_file('../escaped.evil')
+
+ for filter in 'tar', 'data':
+ with self.check_context(arc.open(), filter):
+ if str(self.outerdir).startswith('/'):
+ # We strip leading slashes, as e.g. GNU tar does
+ # (without --absolute-filenames).
+ outerdir_stripped = str(self.outerdir).lstrip('/')
+ self.expect_file(f'{outerdir_stripped}/escaped.evil')
+ else:
+ # On this system, absolute paths don't have leading
+ # slashes.
+ # So, there's nothing to strip. We refuse to unpack
+ # to an absolute path, nonetheless.
+ self.expect_exception(
+ tarfile.AbsolutePathError,
+ """['"].*escaped.evil['"] has an absolute path""")
+
+ @symlink_test
+ def test_parent_symlink(self):
+ # Test interplaying symlinks
+ # Inspired by 'dirsymlink2a' in jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add('current', symlink_to='.')
+ arc.add('parent', symlink_to='current/..')
+ arc.add('parent/evil')
+
+ if os_helper.can_symlink():
+ with self.check_context(arc.open(), 'fully_trusted'):
+ if self.raised_exception is not None:
+ # Windows will refuse to create a file that's a symlink to itself
+ # (and tarfile doesn't swallow that exception)
+ self.expect_exception(FileExistsError)
+ # The other cases will fail with this error too.
+ # Skip the rest of this test.
+ return
+ else:
+ self.expect_file('current', symlink_to='.')
+ self.expect_file('parent', symlink_to='current/..')
+ self.expect_file('../evil')
+
+ with self.check_context(arc.open(), 'tar'):
+ self.expect_exception(
+ tarfile.OutsideDestinationError,
+ """'parent/evil' would be extracted to ['"].*evil['"], """
+ + "which is outside the destination")
+
+ with self.check_context(arc.open(), 'data'):
+ self.expect_exception(
+ tarfile.LinkOutsideDestinationError,
+ """'parent' would link to ['"].*outerdir['"], """
+ + "which is outside the destination")
+
+ else:
+ # No symlink support. The symlinks are ignored.
+ with self.check_context(arc.open(), 'fully_trusted'):
+ self.expect_file('parent/evil')
+ with self.check_context(arc.open(), 'tar'):
+ self.expect_file('parent/evil')
+ with self.check_context(arc.open(), 'data'):
+ self.expect_file('parent/evil')
+
+ @symlink_test
+ def test_parent_symlink2(self):
+ # Test interplaying symlinks
+ # Inspired by 'dirsymlink2b' in jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add('current', symlink_to='.')
+ arc.add('current/parent', symlink_to='..')
+ arc.add('parent/evil')
+
+ with self.check_context(arc.open(), 'fully_trusted'):
+ if os_helper.can_symlink():
+ self.expect_file('current', symlink_to='.')
+ self.expect_file('parent', symlink_to='..')
+ self.expect_file('../evil')
+ else:
+ self.expect_file('current/')
+ self.expect_file('parent/evil')
+
+ with self.check_context(arc.open(), 'tar'):
+ if os_helper.can_symlink():
+ self.expect_exception(
+ tarfile.OutsideDestinationError,
+ "'parent/evil' would be extracted to "
+ + """['"].*evil['"], which is outside """
+ + "the destination")
+ else:
+ self.expect_file('current/')
+ self.expect_file('parent/evil')
+
+ with self.check_context(arc.open(), 'data'):
+ self.expect_exception(
+ tarfile.LinkOutsideDestinationError,
+ """'current/parent' would link to ['"].*['"], """
+ + "which is outside the destination")
+
+ @symlink_test
+ def test_absolute_symlink(self):
+ # Test symlink to an absolute path
+ # Inspired by 'dirsymlink' in jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add('parent', symlink_to=self.outerdir)
+ arc.add('parent/evil')
+
+ with self.check_context(arc.open(), 'fully_trusted'):
+ if os_helper.can_symlink():
+ self.expect_file('parent', symlink_to=self.outerdir)
+ self.expect_file('../evil')
+ else:
+ self.expect_file('parent/evil')
+
+ with self.check_context(arc.open(), 'tar'):
+ if os_helper.can_symlink():
+ self.expect_exception(
+ tarfile.OutsideDestinationError,
+ "'parent/evil' would be extracted to "
+ + """['"].*evil['"], which is outside """
+ + "the destination")
+ else:
+ self.expect_file('parent/evil')
+
+ with self.check_context(arc.open(), 'data'):
+ self.expect_exception(
+ tarfile.AbsoluteLinkError,
+ "'parent' is a symlink to an absolute path")
+
+ @symlink_test
+ def test_sly_relative0(self):
+ # Inspired by 'relative0' in jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add('../moo', symlink_to='..//tmp/moo')
+
+ try:
+ with self.check_context(arc.open(), filter='fully_trusted'):
+ if os_helper.can_symlink():
+ if isinstance(self.raised_exception, FileExistsError):
+ # XXX TarFile happens to fail creating a parent
+ # directory.
+ # This might be a bug, but fixing it would hurt
+ # security.
+ # Note that e.g. GNU `tar` rejects '..' components,
+ # so you could argue this is an invalid archive and we
+ # just raise an bad type of exception.
+ self.expect_exception(FileExistsError)
+ else:
+ self.expect_file('../moo', symlink_to='..//tmp/moo')
+ else:
+ # The symlink can't be extracted and is ignored
+ pass
+ except FileExistsError:
+ pass
+
+ for filter in 'tar', 'data':
+ with self.check_context(arc.open(), filter):
+ self.expect_exception(
+ tarfile.OutsideDestinationError,
+ "'../moo' would be extracted to "
+ + "'.*moo', which is outside "
+ + "the destination")
+
+ @symlink_test
+ def test_sly_relative2(self):
+ # Inspired by 'relative2' in jwilk/traversal-archives
+ with ArchiveMaker() as arc:
+ arc.add('tmp/')
+ arc.add('tmp/../../moo', symlink_to='tmp/../..//tmp/moo')
+
+ with self.check_context(arc.open(), 'fully_trusted'):
+ self.expect_file('tmp', type=tarfile.DIRTYPE)
+ if os_helper.can_symlink():
+ self.expect_file('../moo', symlink_to='tmp/../../tmp/moo')
+
+ for filter in 'tar', 'data':
+ with self.check_context(arc.open(), filter):
+ self.expect_exception(
+ tarfile.OutsideDestinationError,
+ "'tmp/../../moo' would be extracted to "
+ + """['"].*moo['"], which is outside the """
+ + "destination")
+
+ def test_modes(self):
+ # Test how file modes are extracted
+ # (Note that the modes are ignored on platforms without working chmod)
+ with ArchiveMaker() as arc:
+ arc.add('all_bits', mode='?rwsrwsrwt')
+ arc.add('perm_bits', mode='?rwxrwxrwx')
+ arc.add('exec_group_other', mode='?rw-rwxrwx')
+ arc.add('read_group_only', mode='?---r-----')
+ arc.add('no_bits', mode='?---------')
+ arc.add('dir/', mode='?---rwsrwt')
+
+ # On some systems, setting the sticky bit is a no-op.
+ # Check if that's the case.
+ tmp_filename = os.path.join(TEMPDIR, "tmp.file")
+ with open(tmp_filename, 'w'):
+ pass
+ os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX)
+ have_sticky_files = (os.stat(tmp_filename).st_mode & stat.S_ISVTX)
+ os.unlink(tmp_filename)
+
+ os.mkdir(tmp_filename)
+ os.chmod(tmp_filename, os.stat(tmp_filename).st_mode | stat.S_ISVTX)
+ have_sticky_dirs = (os.stat(tmp_filename).st_mode & stat.S_ISVTX)
+ os.rmdir(tmp_filename)
+
+ with self.check_context(arc.open(), 'fully_trusted'):
+ if have_sticky_files:
+ self.expect_file('all_bits', mode='?rwsrwsrwt')
+ else:
+ self.expect_file('all_bits', mode='?rwsrwsrwx')
+ self.expect_file('perm_bits', mode='?rwxrwxrwx')
+ self.expect_file('exec_group_other', mode='?rw-rwxrwx')
+ self.expect_file('read_group_only', mode='?---r-----')
+ self.expect_file('no_bits', mode='?---------')
+ if have_sticky_dirs:
+ self.expect_file('dir/', mode='?---rwsrwt')
+ else:
+ self.expect_file('dir/', mode='?---rwsrwx')
+
+ with self.check_context(arc.open(), 'tar'):
+ self.expect_file('all_bits', mode='?rwxr-xr-x')
+ self.expect_file('perm_bits', mode='?rwxr-xr-x')
+ self.expect_file('exec_group_other', mode='?rw-r-xr-x')
+ self.expect_file('read_group_only', mode='?---r-----')
+ self.expect_file('no_bits', mode='?---------')
+ self.expect_file('dir/', mode='?---r-xr-x')
+
+ with self.check_context(arc.open(), 'data'):
+ normal_dir_mode = stat.filemode(stat.S_IMODE(
+ self.outerdir.stat().st_mode))
+ self.expect_file('all_bits', mode='?rwxr-xr-x')
+ self.expect_file('perm_bits', mode='?rwxr-xr-x')
+ self.expect_file('exec_group_other', mode='?rw-r--r--')
+ self.expect_file('read_group_only', mode='?rw-r-----')
+ self.expect_file('no_bits', mode='?rw-------')
+ self.expect_file('dir/', mode=normal_dir_mode)
+
+ def test_pipe(self):
+ # Test handling of a special file
+ with ArchiveMaker() as arc:
+ arc.add('foo', type=tarfile.FIFOTYPE)
+
+ for filter in 'fully_trusted', 'tar':
+ with self.check_context(arc.open(), filter):
+ if hasattr(os, 'mkfifo'):
+ self.expect_file('foo', type=tarfile.FIFOTYPE)
+ else:
+ # The pipe can't be extracted and is skipped.
+ pass
+
+ with self.check_context(arc.open(), 'data'):
+ self.expect_exception(
+ tarfile.SpecialFileError,
+ "'foo' is a special file")
+
+ def test_special_files(self):
+ # Creating device files is tricky. Instead of attempting that let's
+ # only check the filter result.
+ for special_type in tarfile.FIFOTYPE, tarfile.CHRTYPE, tarfile.BLKTYPE:
+ tarinfo = tarfile.TarInfo('foo')
+ tarinfo.type = special_type
+ trusted = tarfile.fully_trusted_filter(tarinfo, '')
+ self.assertIs(trusted, tarinfo)
+ tar = tarfile.tar_filter(tarinfo, '')
+ self.assertEqual(tar.type, special_type)
+ with self.assertRaises(tarfile.SpecialFileError) as cm:
+ tarfile.data_filter(tarinfo, '')
+ self.assertIsInstance(cm.exception.tarinfo, tarfile.TarInfo)
+ self.assertEqual(cm.exception.tarinfo.name, 'foo')
+
+ def test_fully_trusted_filter(self):
+ # The 'fully_trusted' filter returns the original TarInfo objects.
+ with tarfile.TarFile.open(tarname) as tar:
+ for tarinfo in tar.getmembers():
+ filtered = tarfile.fully_trusted_filter(tarinfo, '')
+ self.assertIs(filtered, tarinfo)
+
+ def test_tar_filter(self):
+ # The 'tar' filter returns TarInfo objects with the same name/type.
+ # (It can also fail for particularly "evil" input, but we don't have
+ # that in the test archive.)
+ with tarfile.TarFile.open(tarname) as tar:
+ for tarinfo in tar.getmembers():
+ filtered = tarfile.tar_filter(tarinfo, '')
+ self.assertIs(filtered.name, tarinfo.name)
+ self.assertIs(filtered.type, tarinfo.type)
+
+ def test_data_filter(self):
+ # The 'data' filter either raises, or returns TarInfo with the same
+ # name/type.
+ with tarfile.TarFile.open(tarname) as tar:
+ for tarinfo in tar.getmembers():
+ try:
+ filtered = tarfile.data_filter(tarinfo, '')
+ except tarfile.FilterError:
+ continue
+ self.assertIs(filtered.name, tarinfo.name)
+ self.assertIs(filtered.type, tarinfo.type)
+
+ def test_default_filter_warns(self):
+ """Ensure the default filter warns"""
+ with ArchiveMaker() as arc:
+ arc.add('foo')
+ with warnings_helper.check_warnings(
+ ('Python 3.14', DeprecationWarning)):
+ with self.check_context(arc.open(), None):
+ self.expect_file('foo')
+
+ def test_change_default_filter_on_instance(self):
+ tar = tarfile.TarFile(tarname, 'r')
+ def strict_filter(tarinfo, path):
+ if tarinfo.name == 'ustar/regtype':
+ return tarinfo
+ else:
+ return None
+ tar.extraction_filter = strict_filter
+ with self.check_context(tar, None):
+ self.expect_file('ustar/regtype')
+
+ def test_change_default_filter_on_class(self):
+ def strict_filter(tarinfo, path):
+ if tarinfo.name == 'ustar/regtype':
+ return tarinfo
+ else:
+ return None
+ tar = tarfile.TarFile(tarname, 'r')
+ with support.swap_attr(tarfile.TarFile, 'extraction_filter',
+ staticmethod(strict_filter)):
+ with self.check_context(tar, None):
+ self.expect_file('ustar/regtype')
+
+ def test_change_default_filter_on_subclass(self):
+ class TarSubclass(tarfile.TarFile):
+ def extraction_filter(self, tarinfo, path):
+ if tarinfo.name == 'ustar/regtype':
+ return tarinfo
+ else:
+ return None
+
+ tar = TarSubclass(tarname, 'r')
+ with self.check_context(tar, None):
+ self.expect_file('ustar/regtype')
+
+ def test_change_default_filter_to_string(self):
+ tar = tarfile.TarFile(tarname, 'r')
+ tar.extraction_filter = 'data'
+ with self.check_context(tar, None):
+ self.expect_exception(TypeError)
+
+ def test_custom_filter(self):
+ def custom_filter(tarinfo, path):
+ self.assertIs(path, self.destdir)
+ if tarinfo.name == 'move_this':
+ return tarinfo.replace(name='moved')
+ if tarinfo.name == 'ignore_this':
+ return None
+ return tarinfo
+
+ with ArchiveMaker() as arc:
+ arc.add('move_this')
+ arc.add('ignore_this')
+ arc.add('keep')
+ with self.check_context(arc.open(), custom_filter):
+ self.expect_file('moved')
+ self.expect_file('keep')
+
+ def test_bad_filter_name(self):
+ with ArchiveMaker() as arc:
+ arc.add('foo')
+ with self.check_context(arc.open(), 'bad filter name'):
+ self.expect_exception(ValueError)
+
+ def test_stateful_filter(self):
+ # Stateful filters should be possible.
+ # (This doesn't really test tarfile. Rather, it demonstrates
+ # that third parties can implement a stateful filter.)
+ class StatefulFilter:
+ def __enter__(self):
+ self.num_files_processed = 0
+ return self
+
+ def __call__(self, tarinfo, path):
+ try:
+ tarinfo = tarfile.data_filter(tarinfo, path)
+ except tarfile.FilterError:
+ return None
+ self.num_files_processed += 1
+ return tarinfo
+
+ def __exit__(self, *exc_info):
+ self.done = True
+
+ with ArchiveMaker() as arc:
+ arc.add('good')
+ arc.add('bad', symlink_to='/')
+ arc.add('good')
+ with StatefulFilter() as custom_filter:
+ with self.check_context(arc.open(), custom_filter):
+ self.expect_file('good')
+ self.assertEqual(custom_filter.num_files_processed, 2)
+ self.assertEqual(custom_filter.done, True)
+
+ def test_errorlevel(self):
+ def extracterror_filter(tarinfo, path):
+ raise tarfile.ExtractError('failed with ExtractError')
+ def filtererror_filter(tarinfo, path):
+ raise tarfile.FilterError('failed with FilterError')
+ def oserror_filter(tarinfo, path):
+ raise OSError('failed with OSError')
+ def tarerror_filter(tarinfo, path):
+ raise tarfile.TarError('failed with base TarError')
+ def valueerror_filter(tarinfo, path):
+ raise ValueError('failed with ValueError')
+
+ with ArchiveMaker() as arc:
+ arc.add('file')
+
+ # If errorlevel is 0, errors affected by errorlevel are ignored
+
+ with self.check_context(arc.open(errorlevel=0), extracterror_filter):
+ self.expect_file('file')
+
+ with self.check_context(arc.open(errorlevel=0), filtererror_filter):
+ self.expect_file('file')
+
+ with self.check_context(arc.open(errorlevel=0), oserror_filter):
+ self.expect_file('file')
+
+ with self.check_context(arc.open(errorlevel=0), tarerror_filter):
+ self.expect_exception(tarfile.TarError)
+
+ with self.check_context(arc.open(errorlevel=0), valueerror_filter):
+ self.expect_exception(ValueError)
+
+ # If 1, all fatal errors are raised
+
+ with self.check_context(arc.open(errorlevel=1), extracterror_filter):
+ self.expect_file('file')
+
+ with self.check_context(arc.open(errorlevel=1), filtererror_filter):
+ self.expect_exception(tarfile.FilterError)
+
+ with self.check_context(arc.open(errorlevel=1), oserror_filter):
+ self.expect_exception(OSError)
+
+ with self.check_context(arc.open(errorlevel=1), tarerror_filter):
+ self.expect_exception(tarfile.TarError)
+
+ with self.check_context(arc.open(errorlevel=1), valueerror_filter):
+ self.expect_exception(ValueError)
+
+ # If 2, all non-fatal errors are raised as well.
+
+ with self.check_context(arc.open(errorlevel=2), extracterror_filter):
+ self.expect_exception(tarfile.ExtractError)
+
+ with self.check_context(arc.open(errorlevel=2), filtererror_filter):
+ self.expect_exception(tarfile.FilterError)
+
+ with self.check_context(arc.open(errorlevel=2), oserror_filter):
+ self.expect_exception(OSError)
+
+ with self.check_context(arc.open(errorlevel=2), tarerror_filter):
+ self.expect_exception(tarfile.TarError)
+
+ with self.check_context(arc.open(errorlevel=2), valueerror_filter):
+ self.expect_exception(ValueError)
+
+ # We only handle ExtractionError, FilterError & OSError specially.
+
+ with self.check_context(arc.open(errorlevel='boo!'), filtererror_filter):
+ self.expect_exception(TypeError) # errorlevel is not int
+
+
def setUpModule():
os_helper.unlink(TEMPDIR)
os.makedirs(TEMPDIR)
diff --git a/Lib/test/test_tempfile.py b/Lib/test/test_tempfile.py
index 90155487cff585..db08fb1c7f2a42 100644
--- a/Lib/test/test_tempfile.py
+++ b/Lib/test/test_tempfile.py
@@ -850,6 +850,15 @@ def test_for_tempdir_is_bytes_issue40701_api_warts(self):
finally:
tempfile.tempdir = orig_tempdir
+ def test_path_is_absolute(self):
+ # Test that the path returned by mkdtemp with a relative `dir`
+ # argument is absolute
+ try:
+ path = tempfile.mkdtemp(dir=".")
+ self.assertTrue(os.path.isabs(path))
+ finally:
+ os.rmdir(path)
+
class TestMktemp(BaseTestCase):
"""Test mktemp()."""
@@ -1016,7 +1025,7 @@ def use_closed():
self.assertRaises(ValueError, use_closed)
def test_context_man_not_del_on_close_if_delete_on_close_false(self):
- # Issue gh-58451: tempfile.NamedTemporaryFile is not particulary useful
+ # Issue gh-58451: tempfile.NamedTemporaryFile is not particularly useful
# on Windows
# A NamedTemporaryFile is NOT deleted when closed if
# delete_on_close=False, but is deleted on context manager exit
@@ -1608,7 +1617,7 @@ def test_explicit_cleanup(self):
finally:
os.rmdir(dir)
- def test_explict_cleanup_ignore_errors(self):
+ def test_explicit_cleanup_ignore_errors(self):
"""Test that cleanup doesn't return an error when ignoring them."""
with tempfile.TemporaryDirectory() as working_dir:
temp_dir = self.do_create(
diff --git a/Lib/test/test_threading.py b/Lib/test/test_threading.py
index a39a267b403d83..fdd74c37e26235 100644
--- a/Lib/test/test_threading.py
+++ b/Lib/test/test_threading.py
@@ -1343,6 +1343,7 @@ def func():
import test.support
test.support.run_in_subinterp_with_config(
{subinterp_code!r},
+ use_main_obmalloc=True,
allow_fork=True,
allow_exec=True,
allow_threads={allowed},
diff --git a/Lib/test/test_tkinter/test_widgets.py b/Lib/test/test_tkinter/test_widgets.py
index 64c9472706549b..ba4ef49078c5a7 100644
--- a/Lib/test/test_tkinter/test_widgets.py
+++ b/Lib/test/test_tkinter/test_widgets.py
@@ -1377,6 +1377,11 @@ class MenuTest(AbstractWidgetTest, unittest.TestCase):
def create(self, **kwargs):
return tkinter.Menu(self.root, **kwargs)
+ def test_indexcommand_none(self):
+ widget = self.create()
+ i = widget.index('none')
+ self.assertIsNone(i)
+
def test_configure_postcommand(self):
widget = self.create()
self.checkCommandParam(widget, 'postcommand')
diff --git a/Lib/test/test_tokenize.py b/Lib/test/test_tokenize.py
index 63c2501cfe2338..283a7c23609e67 100644
--- a/Lib/test/test_tokenize.py
+++ b/Lib/test/test_tokenize.py
@@ -1625,6 +1625,10 @@ def test_random_files(self):
# 7 more testfiles fail. Remove them also until the failure is diagnosed.
testfiles.remove(os.path.join(tempdir, "test_unicode_identifiers.py"))
+
+ # TODO: Remove this once we can unparse PEP 701 syntax
+ testfiles.remove(os.path.join(tempdir, "test_fstring.py"))
+
for f in ('buffer', 'builtin', 'fileio', 'inspect', 'os', 'platform', 'sys'):
testfiles.remove(os.path.join(tempdir, "test_%s.py") % f)
@@ -1937,25 +1941,39 @@ def test_string(self):
""")
self.check_tokenize('f"abc"', """\
- STRING 'f"abc"' (1, 0) (1, 6)
+ FSTRING_START 'f"' (1, 0) (1, 2)
+ FSTRING_MIDDLE 'abc' (1, 2) (1, 5)
+ FSTRING_END '"' (1, 5) (1, 6)
""")
self.check_tokenize('fR"a{b}c"', """\
- STRING 'fR"a{b}c"' (1, 0) (1, 9)
+ FSTRING_START 'fR"' (1, 0) (1, 3)
+ FSTRING_MIDDLE 'a' (1, 3) (1, 4)
+ LBRACE '{' (1, 4) (1, 5)
+ NAME 'b' (1, 5) (1, 6)
+ RBRACE '}' (1, 6) (1, 7)
+ FSTRING_MIDDLE 'c' (1, 7) (1, 8)
+ FSTRING_END '"' (1, 8) (1, 9)
""")
self.check_tokenize('f"""abc"""', """\
- STRING 'f\"\"\"abc\"\"\"' (1, 0) (1, 10)
+ FSTRING_START 'f\"""' (1, 0) (1, 4)
+ FSTRING_MIDDLE 'abc' (1, 4) (1, 7)
+ FSTRING_END '\"""' (1, 7) (1, 10)
""")
self.check_tokenize(r'f"abc\
def"', """\
- STRING 'f"abc\\\\\\ndef"' (1, 0) (2, 4)
+ FSTRING_START \'f"\' (1, 0) (1, 2)
+ FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 2) (2, 3)
+ FSTRING_END '"' (2, 3) (2, 4)
""")
self.check_tokenize(r'Rf"abc\
def"', """\
- STRING 'Rf"abc\\\\\\ndef"' (1, 0) (2, 4)
+ FSTRING_START 'Rf"' (1, 0) (1, 3)
+ FSTRING_MIDDLE 'abc\\\\\\ndef' (1, 3) (2, 3)
+ FSTRING_END '"' (2, 3) (2, 4)
""")
def test_function(self):
diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py
index a6172ff05eed47..5e2b353782994e 100644
--- a/Lib/test/test_traceback.py
+++ b/Lib/test/test_traceback.py
@@ -802,12 +802,12 @@ def f():
)()
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
- f" .method",
- f" ^^^^^^",
+ " .method",
+ " ^^^^^^",
]
self.assertEqual(actual, expected)
@@ -818,11 +818,11 @@ def f():
)()
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
- f" method",
+ " method",
]
self.assertEqual(actual, expected)
@@ -833,12 +833,12 @@ def f():
)()
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
- f" . method",
- f" ^^^^^^",
+ " . method",
+ " ^^^^^^",
]
self.assertEqual(actual, expected)
@@ -848,11 +848,11 @@ def f():
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 1}, in f",
- f" width",
+ " width",
]
self.assertEqual(actual, expected)
@@ -864,11 +864,11 @@ def f():
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 2}, in f",
- f" raise ValueError(width)",
+ " raise ValueError(width)",
]
self.assertEqual(actual, expected)
@@ -882,12 +882,12 @@ def f():
actual = self.get_exception(f)
expected = [
- f"Traceback (most recent call last):",
+ "Traceback (most recent call last):",
f" File \"{__file__}\", line {self.callable_line}, in get_exception",
- f" callable()",
+ " callable()",
f" File \"{__file__}\", line {f.__code__.co_firstlineno + 4}, in f",
- f" print(1, www(",
- f" ^^^^",
+ " print(1, www(",
+ " ^^^^",
]
self.assertEqual(actual, expected)
@@ -2844,26 +2844,26 @@ def test_max_group_width(self):
formatted = ''.join(teg.format()).split('\n')
expected = [
- f' | ExceptionGroup: eg (2 sub-exceptions)',
- f' +-+---------------- 1 ----------------',
- f' | ExceptionGroup: eg1 (3 sub-exceptions)',
- f' +-+---------------- 1 ----------------',
- f' | ValueError: 0',
- f' +---------------- 2 ----------------',
- f' | ValueError: 1',
- f' +---------------- ... ----------------',
- f' | and 1 more exception',
- f' +------------------------------------',
- f' +---------------- 2 ----------------',
- f' | ExceptionGroup: eg2 (10 sub-exceptions)',
- f' +-+---------------- 1 ----------------',
- f' | TypeError: 0',
- f' +---------------- 2 ----------------',
- f' | TypeError: 1',
- f' +---------------- ... ----------------',
- f' | and 8 more exceptions',
- f' +------------------------------------',
- f'']
+ ' | ExceptionGroup: eg (2 sub-exceptions)',
+ ' +-+---------------- 1 ----------------',
+ ' | ExceptionGroup: eg1 (3 sub-exceptions)',
+ ' +-+---------------- 1 ----------------',
+ ' | ValueError: 0',
+ ' +---------------- 2 ----------------',
+ ' | ValueError: 1',
+ ' +---------------- ... ----------------',
+ ' | and 1 more exception',
+ ' +------------------------------------',
+ ' +---------------- 2 ----------------',
+ ' | ExceptionGroup: eg2 (10 sub-exceptions)',
+ ' +-+---------------- 1 ----------------',
+ ' | TypeError: 0',
+ ' +---------------- 2 ----------------',
+ ' | TypeError: 1',
+ ' +---------------- ... ----------------',
+ ' | and 8 more exceptions',
+ ' +------------------------------------',
+ '']
self.assertEqual(formatted, expected)
@@ -2876,22 +2876,22 @@ def test_max_group_depth(self):
formatted = ''.join(teg.format()).split('\n')
expected = [
- f' | ExceptionGroup: exc (3 sub-exceptions)',
- f' +-+---------------- 1 ----------------',
- f' | ValueError: -2',
- f' +---------------- 2 ----------------',
- f' | ExceptionGroup: exc (3 sub-exceptions)',
- f' +-+---------------- 1 ----------------',
- f' | ValueError: -1',
- f' +---------------- 2 ----------------',
- f' | ... (max_group_depth is 2)',
- f' +---------------- 3 ----------------',
- f' | ValueError: 1',
- f' +------------------------------------',
- f' +---------------- 3 ----------------',
- f' | ValueError: 2',
- f' +------------------------------------',
- f'']
+ ' | ExceptionGroup: exc (3 sub-exceptions)',
+ ' +-+---------------- 1 ----------------',
+ ' | ValueError: -2',
+ ' +---------------- 2 ----------------',
+ ' | ExceptionGroup: exc (3 sub-exceptions)',
+ ' +-+---------------- 1 ----------------',
+ ' | ValueError: -1',
+ ' +---------------- 2 ----------------',
+ ' | ... (max_group_depth is 2)',
+ ' +---------------- 3 ----------------',
+ ' | ValueError: 1',
+ ' +------------------------------------',
+ ' +---------------- 3 ----------------',
+ ' | ValueError: 2',
+ ' +------------------------------------',
+ '']
self.assertEqual(formatted, expected)
diff --git a/Lib/test/test_type_cache.py b/Lib/test/test_type_cache.py
index 8502f6b0584b00..24f83cd3e172c7 100644
--- a/Lib/test/test_type_cache.py
+++ b/Lib/test/test_type_cache.py
@@ -9,6 +9,7 @@
# Skip this test if the _testcapi module isn't available.
type_get_version = import_helper.import_module('_testcapi').type_get_version
+type_assign_version = import_helper.import_module('_testcapi').type_assign_version
@support.cpython_only
@@ -42,6 +43,19 @@ def test_tp_version_tag_unique(self):
self.assertEqual(len(set(all_version_tags)), 30,
msg=f"{all_version_tags} contains non-unique versions")
+ def test_type_assign_version(self):
+ class C:
+ x = 5
+
+ self.assertEqual(type_assign_version(C), 1)
+ c_ver = type_get_version(C)
+
+ C.x = 6
+ self.assertEqual(type_get_version(C), 0)
+ self.assertEqual(type_assign_version(C), 1)
+ self.assertNotEqual(type_get_version(C), 0)
+ self.assertNotEqual(type_get_version(C), c_ver)
+
if __name__ == "__main__":
support.run_unittest(TypeCacheTests)
diff --git a/Lib/test/test_type_comments.py b/Lib/test/test_type_comments.py
index 8db7394d1512aa..aba4a44be9da96 100644
--- a/Lib/test/test_type_comments.py
+++ b/Lib/test/test_type_comments.py
@@ -272,7 +272,7 @@ def test_matmul(self):
pass
def test_fstring(self):
- for tree in self.parse_all(fstring, minver=6):
+ for tree in self.parse_all(fstring):
pass
def test_underscorednumber(self):
diff --git a/Lib/test/test_types.py b/Lib/test/test_types.py
index af095632a36fcb..89548100da62d7 100644
--- a/Lib/test/test_types.py
+++ b/Lib/test/test_types.py
@@ -925,6 +925,35 @@ def test_or_type_operator_with_SpecialForm(self):
assert typing.Optional[int] | str == typing.Union[int, str, None]
assert typing.Union[int, bool] | str == typing.Union[int, bool, str]
+ def test_or_type_operator_with_Literal(self):
+ Literal = typing.Literal
+ self.assertEqual((Literal[1] | Literal[2]).__args__,
+ (Literal[1], Literal[2]))
+
+ self.assertEqual((Literal[0] | Literal[False]).__args__,
+ (Literal[0], Literal[False]))
+ self.assertEqual((Literal[1] | Literal[True]).__args__,
+ (Literal[1], Literal[True]))
+
+ self.assertEqual(Literal[1] | Literal[1], Literal[1])
+ self.assertEqual(Literal['a'] | Literal['a'], Literal['a'])
+
+ import enum
+ class Ints(enum.IntEnum):
+ A = 0
+ B = 1
+
+ self.assertEqual(Literal[Ints.A] | Literal[Ints.A], Literal[Ints.A])
+ self.assertEqual(Literal[Ints.B] | Literal[Ints.B], Literal[Ints.B])
+
+ self.assertEqual((Literal[Ints.B] | Literal[Ints.A]).__args__,
+ (Literal[Ints.B], Literal[Ints.A]))
+
+ self.assertEqual((Literal[0] | Literal[Ints.A]).__args__,
+ (Literal[0], Literal[Ints.A]))
+ self.assertEqual((Literal[1] | Literal[Ints.B]).__args__,
+ (Literal[1], Literal[Ints.B]))
+
def test_or_type_repr(self):
assert repr(int | str) == "int | str"
assert repr((int | str) | list) == "int | str | list"
@@ -1360,6 +1389,67 @@ class C: pass
D = types.new_class('D', (A(), C, B()), {})
self.assertEqual(D.__bases__, (A1, A2, A3, C, B1, B2))
+ def test_get_original_bases(self):
+ T = typing.TypeVar('T')
+ class A: pass
+ class B(typing.Generic[T]): pass
+ class C(B[int]): pass
+ class D(B[str], float): pass
+ self.assertEqual(types.get_original_bases(A), (object,))
+ self.assertEqual(types.get_original_bases(B), (typing.Generic[T],))
+ self.assertEqual(types.get_original_bases(C), (B[int],))
+ self.assertEqual(types.get_original_bases(int), (object,))
+ self.assertEqual(types.get_original_bases(D), (B[str], float))
+
+ class E(list[T]): pass
+ class F(list[int]): pass
+
+ self.assertEqual(types.get_original_bases(E), (list[T],))
+ self.assertEqual(types.get_original_bases(F), (list[int],))
+
+ class ClassBasedNamedTuple(typing.NamedTuple):
+ x: int
+
+ class GenericNamedTuple(typing.NamedTuple, typing.Generic[T]):
+ x: T
+
+ CallBasedNamedTuple = typing.NamedTuple("CallBasedNamedTuple", [("x", int)])
+
+ self.assertIs(
+ types.get_original_bases(ClassBasedNamedTuple)[0], typing.NamedTuple
+ )
+ self.assertEqual(
+ types.get_original_bases(GenericNamedTuple),
+ (typing.NamedTuple, typing.Generic[T])
+ )
+ self.assertIs(
+ types.get_original_bases(CallBasedNamedTuple)[0], typing.NamedTuple
+ )
+
+ class ClassBasedTypedDict(typing.TypedDict):
+ x: int
+
+ class GenericTypedDict(typing.TypedDict, typing.Generic[T]):
+ x: T
+
+ CallBasedTypedDict = typing.TypedDict("CallBasedTypedDict", {"x": int})
+
+ self.assertIs(
+ types.get_original_bases(ClassBasedTypedDict)[0],
+ typing.TypedDict
+ )
+ self.assertEqual(
+ types.get_original_bases(GenericTypedDict),
+ (typing.TypedDict, typing.Generic[T])
+ )
+ self.assertIs(
+ types.get_original_bases(CallBasedTypedDict)[0],
+ typing.TypedDict
+ )
+
+ with self.assertRaisesRegex(TypeError, "Expected an instance of type"):
+ types.get_original_bases(object())
+
# Many of the following tests are derived from test_descr.py
def test_prepare_class(self):
# Basic test of metaclass derivation
diff --git a/Lib/test/test_typing.py b/Lib/test/test_typing.py
index b8eee9a570a301..f36bb958c88ef9 100644
--- a/Lib/test/test_typing.py
+++ b/Lib/test/test_typing.py
@@ -855,6 +855,14 @@ def test_accepts_single_type(self):
(*tuple[int],)
Unpack[Tuple[int]]
+ def test_dir(self):
+ dir_items = set(dir(Unpack[Tuple[int]]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_rejects_multiple_types(self):
with self.assertRaises(TypeError):
Unpack[Tuple[int], Tuple[str]]
@@ -1699,6 +1707,14 @@ def test_repr(self):
u = Optional[str]
self.assertEqual(repr(u), 'typing.Optional[str]')
+ def test_dir(self):
+ dir_items = set(dir(Union[str, int]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_cannot_subclass(self):
with self.assertRaisesRegex(TypeError,
r'Cannot subclass typing\.Union'):
@@ -1773,6 +1789,35 @@ def Elem(*args):
Union[Elem, str] # Nor should this
+ def test_union_of_literals(self):
+ self.assertEqual(Union[Literal[1], Literal[2]].__args__,
+ (Literal[1], Literal[2]))
+ self.assertEqual(Union[Literal[1], Literal[1]],
+ Literal[1])
+
+ self.assertEqual(Union[Literal[False], Literal[0]].__args__,
+ (Literal[False], Literal[0]))
+ self.assertEqual(Union[Literal[True], Literal[1]].__args__,
+ (Literal[True], Literal[1]))
+
+ import enum
+ class Ints(enum.IntEnum):
+ A = 0
+ B = 1
+
+ self.assertEqual(Union[Literal[Ints.A], Literal[Ints.A]],
+ Literal[Ints.A])
+ self.assertEqual(Union[Literal[Ints.B], Literal[Ints.B]],
+ Literal[Ints.B])
+
+ self.assertEqual(Union[Literal[Ints.A], Literal[Ints.B]].__args__,
+ (Literal[Ints.A], Literal[Ints.B]))
+
+ self.assertEqual(Union[Literal[0], Literal[Ints.A], Literal[False]].__args__,
+ (Literal[0], Literal[Ints.A], Literal[False]))
+ self.assertEqual(Union[Literal[1], Literal[Ints.B], Literal[True]].__args__,
+ (Literal[1], Literal[Ints.B], Literal[True]))
+
class TupleTests(BaseTestCase):
@@ -1839,6 +1884,15 @@ def test_eq_hash(self):
self.assertNotEqual(C, Callable[..., int])
self.assertNotEqual(C, Callable)
+ def test_dir(self):
+ Callable = self.Callable
+ dir_items = set(dir(Callable[..., int]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_cannot_instantiate(self):
Callable = self.Callable
with self.assertRaises(TypeError):
@@ -2131,6 +2185,13 @@ def test_basics(self):
Literal[Literal[1, 2], Literal[4, 5]]
Literal[b"foo", u"bar"]
+ def test_enum(self):
+ import enum
+ class My(enum.Enum):
+ A = 'A'
+
+ self.assertEqual(Literal[My.A].__args__, (My.A,))
+
def test_illegal_parameters_do_not_raise_runtime_errors(self):
# Type checkers should reject these types, but we do not
# raise errors at runtime to maintain maximum flexibility.
@@ -2151,6 +2212,14 @@ def test_repr(self):
self.assertEqual(repr(Literal[None]), "typing.Literal[None]")
self.assertEqual(repr(Literal[1, 2, 3, 3]), "typing.Literal[1, 2, 3]")
+ def test_dir(self):
+ dir_items = set(dir(Literal[1, 2, 3]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_cannot_init(self):
with self.assertRaises(TypeError):
Literal()
@@ -2212,6 +2281,20 @@ def test_flatten(self):
self.assertEqual(l, Literal[1, 2, 3])
self.assertEqual(l.__args__, (1, 2, 3))
+ def test_does_not_flatten_enum(self):
+ import enum
+ class Ints(enum.IntEnum):
+ A = 1
+ B = 2
+
+ l = Literal[
+ Literal[Ints.A],
+ Literal[Ints.B],
+ Literal[1],
+ Literal[2],
+ ]
+ self.assertEqual(l.__args__, (Ints.A, Ints.B, 1, 2))
+
XK = TypeVar('XK', str, bytes)
XV = TypeVar('XV')
@@ -6662,6 +6745,22 @@ def test_copy_and_pickle(self):
self.assertEqual(jane2, jane)
self.assertIsInstance(jane2, cls)
+ def test_orig_bases(self):
+ T = TypeVar('T')
+
+ class SimpleNamedTuple(NamedTuple):
+ pass
+
+ class GenericNamedTuple(NamedTuple, Generic[T]):
+ pass
+
+ self.assertEqual(SimpleNamedTuple.__orig_bases__, (NamedTuple,))
+ self.assertEqual(GenericNamedTuple.__orig_bases__, (NamedTuple, Generic[T]))
+
+ CallNamedTuple = NamedTuple('CallNamedTuple', [])
+
+ self.assertEqual(CallNamedTuple.__orig_bases__, (NamedTuple,))
+
class TypedDictTests(BaseTestCase):
def test_basics_functional_syntax(self):
@@ -7093,6 +7192,49 @@ class TD(TypedDict):
self.assertIs(type(a), dict)
self.assertEqual(a, {'a': 1})
+ def test_orig_bases(self):
+ T = TypeVar('T')
+
+ class Parent(TypedDict):
+ pass
+
+ class Child(Parent):
+ pass
+
+ class OtherChild(Parent):
+ pass
+
+ class MixedChild(Child, OtherChild, Parent):
+ pass
+
+ class GenericParent(TypedDict, Generic[T]):
+ pass
+
+ class GenericChild(GenericParent[int]):
+ pass
+
+ class OtherGenericChild(GenericParent[str]):
+ pass
+
+ class MixedGenericChild(GenericChild, OtherGenericChild, GenericParent[float]):
+ pass
+
+ class MultipleGenericBases(GenericParent[int], GenericParent[float]):
+ pass
+
+ CallTypedDict = TypedDict('CallTypedDict', {})
+
+ self.assertEqual(Parent.__orig_bases__, (TypedDict,))
+ self.assertEqual(Child.__orig_bases__, (Parent,))
+ self.assertEqual(OtherChild.__orig_bases__, (Parent,))
+ self.assertEqual(MixedChild.__orig_bases__, (Child, OtherChild, Parent,))
+ self.assertEqual(GenericParent.__orig_bases__, (TypedDict, Generic[T]))
+ self.assertEqual(GenericChild.__orig_bases__, (GenericParent[int],))
+ self.assertEqual(OtherGenericChild.__orig_bases__, (GenericParent[str],))
+ self.assertEqual(MixedGenericChild.__orig_bases__, (GenericChild, OtherGenericChild, GenericParent[float]))
+ self.assertEqual(MultipleGenericBases.__orig_bases__, (GenericParent[int], GenericParent[float]))
+ self.assertEqual(CallTypedDict.__orig_bases__, (TypedDict,))
+
class RequiredTests(BaseTestCase):
@@ -7315,6 +7457,15 @@ def test_repr(self):
"typing.Annotated[typing.List[int], 4, 5]"
)
+ def test_dir(self):
+ dir_items = set(dir(Annotated[int, 4]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ '__metadata__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_flatten(self):
A = Annotated[Annotated[int, 4], 5]
self.assertEqual(A, Annotated[int, 4, 5])
@@ -8033,6 +8184,15 @@ class MyClass: ...
c = Concatenate[MyClass, P]
self.assertNotEqual(c, Concatenate)
+ def test_dir(self):
+ P = ParamSpec('P')
+ dir_items = set(dir(Concatenate[int, P]))
+ for required_item in [
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+
def test_valid_uses(self):
P = ParamSpec('P')
T = TypeVar('T')
@@ -8310,10 +8470,18 @@ class Foo(Generic[T]):
def bar(self):
pass
baz = 3
+ __magic__ = 4
+
# The class attributes of the original class should be visible even
# in dir() of the GenericAlias. See bpo-45755.
- self.assertIn('bar', dir(Foo[int]))
- self.assertIn('baz', dir(Foo[int]))
+ dir_items = set(dir(Foo[int]))
+ for required_item in [
+ 'bar', 'baz',
+ '__args__', '__parameters__', '__origin__',
+ ]:
+ with self.subTest(required_item=required_item):
+ self.assertIn(required_item, dir_items)
+ self.assertNotIn('__magic__', dir_items)
class RevealTypeTests(BaseTestCase):
diff --git a/Lib/test/test_unittest/test_runner.py b/Lib/test/test_unittest/test_runner.py
index 1ce42a106c5883..ceb4c8acde532c 100644
--- a/Lib/test/test_unittest/test_runner.py
+++ b/Lib/test/test_unittest/test_runner.py
@@ -1367,7 +1367,7 @@ def testSpecifiedStreamUsed(self):
self.assertTrue(runner.stream.stream is f)
def test_durations(self):
- def run(test, expect_durations):
+ def run(test, *, expect_durations=True):
stream = BufferedWriter()
runner = unittest.TextTestRunner(stream=stream, durations=5, verbosity=2)
result = runner.run(test)
@@ -1389,21 +1389,21 @@ class Foo(unittest.TestCase):
def test_1(self):
pass
- run(Foo('test_1'), True)
+ run(Foo('test_1'), expect_durations=True)
# failure
class Foo(unittest.TestCase):
def test_1(self):
self.assertEqual(0, 1)
- run(Foo('test_1'), True)
+ run(Foo('test_1'), expect_durations=True)
# error
class Foo(unittest.TestCase):
def test_1(self):
1 / 0
- run(Foo('test_1'), True)
+ run(Foo('test_1'), expect_durations=True)
# error in setUp and tearDown
@@ -1414,7 +1414,7 @@ def setUp(self):
def test_1(self):
pass
- run(Foo('test_1'), True)
+ run(Foo('test_1'), expect_durations=True)
# skip (expect no durations)
class Foo(unittest.TestCase):
@@ -1422,7 +1422,7 @@ class Foo(unittest.TestCase):
def test_1(self):
pass
- run(Foo('test_1'), False)
+ run(Foo('test_1'), expect_durations=False)
diff --git a/Lib/test/test_unittest/testmock/testhelpers.py b/Lib/test/test_unittest/testmock/testhelpers.py
index dc4d004cda8a75..74785a83757a92 100644
--- a/Lib/test/test_unittest/testmock/testhelpers.py
+++ b/Lib/test/test_unittest/testmock/testhelpers.py
@@ -952,6 +952,24 @@ def __getattr__(self, attribute):
self.assertFalse(hasattr(autospec, '__name__'))
+ def test_autospec_signature_staticmethod(self):
+ class Foo:
+ @staticmethod
+ def static_method(a, b=10, *, c): pass
+
+ mock = create_autospec(Foo.__dict__['static_method'])
+ self.assertEqual(inspect.signature(Foo.static_method), inspect.signature(mock))
+
+
+ def test_autospec_signature_classmethod(self):
+ class Foo:
+ @classmethod
+ def class_method(cls, a, b=10, *, c): pass
+
+ mock = create_autospec(Foo.__dict__['class_method'])
+ self.assertEqual(inspect.signature(Foo.class_method), inspect.signature(mock))
+
+
def test_spec_inspect_signature(self):
def myfunc(x, y): pass
diff --git a/Lib/test/test_unittest/testmock/testpatch.py b/Lib/test/test_unittest/testmock/testpatch.py
index 8ceb5d973e1aaf..833d7da1f31a20 100644
--- a/Lib/test/test_unittest/testmock/testpatch.py
+++ b/Lib/test/test_unittest/testmock/testpatch.py
@@ -996,6 +996,36 @@ def test_autospec_classmethod(self):
method.assert_called_once_with()
+ def test_autospec_staticmethod_signature(self):
+ # Patched methods which are decorated with @staticmethod should have the same signature
+ class Foo:
+ @staticmethod
+ def static_method(a, b=10, *, c): pass
+
+ Foo.static_method(1, 2, c=3)
+
+ with patch.object(Foo, 'static_method', autospec=True) as method:
+ method(1, 2, c=3)
+ self.assertRaises(TypeError, method)
+ self.assertRaises(TypeError, method, 1)
+ self.assertRaises(TypeError, method, 1, 2, 3, c=4)
+
+
+ def test_autospec_classmethod_signature(self):
+ # Patched methods which are decorated with @classmethod should have the same signature
+ class Foo:
+ @classmethod
+ def class_method(cls, a, b=10, *, c): pass
+
+ Foo.class_method(1, 2, c=3)
+
+ with patch.object(Foo, 'class_method', autospec=True) as method:
+ method(1, 2, c=3)
+ self.assertRaises(TypeError, method)
+ self.assertRaises(TypeError, method, 1)
+ self.assertRaises(TypeError, method, 1, 2, 3, c=4)
+
+
def test_autospec_with_new(self):
patcher = patch('%s.function' % __name__, new=3, autospec=True)
self.assertRaises(TypeError, patcher.start)
diff --git a/Lib/test/test_urllib2.py b/Lib/test/test_urllib2.py
index 633d596ac3de3f..b7c6f6dd8f1b99 100644
--- a/Lib/test/test_urllib2.py
+++ b/Lib/test/test_urllib2.py
@@ -3,6 +3,7 @@
from test.support import os_helper
from test.support import warnings_helper
from test import test_urllib
+from unittest import mock
import os
import io
@@ -484,7 +485,18 @@ def build_test_opener(*handler_instances):
return opener
-class MockHTTPHandler(urllib.request.BaseHandler):
+class MockHTTPHandler(urllib.request.HTTPHandler):
+ # Very simple mock HTTP handler with no special behavior other than using a mock HTTP connection
+
+ def __init__(self, debuglevel=None):
+ super(MockHTTPHandler, self).__init__(debuglevel=debuglevel)
+ self.httpconn = MockHTTPClass()
+
+ def http_open(self, req):
+ return self.do_open(self.httpconn, req)
+
+
+class MockHTTPHandlerRedirect(urllib.request.BaseHandler):
# useful for testing redirections and auth
# sends supplied headers and code as first response
# sends 200 OK as second response
@@ -512,12 +524,12 @@ def http_open(self, req):
return MockResponse(200, "OK", msg, "", req.get_full_url())
-class MockHTTPSHandler(urllib.request.AbstractHTTPHandler):
+class MockHTTPSHandler(urllib.request.HTTPSHandler):
# Useful for testing the Proxy-Authorization request by verifying the
# properties of httpcon
- def __init__(self, debuglevel=0):
- urllib.request.AbstractHTTPHandler.__init__(self, debuglevel=debuglevel)
+ def __init__(self, debuglevel=None, context=None, check_hostname=None):
+ super(MockHTTPSHandler, self).__init__(debuglevel, context, check_hostname)
self.httpconn = MockHTTPClass()
def https_open(self, req):
@@ -1048,12 +1060,35 @@ def test_http_body_array(self):
newreq = h.do_request_(req)
self.assertEqual(int(newreq.get_header('Content-length')),16)
- def test_http_handler_debuglevel(self):
+ def test_http_handler_global_debuglevel(self):
+ with mock.patch.object(http.client.HTTPConnection, 'debuglevel', 6):
+ o = OpenerDirector()
+ h = MockHTTPHandler()
+ o.add_handler(h)
+ o.open("http://www.example.com")
+ self.assertEqual(h._debuglevel, 6)
+
+ def test_http_handler_local_debuglevel(self):
+ o = OpenerDirector()
+ h = MockHTTPHandler(debuglevel=5)
+ o.add_handler(h)
+ o.open("http://www.example.com")
+ self.assertEqual(h._debuglevel, 5)
+
+ def test_https_handler_global_debuglevel(self):
+ with mock.patch.object(http.client.HTTPSConnection, 'debuglevel', 7):
+ o = OpenerDirector()
+ h = MockHTTPSHandler()
+ o.add_handler(h)
+ o.open("https://www.example.com")
+ self.assertEqual(h._debuglevel, 7)
+
+ def test_https_handler_local_debuglevel(self):
o = OpenerDirector()
- h = MockHTTPSHandler(debuglevel=1)
+ h = MockHTTPSHandler(debuglevel=4)
o.add_handler(h)
o.open("https://www.example.com")
- self.assertEqual(h._debuglevel, 1)
+ self.assertEqual(h._debuglevel, 4)
def test_http_doubleslash(self):
# Checks the presence of any unnecessary double slash in url does not
@@ -1289,7 +1324,7 @@ def test_cookie_redirect(self):
cj = CookieJar()
interact_netscape(cj, "http://www.example.com/", "spam=eggs")
- hh = MockHTTPHandler(302, "Location: http://www.cracker.com/\r\n\r\n")
+ hh = MockHTTPHandlerRedirect(302, "Location: http://www.cracker.com/\r\n\r\n")
hdeh = urllib.request.HTTPDefaultErrorHandler()
hrh = urllib.request.HTTPRedirectHandler()
cp = urllib.request.HTTPCookieProcessor(cj)
@@ -1299,7 +1334,7 @@ def test_cookie_redirect(self):
def test_redirect_fragment(self):
redirected_url = 'http://www.example.com/index.html#OK\r\n\r\n'
- hh = MockHTTPHandler(302, 'Location: ' + redirected_url)
+ hh = MockHTTPHandlerRedirect(302, 'Location: ' + redirected_url)
hdeh = urllib.request.HTTPDefaultErrorHandler()
hrh = urllib.request.HTTPRedirectHandler()
o = build_test_opener(hh, hdeh, hrh)
@@ -1484,7 +1519,7 @@ def check_basic_auth(self, headers, realm):
password_manager = MockPasswordManager()
auth_handler = urllib.request.HTTPBasicAuthHandler(password_manager)
body = '\r\n'.join(headers) + '\r\n\r\n'
- http_handler = MockHTTPHandler(401, body)
+ http_handler = MockHTTPHandlerRedirect(401, body)
opener.add_handler(auth_handler)
opener.add_handler(http_handler)
self._test_basic_auth(opener, auth_handler, "Authorization",
@@ -1544,7 +1579,7 @@ def test_proxy_basic_auth(self):
password_manager = MockPasswordManager()
auth_handler = urllib.request.ProxyBasicAuthHandler(password_manager)
realm = "ACME Networks"
- http_handler = MockHTTPHandler(
+ http_handler = MockHTTPHandlerRedirect(
407, 'Proxy-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
opener.add_handler(auth_handler)
opener.add_handler(http_handler)
@@ -1588,7 +1623,7 @@ def http_error_401(self, *args, **kwds):
digest_handler = TestDigestAuthHandler(password_manager)
basic_handler = TestBasicAuthHandler(password_manager)
realm = "ACME Networks"
- http_handler = MockHTTPHandler(
+ http_handler = MockHTTPHandlerRedirect(
401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % realm)
opener.add_handler(basic_handler)
opener.add_handler(digest_handler)
@@ -1608,7 +1643,7 @@ def test_unsupported_auth_digest_handler(self):
opener = OpenerDirector()
# While using DigestAuthHandler
digest_auth_handler = urllib.request.HTTPDigestAuthHandler(None)
- http_handler = MockHTTPHandler(
+ http_handler = MockHTTPHandlerRedirect(
401, 'WWW-Authenticate: Kerberos\r\n\r\n')
opener.add_handler(digest_auth_handler)
opener.add_handler(http_handler)
@@ -1618,7 +1653,7 @@ def test_unsupported_auth_basic_handler(self):
# While using BasicAuthHandler
opener = OpenerDirector()
basic_auth_handler = urllib.request.HTTPBasicAuthHandler(None)
- http_handler = MockHTTPHandler(
+ http_handler = MockHTTPHandlerRedirect(
401, 'WWW-Authenticate: NTLM\r\n\r\n')
opener.add_handler(basic_auth_handler)
opener.add_handler(http_handler)
@@ -1705,7 +1740,7 @@ def test_basic_prior_auth_send_after_first_success(self):
opener = OpenerDirector()
opener.add_handler(auth_prior_handler)
- http_handler = MockHTTPHandler(
+ http_handler = MockHTTPHandlerRedirect(
401, 'WWW-Authenticate: Basic realm="%s"\r\n\r\n' % None)
opener.add_handler(http_handler)
diff --git a/Lib/test/test_urllib2net.py b/Lib/test/test_urllib2net.py
index 5da41c37bbfb8e..d8d882b2d33589 100644
--- a/Lib/test/test_urllib2net.py
+++ b/Lib/test/test_urllib2net.py
@@ -134,7 +134,9 @@ def setUp(self):
# They do sometimes catch some major disasters, though.
def test_ftp(self):
+ # Testing the same URL twice exercises the caching in CacheFTPHandler
urls = [
+ 'ftp://www.pythontest.net/README',
'ftp://www.pythontest.net/README',
('ftp://www.pythontest.net/non-existent-file',
None, urllib.error.URLError),
diff --git a/Lib/test/test_venv.py b/Lib/test/test_venv.py
index 4e18dfc23c40c2..95944c7c711620 100644
--- a/Lib/test/test_venv.py
+++ b/Lib/test/test_venv.py
@@ -227,7 +227,6 @@ def pip_cmd_checker(cmd, **kwargs):
'install',
'--upgrade',
'pip',
- 'setuptools'
]
)
@@ -601,9 +600,15 @@ def test_zippath_from_non_installed_posix(self):
ld_library_path_env = "DYLD_LIBRARY_PATH"
else:
ld_library_path_env = "LD_LIBRARY_PATH"
- subprocess.check_call(cmd,
- env={"PYTHONPATH": pythonpath,
- ld_library_path_env: ld_library_path})
+ # Note that in address sanitizer mode, the current runtime
+ # implementation leaks memory due to not being able to correctly
+ # clean all unicode objects during runtime shutdown. Therefore,
+ # this uses subprocess.run instead of subprocess.check_call to
+ # maintain the core of the test while not failing due to the refleaks.
+ # This should be able to use check_call once all refleaks are fixed.
+ subprocess.run(cmd,
+ env={"PYTHONPATH": pythonpath,
+ ld_library_path_env: ld_library_path})
envpy = os.path.join(self.env_dir, self.bindir, self.exe)
# Now check the venv created from the non-installed python has
# correct zip path in pythonpath.
@@ -611,6 +616,22 @@ def test_zippath_from_non_installed_posix(self):
out, err = check_output(cmd)
self.assertTrue(zip_landmark.encode() in out)
+ def test_activate_shell_script_has_no_dos_newlines(self):
+ """
+ Test that the `activate` shell script contains no CR LF.
+ This is relevant for Cygwin, as the Windows build might have
+ converted line endings accidentally.
+ """
+ venv_dir = pathlib.Path(self.env_dir)
+ rmtree(venv_dir)
+ [[scripts_dir], *_] = self.ENV_SUBDIRS
+ script_path = venv_dir / scripts_dir / "activate"
+ venv.create(venv_dir)
+ with open(script_path, 'rb') as script:
+ for i, line in enumerate(script, 1):
+ error_message = f"CR LF found in line {i}"
+ self.assertFalse(line.endswith(b'\r\n'), error_message)
+
@requireVenvCreate
class EnsurePipTest(BaseTest):
"""Test venv module installation of pip."""
@@ -729,7 +750,6 @@ def do_test_with_pip(self, system_site_packages):
# future pip versions, this test can likely be relaxed further.
out = out.decode("latin-1") # Force to text, prevent decoding errors
self.assertIn("Successfully uninstalled pip", out)
- self.assertIn("Successfully uninstalled setuptools", out)
# Check pip is now gone from the virtual environment. This only
# applies in the system_site_packages=False case, because in the
# other case, pip may still be available in the system site-packages
diff --git a/Lib/test/test_weakref.py b/Lib/test/test_weakref.py
index 7c5920797d2538..1bc1d05f7daba9 100644
--- a/Lib/test/test_weakref.py
+++ b/Lib/test/test_weakref.py
@@ -116,6 +116,17 @@ def test_basic_ref(self):
del o
repr(wr)
+ def test_repr_failure_gh99184(self):
+ class MyConfig(dict):
+ def __getattr__(self, x):
+ return self[x]
+
+ obj = MyConfig(offset=5)
+ obj_weakref = weakref.ref(obj)
+
+ self.assertIn('MyConfig', repr(obj_weakref))
+ self.assertIn('MyConfig', str(obj_weakref))
+
def test_basic_callback(self):
self.check_basic_callback(C)
self.check_basic_callback(create_function)
diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py
index 769ab67b0f5611..924a962781a75b 100644
--- a/Lib/test/test_winreg.py
+++ b/Lib/test/test_winreg.py
@@ -1,11 +1,12 @@
# Test the windows specific win32reg module.
# Only win32reg functions not hit here: FlushKey, LoadKey and SaveKey
+import gc
import os, sys, errno
-import unittest
-from test.support import import_helper
import threading
+import unittest
from platform import machine, win32_edition
+from test.support import cpython_only, import_helper
# Do this first so test will be skipped if module doesn't exist
import_helper.import_module('winreg', required_on=['win'])
@@ -49,6 +50,17 @@
("Japanese 日本", "日本語", REG_SZ),
]
+
+@cpython_only
+class HeapTypeTests(unittest.TestCase):
+ def test_have_gc(self):
+ self.assertTrue(gc.is_tracked(HKEYType))
+
+ def test_immutable(self):
+ with self.assertRaisesRegex(TypeError, "immutable"):
+ HKEYType.foo = "bar"
+
+
class BaseWinregTests(unittest.TestCase):
def setUp(self):
diff --git a/Lib/test/wheel-0.40.0-py3-none-any.whl b/Lib/test/wheel-0.40.0-py3-none-any.whl
new file mode 100644
index 00000000000000..410132385bba4d
Binary files /dev/null and b/Lib/test/wheel-0.40.0-py3-none-any.whl differ
diff --git a/Lib/tkinter/__init__.py b/Lib/tkinter/__init__.py
index 479daf0e5abfc3..bf0b3b92155938 100644
--- a/Lib/tkinter/__init__.py
+++ b/Lib/tkinter/__init__.py
@@ -3430,8 +3430,7 @@ def entryconfigure(self, index, cnf=None, **kw):
def index(self, index):
"""Return the index of a menu item identified by INDEX."""
i = self.tk.call(self._w, 'index', index)
- if i == 'none': return None
- return self.tk.getint(i)
+ return None if i in ('', 'none') else self.tk.getint(i) # GH-103685.
def invoke(self, index):
"""Invoke a menu item identified by INDEX and execute
diff --git a/Lib/token.py b/Lib/token.py
index 95b107c6643b3f..1459d12b376f82 100644
--- a/Lib/token.py
+++ b/Lib/token.py
@@ -57,18 +57,22 @@
RARROW = 51
ELLIPSIS = 52
COLONEQUAL = 53
-OP = 54
-AWAIT = 55
-ASYNC = 56
-TYPE_IGNORE = 57
-TYPE_COMMENT = 58
-SOFT_KEYWORD = 59
+EXCLAMATION = 54
+OP = 55
+AWAIT = 56
+ASYNC = 57
+TYPE_IGNORE = 58
+TYPE_COMMENT = 59
+SOFT_KEYWORD = 60
+FSTRING_START = 61
+FSTRING_MIDDLE = 62
+FSTRING_END = 63
# These aren't used by the C tokenizer but are needed for tokenize.py
-ERRORTOKEN = 60
-COMMENT = 61
-NL = 62
-ENCODING = 63
-N_TOKENS = 64
+ERRORTOKEN = 64
+COMMENT = 65
+NL = 66
+ENCODING = 67
+N_TOKENS = 68
# Special definitions for cooperation with parser
NT_OFFSET = 256
@@ -78,6 +82,7 @@
__all__.extend(tok_name.values())
EXACT_TOKEN_TYPES = {
+ '!': EXCLAMATION,
'!=': NOTEQUAL,
'%': PERCENT,
'%=': PERCENTEQUAL,
diff --git a/Lib/types.py b/Lib/types.py
index aa8a1c84722399..6110e6e1de7249 100644
--- a/Lib/types.py
+++ b/Lib/types.py
@@ -143,6 +143,38 @@ def _calculate_meta(meta, bases):
"of the metaclasses of all its bases")
return winner
+
+def get_original_bases(cls, /):
+ """Return the class's "original" bases prior to modification by `__mro_entries__`.
+
+ Examples::
+
+ from typing import TypeVar, Generic, NamedTuple, TypedDict
+
+ T = TypeVar("T")
+ class Foo(Generic[T]): ...
+ class Bar(Foo[int], float): ...
+ class Baz(list[str]): ...
+ Eggs = NamedTuple("Eggs", [("a", int), ("b", str)])
+ Spam = TypedDict("Spam", {"a": int, "b": str})
+
+ assert get_original_bases(Bar) == (Foo[int], float)
+ assert get_original_bases(Baz) == (list[str],)
+ assert get_original_bases(Eggs) == (NamedTuple,)
+ assert get_original_bases(Spam) == (TypedDict,)
+ assert get_original_bases(int) == (object,)
+ """
+ try:
+ return cls.__orig_bases__
+ except AttributeError:
+ try:
+ return cls.__bases__
+ except AttributeError:
+ raise TypeError(
+ f'Expected an instance of type, not {type(cls).__name__!r}'
+ ) from None
+
+
class DynamicClassAttribute:
"""Route attribute access on a class to __getattr__.
diff --git a/Lib/typing.py b/Lib/typing.py
index e4877a35952aac..9ef3d1d4987352 100644
--- a/Lib/typing.py
+++ b/Lib/typing.py
@@ -2191,6 +2191,8 @@ class _AnnotatedAlias(_NotIterable, _GenericAlias, _root=True):
with extra annotations. The alias behaves like a normal typing alias,
instantiating is the same as instantiating the underlying type, binding
it to types is also the same.
+
+ The metadata itself is stored in a '__metadata__' attribute as a tuple.
"""
def __init__(self, origin, metadata):
if isinstance(origin, _AnnotatedAlias):
@@ -2246,6 +2248,10 @@ class Annotated:
Details:
- It's an error to call `Annotated` with less than two arguments.
+ - Access the metadata via the ``__metadata__`` attribute::
+
+ Annotated[int, '$'].__metadata__ == ('$',)
+
- Nested Annotated are flattened::
Annotated[Annotated[T, Ann1, Ann2], Ann3] == Annotated[T, Ann1, Ann2, Ann3]
@@ -2993,7 +2999,9 @@ class Employee(NamedTuple):
elif kwargs:
raise TypeError("Either list of fields or keywords"
" can be provided to NamedTuple, not both")
- return _make_nmtuple(typename, fields, module=_caller())
+ nt = _make_nmtuple(typename, fields, module=_caller())
+ nt.__orig_bases__ = (NamedTuple,)
+ return nt
_NamedTuple = type.__new__(NamedTupleMeta, 'NamedTuple', (), {})
@@ -3025,6 +3033,9 @@ def __new__(cls, name, bases, ns, total=True):
tp_dict = type.__new__(_TypedDictMeta, name, (*generic_base, dict), ns)
+ if not hasattr(tp_dict, '__orig_bases__'):
+ tp_dict.__orig_bases__ = bases
+
annotations = {}
own_annotations = ns.get('__annotations__', {})
msg = "TypedDict('Name', {f0: t0, f1: t1, ...}); each t must be a type"
@@ -3135,7 +3146,9 @@ class body be required.
# Setting correct module is necessary to make typed dict classes pickleable.
ns['__module__'] = module
- return _TypedDictMeta(typename, (), ns, total=total)
+ td = _TypedDictMeta(typename, (), ns, total=total)
+ td.__orig_bases__ = (TypedDict,)
+ return td
_TypedDict = type.__new__(_TypedDictMeta, 'TypedDict', (), {})
TypedDict.__mro_entries__ = lambda bases: (_TypedDict,)
diff --git a/Lib/unittest/mock.py b/Lib/unittest/mock.py
index 0f93cb53c3d5ce..7ca085760650af 100644
--- a/Lib/unittest/mock.py
+++ b/Lib/unittest/mock.py
@@ -98,6 +98,12 @@ def _get_signature_object(func, as_instance, eat_self):
func = func.__init__
# Skip the `self` argument in __init__
eat_self = True
+ elif isinstance(func, (classmethod, staticmethod)):
+ if isinstance(func, classmethod):
+ # Skip the `cls` argument of a class method
+ eat_self = True
+ # Use the original decorated method to extract the correct function signature
+ func = func.__func__
elif not isinstance(func, FunctionTypes):
# If we really want to model an instance of the passed type,
# __call__ should be looked up, not __init__.
diff --git a/Lib/unittest/result.py b/Lib/unittest/result.py
index fa9bea47c88829..7757dba9670b43 100644
--- a/Lib/unittest/result.py
+++ b/Lib/unittest/result.py
@@ -159,7 +159,11 @@ def addUnexpectedSuccess(self, test):
self.unexpectedSuccesses.append(test)
def addDuration(self, test, elapsed):
- """Called when a test finished to run, regardless of its outcome."""
+ """Called when a test finished to run, regardless of its outcome.
+ *test* is the test case corresponding to the test method.
+ *elapsed* is the time represented in seconds, and it includes the
+ execution of cleanup functions.
+ """
# support for a TextTestRunner using an old TestResult class
if hasattr(self, "collectedDurations"):
self.collectedDurations.append((test, elapsed))
diff --git a/Lib/urllib/request.py b/Lib/urllib/request.py
index 151034e6a81bf9..5314b3f26021eb 100644
--- a/Lib/urllib/request.py
+++ b/Lib/urllib/request.py
@@ -1251,8 +1251,8 @@ def http_error_407(self, req, fp, code, msg, headers):
class AbstractHTTPHandler(BaseHandler):
- def __init__(self, debuglevel=0):
- self._debuglevel = debuglevel
+ def __init__(self, debuglevel=None):
+ self._debuglevel = debuglevel if debuglevel is not None else http.client.HTTPConnection.debuglevel
def set_http_debuglevel(self, level):
self._debuglevel = level
@@ -1378,7 +1378,8 @@ def http_open(self, req):
class HTTPSHandler(AbstractHTTPHandler):
- def __init__(self, debuglevel=0, context=None, check_hostname=None):
+ def __init__(self, debuglevel=None, context=None, check_hostname=None):
+ debuglevel = debuglevel if debuglevel is not None else http.client.HTTPSConnection.debuglevel
AbstractHTTPHandler.__init__(self, debuglevel)
if context is None:
http_version = http.client.HTTPSConnection._http_vsn
@@ -2474,7 +2475,13 @@ def retrfile(self, file, type):
return (ftpobj, retrlen)
def endtransfer(self):
+ if not self.busy:
+ return
self.busy = 0
+ try:
+ self.ftp.voidresp()
+ except ftperrors():
+ pass
def close(self):
self.keepalive = False
diff --git a/Lib/venv/__init__.py b/Lib/venv/__init__.py
index 2f87c62ccba866..2173c9b13e5cf7 100644
--- a/Lib/venv/__init__.py
+++ b/Lib/venv/__init__.py
@@ -13,7 +13,7 @@
import types
-CORE_VENV_DEPS = ('pip', 'setuptools')
+CORE_VENV_DEPS = ('pip',)
logger = logging.getLogger(__name__)
@@ -523,7 +523,7 @@ def main(args=None):
'this environment.')
parser.add_argument('--upgrade-deps', default=False, action='store_true',
dest='upgrade_deps',
- help=f'Upgrade core dependencies: {", ".join(CORE_VENV_DEPS)} '
+ help=f'Upgrade core dependencies ({", ".join(CORE_VENV_DEPS)}) '
'to the latest version in PyPI')
options = parser.parse_args(args)
if options.upgrade and options.clear:
diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate
index 6fbc2b8801da04..408df5cb93b9e9 100644
--- a/Lib/venv/scripts/common/activate
+++ b/Lib/venv/scripts/common/activate
@@ -1,5 +1,5 @@
# This file must be used with "source bin/activate" *from bash*
-# you cannot run it directly
+# You cannot run it directly
deactivate () {
# reset old environment variables
@@ -38,8 +38,15 @@ deactivate () {
# unset irrelevant variables
deactivate nondestructive
-VIRTUAL_ENV="__VENV_DIR__"
-export VIRTUAL_ENV
+# on Windows, a path can contain colons and backslashes and has to be converted:
+if [ "$OSTYPE" = "cygwin" ] || [ "$OSTYPE" = "msys" ] ; then
+ # transform D:\path\to\venv to /d/path/to/venv on MSYS
+ # and to /cygdrive/d/path/to/venv on Cygwin
+ export VIRTUAL_ENV=$(cygpath "__VENV_DIR__")
+else
+ # use the path as-is
+ export VIRTUAL_ENV="__VENV_DIR__"
+fi
_OLD_VIRTUAL_PATH="$PATH"
PATH="$VIRTUAL_ENV/__VENV_BIN_NAME__:$PATH"
diff --git a/Lib/venv/scripts/posix/activate.csh b/Lib/venv/scripts/posix/activate.csh
index d6f697c55ed81c..5e8d66fa9e5061 100644
--- a/Lib/venv/scripts/posix/activate.csh
+++ b/Lib/venv/scripts/posix/activate.csh
@@ -1,5 +1,6 @@
# This file must be used with "source bin/activate.csh" *from csh*.
# You cannot run it directly.
+
# Created by Davide Di Blasi .
# Ported to Python 3.3 venv by Andrew Svetlov
diff --git a/Lib/venv/scripts/posix/activate.fish b/Lib/venv/scripts/posix/activate.fish
index 9aa4446005f4d8..91ad6442e05692 100644
--- a/Lib/venv/scripts/posix/activate.fish
+++ b/Lib/venv/scripts/posix/activate.fish
@@ -1,5 +1,5 @@
# This file must be used with "source /bin/activate.fish" *from fish*
-# (https://fishshell.com/); you cannot run it directly.
+# (https://fishshell.com/). You cannot run it directly.
function deactivate -d "Exit virtual environment and return to normal shell environment"
# reset old environment variables
diff --git a/Mac/BuildScript/scripts/postflight.ensurepip b/Mac/BuildScript/scripts/postflight.ensurepip
index 36d05945b6fd90..ce3c6c1c2bf9e6 100755
--- a/Mac/BuildScript/scripts/postflight.ensurepip
+++ b/Mac/BuildScript/scripts/postflight.ensurepip
@@ -56,19 +56,19 @@ if [ -d /usr/local/bin ] ; then
cd /usr/local/bin
- # Create pipx.y and easy_install-x.y links if /usr/local/bin/pythonx.y
+ # Create pipx.y links if /usr/local/bin/pythonx.y
# is linked to this framework version
install_links_if_our_fw "python${PYVER}" \
- "pip${PYVER}" "easy_install-${PYVER}"
+ "pip${PYVER}"
# Create pipx link if /usr/local/bin/pythonx is linked to this version
install_links_if_our_fw "python${PYMAJOR}" \
"pip${PYMAJOR}"
- # Create pip and easy_install link if /usr/local/bin/python
+ # Create pip link if /usr/local/bin/python
# is linked to this version
install_links_if_our_fw "python" \
- "pip" "easy_install"
+ "pip"
)
fi
exit 0
diff --git a/Mac/Makefile.in b/Mac/Makefile.in
index f9691288414538..69ab4198988570 100644
--- a/Mac/Makefile.in
+++ b/Mac/Makefile.in
@@ -166,7 +166,6 @@ altinstallunixtools:
-if test "x$(ENSUREPIP)" != "xno" ; then \
cd "$(DESTDIR)$(FRAMEWORKUNIXTOOLSPREFIX)/bin" && \
for fn in \
- easy_install-$(VERSION) \
pip$(VERSION) \
; \
do \
diff --git a/Makefile.pre.in b/Makefile.pre.in
index fefa5d4e8147bf..774a29ebf59793 100644
--- a/Makefile.pre.in
+++ b/Makefile.pre.in
@@ -38,6 +38,7 @@ CC= @CC@
CXX= @CXX@
LINKCC= @LINKCC@
AR= @AR@
+READELF= @READELF@
SOABI= @SOABI@
LDVERSION= @LDVERSION@
LIBPYTHON= @LIBPYTHON@
@@ -369,17 +370,18 @@ PYTHON_OBJS= \
Python/Python-ast.o \
Python/Python-tokenize.o \
Python/asdl.o \
+ Python/assemble.o \
Python/ast.o \
Python/ast_opt.o \
Python/ast_unparse.o \
Python/bltinmodule.o \
Python/ceval.o \
- Python/flowgraph.o \
Python/codecs.o \
Python/compile.o \
Python/context.o \
Python/dynamic_annotations.o \
Python/errors.o \
+ Python/flowgraph.o \
Python/frame.o \
Python/frozenmain.o \
Python/future.o \
@@ -394,7 +396,9 @@ PYTHON_OBJS= \
Python/import.o \
Python/importdl.o \
Python/initconfig.o \
+ Python/instrumentation.o \
Python/intrinsics.o \
+ Python/legacy_tracing.o \
Python/marshal.o \
Python/modsupport.o \
Python/mysnprintf.o \
@@ -667,13 +671,18 @@ profile-opt: profile-run-stamp
bolt-opt: @PREBOLT_RULE@
rm -f *.fdata
- @LLVM_BOLT@ ./$(BUILDPYTHON) -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $(BUILDPYTHON).bolt) -o $(BUILDPYTHON).bolt_inst
- ./$(BUILDPYTHON).bolt_inst $(PROFILE_TASK) || true
- @MERGE_FDATA@ $(BUILDPYTHON).*.fdata > $(BUILDPYTHON).fdata
- @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot
- rm -f *.fdata
- rm -f $(BUILDPYTHON).bolt_inst
- mv $(BUILDPYTHON).bolt $(BUILDPYTHON)
+ @if $(READELF) -p .note.bolt_info $(BUILDPYTHON) | grep BOLT > /dev/null; then\
+ echo "skip: $(BUILDPYTHON) is already BOLTed."; \
+ else \
+ @LLVM_BOLT@ ./$(BUILDPYTHON) -instrument -instrumentation-file-append-pid -instrumentation-file=$(abspath $(BUILDPYTHON).bolt) -o $(BUILDPYTHON).bolt_inst; \
+ ./$(BUILDPYTHON).bolt_inst $(PROFILE_TASK) || true; \
+ @MERGE_FDATA@ $(BUILDPYTHON).*.fdata > $(BUILDPYTHON).fdata; \
+ @LLVM_BOLT@ ./$(BUILDPYTHON) -o $(BUILDPYTHON).bolt -data=$(BUILDPYTHON).fdata -update-debug-sections -reorder-blocks=ext-tsp -reorder-functions=hfsort+ -split-functions -icf=1 -inline-all -split-eh -reorder-functions-use-hot-size -peepholes=none -jump-tables=aggressive -inline-ap -indirect-call-promotion=all -dyno-stats -use-gnu-stack -frame-opt=hot; \
+ rm -f *.fdata; \
+ rm -f $(BUILDPYTHON).bolt_inst; \
+ mv $(BUILDPYTHON).bolt $(BUILDPYTHON); \
+ fi
+
# Compile and run with gcov
.PHONY=coverage coverage-lcov coverage-report
@@ -973,7 +982,7 @@ Makefile Modules/config.c: Makefile.pre \
Modules/Setup.local \
Modules/Setup.bootstrap \
Modules/Setup.stdlib
- $(SHELL) $(MAKESETUP) -c $(srcdir)/Modules/config.c.in \
+ $(MAKESETUP) -c $(srcdir)/Modules/config.c.in \
-s Modules \
Modules/Setup.local \
Modules/Setup.stdlib \
@@ -1185,7 +1194,7 @@ Tools/build/freeze_modules.py: $(FREEZE_MODULE)
.PHONY: regen-frozen
regen-frozen: Tools/build/freeze_modules.py $(FROZEN_FILES_IN)
- $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/freeze_modules.py
+ $(PYTHON_FOR_REGEN) $(srcdir)/Tools/build/freeze_modules.py --frozen-modules
@echo "The Makefile was updated, you may need to re-run make."
############################################################################
@@ -2414,12 +2423,12 @@ frameworkinstallextras:
# Build the toplevel Makefile
Makefile.pre: $(srcdir)/Makefile.pre.in config.status
- CONFIG_FILES=Makefile.pre CONFIG_HEADERS= $(SHELL) config.status
+ CONFIG_FILES=Makefile.pre CONFIG_HEADERS= ./config.status
$(MAKE) -f Makefile.pre Makefile
# Run the configure script.
config.status: $(srcdir)/configure
- $(SHELL) $(srcdir)/configure $(CONFIG_ARGS)
+ $(srcdir)/configure $(CONFIG_ARGS)
.PRECIOUS: config.status $(BUILDPYTHON) Makefile Makefile.pre
@@ -2444,8 +2453,8 @@ reindent:
# Rerun configure with the same options as it was run last time,
# provided the config.status script exists
recheck:
- $(SHELL) config.status --recheck
- $(SHELL) config.status
+ ./config.status --recheck
+ ./config.status
# Regenerate configure and pyconfig.h.in
.PHONY: autoconf
@@ -2660,6 +2669,15 @@ MODULE__SSL_DEPS=$(srcdir)/Modules/_ssl.h $(srcdir)/Modules/_ssl/cert.c $(srcdir
MODULE__TESTCAPI_DEPS=$(srcdir)/Modules/_testcapi/testcapi_long.h $(srcdir)/Modules/_testcapi/parts.h
MODULE__SQLITE3_DEPS=$(srcdir)/Modules/_sqlite/connection.h $(srcdir)/Modules/_sqlite/cursor.h $(srcdir)/Modules/_sqlite/microprotocols.h $(srcdir)/Modules/_sqlite/module.h $(srcdir)/Modules/_sqlite/prepare_protocol.h $(srcdir)/Modules/_sqlite/row.h $(srcdir)/Modules/_sqlite/util.h
+CODECS_COMMON_HEADERS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h $(srcdir)/Modules/cjkcodecs/cjkcodecs.h
+MODULE__CODECS_CN_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_cn.h $(CODECS_COMMON_HEADERS)
+MODULE__CODECS_HK_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_hk.h $(CODECS_COMMON_HEADERS)
+MODULE__CODECS_ISO2022_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(CODECS_COMMON_HEADERS)
+MODULE__CODECS_JP_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_jisx0213_pair.h $(srcdir)/Modules/cjkcodecs/alg_jisx0201.h $(srcdir)/Modules/cjkcodecs/emu_jisx0213_2000.h $(srcdir)/Modules/cjkcodecs/mappings_jp.h $(CODECS_COMMON_HEADERS)
+MODULE__CODECS_KR_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_kr.h $(CODECS_COMMON_HEADERS)
+MODULE__CODECS_TW_DEPS=$(srcdir)/Modules/cjkcodecs/mappings_tw.h $(CODECS_COMMON_HEADERS)
+MODULE__MULTIBYTECODEC_DEPS=$(srcdir)/Modules/cjkcodecs/multibytecodec.h
+
# IF YOU PUT ANYTHING HERE IT WILL GO AWAY
# Local Variables:
# mode: makefile
diff --git a/Misc/ACKS b/Misc/ACKS
index 49f3692dfd6b8f..19475698a4bc37 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -160,6 +160,7 @@ Brice Berna
Olivier Bernard
Vivien Bernet-Rollande
Maxwell Bernstein
+Jay Berry
Eric Beser
Steven Bethard
Stephen Bevan
@@ -298,6 +299,7 @@ Dave Chambers
Pascal Chambon
Nicholas Chammas
Ofey Chan
+Juhi Chandalia
John Chandler
Hye-Shik Chang
Jeffrey Chang
@@ -1115,6 +1117,7 @@ Jason Lowe
Tony Lownds
Ray Loyzaga
Kang-Hao (Kenny) Lu
+Raymond Lu
Lukas Lueg
Loren Luke
Fredrik Lundh
@@ -1549,6 +1552,7 @@ Hugo van Rossum
Saskia van Rossum
Robin Roth
Clement Rouault
+Tomas Roun
Donald Wallace Rouse II
Liam Routt
Todd Rovito
diff --git a/Misc/NEWS.d/3.7.0b2.rst b/Misc/NEWS.d/3.7.0b2.rst
index b2ade206bd5f97..9590914599bb86 100644
--- a/Misc/NEWS.d/3.7.0b2.rst
+++ b/Misc/NEWS.d/3.7.0b2.rst
@@ -357,7 +357,7 @@ Wirtel
Add TLSVersion constants and SSLContext.maximum_version / minimum_version
attributes. The new API wraps OpenSSL 1.1
-https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html
+https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html
feature.
..
diff --git a/Misc/NEWS.d/3.8.0a1.rst b/Misc/NEWS.d/3.8.0a1.rst
index 991bbc128670b2..db2eba32e6ea34 100644
--- a/Misc/NEWS.d/3.8.0a1.rst
+++ b/Misc/NEWS.d/3.8.0a1.rst
@@ -5951,7 +5951,7 @@ Wirtel
Add TLSVersion constants and SSLContext.maximum_version / minimum_version
attributes. The new API wraps OpenSSL 1.1
-https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html
+https://web.archive.org/web/20180309043602/https://www.openssl.org/docs/man1.1.0/ssl/SSL_CTX_set_min_proto_version.html
feature.
..
diff --git a/Misc/NEWS.d/3.9.0a1.rst b/Misc/NEWS.d/3.9.0a1.rst
index 633620583838df..0888a5c43087b5 100644
--- a/Misc/NEWS.d/3.9.0a1.rst
+++ b/Misc/NEWS.d/3.9.0a1.rst
@@ -4887,7 +4887,7 @@ Fix use of registry values to launch Python from Microsoft Store app.
.. section: Windows
Fix memory leak on Windows in creating an SSLContext object or running
-urllib.request.urlopen('https://...').
+``urllib.request.urlopen('https://...')``.
..
diff --git a/Misc/NEWS.d/3.9.0a2.rst b/Misc/NEWS.d/3.9.0a2.rst
index 226ea0d3df2243..a03eb10f1d523a 100644
--- a/Misc/NEWS.d/3.9.0a2.rst
+++ b/Misc/NEWS.d/3.9.0a2.rst
@@ -686,7 +686,7 @@ added.
Update documentation to state that to activate virtual environments under
fish one should use `source`, not `.` as documented at
-https://fishshell.com/docs/current/commands.html#source.
+https://fishshell.com/docs/current/cmds/source.html.
..
diff --git a/Misc/NEWS.d/3.9.0a4.rst b/Misc/NEWS.d/3.9.0a4.rst
index 2aef8b26b01696..019b34c4082d10 100644
--- a/Misc/NEWS.d/3.9.0a4.rst
+++ b/Misc/NEWS.d/3.9.0a4.rst
@@ -392,7 +392,7 @@ The distutils ``bdist_msi`` command is deprecated in Python 3.9, use
Improved performance of zipfile.Path for files with a large number of
entries. Also improved performance and fixed minor issue as published with
`importlib_metadata 1.5
-`_.
+`_.
..
diff --git a/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst
new file mode 100644
index 00000000000000..255c9833282c2f
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2023-04-14-10-24-37.gh-issue-103532.H1djkd.rst
@@ -0,0 +1,4 @@
+The ``TKINTER_PROTECT_LOADTK`` macro is no longer defined or used in the
+``_tkinter`` module. It was previously only defined when building against
+Tk 8.4.13 and older, but Tk older than 8.5.12 has been unsupported since
+gh-issue-91152.
diff --git a/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst b/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst
new file mode 100644
index 00000000000000..172d66163d42e6
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2023-02-09-23-09-29.gh-issue-101408._paFIF.rst
@@ -0,0 +1,2 @@
+:c:func:`PyObject_GC_Resize` should calculate preheader size if needed.
+Patch by Dong-hee Na.
diff --git a/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst b/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst
new file mode 100644
index 00000000000000..28c77b6816af87
--- /dev/null
+++ b/Misc/NEWS.d/next/C API/2023-03-28-12-31-51.gh-issue-103091.CzZyaZ.rst
@@ -0,0 +1 @@
+Add a new C-API function to eagerly assign a version tag to a PyTypeObject: ``PyUnstable_Type_AssignVersionTag()``.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst b/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst
new file mode 100644
index 00000000000000..d65e0f3db9d6f5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-02-11-15-54-40.bpo-39610.fvgsCl.rst
@@ -0,0 +1,2 @@
+``len()`` for 0-dimensional :class:`memoryview`` objects (such as ``memoryview(ctypes.c_uint8(42))``) now raises a :exc:`TypeError`.
+Previously this returned ``1``, which was not consistent with ``mem_0d[0]`` raising an :exc:`IndexError``.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst b/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst
new file mode 100644
index 00000000000000..80076831badfea
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2022-11-08-12-36-25.gh-issue-99184.KIaqzz.rst
@@ -0,0 +1,2 @@
+Bypass instance attribute access of ``__name__`` in ``repr`` of
+:class:`weakref.ref`.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst
new file mode 100644
index 00000000000000..631ef4c7890450
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-03-31-17-24-03.gh-issue-103082.isRUcV.rst
@@ -0,0 +1 @@
+Implement :pep:`669` Low Impact Monitoring for CPython.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst
new file mode 100644
index 00000000000000..c4d8ce75b35a30
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-02-22-14-57.gh-issue-84436.hvMgwF.rst
@@ -0,0 +1,3 @@
+The implementation of PEP-683 which adds Immortal Objects by using a fixed
+reference count that skips reference counting to make objects truly
+immutable.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst
new file mode 100644
index 00000000000000..347c91d973e5ce
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-07-12-18-41.gh-issue-103323.9802br.rst
@@ -0,0 +1,3 @@
+We've replaced our use of ``_PyRuntime.tstate_current`` with a thread-local
+variable. This is a fairly low-level implementation detail, and there
+should be no change in behavior.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst
new file mode 100644
index 00000000000000..85c8ecf7de8d1b
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-09-22-21-57.gh-issue-77757._Ow-u2.rst
@@ -0,0 +1,3 @@
+Exceptions raised in a typeobject's ``__set_name__`` method are no longer
+wrapped by a :exc:`RuntimeError`. Context information is added to the
+exception as a :pep:`678` note.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst
new file mode 100644
index 00000000000000..e7daa104e57105
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-18-51.gh-issue-103488.vYvlHD.rst
@@ -0,0 +1,3 @@
+Change the internal offset distinguishing yield and return target addresses,
+so that the instruction pointer is correct for exception handling and other
+stack unwinding.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst
new file mode 100644
index 00000000000000..9d75de1565a170
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-12-20-22-03.gh-issue-87729.99A7UO.rst
@@ -0,0 +1,4 @@
+Add :opcode:`LOAD_SUPER_ATTR` (and a specialization for ``super().method()``) to
+speed up ``super().method()`` and ``super().attr``. This makes
+``super().method()`` roughly 2.3x faster and brings it within 20% of the
+performance of a simple method call. Patch by Vladimir Matveev and Carl Meyer.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst
new file mode 100644
index 00000000000000..929650968173e7
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-13-00-58-55.gh-issue-103492.P4k0Ay.rst
@@ -0,0 +1 @@
+Clarify :exc:`SyntaxWarning` with literal ``is`` comparison by specifying which literal is problematic, since comparisons using ``is`` with e.g. None and bool literals are idiomatic.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst
new file mode 100644
index 00000000000000..730c6cd40d7235
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-14-22-35-23.gh-issue-101517.5EqM-S.rst
@@ -0,0 +1 @@
+Fix bug in line numbers of instructions emitted for :keyword:`except* `.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst
new file mode 100644
index 00000000000000..5b1bcc4a680fc3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-16-14-38-39.gh-issue-100530.OR6-sn.rst
@@ -0,0 +1 @@
+Clarify the error message raised when the called part of a class pattern isn't actually a class.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst
new file mode 100644
index 00000000000000..35eceb83816bcb
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-17-16-00-32.gh-issue-102856.UunJ7y.rst
@@ -0,0 +1 @@
+Implement the required C tokenizer changes for PEP 701. Patch by Pablo Galindo Salgado, Lysandros Nikolaou, Batuhan Taskaya, Marta Gómez Macías and sunmy2019.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst
new file mode 100644
index 00000000000000..15cb6c64adbab1
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-21-17-03-14.gh-issue-102310.anLjDx.rst
@@ -0,0 +1 @@
+Change the error range for invalid bytes literals.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst b/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst
new file mode 100644
index 00000000000000..6f07d72fafdfc3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-04-24-21-47-38.gh-issue-103801.WaBanq.rst
@@ -0,0 +1 @@
+Adds three minor linting fixes to the wasm module caught that were caught by ruff.
diff --git a/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst b/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst
new file mode 100644
index 00000000000000..53c32d397b206b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2021-11-07-15-31-25.bpo-23041.564i32.rst
@@ -0,0 +1,2 @@
+Add :data:`~csv.QUOTE_STRINGS` and :data:`~csv.QUOTE_NOTNULL` to the suite
+of :mod:`csv` module quoting styles.
diff --git a/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst b/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst
new file mode 100644
index 00000000000000..7719b74b8e5ef1
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-03-23-13-28.gh-issue-94518.511Tbh.rst
@@ -0,0 +1 @@
+Convert private :meth:`_posixsubprocess.fork_exec` to use Argument Clinic.
diff --git a/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst b/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst
new file mode 100644
index 00000000000000..50a3d6a4629182
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-06-11-10-37.gh-issue-51574.sveUeD.rst
@@ -0,0 +1,2 @@
+Make :func:`tempfile.mkdtemp` return absolute paths when its *dir*
+parameter is relative.
diff --git a/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst b/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst
new file mode 100644
index 00000000000000..1ad42d5c9aa53d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-11-10-16-26-47.gh-issue-99353.DQFjnt.rst
@@ -0,0 +1,3 @@
+Respect the :class:`http.client.HTTPConnection` ``.debuglevel`` flag
+in :class:`urllib.request.AbstractHTTPHandler` when its constructor
+parameter ``debuglevel`` is not set. And do the same for ``*HTTPS*``.
diff --git a/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst
new file mode 100644
index 00000000000000..29c30848e09a83
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-01-14-17-54-56.gh-issue-95299.vUhpKz.rst
@@ -0,0 +1 @@
+Remove the bundled setuptools wheel from ``ensurepip``, and stop installing setuptools in environments created by ``venv``.
diff --git a/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst b/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst
new file mode 100644
index 00000000000000..e85e7a4ff2e73a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-02-06-16-45-18.gh-issue-83861.mMbIU3.rst
@@ -0,0 +1,4 @@
+Fix datetime.astimezone method return value when invoked on a naive datetime
+instance that represents local time falling in a timezone transition gap.
+PEP 495 requires that instances with fold=1 produce earlier times than those
+with fold=0 in this case.
diff --git a/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst b/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst
new file mode 100644
index 00000000000000..6df69463931494
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-02-11-15-01-32.gh-issue-101688.kwXmfM.rst
@@ -0,0 +1,2 @@
+Implement :func:`types.get_original_bases` to provide further introspection
+for types.
diff --git a/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst b/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst
new file mode 100644
index 00000000000000..bbb9ac3e3f8faa
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-02-17-21-14-40.gh-issue-78079.z3Szr6.rst
@@ -0,0 +1,3 @@
+Fix incorrect normalization of UNC device path roots, and partial UNC share
+path roots, in :class:`pathlib.PurePath`. Pathlib no longer appends a
+trailing slash to such paths.
diff --git a/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst b/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst
new file mode 100644
index 00000000000000..4140c9a96cd272
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-02-21-14-57-34.gh-issue-102114.uUDQzb.rst
@@ -0,0 +1 @@
+Functions in the :mod:`dis` module that accept a source code string as argument now print a more concise traceback when the string contains a syntax or indentation error.
diff --git a/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst b/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst
new file mode 100644
index 00000000000000..87617a503c0dba
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-06-18-49-57.gh-issue-101362.eSSy6L.rst
@@ -0,0 +1,2 @@
+Speed up :class:`pathlib.Path` construction by omitting the path anchor from
+the internal list of path parts.
diff --git a/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst
new file mode 100644
index 00000000000000..48a105a4a17b29
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-23-15-24-38.gh-issue-102953.YR4KaK.rst
@@ -0,0 +1,4 @@
+The extraction methods in :mod:`tarfile`, and :func:`shutil.unpack_archive`,
+have a new a *filter* argument that allows limiting tar features than may be
+surprising or dangerous, such as creating files outside the destination
+directory. See :ref:`tarfile-extraction-filter` for details.
diff --git a/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst
new file mode 100644
index 00000000000000..15f16d9eb4c1bf
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-24-20-49-48.gh-issue-103000.6eVNZI.rst
@@ -0,0 +1,2 @@
+Improve performance of :func:`dataclasses.astuple` and
+:func:`dataclasses.asdict` in cases where the contents are common Python types.
diff --git a/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst
new file mode 100644
index 00000000000000..32bd62d27c7c6d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-03-31-01-13-00.gh-issue-103143.6eMluy.rst
@@ -0,0 +1 @@
+Polish the help messages and docstrings of :mod:`pdb`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst b/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst
new file mode 100644
index 00000000000000..b89f9bae595457
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-01-23-01-31.gh-issue-103176.FBsdxa.rst
@@ -0,0 +1,2 @@
+:func:`sys._current_exceptions` now returns a mapping from thread-id to an
+exception instance, rather than to a ``(typ, exc, tb)`` tuple.
diff --git a/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst b/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst
new file mode 100644
index 00000000000000..9cf26c26873b2a
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-03-21-08-53.gh-issue-103220.OW_Bj5.rst
@@ -0,0 +1,2 @@
+Fix issue where :func:`os.path.join` added a slash when joining onto an
+incomplete UNC drive with a trailing slash on Windows.
diff --git a/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst b/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst
new file mode 100644
index 00000000000000..e7586a223c1415
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-03-23-43-12.gh-issue-103092.3xqk4y.rst
@@ -0,0 +1 @@
+Isolate :mod:`!_socket` (apply :pep:`687`). Patch by Erlend E. Aasland.
diff --git a/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst b/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst
new file mode 100644
index 00000000000000..df63af10a385eb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-03-23-44-34.gh-issue-102978.gy9eVk.rst
@@ -0,0 +1,3 @@
+Fixes :func:`unittest.mock.patch` not enforcing function signatures for methods
+decorated with ``@classmethod`` or ``@staticmethod`` when patch is called with
+``autospec=True``.
diff --git a/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst b/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst
new file mode 100644
index 00000000000000..39c62ffbe8c659
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-04-21-27-51.gh-issue-103092.7s7Bzf.rst
@@ -0,0 +1 @@
+Adapt the :mod:`winsound` extension module to :pep:`687`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst b/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst
new file mode 100644
index 00000000000000..7bd191e3c22b2b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-04-21-44-25.gh-issue-103092.Dz0_Xn.rst
@@ -0,0 +1 @@
+Adapt the :mod:`msvcrt` extension module to :pep:`687`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst b/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst
new file mode 100644
index 00000000000000..62b4364c2b1665
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-06-04-35-59.gh-issue-103285.rCZ9-G.rst
@@ -0,0 +1 @@
+Improve performance of :func:`ast.get_source_segment`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst b/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst
new file mode 100644
index 00000000000000..64ae5b5b6d564b
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-06-16-55-51.gh-issue-102778.BWeAmE.rst
@@ -0,0 +1 @@
+Support ``sys.last_exc`` in :mod:`idlelib`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst b/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst
new file mode 100644
index 00000000000000..0f2108fee763d0
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-08-00-48-40.gh-issue-103092.5EFts0.rst
@@ -0,0 +1 @@
+Adapt the :mod:`winreg` extension module to :pep:`687`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst b/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst
new file mode 100644
index 00000000000000..83dce56ed0b7c5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-08-01-33-12.gh-issue-103357.vjin28.rst
@@ -0,0 +1,3 @@
+Added support for :class:`logging.Formatter` ``defaults`` parameter to
+:func:`logging.config.dictConfig` and :func:`logging.config.fileConfig`.
+Patch by Bar Harel.
diff --git a/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst
new file mode 100644
index 00000000000000..6977c1489a29cb
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-09-06-59-36.gh-issue-103092.vskbro.rst
@@ -0,0 +1 @@
+Isolate :mod:`!_collections` (apply :pep:`687`). Patch by Erlend E. Aasland.
diff --git a/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst
new file mode 100644
index 00000000000000..0b2b47af1cbaab
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-11-21-38-39.gh-issue-103449.-nxmhb.rst
@@ -0,0 +1 @@
+Fix a bug in doc string generation in :func:`dataclasses.dataclass`.
diff --git a/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst b/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst
new file mode 100644
index 00000000000000..50758c89cc2856
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-12-06-00-02.gh-issue-103462.w6yBlM.rst
@@ -0,0 +1,4 @@
+Fixed an issue with using :meth:`~asyncio.WriteTransport.writelines` in :mod:`asyncio` to send very
+large payloads that exceed the amount of data that can be written in one
+call to :meth:`socket.socket.send` or :meth:`socket.socket.sendmsg`,
+resulting in the remaining buffer being left unwritten.
diff --git a/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst
new file mode 100644
index 00000000000000..4d69f6f6fff713
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-12-17-59-55.gh-issue-103365.UBEE0U.rst
@@ -0,0 +1 @@
+Set default Flag boundary to ``STRICT`` and fix bitwise operations.
diff --git a/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst b/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst
new file mode 100644
index 00000000000000..2c9d67e2c4bf71
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-15-11-21-38.gh-issue-103559.a9rYHG.rst
@@ -0,0 +1 @@
+Update the bundled copy of pip to version 23.1.1.
diff --git a/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst
new file mode 100644
index 00000000000000..fe2267b7b79019
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-15-12-19-14.gh-issue-103556.TEf-2m.rst
@@ -0,0 +1,3 @@
+Now creating :class:`inspect.Signature` objects with positional-only
+parameter with a default followed by a positional-or-keyword parameter
+without one is impossible.
diff --git a/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst b/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst
new file mode 100644
index 00000000000000..6d7c93ade9cd94
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-16-19-48-21.gh-issue-103584.3mBTuM.rst
@@ -0,0 +1,12 @@
+Updated ``importlib.metadata`` with changes from ``importlib_metadata`` 5.2
+through 6.5.0, including: Support ``installed-files.txt`` for
+``Distribution.files`` when present. ``PackageMetadata`` now stipulates an
+additional ``get`` method allowing for easy querying of metadata keys that
+may not be present. ``packages_distributions`` now honors packages and
+modules with Python modules that not ``.py`` sources (e.g. ``.pyc``,
+``.so``). Expand protocol for ``PackageMetadata.get_all`` to match the
+upstream implementation of ``email.message.Message.get_all`` in
+python/typeshed#9620. Deprecated use of ``Distribution`` without defining
+abstract methods. Deprecated expectation that
+``PackageMetadata.__getitem__`` will return ``None`` for missing keys. In
+the future, it will raise a ``KeyError``.
diff --git a/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst b/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst
new file mode 100644
index 00000000000000..2fa27e60b58efe
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-17-14-47-28.gh-issue-103596.ME1y3_.rst
@@ -0,0 +1,2 @@
+Attributes/methods are no longer shadowed by same-named enum members,
+although they may be shadowed by enum.property's.
diff --git a/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst b/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst
new file mode 100644
index 00000000000000..b3b5085250f078
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-21-10-25-39.gh-issue-103636.YK6NEa.rst
@@ -0,0 +1 @@
+Added Enum for months and days in the calendar module.
diff --git a/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst b/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst
new file mode 100644
index 00000000000000..bd5317744ff140
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-22-02-41-06.gh-issue-103673.oE7S_k.rst
@@ -0,0 +1,2 @@
+:mod:`socketserver` gains ``ForkingUnixStreamServer`` and
+``ForkingUnixDatagramServer`` classes. Patch by Jay Berry.
diff --git a/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst b/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst
new file mode 100644
index 00000000000000..60547a25a109bc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-22-22-37-39.gh-issue-103699.NizCjc.rst
@@ -0,0 +1,2 @@
+Add ``__orig_bases__`` to non-generic TypedDicts, call-based TypedDicts, and
+call-based NamedTuples. Other TypedDicts and NamedTuples already had the attribute.
diff --git a/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst b/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst
new file mode 100644
index 00000000000000..6adb71f7677229
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-23-15-39-17.gh-issue-81403.zVz9Td.rst
@@ -0,0 +1,3 @@
+:class:`urllib.request.CacheFTPHandler` no longer raises :class:`URLError`
+if a cached FTP instance is reused. ftplib's endtransfer method calls
+voidresp to drain the connection to handle FTP instance reuse properly.
diff --git a/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst b/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst
new file mode 100644
index 00000000000000..31df04790721a8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-24-00-34-23.gh-issue-103685.U14jBM.rst
@@ -0,0 +1 @@
+Prepare :meth:`tkinter.Menu.index` for Tk 8.7 so that it does not raise ``TclError: expected integer but got ""`` when it should return ``None``.
diff --git a/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst b/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst
new file mode 100644
index 00000000000000..f00384cde9706e
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2023-04-24-23-07-56.gh-issue-103791.bBPWdS.rst
@@ -0,0 +1,3 @@
+:class:`contextlib.suppress` now supports suppressing exceptions raised as
+part of an :exc:`ExceptionGroup`. If other exceptions exist on the group, they
+are re-raised in a group that does not contain the suppressed exceptions.
diff --git a/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst b/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst
new file mode 100644
index 00000000000000..f9f5343f4210dc
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2023-04-11-09-22-22.gh-issue-103088.6AJEuR.rst
@@ -0,0 +1 @@
+Fixes venvs not working in bash on Windows across different disks
diff --git a/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst b/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst
new file mode 100644
index 00000000000000..1fee99da240378
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2023-04-12-10-49-21.gh-issue-103088.Yjj-qJ.rst
@@ -0,0 +1 @@
+Fix virtual environment :file:`activate` script having incorrect line endings for Cygwin.
diff --git a/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst b/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst
new file mode 100644
index 00000000000000..5bd005ffacb800
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2023-04-24-15-51-11.gh-issue-82814.GI3UkZ.rst
@@ -0,0 +1,3 @@
+Fix a potential ``[Errno 13] Permission denied`` when using :func:`shutil.copystat`
+within Windows Subsystem for Linux (WSL) on a mounted filesystem by adding
+``errno.EACCES`` to the list of ignored errors within the internal implementation.
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 9d8aef1e677157..a9b1425177c3d7 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1,17 +1,56 @@
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_long.h" // _PyLong_GetZero()
+#include "pycore_moduleobject.h" // _PyModule_GetState()
+#include "pycore_typeobject.h" // _PyType_GetModuleState()
#include "structmember.h" // PyMemberDef
#include
+typedef struct {
+ PyTypeObject *deque_type;
+ PyTypeObject *defdict_type;
+ PyTypeObject *dequeiter_type;
+ PyTypeObject *dequereviter_type;
+ PyTypeObject *tuplegetter_type;
+} collections_state;
+
+static inline collections_state *
+get_module_state(PyObject *mod)
+{
+ void *state = _PyModule_GetState(mod);
+ assert(state != NULL);
+ return (collections_state *)state;
+}
+
+static inline collections_state *
+get_module_state_by_cls(PyTypeObject *cls)
+{
+ void *state = _PyType_GetModuleState(cls);
+ assert(state != NULL);
+ return (collections_state *)state;
+}
+
+static struct PyModuleDef _collectionsmodule;
+
+static inline collections_state *
+find_module_state_by_def(PyTypeObject *type)
+{
+ PyObject *mod = PyType_GetModuleByDef(type, &_collectionsmodule);
+ assert(mod != NULL);
+ return get_module_state(mod);
+}
+
/*[clinic input]
module _collections
-class _tuplegetter "_tuplegetterobject *" "&tuplegetter_type"
+class _tuplegetter "_tuplegetterobject *" "clinic_state()->tuplegetter_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=a8ece4ccad7e30ac]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7356042a89862e0e]*/
-static PyTypeObject tuplegetter_type;
+/* We can safely assume type to be the defining class,
+ * since tuplegetter is not a base type */
+#define clinic_state() (get_module_state_by_cls(type))
#include "clinic/_collectionsmodule.c.h"
+#undef clinic_state
/* collections module implementation of a deque() datatype
Written and maintained by Raymond D. Hettinger
@@ -94,8 +133,6 @@ typedef struct {
PyObject *weakreflist;
} dequeobject;
-static PyTypeObject deque_type;
-
/* For debug builds, add error checking to track the endpoints
* in the chain of links. The goal is to make sure that link
* assignments only take place at endpoints so that links already
@@ -484,11 +521,13 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored))
{
PyObject *result;
dequeobject *old_deque = (dequeobject *)deque;
- if (Py_IS_TYPE(deque, &deque_type)) {
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ if (Py_IS_TYPE(deque, state->deque_type)) {
dequeobject *new_deque;
PyObject *rv;
- new_deque = (dequeobject *)deque_new(&deque_type, (PyObject *)NULL, (PyObject *)NULL);
+ new_deque = (dequeobject *)deque_new(state->deque_type,
+ (PyObject *)NULL, (PyObject *)NULL);
if (new_deque == NULL)
return NULL;
new_deque->maxlen = old_deque->maxlen;
@@ -511,7 +550,7 @@ deque_copy(PyObject *deque, PyObject *Py_UNUSED(ignored))
else
result = PyObject_CallFunction((PyObject *)(Py_TYPE(deque)), "Oi",
deque, old_deque->maxlen, NULL);
- if (result != NULL && !PyObject_TypeCheck(result, &deque_type)) {
+ if (result != NULL && !PyObject_TypeCheck(result, state->deque_type)) {
PyErr_Format(PyExc_TypeError,
"%.200s() must return a deque, not %.200s",
Py_TYPE(deque)->tp_name, Py_TYPE(result)->tp_name);
@@ -529,7 +568,8 @@ deque_concat(dequeobject *deque, PyObject *other)
PyObject *new_deque, *result;
int rv;
- rv = PyObject_IsInstance(other, (PyObject *)&deque_type);
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ rv = PyObject_IsInstance(other, (PyObject *)state->deque_type);
if (rv <= 0) {
if (rv == 0) {
PyErr_Format(PyExc_TypeError,
@@ -1288,6 +1328,7 @@ deque_ass_item(dequeobject *deque, Py_ssize_t i, PyObject *v)
static void
deque_dealloc(dequeobject *deque)
{
+ PyTypeObject *tp = Py_TYPE(deque);
Py_ssize_t i;
PyObject_GC_UnTrack(deque);
@@ -1303,12 +1344,15 @@ deque_dealloc(dequeobject *deque)
for (i=0 ; i < deque->numfreeblocks ; i++) {
PyMem_Free(deque->freeblocks[i]);
}
- Py_TYPE(deque)->tp_free(deque);
+ tp->tp_free(deque);
+ Py_DECREF(tp);
}
static int
deque_traverse(dequeobject *deque, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(deque));
+
block *b;
PyObject *item;
Py_ssize_t index;
@@ -1393,8 +1437,9 @@ deque_richcompare(PyObject *v, PyObject *w, int op)
Py_ssize_t vs, ws;
int b, cmp=-1;
- if (!PyObject_TypeCheck(v, &deque_type) ||
- !PyObject_TypeCheck(w, &deque_type)) {
+ collections_state *state = find_module_state_by_def(Py_TYPE(v));
+ if (!PyObject_TypeCheck(v, state->deque_type) ||
+ !PyObject_TypeCheck(w, state->deque_type)) {
Py_RETURN_NOTIMPLEMENTED;
}
@@ -1537,19 +1582,6 @@ static PyGetSetDef deque_getset[] = {
{0}
};
-static PySequenceMethods deque_as_sequence = {
- (lenfunc)deque_len, /* sq_length */
- (binaryfunc)deque_concat, /* sq_concat */
- (ssizeargfunc)deque_repeat, /* sq_repeat */
- (ssizeargfunc)deque_item, /* sq_item */
- 0, /* sq_slice */
- (ssizeobjargproc)deque_ass_item, /* sq_ass_item */
- 0, /* sq_ass_slice */
- (objobjproc)deque_contains, /* sq_contains */
- (binaryfunc)deque_inplace_concat, /* sq_inplace_concat */
- (ssizeargfunc)deque_inplace_repeat, /* sq_inplace_repeat */
-};
-
static PyObject *deque_iter(dequeobject *deque);
static PyObject *deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored));
PyDoc_STRVAR(reversed_doc,
@@ -1597,54 +1629,53 @@ static PyMethodDef deque_methods[] = {
{NULL, NULL} /* sentinel */
};
+static PyMemberDef deque_members[] = {
+ {"__weaklistoffset__", T_PYSSIZET, offsetof(dequeobject, weakreflist), READONLY},
+ {NULL},
+};
+
PyDoc_STRVAR(deque_doc,
"deque([iterable[, maxlen]]) --> deque object\n\
\n\
A list-like sequence optimized for data accesses near its endpoints.");
-static PyTypeObject deque_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "collections.deque", /* tp_name */
- sizeof(dequeobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)deque_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- deque_repr, /* tp_repr */
- 0, /* tp_as_number */
- &deque_as_sequence, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- PyObject_HashNotImplemented, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
- Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE,
- /* tp_flags */
- deque_doc, /* tp_doc */
- (traverseproc)deque_traverse, /* tp_traverse */
- (inquiry)deque_clear, /* tp_clear */
- (richcmpfunc)deque_richcompare, /* tp_richcompare */
- offsetof(dequeobject, weakreflist), /* tp_weaklistoffset*/
- (getiterfunc)deque_iter, /* tp_iter */
- 0, /* tp_iternext */
- deque_methods, /* tp_methods */
- 0, /* tp_members */
- deque_getset, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- (initproc)deque_init, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- deque_new, /* tp_new */
- PyObject_GC_Del, /* tp_free */
+static PyType_Slot deque_slots[] = {
+ {Py_tp_dealloc, deque_dealloc},
+ {Py_tp_repr, deque_repr},
+ {Py_tp_hash, PyObject_HashNotImplemented},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_doc, (void *)deque_doc},
+ {Py_tp_traverse, deque_traverse},
+ {Py_tp_clear, deque_clear},
+ {Py_tp_richcompare, deque_richcompare},
+ {Py_tp_iter, deque_iter},
+ {Py_tp_getset, deque_getset},
+ {Py_tp_init, deque_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_new, deque_new},
+ {Py_tp_free, PyObject_GC_Del},
+ {Py_tp_methods, deque_methods},
+ {Py_tp_members, deque_members},
+
+ // Sequence protocol
+ {Py_sq_length, deque_len},
+ {Py_sq_concat, deque_concat},
+ {Py_sq_repeat, deque_repeat},
+ {Py_sq_item, deque_item},
+ {Py_sq_ass_item, deque_ass_item},
+ {Py_sq_contains, deque_contains},
+ {Py_sq_inplace_concat, deque_inplace_concat},
+ {Py_sq_inplace_repeat, deque_inplace_repeat},
+ {0, NULL},
+};
+
+static PyType_Spec deque_spec = {
+ .name = "collections.deque",
+ .basicsize = sizeof(dequeobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_SEQUENCE |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = deque_slots,
};
/*********************** Deque Iterator **************************/
@@ -1658,14 +1689,13 @@ typedef struct {
Py_ssize_t counter; /* number of items remaining for iteration */
} dequeiterobject;
-static PyTypeObject dequeiter_type;
-
static PyObject *
deque_iter(dequeobject *deque)
{
dequeiterobject *it;
- it = PyObject_GC_New(dequeiterobject, &dequeiter_type);
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
+ it = PyObject_GC_New(dequeiterobject, state->dequeiter_type);
if (it == NULL)
return NULL;
it->b = deque->leftblock;
@@ -1680,17 +1710,27 @@ deque_iter(dequeobject *deque)
static int
dequeiter_traverse(dequeiterobject *dio, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(dio));
Py_VISIT(dio->deque);
return 0;
}
+static int
+dequeiter_clear(dequeiterobject *dio)
+{
+ Py_CLEAR(dio->deque);
+ return 0;
+}
+
static void
dequeiter_dealloc(dequeiterobject *dio)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
+ PyTypeObject *tp = Py_TYPE(dio);
PyObject_GC_UnTrack(dio);
- Py_XDECREF(dio->deque);
+ (void)dequeiter_clear(dio);
PyObject_GC_Del(dio);
+ Py_DECREF(tp);
}
static PyObject *
@@ -1726,9 +1766,10 @@ dequeiter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_ssize_t i, index=0;
PyObject *deque;
dequeiterobject *it;
- if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ collections_state *state = get_module_state_by_cls(type);
+ if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index))
return NULL;
- assert(type == &dequeiter_type);
+ assert(type == state->dequeiter_type);
it = (dequeiterobject*)deque_iter((dequeobject *)deque);
if (!it)
@@ -1769,59 +1810,35 @@ static PyMethodDef dequeiter_methods[] = {
{NULL, NULL} /* sentinel */
};
-static PyTypeObject dequeiter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._deque_iterator", /* tp_name */
- sizeof(dequeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dequeiter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dequeiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dequeiter_next, /* tp_iternext */
- dequeiter_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- dequeiter_new, /* tp_new */
- 0,
+static PyType_Slot dequeiter_slots[] = {
+ {Py_tp_dealloc, dequeiter_dealloc},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, dequeiter_traverse},
+ {Py_tp_clear, dequeiter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, dequeiter_next},
+ {Py_tp_methods, dequeiter_methods},
+ {Py_tp_new, dequeiter_new},
+ {0, NULL},
};
-/*********************** Deque Reverse Iterator **************************/
+static PyType_Spec dequeiter_spec = {
+ .name = "collections._deque_iterator",
+ .basicsize = sizeof(dequeiterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = dequeiter_slots,
+};
-static PyTypeObject dequereviter_type;
+/*********************** Deque Reverse Iterator **************************/
static PyObject *
deque_reviter(dequeobject *deque, PyObject *Py_UNUSED(ignored))
{
dequeiterobject *it;
+ collections_state *state = find_module_state_by_def(Py_TYPE(deque));
- it = PyObject_GC_New(dequeiterobject, &dequereviter_type);
+ it = PyObject_GC_New(dequeiterobject, state->dequereviter_type);
if (it == NULL)
return NULL;
it->b = deque->rightblock;
@@ -1866,9 +1883,10 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_ssize_t i, index=0;
PyObject *deque;
dequeiterobject *it;
- if (!PyArg_ParseTuple(args, "O!|n", &deque_type, &deque, &index))
+ collections_state *state = get_module_state_by_cls(type);
+ if (!PyArg_ParseTuple(args, "O!|n", state->deque_type, &deque, &index))
return NULL;
- assert(type == &dequereviter_type);
+ assert(type == state->dequereviter_type);
it = (dequeiterobject*)deque_reviter((dequeobject *)deque, NULL);
if (!it)
@@ -1889,47 +1907,24 @@ dequereviter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject*)it;
}
-static PyTypeObject dequereviter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._deque_reverse_iterator", /* tp_name */
- sizeof(dequeiterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)dequeiter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)dequeiter_traverse, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- PyObject_SelfIter, /* tp_iter */
- (iternextfunc)dequereviter_next, /* tp_iternext */
- dequeiter_methods, /* tp_methods */
- 0, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- dequereviter_new, /* tp_new */
- 0,
+static PyType_Slot dequereviter_slots[] = {
+ {Py_tp_dealloc, dequeiter_dealloc},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_traverse, dequeiter_traverse},
+ {Py_tp_clear, dequeiter_clear},
+ {Py_tp_iter, PyObject_SelfIter},
+ {Py_tp_iternext, dequereviter_next},
+ {Py_tp_methods, dequeiter_methods},
+ {Py_tp_new, dequereviter_new},
+ {0, NULL},
+};
+
+static PyType_Spec dequereviter_spec = {
+ .name = "collections._deque_reverse_iterator",
+ .basicsize = sizeof(dequeiterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = dequereviter_slots,
};
/* defaultdict type *********************************************************/
@@ -1939,8 +1934,6 @@ typedef struct {
PyObject *default_factory;
} defdictobject;
-static PyTypeObject defdict_type; /* Forward */
-
PyDoc_STRVAR(defdict_missing_doc,
"__missing__(key) # Called by __getitem__ for missing key; pseudo-code:\n\
if self.default_factory is None: raise KeyError((key,))\n\
@@ -2071,9 +2064,11 @@ static void
defdict_dealloc(defdictobject *dd)
{
/* bpo-31095: UnTrack is needed before calling any callbacks */
+ PyTypeObject *tp = Py_TYPE(dd);
PyObject_GC_UnTrack(dd);
Py_CLEAR(dd->default_factory);
PyDict_Type.tp_dealloc((PyObject *)dd);
+ Py_DECREF(tp);
}
static PyObject *
@@ -2117,11 +2112,24 @@ static PyObject*
defdict_or(PyObject* left, PyObject* right)
{
PyObject *self, *other;
- if (PyObject_TypeCheck(left, &defdict_type)) {
+
+ // Find module state
+ PyTypeObject *tp = Py_TYPE(left);
+ PyObject *mod = PyType_GetModuleByDef(tp, &_collectionsmodule);
+ if (mod == NULL) {
+ PyErr_Clear();
+ tp = Py_TYPE(right);
+ mod = PyType_GetModuleByDef(tp, &_collectionsmodule);
+ }
+ assert(mod != NULL);
+ collections_state *state = get_module_state(mod);
+
+ if (PyObject_TypeCheck(left, state->defdict_type)) {
self = left;
other = right;
}
else {
+ assert(PyObject_TypeCheck(right, state->defdict_type));
self = right;
other = left;
}
@@ -2141,13 +2149,10 @@ defdict_or(PyObject* left, PyObject* right)
return new;
}
-static PyNumberMethods defdict_as_number = {
- .nb_or = defdict_or,
-};
-
static int
defdict_traverse(PyObject *self, visitproc visit, void *arg)
{
+ Py_VISIT(Py_TYPE(self));
Py_VISIT(((defdictobject *)self)->default_factory);
return PyDict_Type.tp_traverse(self, visit, arg);
}
@@ -2203,48 +2208,28 @@ passed to the dict constructor, including keyword arguments.\n\
/* See comment in xxsubtype.c */
#define DEFERRED_ADDRESS(ADDR) 0
-static PyTypeObject defdict_type = {
- PyVarObject_HEAD_INIT(DEFERRED_ADDRESS(&PyType_Type), 0)
- "collections.defaultdict", /* tp_name */
- sizeof(defdictobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)defdict_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)defdict_repr, /* tp_repr */
- &defdict_as_number, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC,
- /* tp_flags */
- defdict_doc, /* tp_doc */
- defdict_traverse, /* tp_traverse */
- (inquiry)defdict_tp_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset*/
- 0, /* tp_iter */
- 0, /* tp_iternext */
- defdict_methods, /* tp_methods */
- defdict_members, /* tp_members */
- 0, /* tp_getset */
- DEFERRED_ADDRESS(&PyDict_Type), /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- defdict_init, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- 0, /* tp_new */
- PyObject_GC_Del, /* tp_free */
+static PyType_Slot defdict_slots[] = {
+ {Py_tp_dealloc, defdict_dealloc},
+ {Py_tp_repr, defdict_repr},
+ {Py_nb_or, defdict_or},
+ {Py_tp_getattro, PyObject_GenericGetAttr},
+ {Py_tp_doc, (void *)defdict_doc},
+ {Py_tp_traverse, defdict_traverse},
+ {Py_tp_clear, defdict_tp_clear},
+ {Py_tp_methods, defdict_methods},
+ {Py_tp_members, defdict_members},
+ {Py_tp_init, defdict_init},
+ {Py_tp_alloc, PyType_GenericAlloc},
+ {Py_tp_free, PyObject_GC_Del},
+ {0, NULL},
+};
+
+static PyType_Spec defdict_spec = {
+ .name = "collections.defaultdict",
+ .basicsize = sizeof(defdictobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = defdict_slots,
};
/* helper function for Counter *********************************************/
@@ -2442,6 +2427,7 @@ static int
tuplegetter_traverse(PyObject *self, visitproc visit, void *arg)
{
_tuplegetterobject *tuplegetter = (_tuplegetterobject *)self;
+ Py_VISIT(Py_TYPE(tuplegetter));
Py_VISIT(tuplegetter->doc);
return 0;
}
@@ -2457,9 +2443,11 @@ tuplegetter_clear(PyObject *self)
static void
tuplegetter_dealloc(_tuplegetterobject *self)
{
+ PyTypeObject *tp = Py_TYPE(self);
PyObject_GC_UnTrack(self);
tuplegetter_clear((PyObject*)self);
- Py_TYPE(self)->tp_free((PyObject*)self);
+ tp->tp_free((PyObject*)self);
+ Py_DECREF(tp);
}
static PyObject*
@@ -2487,52 +2475,60 @@ static PyMethodDef tuplegetter_methods[] = {
{NULL},
};
-static PyTypeObject tuplegetter_type = {
- PyVarObject_HEAD_INIT(NULL, 0)
- "_collections._tuplegetter", /* tp_name */
- sizeof(_tuplegetterobject), /* tp_basicsize */
- 0, /* tp_itemsize */
- /* methods */
- (destructor)tuplegetter_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)tuplegetter_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC, /* tp_flags */
- 0, /* tp_doc */
- (traverseproc)tuplegetter_traverse, /* tp_traverse */
- (inquiry)tuplegetter_clear, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- tuplegetter_methods, /* tp_methods */
- tuplegetter_members, /* tp_members */
- 0, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- tuplegetter_descr_get, /* tp_descr_get */
- tuplegetter_descr_set, /* tp_descr_set */
- 0, /* tp_dictoffset */
- 0, /* tp_init */
- 0, /* tp_alloc */
- tuplegetter_new, /* tp_new */
- 0,
+static PyType_Slot tuplegetter_slots[] = {
+ {Py_tp_dealloc, tuplegetter_dealloc},
+ {Py_tp_repr, tuplegetter_repr},
+ {Py_tp_traverse, tuplegetter_traverse},
+ {Py_tp_clear, tuplegetter_clear},
+ {Py_tp_methods, tuplegetter_methods},
+ {Py_tp_members, tuplegetter_members},
+ {Py_tp_descr_get, tuplegetter_descr_get},
+ {Py_tp_descr_set, tuplegetter_descr_set},
+ {Py_tp_new, tuplegetter_new},
+ {0, NULL},
+};
+
+static PyType_Spec tuplegetter_spec = {
+ .name = "collections._tuplegetter",
+ .basicsize = sizeof(_tuplegetterobject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = tuplegetter_slots,
};
/* module level code ********************************************************/
+static int
+collections_traverse(PyObject *mod, visitproc visit, void *arg)
+{
+ collections_state *state = get_module_state(mod);
+ Py_VISIT(state->deque_type);
+ Py_VISIT(state->defdict_type);
+ Py_VISIT(state->dequeiter_type);
+ Py_VISIT(state->dequereviter_type);
+ Py_VISIT(state->tuplegetter_type);
+ return 0;
+}
+
+static int
+collections_clear(PyObject *mod)
+{
+ collections_state *state = get_module_state(mod);
+ Py_CLEAR(state->deque_type);
+ Py_CLEAR(state->defdict_type);
+ Py_CLEAR(state->dequeiter_type);
+ Py_CLEAR(state->dequereviter_type);
+ Py_CLEAR(state->tuplegetter_type);
+ return 0;
+}
+
+static void
+collections_free(void *module)
+{
+ collections_clear((PyObject *)module);
+}
+
PyDoc_STRVAR(collections_doc,
"High performance data structures.\n\
- deque: ordered collection accessible from endpoints only\n\
@@ -2544,43 +2540,50 @@ static struct PyMethodDef collections_methods[] = {
{NULL, NULL} /* sentinel */
};
+#define ADD_TYPE(MOD, SPEC, TYPE, BASE) do { \
+ TYPE = (PyTypeObject *)PyType_FromMetaclass(NULL, MOD, SPEC, \
+ (PyObject *)BASE); \
+ if (TYPE == NULL) { \
+ return -1; \
+ } \
+ if (PyModule_AddType(MOD, TYPE) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
static int
collections_exec(PyObject *module) {
- PyTypeObject *typelist[] = {
- &deque_type,
- &defdict_type,
- &PyODict_Type,
- &dequeiter_type,
- &dequereviter_type,
- &tuplegetter_type
- };
-
- defdict_type.tp_base = &PyDict_Type;
-
- for (size_t i = 0; i < Py_ARRAY_LENGTH(typelist); i++) {
- if (PyModule_AddType(module, typelist[i]) < 0) {
- return -1;
- }
+ collections_state *state = get_module_state(module);
+ ADD_TYPE(module, &deque_spec, state->deque_type, NULL);
+ ADD_TYPE(module, &defdict_spec, state->defdict_type, &PyDict_Type);
+ ADD_TYPE(module, &dequeiter_spec, state->dequeiter_type, NULL);
+ ADD_TYPE(module, &dequereviter_spec, state->dequereviter_type, NULL);
+ ADD_TYPE(module, &tuplegetter_spec, state->tuplegetter_type, NULL);
+
+ if (PyModule_AddType(module, &PyODict_Type) < 0) {
+ return -1;
}
return 0;
}
+#undef ADD_TYPE
+
static struct PyModuleDef_Slot collections_slots[] = {
{Py_mod_exec, collections_exec},
{0, NULL}
};
static struct PyModuleDef _collectionsmodule = {
- PyModuleDef_HEAD_INIT,
- "_collections",
- collections_doc,
- 0,
- collections_methods,
- collections_slots,
- NULL,
- NULL,
- NULL
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "_collections",
+ .m_doc = collections_doc,
+ .m_size = sizeof(collections_state),
+ .m_methods = collections_methods,
+ .m_slots = collections_slots,
+ .m_traverse = collections_traverse,
+ .m_clear = collections_clear,
+ .m_free = collections_free,
};
PyMODINIT_FUNC
diff --git a/Modules/_csv.c b/Modules/_csv.c
index bd337084dbff81..2217cc2ca7a775 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -82,7 +82,8 @@ typedef enum {
} ParserState;
typedef enum {
- QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE
+ QUOTE_MINIMAL, QUOTE_ALL, QUOTE_NONNUMERIC, QUOTE_NONE,
+ QUOTE_STRINGS, QUOTE_NOTNULL
} QuoteStyle;
typedef struct {
@@ -95,6 +96,8 @@ static const StyleDesc quote_styles[] = {
{ QUOTE_ALL, "QUOTE_ALL" },
{ QUOTE_NONNUMERIC, "QUOTE_NONNUMERIC" },
{ QUOTE_NONE, "QUOTE_NONE" },
+ { QUOTE_STRINGS, "QUOTE_STRINGS" },
+ { QUOTE_NOTNULL, "QUOTE_NOTNULL" },
{ 0 }
};
@@ -1264,6 +1267,12 @@ csv_writerow(WriterObj *self, PyObject *seq)
case QUOTE_ALL:
quoted = 1;
break;
+ case QUOTE_STRINGS:
+ quoted = PyUnicode_Check(field);
+ break;
+ case QUOTE_NOTNULL:
+ quoted = field != Py_None;
+ break;
default:
quoted = 0;
break;
@@ -1659,6 +1668,11 @@ PyDoc_STRVAR(csv_module_doc,
" csv.QUOTE_NONNUMERIC means that quotes are always placed around\n"
" fields which do not parse as integers or floating point\n"
" numbers.\n"
+" csv.QUOTE_STRINGS means that quotes are always placed around\n"
+" fields which are strings. Note that the Python value None\n"
+" is not a string.\n"
+" csv.QUOTE_NOTNULL means that quotes are only placed around fields\n"
+" that are not the Python value None.\n"
" csv.QUOTE_NONE means that quotes are never placed around fields.\n"
" * escapechar - specifies a one-character string used to escape\n"
" the delimiter when quoting is set to QUOTE_NONE.\n"
diff --git a/Modules/_datetimemodule.c b/Modules/_datetimemodule.c
index eda8c5610ba659..f317dc14e15bf1 100644
--- a/Modules/_datetimemodule.c
+++ b/Modules/_datetimemodule.c
@@ -6153,17 +6153,31 @@ local_to_seconds(int year, int month, int day,
static PyObject *
local_timezone_from_local(PyDateTime_DateTime *local_dt)
{
- long long seconds;
+ long long seconds, seconds2;
time_t timestamp;
+ int fold = DATE_GET_FOLD(local_dt);
seconds = local_to_seconds(GET_YEAR(local_dt),
GET_MONTH(local_dt),
GET_DAY(local_dt),
DATE_GET_HOUR(local_dt),
DATE_GET_MINUTE(local_dt),
DATE_GET_SECOND(local_dt),
- DATE_GET_FOLD(local_dt));
+ fold);
if (seconds == -1)
return NULL;
+ seconds2 = local_to_seconds(GET_YEAR(local_dt),
+ GET_MONTH(local_dt),
+ GET_DAY(local_dt),
+ DATE_GET_HOUR(local_dt),
+ DATE_GET_MINUTE(local_dt),
+ DATE_GET_SECOND(local_dt),
+ !fold);
+ if (seconds2 == -1)
+ return NULL;
+ /* Detect gap */
+ if (seconds2 != seconds && (seconds2 > seconds) == fold)
+ seconds = seconds2;
+
/* XXX: add bounds check */
timestamp = seconds - epoch;
return local_timezone_from_timestamp(timestamp);
diff --git a/Modules/_io/_iomodule.c b/Modules/_io/_iomodule.c
index 5644cc05c45800..7f4f1d939fb7e9 100644
--- a/Modules/_io/_iomodule.c
+++ b/Modules/_io/_iomodule.c
@@ -616,8 +616,9 @@ iomodule_clear(PyObject *mod) {
}
static void
-iomodule_free(PyObject *mod) {
- iomodule_clear(mod);
+iomodule_free(void *mod)
+{
+ (void)iomodule_clear((PyObject *)mod);
}
diff --git a/Modules/_posixsubprocess.c b/Modules/_posixsubprocess.c
index f3ff39215eab76..f5bce8cd7628ad 100644
--- a/Modules/_posixsubprocess.c
+++ b/Modules/_posixsubprocess.c
@@ -75,6 +75,28 @@
static struct PyModuleDef _posixsubprocessmodule;
+/*[clinic input]
+module _posixsubprocess
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=c62211df27cf7334]*/
+
+/*[python input]
+class pid_t_converter(CConverter):
+ type = 'pid_t'
+ format_unit = '" _Py_PARSE_PID "'
+
+ def parse_arg(self, argname, displayname):
+ return """
+ {paramname} = PyLong_AsPid({argname});
+ if ({paramname} == -1 && PyErr_Occurred()) {{{{
+ goto exit;
+ }}}}
+ """.format(argname=argname, paramname=self.parser_name)
+[python start generated code]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=5af1c116d56cbb5a]*/
+
+#include "clinic/_posixsubprocess.c.h"
+
/* Convert ASCII to a positive int, no libc call. no overflow. -1 on error. */
static int
_pos_int_from_ascii(const char *name)
@@ -744,7 +766,7 @@ do_fork_exec(char *const exec_array[],
assert(preexec_fn == Py_None);
pid = vfork();
- if (pid == -1) {
+ if (pid == (pid_t)-1) {
/* If vfork() fails, fall back to using fork(). When it isn't
* allowed in a process by the kernel, vfork can return -1
* with errno EINVAL. https://bugs.python.org/issue47151. */
@@ -784,44 +806,81 @@ do_fork_exec(char *const exec_array[],
return 0; /* Dead code to avoid a potential compiler warning. */
}
+/*[clinic input]
+_posixsubprocess.fork_exec as subprocess_fork_exec
+ args as process_args: object
+ executable_list: object
+ close_fds: bool
+ pass_fds as py_fds_to_keep: object(subclass_of='&PyTuple_Type')
+ cwd as cwd_obj: object
+ env as env_list: object
+ p2cread: int
+ p2cwrite: int
+ c2pread: int
+ c2pwrite: int
+ errread: int
+ errwrite: int
+ errpipe_read: int
+ errpipe_write: int
+ restore_signals: bool
+ call_setsid: bool
+ pgid_to_set: pid_t
+ gid as gid_object: object
+ extra_groups as extra_groups_packed: object
+ uid as uid_object: object
+ child_umask: int
+ preexec_fn: object
+ allow_vfork: bool
+ /
+
+Spawn a fresh new child process.
+
+Fork a child process, close parent file descriptors as appropriate in the
+child and duplicate the few that are needed before calling exec() in the
+child process.
+
+If close_fds is True, close file descriptors 3 and higher, except those listed
+in the sorted tuple pass_fds.
+
+The preexec_fn, if supplied, will be called immediately before closing file
+descriptors and exec.
+
+WARNING: preexec_fn is NOT SAFE if your application uses threads.
+ It may trigger infrequent, difficult to debug deadlocks.
+
+If an error occurs in the child process before the exec, it is
+serialized and written to the errpipe_write fd per subprocess.py.
+
+Returns: the child process's PID.
+
+Raises: Only on an error in the parent process.
+[clinic start generated code]*/
static PyObject *
-subprocess_fork_exec(PyObject *module, PyObject *args)
+subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
+ PyObject *executable_list, int close_fds,
+ PyObject *py_fds_to_keep, PyObject *cwd_obj,
+ PyObject *env_list, int p2cread, int p2cwrite,
+ int c2pread, int c2pwrite, int errread,
+ int errwrite, int errpipe_read, int errpipe_write,
+ int restore_signals, int call_setsid,
+ pid_t pgid_to_set, PyObject *gid_object,
+ PyObject *extra_groups_packed,
+ PyObject *uid_object, int child_umask,
+ PyObject *preexec_fn, int allow_vfork)
+/*[clinic end generated code: output=7ee4f6ee5cf22b5b input=51757287ef266ffa]*/
{
- PyObject *gc_module = NULL;
- PyObject *executable_list, *py_fds_to_keep;
- PyObject *env_list, *preexec_fn;
- PyObject *process_args, *converted_args = NULL, *fast_args = NULL;
+ PyObject *converted_args = NULL, *fast_args = NULL;
PyObject *preexec_fn_args_tuple = NULL;
- PyObject *extra_groups_packed;
- PyObject *uid_object, *gid_object;
- int p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite;
- int errpipe_read, errpipe_write, close_fds, restore_signals;
- int call_setsid;
- pid_t pgid_to_set = -1;
gid_t *extra_groups = NULL;
- int child_umask;
- PyObject *cwd_obj, *cwd_obj2 = NULL;
- const char *cwd;
+ PyObject *cwd_obj2 = NULL;
+ const char *cwd = NULL;
pid_t pid = -1;
int need_to_reenable_gc = 0;
- char *const *exec_array, *const *argv = NULL, *const *envp = NULL;
- Py_ssize_t arg_num, extra_group_size = 0;
+ char *const *argv = NULL, *const *envp = NULL;
+ Py_ssize_t extra_group_size = 0;
int need_after_fork = 0;
int saved_errno = 0;
- int allow_vfork;
-
- if (!PyArg_ParseTuple(
- args, "OOpO!OOiiiiiiiipp" _Py_PARSE_PID "OOOiOp:fork_exec",
- &process_args, &executable_list,
- &close_fds, &PyTuple_Type, &py_fds_to_keep,
- &cwd_obj, &env_list,
- &p2cread, &p2cwrite, &c2pread, &c2pwrite,
- &errread, &errwrite, &errpipe_read, &errpipe_write,
- &restore_signals, &call_setsid, &pgid_to_set,
- &gid_object, &extra_groups_packed, &uid_object, &child_umask,
- &preexec_fn, &allow_vfork))
- return NULL;
PyInterpreterState *interp = PyInterpreterState_Get();
if ((preexec_fn != Py_None) && (interp != PyInterpreterState_Main())) {
@@ -844,7 +903,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
need_to_reenable_gc = PyGC_Disable();
}
- exec_array = _PySequence_BytesToCharpArray(executable_list);
+ char *const *exec_array = _PySequence_BytesToCharpArray(executable_list);
if (!exec_array)
goto cleanup;
@@ -862,7 +921,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
converted_args = PyTuple_New(num_args);
if (converted_args == NULL)
goto cleanup;
- for (arg_num = 0; arg_num < num_args; ++arg_num) {
+ for (Py_ssize_t arg_num = 0; arg_num < num_args; ++arg_num) {
PyObject *borrowed_arg, *converted_arg;
if (PySequence_Fast_GET_SIZE(fast_args) != num_args) {
PyErr_SetString(PyExc_RuntimeError, "args changed during iteration");
@@ -891,8 +950,6 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
if (PyUnicode_FSConverter(cwd_obj, &cwd_obj2) == 0)
goto cleanup;
cwd = PyBytes_AsString(cwd_obj2);
- } else {
- cwd = NULL;
}
if (extra_groups_packed != Py_None) {
@@ -1019,7 +1076,7 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
py_fds_to_keep, preexec_fn, preexec_fn_args_tuple);
/* Parent (original) process */
- if (pid == -1) {
+ if (pid == (pid_t)-1) {
/* Capture errno for the exception. */
saved_errno = errno;
}
@@ -1068,47 +1125,17 @@ subprocess_fork_exec(PyObject *module, PyObject *args)
if (need_to_reenable_gc) {
PyGC_Enable();
}
- Py_XDECREF(gc_module);
return pid == -1 ? NULL : PyLong_FromPid(pid);
}
-
-PyDoc_STRVAR(subprocess_fork_exec_doc,
-"fork_exec(args, executable_list, close_fds, pass_fds, cwd, env,\n\
- p2cread, p2cwrite, c2pread, c2pwrite,\n\
- errread, errwrite, errpipe_read, errpipe_write,\n\
- restore_signals, call_setsid, pgid_to_set,\n\
- gid, extra_groups, uid,\n\
- preexec_fn)\n\
-\n\
-Forks a child process, closes parent file descriptors as appropriate in the\n\
-child and dups the few that are needed before calling exec() in the child\n\
-process.\n\
-\n\
-If close_fds is true, close file descriptors 3 and higher, except those listed\n\
-in the sorted tuple pass_fds.\n\
-\n\
-The preexec_fn, if supplied, will be called immediately before closing file\n\
-descriptors and exec.\n\
-WARNING: preexec_fn is NOT SAFE if your application uses threads.\n\
- It may trigger infrequent, difficult to debug deadlocks.\n\
-\n\
-If an error occurs in the child process before the exec, it is\n\
-serialized and written to the errpipe_write fd per subprocess.py.\n\
-\n\
-Returns: the child process's PID.\n\
-\n\
-Raises: Only on an error in the parent process.\n\
-");
-
/* module level code ********************************************************/
PyDoc_STRVAR(module_doc,
"A POSIX helper for the subprocess module.");
static PyMethodDef module_methods[] = {
- {"fork_exec", subprocess_fork_exec, METH_VARARGS, subprocess_fork_exec_doc},
+ SUBPROCESS_FORK_EXEC_METHODDEF
{NULL, NULL} /* sentinel */
};
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 557a6d46ed4632..c1892f6fa0a4b8 100644
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -1482,6 +1482,7 @@ static PyObject *
run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
{
const char *code;
+ int use_main_obmalloc = -1;
int allow_fork = -1;
int allow_exec = -1;
int allow_threads = -1;
@@ -1493,6 +1494,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
PyCompilerFlags cflags = {0};
static char *kwlist[] = {"code",
+ "use_main_obmalloc",
"allow_fork",
"allow_exec",
"allow_threads",
@@ -1500,12 +1502,17 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
"check_multi_interp_extensions",
NULL};
if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "s$ppppp:run_in_subinterp_with_config", kwlist,
- &code, &allow_fork, &allow_exec,
+ "s$pppppp:run_in_subinterp_with_config", kwlist,
+ &code, &use_main_obmalloc,
+ &allow_fork, &allow_exec,
&allow_threads, &allow_daemon_threads,
&check_multi_interp_extensions)) {
return NULL;
}
+ if (use_main_obmalloc < 0) {
+ PyErr_SetString(PyExc_ValueError, "missing use_main_obmalloc");
+ return NULL;
+ }
if (allow_fork < 0) {
PyErr_SetString(PyExc_ValueError, "missing allow_fork");
return NULL;
@@ -1532,6 +1539,7 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
PyThreadState_Swap(NULL);
const _PyInterpreterConfig config = {
+ .use_main_obmalloc = use_main_obmalloc,
.allow_fork = allow_fork,
.allow_exec = allow_exec,
.allow_threads = allow_threads,
@@ -2733,6 +2741,18 @@ type_get_version(PyObject *self, PyObject *type)
}
+static PyObject *
+type_assign_version(PyObject *self, PyObject *type)
+{
+ if (!PyType_Check(type)) {
+ PyErr_SetString(PyExc_TypeError, "argument must be a type");
+ return NULL;
+ }
+ int res = PyUnstable_Type_AssignVersionTag((PyTypeObject *)type);
+ return PyLong_FromLong(res);
+}
+
+
// Test PyThreadState C API
static PyObject *
test_tstate_capi(PyObject *self, PyObject *Py_UNUSED(args))
@@ -3530,6 +3550,7 @@ static PyMethodDef TestMethods[] = {
{"test_py_is_macros", test_py_is_macros, METH_NOARGS},
{"test_py_is_funcs", test_py_is_funcs, METH_NOARGS},
{"type_get_version", type_get_version, METH_O, PyDoc_STR("type->tp_version_tag")},
+ {"type_assign_version", type_assign_version, METH_O, PyDoc_STR("PyUnstable_Type_AssignVersionTag")},
{"test_tstate_capi", test_tstate_capi, METH_NOARGS, NULL},
{"frame_getlocals", frame_getlocals, METH_O, NULL},
{"frame_getglobals", frame_getglobals, METH_O, NULL},
diff --git a/Modules/_threadmodule.c b/Modules/_threadmodule.c
index 9c12c696757439..fd2fd9ab25f113 100644
--- a/Modules/_threadmodule.c
+++ b/Modules/_threadmodule.c
@@ -946,7 +946,7 @@ local_setattro(localobject *self, PyObject *name, PyObject *v)
}
if (r == 1) {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object attribute '%U' is read-only",
+ "'%.100s' object attribute '%U' is read-only",
Py_TYPE(self)->tp_name, name);
return -1;
}
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 20e01c79668549..385a05932a77ed 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -324,10 +324,6 @@ static int quitMainLoop = 0;
static int errorInCmd = 0;
static PyObject *excInCmd;
-#ifdef TKINTER_PROTECT_LOADTK
-static int tk_load_failed = 0;
-#endif
-
static PyObject *Tkapp_UnicodeResult(TkappObject *);
@@ -532,17 +528,7 @@ Tcl_AppInit(Tcl_Interp *interp)
return TCL_OK;
}
-#ifdef TKINTER_PROTECT_LOADTK
- if (tk_load_failed) {
- PySys_WriteStderr("Tk_Init error: %s\n", TKINTER_LOADTK_ERRMSG);
- return TCL_ERROR;
- }
-#endif
-
if (Tk_Init(interp) == TCL_ERROR) {
-#ifdef TKINTER_PROTECT_LOADTK
- tk_load_failed = 1;
-#endif
PySys_WriteStderr("Tk_Init error: %s\n", Tcl_GetStringResult(interp));
return TCL_ERROR;
}
@@ -635,12 +621,6 @@ Tkapp_New(const char *screenName, const char *className,
Tcl_SetVar(v->interp,
"_tkinter_skip_tk_init", "1", TCL_GLOBAL_ONLY);
}
-#ifdef TKINTER_PROTECT_LOADTK
- else if (tk_load_failed) {
- Tcl_SetVar(v->interp,
- "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY);
- }
-#endif
/* some initial arguments need to be in argv */
if (sync || use) {
@@ -702,18 +682,6 @@ Tkapp_New(const char *screenName, const char *className,
if (Tcl_AppInit(v->interp) != TCL_OK) {
PyObject *result = Tkinter_Error(v);
-#ifdef TKINTER_PROTECT_LOADTK
- if (wantTk) {
- const char *_tkinter_tk_failed;
- _tkinter_tk_failed = Tcl_GetVar(v->interp,
- "_tkinter_tk_failed", TCL_GLOBAL_ONLY);
-
- if ( _tkinter_tk_failed != NULL &&
- strcmp(_tkinter_tk_failed, "1") == 0) {
- tk_load_failed = 1;
- }
- }
-#endif
Py_DECREF((PyObject *)v);
return (TkappObject *)result;
}
@@ -2780,18 +2748,6 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
const char * _tk_exists = NULL;
int err;
-#ifdef TKINTER_PROTECT_LOADTK
- /* Up to Tk 8.4.13, Tk_Init deadlocks on the second call when the
- * first call failed.
- * To avoid the deadlock, we just refuse the second call through
- * a static variable.
- */
- if (tk_load_failed) {
- PyErr_SetString(Tkinter_TclError, TKINTER_LOADTK_ERRMSG);
- return NULL;
- }
-#endif
-
/* We want to guard against calling Tk_Init() multiple times */
CHECK_TCL_APPARTMENT;
ENTER_TCL
@@ -2811,9 +2767,6 @@ _tkinter_tkapp_loadtk_impl(TkappObject *self)
if (_tk_exists == NULL || strcmp(_tk_exists, "1") != 0) {
if (Tk_Init(interp) == TCL_ERROR) {
Tkinter_Error(self);
-#ifdef TKINTER_PROTECT_LOADTK
- tk_load_failed = 1;
-#endif
return NULL;
}
}
diff --git a/Modules/cjkcodecs/_codecs_cn.c b/Modules/cjkcodecs/_codecs_cn.c
index 8a62f7e257c6b1..e2c7908c9bb275 100644
--- a/Modules/cjkcodecs/_codecs_cn.c
+++ b/Modules/cjkcodecs/_codecs_cn.c
@@ -453,14 +453,14 @@ DECODER(hz)
}
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(4)
MAPPING_DECONLY(gb2312)
MAPPING_DECONLY(gbkext)
MAPPING_ENCONLY(gbcommon)
MAPPING_ENCDEC(gb18030ext)
END_MAPPINGS_LIST
-BEGIN_CODECS_LIST
+BEGIN_CODECS_LIST(4)
CODEC_STATELESS(gb2312)
CODEC_STATELESS(gbk)
CODEC_STATELESS(gb18030)
diff --git a/Modules/cjkcodecs/_codecs_hk.c b/Modules/cjkcodecs/_codecs_hk.c
index 4f21569a0ce73f..43593b873733e6 100644
--- a/Modules/cjkcodecs/_codecs_hk.c
+++ b/Modules/cjkcodecs/_codecs_hk.c
@@ -177,14 +177,13 @@ DECODER(big5hkscs)
return 0;
}
-
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(3)
MAPPING_DECONLY(big5hkscs)
MAPPING_ENCONLY(big5hkscs_bmp)
MAPPING_ENCONLY(big5hkscs_nonbmp)
END_MAPPINGS_LIST
-BEGIN_CODECS_LIST
+BEGIN_CODECS_LIST(1)
CODEC_STATELESS_WINIT(big5hkscs)
END_CODECS_LIST
diff --git a/Modules/cjkcodecs/_codecs_iso2022.c b/Modules/cjkcodecs/_codecs_iso2022.c
index 7394cf67e0e7dd..cf34752e16a527 100644
--- a/Modules/cjkcodecs/_codecs_iso2022.c
+++ b/Modules/cjkcodecs/_codecs_iso2022.c
@@ -1119,18 +1119,19 @@ static const struct iso2022_designation iso2022_jp_ext_designations[] = {
CONFIGDEF(jp_ext, NO_SHIFT | USE_JISX0208_EXT)
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(0)
/* no mapping table here */
END_MAPPINGS_LIST
-#define ISO2022_CODEC(variation) { \
+#define ISO2022_CODEC(variation) \
+NEXT_CODEC = (MultibyteCodec){ \
"iso2022_" #variation, \
&iso2022_##variation##_config, \
iso2022_codec_init, \
_STATEFUL_METHODS(iso2022) \
-},
+};
-BEGIN_CODECS_LIST
+BEGIN_CODECS_LIST(7)
ISO2022_CODEC(kr)
ISO2022_CODEC(jp)
ISO2022_CODEC(jp_1)
diff --git a/Modules/cjkcodecs/_codecs_jp.c b/Modules/cjkcodecs/_codecs_jp.c
index 3a332953b957cb..7a8b78a23592ea 100644
--- a/Modules/cjkcodecs/_codecs_jp.c
+++ b/Modules/cjkcodecs/_codecs_jp.c
@@ -733,7 +733,7 @@ DECODER(shift_jis_2004)
}
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(11)
MAPPING_DECONLY(jisx0208)
MAPPING_DECONLY(jisx0212)
MAPPING_ENCONLY(jisxcommon)
@@ -747,14 +747,19 @@ BEGIN_MAPPINGS_LIST
MAPPING_ENCDEC(cp932ext)
END_MAPPINGS_LIST
-BEGIN_CODECS_LIST
+#define CODEC_CUSTOM(NAME, N, METH) \
+ NEXT_CODEC = (MultibyteCodec){NAME, (void *)N, NULL, _STATELESS_METHODS(METH)};
+
+BEGIN_CODECS_LIST(7)
CODEC_STATELESS(shift_jis)
CODEC_STATELESS(cp932)
CODEC_STATELESS(euc_jp)
CODEC_STATELESS(shift_jis_2004)
CODEC_STATELESS(euc_jis_2004)
- { "euc_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(euc_jis_2004) },
- { "shift_jisx0213", (void *)2000, NULL, _STATELESS_METHODS(shift_jis_2004) },
+ CODEC_CUSTOM("euc_jisx0213", 2000, euc_jis_2004)
+ CODEC_CUSTOM("shift_jisx0213", 2000, shift_jis_2004)
END_CODECS_LIST
+#undef CODEC_CUSTOM
+
I_AM_A_MODULE_FOR(jp)
diff --git a/Modules/cjkcodecs/_codecs_kr.c b/Modules/cjkcodecs/_codecs_kr.c
index 72641e495af0b0..fd9a9fd92db1fd 100644
--- a/Modules/cjkcodecs/_codecs_kr.c
+++ b/Modules/cjkcodecs/_codecs_kr.c
@@ -453,13 +453,13 @@ DECODER(johab)
#undef FILL
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(3)
MAPPING_DECONLY(ksx1001)
MAPPING_ENCONLY(cp949)
MAPPING_DECONLY(cp949ext)
END_MAPPINGS_LIST
-BEGIN_CODECS_LIST
+BEGIN_CODECS_LIST(3)
CODEC_STATELESS(euc_kr)
CODEC_STATELESS(cp949)
CODEC_STATELESS(johab)
diff --git a/Modules/cjkcodecs/_codecs_tw.c b/Modules/cjkcodecs/_codecs_tw.c
index 722b26b128a708..3e440991414434 100644
--- a/Modules/cjkcodecs/_codecs_tw.c
+++ b/Modules/cjkcodecs/_codecs_tw.c
@@ -130,12 +130,12 @@ DECODER(cp950)
-BEGIN_MAPPINGS_LIST
+BEGIN_MAPPINGS_LIST(2)
MAPPING_ENCDEC(big5)
MAPPING_ENCDEC(cp950ext)
END_MAPPINGS_LIST
-BEGIN_CODECS_LIST
+BEGIN_CODECS_LIST(2)
CODEC_STATELESS(big5)
CODEC_STATELESS(cp950)
END_CODECS_LIST
diff --git a/Modules/cjkcodecs/cjkcodecs.h b/Modules/cjkcodecs/cjkcodecs.h
index d9aeec2ff40b08..1b0355310eddab 100644
--- a/Modules/cjkcodecs/cjkcodecs.h
+++ b/Modules/cjkcodecs/cjkcodecs.h
@@ -60,8 +60,20 @@ struct pair_encodemap {
DBCHAR code;
};
-static const MultibyteCodec *codec_list;
-static const struct dbcs_map *mapping_list;
+typedef struct {
+ int num_mappings;
+ int num_codecs;
+ struct dbcs_map *mapping_list;
+ MultibyteCodec *codec_list;
+} cjkcodecs_module_state;
+
+static inline cjkcodecs_module_state *
+get_module_state(PyObject *mod)
+{
+ void *state = PyModule_GetState(mod);
+ assert(state != NULL);
+ return (cjkcodecs_module_state *)state;
+}
#define CODEC_INIT(encoding) \
static int encoding##_codec_init(const void *config)
@@ -202,16 +214,42 @@ static const struct dbcs_map *mapping_list;
#define TRYMAP_DEC(charset, assi, c1, c2) \
_TRYMAP_DEC(&charset##_decmap[c1], assi, c2)
-#define BEGIN_MAPPINGS_LIST static const struct dbcs_map _mapping_list[] = {
-#define MAPPING_ENCONLY(enc) {#enc, (void*)enc##_encmap, NULL},
-#define MAPPING_DECONLY(enc) {#enc, NULL, (void*)enc##_decmap},
-#define MAPPING_ENCDEC(enc) {#enc, (void*)enc##_encmap, (void*)enc##_decmap},
-#define END_MAPPINGS_LIST \
- {"", NULL, NULL} }; \
- static const struct dbcs_map *mapping_list = \
- (const struct dbcs_map *)_mapping_list;
+#define BEGIN_MAPPINGS_LIST(NUM) \
+static int \
+add_mappings(cjkcodecs_module_state *st) \
+{ \
+ int idx = 0; \
+ (void)idx; \
+ st->num_mappings = NUM; \
+ st->mapping_list = PyMem_Calloc(NUM, sizeof(struct dbcs_map)); \
+ if (st->mapping_list == NULL) { \
+ return -1; \
+ }
+
+#define MAPPING_ENCONLY(enc) \
+ st->mapping_list[idx++] = (struct dbcs_map){#enc, (void*)enc##_encmap, NULL};
+#define MAPPING_DECONLY(enc) \
+ st->mapping_list[idx++] = (struct dbcs_map){#enc, NULL, (void*)enc##_decmap};
+#define MAPPING_ENCDEC(enc) \
+ st->mapping_list[idx++] = (struct dbcs_map){#enc, (void*)enc##_encmap, (void*)enc##_decmap};
+
+#define END_MAPPINGS_LIST \
+ assert(st->num_mappings == idx); \
+ return 0; \
+}
+
+#define BEGIN_CODECS_LIST(NUM) \
+static int \
+add_codecs(cjkcodecs_module_state *st) \
+{ \
+ int idx = 0; \
+ (void)idx; \
+ st->num_codecs = NUM; \
+ st->codec_list = PyMem_Calloc(NUM, sizeof(MultibyteCodec)); \
+ if (st->codec_list == NULL) { \
+ return -1; \
+ }
-#define BEGIN_CODECS_LIST static const MultibyteCodec _codec_list[] = {
#define _STATEFUL_METHODS(enc) \
enc##_encode, \
enc##_encode_init, \
@@ -222,23 +260,21 @@ static const struct dbcs_map *mapping_list;
#define _STATELESS_METHODS(enc) \
enc##_encode, NULL, NULL, \
enc##_decode, NULL, NULL,
-#define CODEC_STATEFUL(enc) { \
- #enc, NULL, NULL, \
- _STATEFUL_METHODS(enc) \
-},
-#define CODEC_STATELESS(enc) { \
- #enc, NULL, NULL, \
- _STATELESS_METHODS(enc) \
-},
-#define CODEC_STATELESS_WINIT(enc) { \
- #enc, NULL, \
- enc##_codec_init, \
- _STATELESS_METHODS(enc) \
-},
-#define END_CODECS_LIST \
- {"", NULL,} }; \
- static const MultibyteCodec *codec_list = \
- (const MultibyteCodec *)_codec_list;
+
+#define NEXT_CODEC \
+ st->codec_list[idx++]
+
+#define CODEC_STATEFUL(enc) \
+ NEXT_CODEC = (MultibyteCodec){#enc, NULL, NULL, _STATEFUL_METHODS(enc)};
+#define CODEC_STATELESS(enc) \
+ NEXT_CODEC = (MultibyteCodec){#enc, NULL, NULL, _STATELESS_METHODS(enc)};
+#define CODEC_STATELESS_WINIT(enc) \
+ NEXT_CODEC = (MultibyteCodec){#enc, NULL, enc##_codec_init, _STATELESS_METHODS(enc)};
+
+#define END_CODECS_LIST \
+ assert(st->num_codecs == idx); \
+ return 0; \
+}
@@ -248,59 +284,102 @@ getmultibytecodec(void)
return _PyImport_GetModuleAttrString("_multibytecodec", "__create_codec");
}
-static PyObject *
-getcodec(PyObject *self, PyObject *encoding)
+static void
+destroy_codec_capsule(PyObject *capsule)
{
- PyObject *codecobj, *r, *cofunc;
- const MultibyteCodec *codec;
- const char *enc;
+ void *ptr = PyCapsule_GetPointer(capsule, CODEC_CAPSULE);
+ codec_capsule *data = (codec_capsule *)ptr;
+ Py_DECREF(data->cjk_module);
+ PyMem_Free(ptr);
+}
- if (!PyUnicode_Check(encoding)) {
- PyErr_SetString(PyExc_TypeError,
- "encoding name must be a string.");
+static codec_capsule *
+capsulate_codec(PyObject *mod, const MultibyteCodec *codec)
+{
+ codec_capsule *data = PyMem_Malloc(sizeof(codec_capsule));
+ if (data == NULL) {
+ PyErr_NoMemory();
return NULL;
}
- enc = PyUnicode_AsUTF8(encoding);
- if (enc == NULL)
- return NULL;
+ data->codec = codec;
+ data->cjk_module = Py_NewRef(mod);
+ return data;
+}
- cofunc = getmultibytecodec();
- if (cofunc == NULL)
+static PyObject *
+_getcodec(PyObject *self, const MultibyteCodec *codec)
+{
+ PyObject *cofunc = getmultibytecodec();
+ if (cofunc == NULL) {
return NULL;
+ }
- for (codec = codec_list; codec->encoding[0]; codec++)
- if (strcmp(codec->encoding, enc) == 0)
- break;
-
- if (codec->encoding[0] == '\0') {
- PyErr_SetString(PyExc_LookupError,
- "no such codec is supported.");
+ codec_capsule *data = capsulate_codec(self, codec);
+ if (data == NULL) {
+ Py_DECREF(cofunc);
return NULL;
}
-
- codecobj = PyCapsule_New((void *)codec, PyMultibyteCodec_CAPSULE_NAME, NULL);
- if (codecobj == NULL)
+ PyObject *codecobj = PyCapsule_New(data, CODEC_CAPSULE,
+ destroy_codec_capsule);
+ if (codecobj == NULL) {
+ PyMem_Free(data);
+ Py_DECREF(cofunc);
return NULL;
+ }
- r = PyObject_CallOneArg(cofunc, codecobj);
+ PyObject *res = PyObject_CallOneArg(cofunc, codecobj);
Py_DECREF(codecobj);
Py_DECREF(cofunc);
+ return res;
+}
+
+static PyObject *
+getcodec(PyObject *self, PyObject *encoding)
+{
+ if (!PyUnicode_Check(encoding)) {
+ PyErr_SetString(PyExc_TypeError,
+ "encoding name must be a string.");
+ return NULL;
+ }
+ const char *enc = PyUnicode_AsUTF8(encoding);
+ if (enc == NULL) {
+ return NULL;
+ }
+
+ cjkcodecs_module_state *st = get_module_state(self);
+ for (int i = 0; i < st->num_codecs; i++) {
+ const MultibyteCodec *codec = &st->codec_list[i];
+ if (strcmp(codec->encoding, enc) == 0) {
+ return _getcodec(self, codec);
+ }
+ }
- return r;
+ PyErr_SetString(PyExc_LookupError,
+ "no such codec is supported.");
+ return NULL;
}
+static int add_mappings(cjkcodecs_module_state *);
+static int add_codecs(cjkcodecs_module_state *);
static int
register_maps(PyObject *module)
{
- const struct dbcs_map *h;
+ // Init module state.
+ cjkcodecs_module_state *st = get_module_state(module);
+ if (add_mappings(st) < 0) {
+ return -1;
+ }
+ if (add_codecs(st) < 0) {
+ return -1;
+ }
- for (h = mapping_list; h->charset[0] != '\0'; h++) {
+ for (int i = 0; i < st->num_mappings; i++) {
+ const struct dbcs_map *h = &st->mapping_list[i];
char mhname[256] = "__map_";
strcpy(mhname + sizeof("__map_") - 1, h->charset);
- PyObject *capsule = PyCapsule_New((void *)h,
- PyMultibyteCodec_CAPSULE_NAME, NULL);
+ PyObject *capsule = PyCapsule_New((void *)h, MAP_CAPSULE, NULL);
if (capsule == NULL) {
return -1;
}
@@ -364,14 +443,14 @@ importmap(const char *modname, const char *symbol,
o = PyObject_GetAttrString(mod, symbol);
if (o == NULL)
goto errorexit;
- else if (!PyCapsule_IsValid(o, PyMultibyteCodec_CAPSULE_NAME)) {
+ else if (!PyCapsule_IsValid(o, MAP_CAPSULE)) {
PyErr_SetString(PyExc_ValueError,
"map data must be a Capsule.");
goto errorexit;
}
else {
struct dbcs_map *map;
- map = PyCapsule_GetPointer(o, PyMultibyteCodec_CAPSULE_NAME);
+ map = PyCapsule_GetPointer(o, MAP_CAPSULE);
if (encmap != NULL)
*encmap = map->encmap;
if (decmap != NULL)
@@ -394,6 +473,13 @@ _cjk_exec(PyObject *module)
return register_maps(module);
}
+static void
+_cjk_free(void *mod)
+{
+ cjkcodecs_module_state *st = get_module_state((PyObject *)mod);
+ PyMem_Free(st->mapping_list);
+ PyMem_Free(st->codec_list);
+}
static struct PyMethodDef _cjk_methods[] = {
{"getcodec", (PyCFunction)getcodec, METH_O, ""},
@@ -409,9 +495,10 @@ static PyModuleDef_Slot _cjk_slots[] = {
static struct PyModuleDef _cjk_module = { \
PyModuleDef_HEAD_INIT, \
.m_name = "_codecs_"#loc, \
- .m_size = 0, \
+ .m_size = sizeof(cjkcodecs_module_state), \
.m_methods = _cjk_methods, \
.m_slots = _cjk_slots, \
+ .m_free = _cjk_free, \
}; \
\
PyMODINIT_FUNC \
diff --git a/Modules/cjkcodecs/multibytecodec.c b/Modules/cjkcodecs/multibytecodec.c
index 8564494f6262fb..8976ad331aaa2a 100644
--- a/Modules/cjkcodecs/multibytecodec.c
+++ b/Modules/cjkcodecs/multibytecodec.c
@@ -19,26 +19,27 @@ typedef struct {
PyTypeObject *writer_type;
PyTypeObject *multibytecodec_type;
PyObject *str_write;
-} _multibytecodec_state;
+} module_state;
-static _multibytecodec_state *
-_multibytecodec_get_state(PyObject *module)
+static module_state *
+get_module_state(PyObject *module)
{
- _multibytecodec_state *state = PyModule_GetState(module);
+ module_state *state = PyModule_GetState(module);
assert(state != NULL);
return state;
}
static struct PyModuleDef _multibytecodecmodule;
-static _multibytecodec_state *
-_multibyte_codec_find_state_by_type(PyTypeObject *type)
+
+static module_state *
+find_state_by_def(PyTypeObject *type)
{
PyObject *module = PyType_GetModuleByDef(type, &_multibytecodecmodule);
assert(module != NULL);
- return _multibytecodec_get_state(module);
+ return get_module_state(module);
}
-#define clinic_get_state() _multibyte_codec_find_state_by_type(type)
+#define clinic_get_state() find_state_by_def(type)
/*[clinic input]
module _multibytecodec
class _multibytecodec.MultibyteCodec "MultibyteCodecObject *" "clinic_get_state()->multibytecodec_type"
@@ -66,7 +67,7 @@ typedef struct {
static char *incnewkwarglist[] = {"errors", NULL};
static char *streamkwarglist[] = {"stream", "errors", NULL};
-static PyObject *multibytecodec_encode(MultibyteCodec *,
+static PyObject *multibytecodec_encode(const MultibyteCodec *,
MultibyteCodec_State *, PyObject *, Py_ssize_t *,
PyObject *, int);
@@ -220,7 +221,7 @@ expand_encodebuffer(MultibyteEncodeBuffer *buf, Py_ssize_t esize)
*/
static int
-multibytecodec_encerror(MultibyteCodec *codec,
+multibytecodec_encerror(const MultibyteCodec *codec,
MultibyteCodec_State *state,
MultibyteEncodeBuffer *buf,
PyObject *errors, Py_ssize_t e)
@@ -374,7 +375,7 @@ multibytecodec_encerror(MultibyteCodec *codec,
}
static int
-multibytecodec_decerror(MultibyteCodec *codec,
+multibytecodec_decerror(const MultibyteCodec *codec,
MultibyteCodec_State *state,
MultibyteDecodeBuffer *buf,
PyObject *errors, Py_ssize_t e)
@@ -478,7 +479,7 @@ multibytecodec_decerror(MultibyteCodec *codec,
}
static PyObject *
-multibytecodec_encode(MultibyteCodec *codec,
+multibytecodec_encode(const MultibyteCodec *codec,
MultibyteCodec_State *state,
PyObject *text, Py_ssize_t *inpos_t,
PyObject *errors, int flags)
@@ -719,9 +720,17 @@ static struct PyMethodDef multibytecodec_methods[] = {
};
static int
-multibytecodec_traverse(PyObject *self, visitproc visit, void *arg)
+multibytecodec_clear(MultibyteCodecObject *self)
+{
+ Py_CLEAR(self->cjk_module);
+ return 0;
+}
+
+static int
+multibytecodec_traverse(MultibyteCodecObject *self, visitproc visit, void *arg)
{
Py_VISIT(Py_TYPE(self));
+ Py_VISIT(self->cjk_module);
return 0;
}
@@ -730,6 +739,7 @@ multibytecodec_dealloc(MultibyteCodecObject *self)
{
PyObject_GC_UnTrack(self);
PyTypeObject *tp = Py_TYPE(self);
+ (void)multibytecodec_clear(self);
tp->tp_free(self);
Py_DECREF(tp);
}
@@ -739,6 +749,7 @@ static PyType_Slot multibytecodec_slots[] = {
{Py_tp_getattro, PyObject_GenericGetAttr},
{Py_tp_methods, multibytecodec_methods},
{Py_tp_traverse, multibytecodec_traverse},
+ {Py_tp_clear, multibytecodec_clear},
{0, NULL},
};
@@ -1040,7 +1051,7 @@ mbiencoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (codec == NULL)
goto errorexit;
- _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type);
+ module_state *state = find_state_by_def(type);
if (!MultibyteCodec_Check(state, codec)) {
PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
goto errorexit;
@@ -1315,7 +1326,7 @@ mbidecoder_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (codec == NULL)
goto errorexit;
- _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type);
+ module_state *state = find_state_by_def(type);
if (!MultibyteCodec_Check(state, codec)) {
PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
goto errorexit;
@@ -1630,7 +1641,7 @@ mbstreamreader_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (codec == NULL)
goto errorexit;
- _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type);
+ module_state *state = find_state_by_def(type);
if (!MultibyteCodec_Check(state, codec)) {
PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
goto errorexit;
@@ -1735,7 +1746,7 @@ _multibytecodec_MultibyteStreamWriter_write_impl(MultibyteStreamWriterObject *se
PyObject *strobj)
/*[clinic end generated code: output=68ade3aea26410ac input=199f26f68bd8425a]*/
{
- _multibytecodec_state *state = PyType_GetModuleState(cls);
+ module_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
if (mbstreamwriter_iwrite(self, strobj, state->str_write)) {
return NULL;
@@ -1766,7 +1777,7 @@ _multibytecodec_MultibyteStreamWriter_writelines_impl(MultibyteStreamWriterObjec
return NULL;
}
- _multibytecodec_state *state = PyType_GetModuleState(cls);
+ module_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
for (i = 0; i < PySequence_Length(lines); i++) {
/* length can be changed even within this loop */
@@ -1817,7 +1828,7 @@ _multibytecodec_MultibyteStreamWriter_reset_impl(MultibyteStreamWriterObject *se
assert(PyBytes_Check(pwrt));
- _multibytecodec_state *state = PyType_GetModuleState(cls);
+ module_state *state = PyType_GetModuleState(cls);
assert(state != NULL);
if (PyBytes_Size(pwrt) > 0) {
@@ -1853,7 +1864,7 @@ mbstreamwriter_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
if (codec == NULL)
goto errorexit;
- _multibytecodec_state *state = _multibyte_codec_find_state_by_type(type);
+ module_state *state = find_state_by_def(type);
if (!MultibyteCodec_Check(state, codec)) {
PyErr_SetString(PyExc_TypeError, "codec is unexpected type");
goto errorexit;
@@ -1952,22 +1963,23 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg)
/*[clinic end generated code: output=cfa3dce8260e809d input=6840b2a6b183fcfa]*/
{
MultibyteCodecObject *self;
- MultibyteCodec *codec;
- if (!PyCapsule_IsValid(arg, PyMultibyteCodec_CAPSULE_NAME)) {
+ if (!PyCapsule_IsValid(arg, CODEC_CAPSULE)) {
PyErr_SetString(PyExc_ValueError, "argument type invalid");
return NULL;
}
- codec = PyCapsule_GetPointer(arg, PyMultibyteCodec_CAPSULE_NAME);
+ codec_capsule *data = PyCapsule_GetPointer(arg, CODEC_CAPSULE);
+ const MultibyteCodec *codec = data->codec;
if (codec->codecinit != NULL && codec->codecinit(codec->config) != 0)
return NULL;
- _multibytecodec_state *state = _multibytecodec_get_state(module);
+ module_state *state = get_module_state(module);
self = PyObject_GC_New(MultibyteCodecObject, state->multibytecodec_type);
if (self == NULL)
return NULL;
self->codec = codec;
+ self->cjk_module = Py_NewRef(data->cjk_module);
PyObject_GC_Track(self);
return (PyObject *)self;
@@ -1976,7 +1988,7 @@ _multibytecodec___create_codec(PyObject *module, PyObject *arg)
static int
_multibytecodec_traverse(PyObject *mod, visitproc visit, void *arg)
{
- _multibytecodec_state *state = _multibytecodec_get_state(mod);
+ module_state *state = get_module_state(mod);
Py_VISIT(state->multibytecodec_type);
Py_VISIT(state->encoder_type);
Py_VISIT(state->decoder_type);
@@ -1988,7 +2000,7 @@ _multibytecodec_traverse(PyObject *mod, visitproc visit, void *arg)
static int
_multibytecodec_clear(PyObject *mod)
{
- _multibytecodec_state *state = _multibytecodec_get_state(mod);
+ module_state *state = get_module_state(mod);
Py_CLEAR(state->multibytecodec_type);
Py_CLEAR(state->encoder_type);
Py_CLEAR(state->decoder_type);
@@ -2022,7 +2034,7 @@ _multibytecodec_free(void *mod)
static int
_multibytecodec_exec(PyObject *mod)
{
- _multibytecodec_state *state = _multibytecodec_get_state(mod);
+ module_state *state = get_module_state(mod);
state->str_write = PyUnicode_InternFromString("write");
if (state->str_write == NULL) {
return -1;
@@ -2056,7 +2068,7 @@ static PyModuleDef_Slot _multibytecodec_slots[] = {
static struct PyModuleDef _multibytecodecmodule = {
.m_base = PyModuleDef_HEAD_INIT,
.m_name = "_multibytecodec",
- .m_size = sizeof(_multibytecodec_state),
+ .m_size = sizeof(module_state),
.m_methods = _multibytecodec_methods,
.m_slots = _multibytecodec_slots,
.m_traverse = _multibytecodec_traverse,
diff --git a/Modules/cjkcodecs/multibytecodec.h b/Modules/cjkcodecs/multibytecodec.h
index 69404ba96aa1f0..327cb51129d945 100644
--- a/Modules/cjkcodecs/multibytecodec.h
+++ b/Modules/cjkcodecs/multibytecodec.h
@@ -62,14 +62,15 @@ typedef struct {
typedef struct {
PyObject_HEAD
- MultibyteCodec *codec;
+ const MultibyteCodec *codec;
+ PyObject *cjk_module;
} MultibyteCodecObject;
#define MultibyteCodec_Check(state, op) Py_IS_TYPE((op), state->multibytecodec_type)
#define _MultibyteStatefulCodec_HEAD \
PyObject_HEAD \
- MultibyteCodec *codec; \
+ const MultibyteCodec *codec; \
MultibyteCodec_State state; \
PyObject *errors;
typedef struct {
@@ -130,7 +131,13 @@ typedef struct {
#define MBENC_FLUSH 0x0001 /* encode all characters encodable */
#define MBENC_MAX MBENC_FLUSH
-#define PyMultibyteCodec_CAPSULE_NAME "multibytecodec.__map_*"
+typedef struct {
+ const MultibyteCodec *codec;
+ PyObject *cjk_module;
+} codec_capsule;
+
+#define MAP_CAPSULE "multibytecodec.map"
+#define CODEC_CAPSULE "multibytecodec.codec"
#ifdef __cplusplus
diff --git a/Modules/clinic/_collectionsmodule.c.h b/Modules/clinic/_collectionsmodule.c.h
index 8ea0255b061070..3882d069216e28 100644
--- a/Modules/clinic/_collectionsmodule.c.h
+++ b/Modules/clinic/_collectionsmodule.c.h
@@ -46,7 +46,7 @@ static PyObject *
tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
PyObject *return_value = NULL;
- PyTypeObject *base_tp = &tuplegetter_type;
+ PyTypeObject *base_tp = clinic_state()->tuplegetter_type;
Py_ssize_t index;
PyObject *doc;
@@ -75,4 +75,4 @@ tuplegetter_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
exit:
return return_value;
}
-/*[clinic end generated code: output=91a0f221c7b1f96c input=a9049054013a1b77]*/
+/*[clinic end generated code: output=00e516317d2b8bed input=a9049054013a1b77]*/
diff --git a/Modules/clinic/_posixsubprocess.c.h b/Modules/clinic/_posixsubprocess.c.h
new file mode 100644
index 00000000000000..f08878cf668908
--- /dev/null
+++ b/Modules/clinic/_posixsubprocess.c.h
@@ -0,0 +1,162 @@
+/*[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(subprocess_fork_exec__doc__,
+"fork_exec($module, args, executable_list, close_fds, pass_fds, cwd,\n"
+" env, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite,\n"
+" errpipe_read, errpipe_write, restore_signals, call_setsid,\n"
+" pgid_to_set, gid, extra_groups, uid, child_umask, preexec_fn,\n"
+" allow_vfork, /)\n"
+"--\n"
+"\n"
+"Spawn a fresh new child process.\n"
+"\n"
+"Fork a child process, close parent file descriptors as appropriate in the\n"
+"child and duplicate the few that are needed before calling exec() in the\n"
+"child process.\n"
+"\n"
+"If close_fds is True, close file descriptors 3 and higher, except those listed\n"
+"in the sorted tuple pass_fds.\n"
+"\n"
+"The preexec_fn, if supplied, will be called immediately before closing file\n"
+"descriptors and exec.\n"
+"\n"
+"WARNING: preexec_fn is NOT SAFE if your application uses threads.\n"
+" It may trigger infrequent, difficult to debug deadlocks.\n"
+"\n"
+"If an error occurs in the child process before the exec, it is\n"
+"serialized and written to the errpipe_write fd per subprocess.py.\n"
+"\n"
+"Returns: the child process\'s PID.\n"
+"\n"
+"Raises: Only on an error in the parent process.");
+
+#define SUBPROCESS_FORK_EXEC_METHODDEF \
+ {"fork_exec", _PyCFunction_CAST(subprocess_fork_exec), METH_FASTCALL, subprocess_fork_exec__doc__},
+
+static PyObject *
+subprocess_fork_exec_impl(PyObject *module, PyObject *process_args,
+ PyObject *executable_list, int close_fds,
+ PyObject *py_fds_to_keep, PyObject *cwd_obj,
+ PyObject *env_list, int p2cread, int p2cwrite,
+ int c2pread, int c2pwrite, int errread,
+ int errwrite, int errpipe_read, int errpipe_write,
+ int restore_signals, int call_setsid,
+ pid_t pgid_to_set, PyObject *gid_object,
+ PyObject *extra_groups_packed,
+ PyObject *uid_object, int child_umask,
+ PyObject *preexec_fn, int allow_vfork);
+
+static PyObject *
+subprocess_fork_exec(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ PyObject *process_args;
+ PyObject *executable_list;
+ int close_fds;
+ PyObject *py_fds_to_keep;
+ PyObject *cwd_obj;
+ PyObject *env_list;
+ int p2cread;
+ int p2cwrite;
+ int c2pread;
+ int c2pwrite;
+ int errread;
+ int errwrite;
+ int errpipe_read;
+ int errpipe_write;
+ int restore_signals;
+ int call_setsid;
+ pid_t pgid_to_set;
+ PyObject *gid_object;
+ PyObject *extra_groups_packed;
+ PyObject *uid_object;
+ int child_umask;
+ PyObject *preexec_fn;
+ int allow_vfork;
+
+ if (!_PyArg_CheckPositional("fork_exec", nargs, 23, 23)) {
+ goto exit;
+ }
+ process_args = args[0];
+ executable_list = args[1];
+ close_fds = PyObject_IsTrue(args[2]);
+ if (close_fds < 0) {
+ goto exit;
+ }
+ if (!PyTuple_Check(args[3])) {
+ _PyArg_BadArgument("fork_exec", "argument 4", "tuple", args[3]);
+ goto exit;
+ }
+ py_fds_to_keep = args[3];
+ cwd_obj = args[4];
+ env_list = args[5];
+ p2cread = _PyLong_AsInt(args[6]);
+ if (p2cread == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ p2cwrite = _PyLong_AsInt(args[7]);
+ if (p2cwrite == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ c2pread = _PyLong_AsInt(args[8]);
+ if (c2pread == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ c2pwrite = _PyLong_AsInt(args[9]);
+ if (c2pwrite == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ errread = _PyLong_AsInt(args[10]);
+ if (errread == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ errwrite = _PyLong_AsInt(args[11]);
+ if (errwrite == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ errpipe_read = _PyLong_AsInt(args[12]);
+ if (errpipe_read == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ errpipe_write = _PyLong_AsInt(args[13]);
+ if (errpipe_write == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ restore_signals = PyObject_IsTrue(args[14]);
+ if (restore_signals < 0) {
+ goto exit;
+ }
+ call_setsid = PyObject_IsTrue(args[15]);
+ if (call_setsid < 0) {
+ goto exit;
+ }
+ pgid_to_set = PyLong_AsPid(args[16]);
+ if (pgid_to_set == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ gid_object = args[17];
+ extra_groups_packed = args[18];
+ uid_object = args[19];
+ child_umask = _PyLong_AsInt(args[20]);
+ if (child_umask == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ preexec_fn = args[21];
+ allow_vfork = PyObject_IsTrue(args[22]);
+ if (allow_vfork < 0) {
+ goto exit;
+ }
+ return_value = subprocess_fork_exec_impl(module, process_args, executable_list, close_fds, py_fds_to_keep, cwd_obj, env_list, p2cread, p2cwrite, c2pread, c2pwrite, errread, errwrite, errpipe_read, errpipe_write, restore_signals, call_setsid, pgid_to_set, gid_object, extra_groups_packed, uid_object, child_umask, preexec_fn, allow_vfork);
+
+exit:
+ return return_value;
+}
+/*[clinic end generated code: output=46d71e86845c93d7 input=a9049054013a1b77]*/
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 4eaa5490b6134c..966c1e615502ef 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -418,8 +418,20 @@ validate_list(PyGC_Head *head, enum flagstates flags)
static void
update_refs(PyGC_Head *containers)
{
+ PyGC_Head *next;
PyGC_Head *gc = GC_NEXT(containers);
- for (; gc != containers; gc = GC_NEXT(gc)) {
+
+ while (gc != containers) {
+ next = GC_NEXT(gc);
+ /* Move any object that might have become immortal to the
+ * permanent generation as the reference count is not accurately
+ * reflecting the actual number of live references to this object
+ */
+ if (_Py_IsImmortal(FROM_GC(gc))) {
+ gc_list_move(gc, &get_gc_state()->permanent_generation.head);
+ gc = next;
+ continue;
+ }
gc_reset_refs(gc, Py_REFCNT(FROM_GC(gc)));
/* Python's cyclic gc should never see an incoming refcount
* of 0: if something decref'ed to 0, it should have been
@@ -440,6 +452,7 @@ update_refs(PyGC_Head *containers)
* check instead of an assert?
*/
_PyObject_ASSERT(FROM_GC(gc), gc_get_refs(gc) != 0);
+ gc = next;
}
}
@@ -2348,16 +2361,17 @@ PyVarObject *
_PyObject_GC_Resize(PyVarObject *op, Py_ssize_t nitems)
{
const size_t basicsize = _PyObject_VAR_SIZE(Py_TYPE(op), nitems);
+ const size_t presize = _PyType_PreHeaderSize(((PyObject *)op)->ob_type);
_PyObject_ASSERT((PyObject *)op, !_PyObject_GC_IS_TRACKED(op));
- if (basicsize > (size_t)PY_SSIZE_T_MAX - sizeof(PyGC_Head)) {
+ if (basicsize > (size_t)PY_SSIZE_T_MAX - presize) {
return (PyVarObject *)PyErr_NoMemory();
}
-
- PyGC_Head *g = AS_GC(op);
- g = (PyGC_Head *)PyObject_Realloc(g, sizeof(PyGC_Head) + basicsize);
- if (g == NULL)
+ char *mem = (char *)op - presize;
+ mem = (char *)PyObject_Realloc(mem, presize + basicsize);
+ if (mem == NULL) {
return (PyVarObject *)PyErr_NoMemory();
- op = (PyVarObject *) FROM_GC(g);
+ }
+ op = (PyVarObject *) (mem + presize);
Py_SET_SIZE(op, nitems);
return op;
}
diff --git a/Modules/socketmodule.c b/Modules/socketmodule.c
index 49342b3d48de0e..656cd546d46d31 100644
--- a/Modules/socketmodule.c
+++ b/Modules/socketmodule.c
@@ -108,6 +108,7 @@ Local naming conventions:
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "pycore_fileutils.h" // _Py_set_inheritable()
+#include "pycore_moduleobject.h" // _PyModule_GetState
#include "structmember.h" // PyMemberDef
#ifdef _Py_MEMORY_SANITIZER
@@ -337,9 +338,9 @@ static FlagRuntimeInfo win_runtime_flags[] = {
/*[clinic input]
module _socket
-class _socket.socket "PySocketSockObject *" "&sock_type"
+class _socket.socket "PySocketSockObject *" "clinic_state()->sock_type"
[clinic start generated code]*/
-/*[clinic end generated code: output=da39a3ee5e6b4b0d input=7a8313d9b7f51988]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=2db2489bd2219fd8]*/
static int
remove_unusable_flags(PyObject *m)
@@ -541,22 +542,59 @@ remove_unusable_flags(PyObject *m)
#define INADDR_NONE (-1)
#endif
+typedef struct _socket_state {
+ /* The sock_type variable contains pointers to various functions,
+ some of which call new_sockobject(), which uses sock_type, so
+ there has to be a circular reference. */
+ PyTypeObject *sock_type;
+
+ /* Global variable holding the exception type for errors detected
+ by this module (but not argument type or memory errors, etc.). */
+ PyObject *socket_herror;
+ PyObject *socket_gaierror;
+
+ /* Default timeout for new sockets */
+ _PyTime_t defaulttimeout;
+
+#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+ /* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
+ int accept4_works;
+#endif
+#endif
+
+#ifdef SOCK_CLOEXEC
+ /* socket() and socketpair() fail with EINVAL on Linux kernel older
+ * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
+ int sock_cloexec_works;
+#endif
+} socket_state;
+
+static inline socket_state *
+get_module_state(PyObject *mod)
+{
+ void *state = _PyModule_GetState(mod);
+ assert(state != NULL);
+ return (socket_state *)state;
+}
+
+static struct PyModuleDef socketmodule;
+
+static inline socket_state *
+find_module_state_by_def(PyTypeObject *type)
+{
+ PyObject *mod = PyType_GetModuleByDef(type, &socketmodule);
+ assert(mod != NULL);
+ return get_module_state(mod);
+}
+
+#define clinic_state() (find_module_state_by_def(type))
#include "clinic/socketmodule.c.h"
+#undef clinic_state
/* XXX There's a problem here: *static* functions are not supposed to have
a Py prefix (or use CapitalizedWords). Later... */
-/* Global variable holding the exception type for errors detected
- by this module (but not argument type or memory errors, etc.). */
-static PyObject *socket_herror;
-static PyObject *socket_gaierror;
-
-/* A forward reference to the socket type object.
- The sock_type variable contains pointers to various functions,
- some of which call new_sockobject(), which uses sock_type, so
- there has to be a circular reference. */
-static PyTypeObject sock_type;
-
#if defined(HAVE_POLL_H)
#include
#elif defined(HAVE_SYS_POLL_H)
@@ -641,7 +679,7 @@ set_error(void)
#if defined(HAVE_GETHOSTBYNAME_R) || defined (HAVE_GETHOSTBYNAME) || defined (HAVE_GETHOSTBYADDR)
static PyObject *
-set_herror(int h_error)
+set_herror(socket_state *state, int h_error)
{
PyObject *v;
@@ -651,7 +689,7 @@ set_herror(int h_error)
v = Py_BuildValue("(is)", h_error, "host not found");
#endif
if (v != NULL) {
- PyErr_SetObject(socket_herror, v);
+ PyErr_SetObject(state->socket_herror, v);
Py_DECREF(v);
}
@@ -662,7 +700,7 @@ set_herror(int h_error)
#ifdef HAVE_GETADDRINFO
static PyObject *
-set_gaierror(int error)
+set_gaierror(socket_state *state, int error)
{
PyObject *v;
@@ -678,7 +716,7 @@ set_gaierror(int error)
v = Py_BuildValue("(is)", error, "getaddrinfo failed");
#endif
if (v != NULL) {
- PyErr_SetObject(socket_gaierror, v);
+ PyErr_SetObject(state->socket_gaierror, v);
Py_DECREF(v);
}
@@ -991,11 +1029,8 @@ sock_call(PySocketSockObject *s,
/* Initialize a new socket object. */
-/* Default timeout for new sockets */
-static _PyTime_t defaulttimeout = _PYTIME_FROMSECONDS(-1);
-
static int
-init_sockobject(PySocketSockObject *s,
+init_sockobject(socket_state *state, PySocketSockObject *s,
SOCKET_T fd, int family, int type, int proto)
{
s->sock_fd = fd;
@@ -1025,13 +1060,14 @@ init_sockobject(PySocketSockObject *s,
else
#endif
{
- s->sock_timeout = defaulttimeout;
- if (defaulttimeout >= 0) {
+ s->sock_timeout = state->defaulttimeout;
+ if (state->defaulttimeout >= 0) {
if (internal_setblocking(s, 0) == -1) {
return -1;
}
}
}
+ s->state = state;
return 0;
}
@@ -1043,14 +1079,15 @@ init_sockobject(PySocketSockObject *s,
in NEWOBJ()). */
static PySocketSockObject *
-new_sockobject(SOCKET_T fd, int family, int type, int proto)
+new_sockobject(socket_state *state, SOCKET_T fd, int family, int type,
+ int proto)
{
- PySocketSockObject *s;
- s = (PySocketSockObject *)
- PyType_GenericNew(&sock_type, NULL, NULL);
- if (s == NULL)
+ PyTypeObject *tp = state->sock_type;
+ PySocketSockObject *s = (PySocketSockObject *)tp->tp_alloc(tp, 0);
+ if (s == NULL) {
return NULL;
- if (init_sockobject(s, fd, family, type, proto) == -1) {
+ }
+ if (init_sockobject(state, s, fd, family, type, proto) == -1) {
Py_DECREF(s);
return NULL;
}
@@ -1074,7 +1111,8 @@ static PyThread_type_lock netdb_lock;
an error occurred; then an exception is raised. */
static int
-setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int af)
+setipaddr(socket_state *state, const char *name, struct sockaddr *addr_ret,
+ size_t addr_ret_size, int af)
{
struct addrinfo hints, *res;
int error;
@@ -1095,7 +1133,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int
outcome of the first call. */
if (error) {
res = NULL; // no-op, remind us that it is invalid; gh-100795
- set_gaierror(error);
+ set_gaierror(state, error);
return -1;
}
switch (res->ai_family) {
@@ -1206,7 +1244,7 @@ setipaddr(const char *name, struct sockaddr *addr_ret, size_t addr_ret_size, int
Py_END_ALLOW_THREADS
if (error) {
res = NULL; // no-op, remind us that it is invalid; gh-100795
- set_gaierror(error);
+ set_gaierror(state, error);
return -1;
}
if (res->ai_addrlen < addr_ret_size)
@@ -1889,7 +1927,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0;
}
struct sockaddr_in* addr = &addrbuf->in;
- result = setipaddr(host.buf, (struct sockaddr *)addr,
+ result = setipaddr(s->state, host.buf, (struct sockaddr *)addr,
sizeof(*addr), AF_INET);
idna_cleanup(&host);
if (result < 0)
@@ -1934,7 +1972,7 @@ getsockaddrarg(PySocketSockObject *s, PyObject *args,
return 0;
}
struct sockaddr_in6* addr = &addrbuf->in6;
- result = setipaddr(host.buf, (struct sockaddr *)addr,
+ result = setipaddr(s->state, host.buf, (struct sockaddr *)addr,
sizeof(*addr), AF_INET6);
idna_cleanup(&host);
if (result < 0)
@@ -2813,10 +2851,6 @@ struct sock_accept {
};
#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
-#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
-/* accept4() is available on Linux 2.6.28+ and glibc 2.10 */
-static int accept4_works = -1;
-#endif
static int
sock_accept_impl(PySocketSockObject *s, void *data)
@@ -2835,15 +2869,16 @@ sock_accept_impl(PySocketSockObject *s, void *data)
#endif
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- if (accept4_works != 0) {
+ socket_state *state = s->state;
+ if (state->accept4_works != 0) {
ctx->result = accept4(s->sock_fd, addr, paddrlen,
SOCK_CLOEXEC);
- if (ctx->result == INVALID_SOCKET && accept4_works == -1) {
+ if (ctx->result == INVALID_SOCKET && state->accept4_works == -1) {
/* On Linux older than 2.6.28, accept4() fails with ENOSYS */
- accept4_works = (errno != ENOSYS);
+ state->accept4_works = (errno != ENOSYS);
}
}
- if (accept4_works == 0)
+ if (state->accept4_works == 0)
ctx->result = accept(s->sock_fd, addr, paddrlen);
#else
ctx->result = accept(s->sock_fd, addr, paddrlen);
@@ -2896,7 +2931,8 @@ sock_accept(PySocketSockObject *s, PyObject *Py_UNUSED(ignored))
#else
#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
- if (!accept4_works)
+ socket_state *state = s->state;
+ if (!state->accept4_works)
#endif
{
if (_Py_set_inheritable(newfd, 0, NULL) < 0) {
@@ -5219,13 +5255,23 @@ sock_finalize(PySocketSockObject *s)
PyErr_SetRaisedException(exc);
}
+static int
+sock_traverse(PySocketSockObject *s, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(s));
+ return 0;
+}
+
static void
sock_dealloc(PySocketSockObject *s)
{
- if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0)
+ if (PyObject_CallFinalizerFromDealloc((PyObject *)s) < 0) {
return;
-
- Py_TYPE(s)->tp_free((PyObject *)s);
+ }
+ PyTypeObject *tp = Py_TYPE(s);
+ PyObject_GC_UnTrack(s);
+ tp->tp_free((PyObject *)s);
+ Py_DECREF(tp);
}
@@ -5277,12 +5323,6 @@ sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
/* Initialize a new socket object. */
-#ifdef SOCK_CLOEXEC
-/* socket() and socketpair() fail with EINVAL on Linux kernel older
- * than 2.6.27 if SOCK_CLOEXEC flag is set in the socket type. */
-static int sock_cloexec_works = -1;
-#endif
-
/*ARGSUSED*/
#ifndef HAVE_SOCKET
@@ -5310,10 +5350,11 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
{
SOCKET_T fd = INVALID_SOCKET;
+ socket_state *state = find_module_state_by_def(Py_TYPE(self));
#ifndef MS_WINDOWS
#ifdef SOCK_CLOEXEC
- int *atomic_flag_works = &sock_cloexec_works;
+ int *atomic_flag_works = &state->sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@@ -5468,15 +5509,15 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
/* UNIX */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
- if (sock_cloexec_works != 0) {
+ if (state->sock_cloexec_works != 0) {
fd = socket(family, type | SOCK_CLOEXEC, proto);
- if (sock_cloexec_works == -1) {
+ if (state->sock_cloexec_works == -1) {
if (fd >= 0) {
- sock_cloexec_works = 1;
+ state->sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
- sock_cloexec_works = 0;
+ state->sock_cloexec_works = 0;
fd = socket(family, type, proto);
}
}
@@ -5499,7 +5540,7 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
}
#endif
}
- if (init_sockobject(self, fd, family, type, proto) == -1) {
+ if (init_sockobject(state, self, fd, family, type, proto) == -1) {
SOCKETCLOSE(fd);
return -1;
}
@@ -5511,55 +5552,26 @@ sock_initobj_impl(PySocketSockObject *self, int family, int type, int proto,
/* Type object for socket objects. */
-static PyTypeObject sock_type = {
- PyVarObject_HEAD_INIT(0, 0) /* Must fill in type value later */
- "_socket.socket", /* tp_name */
- sizeof(PySocketSockObject), /* tp_basicsize */
- 0, /* tp_itemsize */
- (destructor)sock_dealloc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- (reprfunc)sock_repr, /* tp_repr */
- 0, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- 0, /* tp_hash */
- 0, /* tp_call */
- 0, /* tp_str */
- PyObject_GenericGetAttr, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
- sock_doc, /* tp_doc */
- 0, /* tp_traverse */
- 0, /* tp_clear */
- 0, /* tp_richcompare */
- 0, /* tp_weaklistoffset */
- 0, /* tp_iter */
- 0, /* tp_iternext */
- sock_methods, /* tp_methods */
- sock_memberlist, /* tp_members */
- sock_getsetlist, /* tp_getset */
- 0, /* tp_base */
- 0, /* tp_dict */
- 0, /* tp_descr_get */
- 0, /* tp_descr_set */
- 0, /* tp_dictoffset */
- sock_initobj, /* tp_init */
- PyType_GenericAlloc, /* tp_alloc */
- sock_new, /* tp_new */
- PyObject_Del, /* tp_free */
- 0, /* tp_is_gc */
- 0, /* tp_bases */
- 0, /* tp_mro */
- 0, /* tp_cache */
- 0, /* tp_subclasses */
- 0, /* tp_weaklist */
- 0, /* tp_del */
- 0, /* tp_version_tag */
- (destructor)sock_finalize, /* tp_finalize */
+static PyType_Slot sock_slots[] = {
+ {Py_tp_dealloc, sock_dealloc},
+ {Py_tp_traverse, sock_traverse},
+ {Py_tp_repr, sock_repr},
+ {Py_tp_doc, (void *)sock_doc},
+ {Py_tp_methods, sock_methods},
+ {Py_tp_members, sock_memberlist},
+ {Py_tp_getset, sock_getsetlist},
+ {Py_tp_init, sock_initobj},
+ {Py_tp_new, sock_new},
+ {Py_tp_finalize, sock_finalize},
+ {0, NULL},
+};
+
+static PyType_Spec sock_spec = {
+ .name = "_socket.socket",
+ .basicsize = sizeof(PySocketSockObject),
+ .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC |
+ Py_TPFLAGS_IMMUTABLETYPE),
+ .slots = sock_slots,
};
@@ -5687,8 +5699,12 @@ socket_gethostbyname(PyObject *self, PyObject *args)
if (PySys_Audit("socket.gethostbyname", "O", args) < 0) {
goto finally;
}
- if (setipaddr(name, (struct sockaddr *)&addrbuf, sizeof(addrbuf), AF_INET) < 0)
+ socket_state *state = get_module_state(self);
+ int rc = setipaddr(state, name, (struct sockaddr *)&addrbuf,
+ sizeof(addrbuf), AF_INET);
+ if (rc < 0) {
goto finally;
+ }
ret = make_ipv4_addr(&addrbuf);
finally:
PyMem_Free(name);
@@ -5719,7 +5735,8 @@ sock_decode_hostname(const char *name)
/* Convenience function common to gethostbyname_ex and gethostbyaddr */
static PyObject *
-gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
+gethost_common(socket_state *state, struct hostent *h, struct sockaddr *addr,
+ size_t alen, int af)
{
char **pch;
PyObject *rtn_tuple = (PyObject *)NULL;
@@ -5730,7 +5747,7 @@ gethost_common(struct hostent *h, struct sockaddr *addr, size_t alen, int af)
if (h == NULL) {
/* Let's get real error message to return */
- set_herror(h_errno);
+ set_herror(state, h_errno);
return NULL;
}
@@ -5877,8 +5894,10 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
if (PySys_Audit("socket.gethostbyname", "O", args) < 0) {
goto finally;
}
- if (setipaddr(name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0)
+ socket_state *state = get_module_state(self);
+ if (setipaddr(state, name, SAS2SA(&addr), sizeof(addr), AF_INET) < 0) {
goto finally;
+ }
Py_BEGIN_ALLOW_THREADS
#ifdef HAVE_GETHOSTBYNAME_R
#if defined(HAVE_GETHOSTBYNAME_R_6_ARG)
@@ -5904,7 +5923,7 @@ socket_gethostbyname_ex(PyObject *self, PyObject *args)
Therefore, we cast the sockaddr_storage into sockaddr to
access sa_family. */
sa = SAS2SA(&addr);
- ret = gethost_common(h, SAS2SA(&addr), sizeof(addr),
+ ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr),
sa->sa_family);
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(netdb_lock);
@@ -5960,8 +5979,10 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
goto finally;
}
af = AF_UNSPEC;
- if (setipaddr(ip_num, sa, sizeof(addr), af) < 0)
+ socket_state *state = get_module_state(self);
+ if (setipaddr(state, ip_num, sa, sizeof(addr), af) < 0) {
goto finally;
+ }
af = sa->sa_family;
ap = NULL;
/* al = 0; */
@@ -6002,7 +6023,7 @@ socket_gethostbyaddr(PyObject *self, PyObject *args)
h = gethostbyaddr(ap, al, af);
#endif /* HAVE_GETHOSTBYNAME_R */
Py_END_ALLOW_THREADS
- ret = gethost_common(h, SAS2SA(&addr), sizeof(addr), af);
+ ret = gethost_common(state, h, SAS2SA(&addr), sizeof(addr), af);
#ifdef USE_GETHOSTBYNAME_LOCK
PyThread_release_lock(netdb_lock);
#endif
@@ -6221,8 +6242,9 @@ socket_socketpair(PyObject *self, PyObject *args)
SOCKET_T sv[2];
int family, type = SOCK_STREAM, proto = 0;
PyObject *res = NULL;
+ socket_state *state = get_module_state(self);
#ifdef SOCK_CLOEXEC
- int *atomic_flag_works = &sock_cloexec_works;
+ int *atomic_flag_works = &state->sock_cloexec_works;
#else
int *atomic_flag_works = NULL;
#endif
@@ -6240,15 +6262,15 @@ socket_socketpair(PyObject *self, PyObject *args)
/* Create a pair of socket fds */
Py_BEGIN_ALLOW_THREADS
#ifdef SOCK_CLOEXEC
- if (sock_cloexec_works != 0) {
+ if (state->sock_cloexec_works != 0) {
ret = socketpair(family, type | SOCK_CLOEXEC, proto, sv);
- if (sock_cloexec_works == -1) {
+ if (state->sock_cloexec_works == -1) {
if (ret >= 0) {
- sock_cloexec_works = 1;
+ state->sock_cloexec_works = 1;
}
else if (errno == EINVAL) {
/* Linux older than 2.6.27 does not support SOCK_CLOEXEC */
- sock_cloexec_works = 0;
+ state->sock_cloexec_works = 0;
ret = socketpair(family, type, proto, sv);
}
}
@@ -6268,10 +6290,10 @@ socket_socketpair(PyObject *self, PyObject *args)
if (_Py_set_inheritable(sv[1], 0, atomic_flag_works) < 0)
goto finally;
- s0 = new_sockobject(sv[0], family, type, proto);
+ s0 = new_sockobject(state, sv[0], family, type, proto);
if (s0 == NULL)
goto finally;
- s1 = new_sockobject(sv[1], family, type, proto);
+ s1 = new_sockobject(state, sv[1], family, type, proto);
if (s1 == NULL)
goto finally;
res = PyTuple_Pack(2, s0, s1);
@@ -6726,7 +6748,8 @@ socket_getaddrinfo(PyObject *self, PyObject *args, PyObject* kwargs)
Py_END_ALLOW_THREADS
if (error) {
res0 = NULL; // gh-100795
- set_gaierror(error);
+ socket_state *state = get_module_state(self);
+ set_gaierror(state, error);
goto err;
}
@@ -6825,7 +6848,8 @@ socket_getnameinfo(PyObject *self, PyObject *args)
Py_END_ALLOW_THREADS
if (error) {
res = NULL; // gh-100795
- set_gaierror(error);
+ socket_state *state = get_module_state(self);
+ set_gaierror(state, error);
goto fail;
}
if (res->ai_next) {
@@ -6857,7 +6881,8 @@ socket_getnameinfo(PyObject *self, PyObject *args)
error = getnameinfo(res->ai_addr, (socklen_t) res->ai_addrlen,
hbuf, sizeof(hbuf), pbuf, sizeof(pbuf), flags);
if (error) {
- set_gaierror(error);
+ socket_state *state = get_module_state(self);
+ set_gaierror(state, error);
goto fail;
}
@@ -6883,11 +6908,12 @@ Get host and port for a sockaddr.");
static PyObject *
socket_getdefaulttimeout(PyObject *self, PyObject *Py_UNUSED(ignored))
{
- if (defaulttimeout < 0) {
+ socket_state *state = get_module_state(self);
+ if (state->defaulttimeout < 0) {
Py_RETURN_NONE;
}
else {
- double seconds = _PyTime_AsSecondsDouble(defaulttimeout);
+ double seconds = _PyTime_AsSecondsDouble(state->defaulttimeout);
return PyFloat_FromDouble(seconds);
}
}
@@ -6907,7 +6933,8 @@ socket_setdefaulttimeout(PyObject *self, PyObject *arg)
if (socket_parse_timeout(&timeout, arg) < 0)
return NULL;
- defaulttimeout = timeout;
+ socket_state *state = get_module_state(self);
+ state->defaulttimeout = timeout;
Py_RETURN_NONE;
}
@@ -7293,7 +7320,7 @@ sock_destroy_api(PyObject *capsule)
}
static PySocketModule_APIObject *
-sock_get_api(void)
+sock_get_api(socket_state *state)
{
PySocketModule_APIObject *capi = PyMem_Malloc(sizeof(PySocketModule_APIObject));
if (capi == NULL) {
@@ -7301,7 +7328,7 @@ sock_get_api(void)
return NULL;
}
- capi->Sock_Type = (PyTypeObject *)Py_NewRef(&sock_type);
+ capi->Sock_Type = (PyTypeObject *)Py_NewRef(state->sock_type);
capi->error = Py_NewRef(PyExc_OSError);
capi->timeout_error = Py_NewRef(PyExc_TimeoutError);
return capi;
@@ -7323,47 +7350,38 @@ PyDoc_STRVAR(socket_doc,
\n\
See the socket module for documentation.");
-static struct PyModuleDef socketmodule = {
- PyModuleDef_HEAD_INIT,
- PySocket_MODULE_NAME,
- socket_doc,
- -1,
- socket_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-PyMODINIT_FUNC
-PyInit__socket(void)
+static int
+socket_exec(PyObject *m)
{
- PyObject *m = NULL;
-
if (!os_init()) {
goto error;
}
- Py_SET_TYPE(&sock_type, &PyType_Type);
- m = PyModule_Create(&socketmodule);
- if (m == NULL) {
- goto error;
- }
+ socket_state *state = get_module_state(m);
+ state->defaulttimeout = _PYTIME_FROMSECONDS(-1);
+
+#if defined(HAVE_ACCEPT) || defined(HAVE_ACCEPT4)
+#if defined(HAVE_ACCEPT4) && defined(SOCK_CLOEXEC)
+ state->accept4_works = -1;
+#endif
+#endif
+
+#ifdef SOCK_CLOEXEC
+ state->sock_cloexec_works = -1;
+#endif
#define ADD_EXC(MOD, NAME, VAR, BASE) do { \
VAR = PyErr_NewException("socket." NAME, BASE, NULL); \
if (VAR == NULL) { \
goto error; \
} \
- int rc = PyModule_AddObjectRef(MOD, NAME, VAR); \
- Py_DECREF(VAR); \
- if (rc < 0) { \
+ if (PyModule_AddObjectRef(MOD, NAME, VAR) < 0) { \
goto error; \
} \
} while (0)
- ADD_EXC(m, "herror", socket_herror, PyExc_OSError);
- ADD_EXC(m, "gaierror", socket_gaierror, PyExc_OSError);
+ ADD_EXC(m, "herror", state->socket_herror, PyExc_OSError);
+ ADD_EXC(m, "gaierror", state->socket_gaierror, PyExc_OSError);
#undef ADD_EXC
@@ -7373,10 +7391,16 @@ PyInit__socket(void)
if (PyModule_AddObjectRef(m, "timeout", PyExc_TimeoutError) < 0) {
goto error;
}
- if (PyModule_AddObjectRef(m, "SocketType", (PyObject *)&sock_type) < 0) {
+
+ PyObject *sock_type = PyType_FromMetaclass(NULL, m, &sock_spec, NULL);
+ if (sock_type == NULL) {
+ goto error;
+ }
+ state->sock_type = (PyTypeObject *)sock_type;
+ if (PyModule_AddObjectRef(m, "SocketType", sock_type) < 0) {
goto error;
}
- if (PyModule_AddType(m, &sock_type) < 0) {
+ if (PyModule_AddType(m, state->sock_type) < 0) {
goto error;
}
@@ -7391,7 +7415,7 @@ PyInit__socket(void)
}
/* Export C API */
- PySocketModule_APIObject *capi = sock_get_api();
+ PySocketModule_APIObject *capi = sock_get_api(state);
if (capi == NULL) {
goto error;
}
@@ -8813,9 +8837,57 @@ PyInit__socket(void)
#undef ADD_INT_CONST
#undef ADD_STR_CONST
- return m;
+ return 0;
error:
- Py_XDECREF(m);
- return NULL;
+ return -1;
+}
+
+static struct PyModuleDef_Slot socket_slots[] = {
+ {Py_mod_exec, socket_exec},
+ {0, NULL},
+};
+
+static int
+socket_traverse(PyObject *mod, visitproc visit, void *arg)
+{
+ socket_state *state = get_module_state(mod);
+ Py_VISIT(state->sock_type);
+ Py_VISIT(state->socket_herror);
+ Py_VISIT(state->socket_gaierror);
+ return 0;
+}
+
+static int
+socket_clear(PyObject *mod)
+{
+ socket_state *state = get_module_state(mod);
+ Py_CLEAR(state->sock_type);
+ Py_CLEAR(state->socket_herror);
+ Py_CLEAR(state->socket_gaierror);
+ return 0;
+}
+
+static void
+socket_free(void *mod)
+{
+ (void)socket_clear((PyObject *)mod);
+}
+
+static struct PyModuleDef socketmodule = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = PySocket_MODULE_NAME,
+ .m_doc = socket_doc,
+ .m_size = sizeof(socket_state),
+ .m_methods = socket_methods,
+ .m_slots = socket_slots,
+ .m_traverse = socket_traverse,
+ .m_clear = socket_clear,
+ .m_free = socket_free,
+};
+
+PyMODINIT_FUNC
+PyInit__socket(void)
+{
+ return PyModuleDef_Init(&socketmodule);
}
diff --git a/Modules/socketmodule.h b/Modules/socketmodule.h
index f31ba532a6c60d..f5ca00450ee92a 100644
--- a/Modules/socketmodule.h
+++ b/Modules/socketmodule.h
@@ -322,6 +322,7 @@ typedef struct {
sets a Python exception */
_PyTime_t sock_timeout; /* Operation timeout in seconds;
0.0 means non-blocking */
+ struct _socket_state *state;
} PySocketSockObject;
/* --- C API ----------------------------------------------------*/
diff --git a/Modules/tkappinit.c b/Modules/tkappinit.c
index 7616d9d319d228..67d6250318c616 100644
--- a/Modules/tkappinit.c
+++ b/Modules/tkappinit.c
@@ -18,18 +18,10 @@
#include "tkinter.h"
-#ifdef TKINTER_PROTECT_LOADTK
-/* See Tkapp_TkInit in _tkinter.c for the usage of tk_load_faile */
-static int tk_load_failed;
-#endif
-
int
Tcl_AppInit(Tcl_Interp *interp)
{
const char *_tkinter_skip_tk_init;
-#ifdef TKINTER_PROTECT_LOADTK
- const char *_tkinter_tk_failed;
-#endif
#ifdef TK_AQUA
#ifndef MAX_PATH_LEN
@@ -90,23 +82,7 @@ Tcl_AppInit(Tcl_Interp *interp)
return TCL_OK;
}
-#ifdef TKINTER_PROTECT_LOADTK
- _tkinter_tk_failed = Tcl_GetVar(interp,
- "_tkinter_tk_failed", TCL_GLOBAL_ONLY);
-
- if (tk_load_failed || (
- _tkinter_tk_failed != NULL &&
- strcmp(_tkinter_tk_failed, "1") == 0)) {
- Tcl_SetResult(interp, TKINTER_LOADTK_ERRMSG, TCL_STATIC);
- return TCL_ERROR;
- }
-#endif
-
if (Tk_Init(interp) == TCL_ERROR) {
-#ifdef TKINTER_PROTECT_LOADTK
- tk_load_failed = 1;
- Tcl_SetVar(interp, "_tkinter_tk_failed", "1", TCL_GLOBAL_ONLY);
-#endif
return TCL_ERROR;
}
diff --git a/Modules/tkinter.h b/Modules/tkinter.h
index cb5a806b0c4326..40281c21760331 100644
--- a/Modules/tkinter.h
+++ b/Modules/tkinter.h
@@ -16,12 +16,4 @@
(TK_RELEASE_LEVEL << 8) | \
(TK_RELEASE_SERIAL << 0))
-/* Protect Tk 8.4.13 and older from a deadlock that happens when trying
- * to load tk after a failed attempt. */
-#if TK_HEX_VERSION < 0x0804020e
-#define TKINTER_PROTECT_LOADTK
-#define TKINTER_LOADTK_ERRMSG \
- "Calling Tk_Init again after a previous call failed might deadlock"
-#endif
-
#endif /* !TKINTER_H */
diff --git a/Objects/boolobject.c b/Objects/boolobject.c
index 9d8e956e06f712..597a76fa5cb162 100644
--- a/Objects/boolobject.c
+++ b/Objects/boolobject.c
@@ -145,10 +145,14 @@ static PyNumberMethods bool_as_number = {
0, /* nb_index */
};
-static void _Py_NO_RETURN
-bool_dealloc(PyObject* Py_UNUSED(ignore))
+static void
+bool_dealloc(PyObject *boolean)
{
- _Py_FatalRefcountError("deallocating True or False");
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref Booleans out of existence. Instead,
+ * since bools are immortal, re-set the reference count.
+ */
+ _Py_SetImmortal(boolean);
}
/* The type object for bool. Note that this cannot be subclassed! */
diff --git a/Objects/bytes_methods.c b/Objects/bytes_methods.c
index ef9e65e566ece9..33aa9c3db6e805 100644
--- a/Objects/bytes_methods.c
+++ b/Objects/bytes_methods.c
@@ -258,9 +258,12 @@ _Py_bytes_istitle(const char *cptr, Py_ssize_t len)
const unsigned char *e;
int cased, previous_is_cased;
- /* Shortcut for single character strings */
- if (len == 1)
- return PyBool_FromLong(Py_ISUPPER(*p));
+ if (len == 1) {
+ if (Py_ISUPPER(*p)) {
+ Py_RETURN_TRUE;
+ }
+ Py_RETURN_FALSE;
+ }
/* Special case for empty strings */
if (len == 0)
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 755d0b85e7cf30..9b54c610581174 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -431,13 +431,13 @@ init_code(PyCodeObject *co, struct _PyCodeConstructor *con)
if (_Py_next_func_version != 0) {
_Py_next_func_version++;
}
+ co->_co_monitoring = NULL;
+ co->_co_instrumentation_version = 0;
/* not set */
co->co_weakreflist = NULL;
co->co_extra = NULL;
co->_co_cached = NULL;
- co->_co_linearray_entry_size = 0;
- co->_co_linearray = NULL;
memcpy(_PyCode_CODE(co), PyBytes_AS_STRING(con->code),
PyBytes_GET_SIZE(con->code));
int entry_point = 0;
@@ -816,54 +816,6 @@ PyCode_NewEmpty(const char *filename, const char *funcname, int firstlineno)
* source location tracking (co_lines/co_positions)
******************/
-/* Use co_linetable to compute the line number from a bytecode index, addrq. See
- lnotab_notes.txt for the details of the lnotab representation.
-*/
-
-int
-_PyCode_CreateLineArray(PyCodeObject *co)
-{
- assert(co->_co_linearray == NULL);
- PyCodeAddressRange bounds;
- int size;
- int max_line = 0;
- _PyCode_InitAddressRange(co, &bounds);
- while(_PyLineTable_NextAddressRange(&bounds)) {
- if (bounds.ar_line > max_line) {
- max_line = bounds.ar_line;
- }
- }
- if (max_line < (1 << 15)) {
- size = 2;
- }
- else {
- size = 4;
- }
- co->_co_linearray = PyMem_Malloc(Py_SIZE(co)*size);
- if (co->_co_linearray == NULL) {
- PyErr_NoMemory();
- return -1;
- }
- co->_co_linearray_entry_size = size;
- _PyCode_InitAddressRange(co, &bounds);
- while(_PyLineTable_NextAddressRange(&bounds)) {
- int start = bounds.ar_start / sizeof(_Py_CODEUNIT);
- int end = bounds.ar_end / sizeof(_Py_CODEUNIT);
- for (int index = start; index < end; index++) {
- assert(index < (int)Py_SIZE(co));
- if (size == 2) {
- assert(((int16_t)bounds.ar_line) == bounds.ar_line);
- ((int16_t *)co->_co_linearray)[index] = bounds.ar_line;
- }
- else {
- assert(size == 4);
- ((int32_t *)co->_co_linearray)[index] = bounds.ar_line;
- }
- }
- }
- return 0;
-}
-
int
PyCode_Addr2Line(PyCodeObject *co, int addrq)
{
@@ -871,9 +823,6 @@ PyCode_Addr2Line(PyCodeObject *co, int addrq)
return co->co_firstlineno;
}
assert(addrq >= 0 && addrq < _PyCode_NBYTES(co));
- if (co->_co_linearray) {
- return _PyCode_LineNumberFromArray(co, addrq / sizeof(_Py_CODEUNIT));
- }
PyCodeAddressRange bounds;
_PyCode_InitAddressRange(co, &bounds);
return _PyCode_CheckLineNumber(addrq, &bounds);
@@ -1531,17 +1480,17 @@ PyCode_GetFreevars(PyCodeObject *code)
}
static void
-deopt_code(_Py_CODEUNIT *instructions, Py_ssize_t len)
+deopt_code(PyCodeObject *code, _Py_CODEUNIT *instructions)
{
+ Py_ssize_t len = Py_SIZE(code);
for (int i = 0; i < len; i++) {
- _Py_CODEUNIT instruction = instructions[i];
- int opcode = _PyOpcode_Deopt[instruction.op.code];
+ int opcode = _Py_GetBaseOpcode(code, i);
int caches = _PyOpcode_Caches[opcode];
instructions[i].op.code = opcode;
- while (caches--) {
- instructions[++i].op.code = CACHE;
- instructions[i].op.arg = 0;
+ for (int j = 1; j <= caches; j++) {
+ instructions[i+j].cache = 0;
}
+ i += caches;
}
}
@@ -1559,7 +1508,7 @@ _PyCode_GetCode(PyCodeObject *co)
if (code == NULL) {
return NULL;
}
- deopt_code((_Py_CODEUNIT *)PyBytes_AS_STRING(code), Py_SIZE(co));
+ deopt_code(co, (_Py_CODEUNIT *)PyBytes_AS_STRING(code));
assert(co->_co_cached->_co_code == NULL);
co->_co_cached->_co_code = Py_NewRef(code);
return code;
@@ -1693,6 +1642,30 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount,
return co;
}
+static void
+free_monitoring_data(_PyCoMonitoringData *data)
+{
+ if (data == NULL) {
+ return;
+ }
+ if (data->tools) {
+ PyMem_Free(data->tools);
+ }
+ if (data->lines) {
+ PyMem_Free(data->lines);
+ }
+ if (data->line_tools) {
+ PyMem_Free(data->line_tools);
+ }
+ if (data->per_instruction_opcodes) {
+ PyMem_Free(data->per_instruction_opcodes);
+ }
+ if (data->per_instruction_tools) {
+ PyMem_Free(data->per_instruction_tools);
+ }
+ PyMem_Free(data);
+}
+
static void
code_dealloc(PyCodeObject *co)
{
@@ -1739,9 +1712,7 @@ code_dealloc(PyCodeObject *co)
if (co->co_weakreflist != NULL) {
PyObject_ClearWeakRefs((PyObject*)co);
}
- if (co->_co_linearray) {
- PyMem_Free(co->_co_linearray);
- }
+ free_monitoring_data(co->_co_monitoring);
PyObject_Free(co);
}
@@ -1885,7 +1856,7 @@ code_hash(PyCodeObject *co)
SCRAMBLE_IN(co->co_firstlineno);
SCRAMBLE_IN(Py_SIZE(co));
for (int i = 0; i < Py_SIZE(co); i++) {
- int deop = _PyOpcode_Deopt[_PyCode_CODE(co)[i].op.code];
+ int deop = _Py_GetBaseOpcode(co, i);
SCRAMBLE_IN(deop);
SCRAMBLE_IN(_PyCode_CODE(co)[i].op.arg);
i += _PyOpcode_Caches[deop];
@@ -2314,7 +2285,7 @@ _PyCode_ConstantKey(PyObject *op)
void
_PyStaticCode_Fini(PyCodeObject *co)
{
- deopt_code(_PyCode_CODE(co), Py_SIZE(co));
+ deopt_code(co, _PyCode_CODE(co));
PyMem_Free(co->co_extra);
if (co->_co_cached != NULL) {
Py_CLEAR(co->_co_cached->_co_code);
@@ -2329,10 +2300,8 @@ _PyStaticCode_Fini(PyCodeObject *co)
PyObject_ClearWeakRefs((PyObject *)co);
co->co_weakreflist = NULL;
}
- if (co->_co_linearray) {
- PyMem_Free(co->_co_linearray);
- co->_co_linearray = NULL;
- }
+ free_monitoring_data(co->_co_monitoring);
+ co->_co_monitoring = NULL;
}
int
diff --git a/Objects/frameobject.c b/Objects/frameobject.c
index 63590d58809e3e..ef0070199ab2c0 100644
--- a/Objects/frameobject.c
+++ b/Objects/frameobject.c
@@ -17,7 +17,6 @@
static PyMemberDef frame_memberlist[] = {
{"f_trace_lines", T_BOOL, OFF(f_trace_lines), 0},
- {"f_trace_opcodes", T_BOOL, OFF(f_trace_opcodes), 0},
{NULL} /* Sentinel */
};
@@ -104,24 +103,29 @@ frame_getback(PyFrameObject *f, void *closure)
return res;
}
-// Given the index of the effective opcode, scan back to construct the oparg
-// with EXTENDED_ARG. This only works correctly with *unquickened* code,
-// obtained via a call to _PyCode_GetCode!
-static unsigned int
-get_arg(const _Py_CODEUNIT *codestr, Py_ssize_t i)
+static PyObject *
+frame_gettrace_opcodes(PyFrameObject *f, void *closure)
{
- _Py_CODEUNIT word;
- unsigned int oparg = codestr[i].op.arg;
- if (i >= 1 && (word = codestr[i-1]).op.code == EXTENDED_ARG) {
- oparg |= word.op.arg << 8;
- if (i >= 2 && (word = codestr[i-2]).op.code == EXTENDED_ARG) {
- oparg |= word.op.arg << 16;
- if (i >= 3 && (word = codestr[i-3]).op.code == EXTENDED_ARG) {
- oparg |= word.op.arg << 24;
- }
- }
+ PyObject *result = f->f_trace_opcodes ? Py_True : Py_False;
+ return Py_NewRef(result);
+}
+
+static int
+frame_settrace_opcodes(PyFrameObject *f, PyObject* value, void *Py_UNUSED(ignored))
+{
+ if (!PyBool_Check(value)) {
+ PyErr_SetString(PyExc_TypeError,
+ "attribute value type must be bool");
+ return -1;
+ }
+ if (value == Py_True) {
+ f->f_trace_opcodes = 1;
+ _PyInterpreterState_GET()->f_opcode_trace_set = true;
}
- return oparg;
+ else {
+ f->f_trace_opcodes = 0;
+ }
+ return 0;
}
/* Model the evaluation stack, to determine which jumps
@@ -299,46 +303,52 @@ mark_stacks(PyCodeObject *code_obj, int len)
while (todo) {
todo = 0;
/* Scan instructions */
- for (i = 0; i < len; i++) {
+ for (i = 0; i < len;) {
int64_t next_stack = stacks[i];
+ opcode = _Py_GetBaseOpcode(code_obj, i);
+ int oparg = 0;
+ while (opcode == EXTENDED_ARG) {
+ oparg = (oparg << 8) | code[i].op.arg;
+ i++;
+ opcode = _Py_GetBaseOpcode(code_obj, i);
+ stacks[i] = next_stack;
+ }
+ int next_i = i + _PyOpcode_Caches[opcode] + 1;
if (next_stack == UNINITIALIZED) {
+ i = next_i;
continue;
}
- opcode = code[i].op.code;
+ oparg = (oparg << 8) | code[i].op.arg;
switch (opcode) {
case POP_JUMP_IF_FALSE:
case POP_JUMP_IF_TRUE:
{
int64_t target_stack;
- int j = get_arg(code, i);
- j += i + 1;
+ int j = next_i + oparg;
assert(j < len);
- if (stacks[j] == UNINITIALIZED && j < i) {
- todo = 1;
- }
next_stack = pop_value(next_stack);
target_stack = next_stack;
assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack);
stacks[j] = target_stack;
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
case SEND:
- j = get_arg(code, i) + i + INLINE_CACHE_ENTRIES_SEND + 1;
+ j = oparg + i + INLINE_CACHE_ENTRIES_SEND + 1;
assert(j < len);
assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
stacks[j] = next_stack;
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case JUMP_FORWARD:
- j = get_arg(code, i) + i + 1;
+ j = oparg + i + 1;
assert(j < len);
assert(stacks[j] == UNINITIALIZED || stacks[j] == next_stack);
stacks[j] = next_stack;
break;
case JUMP_BACKWARD:
case JUMP_BACKWARD_NO_INTERRUPT:
- j = i + 1 - get_arg(code, i);
+ j = i + 1 - oparg;
assert(j >= 0);
assert(j < len);
if (stacks[j] == UNINITIALIZED && j < i) {
@@ -350,13 +360,13 @@ mark_stacks(PyCodeObject *code_obj, int len)
case GET_ITER:
case GET_AITER:
next_stack = push_value(pop_value(next_stack), Iterator);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case FOR_ITER:
{
int64_t target_stack = push_value(next_stack, Object);
- stacks[i+1] = target_stack;
- j = get_arg(code, i) + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + i;
+ stacks[next_i] = target_stack;
+ j = oparg + 1 + INLINE_CACHE_ENTRIES_FOR_ITER + i;
assert(j < len);
assert(stacks[j] == UNINITIALIZED || stacks[j] == target_stack);
stacks[j] = target_stack;
@@ -364,16 +374,16 @@ mark_stacks(PyCodeObject *code_obj, int len)
}
case END_ASYNC_FOR:
next_stack = pop_value(pop_value(next_stack));
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case PUSH_EXC_INFO:
next_stack = push_value(next_stack, Except);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case POP_EXCEPT:
assert(top_of_stack(next_stack) == Except);
next_stack = pop_value(next_stack);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case RETURN_VALUE:
assert(pop_value(next_stack) == EMPTY_STACK);
@@ -389,57 +399,62 @@ mark_stacks(PyCodeObject *code_obj, int len)
break;
case PUSH_NULL:
next_stack = push_value(next_stack, Null);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
case LOAD_GLOBAL:
{
- int j = get_arg(code, i);
+ int j = oparg;
if (j & 1) {
next_stack = push_value(next_stack, Null);
}
next_stack = push_value(next_stack, Object);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
case LOAD_ATTR:
{
assert(top_of_stack(next_stack) == Object);
- int j = get_arg(code, i);
+ int j = oparg;
if (j & 1) {
next_stack = pop_value(next_stack);
next_stack = push_value(next_stack, Null);
next_stack = push_value(next_stack, Object);
}
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
case CALL:
{
- int args = get_arg(code, i);
+ int args = oparg;
for (int j = 0; j < args+2; j++) {
next_stack = pop_value(next_stack);
}
next_stack = push_value(next_stack, Object);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
case SWAP:
{
- int n = get_arg(code, i);
+ int n = oparg;
next_stack = stack_swap(next_stack, n);
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
case COPY:
{
- int n = get_arg(code, i);
+ int n = oparg;
next_stack = push_value(next_stack, peek(next_stack, n));
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
break;
}
+ case CACHE:
+ case RESERVED:
+ {
+ assert(0);
+ }
default:
{
- int delta = PyCompile_OpcodeStackEffect(opcode, get_arg(code, i));
+ int delta = PyCompile_OpcodeStackEffect(opcode, oparg);
assert(delta != PY_INVALID_STACK_EFFECT);
while (delta < 0) {
next_stack = pop_value(next_stack);
@@ -449,9 +464,10 @@ mark_stacks(PyCodeObject *code_obj, int len)
next_stack = push_value(next_stack, Object);
delta--;
}
- stacks[i+1] = next_stack;
+ stacks[next_i] = next_stack;
}
}
+ i = next_i;
}
/* Scan exception table */
unsigned char *start = (unsigned char *)PyBytes_AS_STRING(code_obj->co_exceptiontable);
@@ -646,31 +662,43 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
* In addition, jumps are forbidden when not tracing,
* as this is a debugging feature.
*/
- switch(PyThreadState_GET()->tracing_what) {
- case PyTrace_EXCEPTION:
- PyErr_SetString(PyExc_ValueError,
- "can only jump from a 'line' trace event");
- return -1;
- case PyTrace_CALL:
+ int what_event = PyThreadState_GET()->what_event;
+ if (what_event < 0) {
+ PyErr_Format(PyExc_ValueError,
+ "f_lineno can only be set in a trace function");
+ return -1;
+ }
+ switch (what_event) {
+ case PY_MONITORING_EVENT_PY_RESUME:
+ case PY_MONITORING_EVENT_JUMP:
+ case PY_MONITORING_EVENT_BRANCH:
+ case PY_MONITORING_EVENT_LINE:
+ case PY_MONITORING_EVENT_PY_YIELD:
+ /* Setting f_lineno is allowed for the above events */
+ break;
+ case PY_MONITORING_EVENT_PY_START:
PyErr_Format(PyExc_ValueError,
"can't jump from the 'call' trace event of a new frame");
return -1;
- case PyTrace_LINE:
- break;
- case PyTrace_RETURN:
- if (state == FRAME_SUSPENDED) {
- break;
- }
- /* fall through */
- default:
+ case PY_MONITORING_EVENT_CALL:
+ case PY_MONITORING_EVENT_C_RETURN:
PyErr_SetString(PyExc_ValueError,
+ "can't jump during a call");
+ return -1;
+ case PY_MONITORING_EVENT_PY_RETURN:
+ case PY_MONITORING_EVENT_PY_UNWIND:
+ case PY_MONITORING_EVENT_PY_THROW:
+ case PY_MONITORING_EVENT_RAISE:
+ case PY_MONITORING_EVENT_C_RAISE:
+ case PY_MONITORING_EVENT_INSTRUCTION:
+ case PY_MONITORING_EVENT_EXCEPTION_HANDLED:
+ PyErr_Format(PyExc_ValueError,
"can only jump from a 'line' trace event");
return -1;
- }
- if (!f->f_trace) {
- PyErr_Format(PyExc_ValueError,
- "f_lineno can only be set by a trace function");
- return -1;
+ default:
+ PyErr_SetString(PyExc_SystemError,
+ "unexpected event type");
+ return -1;
}
int new_lineno;
@@ -803,6 +831,7 @@ frame_setlineno(PyFrameObject *f, PyObject* p_new_lineno, void *Py_UNUSED(ignore
start_stack = pop_value(start_stack);
}
/* Finally set the new lasti and return OK. */
+ f->f_last_traced_line = new_lineno;
f->f_lineno = 0;
f->f_frame->prev_instr = _PyCode_CODE(f->f_frame->f_code) + best_addr;
return 0;
@@ -823,7 +852,10 @@ frame_settrace(PyFrameObject *f, PyObject* v, void *closure)
if (v == Py_None) {
v = NULL;
}
- Py_XSETREF(f->f_trace, Py_XNewRef(v));
+ if (v != f->f_trace) {
+ Py_XSETREF(f->f_trace, Py_XNewRef(v));
+ f->f_last_traced_line = -1;
+ }
return 0;
}
@@ -838,6 +870,7 @@ static PyGetSetDef frame_getsetlist[] = {
{"f_globals", (getter)frame_getglobals, NULL, NULL},
{"f_builtins", (getter)frame_getbuiltins, NULL, NULL},
{"f_code", (getter)frame_getcode, NULL, NULL},
+ {"f_trace_opcodes", (getter)frame_gettrace_opcodes, (setter)frame_settrace_opcodes, NULL},
{0}
};
@@ -1023,6 +1056,7 @@ _PyFrame_New_NoTrack(PyCodeObject *code)
f->f_trace_opcodes = 0;
f->f_fast_as_locals = 0;
f->f_lineno = 0;
+ f->f_last_traced_line = -1;
return f;
}
diff --git a/Objects/funcobject.c b/Objects/funcobject.c
index 3047ec8884cd32..0a0e2bbb5caa24 100644
--- a/Objects/funcobject.c
+++ b/Objects/funcobject.c
@@ -959,7 +959,7 @@ functools_wraps(PyObject *wrapper, PyObject *wrapped)
class C:
@classmethod
- def f(cls, arg1, arg2, ...):
+ def f(cls, arg1, arg2, argN):
...
It can be called either on the class (e.g. C.f()) or on an instance
@@ -1083,7 +1083,7 @@ To declare a class method, use this idiom:\n\
\n\
class C:\n\
@classmethod\n\
- def f(cls, arg1, arg2, ...):\n\
+ def f(cls, arg1, arg2, argN):\n\
...\n\
\n\
It can be called either on the class (e.g. C.f()) or on an instance\n\
@@ -1155,7 +1155,7 @@ PyClassMethod_New(PyObject *callable)
class C:
@staticmethod
- def f(arg1, arg2, ...):
+ def f(arg1, arg2, argN):
...
It can be called either on the class (e.g. C.f()) or on an instance
@@ -1277,7 +1277,7 @@ To declare a static method, use this idiom:\n\
\n\
class C:\n\
@staticmethod\n\
- def f(arg1, arg2, ...):\n\
+ def f(arg1, arg2, argN):\n\
...\n\
\n\
It can be called either on the class (e.g. C.f()) or on an instance\n\
diff --git a/Objects/longobject.c b/Objects/longobject.c
index bb4eac0d932bb8..d98bbbb6d6ff46 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -52,8 +52,7 @@ static PyObject *
get_small_int(sdigit ival)
{
assert(IS_SMALL_INT(ival));
- PyObject *v = (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival];
- return Py_NewRef(v);
+ return (PyObject *)&_PyLong_SMALL_INTS[_PY_NSMALLNEGINTS + ival];
}
static PyLongObject *
@@ -3271,6 +3270,27 @@ long_richcompare(PyObject *self, PyObject *other, int op)
Py_RETURN_RICHCOMPARE(result, 0, op);
}
+static void
+long_dealloc(PyObject *self)
+{
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref small Ints out of existence. Instead,
+ * since small Ints are immortal, re-set the reference count.
+ */
+ PyLongObject *pylong = (PyLongObject*)self;
+ if (pylong && _PyLong_IsCompact(pylong)) {
+ stwodigits ival = medium_value(pylong);
+ if (IS_SMALL_INT(ival)) {
+ PyLongObject *small_pylong = (PyLongObject *)get_small_int((sdigit)ival);
+ if (pylong == small_pylong) {
+ _Py_SetImmortal(self);
+ return;
+ }
+ }
+ }
+ Py_TYPE(self)->tp_free(self);
+}
+
static Py_hash_t
long_hash(PyLongObject *v)
{
@@ -6233,7 +6253,7 @@ PyTypeObject PyLong_Type = {
"int", /* tp_name */
offsetof(PyLongObject, long_value.ob_digit), /* tp_basicsize */
sizeof(digit), /* tp_itemsize */
- 0, /* tp_dealloc */
+ long_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index 1d6cc3b508448d..34cc797b404cda 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -2642,7 +2642,11 @@ static Py_ssize_t
memory_length(PyMemoryViewObject *self)
{
CHECK_RELEASED_INT(self);
- return self->view.ndim == 0 ? 1 : self->view.shape[0];
+ if (self->view.ndim == 0) {
+ PyErr_SetString(PyExc_TypeError, "0-dim memory has no length");
+ return -1;
+ }
+ return self->view.shape[0];
}
/* As mapping */
diff --git a/Objects/object.c b/Objects/object.c
index 71f098eed37f51..65c296e9340601 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -145,7 +145,7 @@ _PyDebug_PrintTotalRefs(void) {
_PyRuntimeState *runtime = &_PyRuntime;
fprintf(stderr,
"[%zd refs, %zd blocks]\n",
- get_global_reftotal(runtime), _Py_GetAllocatedBlocks());
+ get_global_reftotal(runtime), _Py_GetGlobalAllocatedBlocks());
/* It may be helpful to also print the "legacy" reftotal separately.
Likewise for the total for each interpreter. */
}
@@ -1033,7 +1033,7 @@ PyObject_GetAttr(PyObject *v, PyObject *name)
}
else {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
}
@@ -1353,7 +1353,7 @@ _PyObject_GetMethod(PyObject *obj, PyObject *name, PyObject **method)
}
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
set_attribute_error_context(obj, name);
@@ -1474,7 +1474,7 @@ _PyObject_GenericGetAttrWithDict(PyObject *obj, PyObject *name,
if (!suppress) {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%U'",
+ "'%.100s' object has no attribute '%U'",
tp->tp_name, name);
set_attribute_error_context(obj, name);
@@ -1545,7 +1545,7 @@ _PyObject_GenericSetAttrWithDict(PyObject *obj, PyObject *name,
}
else {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object attribute '%U' is read-only",
+ "'%.100s' object attribute '%U' is read-only",
tp->tp_name, name);
}
goto done;
@@ -1754,10 +1754,14 @@ none_repr(PyObject *op)
return PyUnicode_FromString("None");
}
-static void _Py_NO_RETURN
-none_dealloc(PyObject* Py_UNUSED(ignore))
+static void
+none_dealloc(PyObject* none)
{
- _Py_FatalRefcountError("deallocating None");
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref None out of existence. Instead,
+ * since None is an immortal object, re-set the reference count.
+ */
+ _Py_SetImmortal(none);
}
static PyObject *
@@ -1823,7 +1827,7 @@ PyTypeObject _PyNone_Type = {
"NoneType",
0,
0,
- none_dealloc, /*tp_dealloc*/ /*never called*/
+ none_dealloc, /*tp_dealloc*/
0, /*tp_vectorcall_offset*/
0, /*tp_getattr*/
0, /*tp_setattr*/
@@ -1860,8 +1864,9 @@ PyTypeObject _PyNone_Type = {
};
PyObject _Py_NoneStruct = {
- _PyObject_EXTRA_INIT
- 1, &_PyNone_Type
+ _PyObject_EXTRA_INIT
+ { _Py_IMMORTAL_REFCNT },
+ &_PyNone_Type
};
/* NotImplemented is an object that can be used to signal that an
@@ -1894,13 +1899,14 @@ notimplemented_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
Py_RETURN_NOTIMPLEMENTED;
}
-static void _Py_NO_RETURN
-notimplemented_dealloc(PyObject* ignore)
+static void
+notimplemented_dealloc(PyObject *notimplemented)
{
/* This should never get called, but we also don't want to SEGV if
- * we accidentally decref NotImplemented out of existence.
+ * we accidentally decref NotImplemented out of existence. Instead,
+ * since Notimplemented is an immortal object, re-set the reference count.
*/
- Py_FatalError("deallocating NotImplemented");
+ _Py_SetImmortal(notimplemented);
}
static int
@@ -1962,16 +1968,15 @@ PyTypeObject _PyNotImplemented_Type = {
PyObject _Py_NotImplementedStruct = {
_PyObject_EXTRA_INIT
- 1, &_PyNotImplemented_Type
+ { _Py_IMMORTAL_REFCNT },
+ &_PyNotImplemented_Type
};
-#ifdef MS_WINDOWS
-extern PyTypeObject PyHKEY_Type;
-#endif
extern PyTypeObject _Py_GenericAliasIterType;
extern PyTypeObject _PyMemoryIter_Type;
extern PyTypeObject _PyLineIterator;
extern PyTypeObject _PyPositionsIterator;
+extern PyTypeObject _PyLegacyEventHandler_Type;
static PyTypeObject* static_types[] = {
// The two most important base types: must be initialized first and
@@ -2017,9 +2022,6 @@ static PyTypeObject* static_types[] = {
&PyFunction_Type,
&PyGen_Type,
&PyGetSetDescr_Type,
-#ifdef MS_WINDOWS
- &PyHKEY_Type,
-#endif
&PyInstanceMethod_Type,
&PyListIter_Type,
&PyListRevIter_Type,
@@ -2069,6 +2071,7 @@ static PyTypeObject* static_types[] = {
&_PyHamt_BitmapNode_Type,
&_PyHamt_CollisionNode_Type,
&_PyHamt_Type,
+ &_PyLegacyEventHandler_Type,
&_PyInterpreterID_Type,
&_PyLineIterator,
&_PyManagedBuffer_Type,
@@ -2147,7 +2150,8 @@ new_reference(PyObject *op)
if (_PyRuntime.tracemalloc.config.tracing) {
_PyTraceMalloc_NewReference(op);
}
- Py_SET_REFCNT(op, 1);
+ // Skip the immortal object check in Py_SET_REFCNT; always set refcnt to 1
+ op->ob_refcnt = 1;
#ifdef Py_TRACE_REFS
_Py_AddToAllObjects(op, 1);
#endif
diff --git a/Objects/obmalloc.c b/Objects/obmalloc.c
index 5e1bcda1d976bb..de62aeb04461fa 100644
--- a/Objects/obmalloc.c
+++ b/Objects/obmalloc.c
@@ -725,20 +725,51 @@ PyObject_Free(void *ptr)
static int running_on_valgrind = -1;
#endif
+typedef struct _obmalloc_state OMState;
-#define allarenas (_PyRuntime.obmalloc.mgmt.arenas)
-#define maxarenas (_PyRuntime.obmalloc.mgmt.maxarenas)
-#define unused_arena_objects (_PyRuntime.obmalloc.mgmt.unused_arena_objects)
-#define usable_arenas (_PyRuntime.obmalloc.mgmt.usable_arenas)
-#define nfp2lasta (_PyRuntime.obmalloc.mgmt.nfp2lasta)
-#define narenas_currently_allocated (_PyRuntime.obmalloc.mgmt.narenas_currently_allocated)
-#define ntimes_arena_allocated (_PyRuntime.obmalloc.mgmt.ntimes_arena_allocated)
-#define narenas_highwater (_PyRuntime.obmalloc.mgmt.narenas_highwater)
-#define raw_allocated_blocks (_PyRuntime.obmalloc.mgmt.raw_allocated_blocks)
+static inline int
+has_own_state(PyInterpreterState *interp)
+{
+ return (_Py_IsMainInterpreter(interp) ||
+ !(interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC) ||
+ _Py_IsMainInterpreterFinalizing(interp));
+}
+
+static inline OMState *
+get_state(void)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ if (!has_own_state(interp)) {
+ interp = _PyInterpreterState_Main();
+ }
+ return &interp->obmalloc;
+}
+
+// These macros all rely on a local "state" variable.
+#define usedpools (state->pools.used)
+#define allarenas (state->mgmt.arenas)
+#define maxarenas (state->mgmt.maxarenas)
+#define unused_arena_objects (state->mgmt.unused_arena_objects)
+#define usable_arenas (state->mgmt.usable_arenas)
+#define nfp2lasta (state->mgmt.nfp2lasta)
+#define narenas_currently_allocated (state->mgmt.narenas_currently_allocated)
+#define ntimes_arena_allocated (state->mgmt.ntimes_arena_allocated)
+#define narenas_highwater (state->mgmt.narenas_highwater)
+#define raw_allocated_blocks (state->mgmt.raw_allocated_blocks)
Py_ssize_t
-_Py_GetAllocatedBlocks(void)
+_PyInterpreterState_GetAllocatedBlocks(PyInterpreterState *interp)
{
+#ifdef Py_DEBUG
+ assert(has_own_state(interp));
+#else
+ if (!has_own_state(interp)) {
+ _Py_FatalErrorFunc(__func__,
+ "the interpreter doesn't have its own allocator");
+ }
+#endif
+ OMState *state = &interp->obmalloc;
+
Py_ssize_t n = raw_allocated_blocks;
/* add up allocated blocks for used pools */
for (uint i = 0; i < maxarenas; ++i) {
@@ -759,20 +790,100 @@ _Py_GetAllocatedBlocks(void)
return n;
}
+void
+_PyInterpreterState_FinalizeAllocatedBlocks(PyInterpreterState *interp)
+{
+ if (has_own_state(interp)) {
+ Py_ssize_t leaked = _PyInterpreterState_GetAllocatedBlocks(interp);
+ assert(has_own_state(interp) || leaked == 0);
+ interp->runtime->obmalloc.interpreter_leaks += leaked;
+ }
+}
+
+static Py_ssize_t get_num_global_allocated_blocks(_PyRuntimeState *);
+
+/* We preserve the number of blockss leaked during runtime finalization,
+ so they can be reported if the runtime is initialized again. */
+// XXX We don't lose any information by dropping this,
+// so we should consider doing so.
+static Py_ssize_t last_final_leaks = 0;
+
+void
+_Py_FinalizeAllocatedBlocks(_PyRuntimeState *runtime)
+{
+ last_final_leaks = get_num_global_allocated_blocks(runtime);
+ runtime->obmalloc.interpreter_leaks = 0;
+}
+
+static Py_ssize_t
+get_num_global_allocated_blocks(_PyRuntimeState *runtime)
+{
+ Py_ssize_t total = 0;
+ if (_PyRuntimeState_GetFinalizing(runtime) != NULL) {
+ PyInterpreterState *interp = _PyInterpreterState_Main();
+ if (interp == NULL) {
+ /* We are at the very end of runtime finalization.
+ We can't rely on finalizing->interp since that thread
+ state is probably already freed, so we don't worry
+ about it. */
+ assert(PyInterpreterState_Head() == NULL);
+ }
+ else {
+ assert(interp != NULL);
+ /* It is probably the last interpreter but not necessarily. */
+ assert(PyInterpreterState_Next(interp) == NULL);
+ total += _PyInterpreterState_GetAllocatedBlocks(interp);
+ }
+ }
+ else {
+ HEAD_LOCK(runtime);
+ PyInterpreterState *interp = PyInterpreterState_Head();
+ assert(interp != NULL);
+#ifdef Py_DEBUG
+ int got_main = 0;
+#endif
+ for (; interp != NULL; interp = PyInterpreterState_Next(interp)) {
+#ifdef Py_DEBUG
+ if (_Py_IsMainInterpreter(interp)) {
+ assert(!got_main);
+ got_main = 1;
+ assert(has_own_state(interp));
+ }
+#endif
+ if (has_own_state(interp)) {
+ total += _PyInterpreterState_GetAllocatedBlocks(interp);
+ }
+ }
+ HEAD_UNLOCK(runtime);
+#ifdef Py_DEBUG
+ assert(got_main);
+#endif
+ }
+ total += runtime->obmalloc.interpreter_leaks;
+ total += last_final_leaks;
+ return total;
+}
+
+Py_ssize_t
+_Py_GetGlobalAllocatedBlocks(void)
+{
+ return get_num_global_allocated_blocks(&_PyRuntime);
+}
+
#if WITH_PYMALLOC_RADIX_TREE
/*==========================================================================*/
/* radix tree for tracking arena usage. */
-#define arena_map_root (_PyRuntime.obmalloc.usage.arena_map_root)
+#define arena_map_root (state->usage.arena_map_root)
#ifdef USE_INTERIOR_NODES
-#define arena_map_mid_count (_PyRuntime.obmalloc.usage.arena_map_mid_count)
-#define arena_map_bot_count (_PyRuntime.obmalloc.usage.arena_map_bot_count)
+#define arena_map_mid_count (state->usage.arena_map_mid_count)
+#define arena_map_bot_count (state->usage.arena_map_bot_count)
#endif
/* Return a pointer to a bottom tree node, return NULL if it doesn't exist or
* it cannot be created */
static Py_ALWAYS_INLINE arena_map_bot_t *
-arena_map_get(pymem_block *p, int create)
+arena_map_get(OMState *state, pymem_block *p, int create)
{
#ifdef USE_INTERIOR_NODES
/* sanity check that IGNORE_BITS is correct */
@@ -833,11 +944,12 @@ arena_map_get(pymem_block *p, int create)
/* mark or unmark addresses covered by arena */
static int
-arena_map_mark_used(uintptr_t arena_base, int is_used)
+arena_map_mark_used(OMState *state, uintptr_t arena_base, int is_used)
{
/* sanity check that IGNORE_BITS is correct */
assert(HIGH_BITS(arena_base) == HIGH_BITS(&arena_map_root));
- arena_map_bot_t *n_hi = arena_map_get((pymem_block *)arena_base, is_used);
+ arena_map_bot_t *n_hi = arena_map_get(
+ state, (pymem_block *)arena_base, is_used);
if (n_hi == NULL) {
assert(is_used); /* otherwise node should already exist */
return 0; /* failed to allocate space for node */
@@ -862,7 +974,8 @@ arena_map_mark_used(uintptr_t arena_base, int is_used)
* must overflow to 0. However, that would mean arena_base was
* "ideal" and we should not be in this case. */
assert(arena_base < arena_base_next);
- arena_map_bot_t *n_lo = arena_map_get((pymem_block *)arena_base_next, is_used);
+ arena_map_bot_t *n_lo = arena_map_get(
+ state, (pymem_block *)arena_base_next, is_used);
if (n_lo == NULL) {
assert(is_used); /* otherwise should already exist */
n_hi->arenas[i3].tail_hi = 0;
@@ -877,9 +990,9 @@ arena_map_mark_used(uintptr_t arena_base, int is_used)
/* Return true if 'p' is a pointer inside an obmalloc arena.
* _PyObject_Free() calls this so it needs to be very fast. */
static int
-arena_map_is_used(pymem_block *p)
+arena_map_is_used(OMState *state, pymem_block *p)
{
- arena_map_bot_t *n = arena_map_get(p, 0);
+ arena_map_bot_t *n = arena_map_get(state, p, 0);
if (n == NULL) {
return 0;
}
@@ -902,7 +1015,7 @@ arena_map_is_used(pymem_block *p)
* `usable_arenas` to the return value.
*/
static struct arena_object*
-new_arena(void)
+new_arena(OMState *state)
{
struct arena_object* arenaobj;
uint excess; /* number of bytes above pool alignment */
@@ -968,7 +1081,7 @@ new_arena(void)
address = _PyObject_Arena.alloc(_PyObject_Arena.ctx, ARENA_SIZE);
#if WITH_PYMALLOC_RADIX_TREE
if (address != NULL) {
- if (!arena_map_mark_used((uintptr_t)address, 1)) {
+ if (!arena_map_mark_used(state, (uintptr_t)address, 1)) {
/* marking arena in radix tree failed, abort */
_PyObject_Arena.free(_PyObject_Arena.ctx, address, ARENA_SIZE);
address = NULL;
@@ -1011,9 +1124,9 @@ new_arena(void)
pymalloc. When the radix tree is used, 'poolp' is unused.
*/
static bool
-address_in_range(void *p, poolp Py_UNUSED(pool))
+address_in_range(OMState *state, void *p, poolp Py_UNUSED(pool))
{
- return arena_map_is_used(p);
+ return arena_map_is_used(state, p);
}
#else
/*
@@ -1094,7 +1207,7 @@ extremely desirable that it be this fast.
static bool _Py_NO_SANITIZE_ADDRESS
_Py_NO_SANITIZE_THREAD
_Py_NO_SANITIZE_MEMORY
-address_in_range(void *p, poolp pool)
+address_in_range(OMState *state, void *p, poolp pool)
{
// Since address_in_range may be reading from memory which was not allocated
// by Python, it is important that pool->arenaindex is read only once, as
@@ -1111,8 +1224,6 @@ address_in_range(void *p, poolp pool)
/*==========================================================================*/
-#define usedpools (_PyRuntime.obmalloc.pools.used)
-
// Called when freelist is exhausted. Extend the freelist if there is
// space for a block. Otherwise, remove this pool from usedpools.
static void
@@ -1138,7 +1249,7 @@ pymalloc_pool_extend(poolp pool, uint size)
* This function takes new pool and allocate a block from it.
*/
static void*
-allocate_from_new_pool(uint size)
+allocate_from_new_pool(OMState *state, uint size)
{
/* There isn't a pool of the right size class immediately
* available: use a free pool.
@@ -1150,7 +1261,7 @@ allocate_from_new_pool(uint size)
return NULL;
}
#endif
- usable_arenas = new_arena();
+ usable_arenas = new_arena(state);
if (usable_arenas == NULL) {
return NULL;
}
@@ -1274,7 +1385,7 @@ allocate_from_new_pool(uint size)
or when the max memory limit has been reached.
*/
static inline void*
-pymalloc_alloc(void *Py_UNUSED(ctx), size_t nbytes)
+pymalloc_alloc(OMState *state, void *Py_UNUSED(ctx), size_t nbytes)
{
#ifdef WITH_VALGRIND
if (UNLIKELY(running_on_valgrind == -1)) {
@@ -1314,7 +1425,7 @@ pymalloc_alloc(void *Py_UNUSED(ctx), size_t nbytes)
/* There isn't a pool of the right size class immediately
* available: use a free pool.
*/
- bp = allocate_from_new_pool(size);
+ bp = allocate_from_new_pool(state, size);
}
return (void *)bp;
@@ -1324,7 +1435,8 @@ pymalloc_alloc(void *Py_UNUSED(ctx), size_t nbytes)
void *
_PyObject_Malloc(void *ctx, size_t nbytes)
{
- void* ptr = pymalloc_alloc(ctx, nbytes);
+ OMState *state = get_state();
+ void* ptr = pymalloc_alloc(state, ctx, nbytes);
if (LIKELY(ptr != NULL)) {
return ptr;
}
@@ -1343,7 +1455,8 @@ _PyObject_Calloc(void *ctx, size_t nelem, size_t elsize)
assert(elsize == 0 || nelem <= (size_t)PY_SSIZE_T_MAX / elsize);
size_t nbytes = nelem * elsize;
- void* ptr = pymalloc_alloc(ctx, nbytes);
+ OMState *state = get_state();
+ void* ptr = pymalloc_alloc(state, ctx, nbytes);
if (LIKELY(ptr != NULL)) {
memset(ptr, 0, nbytes);
return ptr;
@@ -1358,7 +1471,7 @@ _PyObject_Calloc(void *ctx, size_t nelem, size_t elsize)
static void
-insert_to_usedpool(poolp pool)
+insert_to_usedpool(OMState *state, poolp pool)
{
assert(pool->ref.count > 0); /* else the pool is empty */
@@ -1374,7 +1487,7 @@ insert_to_usedpool(poolp pool)
}
static void
-insert_to_freepool(poolp pool)
+insert_to_freepool(OMState *state, poolp pool)
{
poolp next = pool->nextpool;
poolp prev = pool->prevpool;
@@ -1457,7 +1570,7 @@ insert_to_freepool(poolp pool)
#if WITH_PYMALLOC_RADIX_TREE
/* mark arena region as not under control of obmalloc */
- arena_map_mark_used(ao->address, 0);
+ arena_map_mark_used(state, ao->address, 0);
#endif
/* Free the entire arena. */
@@ -1544,7 +1657,7 @@ insert_to_freepool(poolp pool)
Return 1 if it was freed.
Return 0 if the block was not allocated by pymalloc_alloc(). */
static inline int
-pymalloc_free(void *Py_UNUSED(ctx), void *p)
+pymalloc_free(OMState *state, void *Py_UNUSED(ctx), void *p)
{
assert(p != NULL);
@@ -1555,7 +1668,7 @@ pymalloc_free(void *Py_UNUSED(ctx), void *p)
#endif
poolp pool = POOL_ADDR(p);
- if (UNLIKELY(!address_in_range(p, pool))) {
+ if (UNLIKELY(!address_in_range(state, p, pool))) {
return 0;
}
/* We allocated this address. */
@@ -1579,7 +1692,7 @@ pymalloc_free(void *Py_UNUSED(ctx), void *p)
* targets optimal filling when several pools contain
* blocks of the same size class.
*/
- insert_to_usedpool(pool);
+ insert_to_usedpool(state, pool);
return 1;
}
@@ -1596,7 +1709,7 @@ pymalloc_free(void *Py_UNUSED(ctx), void *p)
* previously freed pools will be allocated later
* (being not referenced, they are perhaps paged out).
*/
- insert_to_freepool(pool);
+ insert_to_freepool(state, pool);
return 1;
}
@@ -1609,7 +1722,8 @@ _PyObject_Free(void *ctx, void *p)
return;
}
- if (UNLIKELY(!pymalloc_free(ctx, p))) {
+ OMState *state = get_state();
+ if (UNLIKELY(!pymalloc_free(state, ctx, p))) {
/* pymalloc didn't allocate this address */
PyMem_RawFree(p);
raw_allocated_blocks--;
@@ -1627,7 +1741,8 @@ _PyObject_Free(void *ctx, void *p)
Return 0 if pymalloc didn't allocated p. */
static int
-pymalloc_realloc(void *ctx, void **newptr_p, void *p, size_t nbytes)
+pymalloc_realloc(OMState *state, void *ctx,
+ void **newptr_p, void *p, size_t nbytes)
{
void *bp;
poolp pool;
@@ -1643,7 +1758,7 @@ pymalloc_realloc(void *ctx, void **newptr_p, void *p, size_t nbytes)
#endif
pool = POOL_ADDR(p);
- if (!address_in_range(p, pool)) {
+ if (!address_in_range(state, p, pool)) {
/* pymalloc is not managing this block.
If nbytes <= SMALL_REQUEST_THRESHOLD, it's tempting to try to take
@@ -1696,7 +1811,8 @@ _PyObject_Realloc(void *ctx, void *ptr, size_t nbytes)
return _PyObject_Malloc(ctx, nbytes);
}
- if (pymalloc_realloc(ctx, &ptr2, ptr, nbytes)) {
+ OMState *state = get_state();
+ if (pymalloc_realloc(state, ctx, &ptr2, ptr, nbytes)) {
return ptr2;
}
@@ -1710,11 +1826,29 @@ _PyObject_Realloc(void *ctx, void *ptr, size_t nbytes)
* only be used by extensions that are compiled with pymalloc enabled. */
Py_ssize_t
-_Py_GetAllocatedBlocks(void)
+_PyInterpreterState_GetAllocatedBlocks(PyInterpreterState *Py_UNUSED(interp))
+{
+ return 0;
+}
+
+Py_ssize_t
+_Py_GetGlobalAllocatedBlocks(void)
{
return 0;
}
+void
+_PyInterpreterState_FinalizeAllocatedBlocks(PyInterpreterState *Py_UNUSED(interp))
+{
+ return;
+}
+
+void
+_Py_FinalizeAllocatedBlocks(_PyRuntimeState *Py_UNUSED(runtime))
+{
+ return;
+}
+
#endif /* WITH_PYMALLOC */
@@ -2289,6 +2423,7 @@ _PyObject_DebugMallocStats(FILE *out)
if (!_PyMem_PymallocEnabled()) {
return 0;
}
+ OMState *state = get_state();
uint i;
const uint numclasses = SMALL_REQUEST_THRESHOLD >> ALIGNMENT_SHIFT;
diff --git a/Objects/setobject.c b/Objects/setobject.c
index fcdda2a0bca2b6..58f0ae73c0c403 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -2543,6 +2543,7 @@ static PyTypeObject _PySetDummy_Type = {
};
static PyObject _dummy_struct = {
- _PyObject_EXTRA_INIT
- 2, &_PySetDummy_Type
+ _PyObject_EXTRA_INIT
+ { _Py_IMMORTAL_REFCNT },
+ &_PySetDummy_Type
};
diff --git a/Objects/sliceobject.c b/Objects/sliceobject.c
index 584ebce721faed..e6776ac92b669c 100644
--- a/Objects/sliceobject.c
+++ b/Objects/sliceobject.c
@@ -29,6 +29,16 @@ ellipsis_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
return Py_NewRef(Py_Ellipsis);
}
+static void
+ellipsis_dealloc(PyObject *ellipsis)
+{
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref Ellipsis out of existence. Instead,
+ * since Ellipsis is an immortal object, re-set the reference count.
+ */
+ _Py_SetImmortal(ellipsis);
+}
+
static PyObject *
ellipsis_repr(PyObject *op)
{
@@ -51,7 +61,7 @@ PyTypeObject PyEllipsis_Type = {
"ellipsis", /* tp_name */
0, /* tp_basicsize */
0, /* tp_itemsize */
- 0, /*never called*/ /* tp_dealloc */
+ ellipsis_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
@@ -89,7 +99,8 @@ PyTypeObject PyEllipsis_Type = {
PyObject _Py_EllipsisObject = {
_PyObject_EXTRA_INIT
- 1, &PyEllipsis_Type
+ { _Py_IMMORTAL_REFCNT },
+ &PyEllipsis_Type
};
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index fc5394dc8a6785..a4ea86da0d5772 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -45,7 +45,9 @@ class object "PyObject *" "&PyBaseObject_Type"
PyUnicode_IS_READY(name) && \
(PyUnicode_GET_LENGTH(name) <= MCACHE_MAX_ATTR_SIZE)
-#define next_version_tag (_PyRuntime.types.next_version_tag)
+#define NEXT_GLOBAL_VERSION_TAG _PyRuntime.types.next_version_tag
+#define NEXT_VERSION_TAG(interp) \
+ (interp)->types.next_version_tag
typedef struct PySlot_Offset {
short subslot_offset;
@@ -318,27 +320,11 @@ _PyType_InitCache(PyInterpreterState *interp)
entry->version = 0;
// Set to None so _PyType_Lookup() can use Py_SETREF(),
// rather than using slower Py_XSETREF().
- // (See _PyType_FixCacheRefcounts() about the refcount.)
entry->name = Py_None;
entry->value = NULL;
}
}
-// This is the temporary fix used by pycore_create_interpreter(),
-// in pylifecycle.c. _PyType_InitCache() is called before the GIL
-// has been created (for the main interpreter) and without the
-// "current" thread state set. This causes crashes when the
-// reftotal is updated, so we don't modify the refcount in
-// _PyType_InitCache(), and instead do it later by calling
-// _PyType_FixCacheRefcounts().
-// XXX This workaround should be removed once we have immortal
-// objects (PEP 683).
-void
-_PyType_FixCacheRefcounts(void)
-{
- _Py_RefcntAdd(Py_None, (1 << MCACHE_SIZE_EXP));
-}
-
static unsigned int
_PyType_ClearCache(PyInterpreterState *interp)
@@ -348,7 +334,7 @@ _PyType_ClearCache(PyInterpreterState *interp)
// use Py_SETREF() rather than using slower Py_XSETREF().
type_cache_clear(cache, Py_None);
- return next_version_tag - 1;
+ return NEXT_VERSION_TAG(interp) - 1;
}
@@ -417,7 +403,7 @@ PyType_ClearWatcher(int watcher_id)
return 0;
}
-static int assign_version_tag(PyTypeObject *type);
+static int assign_version_tag(PyInterpreterState *interp, PyTypeObject *type);
int
PyType_Watch(int watcher_id, PyObject* obj)
@@ -432,7 +418,7 @@ PyType_Watch(int watcher_id, PyObject* obj)
return -1;
}
// ensure we will get a callback on the next modification
- assign_version_tag(type);
+ assign_version_tag(interp, type);
type->tp_watched |= (1 << watcher_id);
return 0;
}
@@ -565,7 +551,9 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
}
}
return;
+
clear:
+ assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
type->tp_flags &= ~Py_TPFLAGS_VALID_VERSION_TAG;
type->tp_version_tag = 0; /* 0 is not a valid version tag */
if (PyType_HasFeature(type, Py_TPFLAGS_HEAPTYPE)) {
@@ -576,7 +564,7 @@ type_mro_modified(PyTypeObject *type, PyObject *bases) {
}
static int
-assign_version_tag(PyTypeObject *type)
+assign_version_tag(PyInterpreterState *interp, PyTypeObject *type)
{
/* Ensure that the tp_version_tag is valid and set
Py_TPFLAGS_VALID_VERSION_TAG. To respect the invariant, this
@@ -590,24 +578,42 @@ assign_version_tag(PyTypeObject *type)
return 0;
}
- if (next_version_tag == 0) {
- /* We have run out of version numbers */
- return 0;
+ if (type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE) {
+ /* static types */
+ if (NEXT_GLOBAL_VERSION_TAG > _Py_MAX_GLOBAL_TYPE_VERSION_TAG) {
+ /* We have run out of version numbers */
+ return 0;
+ }
+ type->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
+ assert (type->tp_version_tag <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
+ }
+ else {
+ /* heap types */
+ if (NEXT_VERSION_TAG(interp) == 0) {
+ /* We have run out of version numbers */
+ return 0;
+ }
+ type->tp_version_tag = NEXT_VERSION_TAG(interp)++;
+ assert (type->tp_version_tag != 0);
}
- type->tp_version_tag = next_version_tag++;
- assert (type->tp_version_tag != 0);
PyObject *bases = type->tp_bases;
Py_ssize_t n = PyTuple_GET_SIZE(bases);
for (Py_ssize_t i = 0; i < n; i++) {
PyObject *b = PyTuple_GET_ITEM(bases, i);
- if (!assign_version_tag(_PyType_CAST(b)))
+ if (!assign_version_tag(interp, _PyType_CAST(b)))
return 0;
}
type->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
return 1;
}
+int PyUnstable_Type_AssignVersionTag(PyTypeObject *type)
+{
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ return assign_version_tag(interp, type);
+}
+
static PyMemberDef type_members[] = {
{"__basicsize__", T_PYSSIZET, offsetof(PyTypeObject,tp_basicsize),READONLY},
@@ -2373,7 +2379,15 @@ mro_internal(PyTypeObject *type, PyObject **p_old_mro)
from the custom MRO */
type_mro_modified(type, type->tp_bases);
- PyType_Modified(type);
+ // XXX Expand this to Py_TPFLAGS_IMMUTABLETYPE?
+ if (!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN)) {
+ PyType_Modified(type);
+ }
+ else {
+ /* For static builtin types, this is only called during init
+ before the method cache has been populated. */
+ assert(_PyType_HasFeature(type, Py_TPFLAGS_VALID_VERSION_TAG));
+ }
if (p_old_mro != NULL)
*p_old_mro = old_mro; /* transfer the ownership */
@@ -4208,6 +4222,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
{
PyObject *res;
int error;
+ PyInterpreterState *interp = _PyInterpreterState_GET();
unsigned int h = MCACHE_HASH_METHOD(type, name);
struct type_cache *cache = get_type_cache();
@@ -4242,7 +4257,7 @@ _PyType_Lookup(PyTypeObject *type, PyObject *name)
return NULL;
}
- if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(type)) {
+ if (MCACHE_CACHEABLE_NAME(name) && assign_version_tag(interp, type)) {
h = MCACHE_HASH_METHOD(type, name);
struct type_cache_entry *entry = &cache->hashtable[h];
entry->version = type->tp_version_tag;
@@ -4360,7 +4375,7 @@ _Py_type_getattro_impl(PyTypeObject *type, PyObject *name, int * suppress_missin
/* Give up */
if (suppress_missing_attribute == NULL) {
PyErr_Format(PyExc_AttributeError,
- "type object '%.50s' has no attribute '%U'",
+ "type object '%.100s' has no attribute '%U'",
type->tp_name, name);
} else {
// signal the caller we have not set an PyExc_AttributeError and gave up
@@ -6703,8 +6718,10 @@ type_ready_mro(PyTypeObject *type)
assert(type->tp_mro != NULL);
assert(PyTuple_Check(type->tp_mro));
- /* All bases of statically allocated type should be statically allocated */
+ /* All bases of statically allocated type should be statically allocated,
+ and static builtin types must have static builtin bases. */
if (!(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) {
+ assert(type->tp_flags & Py_TPFLAGS_IMMUTABLETYPE);
PyObject *mro = type->tp_mro;
Py_ssize_t n = PyTuple_GET_SIZE(mro);
for (Py_ssize_t i = 0; i < n; i++) {
@@ -6716,6 +6733,8 @@ type_ready_mro(PyTypeObject *type)
type->tp_name, base->tp_name);
return -1;
}
+ assert(!(type->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN) ||
+ (base->tp_flags & _Py_TPFLAGS_STATIC_BUILTIN));
}
}
return 0;
@@ -7027,7 +7046,11 @@ PyType_Ready(PyTypeObject *type)
int
_PyStaticType_InitBuiltin(PyTypeObject *self)
{
- self->tp_flags = self->tp_flags | _Py_TPFLAGS_STATIC_BUILTIN;
+ self->tp_flags |= _Py_TPFLAGS_STATIC_BUILTIN;
+
+ assert(NEXT_GLOBAL_VERSION_TAG <= _Py_MAX_GLOBAL_TYPE_VERSION_TAG);
+ self->tp_version_tag = NEXT_GLOBAL_VERSION_TAG++;
+ self->tp_flags |= Py_TPFLAGS_VALID_VERSION_TAG;
static_builtin_state_init(self);
@@ -9153,13 +9176,15 @@ type_new_set_names(PyTypeObject *type)
Py_DECREF(set_name);
if (res == NULL) {
- _PyErr_FormatFromCause(PyExc_RuntimeError,
+ _PyErr_FormatNote(
"Error calling __set_name__ on '%.100s' instance %R "
"in '%.100s'",
Py_TYPE(value)->tp_name, key, type->tp_name);
goto error;
}
- Py_DECREF(res);
+ else {
+ Py_DECREF(res);
+ }
}
Py_DECREF(names_to_set);
@@ -9371,42 +9396,33 @@ super_repr(PyObject *self)
su->type ? su->type->tp_name : "NULL");
}
+/* Do a super lookup without executing descriptors or falling back to getattr
+on the super object itself.
+
+May return NULL with or without an exception set, like PyDict_GetItemWithError. */
static PyObject *
-super_getattro(PyObject *self, PyObject *name)
+_super_lookup_descr(PyTypeObject *su_type, PyTypeObject *su_obj_type, PyObject *name)
{
- superobject *su = (superobject *)self;
- PyTypeObject *starttype;
- PyObject *mro;
+ PyObject *mro, *res;
Py_ssize_t i, n;
- starttype = su->obj_type;
- if (starttype == NULL)
- goto skip;
-
- /* We want __class__ to return the class of the super object
- (i.e. super, or a subclass), not the class of su->obj. */
- if (PyUnicode_Check(name) &&
- PyUnicode_GET_LENGTH(name) == 9 &&
- _PyUnicode_Equal(name, &_Py_ID(__class__)))
- goto skip;
-
- mro = starttype->tp_mro;
+ mro = su_obj_type->tp_mro;
if (mro == NULL)
- goto skip;
+ return NULL;
assert(PyTuple_Check(mro));
n = PyTuple_GET_SIZE(mro);
/* No need to check the last one: it's gonna be skipped anyway. */
for (i = 0; i+1 < n; i++) {
- if ((PyObject *)(su->type) == PyTuple_GET_ITEM(mro, i))
+ if ((PyObject *)(su_type) == PyTuple_GET_ITEM(mro, i))
break;
}
i++; /* skip su->type (if any) */
if (i >= n)
- goto skip;
+ return NULL;
- /* keep a strong reference to mro because starttype->tp_mro can be
+ /* keep a strong reference to mro because su_obj_type->tp_mro can be
replaced during PyDict_GetItemWithError(dict, name) */
Py_INCREF(mro);
do {
@@ -9414,21 +9430,9 @@ super_getattro(PyObject *self, PyObject *name)
PyObject *dict = _PyType_CAST(obj)->tp_dict;
assert(dict != NULL && PyDict_Check(dict));
- PyObject *res = PyDict_GetItemWithError(dict, name);
+ res = PyDict_GetItemWithError(dict, name);
if (res != NULL) {
Py_INCREF(res);
-
- descrgetfunc f = Py_TYPE(res)->tp_descr_get;
- if (f != NULL) {
- PyObject *res2;
- res2 = f(res,
- /* Only pass 'obj' param if this is instance-mode super
- (See SF ID #743627) */
- (su->obj == (PyObject *)starttype) ? NULL : su->obj,
- (PyObject *)starttype);
- Py_SETREF(res, res2);
- }
-
Py_DECREF(mro);
return res;
}
@@ -9440,9 +9444,75 @@ super_getattro(PyObject *self, PyObject *name)
i++;
} while (i < n);
Py_DECREF(mro);
+ return NULL;
+}
+
+// if `method` is non-NULL, we are looking for a method descriptor,
+// and setting `*method = 1` means we found one.
+static PyObject *
+do_super_lookup(superobject *su, PyTypeObject *su_type, PyObject *su_obj,
+ PyTypeObject *su_obj_type, PyObject *name, int *method)
+{
+ PyObject *res;
+ int temp_su = 0;
+
+ if (su_obj_type == NULL) {
+ goto skip;
+ }
+
+ res = _super_lookup_descr(su_type, su_obj_type, name);
+ if (res != NULL) {
+ if (method && _PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
+ *method = 1;
+ }
+ else {
+ descrgetfunc f = Py_TYPE(res)->tp_descr_get;
+ if (f != NULL) {
+ PyObject *res2;
+ res2 = f(res,
+ /* Only pass 'obj' param if this is instance-mode super
+ (See SF ID #743627) */
+ (su_obj == (PyObject *)su_obj_type) ? NULL : su_obj,
+ (PyObject *)su_obj_type);
+ Py_SETREF(res, res2);
+ }
+ }
+
+ return res;
+ }
+ else if (PyErr_Occurred()) {
+ return NULL;
+ }
skip:
- return PyObject_GenericGetAttr(self, name);
+ if (su == NULL) {
+ PyObject *args[] = {(PyObject *)su_type, su_obj};
+ su = (superobject *)PyObject_Vectorcall((PyObject *)&PySuper_Type, args, 2, NULL);
+ if (su == NULL) {
+ return NULL;
+ }
+ temp_su = 1;
+ }
+ res = PyObject_GenericGetAttr((PyObject *)su, name);
+ if (temp_su) {
+ Py_DECREF(su);
+ }
+ return res;
+}
+
+static PyObject *
+super_getattro(PyObject *self, PyObject *name)
+{
+ superobject *su = (superobject *)self;
+
+ /* We want __class__ to return the class of the super object
+ (i.e. super, or a subclass), not the class of su->obj. */
+ if (PyUnicode_Check(name) &&
+ PyUnicode_GET_LENGTH(name) == 9 &&
+ _PyUnicode_Equal(name, &_Py_ID(__class__)))
+ return PyObject_GenericGetAttr(self, name);
+
+ return do_super_lookup(su, su->type, su->obj, su->obj_type, name, NULL);
}
static PyTypeObject *
@@ -9498,6 +9568,30 @@ supercheck(PyTypeObject *type, PyObject *obj)
return NULL;
}
+PyObject *
+_PySuper_Lookup(PyTypeObject *su_type, PyObject *su_obj, PyObject *name, int *method)
+{
+ PyTypeObject *su_obj_type = supercheck(su_type, su_obj);
+ if (su_obj_type == NULL) {
+ return NULL;
+ }
+ PyObject *res = do_super_lookup(NULL, su_type, su_obj, su_obj_type, name, method);
+ Py_DECREF(su_obj_type);
+ return res;
+}
+
+PyObject *
+_PySuper_LookupDescr(PyTypeObject *su_type, PyObject *su_obj, PyObject *name)
+{
+ PyTypeObject *su_obj_type = supercheck(su_type, su_obj);
+ if (su_obj_type == NULL) {
+ return NULL;
+ }
+ PyObject *res = _super_lookup_descr(su_type, su_obj_type, name);
+ Py_DECREF(su_obj_type);
+ return res;
+}
+
static PyObject *
super_descr_get(PyObject *self, PyObject *obj, PyObject *type)
{
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 85e5ae735709fd..fd056e38f3f86b 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -228,14 +228,18 @@ static inline PyObject* unicode_new_empty(void)
to strings in this dictionary are *not* counted in the string's ob_refcnt.
When the interned string reaches a refcnt of 0 the string deallocation
function will delete the reference from this dictionary.
- Another way to look at this is that to say that the actual reference
- count of a string is: s->ob_refcnt + (s->state ? 2 : 0)
*/
static inline PyObject *get_interned_dict(PyInterpreterState *interp)
{
return _Py_INTERP_CACHED_OBJECT(interp, interned_strings);
}
+Py_ssize_t
+_PyUnicode_InternedSize()
+{
+ return PyObject_Length(get_interned_dict(_PyInterpreterState_GET()));
+}
+
static int
init_interned_dict(PyInterpreterState *interp)
{
@@ -1538,30 +1542,19 @@ find_maxchar_surrogates(const wchar_t *begin, const wchar_t *end,
static void
unicode_dealloc(PyObject *unicode)
{
- PyInterpreterState *interp = _PyInterpreterState_GET();
#ifdef Py_DEBUG
if (!unicode_is_finalizing() && unicode_is_singleton(unicode)) {
_Py_FatalRefcountError("deallocating an Unicode singleton");
}
#endif
+ /* This should never get called, but we also don't want to SEGV if
+ * we accidentally decref an immortal string out of existence. Since
+ * the string is an immortal object, just re-set the reference count.
+ */
if (PyUnicode_CHECK_INTERNED(unicode)) {
- /* Revive the dead object temporarily. PyDict_DelItem() removes two
- references (key and value) which were ignored by
- PyUnicode_InternInPlace(). Use refcnt=3 rather than refcnt=2
- to prevent calling unicode_dealloc() again. Adjust refcnt after
- PyDict_DelItem(). */
- assert(Py_REFCNT(unicode) == 0);
- Py_SET_REFCNT(unicode, 3);
- PyObject *interned = get_interned_dict(interp);
- assert(interned != NULL);
- if (PyDict_DelItem(interned, unicode) != 0) {
- _PyErr_WriteUnraisableMsg("deletion of interned string failed",
- NULL);
- }
- assert(Py_REFCNT(unicode) == 1);
- Py_SET_REFCNT(unicode, 0);
+ _Py_SetImmortal(unicode);
+ return;
}
-
if (_PyUnicode_HAS_UTF8_MEMORY(unicode)) {
PyObject_Free(_PyUnicode_UTF8(unicode));
}
@@ -14637,11 +14630,21 @@ _PyUnicode_InternInPlace(PyInterpreterState *interp, PyObject **p)
return;
}
- /* The two references in interned dict (key and value) are not counted by
- refcnt. unicode_dealloc() and _PyUnicode_ClearInterned() take care of
- this. */
- Py_SET_REFCNT(s, Py_REFCNT(s) - 2);
- _PyUnicode_STATE(s).interned = 1;
+ if (_Py_IsImmortal(s)) {
+ _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL_STATIC;
+ return;
+ }
+#ifdef Py_REF_DEBUG
+ /* The reference count value excluding the 2 references from the
+ interned dictionary should be excluded from the RefTotal. The
+ decrements to these objects will not be registered so they
+ need to be accounted for in here. */
+ for (Py_ssize_t i = 0; i < Py_REFCNT(s) - 2; i++) {
+ _Py_DecRefTotal(_PyInterpreterState_GET());
+ }
+#endif
+ _Py_SetImmortal(s);
+ _PyUnicode_STATE(*p).interned = SSTATE_INTERNED_IMMORTAL;
}
void
@@ -14681,10 +14684,20 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
}
assert(PyDict_CheckExact(interned));
- /* Interned unicode strings are not forcibly deallocated; rather, we give
- them their stolen references back, and then clear and DECREF the
- interned dict. */
-
+ /* TODO:
+ * Currently, the runtime is not able to guarantee that it can exit without
+ * allocations that carry over to a future initialization of Python within
+ * the same process. i.e:
+ * ./python -X showrefcount -c 'import itertools'
+ * [237 refs, 237 blocks]
+ *
+ * Therefore, this should remain disabled for until there is a strict guarantee
+ * that no memory will be left after `Py_Finalize`.
+ */
+#ifdef Py_DEBUG
+ /* For all non-singleton interned strings, restore the two valid references
+ to that instance from within the intern string dictionary and let the
+ normal reference counting process clean up these instances. */
#ifdef INTERNED_STATS
fprintf(stderr, "releasing %zd interned strings\n",
PyDict_GET_SIZE(interned));
@@ -14694,15 +14707,27 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
Py_ssize_t pos = 0;
PyObject *s, *ignored_value;
while (PyDict_Next(interned, &pos, &s, &ignored_value)) {
- assert(PyUnicode_CHECK_INTERNED(s));
- // Restore the two references (key and value) ignored
- // by PyUnicode_InternInPlace().
- Py_SET_REFCNT(s, Py_REFCNT(s) + 2);
+ assert(PyUnicode_IS_READY(s));
+ switch (PyUnicode_CHECK_INTERNED(s)) {
+ case SSTATE_INTERNED_IMMORTAL:
+ // Skip the Immortal Instance check and restore
+ // the two references (key and value) ignored
+ // by PyUnicode_InternInPlace().
+ s->ob_refcnt = 2;
#ifdef INTERNED_STATS
- total_length += PyUnicode_GET_LENGTH(s);
+ total_length += PyUnicode_GET_LENGTH(s);
#endif
-
- _PyUnicode_STATE(s).interned = 0;
+ break;
+ case SSTATE_INTERNED_IMMORTAL_STATIC:
+ break;
+ case SSTATE_INTERNED_MORTAL:
+ /* fall through */
+ case SSTATE_NOT_INTERNED:
+ /* fall through */
+ default:
+ Py_UNREACHABLE();
+ }
+ _PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
}
#ifdef INTERNED_STATS
fprintf(stderr,
@@ -14710,6 +14735,12 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
total_length);
#endif
+ struct _Py_unicode_state *state = &interp->unicode;
+ struct _Py_unicode_ids *ids = &state->ids;
+ for (Py_ssize_t i=0; i < ids->size; i++) {
+ Py_XINCREF(ids->array[i]);
+ }
+#endif /* Py_DEBUG */
clear_interned_dict(interp);
}
diff --git a/Objects/weakrefobject.c b/Objects/weakrefobject.c
index 5a3e49a6fe45e3..c1afe63ecf66f6 100644
--- a/Objects/weakrefobject.c
+++ b/Objects/weakrefobject.c
@@ -170,10 +170,7 @@ weakref_repr(PyWeakReference *self)
}
Py_INCREF(obj);
- if (_PyObject_LookupAttr(obj, &_Py_ID(__name__), &name) < 0) {
- Py_DECREF(obj);
- return NULL;
- }
+ name = _PyObject_LookupSpecial(obj, &_Py_ID(__name__));
if (name == NULL || !PyUnicode_Check(name)) {
repr = PyUnicode_FromFormat(
"",
diff --git a/PC/clinic/winreg.c.h b/PC/clinic/winreg.c.h
index 7a9474301da8a1..4109c85276f0a4 100644
--- a/PC/clinic/winreg.c.h
+++ b/PC/clinic/winreg.c.h
@@ -219,14 +219,14 @@ winreg_ConnectRegistry(PyObject *module, PyObject *const *args, Py_ssize_t nargs
_PyArg_BadArgument("ConnectRegistry", "argument 1", "str or None", args[0]);
goto exit;
}
- if (!clinic_HKEY_converter(args[1], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[1], &key)) {
goto exit;
}
_return_value = winreg_ConnectRegistry_impl(module, computer_name, key);
if (_return_value == NULL) {
goto exit;
}
- return_value = PyHKEY_FromHKEY(_return_value);
+ return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);
exit:
/* Cleanup for computer_name */
@@ -275,7 +275,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("CreateKey", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -295,7 +295,7 @@ winreg_CreateKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (_return_value == NULL) {
goto exit;
}
- return_value = PyHKEY_FromHKEY(_return_value);
+ return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);
exit:
/* Cleanup for sub_key */
@@ -382,7 +382,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py
if (!args) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -419,7 +419,7 @@ winreg_CreateKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py
if (_return_value == NULL) {
goto exit;
}
- return_value = PyHKEY_FromHKEY(_return_value);
+ return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);
exit:
/* Cleanup for sub_key */
@@ -466,7 +466,7 @@ winreg_DeleteKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("DeleteKey", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (!PyUnicode_Check(args[1])) {
@@ -566,7 +566,7 @@ winreg_DeleteKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, Py
if (!args) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (!PyUnicode_Check(args[1])) {
@@ -634,7 +634,7 @@ winreg_DeleteValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("DeleteValue", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -694,7 +694,7 @@ winreg_EnumKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("EnumKey", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
index = _PyLong_AsInt(args[1]);
@@ -751,7 +751,7 @@ winreg_EnumValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("EnumValue", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
index = _PyLong_AsInt(args[1]);
@@ -839,7 +839,7 @@ winreg_FlushKey(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
HKEY key;
- if (!clinic_HKEY_converter(arg, &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) {
goto exit;
}
return_value = winreg_FlushKey_impl(module, key);
@@ -898,7 +898,7 @@ winreg_LoadKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("LoadKey", nargs, 3, 3)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (!PyUnicode_Check(args[1])) {
@@ -999,7 +999,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje
if (!args) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1036,7 +1036,7 @@ winreg_OpenKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObje
if (_return_value == NULL) {
goto exit;
}
- return_value = PyHKEY_FromHKEY(_return_value);
+ return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);
exit:
/* Cleanup for sub_key */
@@ -1116,7 +1116,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb
if (!args) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1153,7 +1153,7 @@ winreg_OpenKeyEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyOb
if (_return_value == NULL) {
goto exit;
}
- return_value = PyHKEY_FromHKEY(_return_value);
+ return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);
exit:
/* Cleanup for sub_key */
@@ -1193,7 +1193,7 @@ winreg_QueryInfoKey(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
HKEY key;
- if (!clinic_HKEY_converter(arg, &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) {
goto exit;
}
return_value = winreg_QueryInfoKey_impl(module, key);
@@ -1242,7 +1242,7 @@ winreg_QueryValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("QueryValue", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1303,7 +1303,7 @@ winreg_QueryValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("QueryValueEx", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1369,7 +1369,7 @@ winreg_SaveKey(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("SaveKey", nargs, 2, 2)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (!PyUnicode_Check(args[1])) {
@@ -1438,7 +1438,7 @@ winreg_SetValue(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("SetValue", nargs, 4, 4)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1542,7 +1542,7 @@ winreg_SetValueEx(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
if (!_PyArg_CheckPositional("SetValueEx", nargs, 5, 5)) {
goto exit;
}
- if (!clinic_HKEY_converter(args[0], &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), args[0], &key)) {
goto exit;
}
if (args[1] == Py_None) {
@@ -1603,7 +1603,7 @@ winreg_DisableReflectionKey(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
HKEY key;
- if (!clinic_HKEY_converter(arg, &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) {
goto exit;
}
return_value = winreg_DisableReflectionKey_impl(module, key);
@@ -1641,7 +1641,7 @@ winreg_EnableReflectionKey(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
HKEY key;
- if (!clinic_HKEY_converter(arg, &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) {
goto exit;
}
return_value = winreg_EnableReflectionKey_impl(module, key);
@@ -1677,7 +1677,7 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg)
PyObject *return_value = NULL;
HKEY key;
- if (!clinic_HKEY_converter(arg, &key)) {
+ if (!clinic_HKEY_converter(_PyModule_GetState(module), arg, &key)) {
goto exit;
}
return_value = winreg_QueryReflectionKey_impl(module, key);
@@ -1795,4 +1795,4 @@ winreg_QueryReflectionKey(PyObject *module, PyObject *arg)
#ifndef WINREG_QUERYREFLECTIONKEY_METHODDEF
#define WINREG_QUERYREFLECTIONKEY_METHODDEF
#endif /* !defined(WINREG_QUERYREFLECTIONKEY_METHODDEF) */
-/*[clinic end generated code: output=715db416dc1321ee input=a9049054013a1b77]*/
+/*[clinic end generated code: output=15dc2e6c4d4e2ad5 input=a9049054013a1b77]*/
diff --git a/PC/layout/support/pip.py b/PC/layout/support/pip.py
index c54acb250a252e..0a6582acf348a3 100644
--- a/PC/layout/support/pip.py
+++ b/PC/layout/support/pip.py
@@ -67,7 +67,6 @@ def extract_pip_files(ns):
"--no-color",
"install",
"pip",
- "setuptools",
"--upgrade",
"--target",
str(dest),
diff --git a/PC/msvcrtmodule.c b/PC/msvcrtmodule.c
index face4d03af9d4f..090254befc934d 100644
--- a/PC/msvcrtmodule.c
+++ b/PC/msvcrtmodule.c
@@ -564,110 +564,115 @@ static struct PyMethodDef msvcrt_functions[] = {
{NULL, NULL}
};
-
-static struct PyModuleDef msvcrtmodule = {
- PyModuleDef_HEAD_INIT,
- "msvcrt",
- NULL,
- -1,
- msvcrt_functions,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-static void
-insertint(PyObject *d, char *name, int value)
-{
- PyObject *v = PyLong_FromLong((long) value);
- if (v == NULL) {
- /* Don't bother reporting this error */
- PyErr_Clear();
- }
- else {
- PyDict_SetItemString(d, name, v);
- Py_DECREF(v);
- }
-}
-
-static void
-insertptr(PyObject *d, char *name, void *value)
+static int
+insertptr(PyObject *mod, char *name, void *value)
{
PyObject *v = PyLong_FromVoidPtr(value);
if (v == NULL) {
- /* Don't bother reporting this error */
- PyErr_Clear();
- }
- else {
- PyDict_SetItemString(d, name, v);
- Py_DECREF(v);
+ return -1;
}
+ int rc = PyModule_AddObjectRef(mod, name, v);
+ Py_DECREF(v);
+ return rc;
}
-PyMODINIT_FUNC
-PyInit_msvcrt(void)
-{
- int st;
- PyObject *d, *version;
- PyObject *m = PyModule_Create(&msvcrtmodule);
- if (m == NULL)
- return NULL;
- d = PyModule_GetDict(m);
+#define INSERTINT(MOD, NAME, VAL) do { \
+ if (PyModule_AddIntConstant(MOD, NAME, VAL) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
+#define INSERTPTR(MOD, NAME, PTR) do { \
+ if (insertptr(MOD, NAME, PTR) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
+#define INSERTSTR(MOD, NAME, CONST) do { \
+ if (PyModule_AddStringConstant(MOD, NAME, CONST) < 0) { \
+ return -1; \
+ } \
+} while (0)
+static int
+exec_module(PyObject* m)
+{
/* constants for the locking() function's mode argument */
- insertint(d, "LK_LOCK", _LK_LOCK);
- insertint(d, "LK_NBLCK", _LK_NBLCK);
- insertint(d, "LK_NBRLCK", _LK_NBRLCK);
- insertint(d, "LK_RLCK", _LK_RLCK);
- insertint(d, "LK_UNLCK", _LK_UNLCK);
+ INSERTINT(m, "LK_LOCK", _LK_LOCK);
+ INSERTINT(m, "LK_NBLCK", _LK_NBLCK);
+ INSERTINT(m, "LK_NBRLCK", _LK_NBRLCK);
+ INSERTINT(m, "LK_RLCK", _LK_RLCK);
+ INSERTINT(m, "LK_UNLCK", _LK_UNLCK);
#ifdef MS_WINDOWS_DESKTOP
- insertint(d, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS);
- insertint(d, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT);
- insertint(d, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX);
- insertint(d, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX);
+ INSERTINT(m, "SEM_FAILCRITICALERRORS", SEM_FAILCRITICALERRORS);
+ INSERTINT(m, "SEM_NOALIGNMENTFAULTEXCEPT", SEM_NOALIGNMENTFAULTEXCEPT);
+ INSERTINT(m, "SEM_NOGPFAULTERRORBOX", SEM_NOGPFAULTERRORBOX);
+ INSERTINT(m, "SEM_NOOPENFILEERRORBOX", SEM_NOOPENFILEERRORBOX);
#endif
#ifdef _DEBUG
- insertint(d, "CRT_WARN", _CRT_WARN);
- insertint(d, "CRT_ERROR", _CRT_ERROR);
- insertint(d, "CRT_ASSERT", _CRT_ASSERT);
- insertint(d, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG);
- insertint(d, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
- insertint(d, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW);
- insertint(d, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE);
- insertptr(d, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR);
- insertptr(d, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT);
- insertptr(d, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE);
+ INSERTINT(m, "CRT_WARN", _CRT_WARN);
+ INSERTINT(m, "CRT_ERROR", _CRT_ERROR);
+ INSERTINT(m, "CRT_ASSERT", _CRT_ASSERT);
+ INSERTINT(m, "CRTDBG_MODE_DEBUG", _CRTDBG_MODE_DEBUG);
+ INSERTINT(m, "CRTDBG_MODE_FILE", _CRTDBG_MODE_FILE);
+ INSERTINT(m, "CRTDBG_MODE_WNDW", _CRTDBG_MODE_WNDW);
+ INSERTINT(m, "CRTDBG_REPORT_MODE", _CRTDBG_REPORT_MODE);
+ INSERTPTR(m, "CRTDBG_FILE_STDERR", _CRTDBG_FILE_STDERR);
+ INSERTPTR(m, "CRTDBG_FILE_STDOUT", _CRTDBG_FILE_STDOUT);
+ INSERTPTR(m, "CRTDBG_REPORT_FILE", _CRTDBG_REPORT_FILE);
#endif
+#undef INSERTINT
+#undef INSERTPTR
+
/* constants for the crt versions */
#ifdef _VC_ASSEMBLY_PUBLICKEYTOKEN
- st = PyModule_AddStringConstant(m, "VC_ASSEMBLY_PUBLICKEYTOKEN",
- _VC_ASSEMBLY_PUBLICKEYTOKEN);
- if (st < 0) return NULL;
+ INSERTSTR(m, "VC_ASSEMBLY_PUBLICKEYTOKEN", _VC_ASSEMBLY_PUBLICKEYTOKEN);
#endif
#ifdef _CRT_ASSEMBLY_VERSION
- st = PyModule_AddStringConstant(m, "CRT_ASSEMBLY_VERSION",
- _CRT_ASSEMBLY_VERSION);
- if (st < 0) return NULL;
+ INSERTSTR(m, "CRT_ASSEMBLY_VERSION", _CRT_ASSEMBLY_VERSION);
#endif
#ifdef __LIBRARIES_ASSEMBLY_NAME_PREFIX
- st = PyModule_AddStringConstant(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
- __LIBRARIES_ASSEMBLY_NAME_PREFIX);
- if (st < 0) return NULL;
+ INSERTSTR(m, "LIBRARIES_ASSEMBLY_NAME_PREFIX",
+ __LIBRARIES_ASSEMBLY_NAME_PREFIX);
#endif
+#undef INSERTSTR
+
/* constants for the 2010 crt versions */
#if defined(_VC_CRT_MAJOR_VERSION) && defined (_VC_CRT_MINOR_VERSION) && defined(_VC_CRT_BUILD_VERSION) && defined(_VC_CRT_RBUILD_VERSION)
- version = PyUnicode_FromFormat("%d.%d.%d.%d", _VC_CRT_MAJOR_VERSION,
- _VC_CRT_MINOR_VERSION,
- _VC_CRT_BUILD_VERSION,
- _VC_CRT_RBUILD_VERSION);
- st = PyModule_AddObject(m, "CRT_ASSEMBLY_VERSION", version);
- if (st < 0) return NULL;
+ PyObject *version = PyUnicode_FromFormat("%d.%d.%d.%d",
+ _VC_CRT_MAJOR_VERSION,
+ _VC_CRT_MINOR_VERSION,
+ _VC_CRT_BUILD_VERSION,
+ _VC_CRT_RBUILD_VERSION);
+ if (version == NULL) {
+ return -1;
+ }
+ int st = PyModule_AddObjectRef(m, "CRT_ASSEMBLY_VERSION", version);
+ Py_DECREF(version);
+ if (st < 0) {
+ return -1;
+ }
#endif
- /* make compiler warning quiet if st is unused */
- (void)st;
- return m;
+ return 0;
+}
+
+static PyModuleDef_Slot msvcrt_slots[] = {
+ {Py_mod_exec, exec_module},
+ {0, NULL}
+};
+
+static struct PyModuleDef msvcrtmodule = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "msvcrt",
+ .m_methods = msvcrt_functions,
+ .m_slots = msvcrt_slots,
+};
+
+PyMODINIT_FUNC
+PyInit_msvcrt(void)
+{
+ return PyModuleDef_Init(&msvcrtmodule);
}
diff --git a/PC/winreg.c b/PC/winreg.c
index 073598a12a68aa..4884125c3609ad 100644
--- a/PC/winreg.c
+++ b/PC/winreg.c
@@ -15,15 +15,22 @@
#define PY_SSIZE_T_CLEAN
#include "Python.h"
#include "pycore_object.h" // _PyObject_Init()
+#include "pycore_moduleobject.h"
#include "structmember.h" // PyMemberDef
#include
#if defined(MS_WINDOWS_DESKTOP) || defined(MS_WINDOWS_SYSTEM) || defined(MS_WINDOWS_GAMES)
-static BOOL PyHKEY_AsHKEY(PyObject *ob, HKEY *pRes, BOOL bNoneOK);
-static BOOL clinic_HKEY_converter(PyObject *ob, void *p);
-static PyObject *PyHKEY_FromHKEY(HKEY h);
-static BOOL PyHKEY_Close(PyObject *obHandle);
+typedef struct {
+ PyTypeObject *PyHKEY_Type;
+} winreg_state;
+
+/* Forward declares */
+
+static BOOL PyHKEY_AsHKEY(winreg_state *st, PyObject *ob, HKEY *pRes, BOOL bNoneOK);
+static BOOL clinic_HKEY_converter(winreg_state *st, PyObject *ob, void *p);
+static PyObject *PyHKEY_FromHKEY(winreg_state *st, HKEY h);
+static BOOL PyHKEY_Close(winreg_state *st, PyObject *obHandle);
static char errNotAHandle[] = "Object is not a handle";
@@ -35,8 +42,6 @@ static char errNotAHandle[] = "Object is not a handle";
#define PyErr_SetFromWindowsErrWithFunction(rc, fnname) \
PyErr_SetFromWindowsErr(rc)
-/* Forward declares */
-
/* Doc strings */
PyDoc_STRVAR(module_doc,
"This module provides access to the Windows registry API.\n"
@@ -114,7 +119,7 @@ typedef struct {
HKEY hkey;
} PyHKEYObject;
-#define PyHKEY_Check(op) Py_IS_TYPE(op, &PyHKEY_Type)
+#define PyHKEY_Check(st, op) Py_IS_TYPE(op, st->PyHKEY_Type)
static char *failMsg = "bad operand type";
@@ -147,7 +152,18 @@ PyHKEY_deallocFunc(PyObject *ob)
PyHKEYObject *obkey = (PyHKEYObject *)ob;
if (obkey->hkey)
RegCloseKey((HKEY)obkey->hkey);
- PyObject_Free(ob);
+
+ PyTypeObject *tp = Py_TYPE(ob);
+ PyObject_GC_UnTrack(ob);
+ PyObject_GC_Del(ob);
+ Py_DECREF(tp);
+}
+
+static int
+PyHKEY_traverseFunc(PyHKEYObject *self, visitproc visit, void *arg)
+{
+ Py_VISIT(Py_TYPE(self));
+ return 0;
}
static int
@@ -189,29 +205,6 @@ PyHKEY_hashFunc(PyObject *ob)
}
-static PyNumberMethods PyHKEY_NumberMethods =
-{
- PyHKEY_binaryFailureFunc, /* nb_add */
- PyHKEY_binaryFailureFunc, /* nb_subtract */
- PyHKEY_binaryFailureFunc, /* nb_multiply */
- PyHKEY_binaryFailureFunc, /* nb_remainder */
- PyHKEY_binaryFailureFunc, /* nb_divmod */
- PyHKEY_ternaryFailureFunc, /* nb_power */
- PyHKEY_unaryFailureFunc, /* nb_negative */
- PyHKEY_unaryFailureFunc, /* nb_positive */
- PyHKEY_unaryFailureFunc, /* nb_absolute */
- PyHKEY_boolFunc, /* nb_bool */
- PyHKEY_unaryFailureFunc, /* nb_invert */
- PyHKEY_binaryFailureFunc, /* nb_lshift */
- PyHKEY_binaryFailureFunc, /* nb_rshift */
- PyHKEY_binaryFailureFunc, /* nb_and */
- PyHKEY_binaryFailureFunc, /* nb_xor */
- PyHKEY_binaryFailureFunc, /* nb_or */
- PyHKEY_intFunc, /* nb_int */
- 0, /* nb_reserved */
- PyHKEY_unaryFailureFunc, /* nb_float */
-};
-
/*[clinic input]
module winreg
class winreg.HKEYType "PyHKEYObject *" "&PyHKEY_Type"
@@ -229,6 +222,14 @@ class HKEY_converter(CConverter):
type = 'HKEY'
converter = 'clinic_HKEY_converter'
+ def parse_arg(self, argname, displayname):
+ return """
+ if (!{converter}(_PyModule_GetState(module), {argname}, &{paramname})) {{{{
+ goto exit;
+ }}}}
+ """.format(argname=argname, paramname=self.parser_name,
+ converter=self.converter)
+
class HKEY_return_converter(CReturnConverter):
type = 'HKEY'
@@ -236,7 +237,7 @@ class HKEY_return_converter(CReturnConverter):
self.declare(data)
self.err_occurred_if_null_pointer("_return_value", data)
data.return_conversion.append(
- 'return_value = PyHKEY_FromHKEY(_return_value);\n')
+ 'return_value = PyHKEY_FromHKEY(_PyModule_GetState(module), _return_value);\n')
# HACK: this only works for PyHKEYObjects, nothing else.
# Should this be generalized and enshrined in clinic.py,
@@ -249,7 +250,7 @@ class self_return_converter(CReturnConverter):
data.return_conversion.append(
'return_value = (PyObject *)_return_value;\n')
[python start generated code]*/
-/*[python end generated code: output=da39a3ee5e6b4b0d input=2ebb7a4922d408d6]*/
+/*[python end generated code: output=da39a3ee5e6b4b0d input=17e645060c7b8ae1]*/
#include "clinic/winreg.c.h"
@@ -270,8 +271,11 @@ static PyObject *
winreg_HKEYType_Close_impl(PyHKEYObject *self)
/*[clinic end generated code: output=fced3a624fb0c344 input=6786ac75f6b89de6]*/
{
- if (!PyHKEY_Close((PyObject *)self))
+ winreg_state *st = _PyType_GetModuleState(Py_TYPE(self));
+ assert(st != NULL);
+ if (!PyHKEY_Close(st, (PyObject *)self)) {
return NULL;
+ }
Py_RETURN_NONE;
}
@@ -327,8 +331,11 @@ winreg_HKEYType___exit___impl(PyHKEYObject *self, PyObject *exc_type,
PyObject *exc_value, PyObject *traceback)
/*[clinic end generated code: output=923ebe7389e6a263 input=fb32489ee92403c7]*/
{
- if (!PyHKEY_Close((PyObject *)self))
+ winreg_state *st = _PyType_GetModuleState(Py_TYPE(self));
+ assert(st != NULL);
+ if (!PyHKEY_Close(st, (PyObject *)self)) {
return NULL;
+ }
Py_RETURN_NONE;
}
@@ -350,62 +357,71 @@ static PyMemberDef PyHKEY_memberlist[] = {
{NULL} /* Sentinel */
};
-/* The type itself */
-PyTypeObject PyHKEY_Type =
-{
- PyVarObject_HEAD_INIT(0, 0) /* fill in type at module init */
- "PyHKEY",
- sizeof(PyHKEYObject),
- 0,
- PyHKEY_deallocFunc, /* tp_dealloc */
- 0, /* tp_vectorcall_offset */
- 0, /* tp_getattr */
- 0, /* tp_setattr */
- 0, /* tp_as_async */
- 0, /* tp_repr */
- &PyHKEY_NumberMethods, /* tp_as_number */
- 0, /* tp_as_sequence */
- 0, /* tp_as_mapping */
- PyHKEY_hashFunc, /* tp_hash */
- 0, /* tp_call */
- PyHKEY_strFunc, /* tp_str */
- 0, /* tp_getattro */
- 0, /* tp_setattro */
- 0, /* tp_as_buffer */
- 0, /* tp_flags */
- PyHKEY_doc, /* tp_doc */
- 0, /*tp_traverse*/
- 0, /*tp_clear*/
- 0, /*tp_richcompare*/
- 0, /*tp_weaklistoffset*/
- 0, /*tp_iter*/
- 0, /*tp_iternext*/
- PyHKEY_methods, /*tp_methods*/
- PyHKEY_memberlist, /*tp_members*/
+static PyType_Slot pyhkey_type_slots[] = {
+ {Py_tp_dealloc, PyHKEY_deallocFunc},
+ {Py_tp_members, PyHKEY_memberlist},
+ {Py_tp_methods, PyHKEY_methods},
+ {Py_tp_doc, (char *)PyHKEY_doc},
+ {Py_tp_traverse, PyHKEY_traverseFunc},
+ {Py_tp_hash, PyHKEY_hashFunc},
+ {Py_tp_str, PyHKEY_strFunc},
+
+ // Number protocol
+ {Py_nb_add, PyHKEY_binaryFailureFunc},
+ {Py_nb_subtract, PyHKEY_binaryFailureFunc},
+ {Py_nb_multiply, PyHKEY_binaryFailureFunc},
+ {Py_nb_remainder, PyHKEY_binaryFailureFunc},
+ {Py_nb_divmod, PyHKEY_binaryFailureFunc},
+ {Py_nb_power, PyHKEY_ternaryFailureFunc},
+ {Py_nb_negative, PyHKEY_unaryFailureFunc},
+ {Py_nb_positive, PyHKEY_unaryFailureFunc},
+ {Py_nb_absolute, PyHKEY_unaryFailureFunc},
+ {Py_nb_bool, PyHKEY_boolFunc},
+ {Py_nb_invert, PyHKEY_unaryFailureFunc},
+ {Py_nb_lshift, PyHKEY_binaryFailureFunc},
+ {Py_nb_rshift, PyHKEY_binaryFailureFunc},
+ {Py_nb_and, PyHKEY_binaryFailureFunc},
+ {Py_nb_xor, PyHKEY_binaryFailureFunc},
+ {Py_nb_or, PyHKEY_binaryFailureFunc},
+ {Py_nb_int, PyHKEY_intFunc},
+ {Py_nb_float, PyHKEY_unaryFailureFunc},
+ {0, NULL},
+};
+
+static PyType_Spec pyhkey_type_spec = {
+ .name = "winreg.PyHKEY",
+ .basicsize = sizeof(PyHKEYObject),
+ .flags = (Py_TPFLAGS_HAVE_GC | Py_TPFLAGS_IMMUTABLETYPE |
+ Py_TPFLAGS_DISALLOW_INSTANTIATION),
+ .slots = pyhkey_type_slots,
};
/************************************************************************
The public PyHKEY API (well, not public yet :-)
************************************************************************/
PyObject *
-PyHKEY_New(HKEY hInit)
+PyHKEY_New(PyObject *m, HKEY hInit)
{
- PyHKEYObject *key = PyObject_New(PyHKEYObject, &PyHKEY_Type);
- if (key)
- key->hkey = hInit;
+ winreg_state *st = _PyModule_GetState(m);
+ PyHKEYObject *key = PyObject_GC_New(PyHKEYObject, st->PyHKEY_Type);
+ if (key == NULL) {
+ return NULL;
+ }
+ key->hkey = hInit;
+ PyObject_GC_Track(key);
return (PyObject *)key;
}
BOOL
-PyHKEY_Close(PyObject *ob_handle)
+PyHKEY_Close(winreg_state *st, PyObject *ob_handle)
{
LONG rc;
HKEY key;
- if (!PyHKEY_AsHKEY(ob_handle, &key, TRUE)) {
+ if (!PyHKEY_AsHKEY(st, ob_handle, &key, TRUE)) {
return FALSE;
}
- if (PyHKEY_Check(ob_handle)) {
+ if (PyHKEY_Check(st, ob_handle)) {
((PyHKEYObject*)ob_handle)->hkey = 0;
}
rc = key ? RegCloseKey(key) : ERROR_SUCCESS;
@@ -415,7 +431,7 @@ PyHKEY_Close(PyObject *ob_handle)
}
BOOL
-PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK)
+PyHKEY_AsHKEY(winreg_state *st, PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK)
{
if (ob == Py_None) {
if (!bNoneOK) {
@@ -426,7 +442,7 @@ PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK)
}
*pHANDLE = (HKEY)0;
}
- else if (PyHKEY_Check(ob)) {
+ else if (PyHKEY_Check(st ,ob)) {
PyHKEYObject *pH = (PyHKEYObject *)ob;
*pHANDLE = pH->hkey;
}
@@ -447,23 +463,24 @@ PyHKEY_AsHKEY(PyObject *ob, HKEY *pHANDLE, BOOL bNoneOK)
}
BOOL
-clinic_HKEY_converter(PyObject *ob, void *p)
+clinic_HKEY_converter(winreg_state *st, PyObject *ob, void *p)
{
- if (!PyHKEY_AsHKEY(ob, (HKEY *)p, FALSE))
+ if (!PyHKEY_AsHKEY(st, ob, (HKEY *)p, FALSE)) {
return FALSE;
+ }
return TRUE;
}
PyObject *
-PyHKEY_FromHKEY(HKEY h)
+PyHKEY_FromHKEY(winreg_state *st, HKEY h)
{
- /* Inline PyObject_New */
- PyHKEYObject *op = (PyHKEYObject *) PyObject_Malloc(sizeof(PyHKEYObject));
+ PyHKEYObject *op = (PyHKEYObject *)PyObject_GC_New(PyHKEYObject,
+ st->PyHKEY_Type);
if (op == NULL) {
- return PyErr_NoMemory();
+ return NULL;
}
- _PyObject_Init((PyObject*)op, &PyHKEY_Type);
op->hkey = h;
+ PyObject_GC_Track(op);
return (PyObject *)op;
}
@@ -472,11 +489,11 @@ PyHKEY_FromHKEY(HKEY h)
The module methods
************************************************************************/
BOOL
-PyWinObject_CloseHKEY(PyObject *obHandle)
+PyWinObject_CloseHKEY(winreg_state *st, PyObject *obHandle)
{
BOOL ok;
- if (PyHKEY_Check(obHandle)) {
- ok = PyHKEY_Close(obHandle);
+ if (PyHKEY_Check(st, obHandle)) {
+ ok = PyHKEY_Close(st, obHandle);
}
#if SIZEOF_LONG >= SIZEOF_HKEY
else if (PyLong_Check(obHandle)) {
@@ -826,8 +843,9 @@ static PyObject *
winreg_CloseKey(PyObject *module, PyObject *hkey)
/*[clinic end generated code: output=a4fa537019a80d15 input=5b1aac65ba5127ad]*/
{
- if (!PyHKEY_Close(hkey))
+ if (!PyHKEY_Close(_PyModule_GetState(module), hkey)) {
return NULL;
+ }
Py_RETURN_NONE;
}
@@ -2059,57 +2077,46 @@ static struct PyMethodDef winreg_methods[] = {
NULL,
};
-static void
-insint(PyObject * d, char * name, long value)
-{
- PyObject *v = PyLong_FromLong(value);
- if (!v || PyDict_SetItemString(d, name, v))
- PyErr_Clear();
- Py_XDECREF(v);
-}
-
-#define ADD_INT(val) insint(d, #val, val)
+#define ADD_INT(VAL) do { \
+ if (PyModule_AddIntConstant(m, #VAL, VAL) < 0) { \
+ return -1; \
+ } \
+} while (0)
-static void
-inskey(PyObject * d, char * name, HKEY key)
+static int
+inskey(PyObject *mod, char *name, HKEY key)
{
PyObject *v = PyLong_FromVoidPtr(key);
- if (!v || PyDict_SetItemString(d, name, v))
- PyErr_Clear();
- Py_XDECREF(v);
+ if (v == NULL) {
+ return -1;
+ }
+ int rc = PyModule_AddObjectRef(mod, name, v);
+ Py_DECREF(v);
+ return rc;
}
-#define ADD_KEY(val) inskey(d, #val, val)
+#define ADD_KEY(VAL) do { \
+ if (inskey(m, #VAL, VAL) < 0) { \
+ return -1; \
+ } \
+} while (0)
-
-static struct PyModuleDef winregmodule = {
- PyModuleDef_HEAD_INIT,
- "winreg",
- module_doc,
- -1,
- winreg_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-PyMODINIT_FUNC PyInit_winreg(void)
+static int
+exec_module(PyObject *m)
{
- PyObject *m, *d;
- m = PyModule_Create(&winregmodule);
- if (m == NULL)
- return NULL;
- d = PyModule_GetDict(m);
- PyHKEY_Type.tp_doc = PyHKEY_doc;
- if (PyType_Ready(&PyHKEY_Type) < 0)
- return NULL;
- if (PyDict_SetItemString(d, "HKEYType",
- (PyObject *)&PyHKEY_Type) != 0)
- return NULL;
- if (PyDict_SetItemString(d, "error",
- PyExc_OSError) != 0)
- return NULL;
+ winreg_state *st = (winreg_state *)_PyModule_GetState(m);
+
+ st->PyHKEY_Type = (PyTypeObject *)
+ PyType_FromModuleAndSpec(m, &pyhkey_type_spec, NULL);
+ if (st->PyHKEY_Type == NULL) {
+ return -1;
+ }
+ if (PyModule_AddObjectRef(m, "HKEYType", (PyObject *)st->PyHKEY_Type) < 0) {
+ return -1;
+ }
+ if (PyModule_AddObjectRef(m, "error", PyExc_OSError) < 0) {
+ return -1;
+ }
/* Add the relevant constants */
ADD_KEY(HKEY_CLASSES_ROOT);
@@ -2170,7 +2177,46 @@ PyMODINIT_FUNC PyInit_winreg(void)
ADD_INT(REG_RESOURCE_LIST);
ADD_INT(REG_FULL_RESOURCE_DESCRIPTOR);
ADD_INT(REG_RESOURCE_REQUIREMENTS_LIST);
- return m;
+
+#undef ADD_INT
+ return 0;
+}
+
+static PyModuleDef_Slot winreg_slots[] = {
+ {Py_mod_exec, exec_module},
+ {0, NULL}
+};
+
+static int
+winreg_traverse(PyObject *module, visitproc visit, void *arg)
+{
+ winreg_state *state = _PyModule_GetState(module);
+ Py_VISIT(state->PyHKEY_Type);
+ return 0;
+}
+
+static int
+winreg_clear(PyObject *module)
+{
+ winreg_state *state = _PyModule_GetState(module);
+ Py_CLEAR(state->PyHKEY_Type);
+ return 0;
+}
+
+static struct PyModuleDef winregmodule = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "winreg",
+ .m_doc = module_doc,
+ .m_size = sizeof(winreg_state),
+ .m_methods = winreg_methods,
+ .m_slots = winreg_slots,
+ .m_traverse = winreg_traverse,
+ .m_clear = winreg_clear,
+};
+
+PyMODINIT_FUNC PyInit_winreg(void)
+{
+ return PyModuleDef_Init(&winregmodule);
}
#endif /* MS_WINDOWS_DESKTOP || MS_WINDOWS_SYSTEM || MS_WINDOWS_GAMES */
diff --git a/PC/winsound.c b/PC/winsound.c
index 65025ddc5e1f51..17ce2ef423b1f9 100644
--- a/PC/winsound.c
+++ b/PC/winsound.c
@@ -202,42 +202,15 @@ static struct PyMethodDef sound_methods[] =
{NULL, NULL}
};
-static void
-add_define(PyObject *dict, const char *key, long value)
+#define ADD_DEFINE(CONST) do { \
+ if (PyModule_AddIntConstant(module, #CONST, CONST) < 0) { \
+ return -1; \
+ } \
+} while (0)
+
+static int
+exec_module(PyObject *module)
{
- PyObject *k = PyUnicode_FromString(key);
- PyObject *v = PyLong_FromLong(value);
- if (v && k) {
- PyDict_SetItem(dict, k, v);
- }
- Py_XDECREF(k);
- Py_XDECREF(v);
-}
-
-#define ADD_DEFINE(tok) add_define(dict,#tok,tok)
-
-
-static struct PyModuleDef winsoundmodule = {
- PyModuleDef_HEAD_INIT,
- "winsound",
- sound_module_doc,
- -1,
- sound_methods,
- NULL,
- NULL,
- NULL,
- NULL
-};
-
-PyMODINIT_FUNC
-PyInit_winsound(void)
-{
- PyObject *dict;
- PyObject *module = PyModule_Create(&winsoundmodule);
- if (module == NULL)
- return NULL;
- dict = PyModule_GetDict(module);
-
ADD_DEFINE(SND_ASYNC);
ADD_DEFINE(SND_NODEFAULT);
ADD_DEFINE(SND_NOSTOP);
@@ -254,5 +227,27 @@ PyInit_winsound(void)
ADD_DEFINE(MB_ICONEXCLAMATION);
ADD_DEFINE(MB_ICONHAND);
ADD_DEFINE(MB_ICONQUESTION);
- return module;
+
+#undef ADD_DEFINE
+
+ return 0;
+}
+
+static PyModuleDef_Slot sound_slots[] = {
+ {Py_mod_exec, exec_module},
+ {0, NULL}
+};
+
+static struct PyModuleDef winsoundmodule = {
+ .m_base = PyModuleDef_HEAD_INIT,
+ .m_name = "winsound",
+ .m_doc = sound_module_doc,
+ .m_methods = sound_methods,
+ .m_slots = sound_slots,
+};
+
+PyMODINIT_FUNC
+PyInit_winsound(void)
+{
+ return PyModuleDef_Init(&winsoundmodule);
}
diff --git a/PCbuild/_freeze_module.vcxproj b/PCbuild/_freeze_module.vcxproj
index 28eced6d4b2862..d897925f58c0de 100644
--- a/PCbuild/_freeze_module.vcxproj
+++ b/PCbuild/_freeze_module.vcxproj
@@ -177,13 +177,13 @@
+
-
@@ -192,6 +192,7 @@
+
@@ -208,6 +209,8 @@
+
+
diff --git a/PCbuild/_freeze_module.vcxproj.filters b/PCbuild/_freeze_module.vcxproj.filters
index e4faa89bb831d9..176935a63c4852 100644
--- a/PCbuild/_freeze_module.vcxproj.filters
+++ b/PCbuild/_freeze_module.vcxproj.filters
@@ -28,6 +28,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -76,9 +79,6 @@
Source Files
-
- Source Files
-
Source Files
@@ -142,6 +142,9 @@
Source Files
+
+ Source Files
+
Source Files
@@ -211,6 +214,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
Source Files
diff --git a/PCbuild/find_python.bat b/PCbuild/find_python.bat
index 11d6cba7a172c9..7af5503d80a0fc 100644
--- a/PCbuild/find_python.bat
+++ b/PCbuild/find_python.bat
@@ -42,7 +42,7 @@
@if NOT "%HOST_PYTHON%"=="" @%HOST_PYTHON% -Ec "import sys; assert sys.version_info[:2] >= (3, 9)" >nul 2>nul && (set PYTHON="%HOST_PYTHON%") && (set _Py_Python_Source=found as HOST_PYTHON) && goto :found
@rem If py.exe finds a recent enough version, use that one
-@for %%p in (3.10 3.9) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found
+@for %%p in (3.11 3.10 3.9) do @py -%%p -EV >nul 2>&1 && (set PYTHON=py -%%p) && (set _Py_Python_Source=found %%p with py.exe) && goto :found
@if NOT exist "%_Py_EXTERNALS_DIR%" mkdir "%_Py_EXTERNALS_DIR%"
@set _Py_NUGET=%NUGET%
diff --git a/PCbuild/pythoncore.vcxproj b/PCbuild/pythoncore.vcxproj
index 29f32db579fa40..8aafcb786a6064 100644
--- a/PCbuild/pythoncore.vcxproj
+++ b/PCbuild/pythoncore.vcxproj
@@ -500,13 +500,13 @@
+
-
@@ -514,6 +514,7 @@
+
@@ -531,6 +532,8 @@
+
+
diff --git a/PCbuild/pythoncore.vcxproj.filters b/PCbuild/pythoncore.vcxproj.filters
index 6a622fd93930ad..07476f30833372 100644
--- a/PCbuild/pythoncore.vcxproj.filters
+++ b/PCbuild/pythoncore.vcxproj.filters
@@ -1094,6 +1094,9 @@
Python
+
+ Python
+
Python
@@ -1109,9 +1112,6 @@
Python
-
- Python
-
Python
@@ -1130,6 +1130,9 @@
Python
+
+ Python
+
Python
@@ -1175,6 +1178,12 @@
Source Files
+
+ Source Files
+
+
+ Source Files
+
Python
diff --git a/Parser/action_helpers.c b/Parser/action_helpers.c
index 682daaca991d4f..cf07e6ea8d05f1 100644
--- a/Parser/action_helpers.c
+++ b/Parser/action_helpers.c
@@ -1,6 +1,7 @@
#include
#include "pegen.h"
+#include "tokenizer.h"
#include "string_parser.h"
#include "pycore_runtime.h" // _PyRuntime
@@ -856,96 +857,6 @@ _PyPegen_seq_delete_starred_exprs(Parser *p, asdl_seq *kwargs)
return new_seq;
}
-expr_ty
-_PyPegen_concatenate_strings(Parser *p, asdl_seq *strings)
-{
- Py_ssize_t len = asdl_seq_LEN(strings);
- assert(len > 0);
-
- Token *first = asdl_seq_GET_UNTYPED(strings, 0);
- Token *last = asdl_seq_GET_UNTYPED(strings, len - 1);
-
- int bytesmode = 0;
- PyObject *bytes_str = NULL;
-
- FstringParser state;
- _PyPegen_FstringParser_Init(&state);
-
- for (Py_ssize_t i = 0; i < len; i++) {
- Token *t = asdl_seq_GET_UNTYPED(strings, i);
-
- int this_bytesmode;
- int this_rawmode;
- PyObject *s;
- const char *fstr;
- Py_ssize_t fstrlen = -1;
-
- if (_PyPegen_parsestr(p, &this_bytesmode, &this_rawmode, &s, &fstr, &fstrlen, t) != 0) {
- goto error;
- }
-
- /* Check that we are not mixing bytes with unicode. */
- if (i != 0 && bytesmode != this_bytesmode) {
- RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals");
- Py_XDECREF(s);
- goto error;
- }
- bytesmode = this_bytesmode;
-
- if (fstr != NULL) {
- assert(s == NULL && !bytesmode);
-
- int result = _PyPegen_FstringParser_ConcatFstring(p, &state, &fstr, fstr + fstrlen,
- this_rawmode, 0, first, t, last);
- if (result < 0) {
- goto error;
- }
- }
- else {
- /* String or byte string. */
- assert(s != NULL && fstr == NULL);
- assert(bytesmode ? PyBytes_CheckExact(s) : PyUnicode_CheckExact(s));
-
- if (bytesmode) {
- if (i == 0) {
- bytes_str = s;
- }
- else {
- PyBytes_ConcatAndDel(&bytes_str, s);
- if (!bytes_str) {
- goto error;
- }
- }
- }
- else {
- /* This is a regular string. Concatenate it. */
- if (_PyPegen_FstringParser_ConcatAndDel(&state, s) < 0) {
- goto error;
- }
- }
- }
- }
-
- if (bytesmode) {
- if (_PyArena_AddPyObject(p->arena, bytes_str) < 0) {
- goto error;
- }
- return _PyAST_Constant(bytes_str, NULL, first->lineno,
- first->col_offset, last->end_lineno,
- last->end_col_offset, p->arena);
- }
-
- return _PyPegen_FstringParser_Finish(p, &state, first, last);
-
-error:
- Py_XDECREF(bytes_str);
- _PyPegen_FstringParser_Dealloc(&state);
- if (PyErr_Occurred()) {
- _Pypegen_raise_decode_error(p);
- }
- return NULL;
-}
-
expr_ty
_PyPegen_ensure_imaginary(Parser *p, expr_ty exp)
{
@@ -1057,6 +968,18 @@ _PyPegen_check_legacy_stmt(Parser *p, expr_ty name) {
return 0;
}
+expr_ty
+_PyPegen_check_fstring_conversion(Parser *p, Token* symbol, expr_ty conv) {
+ if (symbol->lineno != conv->lineno || symbol->end_col_offset != conv->col_offset) {
+ return RAISE_SYNTAX_ERROR_KNOWN_RANGE(
+ symbol, conv,
+ "f-string: conversion type must come right after the exclamanation mark"
+ );
+ }
+ return conv;
+}
+
+
const char *
_PyPegen_get_expr_name(expr_ty e)
{
@@ -1274,3 +1197,439 @@ _PyPegen_nonparen_genexp_in_call(Parser *p, expr_ty args, asdl_comprehension_seq
"Generator expression must be parenthesized"
);
}
+
+// Fstring stuff
+
+static expr_ty
+decode_fstring_buffer(Parser *p, int lineno, int col_offset, int end_lineno,
+ int end_col_offset)
+{
+ tokenizer_mode *tok_mode = &(p->tok->tok_mode_stack[p->tok->tok_mode_stack_index]);
+ assert(tok_mode->last_expr_buffer != NULL);
+ assert(tok_mode->last_expr_size >= 0 && tok_mode->last_expr_end >= 0);
+
+ PyObject *res = PyUnicode_DecodeUTF8(
+ tok_mode->last_expr_buffer,
+ tok_mode->last_expr_size - tok_mode->last_expr_end,
+ NULL
+ );
+ if (!res || _PyArena_AddPyObject(p->arena, res) < 0) {
+ Py_XDECREF(res);
+ return NULL;
+ }
+
+ return _PyAST_Constant(res, NULL, lineno, col_offset, end_lineno, end_col_offset, p->arena);
+}
+
+static expr_ty
+_PyPegen_decode_fstring_part(Parser* p, int is_raw, expr_ty constant) {
+ assert(PyUnicode_CheckExact(constant->v.Constant.value));
+
+ const char* bstr = PyUnicode_AsUTF8(constant->v.Constant.value);
+ if (bstr == NULL) {
+ return NULL;
+ }
+
+ size_t len;
+ if (strcmp(bstr, "{{") == 0 || strcmp(bstr, "}}") == 0) {
+ len = 1;
+ } else {
+ len = strlen(bstr);
+ }
+
+ is_raw = is_raw || strchr(bstr, '\\') == NULL;
+ PyObject *str = _PyPegen_decode_string(p, is_raw, bstr, len, NULL);
+ if (str == NULL) {
+ _Pypegen_raise_decode_error(p);
+ return NULL;
+ }
+ if (_PyArena_AddPyObject(p->arena, str) < 0) {
+ Py_DECREF(str);
+ return NULL;
+ }
+ return _PyAST_Constant(str, NULL, constant->lineno, constant->col_offset,
+ constant->end_lineno, constant->end_col_offset,
+ p->arena);
+}
+
+static asdl_expr_seq *
+unpack_top_level_joined_strs(Parser *p, asdl_expr_seq *raw_expressions)
+{
+ /* The parser might put multiple f-string values into an individual
+ * JoinedStr node at the top level due to stuff like f-string debugging
+ * expressions. This function flattens those and promotes them to the
+ * upper level. Only simplifies AST, but the compiler already takes care
+ * of the regular output, so this is not necessary if you are not going
+ * to expose the output AST to Python level. */
+
+ Py_ssize_t i, req_size, raw_size;
+
+ req_size = raw_size = asdl_seq_LEN(raw_expressions);
+ expr_ty expr;
+ for (i = 0; i < raw_size; i++) {
+ expr = asdl_seq_GET(raw_expressions, i);
+ if (expr->kind == JoinedStr_kind) {
+ req_size += asdl_seq_LEN(expr->v.JoinedStr.values) - 1;
+ }
+ }
+
+ asdl_expr_seq *expressions = _Py_asdl_expr_seq_new(req_size, p->arena);
+
+ Py_ssize_t raw_index, req_index = 0;
+ for (raw_index = 0; raw_index < raw_size; raw_index++) {
+ expr = asdl_seq_GET(raw_expressions, raw_index);
+ if (expr->kind == JoinedStr_kind) {
+ asdl_expr_seq *values = expr->v.JoinedStr.values;
+ for (Py_ssize_t n = 0; n < asdl_seq_LEN(values); n++) {
+ asdl_seq_SET(expressions, req_index, asdl_seq_GET(values, n));
+ req_index++;
+ }
+ } else {
+ asdl_seq_SET(expressions, req_index, expr);
+ req_index++;
+ }
+ }
+ return expressions;
+}
+
+expr_ty
+_PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* raw_expressions, Token*b) {
+ asdl_expr_seq *expr = unpack_top_level_joined_strs(p, raw_expressions);
+ Py_ssize_t n_items = asdl_seq_LEN(expr);
+
+ const char* quote_str = PyBytes_AsString(a->bytes);
+ if (quote_str == NULL) {
+ return NULL;
+ }
+ int is_raw = strpbrk(quote_str, "rR") != NULL;
+
+ asdl_expr_seq *seq = _Py_asdl_expr_seq_new(n_items, p->arena);
+ if (seq == NULL) {
+ return NULL;
+ }
+
+ Py_ssize_t index = 0;
+ for (Py_ssize_t i = 0; i < n_items; i++) {
+ expr_ty item = asdl_seq_GET(expr, i);
+ if (item->kind == Constant_kind) {
+ item = _PyPegen_decode_fstring_part(p, is_raw, item);
+ if (item == NULL) {
+ return NULL;
+ }
+
+ /* Tokenizer emits string parts even when the underlying string
+ might become an empty value (e.g. FSTRING_MIDDLE with the value \\n)
+ so we need to check for them and simplify it here. */
+ if (PyUnicode_CheckExact(item->v.Constant.value)
+ && PyUnicode_GET_LENGTH(item->v.Constant.value) == 0) {
+ continue;
+ }
+ }
+ asdl_seq_SET(seq, index++, item);
+ }
+
+ asdl_expr_seq *resized_exprs;
+ if (index != n_items) {
+ resized_exprs = _Py_asdl_expr_seq_new(index, p->arena);
+ if (resized_exprs == NULL) {
+ return NULL;
+ }
+ for (Py_ssize_t i = 0; i < index; i++) {
+ asdl_seq_SET(resized_exprs, i, asdl_seq_GET(seq, i));
+ }
+ }
+ else {
+ resized_exprs = seq;
+ }
+
+ return _PyAST_JoinedStr(resized_exprs, a->lineno, a->col_offset,
+ b->end_lineno, b->end_col_offset,
+ p->arena);
+}
+
+expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok) {
+ char* bstr = PyBytes_AsString(tok->bytes);
+ if (bstr == NULL) {
+ return NULL;
+ }
+ PyObject* str = PyUnicode_FromString(bstr);
+ if (str == NULL) {
+ return NULL;
+ }
+ if (_PyArena_AddPyObject(p->arena, str) < 0) {
+ Py_DECREF(str);
+ return NULL;
+ }
+ return _PyAST_Constant(str, NULL, tok->lineno, tok->col_offset,
+ tok->end_lineno, tok->end_col_offset,
+ p->arena);
+}
+
+expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok) {
+ char* the_str = PyBytes_AsString(tok->bytes);
+ if (the_str == NULL) {
+ return NULL;
+ }
+ PyObject *s = _PyPegen_parse_string(p, tok);
+ if (s == NULL) {
+ _Pypegen_raise_decode_error(p);
+ return NULL;
+ }
+ if (_PyArena_AddPyObject(p->arena, s) < 0) {
+ Py_DECREF(s);
+ return NULL;
+ }
+ PyObject *kind = NULL;
+ if (the_str && the_str[0] == 'u') {
+ kind = _PyPegen_new_identifier(p, "u");
+ if (kind == NULL) {
+ return NULL;
+ }
+ }
+ return _PyAST_Constant(s, kind, tok->lineno, tok->col_offset, tok->end_lineno, tok->end_col_offset, p->arena);
+}
+
+expr_ty _PyPegen_formatted_value(Parser *p, expr_ty expression, Token *debug, expr_ty conversion,
+ expr_ty format, int lineno, int col_offset, int end_lineno, int end_col_offset,
+ PyArena *arena) {
+ int conversion_val = -1;
+ if (conversion != NULL) {
+ assert(conversion->kind == Name_kind);
+ Py_UCS4 first = PyUnicode_READ_CHAR(conversion->v.Name.id, 0);
+
+ if (PyUnicode_GET_LENGTH(conversion->v.Name.id) > 1 ||
+ !(first == 's' || first == 'r' || first == 'a')) {
+ RAISE_SYNTAX_ERROR_KNOWN_LOCATION(conversion,
+ "f-string: invalid conversion character %R: expected 's', 'r', or 'a'",
+ conversion->v.Name.id);
+ return NULL;
+ }
+
+ conversion_val = Py_SAFE_DOWNCAST(first, Py_UCS4, int);
+ }
+ else if (debug && !format) {
+ /* If no conversion is specified, use !r for debug expressions */
+ conversion_val = (int)'r';
+ }
+
+ expr_ty formatted_value = _PyAST_FormattedValue(
+ expression, conversion_val, format,
+ lineno, col_offset, end_lineno,
+ end_col_offset, arena
+ );
+
+ if (debug) {
+ /* Find the non whitespace token after the "=" */
+ int debug_end_line, debug_end_offset;
+
+ if (conversion) {
+ debug_end_line = conversion->lineno;
+ debug_end_offset = conversion->col_offset;
+ }
+ else if (format) {
+ debug_end_line = format->lineno;
+ debug_end_offset = format->col_offset + 1; // HACK: ??
+ }
+ else {
+ debug_end_line = end_lineno;
+ debug_end_offset = end_col_offset;
+ }
+
+ expr_ty debug_text = decode_fstring_buffer(p, lineno, col_offset + 1,
+ debug_end_line, debug_end_offset - 1);
+ if (!debug_text) {
+ return NULL;
+ }
+
+ asdl_expr_seq *values = _Py_asdl_expr_seq_new(2, arena);
+ asdl_seq_SET(values, 0, debug_text);
+ asdl_seq_SET(values, 1, formatted_value);
+ return _PyAST_JoinedStr(values, lineno, col_offset, debug_end_line, debug_end_offset, p->arena);
+ }
+ else {
+ return formatted_value;
+ }
+}
+
+expr_ty
+_PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *strings,
+ int lineno, int col_offset, int end_lineno,
+ int end_col_offset, PyArena *arena)
+{
+ Py_ssize_t len = asdl_seq_LEN(strings);
+ assert(len > 0);
+
+ int f_string_found = 0;
+ int unicode_string_found = 0;
+ int bytes_found = 0;
+
+ Py_ssize_t i = 0;
+ Py_ssize_t n_flattened_elements = 0;
+ for (i = 0; i < len; i++) {
+ expr_ty elem = asdl_seq_GET(strings, i);
+ if (elem->kind == Constant_kind) {
+ if (PyBytes_CheckExact(elem->v.Constant.value)) {
+ bytes_found = 1;
+ } else {
+ unicode_string_found = 1;
+ }
+ n_flattened_elements++;
+ } else {
+ n_flattened_elements += asdl_seq_LEN(elem->v.JoinedStr.values);
+ f_string_found = 1;
+ }
+ }
+
+ if ((unicode_string_found || f_string_found) && bytes_found) {
+ RAISE_SYNTAX_ERROR("cannot mix bytes and nonbytes literals");
+ return NULL;
+ }
+
+ if (bytes_found) {
+ PyObject* res = PyBytes_FromString("");
+
+ /* Bytes literals never get a kind, but just for consistency
+ since they are represented as Constant nodes, we'll mirror
+ the same behavior as unicode strings for determining the
+ kind. */
+ PyObject* kind = asdl_seq_GET(strings, 0)->v.Constant.kind;
+ for (i = 0; i < len; i++) {
+ expr_ty elem = asdl_seq_GET(strings, i);
+ PyBytes_Concat(&res, elem->v.Constant.value);
+ }
+ if (!res || _PyArena_AddPyObject(arena, res) < 0) {
+ Py_XDECREF(res);
+ return NULL;
+ }
+ return _PyAST_Constant(res, kind, lineno, col_offset, end_lineno, end_col_offset, p->arena);
+ }
+
+ if (!f_string_found && len == 1) {
+ return asdl_seq_GET(strings, 0);
+ }
+
+ asdl_expr_seq* flattened = _Py_asdl_expr_seq_new(n_flattened_elements, p->arena);
+ if (flattened == NULL) {
+ return NULL;
+ }
+
+ /* build flattened list */
+ Py_ssize_t current_pos = 0;
+ Py_ssize_t j = 0;
+ for (i = 0; i < len; i++) {
+ expr_ty elem = asdl_seq_GET(strings, i);
+ if (elem->kind == Constant_kind) {
+ asdl_seq_SET(flattened, current_pos++, elem);
+ } else {
+ for (j = 0; j < asdl_seq_LEN(elem->v.JoinedStr.values); j++) {
+ expr_ty subvalue = asdl_seq_GET(elem->v.JoinedStr.values, j);
+ if (subvalue == NULL) {
+ return NULL;
+ }
+ asdl_seq_SET(flattened, current_pos++, subvalue);
+ }
+ }
+ }
+
+ /* calculate folded element count */
+ Py_ssize_t n_elements = 0;
+ int prev_is_constant = 0;
+ for (i = 0; i < n_flattened_elements; i++) {
+ expr_ty elem = asdl_seq_GET(flattened, i);
+
+ /* The concatenation of a FormattedValue and an empty Contant should
+ lead to the FormattedValue itself. Thus, we will not take any empty
+ constants into account, just as in `_PyPegen_joined_str` */
+ if (f_string_found && elem->kind == Constant_kind &&
+ PyUnicode_CheckExact(elem->v.Constant.value) &&
+ PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0)
+ continue;
+
+ if (!prev_is_constant || elem->kind != Constant_kind) {
+ n_elements++;
+ }
+ prev_is_constant = elem->kind == Constant_kind;
+ }
+
+ asdl_expr_seq* values = _Py_asdl_expr_seq_new(n_elements, p->arena);
+ if (values == NULL) {
+ return NULL;
+ }
+
+ /* build folded list */
+ _PyUnicodeWriter writer;
+ current_pos = 0;
+ for (i = 0; i < n_flattened_elements; i++) {
+ expr_ty elem = asdl_seq_GET(flattened, i);
+
+ /* if the current elem and the following are constants,
+ fold them and all consequent constants */
+ if (elem->kind == Constant_kind) {
+ if (i + 1 < n_flattened_elements &&
+ asdl_seq_GET(flattened, i + 1)->kind == Constant_kind) {
+ expr_ty first_elem = elem;
+
+ /* When a string is getting concatenated, the kind of the string
+ is determined by the first string in the concatenation
+ sequence.
+
+ u"abc" "def" -> u"abcdef"
+ "abc" u"abc" -> "abcabc" */
+ PyObject *kind = elem->v.Constant.kind;
+
+ _PyUnicodeWriter_Init(&writer);
+ expr_ty last_elem = elem;
+ for (j = i; j < n_flattened_elements; j++) {
+ expr_ty current_elem = asdl_seq_GET(flattened, j);
+ if (current_elem->kind == Constant_kind) {
+ if (_PyUnicodeWriter_WriteStr(
+ &writer, current_elem->v.Constant.value)) {
+ _PyUnicodeWriter_Dealloc(&writer);
+ return NULL;
+ }
+ last_elem = current_elem;
+ } else {
+ break;
+ }
+ }
+ i = j - 1;
+
+ PyObject *concat_str = _PyUnicodeWriter_Finish(&writer);
+ if (concat_str == NULL) {
+ _PyUnicodeWriter_Dealloc(&writer);
+ return NULL;
+ }
+ if (_PyArena_AddPyObject(p->arena, concat_str) < 0) {
+ Py_DECREF(concat_str);
+ return NULL;
+ }
+ elem = _PyAST_Constant(concat_str, kind, first_elem->lineno,
+ first_elem->col_offset,
+ last_elem->end_lineno,
+ last_elem->end_col_offset, p->arena);
+ if (elem == NULL) {
+ return NULL;
+ }
+ }
+
+ /* Drop all empty contanst strings */
+ if (f_string_found &&
+ PyUnicode_CheckExact(elem->v.Constant.value) &&
+ PyUnicode_GET_LENGTH(elem->v.Constant.value) == 0) {
+ continue;
+ }
+ }
+
+ asdl_seq_SET(values, current_pos++, elem);
+ }
+
+ if (!f_string_found) {
+ assert(n_elements == 1);
+ expr_ty elem = asdl_seq_GET(values, 0);
+ assert(elem->kind == Constant_kind);
+ return elem;
+ }
+
+ assert(current_pos == n_elements);
+ return _PyAST_JoinedStr(values, lineno, col_offset, end_lineno, end_col_offset, p->arena);
+}
diff --git a/Parser/parser.c b/Parser/parser.c
index cf0a12f3eb6fb0..5c32918859a319 100644
--- a/Parser/parser.c
+++ b/Parser/parser.c
@@ -17,52 +17,52 @@ static KeywordToken *reserved_keywords[] = {
(KeywordToken[]) {{NULL, -1}},
(KeywordToken[]) {{NULL, -1}},
(KeywordToken[]) {
- {"if", 641},
- {"as", 639},
- {"in", 650},
+ {"if", 642},
+ {"as", 640},
+ {"in", 651},
{"or", 574},
{"is", 582},
{NULL, -1},
},
(KeywordToken[]) {
- {"del", 603},
- {"def", 651},
- {"for", 649},
- {"try", 623},
+ {"del", 604},
+ {"def", 652},
+ {"for", 650},
+ {"try", 624},
{"and", 575},
{"not", 581},
{NULL, -1},
},
(KeywordToken[]) {
- {"from", 607},
+ {"from", 608},
{"pass", 504},
- {"with", 614},
- {"elif", 643},
- {"else", 644},
- {"None", 601},
- {"True", 600},
+ {"with", 615},
+ {"elif", 644},
+ {"else", 645},
+ {"None", 602},
+ {"True", 601},
{NULL, -1},
},
(KeywordToken[]) {
{"raise", 522},
{"yield", 573},
{"break", 508},
- {"class", 653},
- {"while", 646},
- {"False", 602},
+ {"class", 654},
+ {"while", 647},
+ {"False", 603},
{NULL, -1},
},
(KeywordToken[]) {
{"return", 519},
- {"import", 606},
+ {"import", 607},
{"assert", 526},
{"global", 523},
- {"except", 636},
- {"lambda", 586},
+ {"except", 637},
+ {"lambda", 600},
{NULL, -1},
},
(KeywordToken[]) {
- {"finally", 632},
+ {"finally", 633},
{NULL, -1},
},
(KeywordToken[]) {
@@ -230,343 +230,372 @@ static char *soft_keywords[] = {
#define lambda_param_with_default_type 1149
#define lambda_param_maybe_default_type 1150
#define lambda_param_type 1151
-#define strings_type 1152
-#define list_type 1153
-#define tuple_type 1154
-#define set_type 1155
-#define dict_type 1156
-#define double_starred_kvpairs_type 1157
-#define double_starred_kvpair_type 1158
-#define kvpair_type 1159
-#define for_if_clauses_type 1160
-#define for_if_clause_type 1161
-#define listcomp_type 1162
-#define setcomp_type 1163
-#define genexp_type 1164
-#define dictcomp_type 1165
-#define arguments_type 1166
-#define args_type 1167
-#define kwargs_type 1168
-#define starred_expression_type 1169
-#define kwarg_or_starred_type 1170
-#define kwarg_or_double_starred_type 1171
-#define star_targets_type 1172
-#define star_targets_list_seq_type 1173
-#define star_targets_tuple_seq_type 1174
-#define star_target_type 1175
-#define target_with_star_atom_type 1176
-#define star_atom_type 1177
-#define single_target_type 1178
-#define single_subscript_attribute_target_type 1179
-#define t_primary_type 1180 // Left-recursive
-#define t_lookahead_type 1181
-#define del_targets_type 1182
-#define del_target_type 1183
-#define del_t_atom_type 1184
-#define type_expressions_type 1185
-#define func_type_comment_type 1186
-#define invalid_arguments_type 1187
-#define invalid_kwarg_type 1188
-#define expression_without_invalid_type 1189
-#define invalid_legacy_expression_type 1190
-#define invalid_expression_type 1191
-#define invalid_named_expression_type 1192
-#define invalid_assignment_type 1193
-#define invalid_ann_assign_target_type 1194
-#define invalid_del_stmt_type 1195
-#define invalid_block_type 1196
-#define invalid_comprehension_type 1197
-#define invalid_dict_comprehension_type 1198
-#define invalid_parameters_type 1199
-#define invalid_default_type 1200
-#define invalid_star_etc_type 1201
-#define invalid_kwds_type 1202
-#define invalid_parameters_helper_type 1203
-#define invalid_lambda_parameters_type 1204
-#define invalid_lambda_parameters_helper_type 1205
-#define invalid_lambda_star_etc_type 1206
-#define invalid_lambda_kwds_type 1207
-#define invalid_double_type_comments_type 1208
-#define invalid_with_item_type 1209
-#define invalid_for_target_type 1210
-#define invalid_group_type 1211
-#define invalid_import_type 1212
-#define invalid_import_from_targets_type 1213
-#define invalid_with_stmt_type 1214
-#define invalid_with_stmt_indent_type 1215
-#define invalid_try_stmt_type 1216
-#define invalid_except_stmt_type 1217
-#define invalid_finally_stmt_type 1218
-#define invalid_except_stmt_indent_type 1219
-#define invalid_except_star_stmt_indent_type 1220
-#define invalid_match_stmt_type 1221
-#define invalid_case_block_type 1222
-#define invalid_as_pattern_type 1223
-#define invalid_class_pattern_type 1224
-#define invalid_class_argument_pattern_type 1225
-#define invalid_if_stmt_type 1226
-#define invalid_elif_stmt_type 1227
-#define invalid_else_stmt_type 1228
-#define invalid_while_stmt_type 1229
-#define invalid_for_stmt_type 1230
-#define invalid_def_raw_type 1231
-#define invalid_class_def_raw_type 1232
-#define invalid_double_starred_kvpairs_type 1233
-#define invalid_kvpair_type 1234
-#define invalid_starred_expression_type 1235
-#define _loop0_1_type 1236
-#define _loop0_2_type 1237
-#define _loop1_3_type 1238
-#define _loop0_5_type 1239
-#define _gather_4_type 1240
-#define _tmp_6_type 1241
-#define _tmp_7_type 1242
-#define _tmp_8_type 1243
-#define _tmp_9_type 1244
-#define _tmp_10_type 1245
-#define _tmp_11_type 1246
-#define _tmp_12_type 1247
-#define _tmp_13_type 1248
-#define _loop1_14_type 1249
-#define _tmp_15_type 1250
-#define _tmp_16_type 1251
-#define _tmp_17_type 1252
-#define _loop0_19_type 1253
-#define _gather_18_type 1254
-#define _loop0_21_type 1255
-#define _gather_20_type 1256
-#define _tmp_22_type 1257
-#define _tmp_23_type 1258
-#define _loop0_24_type 1259
-#define _loop1_25_type 1260
-#define _loop0_27_type 1261
-#define _gather_26_type 1262
-#define _tmp_28_type 1263
-#define _loop0_30_type 1264
-#define _gather_29_type 1265
-#define _tmp_31_type 1266
-#define _loop1_32_type 1267
-#define _tmp_33_type 1268
-#define _tmp_34_type 1269
-#define _tmp_35_type 1270
-#define _loop0_36_type 1271
-#define _loop0_37_type 1272
-#define _loop0_38_type 1273
-#define _loop1_39_type 1274
-#define _loop0_40_type 1275
-#define _loop1_41_type 1276
-#define _loop1_42_type 1277
-#define _loop1_43_type 1278
-#define _loop0_44_type 1279
-#define _loop1_45_type 1280
-#define _loop0_46_type 1281
-#define _loop1_47_type 1282
-#define _loop0_48_type 1283
-#define _loop0_49_type 1284
-#define _loop1_50_type 1285
-#define _loop0_52_type 1286
-#define _gather_51_type 1287
-#define _loop0_54_type 1288
-#define _gather_53_type 1289
-#define _loop0_56_type 1290
-#define _gather_55_type 1291
-#define _loop0_58_type 1292
-#define _gather_57_type 1293
-#define _tmp_59_type 1294
-#define _loop1_60_type 1295
-#define _loop1_61_type 1296
-#define _tmp_62_type 1297
-#define _tmp_63_type 1298
-#define _loop1_64_type 1299
-#define _loop0_66_type 1300
-#define _gather_65_type 1301
-#define _tmp_67_type 1302
-#define _tmp_68_type 1303
-#define _tmp_69_type 1304
-#define _tmp_70_type 1305
-#define _loop0_72_type 1306
-#define _gather_71_type 1307
-#define _loop0_74_type 1308
-#define _gather_73_type 1309
-#define _tmp_75_type 1310
-#define _loop0_77_type 1311
-#define _gather_76_type 1312
-#define _loop0_79_type 1313
-#define _gather_78_type 1314
-#define _loop0_81_type 1315
-#define _gather_80_type 1316
-#define _loop1_82_type 1317
-#define _loop1_83_type 1318
-#define _loop0_85_type 1319
-#define _gather_84_type 1320
-#define _loop1_86_type 1321
-#define _loop1_87_type 1322
-#define _loop1_88_type 1323
-#define _tmp_89_type 1324
-#define _loop0_91_type 1325
-#define _gather_90_type 1326
-#define _tmp_92_type 1327
-#define _tmp_93_type 1328
-#define _tmp_94_type 1329
-#define _tmp_95_type 1330
-#define _tmp_96_type 1331
-#define _loop0_97_type 1332
-#define _loop0_98_type 1333
-#define _loop0_99_type 1334
-#define _loop1_100_type 1335
-#define _loop0_101_type 1336
-#define _loop1_102_type 1337
-#define _loop1_103_type 1338
-#define _loop1_104_type 1339
-#define _loop0_105_type 1340
-#define _loop1_106_type 1341
-#define _loop0_107_type 1342
-#define _loop1_108_type 1343
-#define _loop0_109_type 1344
-#define _loop1_110_type 1345
-#define _loop1_111_type 1346
-#define _tmp_112_type 1347
-#define _loop0_114_type 1348
-#define _gather_113_type 1349
-#define _loop1_115_type 1350
-#define _loop0_116_type 1351
-#define _loop0_117_type 1352
-#define _tmp_118_type 1353
-#define _loop0_120_type 1354
-#define _gather_119_type 1355
-#define _tmp_121_type 1356
-#define _loop0_123_type 1357
-#define _gather_122_type 1358
-#define _loop0_125_type 1359
-#define _gather_124_type 1360
-#define _loop0_127_type 1361
-#define _gather_126_type 1362
-#define _loop0_129_type 1363
-#define _gather_128_type 1364
-#define _loop0_130_type 1365
-#define _loop0_132_type 1366
-#define _gather_131_type 1367
-#define _loop1_133_type 1368
-#define _tmp_134_type 1369
-#define _loop0_136_type 1370
-#define _gather_135_type 1371
-#define _loop0_138_type 1372
-#define _gather_137_type 1373
-#define _loop0_140_type 1374
-#define _gather_139_type 1375
-#define _loop0_142_type 1376
-#define _gather_141_type 1377
-#define _loop0_144_type 1378
-#define _gather_143_type 1379
-#define _tmp_145_type 1380
-#define _tmp_146_type 1381
-#define _tmp_147_type 1382
-#define _tmp_148_type 1383
-#define _tmp_149_type 1384
-#define _tmp_150_type 1385
-#define _tmp_151_type 1386
-#define _tmp_152_type 1387
-#define _tmp_153_type 1388
-#define _tmp_154_type 1389
-#define _tmp_155_type 1390
-#define _loop0_156_type 1391
-#define _loop0_157_type 1392
-#define _loop0_158_type 1393
-#define _tmp_159_type 1394
-#define _tmp_160_type 1395
-#define _tmp_161_type 1396
-#define _tmp_162_type 1397
-#define _tmp_163_type 1398
-#define _loop0_164_type 1399
-#define _loop0_165_type 1400
-#define _loop0_166_type 1401
-#define _loop1_167_type 1402
-#define _tmp_168_type 1403
-#define _loop0_169_type 1404
-#define _tmp_170_type 1405
-#define _loop0_171_type 1406
-#define _loop1_172_type 1407
-#define _tmp_173_type 1408
-#define _tmp_174_type 1409
-#define _tmp_175_type 1410
-#define _loop0_176_type 1411
-#define _tmp_177_type 1412
-#define _tmp_178_type 1413
-#define _loop1_179_type 1414
-#define _tmp_180_type 1415
-#define _loop0_181_type 1416
-#define _loop0_182_type 1417
-#define _loop0_183_type 1418
-#define _loop0_185_type 1419
-#define _gather_184_type 1420
-#define _tmp_186_type 1421
-#define _loop0_187_type 1422
-#define _tmp_188_type 1423
-#define _loop0_189_type 1424
-#define _loop1_190_type 1425
-#define _loop1_191_type 1426
-#define _tmp_192_type 1427
-#define _tmp_193_type 1428
-#define _loop0_194_type 1429
-#define _tmp_195_type 1430
-#define _tmp_196_type 1431
-#define _tmp_197_type 1432
-#define _loop0_199_type 1433
-#define _gather_198_type 1434
-#define _loop0_201_type 1435
-#define _gather_200_type 1436
-#define _loop0_203_type 1437
-#define _gather_202_type 1438
-#define _loop0_205_type 1439
-#define _gather_204_type 1440
-#define _tmp_206_type 1441
-#define _loop0_207_type 1442
-#define _loop1_208_type 1443
-#define _tmp_209_type 1444
-#define _loop0_210_type 1445
-#define _loop1_211_type 1446
-#define _tmp_212_type 1447
-#define _tmp_213_type 1448
-#define _tmp_214_type 1449
-#define _tmp_215_type 1450
-#define _tmp_216_type 1451
-#define _tmp_217_type 1452
-#define _tmp_218_type 1453
-#define _tmp_219_type 1454
-#define _tmp_220_type 1455
-#define _tmp_221_type 1456
-#define _loop0_223_type 1457
-#define _gather_222_type 1458
-#define _tmp_224_type 1459
-#define _tmp_225_type 1460
-#define _tmp_226_type 1461
-#define _tmp_227_type 1462
-#define _tmp_228_type 1463
-#define _tmp_229_type 1464
-#define _tmp_230_type 1465
-#define _tmp_231_type 1466
-#define _tmp_232_type 1467
-#define _tmp_233_type 1468
-#define _tmp_234_type 1469
-#define _tmp_235_type 1470
-#define _tmp_236_type 1471
-#define _tmp_237_type 1472
-#define _tmp_238_type 1473
-#define _tmp_239_type 1474
-#define _tmp_240_type 1475
-#define _tmp_241_type 1476
-#define _tmp_242_type 1477
-#define _tmp_243_type 1478
-#define _tmp_244_type 1479
-#define _tmp_245_type 1480
-#define _tmp_246_type 1481
-#define _tmp_247_type 1482
-#define _tmp_248_type 1483
-#define _tmp_249_type 1484
-#define _tmp_250_type 1485
-#define _tmp_251_type 1486
-#define _tmp_252_type 1487
-#define _tmp_253_type 1488
+#define fstring_middle_type 1152
+#define fstring_replacement_field_type 1153
+#define fstring_conversion_type 1154
+#define fstring_full_format_spec_type 1155
+#define fstring_format_spec_type 1156
+#define string_type 1157
+#define strings_type 1158
+#define list_type 1159
+#define tuple_type 1160
+#define set_type 1161
+#define dict_type 1162
+#define double_starred_kvpairs_type 1163
+#define double_starred_kvpair_type 1164
+#define kvpair_type 1165
+#define for_if_clauses_type 1166
+#define for_if_clause_type 1167
+#define listcomp_type 1168
+#define setcomp_type 1169
+#define genexp_type 1170
+#define dictcomp_type 1171
+#define arguments_type 1172
+#define args_type 1173
+#define kwargs_type 1174
+#define starred_expression_type 1175
+#define kwarg_or_starred_type 1176
+#define kwarg_or_double_starred_type 1177
+#define star_targets_type 1178
+#define star_targets_list_seq_type 1179
+#define star_targets_tuple_seq_type 1180
+#define star_target_type 1181
+#define target_with_star_atom_type 1182
+#define star_atom_type 1183
+#define single_target_type 1184
+#define single_subscript_attribute_target_type 1185
+#define t_primary_type 1186 // Left-recursive
+#define t_lookahead_type 1187
+#define del_targets_type 1188
+#define del_target_type 1189
+#define del_t_atom_type 1190
+#define type_expressions_type 1191
+#define func_type_comment_type 1192
+#define invalid_arguments_type 1193
+#define invalid_kwarg_type 1194
+#define expression_without_invalid_type 1195
+#define invalid_legacy_expression_type 1196
+#define invalid_expression_type 1197
+#define invalid_named_expression_type 1198
+#define invalid_assignment_type 1199
+#define invalid_ann_assign_target_type 1200
+#define invalid_del_stmt_type 1201
+#define invalid_block_type 1202
+#define invalid_comprehension_type 1203
+#define invalid_dict_comprehension_type 1204
+#define invalid_parameters_type 1205
+#define invalid_default_type 1206
+#define invalid_star_etc_type 1207
+#define invalid_kwds_type 1208
+#define invalid_parameters_helper_type 1209
+#define invalid_lambda_parameters_type 1210
+#define invalid_lambda_parameters_helper_type 1211
+#define invalid_lambda_star_etc_type 1212
+#define invalid_lambda_kwds_type 1213
+#define invalid_double_type_comments_type 1214
+#define invalid_with_item_type 1215
+#define invalid_for_target_type 1216
+#define invalid_group_type 1217
+#define invalid_import_type 1218
+#define invalid_import_from_targets_type 1219
+#define invalid_with_stmt_type 1220
+#define invalid_with_stmt_indent_type 1221
+#define invalid_try_stmt_type 1222
+#define invalid_except_stmt_type 1223
+#define invalid_finally_stmt_type 1224
+#define invalid_except_stmt_indent_type 1225
+#define invalid_except_star_stmt_indent_type 1226
+#define invalid_match_stmt_type 1227
+#define invalid_case_block_type 1228
+#define invalid_as_pattern_type 1229
+#define invalid_class_pattern_type 1230
+#define invalid_class_argument_pattern_type 1231
+#define invalid_if_stmt_type 1232
+#define invalid_elif_stmt_type 1233
+#define invalid_else_stmt_type 1234
+#define invalid_while_stmt_type 1235
+#define invalid_for_stmt_type 1236
+#define invalid_def_raw_type 1237
+#define invalid_class_def_raw_type 1238
+#define invalid_double_starred_kvpairs_type 1239
+#define invalid_kvpair_type 1240
+#define invalid_starred_expression_type 1241
+#define invalid_replacement_field_type 1242
+#define invalid_conversion_character_type 1243
+#define _loop0_1_type 1244
+#define _loop0_2_type 1245
+#define _loop0_3_type 1246
+#define _loop1_4_type 1247
+#define _loop0_6_type 1248
+#define _gather_5_type 1249
+#define _tmp_7_type 1250
+#define _tmp_8_type 1251
+#define _tmp_9_type 1252
+#define _tmp_10_type 1253
+#define _tmp_11_type 1254
+#define _tmp_12_type 1255
+#define _tmp_13_type 1256
+#define _tmp_14_type 1257
+#define _loop1_15_type 1258
+#define _tmp_16_type 1259
+#define _tmp_17_type 1260
+#define _tmp_18_type 1261
+#define _loop0_20_type 1262
+#define _gather_19_type 1263
+#define _loop0_22_type 1264
+#define _gather_21_type 1265
+#define _tmp_23_type 1266
+#define _tmp_24_type 1267
+#define _loop0_25_type 1268
+#define _loop1_26_type 1269
+#define _loop0_28_type 1270
+#define _gather_27_type 1271
+#define _tmp_29_type 1272
+#define _loop0_31_type 1273
+#define _gather_30_type 1274
+#define _tmp_32_type 1275
+#define _loop1_33_type 1276
+#define _tmp_34_type 1277
+#define _tmp_35_type 1278
+#define _tmp_36_type 1279
+#define _loop0_37_type 1280
+#define _loop0_38_type 1281
+#define _loop0_39_type 1282
+#define _loop1_40_type 1283
+#define _loop0_41_type 1284
+#define _loop1_42_type 1285
+#define _loop1_43_type 1286
+#define _loop1_44_type 1287
+#define _loop0_45_type 1288
+#define _loop1_46_type 1289
+#define _loop0_47_type 1290
+#define _loop1_48_type 1291
+#define _loop0_49_type 1292
+#define _loop0_50_type 1293
+#define _loop1_51_type 1294
+#define _loop0_53_type 1295
+#define _gather_52_type 1296
+#define _loop0_55_type 1297
+#define _gather_54_type 1298
+#define _loop0_57_type 1299
+#define _gather_56_type 1300
+#define _loop0_59_type 1301
+#define _gather_58_type 1302
+#define _tmp_60_type 1303
+#define _loop1_61_type 1304
+#define _loop1_62_type 1305
+#define _tmp_63_type 1306
+#define _tmp_64_type 1307
+#define _loop1_65_type 1308
+#define _loop0_67_type 1309
+#define _gather_66_type 1310
+#define _tmp_68_type 1311
+#define _tmp_69_type 1312
+#define _tmp_70_type 1313
+#define _tmp_71_type 1314
+#define _loop0_73_type 1315
+#define _gather_72_type 1316
+#define _loop0_75_type 1317
+#define _gather_74_type 1318
+#define _tmp_76_type 1319
+#define _loop0_78_type 1320
+#define _gather_77_type 1321
+#define _loop0_80_type 1322
+#define _gather_79_type 1323
+#define _loop0_82_type 1324
+#define _gather_81_type 1325
+#define _loop1_83_type 1326
+#define _loop1_84_type 1327
+#define _loop0_86_type 1328
+#define _gather_85_type 1329
+#define _loop1_87_type 1330
+#define _loop1_88_type 1331
+#define _loop1_89_type 1332
+#define _tmp_90_type 1333
+#define _loop0_92_type 1334
+#define _gather_91_type 1335
+#define _tmp_93_type 1336
+#define _tmp_94_type 1337
+#define _tmp_95_type 1338
+#define _tmp_96_type 1339
+#define _tmp_97_type 1340
+#define _tmp_98_type 1341
+#define _loop0_99_type 1342
+#define _loop0_100_type 1343
+#define _loop0_101_type 1344
+#define _loop1_102_type 1345
+#define _loop0_103_type 1346
+#define _loop1_104_type 1347
+#define _loop1_105_type 1348
+#define _loop1_106_type 1349
+#define _loop0_107_type 1350
+#define _loop1_108_type 1351
+#define _loop0_109_type 1352
+#define _loop1_110_type 1353
+#define _loop0_111_type 1354
+#define _loop1_112_type 1355
+#define _tmp_113_type 1356
+#define _loop0_114_type 1357
+#define _loop1_115_type 1358
+#define _tmp_116_type 1359
+#define _loop0_118_type 1360
+#define _gather_117_type 1361
+#define _loop1_119_type 1362
+#define _loop0_120_type 1363
+#define _loop0_121_type 1364
+#define _tmp_122_type 1365
+#define _loop0_124_type 1366
+#define _gather_123_type 1367
+#define _tmp_125_type 1368
+#define _loop0_127_type 1369
+#define _gather_126_type 1370
+#define _loop0_129_type 1371
+#define _gather_128_type 1372
+#define _loop0_131_type 1373
+#define _gather_130_type 1374
+#define _loop0_133_type 1375
+#define _gather_132_type 1376
+#define _loop0_134_type 1377
+#define _loop0_136_type 1378
+#define _gather_135_type 1379
+#define _loop1_137_type 1380
+#define _tmp_138_type 1381
+#define _loop0_140_type 1382
+#define _gather_139_type 1383
+#define _loop0_142_type 1384
+#define _gather_141_type 1385
+#define _loop0_144_type 1386
+#define _gather_143_type 1387
+#define _loop0_146_type 1388
+#define _gather_145_type 1389
+#define _loop0_148_type 1390
+#define _gather_147_type 1391
+#define _tmp_149_type 1392
+#define _tmp_150_type 1393
+#define _tmp_151_type 1394
+#define _tmp_152_type 1395
+#define _tmp_153_type 1396
+#define _tmp_154_type 1397
+#define _tmp_155_type 1398
+#define _tmp_156_type 1399
+#define _tmp_157_type 1400
+#define _tmp_158_type 1401
+#define _tmp_159_type 1402
+#define _tmp_160_type 1403
+#define _loop0_161_type 1404
+#define _loop0_162_type 1405
+#define _loop0_163_type 1406
+#define _tmp_164_type 1407
+#define _tmp_165_type 1408
+#define _tmp_166_type 1409
+#define _tmp_167_type 1410
+#define _tmp_168_type 1411
+#define _loop0_169_type 1412
+#define _loop0_170_type 1413
+#define _loop0_171_type 1414
+#define _loop1_172_type 1415
+#define _tmp_173_type 1416
+#define _loop0_174_type 1417
+#define _tmp_175_type 1418
+#define _loop0_176_type 1419
+#define _loop1_177_type 1420
+#define _tmp_178_type 1421
+#define _tmp_179_type 1422
+#define _tmp_180_type 1423
+#define _loop0_181_type 1424
+#define _tmp_182_type 1425
+#define _tmp_183_type 1426
+#define _loop1_184_type 1427
+#define _tmp_185_type 1428
+#define _loop0_186_type 1429
+#define _loop0_187_type 1430
+#define _loop0_188_type 1431
+#define _loop0_190_type 1432
+#define _gather_189_type 1433
+#define _tmp_191_type 1434
+#define _loop0_192_type 1435
+#define _tmp_193_type 1436
+#define _loop0_194_type 1437
+#define _loop1_195_type 1438
+#define _loop1_196_type 1439
+#define _tmp_197_type 1440
+#define _tmp_198_type 1441
+#define _loop0_199_type 1442
+#define _tmp_200_type 1443
+#define _tmp_201_type 1444
+#define _tmp_202_type 1445
+#define _loop0_204_type 1446
+#define _gather_203_type 1447
+#define _loop0_206_type 1448
+#define _gather_205_type 1449
+#define _loop0_208_type 1450
+#define _gather_207_type 1451
+#define _loop0_210_type 1452
+#define _gather_209_type 1453
+#define _tmp_211_type 1454
+#define _loop0_212_type 1455
+#define _loop1_213_type 1456
+#define _tmp_214_type 1457
+#define _loop0_215_type 1458
+#define _loop1_216_type 1459
+#define _tmp_217_type 1460
+#define _tmp_218_type 1461
+#define _tmp_219_type 1462
+#define _tmp_220_type 1463
+#define _tmp_221_type 1464
+#define _tmp_222_type 1465
+#define _tmp_223_type 1466
+#define _tmp_224_type 1467
+#define _tmp_225_type 1468
+#define _tmp_226_type 1469
+#define _loop0_228_type 1470
+#define _gather_227_type 1471
+#define _tmp_229_type 1472
+#define _tmp_230_type 1473
+#define _tmp_231_type 1474
+#define _tmp_232_type 1475
+#define _tmp_233_type 1476
+#define _tmp_234_type 1477
+#define _tmp_235_type 1478
+#define _tmp_236_type 1479
+#define _tmp_237_type 1480
+#define _tmp_238_type 1481
+#define _tmp_239_type 1482
+#define _tmp_240_type 1483
+#define _tmp_241_type 1484
+#define _loop0_242_type 1485
+#define _tmp_243_type 1486
+#define _tmp_244_type 1487
+#define _tmp_245_type 1488
+#define _tmp_246_type 1489
+#define _tmp_247_type 1490
+#define _tmp_248_type 1491
+#define _tmp_249_type 1492
+#define _tmp_250_type 1493
+#define _tmp_251_type 1494
+#define _tmp_252_type 1495
+#define _tmp_253_type 1496
+#define _tmp_254_type 1497
+#define _tmp_255_type 1498
+#define _tmp_256_type 1499
+#define _tmp_257_type 1500
+#define _tmp_258_type 1501
+#define _tmp_259_type 1502
+#define _tmp_260_type 1503
+#define _tmp_261_type 1504
+#define _tmp_262_type 1505
+#define _tmp_263_type 1506
+#define _tmp_264_type 1507
+#define _tmp_265_type 1508
+#define _tmp_266_type 1509
+#define _tmp_267_type 1510
+#define _tmp_268_type 1511
+#define _tmp_269_type 1512
+#define _tmp_270_type 1513
+#define _tmp_271_type 1514
+#define _tmp_272_type 1515
+#define _tmp_273_type 1516
+#define _tmp_274_type 1517
static mod_ty file_rule(Parser *p);
static mod_ty interactive_rule(Parser *p);
@@ -720,6 +749,12 @@ static arg_ty lambda_param_no_default_rule(Parser *p);
static NameDefaultPair* lambda_param_with_default_rule(Parser *p);
static NameDefaultPair* lambda_param_maybe_default_rule(Parser *p);
static arg_ty lambda_param_rule(Parser *p);
+static expr_ty fstring_middle_rule(Parser *p);
+static expr_ty fstring_replacement_field_rule(Parser *p);
+static expr_ty fstring_conversion_rule(Parser *p);
+static expr_ty fstring_full_format_spec_rule(Parser *p);
+static expr_ty fstring_format_spec_rule(Parser *p);
+static expr_ty string_rule(Parser *p);
static expr_ty strings_rule(Parser *p);
static expr_ty list_rule(Parser *p);
static expr_ty tuple_rule(Parser *p);
@@ -804,12 +839,14 @@ static void *invalid_class_def_raw_rule(Parser *p);
static void *invalid_double_starred_kvpairs_rule(Parser *p);
static void *invalid_kvpair_rule(Parser *p);
static void *invalid_starred_expression_rule(Parser *p);
+static void *invalid_replacement_field_rule(Parser *p);
+static void *invalid_conversion_character_rule(Parser *p);
static asdl_seq *_loop0_1_rule(Parser *p);
static asdl_seq *_loop0_2_rule(Parser *p);
-static asdl_seq *_loop1_3_rule(Parser *p);
-static asdl_seq *_loop0_5_rule(Parser *p);
-static asdl_seq *_gather_4_rule(Parser *p);
-static void *_tmp_6_rule(Parser *p);
+static asdl_seq *_loop0_3_rule(Parser *p);
+static asdl_seq *_loop1_4_rule(Parser *p);
+static asdl_seq *_loop0_6_rule(Parser *p);
+static asdl_seq *_gather_5_rule(Parser *p);
static void *_tmp_7_rule(Parser *p);
static void *_tmp_8_rule(Parser *p);
static void *_tmp_9_rule(Parser *p);
@@ -817,141 +854,141 @@ static void *_tmp_10_rule(Parser *p);
static void *_tmp_11_rule(Parser *p);
static void *_tmp_12_rule(Parser *p);
static void *_tmp_13_rule(Parser *p);
-static asdl_seq *_loop1_14_rule(Parser *p);
-static void *_tmp_15_rule(Parser *p);
+static void *_tmp_14_rule(Parser *p);
+static asdl_seq *_loop1_15_rule(Parser *p);
static void *_tmp_16_rule(Parser *p);
static void *_tmp_17_rule(Parser *p);
-static asdl_seq *_loop0_19_rule(Parser *p);
-static asdl_seq *_gather_18_rule(Parser *p);
-static asdl_seq *_loop0_21_rule(Parser *p);
-static asdl_seq *_gather_20_rule(Parser *p);
-static void *_tmp_22_rule(Parser *p);
+static void *_tmp_18_rule(Parser *p);
+static asdl_seq *_loop0_20_rule(Parser *p);
+static asdl_seq *_gather_19_rule(Parser *p);
+static asdl_seq *_loop0_22_rule(Parser *p);
+static asdl_seq *_gather_21_rule(Parser *p);
static void *_tmp_23_rule(Parser *p);
-static asdl_seq *_loop0_24_rule(Parser *p);
-static asdl_seq *_loop1_25_rule(Parser *p);
-static asdl_seq *_loop0_27_rule(Parser *p);
-static asdl_seq *_gather_26_rule(Parser *p);
-static void *_tmp_28_rule(Parser *p);
-static asdl_seq *_loop0_30_rule(Parser *p);
-static asdl_seq *_gather_29_rule(Parser *p);
-static void *_tmp_31_rule(Parser *p);
-static asdl_seq *_loop1_32_rule(Parser *p);
-static void *_tmp_33_rule(Parser *p);
+static void *_tmp_24_rule(Parser *p);
+static asdl_seq *_loop0_25_rule(Parser *p);
+static asdl_seq *_loop1_26_rule(Parser *p);
+static asdl_seq *_loop0_28_rule(Parser *p);
+static asdl_seq *_gather_27_rule(Parser *p);
+static void *_tmp_29_rule(Parser *p);
+static asdl_seq *_loop0_31_rule(Parser *p);
+static asdl_seq *_gather_30_rule(Parser *p);
+static void *_tmp_32_rule(Parser *p);
+static asdl_seq *_loop1_33_rule(Parser *p);
static void *_tmp_34_rule(Parser *p);
static void *_tmp_35_rule(Parser *p);
-static asdl_seq *_loop0_36_rule(Parser *p);
+static void *_tmp_36_rule(Parser *p);
static asdl_seq *_loop0_37_rule(Parser *p);
static asdl_seq *_loop0_38_rule(Parser *p);
-static asdl_seq *_loop1_39_rule(Parser *p);
-static asdl_seq *_loop0_40_rule(Parser *p);
-static asdl_seq *_loop1_41_rule(Parser *p);
+static asdl_seq *_loop0_39_rule(Parser *p);
+static asdl_seq *_loop1_40_rule(Parser *p);
+static asdl_seq *_loop0_41_rule(Parser *p);
static asdl_seq *_loop1_42_rule(Parser *p);
static asdl_seq *_loop1_43_rule(Parser *p);
-static asdl_seq *_loop0_44_rule(Parser *p);
-static asdl_seq *_loop1_45_rule(Parser *p);
-static asdl_seq *_loop0_46_rule(Parser *p);
-static asdl_seq *_loop1_47_rule(Parser *p);
-static asdl_seq *_loop0_48_rule(Parser *p);
+static asdl_seq *_loop1_44_rule(Parser *p);
+static asdl_seq *_loop0_45_rule(Parser *p);
+static asdl_seq *_loop1_46_rule(Parser *p);
+static asdl_seq *_loop0_47_rule(Parser *p);
+static asdl_seq *_loop1_48_rule(Parser *p);
static asdl_seq *_loop0_49_rule(Parser *p);
-static asdl_seq *_loop1_50_rule(Parser *p);
-static asdl_seq *_loop0_52_rule(Parser *p);
-static asdl_seq *_gather_51_rule(Parser *p);
-static asdl_seq *_loop0_54_rule(Parser *p);
-static asdl_seq *_gather_53_rule(Parser *p);
-static asdl_seq *_loop0_56_rule(Parser *p);
-static asdl_seq *_gather_55_rule(Parser *p);
-static asdl_seq *_loop0_58_rule(Parser *p);
-static asdl_seq *_gather_57_rule(Parser *p);
-static void *_tmp_59_rule(Parser *p);
-static asdl_seq *_loop1_60_rule(Parser *p);
+static asdl_seq *_loop0_50_rule(Parser *p);
+static asdl_seq *_loop1_51_rule(Parser *p);
+static asdl_seq *_loop0_53_rule(Parser *p);
+static asdl_seq *_gather_52_rule(Parser *p);
+static asdl_seq *_loop0_55_rule(Parser *p);
+static asdl_seq *_gather_54_rule(Parser *p);
+static asdl_seq *_loop0_57_rule(Parser *p);
+static asdl_seq *_gather_56_rule(Parser *p);
+static asdl_seq *_loop0_59_rule(Parser *p);
+static asdl_seq *_gather_58_rule(Parser *p);
+static void *_tmp_60_rule(Parser *p);
static asdl_seq *_loop1_61_rule(Parser *p);
-static void *_tmp_62_rule(Parser *p);
+static asdl_seq *_loop1_62_rule(Parser *p);
static void *_tmp_63_rule(Parser *p);
-static asdl_seq *_loop1_64_rule(Parser *p);
-static asdl_seq *_loop0_66_rule(Parser *p);
-static asdl_seq *_gather_65_rule(Parser *p);
-static void *_tmp_67_rule(Parser *p);
+static void *_tmp_64_rule(Parser *p);
+static asdl_seq *_loop1_65_rule(Parser *p);
+static asdl_seq *_loop0_67_rule(Parser *p);
+static asdl_seq *_gather_66_rule(Parser *p);
static void *_tmp_68_rule(Parser *p);
static void *_tmp_69_rule(Parser *p);
static void *_tmp_70_rule(Parser *p);
-static asdl_seq *_loop0_72_rule(Parser *p);
-static asdl_seq *_gather_71_rule(Parser *p);
-static asdl_seq *_loop0_74_rule(Parser *p);
-static asdl_seq *_gather_73_rule(Parser *p);
-static void *_tmp_75_rule(Parser *p);
-static asdl_seq *_loop0_77_rule(Parser *p);
-static asdl_seq *_gather_76_rule(Parser *p);
-static asdl_seq *_loop0_79_rule(Parser *p);
-static asdl_seq *_gather_78_rule(Parser *p);
-static asdl_seq *_loop0_81_rule(Parser *p);
-static asdl_seq *_gather_80_rule(Parser *p);
-static asdl_seq *_loop1_82_rule(Parser *p);
+static void *_tmp_71_rule(Parser *p);
+static asdl_seq *_loop0_73_rule(Parser *p);
+static asdl_seq *_gather_72_rule(Parser *p);
+static asdl_seq *_loop0_75_rule(Parser *p);
+static asdl_seq *_gather_74_rule(Parser *p);
+static void *_tmp_76_rule(Parser *p);
+static asdl_seq *_loop0_78_rule(Parser *p);
+static asdl_seq *_gather_77_rule(Parser *p);
+static asdl_seq *_loop0_80_rule(Parser *p);
+static asdl_seq *_gather_79_rule(Parser *p);
+static asdl_seq *_loop0_82_rule(Parser *p);
+static asdl_seq *_gather_81_rule(Parser *p);
static asdl_seq *_loop1_83_rule(Parser *p);
-static asdl_seq *_loop0_85_rule(Parser *p);
-static asdl_seq *_gather_84_rule(Parser *p);
-static asdl_seq *_loop1_86_rule(Parser *p);
+static asdl_seq *_loop1_84_rule(Parser *p);
+static asdl_seq *_loop0_86_rule(Parser *p);
+static asdl_seq *_gather_85_rule(Parser *p);
static asdl_seq *_loop1_87_rule(Parser *p);
static asdl_seq *_loop1_88_rule(Parser *p);
-static void *_tmp_89_rule(Parser *p);
-static asdl_seq *_loop0_91_rule(Parser *p);
-static asdl_seq *_gather_90_rule(Parser *p);
-static void *_tmp_92_rule(Parser *p);
+static asdl_seq *_loop1_89_rule(Parser *p);
+static void *_tmp_90_rule(Parser *p);
+static asdl_seq *_loop0_92_rule(Parser *p);
+static asdl_seq *_gather_91_rule(Parser *p);
static void *_tmp_93_rule(Parser *p);
static void *_tmp_94_rule(Parser *p);
static void *_tmp_95_rule(Parser *p);
static void *_tmp_96_rule(Parser *p);
-static asdl_seq *_loop0_97_rule(Parser *p);
-static asdl_seq *_loop0_98_rule(Parser *p);
+static void *_tmp_97_rule(Parser *p);
+static void *_tmp_98_rule(Parser *p);
static asdl_seq *_loop0_99_rule(Parser *p);
-static asdl_seq *_loop1_100_rule(Parser *p);
+static asdl_seq *_loop0_100_rule(Parser *p);
static asdl_seq *_loop0_101_rule(Parser *p);
static asdl_seq *_loop1_102_rule(Parser *p);
-static asdl_seq *_loop1_103_rule(Parser *p);
+static asdl_seq *_loop0_103_rule(Parser *p);
static asdl_seq *_loop1_104_rule(Parser *p);
-static asdl_seq *_loop0_105_rule(Parser *p);
+static asdl_seq *_loop1_105_rule(Parser *p);
static asdl_seq *_loop1_106_rule(Parser *p);
static asdl_seq *_loop0_107_rule(Parser *p);
static asdl_seq *_loop1_108_rule(Parser *p);
static asdl_seq *_loop0_109_rule(Parser *p);
static asdl_seq *_loop1_110_rule(Parser *p);
-static asdl_seq *_loop1_111_rule(Parser *p);
-static void *_tmp_112_rule(Parser *p);
+static asdl_seq *_loop0_111_rule(Parser *p);
+static asdl_seq *_loop1_112_rule(Parser *p);
+static void *_tmp_113_rule(Parser *p);
static asdl_seq *_loop0_114_rule(Parser *p);
-static asdl_seq *_gather_113_rule(Parser *p);
static asdl_seq *_loop1_115_rule(Parser *p);
-static asdl_seq *_loop0_116_rule(Parser *p);
-static asdl_seq *_loop0_117_rule(Parser *p);
-static void *_tmp_118_rule(Parser *p);
+static void *_tmp_116_rule(Parser *p);
+static asdl_seq *_loop0_118_rule(Parser *p);
+static asdl_seq *_gather_117_rule(Parser *p);
+static asdl_seq *_loop1_119_rule(Parser *p);
static asdl_seq *_loop0_120_rule(Parser *p);
-static asdl_seq *_gather_119_rule(Parser *p);
-static void *_tmp_121_rule(Parser *p);
-static asdl_seq *_loop0_123_rule(Parser *p);
-static asdl_seq *_gather_122_rule(Parser *p);
-static asdl_seq *_loop0_125_rule(Parser *p);
-static asdl_seq *_gather_124_rule(Parser *p);
+static asdl_seq *_loop0_121_rule(Parser *p);
+static void *_tmp_122_rule(Parser *p);
+static asdl_seq *_loop0_124_rule(Parser *p);
+static asdl_seq *_gather_123_rule(Parser *p);
+static void *_tmp_125_rule(Parser *p);
static asdl_seq *_loop0_127_rule(Parser *p);
static asdl_seq *_gather_126_rule(Parser *p);
static asdl_seq *_loop0_129_rule(Parser *p);
static asdl_seq *_gather_128_rule(Parser *p);
-static asdl_seq *_loop0_130_rule(Parser *p);
-static asdl_seq *_loop0_132_rule(Parser *p);
-static asdl_seq *_gather_131_rule(Parser *p);
-static asdl_seq *_loop1_133_rule(Parser *p);
-static void *_tmp_134_rule(Parser *p);
+static asdl_seq *_loop0_131_rule(Parser *p);
+static asdl_seq *_gather_130_rule(Parser *p);
+static asdl_seq *_loop0_133_rule(Parser *p);
+static asdl_seq *_gather_132_rule(Parser *p);
+static asdl_seq *_loop0_134_rule(Parser *p);
static asdl_seq *_loop0_136_rule(Parser *p);
static asdl_seq *_gather_135_rule(Parser *p);
-static asdl_seq *_loop0_138_rule(Parser *p);
-static asdl_seq *_gather_137_rule(Parser *p);
+static asdl_seq *_loop1_137_rule(Parser *p);
+static void *_tmp_138_rule(Parser *p);
static asdl_seq *_loop0_140_rule(Parser *p);
static asdl_seq *_gather_139_rule(Parser *p);
static asdl_seq *_loop0_142_rule(Parser *p);
static asdl_seq *_gather_141_rule(Parser *p);
static asdl_seq *_loop0_144_rule(Parser *p);
static asdl_seq *_gather_143_rule(Parser *p);
-static void *_tmp_145_rule(Parser *p);
-static void *_tmp_146_rule(Parser *p);
-static void *_tmp_147_rule(Parser *p);
-static void *_tmp_148_rule(Parser *p);
+static asdl_seq *_loop0_146_rule(Parser *p);
+static asdl_seq *_gather_145_rule(Parser *p);
+static asdl_seq *_loop0_148_rule(Parser *p);
+static asdl_seq *_gather_147_rule(Parser *p);
static void *_tmp_149_rule(Parser *p);
static void *_tmp_150_rule(Parser *p);
static void *_tmp_151_rule(Parser *p);
@@ -959,79 +996,79 @@ static void *_tmp_152_rule(Parser *p);
static void *_tmp_153_rule(Parser *p);
static void *_tmp_154_rule(Parser *p);
static void *_tmp_155_rule(Parser *p);
-static asdl_seq *_loop0_156_rule(Parser *p);
-static asdl_seq *_loop0_157_rule(Parser *p);
-static asdl_seq *_loop0_158_rule(Parser *p);
+static void *_tmp_156_rule(Parser *p);
+static void *_tmp_157_rule(Parser *p);
+static void *_tmp_158_rule(Parser *p);
static void *_tmp_159_rule(Parser *p);
static void *_tmp_160_rule(Parser *p);
-static void *_tmp_161_rule(Parser *p);
-static void *_tmp_162_rule(Parser *p);
-static void *_tmp_163_rule(Parser *p);
-static asdl_seq *_loop0_164_rule(Parser *p);
-static asdl_seq *_loop0_165_rule(Parser *p);
-static asdl_seq *_loop0_166_rule(Parser *p);
-static asdl_seq *_loop1_167_rule(Parser *p);
+static asdl_seq *_loop0_161_rule(Parser *p);
+static asdl_seq *_loop0_162_rule(Parser *p);
+static asdl_seq *_loop0_163_rule(Parser *p);
+static void *_tmp_164_rule(Parser *p);
+static void *_tmp_165_rule(Parser *p);
+static void *_tmp_166_rule(Parser *p);
+static void *_tmp_167_rule(Parser *p);
static void *_tmp_168_rule(Parser *p);
static asdl_seq *_loop0_169_rule(Parser *p);
-static void *_tmp_170_rule(Parser *p);
+static asdl_seq *_loop0_170_rule(Parser *p);
static asdl_seq *_loop0_171_rule(Parser *p);
static asdl_seq *_loop1_172_rule(Parser *p);
static void *_tmp_173_rule(Parser *p);
-static void *_tmp_174_rule(Parser *p);
+static asdl_seq *_loop0_174_rule(Parser *p);
static void *_tmp_175_rule(Parser *p);
static asdl_seq *_loop0_176_rule(Parser *p);
-static void *_tmp_177_rule(Parser *p);
+static asdl_seq *_loop1_177_rule(Parser *p);
static void *_tmp_178_rule(Parser *p);
-static asdl_seq *_loop1_179_rule(Parser *p);
+static void *_tmp_179_rule(Parser *p);
static void *_tmp_180_rule(Parser *p);
static asdl_seq *_loop0_181_rule(Parser *p);
-static asdl_seq *_loop0_182_rule(Parser *p);
-static asdl_seq *_loop0_183_rule(Parser *p);
-static asdl_seq *_loop0_185_rule(Parser *p);
-static asdl_seq *_gather_184_rule(Parser *p);
-static void *_tmp_186_rule(Parser *p);
+static void *_tmp_182_rule(Parser *p);
+static void *_tmp_183_rule(Parser *p);
+static asdl_seq *_loop1_184_rule(Parser *p);
+static void *_tmp_185_rule(Parser *p);
+static asdl_seq *_loop0_186_rule(Parser *p);
static asdl_seq *_loop0_187_rule(Parser *p);
-static void *_tmp_188_rule(Parser *p);
-static asdl_seq *_loop0_189_rule(Parser *p);
-static asdl_seq *_loop1_190_rule(Parser *p);
-static asdl_seq *_loop1_191_rule(Parser *p);
-static void *_tmp_192_rule(Parser *p);
+static asdl_seq *_loop0_188_rule(Parser *p);
+static asdl_seq *_loop0_190_rule(Parser *p);
+static asdl_seq *_gather_189_rule(Parser *p);
+static void *_tmp_191_rule(Parser *p);
+static asdl_seq *_loop0_192_rule(Parser *p);
static void *_tmp_193_rule(Parser *p);
static asdl_seq *_loop0_194_rule(Parser *p);
-static void *_tmp_195_rule(Parser *p);
-static void *_tmp_196_rule(Parser *p);
+static asdl_seq *_loop1_195_rule(Parser *p);
+static asdl_seq *_loop1_196_rule(Parser *p);
static void *_tmp_197_rule(Parser *p);
+static void *_tmp_198_rule(Parser *p);
static asdl_seq *_loop0_199_rule(Parser *p);
-static asdl_seq *_gather_198_rule(Parser *p);
-static asdl_seq *_loop0_201_rule(Parser *p);
-static asdl_seq *_gather_200_rule(Parser *p);
-static asdl_seq *_loop0_203_rule(Parser *p);
-static asdl_seq *_gather_202_rule(Parser *p);
-static asdl_seq *_loop0_205_rule(Parser *p);
-static asdl_seq *_gather_204_rule(Parser *p);
-static void *_tmp_206_rule(Parser *p);
-static asdl_seq *_loop0_207_rule(Parser *p);
-static asdl_seq *_loop1_208_rule(Parser *p);
-static void *_tmp_209_rule(Parser *p);
+static void *_tmp_200_rule(Parser *p);
+static void *_tmp_201_rule(Parser *p);
+static void *_tmp_202_rule(Parser *p);
+static asdl_seq *_loop0_204_rule(Parser *p);
+static asdl_seq *_gather_203_rule(Parser *p);
+static asdl_seq *_loop0_206_rule(Parser *p);
+static asdl_seq *_gather_205_rule(Parser *p);
+static asdl_seq *_loop0_208_rule(Parser *p);
+static asdl_seq *_gather_207_rule(Parser *p);
static asdl_seq *_loop0_210_rule(Parser *p);
-static asdl_seq *_loop1_211_rule(Parser *p);
-static void *_tmp_212_rule(Parser *p);
-static void *_tmp_213_rule(Parser *p);
+static asdl_seq *_gather_209_rule(Parser *p);
+static void *_tmp_211_rule(Parser *p);
+static asdl_seq *_loop0_212_rule(Parser *p);
+static asdl_seq *_loop1_213_rule(Parser *p);
static void *_tmp_214_rule(Parser *p);
-static void *_tmp_215_rule(Parser *p);
-static void *_tmp_216_rule(Parser *p);
+static asdl_seq *_loop0_215_rule(Parser *p);
+static asdl_seq *_loop1_216_rule(Parser *p);
static void *_tmp_217_rule(Parser *p);
static void *_tmp_218_rule(Parser *p);
static void *_tmp_219_rule(Parser *p);
static void *_tmp_220_rule(Parser *p);
static void *_tmp_221_rule(Parser *p);
-static asdl_seq *_loop0_223_rule(Parser *p);
-static asdl_seq *_gather_222_rule(Parser *p);
+static void *_tmp_222_rule(Parser *p);
+static void *_tmp_223_rule(Parser *p);
static void *_tmp_224_rule(Parser *p);
static void *_tmp_225_rule(Parser *p);
static void *_tmp_226_rule(Parser *p);
-static void *_tmp_227_rule(Parser *p);
-static void *_tmp_228_rule(Parser *p);
+static asdl_seq *_loop0_228_rule(Parser *p);
+static asdl_seq *_gather_227_rule(Parser *p);
static void *_tmp_229_rule(Parser *p);
static void *_tmp_230_rule(Parser *p);
static void *_tmp_231_rule(Parser *p);
@@ -1045,7 +1082,7 @@ static void *_tmp_238_rule(Parser *p);
static void *_tmp_239_rule(Parser *p);
static void *_tmp_240_rule(Parser *p);
static void *_tmp_241_rule(Parser *p);
-static void *_tmp_242_rule(Parser *p);
+static asdl_seq *_loop0_242_rule(Parser *p);
static void *_tmp_243_rule(Parser *p);
static void *_tmp_244_rule(Parser *p);
static void *_tmp_245_rule(Parser *p);
@@ -1057,6 +1094,27 @@ static void *_tmp_250_rule(Parser *p);
static void *_tmp_251_rule(Parser *p);
static void *_tmp_252_rule(Parser *p);
static void *_tmp_253_rule(Parser *p);
+static void *_tmp_254_rule(Parser *p);
+static void *_tmp_255_rule(Parser *p);
+static void *_tmp_256_rule(Parser *p);
+static void *_tmp_257_rule(Parser *p);
+static void *_tmp_258_rule(Parser *p);
+static void *_tmp_259_rule(Parser *p);
+static void *_tmp_260_rule(Parser *p);
+static void *_tmp_261_rule(Parser *p);
+static void *_tmp_262_rule(Parser *p);
+static void *_tmp_263_rule(Parser *p);
+static void *_tmp_264_rule(Parser *p);
+static void *_tmp_265_rule(Parser *p);
+static void *_tmp_266_rule(Parser *p);
+static void *_tmp_267_rule(Parser *p);
+static void *_tmp_268_rule(Parser *p);
+static void *_tmp_269_rule(Parser *p);
+static void *_tmp_270_rule(Parser *p);
+static void *_tmp_271_rule(Parser *p);
+static void *_tmp_272_rule(Parser *p);
+static void *_tmp_273_rule(Parser *p);
+static void *_tmp_274_rule(Parser *p);
// file: statements? $
@@ -1262,7 +1320,7 @@ func_type_rule(Parser *p)
return _res;
}
-// fstring: star_expressions
+// fstring: FSTRING_START fstring_middle* FSTRING_END
static expr_ty
fstring_rule(Parser *p)
{
@@ -1276,24 +1334,35 @@ fstring_rule(Parser *p)
}
expr_ty _res = NULL;
int _mark = p->mark;
- { // star_expressions
+ { // FSTRING_START fstring_middle* FSTRING_END
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
- expr_ty star_expressions_var;
+ D(fprintf(stderr, "%*c> fstring[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END"));
+ Token * a;
+ asdl_seq * b;
+ Token * c;
if (
- (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ (a = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START'
+ &&
+ (b = _loop0_3_rule(p)) // fstring_middle*
+ &&
+ (c = _PyPegen_expect_token(p, FSTRING_END)) // token='FSTRING_END'
)
{
- D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
- _res = star_expressions_var;
+ D(fprintf(stderr, "%*c+ fstring[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END"));
+ _res = _PyPegen_joined_str ( p , a , ( asdl_expr_seq* ) b , c );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
goto done;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s fstring[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START fstring_middle* FSTRING_END"));
}
_res = NULL;
done:
@@ -1323,7 +1392,7 @@ statements_rule(Parser *p)
D(fprintf(stderr, "%*c> statements[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement+"));
asdl_seq * a;
if (
- (a = _loop1_3_rule(p)) // statement+
+ (a = _loop1_4_rule(p)) // statement+
)
{
D(fprintf(stderr, "%*c+ statements[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "statement+"));
@@ -1599,7 +1668,7 @@ simple_stmts_rule(Parser *p)
asdl_stmt_seq* a;
Token * newline_var;
if (
- (a = (asdl_stmt_seq*)_gather_4_rule(p)) // ';'.simple_stmt+
+ (a = (asdl_stmt_seq*)_gather_5_rule(p)) // ';'.simple_stmt+
&&
(_opt_var = _PyPegen_expect_token(p, 13), !p->error_indicator) // ';'?
&&
@@ -1766,7 +1835,7 @@ simple_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('import' | 'from') import_stmt"));
stmt_ty import_stmt_var;
if (
- _PyPegen_lookahead(1, _tmp_6_rule, p)
+ _PyPegen_lookahead(1, _tmp_7_rule, p)
&&
(import_stmt_var = import_stmt_rule(p)) // import_stmt
)
@@ -1841,7 +1910,7 @@ simple_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> simple_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'del' del_stmt"));
stmt_ty del_stmt_var;
if (
- _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 603) // token='del'
+ _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 604) // token='del'
&&
(del_stmt_var = del_stmt_rule(p)) // del_stmt
)
@@ -2041,7 +2110,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('def' | '@' | ASYNC) function_def"));
stmt_ty function_def_var;
if (
- _PyPegen_lookahead(1, _tmp_7_rule, p)
+ _PyPegen_lookahead(1, _tmp_8_rule, p)
&&
(function_def_var = function_def_rule(p)) // function_def
)
@@ -2062,7 +2131,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'if' if_stmt"));
stmt_ty if_stmt_var;
if (
- _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 641) // token='if'
+ _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 642) // token='if'
&&
(if_stmt_var = if_stmt_rule(p)) // if_stmt
)
@@ -2083,7 +2152,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('class' | '@') class_def"));
stmt_ty class_def_var;
if (
- _PyPegen_lookahead(1, _tmp_8_rule, p)
+ _PyPegen_lookahead(1, _tmp_9_rule, p)
&&
(class_def_var = class_def_rule(p)) // class_def
)
@@ -2104,7 +2173,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('with' | ASYNC) with_stmt"));
stmt_ty with_stmt_var;
if (
- _PyPegen_lookahead(1, _tmp_9_rule, p)
+ _PyPegen_lookahead(1, _tmp_10_rule, p)
&&
(with_stmt_var = with_stmt_rule(p)) // with_stmt
)
@@ -2125,7 +2194,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&('for' | ASYNC) for_stmt"));
stmt_ty for_stmt_var;
if (
- _PyPegen_lookahead(1, _tmp_10_rule, p)
+ _PyPegen_lookahead(1, _tmp_11_rule, p)
&&
(for_stmt_var = for_stmt_rule(p)) // for_stmt
)
@@ -2146,7 +2215,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'try' try_stmt"));
stmt_ty try_stmt_var;
if (
- _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 623) // token='try'
+ _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 624) // token='try'
&&
(try_stmt_var = try_stmt_rule(p)) // try_stmt
)
@@ -2167,7 +2236,7 @@ compound_stmt_rule(Parser *p)
D(fprintf(stderr, "%*c> compound_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'while' while_stmt"));
stmt_ty while_stmt_var;
if (
- _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 646) // token='while'
+ _PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 647) // token='while'
&&
(while_stmt_var = while_stmt_rule(p)) // while_stmt
)
@@ -2250,7 +2319,7 @@ assignment_rule(Parser *p)
&&
(b = expression_rule(p)) // expression
&&
- (c = _tmp_11_rule(p), !p->error_indicator) // ['=' annotated_rhs]
+ (c = _tmp_12_rule(p), !p->error_indicator) // ['=' annotated_rhs]
)
{
D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ':' expression ['=' annotated_rhs]"));
@@ -2286,13 +2355,13 @@ assignment_rule(Parser *p)
expr_ty b;
void *c;
if (
- (a = _tmp_12_rule(p)) // '(' single_target ')' | single_subscript_attribute_target
+ (a = _tmp_13_rule(p)) // '(' single_target ')' | single_subscript_attribute_target
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
(b = expression_rule(p)) // expression
&&
- (c = _tmp_13_rule(p), !p->error_indicator) // ['=' annotated_rhs]
+ (c = _tmp_14_rule(p), !p->error_indicator) // ['=' annotated_rhs]
)
{
D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "('(' single_target ')' | single_subscript_attribute_target) ':' expression ['=' annotated_rhs]"));
@@ -2327,9 +2396,9 @@ assignment_rule(Parser *p)
void *b;
void *tc;
if (
- (a = (asdl_expr_seq*)_loop1_14_rule(p)) // ((star_targets '='))+
+ (a = (asdl_expr_seq*)_loop1_15_rule(p)) // ((star_targets '='))+
&&
- (b = _tmp_15_rule(p)) // yield_expr | star_expressions
+ (b = _tmp_16_rule(p)) // yield_expr | star_expressions
&&
_PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='='
&&
@@ -2375,7 +2444,7 @@ assignment_rule(Parser *p)
&&
(_cut_var = 1)
&&
- (c = _tmp_16_rule(p)) // yield_expr | star_expressions
+ (c = _tmp_17_rule(p)) // yield_expr | star_expressions
)
{
D(fprintf(stderr, "%*c+ assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_target augassign ~ (yield_expr | star_expressions)"));
@@ -2934,7 +3003,7 @@ raise_stmt_rule(Parser *p)
&&
(a = expression_rule(p)) // expression
&&
- (b = _tmp_17_rule(p), !p->error_indicator) // ['from' expression]
+ (b = _tmp_18_rule(p), !p->error_indicator) // ['from' expression]
)
{
D(fprintf(stderr, "%*c+ raise_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'raise' expression ['from' expression]"));
@@ -3032,7 +3101,7 @@ global_stmt_rule(Parser *p)
if (
(_keyword = _PyPegen_expect_token(p, 523)) // token='global'
&&
- (a = (asdl_expr_seq*)_gather_18_rule(p)) // ','.NAME+
+ (a = (asdl_expr_seq*)_gather_19_rule(p)) // ','.NAME+
)
{
D(fprintf(stderr, "%*c+ global_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'global' ','.NAME+"));
@@ -3097,7 +3166,7 @@ nonlocal_stmt_rule(Parser *p)
if (
(_keyword = _PyPegen_expect_token(p, 524)) // token='nonlocal'
&&
- (a = (asdl_expr_seq*)_gather_20_rule(p)) // ','.NAME+
+ (a = (asdl_expr_seq*)_gather_21_rule(p)) // ','.NAME+
)
{
D(fprintf(stderr, "%*c+ nonlocal_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'nonlocal' ','.NAME+"));
@@ -3160,11 +3229,11 @@ del_stmt_rule(Parser *p)
Token * _keyword;
asdl_expr_seq* a;
if (
- (_keyword = _PyPegen_expect_token(p, 603)) // token='del'
+ (_keyword = _PyPegen_expect_token(p, 604)) // token='del'
&&
(a = del_targets_rule(p)) // del_targets
&&
- _PyPegen_lookahead(1, _tmp_22_rule, p)
+ _PyPegen_lookahead(1, _tmp_23_rule, p)
)
{
D(fprintf(stderr, "%*c+ del_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'del' del_targets &(';' | NEWLINE)"));
@@ -3313,7 +3382,7 @@ assert_stmt_rule(Parser *p)
&&
(a = expression_rule(p)) // expression
&&
- (b = _tmp_23_rule(p), !p->error_indicator) // [',' expression]
+ (b = _tmp_24_rule(p), !p->error_indicator) // [',' expression]
)
{
D(fprintf(stderr, "%*c+ assert_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'assert' expression [',' expression]"));
@@ -3453,7 +3522,7 @@ import_name_rule(Parser *p)
Token * _keyword;
asdl_alias_seq* a;
if (
- (_keyword = _PyPegen_expect_token(p, 606)) // token='import'
+ (_keyword = _PyPegen_expect_token(p, 607)) // token='import'
&&
(a = dotted_as_names_rule(p)) // dotted_as_names
)
@@ -3523,13 +3592,13 @@ import_from_rule(Parser *p)
expr_ty b;
asdl_alias_seq* c;
if (
- (_keyword = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword = _PyPegen_expect_token(p, 608)) // token='from'
&&
- (a = _loop0_24_rule(p)) // (('.' | '...'))*
+ (a = _loop0_25_rule(p)) // (('.' | '...'))*
&&
(b = dotted_name_rule(p)) // dotted_name
&&
- (_keyword_1 = _PyPegen_expect_token(p, 606)) // token='import'
+ (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='import'
&&
(c = import_from_targets_rule(p)) // import_from_targets
)
@@ -3567,11 +3636,11 @@ import_from_rule(Parser *p)
asdl_seq * a;
asdl_alias_seq* b;
if (
- (_keyword = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword = _PyPegen_expect_token(p, 608)) // token='from'
&&
- (a = _loop1_25_rule(p)) // (('.' | '...'))+
+ (a = _loop1_26_rule(p)) // (('.' | '...'))+
&&
- (_keyword_1 = _PyPegen_expect_token(p, 606)) // token='import'
+ (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='import'
&&
(b = import_from_targets_rule(p)) // import_from_targets
)
@@ -3766,7 +3835,7 @@ import_from_as_names_rule(Parser *p)
D(fprintf(stderr, "%*c> import_from_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+"));
asdl_alias_seq* a;
if (
- (a = (asdl_alias_seq*)_gather_26_rule(p)) // ','.import_from_as_name+
+ (a = (asdl_alias_seq*)_gather_27_rule(p)) // ','.import_from_as_name+
)
{
D(fprintf(stderr, "%*c+ import_from_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.import_from_as_name+"));
@@ -3822,7 +3891,7 @@ import_from_as_name_rule(Parser *p)
if (
(a = _PyPegen_name_token(p)) // NAME
&&
- (b = _tmp_28_rule(p), !p->error_indicator) // ['as' NAME]
+ (b = _tmp_29_rule(p), !p->error_indicator) // ['as' NAME]
)
{
D(fprintf(stderr, "%*c+ import_from_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME ['as' NAME]"));
@@ -3875,7 +3944,7 @@ dotted_as_names_rule(Parser *p)
D(fprintf(stderr, "%*c> dotted_as_names[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+"));
asdl_alias_seq* a;
if (
- (a = (asdl_alias_seq*)_gather_29_rule(p)) // ','.dotted_as_name+
+ (a = (asdl_alias_seq*)_gather_30_rule(p)) // ','.dotted_as_name+
)
{
D(fprintf(stderr, "%*c+ dotted_as_names[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.dotted_as_name+"));
@@ -3931,7 +4000,7 @@ dotted_as_name_rule(Parser *p)
if (
(a = dotted_name_rule(p)) // dotted_name
&&
- (b = _tmp_31_rule(p), !p->error_indicator) // ['as' NAME]
+ (b = _tmp_32_rule(p), !p->error_indicator) // ['as' NAME]
)
{
D(fprintf(stderr, "%*c+ dotted_as_name[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_name ['as' NAME]"));
@@ -4186,7 +4255,7 @@ decorators_rule(Parser *p)
D(fprintf(stderr, "%*c> decorators[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+"));
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_loop1_32_rule(p)) // (('@' named_expression NEWLINE))+
+ (a = (asdl_expr_seq*)_loop1_33_rule(p)) // (('@' named_expression NEWLINE))+
)
{
D(fprintf(stderr, "%*c+ decorators[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(('@' named_expression NEWLINE))+"));
@@ -4331,13 +4400,13 @@ class_def_raw_rule(Parser *p)
asdl_stmt_seq* c;
void *t;
if (
- (_keyword = _PyPegen_expect_token(p, 653)) // token='class'
+ (_keyword = _PyPegen_expect_token(p, 654)) // token='class'
&&
(a = _PyPegen_name_token(p)) // NAME
&&
(t = type_params_rule(p), !p->error_indicator) // type_params?
&&
- (b = _tmp_33_rule(p), !p->error_indicator) // ['(' arguments? ')']
+ (b = _tmp_34_rule(p), !p->error_indicator) // ['(' arguments? ')']
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -4500,7 +4569,7 @@ function_def_raw_rule(Parser *p)
void *t;
void *tc;
if (
- (_keyword = _PyPegen_expect_token(p, 651)) // token='def'
+ (_keyword = _PyPegen_expect_token(p, 652)) // token='def'
&&
(n = _PyPegen_name_token(p)) // NAME
&&
@@ -4512,7 +4581,7 @@ function_def_raw_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
&&
- (a = _tmp_34_rule(p), !p->error_indicator) // ['->' expression]
+ (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression]
&&
(_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
@@ -4563,7 +4632,7 @@ function_def_raw_rule(Parser *p)
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
&&
- (_keyword = _PyPegen_expect_token(p, 651)) // token='def'
+ (_keyword = _PyPegen_expect_token(p, 652)) // token='def'
&&
(n = _PyPegen_name_token(p)) // NAME
&&
@@ -4575,7 +4644,7 @@ function_def_raw_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
&&
- (a = _tmp_35_rule(p), !p->error_indicator) // ['->' expression]
+ (a = _tmp_36_rule(p), !p->error_indicator) // ['->' expression]
&&
(_literal_2 = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
@@ -4702,9 +4771,9 @@ parameters_rule(Parser *p)
if (
(a = slash_no_default_rule(p)) // slash_no_default
&&
- (b = (asdl_arg_seq*)_loop0_36_rule(p)) // param_no_default*
+ (b = (asdl_arg_seq*)_loop0_37_rule(p)) // param_no_default*
&&
- (c = _loop0_37_rule(p)) // param_with_default*
+ (c = _loop0_38_rule(p)) // param_with_default*
&&
(d = star_etc_rule(p), !p->error_indicator) // star_etc?
)
@@ -4734,7 +4803,7 @@ parameters_rule(Parser *p)
if (
(a = slash_with_default_rule(p)) // slash_with_default
&&
- (b = _loop0_38_rule(p)) // param_with_default*
+ (b = _loop0_39_rule(p)) // param_with_default*
&&
(c = star_etc_rule(p), !p->error_indicator) // star_etc?
)
@@ -4762,9 +4831,9 @@ parameters_rule(Parser *p)
asdl_seq * b;
void *c;
if (
- (a = (asdl_arg_seq*)_loop1_39_rule(p)) // param_no_default+
+ (a = (asdl_arg_seq*)_loop1_40_rule(p)) // param_no_default+
&&
- (b = _loop0_40_rule(p)) // param_with_default*
+ (b = _loop0_41_rule(p)) // param_with_default*
&&
(c = star_etc_rule(p), !p->error_indicator) // star_etc?
)
@@ -4791,7 +4860,7 @@ parameters_rule(Parser *p)
asdl_seq * a;
void *b;
if (
- (a = _loop1_41_rule(p)) // param_with_default+
+ (a = _loop1_42_rule(p)) // param_with_default+
&&
(b = star_etc_rule(p), !p->error_indicator) // star_etc?
)
@@ -4863,7 +4932,7 @@ slash_no_default_rule(Parser *p)
Token * _literal_1;
asdl_arg_seq* a;
if (
- (a = (asdl_arg_seq*)_loop1_42_rule(p)) // param_no_default+
+ (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -4892,7 +4961,7 @@ slash_no_default_rule(Parser *p)
Token * _literal;
asdl_arg_seq* a;
if (
- (a = (asdl_arg_seq*)_loop1_43_rule(p)) // param_no_default+
+ (a = (asdl_arg_seq*)_loop1_44_rule(p)) // param_no_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -4945,9 +5014,9 @@ slash_with_default_rule(Parser *p)
asdl_seq * a;
asdl_seq * b;
if (
- (a = _loop0_44_rule(p)) // param_no_default*
+ (a = _loop0_45_rule(p)) // param_no_default*
&&
- (b = _loop1_45_rule(p)) // param_with_default+
+ (b = _loop1_46_rule(p)) // param_with_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -4977,9 +5046,9 @@ slash_with_default_rule(Parser *p)
asdl_seq * a;
asdl_seq * b;
if (
- (a = _loop0_46_rule(p)) // param_no_default*
+ (a = _loop0_47_rule(p)) // param_no_default*
&&
- (b = _loop1_47_rule(p)) // param_with_default+
+ (b = _loop1_48_rule(p)) // param_with_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -5058,7 +5127,7 @@ star_etc_rule(Parser *p)
&&
(a = param_no_default_rule(p)) // param_no_default
&&
- (b = _loop0_48_rule(p)) // param_maybe_default*
+ (b = _loop0_49_rule(p)) // param_maybe_default*
&&
(c = kwds_rule(p), !p->error_indicator) // kwds?
)
@@ -5091,7 +5160,7 @@ star_etc_rule(Parser *p)
&&
(a = param_no_default_star_annotation_rule(p)) // param_no_default_star_annotation
&&
- (b = _loop0_49_rule(p)) // param_maybe_default*
+ (b = _loop0_50_rule(p)) // param_maybe_default*
&&
(c = kwds_rule(p), !p->error_indicator) // kwds?
)
@@ -5124,7 +5193,7 @@ star_etc_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 12)) // token=','
&&
- (b = _loop1_50_rule(p)) // param_maybe_default+
+ (b = _loop1_51_rule(p)) // param_maybe_default+
&&
(c = kwds_rule(p), !p->error_indicator) // kwds?
)
@@ -5917,7 +5986,7 @@ if_stmt_rule(Parser *p)
asdl_stmt_seq* b;
stmt_ty c;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(a = named_expression_rule(p)) // named_expression
&&
@@ -5962,7 +6031,7 @@ if_stmt_rule(Parser *p)
asdl_stmt_seq* b;
void *c;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(a = named_expression_rule(p)) // named_expression
&&
@@ -6058,7 +6127,7 @@ elif_stmt_rule(Parser *p)
asdl_stmt_seq* b;
stmt_ty c;
if (
- (_keyword = _PyPegen_expect_token(p, 643)) // token='elif'
+ (_keyword = _PyPegen_expect_token(p, 644)) // token='elif'
&&
(a = named_expression_rule(p)) // named_expression
&&
@@ -6103,7 +6172,7 @@ elif_stmt_rule(Parser *p)
asdl_stmt_seq* b;
void *c;
if (
- (_keyword = _PyPegen_expect_token(p, 643)) // token='elif'
+ (_keyword = _PyPegen_expect_token(p, 644)) // token='elif'
&&
(a = named_expression_rule(p)) // named_expression
&&
@@ -6185,7 +6254,7 @@ else_block_rule(Parser *p)
Token * _literal;
asdl_stmt_seq* b;
if (
- (_keyword = _PyPegen_expect_token(p, 644)) // token='else'
+ (_keyword = _PyPegen_expect_token(p, 645)) // token='else'
&&
(_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
@@ -6265,7 +6334,7 @@ while_stmt_rule(Parser *p)
asdl_stmt_seq* b;
void *c;
if (
- (_keyword = _PyPegen_expect_token(p, 646)) // token='while'
+ (_keyword = _PyPegen_expect_token(p, 647)) // token='while'
&&
(a = named_expression_rule(p)) // named_expression
&&
@@ -6366,11 +6435,11 @@ for_stmt_rule(Parser *p)
expr_ty t;
void *tc;
if (
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(t = star_targets_rule(p)) // star_targets
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(_cut_var = 1)
&&
@@ -6430,11 +6499,11 @@ for_stmt_rule(Parser *p)
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
&&
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(t = star_targets_rule(p)) // star_targets
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(_cut_var = 1)
&&
@@ -6563,11 +6632,11 @@ with_stmt_rule(Parser *p)
asdl_withitem_seq* a;
asdl_stmt_seq* b;
if (
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (a = (asdl_withitem_seq*)_gather_51_rule(p)) // ','.with_item+
+ (a = (asdl_withitem_seq*)_gather_52_rule(p)) // ','.with_item+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -6612,9 +6681,9 @@ with_stmt_rule(Parser *p)
asdl_stmt_seq* b;
void *tc;
if (
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
- (a = (asdl_withitem_seq*)_gather_53_rule(p)) // ','.with_item+
+ (a = (asdl_withitem_seq*)_gather_54_rule(p)) // ','.with_item+
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -6663,11 +6732,11 @@ with_stmt_rule(Parser *p)
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
&&
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (a = (asdl_withitem_seq*)_gather_55_rule(p)) // ','.with_item+
+ (a = (asdl_withitem_seq*)_gather_56_rule(p)) // ','.with_item+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -6715,9 +6784,9 @@ with_stmt_rule(Parser *p)
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
&&
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
- (a = (asdl_withitem_seq*)_gather_57_rule(p)) // ','.with_item+
+ (a = (asdl_withitem_seq*)_gather_58_rule(p)) // ','.with_item+
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -6802,11 +6871,11 @@ with_item_rule(Parser *p)
if (
(e = expression_rule(p)) // expression
&&
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(t = star_target_rule(p)) // star_target
&&
- _PyPegen_lookahead(1, _tmp_59_rule, p)
+ _PyPegen_lookahead(1, _tmp_60_rule, p)
)
{
D(fprintf(stderr, "%*c+ with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' star_target &(',' | ')' | ':')"));
@@ -6928,7 +6997,7 @@ try_stmt_rule(Parser *p)
asdl_stmt_seq* b;
asdl_stmt_seq* f;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
@@ -6972,13 +7041,13 @@ try_stmt_rule(Parser *p)
asdl_excepthandler_seq* ex;
void *f;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
(b = block_rule(p)) // block
&&
- (ex = (asdl_excepthandler_seq*)_loop1_60_rule(p)) // except_block+
+ (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_block+
&&
(el = else_block_rule(p), !p->error_indicator) // else_block?
&&
@@ -7020,13 +7089,13 @@ try_stmt_rule(Parser *p)
asdl_excepthandler_seq* ex;
void *f;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
(b = block_rule(p)) // block
&&
- (ex = (asdl_excepthandler_seq*)_loop1_61_rule(p)) // except_star_block+
+ (ex = (asdl_excepthandler_seq*)_loop1_62_rule(p)) // except_star_block+
&&
(el = else_block_rule(p), !p->error_indicator) // else_block?
&&
@@ -7119,11 +7188,11 @@ except_block_rule(Parser *p)
expr_ty e;
void *t;
if (
- (_keyword = _PyPegen_expect_token(p, 636)) // token='except'
+ (_keyword = _PyPegen_expect_token(p, 637)) // token='except'
&&
(e = expression_rule(p)) // expression
&&
- (t = _tmp_62_rule(p), !p->error_indicator) // ['as' NAME]
+ (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -7162,7 +7231,7 @@ except_block_rule(Parser *p)
Token * _literal;
asdl_stmt_seq* b;
if (
- (_keyword = _PyPegen_expect_token(p, 636)) // token='except'
+ (_keyword = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -7274,13 +7343,13 @@ except_star_block_rule(Parser *p)
expr_ty e;
void *t;
if (
- (_keyword = _PyPegen_expect_token(p, 636)) // token='except'
+ (_keyword = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
(e = expression_rule(p)) // expression
&&
- (t = _tmp_63_rule(p), !p->error_indicator) // ['as' NAME]
+ (t = _tmp_64_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -7377,7 +7446,7 @@ finally_block_rule(Parser *p)
Token * _literal;
asdl_stmt_seq* a;
if (
- (_keyword = _PyPegen_expect_token(p, 632)) // token='finally'
+ (_keyword = _PyPegen_expect_token(p, 633)) // token='finally'
&&
(_literal = _PyPegen_expect_forced_token(p, 11, ":")) // forced_token=':'
&&
@@ -7452,7 +7521,7 @@ match_stmt_rule(Parser *p)
&&
(indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT'
&&
- (cases = (asdl_match_case_seq*)_loop1_64_rule(p)) // case_block+
+ (cases = (asdl_match_case_seq*)_loop1_65_rule(p)) // case_block+
&&
(dedent_var = _PyPegen_expect_token(p, DEDENT)) // token='DEDENT'
)
@@ -7689,7 +7758,7 @@ guard_rule(Parser *p)
Token * _keyword;
expr_ty guard;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(guard = named_expression_rule(p)) // named_expression
)
@@ -7887,7 +7956,7 @@ as_pattern_rule(Parser *p)
if (
(pattern = or_pattern_rule(p)) // or_pattern
&&
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(target = pattern_capture_target_rule(p)) // pattern_capture_target
)
@@ -7970,7 +8039,7 @@ or_pattern_rule(Parser *p)
D(fprintf(stderr, "%*c> or_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+"));
asdl_pattern_seq* patterns;
if (
- (patterns = (asdl_pattern_seq*)_gather_65_rule(p)) // '|'.closed_pattern+
+ (patterns = (asdl_pattern_seq*)_gather_66_rule(p)) // '|'.closed_pattern+
)
{
D(fprintf(stderr, "%*c+ or_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'|'.closed_pattern+"));
@@ -8225,7 +8294,7 @@ literal_pattern_rule(Parser *p)
if (
(value = signed_number_rule(p)) // signed_number
&&
- _PyPegen_lookahead(0, _tmp_67_rule, p)
+ _PyPegen_lookahead(0, _tmp_68_rule, p)
)
{
D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')"));
@@ -8324,7 +8393,7 @@ literal_pattern_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 601)) // token='None'
+ (_keyword = _PyPegen_expect_token(p, 602)) // token='None'
)
{
D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
@@ -8357,7 +8426,7 @@ literal_pattern_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 600)) // token='True'
+ (_keyword = _PyPegen_expect_token(p, 601)) // token='True'
)
{
D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
@@ -8390,7 +8459,7 @@ literal_pattern_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 602)) // token='False'
+ (_keyword = _PyPegen_expect_token(p, 603)) // token='False'
)
{
D(fprintf(stderr, "%*c+ literal_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
@@ -8460,7 +8529,7 @@ literal_expr_rule(Parser *p)
if (
(signed_number_var = signed_number_rule(p)) // signed_number
&&
- _PyPegen_lookahead(0, _tmp_68_rule, p)
+ _PyPegen_lookahead(0, _tmp_69_rule, p)
)
{
D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "signed_number !('+' | '-')"));
@@ -8517,7 +8586,7 @@ literal_expr_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 601)) // token='None'
+ (_keyword = _PyPegen_expect_token(p, 602)) // token='None'
)
{
D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
@@ -8550,7 +8619,7 @@ literal_expr_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 600)) // token='True'
+ (_keyword = _PyPegen_expect_token(p, 601)) // token='True'
)
{
D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
@@ -8583,7 +8652,7 @@ literal_expr_rule(Parser *p)
D(fprintf(stderr, "%*c> literal_expr[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 602)) // token='False'
+ (_keyword = _PyPegen_expect_token(p, 603)) // token='False'
)
{
D(fprintf(stderr, "%*c+ literal_expr[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
@@ -9067,7 +9136,7 @@ pattern_capture_target_rule(Parser *p)
&&
(name = _PyPegen_name_token(p)) // NAME
&&
- _PyPegen_lookahead(0, _tmp_69_rule, p)
+ _PyPegen_lookahead(0, _tmp_70_rule, p)
)
{
D(fprintf(stderr, "%*c+ pattern_capture_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!\"_\" NAME !('.' | '(' | '=')"));
@@ -9184,7 +9253,7 @@ value_pattern_rule(Parser *p)
if (
(attr = attr_rule(p)) // attr
&&
- _PyPegen_lookahead(0, _tmp_70_rule, p)
+ _PyPegen_lookahead(0, _tmp_71_rule, p)
)
{
D(fprintf(stderr, "%*c+ value_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr !('.' | '(' | '=')"));
@@ -9610,7 +9679,7 @@ maybe_sequence_pattern_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_seq * patterns;
if (
- (patterns = _gather_71_rule(p)) // ','.maybe_star_pattern+
+ (patterns = _gather_72_rule(p)) // ','.maybe_star_pattern+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -10022,13 +10091,13 @@ items_pattern_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> items_pattern[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+"));
- asdl_seq * _gather_73_var;
+ asdl_seq * _gather_74_var;
if (
- (_gather_73_var = _gather_73_rule(p)) // ','.key_value_pattern+
+ (_gather_74_var = _gather_74_rule(p)) // ','.key_value_pattern+
)
{
D(fprintf(stderr, "%*c+ items_pattern[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.key_value_pattern+"));
- _res = _gather_73_var;
+ _res = _gather_74_var;
goto done;
}
p->mark = _mark;
@@ -10065,7 +10134,7 @@ key_value_pattern_rule(Parser *p)
void *key;
pattern_ty pattern;
if (
- (key = _tmp_75_rule(p)) // literal_expr | attr
+ (key = _tmp_76_rule(p)) // literal_expr | attr
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -10396,7 +10465,7 @@ positional_patterns_rule(Parser *p)
D(fprintf(stderr, "%*c> positional_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.pattern+"));
asdl_pattern_seq* args;
if (
- (args = (asdl_pattern_seq*)_gather_76_rule(p)) // ','.pattern+
+ (args = (asdl_pattern_seq*)_gather_77_rule(p)) // ','.pattern+
)
{
D(fprintf(stderr, "%*c+ positional_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.pattern+"));
@@ -10438,13 +10507,13 @@ keyword_patterns_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> keyword_patterns[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+"));
- asdl_seq * _gather_78_var;
+ asdl_seq * _gather_79_var;
if (
- (_gather_78_var = _gather_78_rule(p)) // ','.keyword_pattern+
+ (_gather_79_var = _gather_79_rule(p)) // ','.keyword_pattern+
)
{
D(fprintf(stderr, "%*c+ keyword_patterns[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.keyword_pattern+"));
- _res = _gather_78_var;
+ _res = _gather_79_var;
goto done;
}
p->mark = _mark;
@@ -10655,7 +10724,7 @@ type_param_seq_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_typeparam_seq* a;
if (
- (a = (asdl_typeparam_seq*)_gather_80_rule(p)) // ','.type_param+
+ (a = (asdl_typeparam_seq*)_gather_81_rule(p)) // ','.type_param+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -10904,7 +10973,7 @@ expressions_rule(Parser *p)
if (
(a = expression_rule(p)) // expression
&&
- (b = _loop1_82_rule(p)) // ((',' expression))+
+ (b = _loop1_83_rule(p)) // ((',' expression))+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -11076,11 +11145,11 @@ expression_rule(Parser *p)
if (
(a = disjunction_rule(p)) // disjunction
&&
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(b = disjunction_rule(p)) // disjunction
&&
- (_keyword_1 = _PyPegen_expect_token(p, 644)) // token='else'
+ (_keyword_1 = _PyPegen_expect_token(p, 645)) // token='else'
&&
(c = expression_rule(p)) // expression
)
@@ -11187,7 +11256,7 @@ yield_expr_rule(Parser *p)
if (
(_keyword = _PyPegen_expect_token(p, 573)) // token='yield'
&&
- (_keyword_1 = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword_1 = _PyPegen_expect_token(p, 608)) // token='from'
&&
(a = expression_rule(p)) // expression
)
@@ -11295,7 +11364,7 @@ star_expressions_rule(Parser *p)
if (
(a = star_expression_rule(p)) // star_expression
&&
- (b = _loop1_83_rule(p)) // ((',' star_expression))+
+ (b = _loop1_84_rule(p)) // ((',' star_expression))+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -11496,7 +11565,7 @@ star_named_expressions_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_gather_84_rule(p)) // ','.star_named_expression+
+ (a = (asdl_expr_seq*)_gather_85_rule(p)) // ','.star_named_expression+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -11796,7 +11865,7 @@ disjunction_rule(Parser *p)
if (
(a = conjunction_rule(p)) // conjunction
&&
- (b = _loop1_86_rule(p)) // (('or' conjunction))+
+ (b = _loop1_87_rule(p)) // (('or' conjunction))+
)
{
D(fprintf(stderr, "%*c+ disjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "conjunction (('or' conjunction))+"));
@@ -11885,7 +11954,7 @@ conjunction_rule(Parser *p)
if (
(a = inversion_rule(p)) // inversion
&&
- (b = _loop1_87_rule(p)) // (('and' inversion))+
+ (b = _loop1_88_rule(p)) // (('and' inversion))+
)
{
D(fprintf(stderr, "%*c+ conjunction[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "inversion (('and' inversion))+"));
@@ -12059,7 +12128,7 @@ comparison_rule(Parser *p)
if (
(a = bitwise_or_rule(p)) // bitwise_or
&&
- (b = _loop1_88_rule(p)) // compare_op_bitwise_or_pair+
+ (b = _loop1_89_rule(p)) // compare_op_bitwise_or_pair+
)
{
D(fprintf(stderr, "%*c+ comparison[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "bitwise_or compare_op_bitwise_or_pair+"));
@@ -12396,10 +12465,10 @@ noteq_bitwise_or_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> noteq_bitwise_or[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('!=') bitwise_or"));
- void *_tmp_89_var;
+ void *_tmp_90_var;
expr_ty a;
if (
- (_tmp_89_var = _tmp_89_rule(p)) // '!='
+ (_tmp_90_var = _tmp_90_rule(p)) // '!='
&&
(a = bitwise_or_rule(p)) // bitwise_or
)
@@ -12637,7 +12706,7 @@ notin_bitwise_or_rule(Parser *p)
if (
(_keyword = _PyPegen_expect_token(p, 581)) // token='not'
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(a = bitwise_or_rule(p)) // bitwise_or
)
@@ -12684,7 +12753,7 @@ in_bitwise_or_rule(Parser *p)
Token * _keyword;
expr_ty a;
if (
- (_keyword = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword = _PyPegen_expect_token(p, 651)) // token='in'
&&
(a = bitwise_or_rule(p)) // bitwise_or
)
@@ -14434,7 +14503,7 @@ slices_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_gather_90_rule(p)) // ','.(slice | starred_expression)+
+ (a = (asdl_expr_seq*)_gather_91_rule(p)) // ','.(slice | starred_expression)+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -14507,7 +14576,7 @@ slice_rule(Parser *p)
&&
(b = expression_rule(p), !p->error_indicator) // expression?
&&
- (c = _tmp_92_rule(p), !p->error_indicator) // [':' expression?]
+ (c = _tmp_93_rule(p), !p->error_indicator) // [':' expression?]
)
{
D(fprintf(stderr, "%*c+ slice[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression? ':' expression? [':' expression?]"));
@@ -14567,7 +14636,7 @@ slice_rule(Parser *p)
// | 'True'
// | 'False'
// | 'None'
-// | &STRING strings
+// | &(STRING | FSTRING_START) strings
// | NUMBER
// | &'(' (tuple | group | genexp)
// | &'[' (list | listcomp)
@@ -14622,7 +14691,7 @@ atom_rule(Parser *p)
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 600)) // token='True'
+ (_keyword = _PyPegen_expect_token(p, 601)) // token='True'
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
@@ -14655,7 +14724,7 @@ atom_rule(Parser *p)
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 602)) // token='False'
+ (_keyword = _PyPegen_expect_token(p, 603)) // token='False'
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
@@ -14688,7 +14757,7 @@ atom_rule(Parser *p)
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 601)) // token='None'
+ (_keyword = _PyPegen_expect_token(p, 602)) // token='None'
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
@@ -14713,26 +14782,26 @@ atom_rule(Parser *p)
D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'"));
}
- { // &STRING strings
+ { // &(STRING | FSTRING_START) strings
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&STRING strings"));
+ D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings"));
expr_ty strings_var;
if (
- _PyPegen_lookahead(1, _PyPegen_string_token, p)
+ _PyPegen_lookahead(1, _tmp_94_rule, p)
&&
(strings_var = strings_rule(p)) // strings
)
{
- D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&STRING strings"));
+ D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&(STRING | FSTRING_START) strings"));
_res = strings_var;
goto done;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s atom[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&STRING strings"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "&(STRING | FSTRING_START) strings"));
}
{ // NUMBER
if (p->error_indicator) {
@@ -14759,15 +14828,15 @@ atom_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)"));
- void *_tmp_93_var;
+ void *_tmp_95_var;
if (
_PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 7) // token='('
&&
- (_tmp_93_var = _tmp_93_rule(p)) // tuple | group | genexp
+ (_tmp_95_var = _tmp_95_rule(p)) // tuple | group | genexp
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'(' (tuple | group | genexp)"));
- _res = _tmp_93_var;
+ _res = _tmp_95_var;
goto done;
}
p->mark = _mark;
@@ -14780,15 +14849,15 @@ atom_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)"));
- void *_tmp_94_var;
+ void *_tmp_96_var;
if (
_PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 9) // token='['
&&
- (_tmp_94_var = _tmp_94_rule(p)) // list | listcomp
+ (_tmp_96_var = _tmp_96_rule(p)) // list | listcomp
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'[' (list | listcomp)"));
- _res = _tmp_94_var;
+ _res = _tmp_96_var;
goto done;
}
p->mark = _mark;
@@ -14801,15 +14870,15 @@ atom_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> atom[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)"));
- void *_tmp_95_var;
+ void *_tmp_97_var;
if (
_PyPegen_lookahead_with_int(1, _PyPegen_expect_token, p, 25) // token='{'
&&
- (_tmp_95_var = _tmp_95_rule(p)) // dict | set | dictcomp | setcomp
+ (_tmp_97_var = _tmp_97_rule(p)) // dict | set | dictcomp | setcomp
)
{
D(fprintf(stderr, "%*c+ atom[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "&'{' (dict | set | dictcomp | setcomp)"));
- _res = _tmp_95_var;
+ _res = _tmp_97_var;
goto done;
}
p->mark = _mark;
@@ -14881,7 +14950,7 @@ group_rule(Parser *p)
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (a = _tmp_96_rule(p)) // yield_expr | named_expression
+ (a = _tmp_98_rule(p)) // yield_expr | named_expression
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
@@ -14958,7 +15027,7 @@ lambdef_rule(Parser *p)
void *a;
expr_ty b;
if (
- (_keyword = _PyPegen_expect_token(p, 586)) // token='lambda'
+ (_keyword = _PyPegen_expect_token(p, 600)) // token='lambda'
&&
(a = lambda_params_rule(p), !p->error_indicator) // lambda_params?
&&
@@ -15085,9 +15154,9 @@ lambda_parameters_rule(Parser *p)
if (
(a = lambda_slash_no_default_rule(p)) // lambda_slash_no_default
&&
- (b = (asdl_arg_seq*)_loop0_97_rule(p)) // lambda_param_no_default*
+ (b = (asdl_arg_seq*)_loop0_99_rule(p)) // lambda_param_no_default*
&&
- (c = _loop0_98_rule(p)) // lambda_param_with_default*
+ (c = _loop0_100_rule(p)) // lambda_param_with_default*
&&
(d = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc?
)
@@ -15117,7 +15186,7 @@ lambda_parameters_rule(Parser *p)
if (
(a = lambda_slash_with_default_rule(p)) // lambda_slash_with_default
&&
- (b = _loop0_99_rule(p)) // lambda_param_with_default*
+ (b = _loop0_101_rule(p)) // lambda_param_with_default*
&&
(c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc?
)
@@ -15145,9 +15214,9 @@ lambda_parameters_rule(Parser *p)
asdl_seq * b;
void *c;
if (
- (a = (asdl_arg_seq*)_loop1_100_rule(p)) // lambda_param_no_default+
+ (a = (asdl_arg_seq*)_loop1_102_rule(p)) // lambda_param_no_default+
&&
- (b = _loop0_101_rule(p)) // lambda_param_with_default*
+ (b = _loop0_103_rule(p)) // lambda_param_with_default*
&&
(c = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc?
)
@@ -15174,7 +15243,7 @@ lambda_parameters_rule(Parser *p)
asdl_seq * a;
void *b;
if (
- (a = _loop1_102_rule(p)) // lambda_param_with_default+
+ (a = _loop1_104_rule(p)) // lambda_param_with_default+
&&
(b = lambda_star_etc_rule(p), !p->error_indicator) // lambda_star_etc?
)
@@ -15248,7 +15317,7 @@ lambda_slash_no_default_rule(Parser *p)
Token * _literal_1;
asdl_arg_seq* a;
if (
- (a = (asdl_arg_seq*)_loop1_103_rule(p)) // lambda_param_no_default+
+ (a = (asdl_arg_seq*)_loop1_105_rule(p)) // lambda_param_no_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -15277,7 +15346,7 @@ lambda_slash_no_default_rule(Parser *p)
Token * _literal;
asdl_arg_seq* a;
if (
- (a = (asdl_arg_seq*)_loop1_104_rule(p)) // lambda_param_no_default+
+ (a = (asdl_arg_seq*)_loop1_106_rule(p)) // lambda_param_no_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -15330,9 +15399,9 @@ lambda_slash_with_default_rule(Parser *p)
asdl_seq * a;
asdl_seq * b;
if (
- (a = _loop0_105_rule(p)) // lambda_param_no_default*
+ (a = _loop0_107_rule(p)) // lambda_param_no_default*
&&
- (b = _loop1_106_rule(p)) // lambda_param_with_default+
+ (b = _loop1_108_rule(p)) // lambda_param_with_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -15362,9 +15431,9 @@ lambda_slash_with_default_rule(Parser *p)
asdl_seq * a;
asdl_seq * b;
if (
- (a = _loop0_107_rule(p)) // lambda_param_no_default*
+ (a = _loop0_109_rule(p)) // lambda_param_no_default*
&&
- (b = _loop1_108_rule(p)) // lambda_param_with_default+
+ (b = _loop1_110_rule(p)) // lambda_param_with_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -15442,7 +15511,7 @@ lambda_star_etc_rule(Parser *p)
&&
(a = lambda_param_no_default_rule(p)) // lambda_param_no_default
&&
- (b = _loop0_109_rule(p)) // lambda_param_maybe_default*
+ (b = _loop0_111_rule(p)) // lambda_param_maybe_default*
&&
(c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds?
)
@@ -15475,7 +15544,7 @@ lambda_star_etc_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 12)) // token=','
&&
- (b = _loop1_110_rule(p)) // lambda_param_maybe_default+
+ (b = _loop1_112_rule(p)) // lambda_param_maybe_default+
&&
(c = lambda_kwds_rule(p), !p->error_indicator) // lambda_kwds?
)
@@ -15882,7 +15951,387 @@ lambda_param_rule(Parser *p)
return _res;
}
-// strings: STRING+
+// fstring_middle: fstring_replacement_field | FSTRING_MIDDLE
+static expr_ty
+fstring_middle_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ { // fstring_replacement_field
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_middle[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ expr_ty fstring_replacement_field_var;
+ if (
+ (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_middle[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ _res = fstring_replacement_field_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_middle[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field"));
+ }
+ { // FSTRING_MIDDLE
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_middle[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ Token * t;
+ if (
+ (t = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE'
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_middle[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ _res = _PyPegen_constant_from_token ( p , t );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_middle[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// fstring_replacement_field:
+// | '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}'
+// | invalid_replacement_field
+static expr_ty
+fstring_replacement_field_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ int _start_lineno = p->tokens[_mark]->lineno;
+ UNUSED(_start_lineno); // Only used by EXTRA macro
+ int _start_col_offset = p->tokens[_mark]->col_offset;
+ UNUSED(_start_col_offset); // Only used by EXTRA macro
+ { // '{' (yield_expr | star_expressions) "="? fstring_conversion? fstring_full_format_spec? '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'"));
+ Token * _literal;
+ Token * _literal_1;
+ void *a;
+ void *conversion;
+ void *debug_expr;
+ void *format;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (a = _tmp_113_rule(p)) // yield_expr | star_expressions
+ &&
+ (debug_expr = _PyPegen_expect_token(p, 22), !p->error_indicator) // "="?
+ &&
+ (conversion = fstring_conversion_rule(p), !p->error_indicator) // fstring_conversion?
+ &&
+ (format = fstring_full_format_spec_rule(p), !p->error_indicator) // fstring_full_format_spec?
+ &&
+ (_literal_1 = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'"));
+ Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
+ if (_token == NULL) {
+ p->level--;
+ return NULL;
+ }
+ int _end_lineno = _token->end_lineno;
+ UNUSED(_end_lineno); // Only used by EXTRA macro
+ int _end_col_offset = _token->end_col_offset;
+ UNUSED(_end_col_offset); // Only used by EXTRA macro
+ _res = _PyPegen_formatted_value ( p , a , debug_expr , conversion , format , EXTRA );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) \"=\"? fstring_conversion? fstring_full_format_spec? '}'"));
+ }
+ if (p->call_invalid_rules) { // invalid_replacement_field
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "invalid_replacement_field"));
+ void *invalid_replacement_field_var;
+ if (
+ (invalid_replacement_field_var = invalid_replacement_field_rule(p)) // invalid_replacement_field
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "invalid_replacement_field"));
+ _res = invalid_replacement_field_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "invalid_replacement_field"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// fstring_conversion: "!" NAME
+static expr_ty
+fstring_conversion_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ { // "!" NAME
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_conversion[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "\"!\" NAME"));
+ expr_ty conv;
+ Token * conv_token;
+ if (
+ (conv_token = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ (conv = _PyPegen_name_token(p)) // NAME
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_conversion[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "\"!\" NAME"));
+ _res = _PyPegen_check_fstring_conversion ( p , conv_token , conv );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_conversion[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "\"!\" NAME"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// fstring_full_format_spec: ':' fstring_format_spec*
+static expr_ty
+fstring_full_format_spec_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ int _start_lineno = p->tokens[_mark]->lineno;
+ UNUSED(_start_lineno); // Only used by EXTRA macro
+ int _start_col_offset = p->tokens[_mark]->col_offset;
+ UNUSED(_start_col_offset); // Only used by EXTRA macro
+ { // ':' fstring_format_spec*
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_full_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*"));
+ Token * _literal;
+ asdl_seq * spec;
+ if (
+ (_literal = _PyPegen_expect_token(p, 11)) // token=':'
+ &&
+ (spec = _loop0_114_rule(p)) // fstring_format_spec*
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_full_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' fstring_format_spec*"));
+ Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
+ if (_token == NULL) {
+ p->level--;
+ return NULL;
+ }
+ int _end_lineno = _token->end_lineno;
+ UNUSED(_end_lineno); // Only used by EXTRA macro
+ int _end_col_offset = _token->end_col_offset;
+ UNUSED(_end_col_offset); // Only used by EXTRA macro
+ _res = spec ? _PyAST_JoinedStr ( ( asdl_expr_seq* ) spec , EXTRA ) : NULL;
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_full_format_spec[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' fstring_format_spec*"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// fstring_format_spec: FSTRING_MIDDLE | fstring_replacement_field
+static expr_ty
+fstring_format_spec_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ { // FSTRING_MIDDLE
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ Token * t;
+ if (
+ (t = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE'
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ _res = _PyPegen_constant_from_token ( p , t );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_format_spec[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE"));
+ }
+ { // fstring_replacement_field
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> fstring_format_spec[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ expr_ty fstring_replacement_field_var;
+ if (
+ (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field
+ )
+ {
+ D(fprintf(stderr, "%*c+ fstring_format_spec[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ _res = fstring_replacement_field_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s fstring_format_spec[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// string: STRING
+static expr_ty
+string_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ expr_ty _res = NULL;
+ int _mark = p->mark;
+ { // STRING
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> string[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING"));
+ Token* s;
+ if (
+ (s = (Token*)_PyPegen_string_token(p)) // STRING
+ )
+ {
+ D(fprintf(stderr, "%*c+ string[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING"));
+ _res = _PyPegen_constant_from_string ( p , s );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s string[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// strings: ((fstring | string))+
static expr_ty
strings_rule(Parser *p)
{
@@ -15900,19 +16349,37 @@ strings_rule(Parser *p)
return _res;
}
int _mark = p->mark;
- { // STRING+
+ if (p->mark == p->fill && _PyPegen_fill_token(p) < 0) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ int _start_lineno = p->tokens[_mark]->lineno;
+ UNUSED(_start_lineno); // Only used by EXTRA macro
+ int _start_col_offset = p->tokens[_mark]->col_offset;
+ UNUSED(_start_col_offset); // Only used by EXTRA macro
+ { // ((fstring | string))+
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING+"));
- asdl_seq * a;
+ D(fprintf(stderr, "%*c> strings[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((fstring | string))+"));
+ asdl_expr_seq* a;
if (
- (a = _loop1_111_rule(p)) // STRING+
+ (a = (asdl_expr_seq*)_loop1_115_rule(p)) // ((fstring | string))+
)
{
- D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING+"));
- _res = _PyPegen_concatenate_strings ( p , a );
+ D(fprintf(stderr, "%*c+ strings[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "((fstring | string))+"));
+ Token *_token = _PyPegen_get_last_nonnwhitespace_token(p);
+ if (_token == NULL) {
+ p->level--;
+ return NULL;
+ }
+ int _end_lineno = _token->end_lineno;
+ UNUSED(_end_lineno); // Only used by EXTRA macro
+ int _end_col_offset = _token->end_col_offset;
+ UNUSED(_end_col_offset); // Only used by EXTRA macro
+ _res = _PyPegen_concatenate_strings ( p , a , EXTRA );
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
p->level--;
@@ -15922,7 +16389,7 @@ strings_rule(Parser *p)
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s strings[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING+"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "((fstring | string))+"));
}
_res = NULL;
done:
@@ -16034,7 +16501,7 @@ tuple_rule(Parser *p)
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (a = _tmp_112_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?]
+ (a = _tmp_116_rule(p), !p->error_indicator) // [star_named_expression ',' star_named_expressions?]
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
@@ -16252,7 +16719,7 @@ double_starred_kvpairs_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_seq * a;
if (
- (a = _gather_113_rule(p)) // ','.double_starred_kvpair+
+ (a = _gather_117_rule(p)) // ','.double_starred_kvpair+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -16414,7 +16881,7 @@ for_if_clauses_rule(Parser *p)
D(fprintf(stderr, "%*c> for_if_clauses[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause+"));
asdl_comprehension_seq* a;
if (
- (a = (asdl_comprehension_seq*)_loop1_115_rule(p)) // for_if_clause+
+ (a = (asdl_comprehension_seq*)_loop1_119_rule(p)) // for_if_clause+
)
{
D(fprintf(stderr, "%*c+ for_if_clauses[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "for_if_clause+"));
@@ -16469,17 +16936,17 @@ for_if_clause_rule(Parser *p)
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
&&
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(a = star_targets_rule(p)) // star_targets
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(_cut_var = 1)
&&
(b = disjunction_rule(p)) // disjunction
&&
- (c = (asdl_expr_seq*)_loop0_116_rule(p)) // (('if' disjunction))*
+ (c = (asdl_expr_seq*)_loop0_120_rule(p)) // (('if' disjunction))*
)
{
D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC 'for' star_targets 'in' ~ disjunction (('if' disjunction))*"));
@@ -16512,17 +16979,17 @@ for_if_clause_rule(Parser *p)
expr_ty b;
asdl_expr_seq* c;
if (
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(a = star_targets_rule(p)) // star_targets
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(_cut_var = 1)
&&
(b = disjunction_rule(p)) // disjunction
&&
- (c = (asdl_expr_seq*)_loop0_117_rule(p)) // (('if' disjunction))*
+ (c = (asdl_expr_seq*)_loop0_121_rule(p)) // (('if' disjunction))*
)
{
D(fprintf(stderr, "%*c+ for_if_clause[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for' star_targets 'in' ~ disjunction (('if' disjunction))*"));
@@ -16785,7 +17252,7 @@ genexp_rule(Parser *p)
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (a = _tmp_118_rule(p)) // assignment_expression | expression !':='
+ (a = _tmp_122_rule(p)) // assignment_expression | expression !':='
&&
(b = for_if_clauses_rule(p)) // for_if_clauses
&&
@@ -17037,9 +17504,9 @@ args_rule(Parser *p)
asdl_expr_seq* a;
void *b;
if (
- (a = (asdl_expr_seq*)_gather_119_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+
+ (a = (asdl_expr_seq*)_gather_123_rule(p)) // ','.(starred_expression | (assignment_expression | expression !':=') !'=')+
&&
- (b = _tmp_121_rule(p), !p->error_indicator) // [',' kwargs]
+ (b = _tmp_125_rule(p), !p->error_indicator) // [',' kwargs]
)
{
D(fprintf(stderr, "%*c+ args[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.(starred_expression | (assignment_expression | expression !':=') !'=')+ [',' kwargs]"));
@@ -17130,11 +17597,11 @@ kwargs_rule(Parser *p)
asdl_seq * a;
asdl_seq * b;
if (
- (a = _gather_122_rule(p)) // ','.kwarg_or_starred+
+ (a = _gather_126_rule(p)) // ','.kwarg_or_starred+
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (b = _gather_124_rule(p)) // ','.kwarg_or_double_starred+
+ (b = _gather_128_rule(p)) // ','.kwarg_or_double_starred+
)
{
D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+ ',' ','.kwarg_or_double_starred+"));
@@ -17156,13 +17623,13 @@ kwargs_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+"));
- asdl_seq * _gather_126_var;
+ asdl_seq * _gather_130_var;
if (
- (_gather_126_var = _gather_126_rule(p)) // ','.kwarg_or_starred+
+ (_gather_130_var = _gather_130_rule(p)) // ','.kwarg_or_starred+
)
{
D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_starred+"));
- _res = _gather_126_var;
+ _res = _gather_130_var;
goto done;
}
p->mark = _mark;
@@ -17175,13 +17642,13 @@ kwargs_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> kwargs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+"));
- asdl_seq * _gather_128_var;
+ asdl_seq * _gather_132_var;
if (
- (_gather_128_var = _gather_128_rule(p)) // ','.kwarg_or_double_starred+
+ (_gather_132_var = _gather_132_rule(p)) // ','.kwarg_or_double_starred+
)
{
D(fprintf(stderr, "%*c+ kwargs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.kwarg_or_double_starred+"));
- _res = _gather_128_var;
+ _res = _gather_132_var;
goto done;
}
p->mark = _mark;
@@ -17574,7 +18041,7 @@ star_targets_rule(Parser *p)
if (
(a = star_target_rule(p)) // star_target
&&
- (b = _loop0_130_rule(p)) // ((',' star_target))*
+ (b = _loop0_134_rule(p)) // ((',' star_target))*
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -17631,7 +18098,7 @@ star_targets_list_seq_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_gather_131_rule(p)) // ','.star_target+
+ (a = (asdl_expr_seq*)_gather_135_rule(p)) // ','.star_target+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -17682,7 +18149,7 @@ star_targets_tuple_seq_rule(Parser *p)
if (
(a = star_target_rule(p)) // star_target
&&
- (b = _loop1_133_rule(p)) // ((',' star_target))+
+ (b = _loop1_137_rule(p)) // ((',' star_target))+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -17771,7 +18238,7 @@ star_target_rule(Parser *p)
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (a = _tmp_134_rule(p)) // !'*' star_target
+ (a = _tmp_138_rule(p)) // !'*' star_target
)
{
D(fprintf(stderr, "%*c+ star_target[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (!'*' star_target)"));
@@ -18702,7 +19169,7 @@ del_targets_rule(Parser *p)
UNUSED(_opt_var); // Silence compiler warnings
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_gather_135_rule(p)) // ','.del_target+
+ (a = (asdl_expr_seq*)_gather_139_rule(p)) // ','.del_target+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
)
@@ -19063,7 +19530,7 @@ type_expressions_rule(Parser *p)
expr_ty b;
expr_ty c;
if (
- (a = _gather_137_rule(p)) // ','.expression+
+ (a = _gather_141_rule(p)) // ','.expression+
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
@@ -19102,7 +19569,7 @@ type_expressions_rule(Parser *p)
asdl_seq * a;
expr_ty b;
if (
- (a = _gather_139_rule(p)) // ','.expression+
+ (a = _gather_143_rule(p)) // ','.expression+
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
@@ -19135,7 +19602,7 @@ type_expressions_rule(Parser *p)
asdl_seq * a;
expr_ty b;
if (
- (a = _gather_141_rule(p)) // ','.expression+
+ (a = _gather_145_rule(p)) // ','.expression+
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
@@ -19255,7 +19722,7 @@ type_expressions_rule(Parser *p)
D(fprintf(stderr, "%*c> type_expressions[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.expression+"));
asdl_expr_seq* a;
if (
- (a = (asdl_expr_seq*)_gather_143_rule(p)) // ','.expression+
+ (a = (asdl_expr_seq*)_gather_147_rule(p)) // ','.expression+
)
{
D(fprintf(stderr, "%*c+ type_expressions[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.expression+"));
@@ -19307,7 +19774,7 @@ func_type_comment_rule(Parser *p)
&&
(t = _PyPegen_expect_token(p, TYPE_COMMENT)) // token='TYPE_COMMENT'
&&
- _PyPegen_lookahead(1, _tmp_145_rule, p)
+ _PyPegen_lookahead(1, _tmp_149_rule, p)
)
{
D(fprintf(stderr, "%*c+ func_type_comment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE TYPE_COMMENT &(NEWLINE INDENT)"));
@@ -19436,7 +19903,7 @@ invalid_arguments_rule(Parser *p)
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (_opt_var = _tmp_146_rule(p), !p->error_indicator) // [args | expression for_if_clauses]
+ (_opt_var = _tmp_150_rule(p), !p->error_indicator) // [args | expression for_if_clauses]
)
{
D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses ',' [args | expression for_if_clauses]"));
@@ -19496,13 +19963,13 @@ invalid_arguments_rule(Parser *p)
expr_ty a;
Token * b;
if (
- (_opt_var = _tmp_147_rule(p), !p->error_indicator) // [(args ',')]
+ (_opt_var = _tmp_151_rule(p), !p->error_indicator) // [(args ',')]
&&
(a = _PyPegen_name_token(p)) // NAME
&&
(b = _PyPegen_expect_token(p, 22)) // token='='
&&
- _PyPegen_lookahead(1, _tmp_148_rule, p)
+ _PyPegen_lookahead(1, _tmp_152_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_arguments[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "[(args ',')] NAME '=' &(',' | ')')"));
@@ -19641,7 +20108,7 @@ invalid_kwarg_rule(Parser *p)
Token* a;
Token * b;
if (
- (a = (Token*)_tmp_149_rule(p)) // 'True' | 'False' | 'None'
+ (a = (Token*)_tmp_153_rule(p)) // 'True' | 'False' | 'None'
&&
(b = _PyPegen_expect_token(p, 22)) // token='='
)
@@ -19701,7 +20168,7 @@ invalid_kwarg_rule(Parser *p)
expr_ty a;
Token * b;
if (
- _PyPegen_lookahead(0, _tmp_150_rule, p)
+ _PyPegen_lookahead(0, _tmp_154_rule, p)
&&
(a = expression_rule(p)) // expression
&&
@@ -19805,11 +20272,11 @@ expression_without_invalid_rule(Parser *p)
if (
(a = disjunction_rule(p)) // disjunction
&&
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(b = disjunction_rule(p)) // disjunction
&&
- (_keyword_1 = _PyPegen_expect_token(p, 644)) // token='else'
+ (_keyword_1 = _PyPegen_expect_token(p, 645)) // token='else'
&&
(c = expression_rule(p)) // expression
)
@@ -19937,6 +20404,7 @@ invalid_legacy_expression_rule(Parser *p)
// invalid_expression:
// | !(NAME STRING | SOFT_KEYWORD) disjunction expression_without_invalid
// | disjunction 'if' disjunction !('else' | ':')
+// | 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)
static void *
invalid_expression_rule(Parser *p)
{
@@ -19959,7 +20427,7 @@ invalid_expression_rule(Parser *p)
expr_ty a;
expr_ty b;
if (
- _PyPegen_lookahead(0, _tmp_151_rule, p)
+ _PyPegen_lookahead(0, _tmp_155_rule, p)
&&
(a = disjunction_rule(p)) // disjunction
&&
@@ -19991,11 +20459,11 @@ invalid_expression_rule(Parser *p)
if (
(a = disjunction_rule(p)) // disjunction
&&
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(b = disjunction_rule(p)) // disjunction
&&
- _PyPegen_lookahead(0, _tmp_152_rule, p)
+ _PyPegen_lookahead(0, _tmp_156_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')"));
@@ -20011,6 +20479,39 @@ invalid_expression_rule(Parser *p)
D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "disjunction 'if' disjunction !('else' | ':')"));
}
+ { // 'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_expression[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)"));
+ void *_opt_var;
+ UNUSED(_opt_var); // Silence compiler warnings
+ Token * a;
+ Token * b;
+ if (
+ (a = _PyPegen_expect_token(p, 600)) // token='lambda'
+ &&
+ (_opt_var = lambda_params_rule(p), !p->error_indicator) // lambda_params?
+ &&
+ (b = _PyPegen_expect_token(p, 11)) // token=':'
+ &&
+ _PyPegen_lookahead(1, _tmp_157_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)"));
+ _res = RAISE_SYNTAX_ERROR_KNOWN_RANGE ( a , b , "f-string: lambda expressions are not allowed without parentheses" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_expression[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'lambda' lambda_params? ':' &(FSTRING_MIDDLE | fstring_replacement_field)"));
+ }
_res = NULL;
done:
p->level--;
@@ -20084,7 +20585,7 @@ invalid_named_expression_rule(Parser *p)
&&
(b = bitwise_or_rule(p)) // bitwise_or
&&
- _PyPegen_lookahead(0, _tmp_153_rule, p)
+ _PyPegen_lookahead(0, _tmp_158_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '=' bitwise_or !('=' | ':=')"));
@@ -20110,7 +20611,7 @@ invalid_named_expression_rule(Parser *p)
Token * b;
expr_ty bitwise_or_var;
if (
- _PyPegen_lookahead(0, _tmp_154_rule, p)
+ _PyPegen_lookahead(0, _tmp_159_rule, p)
&&
(a = bitwise_or_rule(p)) // bitwise_or
&&
@@ -20118,7 +20619,7 @@ invalid_named_expression_rule(Parser *p)
&&
(bitwise_or_var = bitwise_or_rule(p)) // bitwise_or
&&
- _PyPegen_lookahead(0, _tmp_155_rule, p)
+ _PyPegen_lookahead(0, _tmp_160_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_named_expression[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!(list | tuple | genexp | 'True' | 'None' | 'False') bitwise_or '=' bitwise_or !('=' | ':=')"));
@@ -20199,7 +20700,7 @@ invalid_assignment_rule(Parser *p)
D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions* ':' expression"));
Token * _literal;
Token * _literal_1;
- asdl_seq * _loop0_156_var;
+ asdl_seq * _loop0_161_var;
expr_ty a;
expr_ty expression_var;
if (
@@ -20207,7 +20708,7 @@ invalid_assignment_rule(Parser *p)
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (_loop0_156_var = _loop0_156_rule(p)) // star_named_expressions*
+ (_loop0_161_var = _loop0_161_rule(p)) // star_named_expressions*
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -20264,10 +20765,10 @@ invalid_assignment_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* star_expressions '='"));
Token * _literal;
- asdl_seq * _loop0_157_var;
+ asdl_seq * _loop0_162_var;
expr_ty a;
if (
- (_loop0_157_var = _loop0_157_rule(p)) // ((star_targets '='))*
+ (_loop0_162_var = _loop0_162_rule(p)) // ((star_targets '='))*
&&
(a = star_expressions_rule(p)) // star_expressions
&&
@@ -20294,10 +20795,10 @@ invalid_assignment_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "((star_targets '='))* yield_expr '='"));
Token * _literal;
- asdl_seq * _loop0_158_var;
+ asdl_seq * _loop0_163_var;
expr_ty a;
if (
- (_loop0_158_var = _loop0_158_rule(p)) // ((star_targets '='))*
+ (_loop0_163_var = _loop0_163_rule(p)) // ((star_targets '='))*
&&
(a = yield_expr_rule(p)) // yield_expr
&&
@@ -20323,7 +20824,7 @@ invalid_assignment_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_assignment[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)"));
- void *_tmp_159_var;
+ void *_tmp_164_var;
expr_ty a;
AugOperator* augassign_var;
if (
@@ -20331,7 +20832,7 @@ invalid_assignment_rule(Parser *p)
&&
(augassign_var = augassign_rule(p)) // augassign
&&
- (_tmp_159_var = _tmp_159_rule(p)) // yield_expr | star_expressions
+ (_tmp_164_var = _tmp_164_rule(p)) // yield_expr | star_expressions
)
{
D(fprintf(stderr, "%*c+ invalid_assignment[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions augassign (yield_expr | star_expressions)"));
@@ -20464,7 +20965,7 @@ invalid_del_stmt_rule(Parser *p)
Token * _keyword;
expr_ty a;
if (
- (_keyword = _PyPegen_expect_token(p, 603)) // token='del'
+ (_keyword = _PyPegen_expect_token(p, 604)) // token='del'
&&
(a = star_expressions_rule(p)) // star_expressions
)
@@ -20557,11 +21058,11 @@ invalid_comprehension_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '(' | '{') starred_expression for_if_clauses"));
- void *_tmp_160_var;
+ void *_tmp_165_var;
expr_ty a;
asdl_comprehension_seq* for_if_clauses_var;
if (
- (_tmp_160_var = _tmp_160_rule(p)) // '[' | '(' | '{'
+ (_tmp_165_var = _tmp_165_rule(p)) // '[' | '(' | '{'
&&
(a = starred_expression_rule(p)) // starred_expression
&&
@@ -20588,12 +21089,12 @@ invalid_comprehension_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' star_named_expressions for_if_clauses"));
Token * _literal;
- void *_tmp_161_var;
+ void *_tmp_166_var;
expr_ty a;
asdl_expr_seq* b;
asdl_comprehension_seq* for_if_clauses_var;
if (
- (_tmp_161_var = _tmp_161_rule(p)) // '[' | '{'
+ (_tmp_166_var = _tmp_166_rule(p)) // '[' | '{'
&&
(a = star_named_expression_rule(p)) // star_named_expression
&&
@@ -20623,12 +21124,12 @@ invalid_comprehension_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_comprehension[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('[' | '{') star_named_expression ',' for_if_clauses"));
- void *_tmp_162_var;
+ void *_tmp_167_var;
expr_ty a;
Token * b;
asdl_comprehension_seq* for_if_clauses_var;
if (
- (_tmp_162_var = _tmp_162_rule(p)) // '[' | '{'
+ (_tmp_167_var = _tmp_167_rule(p)) // '[' | '{'
&&
(a = star_named_expression_rule(p)) // star_named_expression
&&
@@ -20765,13 +21266,13 @@ invalid_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slash_no_default | slash_with_default) param_maybe_default* '/'"));
- asdl_seq * _loop0_164_var;
- void *_tmp_163_var;
+ asdl_seq * _loop0_169_var;
+ void *_tmp_168_var;
Token * a;
if (
- (_tmp_163_var = _tmp_163_rule(p)) // slash_no_default | slash_with_default
+ (_tmp_168_var = _tmp_168_rule(p)) // slash_no_default | slash_with_default
&&
- (_loop0_164_var = _loop0_164_rule(p)) // param_maybe_default*
+ (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 17)) // token='/'
)
@@ -20795,7 +21296,7 @@ invalid_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default? param_no_default* invalid_parameters_helper param_no_default"));
- asdl_seq * _loop0_165_var;
+ asdl_seq * _loop0_170_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
arg_ty a;
@@ -20803,7 +21304,7 @@ invalid_parameters_rule(Parser *p)
if (
(_opt_var = slash_no_default_rule(p), !p->error_indicator) // slash_no_default?
&&
- (_loop0_165_var = _loop0_165_rule(p)) // param_no_default*
+ (_loop0_170_var = _loop0_170_rule(p)) // param_no_default*
&&
(invalid_parameters_helper_var = invalid_parameters_helper_rule(p)) // invalid_parameters_helper
&&
@@ -20829,18 +21330,18 @@ invalid_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default* '(' param_no_default+ ','? ')'"));
- asdl_seq * _loop0_166_var;
- asdl_seq * _loop1_167_var;
+ asdl_seq * _loop0_171_var;
+ asdl_seq * _loop1_172_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
Token * a;
Token * b;
if (
- (_loop0_166_var = _loop0_166_rule(p)) // param_no_default*
+ (_loop0_171_var = _loop0_171_rule(p)) // param_no_default*
&&
(a = _PyPegen_expect_token(p, 7)) // token='('
&&
- (_loop1_167_var = _loop1_167_rule(p)) // param_no_default+
+ (_loop1_172_var = _loop1_172_rule(p)) // param_no_default+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -20867,22 +21368,22 @@ invalid_parameters_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(slash_no_default | slash_with_default)] param_maybe_default* '*' (',' | param_no_default) param_maybe_default* '/'"));
Token * _literal;
- asdl_seq * _loop0_169_var;
- asdl_seq * _loop0_171_var;
+ asdl_seq * _loop0_174_var;
+ asdl_seq * _loop0_176_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
- void *_tmp_170_var;
+ void *_tmp_175_var;
Token * a;
if (
- (_opt_var = _tmp_168_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)]
+ (_opt_var = _tmp_173_rule(p), !p->error_indicator) // [(slash_no_default | slash_with_default)]
&&
- (_loop0_169_var = _loop0_169_rule(p)) // param_maybe_default*
+ (_loop0_174_var = _loop0_174_rule(p)) // param_maybe_default*
&&
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_170_var = _tmp_170_rule(p)) // ',' | param_no_default
+ (_tmp_175_var = _tmp_175_rule(p)) // ',' | param_no_default
&&
- (_loop0_171_var = _loop0_171_rule(p)) // param_maybe_default*
+ (_loop0_176_var = _loop0_176_rule(p)) // param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 17)) // token='/'
)
@@ -20907,10 +21408,10 @@ invalid_parameters_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default+ '/' '*'"));
Token * _literal;
- asdl_seq * _loop1_172_var;
+ asdl_seq * _loop1_177_var;
Token * a;
if (
- (_loop1_172_var = _loop1_172_rule(p)) // param_maybe_default+
+ (_loop1_177_var = _loop1_177_rule(p)) // param_maybe_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -20960,7 +21461,7 @@ invalid_default_rule(Parser *p)
if (
(a = _PyPegen_expect_token(p, 22)) // token='='
&&
- _PyPegen_lookahead(1, _tmp_173_rule, p)
+ _PyPegen_lookahead(1, _tmp_178_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_default[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' &(')' | ',')"));
@@ -21006,12 +21507,12 @@ invalid_star_etc_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))"));
- void *_tmp_174_var;
+ void *_tmp_179_var;
Token * a;
if (
(a = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_174_var = _tmp_174_rule(p)) // ')' | ',' (')' | '**')
+ (_tmp_179_var = _tmp_179_rule(p)) // ')' | ',' (')' | '**')
)
{
D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (')' | ',' (')' | '**'))"));
@@ -21094,20 +21595,20 @@ invalid_star_etc_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')"));
Token * _literal;
- asdl_seq * _loop0_176_var;
- void *_tmp_175_var;
- void *_tmp_177_var;
+ asdl_seq * _loop0_181_var;
+ void *_tmp_180_var;
+ void *_tmp_182_var;
Token * a;
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_175_var = _tmp_175_rule(p)) // param_no_default | ','
+ (_tmp_180_var = _tmp_180_rule(p)) // param_no_default | ','
&&
- (_loop0_176_var = _loop0_176_rule(p)) // param_maybe_default*
+ (_loop0_181_var = _loop0_181_rule(p)) // param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_177_var = _tmp_177_rule(p)) // param_no_default | ','
+ (_tmp_182_var = _tmp_182_rule(p)) // param_no_default | ','
)
{
D(fprintf(stderr, "%*c+ invalid_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (param_no_default | ',') param_maybe_default* '*' (param_no_default | ',')"));
@@ -21223,7 +21724,7 @@ invalid_kwds_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 12)) // token=','
&&
- (a = (Token*)_tmp_178_rule(p)) // '*' | '**' | '/'
+ (a = (Token*)_tmp_183_rule(p)) // '*' | '**' | '/'
)
{
D(fprintf(stderr, "%*c+ invalid_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' param ',' ('*' | '**' | '/')"));
@@ -21289,13 +21790,13 @@ invalid_parameters_helper_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
- asdl_seq * _loop1_179_var;
+ asdl_seq * _loop1_184_var;
if (
- (_loop1_179_var = _loop1_179_rule(p)) // param_with_default+
+ (_loop1_184_var = _loop1_184_rule(p)) // param_with_default+
)
{
D(fprintf(stderr, "%*c+ invalid_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_with_default+"));
- _res = _loop1_179_var;
+ _res = _loop1_184_var;
goto done;
}
p->mark = _mark;
@@ -21361,13 +21862,13 @@ invalid_lambda_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(lambda_slash_no_default | lambda_slash_with_default) lambda_param_maybe_default* '/'"));
- asdl_seq * _loop0_181_var;
- void *_tmp_180_var;
+ asdl_seq * _loop0_186_var;
+ void *_tmp_185_var;
Token * a;
if (
- (_tmp_180_var = _tmp_180_rule(p)) // lambda_slash_no_default | lambda_slash_with_default
+ (_tmp_185_var = _tmp_185_rule(p)) // lambda_slash_no_default | lambda_slash_with_default
&&
- (_loop0_181_var = _loop0_181_rule(p)) // lambda_param_maybe_default*
+ (_loop0_186_var = _loop0_186_rule(p)) // lambda_param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 17)) // token='/'
)
@@ -21391,7 +21892,7 @@ invalid_lambda_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default? lambda_param_no_default* invalid_lambda_parameters_helper lambda_param_no_default"));
- asdl_seq * _loop0_182_var;
+ asdl_seq * _loop0_187_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
arg_ty a;
@@ -21399,7 +21900,7 @@ invalid_lambda_parameters_rule(Parser *p)
if (
(_opt_var = lambda_slash_no_default_rule(p), !p->error_indicator) // lambda_slash_no_default?
&&
- (_loop0_182_var = _loop0_182_rule(p)) // lambda_param_no_default*
+ (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_no_default*
&&
(invalid_lambda_parameters_helper_var = invalid_lambda_parameters_helper_rule(p)) // invalid_lambda_parameters_helper
&&
@@ -21425,18 +21926,18 @@ invalid_lambda_parameters_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default* '(' ','.lambda_param+ ','? ')'"));
- asdl_seq * _gather_184_var;
- asdl_seq * _loop0_183_var;
+ asdl_seq * _gather_189_var;
+ asdl_seq * _loop0_188_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
Token * a;
Token * b;
if (
- (_loop0_183_var = _loop0_183_rule(p)) // lambda_param_no_default*
+ (_loop0_188_var = _loop0_188_rule(p)) // lambda_param_no_default*
&&
(a = _PyPegen_expect_token(p, 7)) // token='('
&&
- (_gather_184_var = _gather_184_rule(p)) // ','.lambda_param+
+ (_gather_189_var = _gather_189_rule(p)) // ','.lambda_param+
&&
(_opt_var = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -21463,22 +21964,22 @@ invalid_lambda_parameters_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "[(lambda_slash_no_default | lambda_slash_with_default)] lambda_param_maybe_default* '*' (',' | lambda_param_no_default) lambda_param_maybe_default* '/'"));
Token * _literal;
- asdl_seq * _loop0_187_var;
- asdl_seq * _loop0_189_var;
+ asdl_seq * _loop0_192_var;
+ asdl_seq * _loop0_194_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
- void *_tmp_188_var;
+ void *_tmp_193_var;
Token * a;
if (
- (_opt_var = _tmp_186_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)]
+ (_opt_var = _tmp_191_rule(p), !p->error_indicator) // [(lambda_slash_no_default | lambda_slash_with_default)]
&&
- (_loop0_187_var = _loop0_187_rule(p)) // lambda_param_maybe_default*
+ (_loop0_192_var = _loop0_192_rule(p)) // lambda_param_maybe_default*
&&
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_188_var = _tmp_188_rule(p)) // ',' | lambda_param_no_default
+ (_tmp_193_var = _tmp_193_rule(p)) // ',' | lambda_param_no_default
&&
- (_loop0_189_var = _loop0_189_rule(p)) // lambda_param_maybe_default*
+ (_loop0_194_var = _loop0_194_rule(p)) // lambda_param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 17)) // token='/'
)
@@ -21503,10 +22004,10 @@ invalid_lambda_parameters_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default+ '/' '*'"));
Token * _literal;
- asdl_seq * _loop1_190_var;
+ asdl_seq * _loop1_195_var;
Token * a;
if (
- (_loop1_190_var = _loop1_190_rule(p)) // lambda_param_maybe_default+
+ (_loop1_195_var = _loop1_195_rule(p)) // lambda_param_maybe_default+
&&
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
&&
@@ -21578,13 +22079,13 @@ invalid_lambda_parameters_helper_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_lambda_parameters_helper[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
- asdl_seq * _loop1_191_var;
+ asdl_seq * _loop1_196_var;
if (
- (_loop1_191_var = _loop1_191_rule(p)) // lambda_param_with_default+
+ (_loop1_196_var = _loop1_196_rule(p)) // lambda_param_with_default+
)
{
D(fprintf(stderr, "%*c+ invalid_lambda_parameters_helper[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default+"));
- _res = _loop1_191_var;
+ _res = _loop1_196_var;
goto done;
}
p->mark = _mark;
@@ -21621,11 +22122,11 @@ invalid_lambda_star_etc_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))"));
Token * _literal;
- void *_tmp_192_var;
+ void *_tmp_197_var;
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_192_var = _tmp_192_rule(p)) // ':' | ',' (':' | '**')
+ (_tmp_197_var = _tmp_197_rule(p)) // ':' | ',' (':' | '**')
)
{
D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (':' | ',' (':' | '**'))"));
@@ -21678,20 +22179,20 @@ invalid_lambda_star_etc_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_lambda_star_etc[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')"));
Token * _literal;
- asdl_seq * _loop0_194_var;
- void *_tmp_193_var;
- void *_tmp_195_var;
+ asdl_seq * _loop0_199_var;
+ void *_tmp_198_var;
+ void *_tmp_200_var;
Token * a;
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_193_var = _tmp_193_rule(p)) // lambda_param_no_default | ','
+ (_tmp_198_var = _tmp_198_rule(p)) // lambda_param_no_default | ','
&&
- (_loop0_194_var = _loop0_194_rule(p)) // lambda_param_maybe_default*
+ (_loop0_199_var = _loop0_199_rule(p)) // lambda_param_maybe_default*
&&
(a = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_195_var = _tmp_195_rule(p)) // lambda_param_no_default | ','
+ (_tmp_200_var = _tmp_200_rule(p)) // lambda_param_no_default | ','
)
{
D(fprintf(stderr, "%*c+ invalid_lambda_star_etc[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*' (lambda_param_no_default | ',') lambda_param_maybe_default* '*' (lambda_param_no_default | ',')"));
@@ -21810,7 +22311,7 @@ invalid_lambda_kwds_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 12)) // token=','
&&
- (a = (Token*)_tmp_196_rule(p)) // '*' | '**' | '/'
+ (a = (Token*)_tmp_201_rule(p)) // '*' | '**' | '/'
)
{
D(fprintf(stderr, "%*c+ invalid_lambda_kwds[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**' lambda_param ',' ('*' | '**' | '/')"));
@@ -21914,11 +22415,11 @@ invalid_with_item_rule(Parser *p)
if (
(expression_var = expression_rule(p)) // expression
&&
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(a = expression_rule(p)) // expression
&&
- _PyPegen_lookahead(1, _tmp_197_rule, p)
+ _PyPegen_lookahead(1, _tmp_202_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_with_item[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression 'as' expression &(',' | ')' | ':')"));
@@ -21967,7 +22468,7 @@ invalid_for_target_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(a = star_expressions_rule(p)) // star_expressions
)
@@ -22099,11 +22600,11 @@ invalid_import_rule(Parser *p)
expr_ty dotted_name_var;
expr_ty dotted_name_var_1;
if (
- (a = _PyPegen_expect_token(p, 606)) // token='import'
+ (a = _PyPegen_expect_token(p, 607)) // token='import'
&&
(dotted_name_var = dotted_name_rule(p)) // dotted_name
&&
- (_keyword = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword = _PyPegen_expect_token(p, 608)) // token='from'
&&
(dotted_name_var_1 = dotted_name_rule(p)) // dotted_name
)
@@ -22199,7 +22700,7 @@ invalid_with_stmt_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ NEWLINE"));
- asdl_seq * _gather_198_var;
+ asdl_seq * _gather_203_var;
Token * _keyword;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
@@ -22207,9 +22708,9 @@ invalid_with_stmt_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
- (_gather_198_var = _gather_198_rule(p)) // ','.(expression ['as' star_target])+
+ (_gather_203_var = _gather_203_rule(p)) // ','.(expression ['as' star_target])+
&&
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
@@ -22233,7 +22734,7 @@ invalid_with_stmt_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_with_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' NEWLINE"));
- asdl_seq * _gather_200_var;
+ asdl_seq * _gather_205_var;
Token * _keyword;
Token * _literal;
Token * _literal_1;
@@ -22245,11 +22746,11 @@ invalid_with_stmt_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
&&
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (_gather_200_var = _gather_200_rule(p)) // ','.(expressions ['as' star_target])+
+ (_gather_205_var = _gather_205_rule(p)) // ','.(expressions ['as' star_target])+
&&
(_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -22299,7 +22800,7 @@ invalid_with_stmt_indent_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' ','.(expression ['as' star_target])+ ':' NEWLINE !INDENT"));
- asdl_seq * _gather_202_var;
+ asdl_seq * _gather_207_var;
Token * _literal;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
@@ -22308,9 +22809,9 @@ invalid_with_stmt_indent_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (a = _PyPegen_expect_token(p, 614)) // token='with'
+ (a = _PyPegen_expect_token(p, 615)) // token='with'
&&
- (_gather_202_var = _gather_202_rule(p)) // ','.(expression ['as' star_target])+
+ (_gather_207_var = _gather_207_rule(p)) // ','.(expression ['as' star_target])+
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -22338,7 +22839,7 @@ invalid_with_stmt_indent_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_with_stmt_indent[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC? 'with' '(' ','.(expressions ['as' star_target])+ ','? ')' ':' NEWLINE !INDENT"));
- asdl_seq * _gather_204_var;
+ asdl_seq * _gather_209_var;
Token * _literal;
Token * _literal_1;
Token * _literal_2;
@@ -22351,11 +22852,11 @@ invalid_with_stmt_indent_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (a = _PyPegen_expect_token(p, 614)) // token='with'
+ (a = _PyPegen_expect_token(p, 615)) // token='with'
&&
(_literal = _PyPegen_expect_token(p, 7)) // token='('
&&
- (_gather_204_var = _gather_204_rule(p)) // ','.(expressions ['as' star_target])+
+ (_gather_209_var = _gather_209_rule(p)) // ','.(expressions ['as' star_target])+
&&
(_opt_var_1 = _PyPegen_expect_token(p, 12), !p->error_indicator) // ','?
&&
@@ -22415,7 +22916,7 @@ invalid_try_stmt_rule(Parser *p)
Token * a;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 623)) // token='try'
+ (a = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -22447,13 +22948,13 @@ invalid_try_stmt_rule(Parser *p)
Token * _literal;
asdl_stmt_seq* block_var;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
(block_var = block_rule(p)) // block
&&
- _PyPegen_lookahead(0, _tmp_206_rule, p)
+ _PyPegen_lookahead(0, _tmp_211_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_try_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'try' ':' block !('except' | 'finally')"));
@@ -22478,29 +22979,29 @@ invalid_try_stmt_rule(Parser *p)
Token * _keyword;
Token * _literal;
Token * _literal_1;
- asdl_seq * _loop0_207_var;
- asdl_seq * _loop1_208_var;
+ asdl_seq * _loop0_212_var;
+ asdl_seq * _loop1_213_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
Token * a;
Token * b;
expr_ty expression_var;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
- (_loop0_207_var = _loop0_207_rule(p)) // block*
+ (_loop0_212_var = _loop0_212_rule(p)) // block*
&&
- (_loop1_208_var = _loop1_208_rule(p)) // except_block+
+ (_loop1_213_var = _loop1_213_rule(p)) // except_block+
&&
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(b = _PyPegen_expect_token(p, 16)) // token='*'
&&
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_209_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
)
@@ -22527,23 +23028,23 @@ invalid_try_stmt_rule(Parser *p)
Token * _keyword;
Token * _literal;
Token * _literal_1;
- asdl_seq * _loop0_210_var;
- asdl_seq * _loop1_211_var;
+ asdl_seq * _loop0_215_var;
+ asdl_seq * _loop1_216_var;
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
Token * a;
if (
- (_keyword = _PyPegen_expect_token(p, 623)) // token='try'
+ (_keyword = _PyPegen_expect_token(p, 624)) // token='try'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
- (_loop0_210_var = _loop0_210_rule(p)) // block*
+ (_loop0_215_var = _loop0_215_rule(p)) // block*
&&
- (_loop1_211_var = _loop1_211_rule(p)) // except_star_block+
+ (_loop1_216_var = _loop1_216_rule(p)) // except_star_block+
&&
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
- (_opt_var = _tmp_212_rule(p), !p->error_indicator) // [expression ['as' NAME]]
+ (_opt_var = _tmp_217_rule(p), !p->error_indicator) // [expression ['as' NAME]]
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
)
@@ -22601,7 +23102,7 @@ invalid_except_stmt_rule(Parser *p)
expr_ty a;
expr_ty expressions_var;
if (
- (_keyword = _PyPegen_expect_token(p, 636)) // token='except'
+ (_keyword = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_opt_var = _PyPegen_expect_token(p, 16), !p->error_indicator) // '*'?
&&
@@ -22611,7 +23112,7 @@ invalid_except_stmt_rule(Parser *p)
&&
(expressions_var = expressions_rule(p)) // expressions
&&
- (_opt_var_1 = _tmp_213_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var_1 = _tmp_218_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
)
@@ -22643,13 +23144,13 @@ invalid_except_stmt_rule(Parser *p)
expr_ty expression_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_opt_var = _PyPegen_expect_token(p, 16), !p->error_indicator) // '*'?
&&
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var_1 = _tmp_214_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var_1 = _tmp_219_rule(p), !p->error_indicator) // ['as' NAME]
&&
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
@@ -22676,7 +23177,7 @@ invalid_except_stmt_rule(Parser *p)
Token * a;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
@@ -22701,14 +23202,14 @@ invalid_except_stmt_rule(Parser *p)
}
D(fprintf(stderr, "%*c> invalid_except_stmt[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')"));
Token * _literal;
- void *_tmp_215_var;
+ void *_tmp_220_var;
Token * a;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
- (_tmp_215_var = _tmp_215_rule(p)) // NEWLINE | ':'
+ (_tmp_220_var = _tmp_220_rule(p)) // NEWLINE | ':'
)
{
D(fprintf(stderr, "%*c+ invalid_except_stmt[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except' '*' (NEWLINE | ':')"));
@@ -22754,7 +23255,7 @@ invalid_finally_stmt_rule(Parser *p)
Token * a;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 632)) // token='finally'
+ (a = _PyPegen_expect_token(p, 633)) // token='finally'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -22811,11 +23312,11 @@ invalid_except_stmt_indent_rule(Parser *p)
expr_ty expression_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_216_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -22847,7 +23348,7 @@ invalid_except_stmt_indent_rule(Parser *p)
Token * a;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -22904,13 +23405,13 @@ invalid_except_star_stmt_indent_rule(Parser *p)
expr_ty expression_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 636)) // token='except'
+ (a = _PyPegen_expect_token(p, 637)) // token='except'
&&
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
&&
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_217_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var = _tmp_222_rule(p), !p->error_indicator) // ['as' NAME]
&&
(_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -23146,7 +23647,7 @@ invalid_as_pattern_rule(Parser *p)
if (
(or_pattern_var = or_pattern_rule(p)) // or_pattern
&&
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(a = _PyPegen_expect_soft_keyword(p, "_")) // soft_keyword='"_"'
)
@@ -23176,7 +23677,7 @@ invalid_as_pattern_rule(Parser *p)
if (
(or_pattern_var = or_pattern_rule(p)) // or_pattern
&&
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
_PyPegen_lookahead_with_name(0, _PyPegen_name_token, p)
&&
@@ -23279,7 +23780,7 @@ invalid_class_argument_pattern_rule(Parser *p)
asdl_pattern_seq* a;
asdl_seq* keyword_patterns_var;
if (
- (_opt_var = _tmp_218_rule(p), !p->error_indicator) // [positional_patterns ',']
+ (_opt_var = _tmp_223_rule(p), !p->error_indicator) // [positional_patterns ',']
&&
(keyword_patterns_var = keyword_patterns_rule(p)) // keyword_patterns
&&
@@ -23333,7 +23834,7 @@ invalid_if_stmt_rule(Parser *p)
expr_ty named_expression_var;
Token * newline_var;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(named_expression_var = named_expression_rule(p)) // named_expression
&&
@@ -23364,7 +23865,7 @@ invalid_if_stmt_rule(Parser *p)
expr_ty a_1;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 641)) // token='if'
+ (a = _PyPegen_expect_token(p, 642)) // token='if'
&&
(a_1 = named_expression_rule(p)) // named_expression
&&
@@ -23420,7 +23921,7 @@ invalid_elif_stmt_rule(Parser *p)
expr_ty named_expression_var;
Token * newline_var;
if (
- (_keyword = _PyPegen_expect_token(p, 643)) // token='elif'
+ (_keyword = _PyPegen_expect_token(p, 644)) // token='elif'
&&
(named_expression_var = named_expression_rule(p)) // named_expression
&&
@@ -23451,7 +23952,7 @@ invalid_elif_stmt_rule(Parser *p)
expr_ty named_expression_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 643)) // token='elif'
+ (a = _PyPegen_expect_token(p, 644)) // token='elif'
&&
(named_expression_var = named_expression_rule(p)) // named_expression
&&
@@ -23505,7 +24006,7 @@ invalid_else_stmt_rule(Parser *p)
Token * a;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 644)) // token='else'
+ (a = _PyPegen_expect_token(p, 645)) // token='else'
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -23559,7 +24060,7 @@ invalid_while_stmt_rule(Parser *p)
expr_ty named_expression_var;
Token * newline_var;
if (
- (_keyword = _PyPegen_expect_token(p, 646)) // token='while'
+ (_keyword = _PyPegen_expect_token(p, 647)) // token='while'
&&
(named_expression_var = named_expression_rule(p)) // named_expression
&&
@@ -23590,7 +24091,7 @@ invalid_while_stmt_rule(Parser *p)
expr_ty named_expression_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 646)) // token='while'
+ (a = _PyPegen_expect_token(p, 647)) // token='while'
&&
(named_expression_var = named_expression_rule(p)) // named_expression
&&
@@ -23652,11 +24153,11 @@ invalid_for_stmt_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
&&
(star_targets_var = star_targets_rule(p)) // star_targets
&&
- (_keyword_1 = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword_1 = _PyPegen_expect_token(p, 651)) // token='in'
&&
(star_expressions_var = star_expressions_rule(p)) // star_expressions
&&
@@ -23693,11 +24194,11 @@ invalid_for_stmt_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (a = _PyPegen_expect_token(p, 649)) // token='for'
+ (a = _PyPegen_expect_token(p, 650)) // token='for'
&&
(star_targets_var = star_targets_rule(p)) // star_targets
&&
- (_keyword = _PyPegen_expect_token(p, 650)) // token='in'
+ (_keyword = _PyPegen_expect_token(p, 651)) // token='in'
&&
(star_expressions_var = star_expressions_rule(p)) // star_expressions
&&
@@ -23763,7 +24264,7 @@ invalid_def_raw_rule(Parser *p)
if (
(_opt_var = _PyPegen_expect_token(p, ASYNC), !p->error_indicator) // ASYNC?
&&
- (a = _PyPegen_expect_token(p, 651)) // token='def'
+ (a = _PyPegen_expect_token(p, 652)) // token='def'
&&
(name_var = _PyPegen_name_token(p)) // NAME
&&
@@ -23773,7 +24274,7 @@ invalid_def_raw_rule(Parser *p)
&&
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
&&
- (_opt_var_2 = _tmp_219_rule(p), !p->error_indicator) // ['->' expression]
+ (_opt_var_2 = _tmp_224_rule(p), !p->error_indicator) // ['->' expression]
&&
(_literal_2 = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -23829,11 +24330,11 @@ invalid_class_def_raw_rule(Parser *p)
expr_ty name_var;
Token * newline_var;
if (
- (_keyword = _PyPegen_expect_token(p, 653)) // token='class'
+ (_keyword = _PyPegen_expect_token(p, 654)) // token='class'
&&
(name_var = _PyPegen_name_token(p)) // NAME
&&
- (_opt_var = _tmp_220_rule(p), !p->error_indicator) // ['(' arguments? ')']
+ (_opt_var = _tmp_225_rule(p), !p->error_indicator) // ['(' arguments? ')']
&&
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
@@ -23864,11 +24365,11 @@ invalid_class_def_raw_rule(Parser *p)
expr_ty name_var;
Token * newline_var;
if (
- (a = _PyPegen_expect_token(p, 653)) // token='class'
+ (a = _PyPegen_expect_token(p, 654)) // token='class'
&&
(name_var = _PyPegen_name_token(p)) // NAME
&&
- (_opt_var = _tmp_221_rule(p), !p->error_indicator) // ['(' arguments? ')']
+ (_opt_var = _tmp_226_rule(p), !p->error_indicator) // ['(' arguments? ')']
&&
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
&&
@@ -23919,11 +24420,11 @@ invalid_double_starred_kvpairs_rule(Parser *p)
return NULL;
}
D(fprintf(stderr, "%*c> invalid_double_starred_kvpairs[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair"));
- asdl_seq * _gather_222_var;
+ asdl_seq * _gather_227_var;
Token * _literal;
void *invalid_kvpair_var;
if (
- (_gather_222_var = _gather_222_rule(p)) // ','.double_starred_kvpair+
+ (_gather_227_var = _gather_227_rule(p)) // ','.double_starred_kvpair+
&&
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
@@ -23931,7 +24432,7 @@ invalid_double_starred_kvpairs_rule(Parser *p)
)
{
D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','.double_starred_kvpair+ ',' invalid_kvpair"));
- _res = _PyPegen_dummy_name(p, _gather_222_var, _literal, invalid_kvpair_var);
+ _res = _PyPegen_dummy_name(p, _gather_227_var, _literal, invalid_kvpair_var);
goto done;
}
p->mark = _mark;
@@ -23984,7 +24485,7 @@ invalid_double_starred_kvpairs_rule(Parser *p)
&&
(a = _PyPegen_expect_token(p, 11)) // token=':'
&&
- _PyPegen_lookahead(1, _tmp_224_rule, p)
+ _PyPegen_lookahead(1, _tmp_229_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_double_starred_kvpairs[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')"));
@@ -24095,7 +24596,7 @@ invalid_kvpair_rule(Parser *p)
&&
(a = _PyPegen_expect_token(p, 11)) // token=':'
&&
- _PyPegen_lookahead(1, _tmp_225_rule, p)
+ _PyPegen_lookahead(1, _tmp_230_rule, p)
)
{
D(fprintf(stderr, "%*c+ invalid_kvpair[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ':' &('}' | ',')"));
@@ -24170,6 +24671,450 @@ invalid_starred_expression_rule(Parser *p)
return _res;
}
+// invalid_replacement_field:
+// | '{' '='
+// | '{' '!'
+// | '{' ':'
+// | '{' '}'
+// | '{' !(yield_expr | star_expressions)
+// | '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')
+// | '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')
+// | '{' (yield_expr | star_expressions) '='? invalid_conversion_character
+// | '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')
+// | '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'
+// | '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'
+static void *
+invalid_replacement_field_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '{' '='
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '='"));
+ Token * _literal;
+ Token * a;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (a = _PyPegen_expect_token(p, 22)) // token='='
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '='"));
+ _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '='" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '='"));
+ }
+ { // '{' '!'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '!'"));
+ Token * _literal;
+ Token * a;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (a = _PyPegen_expect_token(p, 54)) // token='!'
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '!'"));
+ _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '!'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '!'"));
+ }
+ { // '{' ':'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' ':'"));
+ Token * _literal;
+ Token * a;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (a = _PyPegen_expect_token(p, 11)) // token=':'
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' ':'"));
+ _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before ':'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' ':'"));
+ }
+ { // '{' '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' '}'"));
+ Token * _literal;
+ Token * a;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (a = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' '}'"));
+ _res = RAISE_SYNTAX_ERROR_KNOWN_LOCATION ( a , "f-string: valid expression required before '}'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' '}'"));
+ }
+ { // '{' !(yield_expr | star_expressions)
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ _PyPegen_lookahead(0, _tmp_231_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' !(yield_expr | star_expressions)"));
+ _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting a valid expression after '{'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' !(yield_expr | star_expressions)"));
+ }
+ { // '{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')"));
+ Token * _literal;
+ void *_tmp_232_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_232_var = _tmp_232_rule(p)) // yield_expr | star_expressions
+ &&
+ _PyPegen_lookahead(0, _tmp_233_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')"));
+ _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '=', or '!', or ':', or '}'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) !('=' | '!' | ':' | '}')"));
+ }
+ { // '{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')"));
+ Token * _literal;
+ Token * _literal_1;
+ void *_tmp_234_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_234_var = _tmp_234_rule(p)) // yield_expr | star_expressions
+ &&
+ (_literal_1 = _PyPegen_expect_token(p, 22)) // token='='
+ &&
+ _PyPegen_lookahead(0, _tmp_235_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')"));
+ _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '!', or ':', or '}'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '=' !('!' | ':' | '}')"));
+ }
+ { // '{' (yield_expr | star_expressions) '='? invalid_conversion_character
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character"));
+ Token * _literal;
+ void *_opt_var;
+ UNUSED(_opt_var); // Silence compiler warnings
+ void *_tmp_236_var;
+ void *invalid_conversion_character_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_236_var = _tmp_236_rule(p)) // yield_expr | star_expressions
+ &&
+ (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='?
+ &&
+ (invalid_conversion_character_var = invalid_conversion_character_rule(p)) // invalid_conversion_character
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character"));
+ _res = _PyPegen_dummy_name(p, _literal, _tmp_236_var, _opt_var, invalid_conversion_character_var);
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? invalid_conversion_character"));
+ }
+ { // '{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')"));
+ Token * _literal;
+ void *_opt_var;
+ UNUSED(_opt_var); // Silence compiler warnings
+ void *_opt_var_1;
+ UNUSED(_opt_var_1); // Silence compiler warnings
+ void *_tmp_237_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_237_var = _tmp_237_rule(p)) // yield_expr | star_expressions
+ &&
+ (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='?
+ &&
+ (_opt_var_1 = _tmp_238_rule(p), !p->error_indicator) // ['!' NAME]
+ &&
+ _PyPegen_lookahead(0, _tmp_239_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')"));
+ _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting ':' or '}'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !(':' | '}')"));
+ }
+ { // '{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'"));
+ Token * _literal;
+ Token * _literal_1;
+ asdl_seq * _loop0_242_var;
+ void *_opt_var;
+ UNUSED(_opt_var); // Silence compiler warnings
+ void *_opt_var_1;
+ UNUSED(_opt_var_1); // Silence compiler warnings
+ void *_tmp_240_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_240_var = _tmp_240_rule(p)) // yield_expr | star_expressions
+ &&
+ (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='?
+ &&
+ (_opt_var_1 = _tmp_241_rule(p), !p->error_indicator) // ['!' NAME]
+ &&
+ (_literal_1 = _PyPegen_expect_token(p, 11)) // token=':'
+ &&
+ (_loop0_242_var = _loop0_242_rule(p)) // fstring_format_spec*
+ &&
+ _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'"));
+ _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '}', or format specs" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] ':' fstring_format_spec* !'}'"));
+ }
+ { // '{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_replacement_field[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'"));
+ Token * _literal;
+ void *_opt_var;
+ UNUSED(_opt_var); // Silence compiler warnings
+ void *_opt_var_1;
+ UNUSED(_opt_var_1); // Silence compiler warnings
+ void *_tmp_243_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 25)) // token='{'
+ &&
+ (_tmp_243_var = _tmp_243_rule(p)) // yield_expr | star_expressions
+ &&
+ (_opt_var = _PyPegen_expect_token(p, 22), !p->error_indicator) // '='?
+ &&
+ (_opt_var_1 = _tmp_244_rule(p), !p->error_indicator) // ['!' NAME]
+ &&
+ _PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 26) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_replacement_field[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'"));
+ _res = PyErr_Occurred ( ) ? NULL : RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: expecting '}'" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_replacement_field[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{' (yield_expr | star_expressions) '='? ['!' NAME] !'}'"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// invalid_conversion_character: '!' &(':' | '}') | '!' !NAME
+static void *
+invalid_conversion_character_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '!' &(':' | '}')
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_conversion_character[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ _PyPegen_lookahead(1, _tmp_245_rule, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' &(':' | '}')"));
+ _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: missing conversion character" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_conversion_character[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' &(':' | '}')"));
+ }
+ { // '!' !NAME
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> invalid_conversion_character[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' !NAME"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ _PyPegen_lookahead_with_name(0, _PyPegen_name_token, p)
+ )
+ {
+ D(fprintf(stderr, "%*c+ invalid_conversion_character[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' !NAME"));
+ _res = RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN ( "f-string: invalid conversion character" );
+ if (_res == NULL && PyErr_Occurred()) {
+ p->error_indicator = 1;
+ p->level--;
+ return NULL;
+ }
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s invalid_conversion_character[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' !NAME"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
// _loop0_1: NEWLINE
static asdl_seq *
_loop0_1_rule(Parser *p)
@@ -24306,9 +25251,77 @@ _loop0_2_rule(Parser *p)
return _seq;
}
-// _loop1_3: statement
+// _loop0_3: fstring_middle
static asdl_seq *
-_loop1_3_rule(Parser *p)
+_loop0_3_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void *_res = NULL;
+ int _mark = p->mark;
+ void **_children = PyMem_Malloc(sizeof(void *));
+ if (!_children) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ Py_ssize_t _children_capacity = 1;
+ Py_ssize_t _n = 0;
+ { // fstring_middle
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _loop0_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_middle"));
+ expr_ty fstring_middle_var;
+ while (
+ (fstring_middle_var = fstring_middle_rule(p)) // fstring_middle
+ )
+ {
+ _res = fstring_middle_var;
+ if (_n == _children_capacity) {
+ _children_capacity *= 2;
+ void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
+ if (!_new_children) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ _children = _new_children;
+ }
+ _children[_n++] = _res;
+ _mark = p->mark;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _loop0_3[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_middle"));
+ }
+ asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
+ if (!_seq) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);
+ PyMem_Free(_children);
+ p->level--;
+ return _seq;
+}
+
+// _loop1_4: statement
+static asdl_seq *
+_loop1_4_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24334,7 +25347,7 @@ _loop1_3_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_3[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement"));
+ D(fprintf(stderr, "%*c> _loop1_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "statement"));
asdl_stmt_seq* statement_var;
while (
(statement_var = statement_rule(p)) // statement
@@ -24357,7 +25370,7 @@ _loop1_3_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_3[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_4[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "statement"));
}
if (_n == 0 || p->error_indicator) {
@@ -24379,9 +25392,9 @@ _loop1_3_rule(Parser *p)
return _seq;
}
-// _loop0_5: ';' simple_stmt
+// _loop0_6: ';' simple_stmt
static asdl_seq *
-_loop0_5_rule(Parser *p)
+_loop0_6_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24407,7 +25420,7 @@ _loop0_5_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt"));
+ D(fprintf(stderr, "%*c> _loop0_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';' simple_stmt"));
Token * _literal;
stmt_ty elem;
while (
@@ -24439,7 +25452,7 @@ _loop0_5_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_5[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_6[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';' simple_stmt"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -24456,9 +25469,9 @@ _loop0_5_rule(Parser *p)
return _seq;
}
-// _gather_4: simple_stmt _loop0_5
+// _gather_5: simple_stmt _loop0_6
static asdl_seq *
-_gather_4_rule(Parser *p)
+_gather_5_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24470,27 +25483,27 @@ _gather_4_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // simple_stmt _loop0_5
+ { // simple_stmt _loop0_6
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_4[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5"));
+ D(fprintf(stderr, "%*c> _gather_5[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6"));
stmt_ty elem;
asdl_seq * seq;
if (
(elem = simple_stmt_rule(p)) // simple_stmt
&&
- (seq = _loop0_5_rule(p)) // _loop0_5
+ (seq = _loop0_6_rule(p)) // _loop0_6
)
{
- D(fprintf(stderr, "%*c+ _gather_4[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_5"));
+ D(fprintf(stderr, "%*c+ _gather_5[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "simple_stmt _loop0_6"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_4[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_5"));
+ D(fprintf(stderr, "%*c%s _gather_5[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "simple_stmt _loop0_6"));
}
_res = NULL;
done:
@@ -24498,9 +25511,9 @@ _gather_4_rule(Parser *p)
return _res;
}
-// _tmp_6: 'import' | 'from'
+// _tmp_7: 'import' | 'from'
static void *
-_tmp_6_rule(Parser *p)
+_tmp_7_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24517,18 +25530,18 @@ _tmp_6_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'"));
+ D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'import'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 606)) // token='import'
+ (_keyword = _PyPegen_expect_token(p, 607)) // token='import'
)
{
- D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'"));
+ D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'import'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'import'"));
}
{ // 'from'
@@ -24536,18 +25549,18 @@ _tmp_6_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_6[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'"));
+ D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword = _PyPegen_expect_token(p, 608)) // token='from'
)
{
- D(fprintf(stderr, "%*c+ _tmp_6[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'"));
+ D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_6[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from'"));
}
_res = NULL;
@@ -24556,9 +25569,9 @@ _tmp_6_rule(Parser *p)
return _res;
}
-// _tmp_7: 'def' | '@' | ASYNC
+// _tmp_8: 'def' | '@' | ASYNC
static void *
-_tmp_7_rule(Parser *p)
+_tmp_8_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24575,18 +25588,18 @@ _tmp_7_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'"));
+ D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'def'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 651)) // token='def'
+ (_keyword = _PyPegen_expect_token(p, 652)) // token='def'
)
{
- D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'"));
+ D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'def'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'def'"));
}
{ // '@'
@@ -24594,18 +25607,18 @@ _tmp_7_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'"));
+ D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 49)) // token='@'
)
{
- D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'"));
+ D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'"));
}
{ // ASYNC
@@ -24613,18 +25626,18 @@ _tmp_7_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_7[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
Token * async_var;
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
)
{
- D(fprintf(stderr, "%*c+ _tmp_7[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
_res = async_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_7[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC"));
}
_res = NULL;
@@ -24633,9 +25646,9 @@ _tmp_7_rule(Parser *p)
return _res;
}
-// _tmp_8: 'class' | '@'
+// _tmp_9: 'class' | '@'
static void *
-_tmp_8_rule(Parser *p)
+_tmp_9_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24652,18 +25665,18 @@ _tmp_8_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'"));
+ D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'class'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 653)) // token='class'
+ (_keyword = _PyPegen_expect_token(p, 654)) // token='class'
)
{
- D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'"));
+ D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'class'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'class'"));
}
{ // '@'
@@ -24671,18 +25684,18 @@ _tmp_8_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_8[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'"));
+ D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 49)) // token='@'
)
{
- D(fprintf(stderr, "%*c+ _tmp_8[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'"));
+ D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_8[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@'"));
}
_res = NULL;
@@ -24691,9 +25704,9 @@ _tmp_8_rule(Parser *p)
return _res;
}
-// _tmp_9: 'with' | ASYNC
+// _tmp_10: 'with' | ASYNC
static void *
-_tmp_9_rule(Parser *p)
+_tmp_10_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24710,18 +25723,18 @@ _tmp_9_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'"));
+ D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'with'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 614)) // token='with'
+ (_keyword = _PyPegen_expect_token(p, 615)) // token='with'
)
{
- D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'"));
+ D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'with'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'with'"));
}
{ // ASYNC
@@ -24729,18 +25742,18 @@ _tmp_9_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_9[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
Token * async_var;
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
)
{
- D(fprintf(stderr, "%*c+ _tmp_9[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
_res = async_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_9[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC"));
}
_res = NULL;
@@ -24749,9 +25762,9 @@ _tmp_9_rule(Parser *p)
return _res;
}
-// _tmp_10: 'for' | ASYNC
+// _tmp_11: 'for' | ASYNC
static void *
-_tmp_10_rule(Parser *p)
+_tmp_11_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24768,18 +25781,18 @@ _tmp_10_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'"));
+ D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'for'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 649)) // token='for'
+ (_keyword = _PyPegen_expect_token(p, 650)) // token='for'
)
{
- D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'"));
+ D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'for'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'for'"));
}
{ // ASYNC
@@ -24787,18 +25800,18 @@ _tmp_10_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_10[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "ASYNC"));
Token * async_var;
if (
(async_var = _PyPegen_expect_token(p, ASYNC)) // token='ASYNC'
)
{
- D(fprintf(stderr, "%*c+ _tmp_10[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
+ D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "ASYNC"));
_res = async_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_10[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "ASYNC"));
}
_res = NULL;
@@ -24807,9 +25820,9 @@ _tmp_10_rule(Parser *p)
return _res;
}
-// _tmp_11: '=' annotated_rhs
+// _tmp_12: '=' annotated_rhs
static void *
-_tmp_11_rule(Parser *p)
+_tmp_12_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24826,7 +25839,7 @@ _tmp_11_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_11[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
+ D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
Token * _literal;
expr_ty d;
if (
@@ -24835,7 +25848,7 @@ _tmp_11_rule(Parser *p)
(d = annotated_rhs_rule(p)) // annotated_rhs
)
{
- D(fprintf(stderr, "%*c+ _tmp_11[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
+ D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
_res = d;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -24845,7 +25858,7 @@ _tmp_11_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_11[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs"));
}
_res = NULL;
@@ -24854,9 +25867,9 @@ _tmp_11_rule(Parser *p)
return _res;
}
-// _tmp_12: '(' single_target ')' | single_subscript_attribute_target
+// _tmp_13: '(' single_target ')' | single_subscript_attribute_target
static void *
-_tmp_12_rule(Parser *p)
+_tmp_13_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24873,7 +25886,7 @@ _tmp_12_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'"));
+ D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'"));
Token * _literal;
Token * _literal_1;
expr_ty b;
@@ -24885,7 +25898,7 @@ _tmp_12_rule(Parser *p)
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'"));
+ D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' single_target ')'"));
_res = b;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -24895,7 +25908,7 @@ _tmp_12_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' single_target ')'"));
}
{ // single_subscript_attribute_target
@@ -24903,18 +25916,18 @@ _tmp_12_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_12[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target"));
+ D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target"));
expr_ty single_subscript_attribute_target_var;
if (
(single_subscript_attribute_target_var = single_subscript_attribute_target_rule(p)) // single_subscript_attribute_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_12[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target"));
+ D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "single_subscript_attribute_target"));
_res = single_subscript_attribute_target_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_12[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "single_subscript_attribute_target"));
}
_res = NULL;
@@ -24923,9 +25936,9 @@ _tmp_12_rule(Parser *p)
return _res;
}
-// _tmp_13: '=' annotated_rhs
+// _tmp_14: '=' annotated_rhs
static void *
-_tmp_13_rule(Parser *p)
+_tmp_14_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24942,7 +25955,7 @@ _tmp_13_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_13[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
+ D(fprintf(stderr, "%*c> _tmp_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
Token * _literal;
expr_ty d;
if (
@@ -24951,7 +25964,7 @@ _tmp_13_rule(Parser *p)
(d = annotated_rhs_rule(p)) // annotated_rhs
)
{
- D(fprintf(stderr, "%*c+ _tmp_13[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
+ D(fprintf(stderr, "%*c+ _tmp_14[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'=' annotated_rhs"));
_res = d;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -24961,7 +25974,7 @@ _tmp_13_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_13[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_14[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'=' annotated_rhs"));
}
_res = NULL;
@@ -24970,9 +25983,9 @@ _tmp_13_rule(Parser *p)
return _res;
}
-// _loop1_14: (star_targets '=')
+// _loop1_15: (star_targets '=')
static asdl_seq *
-_loop1_14_rule(Parser *p)
+_loop1_15_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -24998,13 +26011,13 @@ _loop1_14_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_14[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
- void *_tmp_226_var;
+ D(fprintf(stderr, "%*c> _loop1_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
+ void *_tmp_246_var;
while (
- (_tmp_226_var = _tmp_226_rule(p)) // star_targets '='
+ (_tmp_246_var = _tmp_246_rule(p)) // star_targets '='
)
{
- _res = _tmp_226_var;
+ _res = _tmp_246_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -25021,7 +26034,7 @@ _loop1_14_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_14[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_15[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')"));
}
if (_n == 0 || p->error_indicator) {
@@ -25043,9 +26056,9 @@ _loop1_14_rule(Parser *p)
return _seq;
}
-// _tmp_15: yield_expr | star_expressions
+// _tmp_16: yield_expr | star_expressions
static void *
-_tmp_15_rule(Parser *p)
+_tmp_16_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25062,18 +26075,18 @@ _tmp_15_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
expr_ty yield_expr_var;
if (
(yield_expr_var = yield_expr_rule(p)) // yield_expr
)
{
- D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
_res = yield_expr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
}
{ // star_expressions
@@ -25081,18 +26094,18 @@ _tmp_15_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_15[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
expr_ty star_expressions_var;
if (
(star_expressions_var = star_expressions_rule(p)) // star_expressions
)
{
- D(fprintf(stderr, "%*c+ _tmp_15[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
_res = star_expressions_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_15[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
}
_res = NULL;
@@ -25101,9 +26114,9 @@ _tmp_15_rule(Parser *p)
return _res;
}
-// _tmp_16: yield_expr | star_expressions
+// _tmp_17: yield_expr | star_expressions
static void *
-_tmp_16_rule(Parser *p)
+_tmp_17_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25120,18 +26133,18 @@ _tmp_16_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
expr_ty yield_expr_var;
if (
(yield_expr_var = yield_expr_rule(p)) // yield_expr
)
{
- D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
_res = yield_expr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
}
{ // star_expressions
@@ -25139,18 +26152,18 @@ _tmp_16_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_16[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
expr_ty star_expressions_var;
if (
(star_expressions_var = star_expressions_rule(p)) // star_expressions
)
{
- D(fprintf(stderr, "%*c+ _tmp_16[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
_res = star_expressions_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_16[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
}
_res = NULL;
@@ -25159,9 +26172,9 @@ _tmp_16_rule(Parser *p)
return _res;
}
-// _tmp_17: 'from' expression
+// _tmp_18: 'from' expression
static void *
-_tmp_17_rule(Parser *p)
+_tmp_18_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25178,16 +26191,16 @@ _tmp_17_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_17[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression"));
+ D(fprintf(stderr, "%*c> _tmp_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'from' expression"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 607)) // token='from'
+ (_keyword = _PyPegen_expect_token(p, 608)) // token='from'
&&
(z = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_17[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'from' expression"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -25197,7 +26210,7 @@ _tmp_17_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_17[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_18[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'from' expression"));
}
_res = NULL;
@@ -25206,9 +26219,9 @@ _tmp_17_rule(Parser *p)
return _res;
}
-// _loop0_19: ',' NAME
+// _loop0_20: ',' NAME
static asdl_seq *
-_loop0_19_rule(Parser *p)
+_loop0_20_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25234,7 +26247,7 @@ _loop0_19_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME"));
+ D(fprintf(stderr, "%*c> _loop0_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME"));
Token * _literal;
expr_ty elem;
while (
@@ -25266,7 +26279,7 @@ _loop0_19_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_19[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_20[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -25283,9 +26296,9 @@ _loop0_19_rule(Parser *p)
return _seq;
}
-// _gather_18: NAME _loop0_19
+// _gather_19: NAME _loop0_20
static asdl_seq *
-_gather_18_rule(Parser *p)
+_gather_19_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25297,27 +26310,27 @@ _gather_18_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // NAME _loop0_19
+ { // NAME _loop0_20
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_18[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19"));
+ D(fprintf(stderr, "%*c> _gather_19[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = _PyPegen_name_token(p)) // NAME
&&
- (seq = _loop0_19_rule(p)) // _loop0_19
+ (seq = _loop0_20_rule(p)) // _loop0_20
)
{
- D(fprintf(stderr, "%*c+ _gather_18[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_19"));
+ D(fprintf(stderr, "%*c+ _gather_19[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_20"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_18[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_19"));
+ D(fprintf(stderr, "%*c%s _gather_19[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_20"));
}
_res = NULL;
done:
@@ -25325,9 +26338,9 @@ _gather_18_rule(Parser *p)
return _res;
}
-// _loop0_21: ',' NAME
+// _loop0_22: ',' NAME
static asdl_seq *
-_loop0_21_rule(Parser *p)
+_loop0_22_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25353,7 +26366,7 @@ _loop0_21_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME"));
+ D(fprintf(stderr, "%*c> _loop0_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' NAME"));
Token * _literal;
expr_ty elem;
while (
@@ -25385,7 +26398,7 @@ _loop0_21_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_21[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_22[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' NAME"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -25402,9 +26415,9 @@ _loop0_21_rule(Parser *p)
return _seq;
}
-// _gather_20: NAME _loop0_21
+// _gather_21: NAME _loop0_22
static asdl_seq *
-_gather_20_rule(Parser *p)
+_gather_21_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25416,27 +26429,27 @@ _gather_20_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // NAME _loop0_21
+ { // NAME _loop0_22
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_20[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21"));
+ D(fprintf(stderr, "%*c> _gather_21[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = _PyPegen_name_token(p)) // NAME
&&
- (seq = _loop0_21_rule(p)) // _loop0_21
+ (seq = _loop0_22_rule(p)) // _loop0_22
)
{
- D(fprintf(stderr, "%*c+ _gather_20[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_21"));
+ D(fprintf(stderr, "%*c+ _gather_21[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME _loop0_22"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_20[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_21"));
+ D(fprintf(stderr, "%*c%s _gather_21[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME _loop0_22"));
}
_res = NULL;
done:
@@ -25444,9 +26457,9 @@ _gather_20_rule(Parser *p)
return _res;
}
-// _tmp_22: ';' | NEWLINE
+// _tmp_23: ';' | NEWLINE
static void *
-_tmp_22_rule(Parser *p)
+_tmp_23_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25463,18 +26476,18 @@ _tmp_22_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'"));
+ D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "';'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 13)) // token=';'
)
{
- D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'"));
+ D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "';'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "';'"));
}
{ // NEWLINE
@@ -25482,18 +26495,18 @@ _tmp_22_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_22[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
+ D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
Token * newline_var;
if (
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
{
- D(fprintf(stderr, "%*c+ _tmp_22[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
+ D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
_res = newline_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_22[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE"));
}
_res = NULL;
@@ -25502,9 +26515,9 @@ _tmp_22_rule(Parser *p)
return _res;
}
-// _tmp_23: ',' expression
+// _tmp_24: ',' expression
static void *
-_tmp_23_rule(Parser *p)
+_tmp_24_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25521,7 +26534,7 @@ _tmp_23_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_23[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _tmp_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty z;
if (
@@ -25530,7 +26543,7 @@ _tmp_23_rule(Parser *p)
(z = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_23[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_24[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -25540,7 +26553,7 @@ _tmp_23_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_23[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_24[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
_res = NULL;
@@ -25549,9 +26562,9 @@ _tmp_23_rule(Parser *p)
return _res;
}
-// _loop0_24: ('.' | '...')
+// _loop0_25: ('.' | '...')
static asdl_seq *
-_loop0_24_rule(Parser *p)
+_loop0_25_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25577,13 +26590,13 @@ _loop0_24_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_24[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
- void *_tmp_227_var;
+ D(fprintf(stderr, "%*c> _loop0_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
+ void *_tmp_247_var;
while (
- (_tmp_227_var = _tmp_227_rule(p)) // '.' | '...'
+ (_tmp_247_var = _tmp_247_rule(p)) // '.' | '...'
)
{
- _res = _tmp_227_var;
+ _res = _tmp_247_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -25600,7 +26613,7 @@ _loop0_24_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_24[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_25[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -25617,9 +26630,9 @@ _loop0_24_rule(Parser *p)
return _seq;
}
-// _loop1_25: ('.' | '...')
+// _loop1_26: ('.' | '...')
static asdl_seq *
-_loop1_25_rule(Parser *p)
+_loop1_26_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25645,13 +26658,13 @@ _loop1_25_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_25[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
- void *_tmp_228_var;
+ D(fprintf(stderr, "%*c> _loop1_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('.' | '...')"));
+ void *_tmp_248_var;
while (
- (_tmp_228_var = _tmp_228_rule(p)) // '.' | '...'
+ (_tmp_248_var = _tmp_248_rule(p)) // '.' | '...'
)
{
- _res = _tmp_228_var;
+ _res = _tmp_248_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -25668,7 +26681,7 @@ _loop1_25_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_25[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_26[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('.' | '...')"));
}
if (_n == 0 || p->error_indicator) {
@@ -25690,9 +26703,9 @@ _loop1_25_rule(Parser *p)
return _seq;
}
-// _loop0_27: ',' import_from_as_name
+// _loop0_28: ',' import_from_as_name
static asdl_seq *
-_loop0_27_rule(Parser *p)
+_loop0_28_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25718,7 +26731,7 @@ _loop0_27_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name"));
+ D(fprintf(stderr, "%*c> _loop0_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' import_from_as_name"));
Token * _literal;
alias_ty elem;
while (
@@ -25750,7 +26763,7 @@ _loop0_27_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_27[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_28[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' import_from_as_name"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -25767,9 +26780,9 @@ _loop0_27_rule(Parser *p)
return _seq;
}
-// _gather_26: import_from_as_name _loop0_27
+// _gather_27: import_from_as_name _loop0_28
static asdl_seq *
-_gather_26_rule(Parser *p)
+_gather_27_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25781,27 +26794,27 @@ _gather_26_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // import_from_as_name _loop0_27
+ { // import_from_as_name _loop0_28
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_26[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27"));
+ D(fprintf(stderr, "%*c> _gather_27[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28"));
alias_ty elem;
asdl_seq * seq;
if (
(elem = import_from_as_name_rule(p)) // import_from_as_name
&&
- (seq = _loop0_27_rule(p)) // _loop0_27
+ (seq = _loop0_28_rule(p)) // _loop0_28
)
{
- D(fprintf(stderr, "%*c+ _gather_26[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_27"));
+ D(fprintf(stderr, "%*c+ _gather_27[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "import_from_as_name _loop0_28"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_26[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_27"));
+ D(fprintf(stderr, "%*c%s _gather_27[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "import_from_as_name _loop0_28"));
}
_res = NULL;
done:
@@ -25809,9 +26822,9 @@ _gather_26_rule(Parser *p)
return _res;
}
-// _tmp_28: 'as' NAME
+// _tmp_29: 'as' NAME
static void *
-_tmp_28_rule(Parser *p)
+_tmp_29_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25828,16 +26841,16 @@ _tmp_28_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_28[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(z = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_28[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -25847,7 +26860,7 @@ _tmp_28_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_28[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_29[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -25856,9 +26869,9 @@ _tmp_28_rule(Parser *p)
return _res;
}
-// _loop0_30: ',' dotted_as_name
+// _loop0_31: ',' dotted_as_name
static asdl_seq *
-_loop0_30_rule(Parser *p)
+_loop0_31_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25884,7 +26897,7 @@ _loop0_30_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name"));
+ D(fprintf(stderr, "%*c> _loop0_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' dotted_as_name"));
Token * _literal;
alias_ty elem;
while (
@@ -25916,7 +26929,7 @@ _loop0_30_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_30[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_31[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' dotted_as_name"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -25933,9 +26946,9 @@ _loop0_30_rule(Parser *p)
return _seq;
}
-// _gather_29: dotted_as_name _loop0_30
+// _gather_30: dotted_as_name _loop0_31
static asdl_seq *
-_gather_29_rule(Parser *p)
+_gather_30_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25947,27 +26960,27 @@ _gather_29_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // dotted_as_name _loop0_30
+ { // dotted_as_name _loop0_31
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_29[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30"));
+ D(fprintf(stderr, "%*c> _gather_30[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31"));
alias_ty elem;
asdl_seq * seq;
if (
(elem = dotted_as_name_rule(p)) // dotted_as_name
&&
- (seq = _loop0_30_rule(p)) // _loop0_30
+ (seq = _loop0_31_rule(p)) // _loop0_31
)
{
- D(fprintf(stderr, "%*c+ _gather_29[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_30"));
+ D(fprintf(stderr, "%*c+ _gather_30[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dotted_as_name _loop0_31"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_29[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_30"));
+ D(fprintf(stderr, "%*c%s _gather_30[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dotted_as_name _loop0_31"));
}
_res = NULL;
done:
@@ -25975,9 +26988,9 @@ _gather_29_rule(Parser *p)
return _res;
}
-// _tmp_31: 'as' NAME
+// _tmp_32: 'as' NAME
static void *
-_tmp_31_rule(Parser *p)
+_tmp_32_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -25994,16 +27007,16 @@ _tmp_31_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_31[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(z = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_31[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_32[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -26013,7 +27026,7 @@ _tmp_31_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_31[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_32[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -26022,9 +27035,9 @@ _tmp_31_rule(Parser *p)
return _res;
}
-// _loop1_32: ('@' named_expression NEWLINE)
+// _loop1_33: ('@' named_expression NEWLINE)
static asdl_seq *
-_loop1_32_rule(Parser *p)
+_loop1_33_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26050,13 +27063,13 @@ _loop1_32_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_32[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)"));
- void *_tmp_229_var;
+ D(fprintf(stderr, "%*c> _loop1_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('@' named_expression NEWLINE)"));
+ void *_tmp_249_var;
while (
- (_tmp_229_var = _tmp_229_rule(p)) // '@' named_expression NEWLINE
+ (_tmp_249_var = _tmp_249_rule(p)) // '@' named_expression NEWLINE
)
{
- _res = _tmp_229_var;
+ _res = _tmp_249_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -26073,7 +27086,7 @@ _loop1_32_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_32[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_33[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('@' named_expression NEWLINE)"));
}
if (_n == 0 || p->error_indicator) {
@@ -26095,9 +27108,9 @@ _loop1_32_rule(Parser *p)
return _seq;
}
-// _tmp_33: '(' arguments? ')'
+// _tmp_34: '(' arguments? ')'
static void *
-_tmp_33_rule(Parser *p)
+_tmp_34_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26114,7 +27127,7 @@ _tmp_33_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_33[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
Token * _literal;
Token * _literal_1;
void *z;
@@ -26126,7 +27139,7 @@ _tmp_33_rule(Parser *p)
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_33[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -26136,7 +27149,7 @@ _tmp_33_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_33[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'"));
}
_res = NULL;
@@ -26145,9 +27158,9 @@ _tmp_33_rule(Parser *p)
return _res;
}
-// _tmp_34: '->' expression
+// _tmp_35: '->' expression
static void *
-_tmp_34_rule(Parser *p)
+_tmp_35_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26164,7 +27177,7 @@ _tmp_34_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_34[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
Token * _literal;
expr_ty z;
if (
@@ -26173,7 +27186,7 @@ _tmp_34_rule(Parser *p)
(z = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_34[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -26183,7 +27196,7 @@ _tmp_34_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_34[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression"));
}
_res = NULL;
@@ -26192,9 +27205,9 @@ _tmp_34_rule(Parser *p)
return _res;
}
-// _tmp_35: '->' expression
+// _tmp_36: '->' expression
static void *
-_tmp_35_rule(Parser *p)
+_tmp_36_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26211,7 +27224,7 @@ _tmp_35_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_35[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c> _tmp_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
Token * _literal;
expr_ty z;
if (
@@ -26220,7 +27233,7 @@ _tmp_35_rule(Parser *p)
(z = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_35[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_36[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -26230,7 +27243,7 @@ _tmp_35_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_35[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_36[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression"));
}
_res = NULL;
@@ -26239,9 +27252,9 @@ _tmp_35_rule(Parser *p)
return _res;
}
-// _loop0_36: param_no_default
+// _loop0_37: param_no_default
static asdl_seq *
-_loop0_36_rule(Parser *p)
+_loop0_37_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26267,7 +27280,7 @@ _loop0_36_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_36[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26290,7 +27303,7 @@ _loop0_36_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_36[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -26307,9 +27320,9 @@ _loop0_36_rule(Parser *p)
return _seq;
}
-// _loop0_37: param_with_default
+// _loop0_38: param_with_default
static asdl_seq *
-_loop0_37_rule(Parser *p)
+_loop0_38_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26335,7 +27348,7 @@ _loop0_37_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_37[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -26358,7 +27371,7 @@ _loop0_37_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_37[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -26375,9 +27388,9 @@ _loop0_37_rule(Parser *p)
return _seq;
}
-// _loop0_38: param_with_default
+// _loop0_39: param_with_default
static asdl_seq *
-_loop0_38_rule(Parser *p)
+_loop0_39_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26403,7 +27416,7 @@ _loop0_38_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_38[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -26426,7 +27439,7 @@ _loop0_38_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_38[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_39[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -26443,9 +27456,9 @@ _loop0_38_rule(Parser *p)
return _seq;
}
-// _loop1_39: param_no_default
+// _loop1_40: param_no_default
static asdl_seq *
-_loop1_39_rule(Parser *p)
+_loop1_40_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26471,7 +27484,7 @@ _loop1_39_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_39[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26494,7 +27507,7 @@ _loop1_39_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_39[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_40[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -26516,9 +27529,9 @@ _loop1_39_rule(Parser *p)
return _seq;
}
-// _loop0_40: param_with_default
+// _loop0_41: param_with_default
static asdl_seq *
-_loop0_40_rule(Parser *p)
+_loop0_41_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26544,7 +27557,7 @@ _loop0_40_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_40[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -26567,7 +27580,7 @@ _loop0_40_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_40[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_41[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -26584,9 +27597,9 @@ _loop0_40_rule(Parser *p)
return _seq;
}
-// _loop1_41: param_with_default
+// _loop1_42: param_with_default
static asdl_seq *
-_loop1_41_rule(Parser *p)
+_loop1_42_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26612,7 +27625,7 @@ _loop1_41_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_41[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -26635,7 +27648,7 @@ _loop1_41_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_41[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -26657,9 +27670,9 @@ _loop1_41_rule(Parser *p)
return _seq;
}
-// _loop1_42: param_no_default
+// _loop1_43: param_no_default
static asdl_seq *
-_loop1_42_rule(Parser *p)
+_loop1_43_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26685,7 +27698,7 @@ _loop1_42_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_42[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26708,7 +27721,7 @@ _loop1_42_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_42[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -26730,9 +27743,9 @@ _loop1_42_rule(Parser *p)
return _seq;
}
-// _loop1_43: param_no_default
+// _loop1_44: param_no_default
static asdl_seq *
-_loop1_43_rule(Parser *p)
+_loop1_44_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26758,7 +27771,7 @@ _loop1_43_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_43[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26781,7 +27794,7 @@ _loop1_43_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_43[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_44[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -26803,9 +27816,9 @@ _loop1_43_rule(Parser *p)
return _seq;
}
-// _loop0_44: param_no_default
+// _loop0_45: param_no_default
static asdl_seq *
-_loop0_44_rule(Parser *p)
+_loop0_45_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26831,7 +27844,7 @@ _loop0_44_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_44[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26854,7 +27867,7 @@ _loop0_44_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_44[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_45[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -26871,9 +27884,9 @@ _loop0_44_rule(Parser *p)
return _seq;
}
-// _loop1_45: param_with_default
+// _loop1_46: param_with_default
static asdl_seq *
-_loop1_45_rule(Parser *p)
+_loop1_46_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26899,7 +27912,7 @@ _loop1_45_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_45[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -26922,7 +27935,7 @@ _loop1_45_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_45[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_46[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -26944,9 +27957,9 @@ _loop1_45_rule(Parser *p)
return _seq;
}
-// _loop0_46: param_no_default
+// _loop0_47: param_no_default
static asdl_seq *
-_loop0_46_rule(Parser *p)
+_loop0_47_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -26972,7 +27985,7 @@ _loop0_46_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_46[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -26995,7 +28008,7 @@ _loop0_46_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_46[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_47[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27012,9 +28025,9 @@ _loop0_46_rule(Parser *p)
return _seq;
}
-// _loop1_47: param_with_default
+// _loop1_48: param_with_default
static asdl_seq *
-_loop1_47_rule(Parser *p)
+_loop1_48_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27040,7 +28053,7 @@ _loop1_47_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_47[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -27063,7 +28076,7 @@ _loop1_47_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_47[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_48[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -27085,9 +28098,9 @@ _loop1_47_rule(Parser *p)
return _seq;
}
-// _loop0_48: param_maybe_default
+// _loop0_49: param_maybe_default
static asdl_seq *
-_loop0_48_rule(Parser *p)
+_loop0_49_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27113,7 +28126,7 @@ _loop0_48_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_48[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -27136,7 +28149,7 @@ _loop0_48_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_48[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27153,9 +28166,9 @@ _loop0_48_rule(Parser *p)
return _seq;
}
-// _loop0_49: param_maybe_default
+// _loop0_50: param_maybe_default
static asdl_seq *
-_loop0_49_rule(Parser *p)
+_loop0_50_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27181,7 +28194,7 @@ _loop0_49_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_49[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -27204,7 +28217,7 @@ _loop0_49_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_49[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_50[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27221,9 +28234,9 @@ _loop0_49_rule(Parser *p)
return _seq;
}
-// _loop1_50: param_maybe_default
+// _loop1_51: param_maybe_default
static asdl_seq *
-_loop1_50_rule(Parser *p)
+_loop1_51_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27249,7 +28262,7 @@ _loop1_50_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_50[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop1_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -27272,7 +28285,7 @@ _loop1_50_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_50[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_51[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -27294,9 +28307,9 @@ _loop1_50_rule(Parser *p)
return _seq;
}
-// _loop0_52: ',' with_item
+// _loop0_53: ',' with_item
static asdl_seq *
-_loop0_52_rule(Parser *p)
+_loop0_53_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27322,7 +28335,7 @@ _loop0_52_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
+ D(fprintf(stderr, "%*c> _loop0_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
Token * _literal;
withitem_ty elem;
while (
@@ -27354,7 +28367,7 @@ _loop0_52_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_52[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_53[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27371,9 +28384,9 @@ _loop0_52_rule(Parser *p)
return _seq;
}
-// _gather_51: with_item _loop0_52
+// _gather_52: with_item _loop0_53
static asdl_seq *
-_gather_51_rule(Parser *p)
+_gather_52_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27385,27 +28398,27 @@ _gather_51_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // with_item _loop0_52
+ { // with_item _loop0_53
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_51[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52"));
+ D(fprintf(stderr, "%*c> _gather_52[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53"));
withitem_ty elem;
asdl_seq * seq;
if (
(elem = with_item_rule(p)) // with_item
&&
- (seq = _loop0_52_rule(p)) // _loop0_52
+ (seq = _loop0_53_rule(p)) // _loop0_53
)
{
- D(fprintf(stderr, "%*c+ _gather_51[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_52"));
+ D(fprintf(stderr, "%*c+ _gather_52[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_53"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_51[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_52"));
+ D(fprintf(stderr, "%*c%s _gather_52[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_53"));
}
_res = NULL;
done:
@@ -27413,9 +28426,9 @@ _gather_51_rule(Parser *p)
return _res;
}
-// _loop0_54: ',' with_item
+// _loop0_55: ',' with_item
static asdl_seq *
-_loop0_54_rule(Parser *p)
+_loop0_55_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27441,7 +28454,7 @@ _loop0_54_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
+ D(fprintf(stderr, "%*c> _loop0_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
Token * _literal;
withitem_ty elem;
while (
@@ -27473,7 +28486,7 @@ _loop0_54_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_54[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_55[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27490,9 +28503,9 @@ _loop0_54_rule(Parser *p)
return _seq;
}
-// _gather_53: with_item _loop0_54
+// _gather_54: with_item _loop0_55
static asdl_seq *
-_gather_53_rule(Parser *p)
+_gather_54_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27504,27 +28517,27 @@ _gather_53_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // with_item _loop0_54
+ { // with_item _loop0_55
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_53[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54"));
+ D(fprintf(stderr, "%*c> _gather_54[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55"));
withitem_ty elem;
asdl_seq * seq;
if (
(elem = with_item_rule(p)) // with_item
&&
- (seq = _loop0_54_rule(p)) // _loop0_54
+ (seq = _loop0_55_rule(p)) // _loop0_55
)
{
- D(fprintf(stderr, "%*c+ _gather_53[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_54"));
+ D(fprintf(stderr, "%*c+ _gather_54[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_55"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_53[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_54"));
+ D(fprintf(stderr, "%*c%s _gather_54[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_55"));
}
_res = NULL;
done:
@@ -27532,9 +28545,9 @@ _gather_53_rule(Parser *p)
return _res;
}
-// _loop0_56: ',' with_item
+// _loop0_57: ',' with_item
static asdl_seq *
-_loop0_56_rule(Parser *p)
+_loop0_57_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27560,7 +28573,7 @@ _loop0_56_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
+ D(fprintf(stderr, "%*c> _loop0_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
Token * _literal;
withitem_ty elem;
while (
@@ -27592,7 +28605,7 @@ _loop0_56_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_56[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_57[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27609,9 +28622,9 @@ _loop0_56_rule(Parser *p)
return _seq;
}
-// _gather_55: with_item _loop0_56
+// _gather_56: with_item _loop0_57
static asdl_seq *
-_gather_55_rule(Parser *p)
+_gather_56_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27623,27 +28636,27 @@ _gather_55_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // with_item _loop0_56
+ { // with_item _loop0_57
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_55[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56"));
+ D(fprintf(stderr, "%*c> _gather_56[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57"));
withitem_ty elem;
asdl_seq * seq;
if (
(elem = with_item_rule(p)) // with_item
&&
- (seq = _loop0_56_rule(p)) // _loop0_56
+ (seq = _loop0_57_rule(p)) // _loop0_57
)
{
- D(fprintf(stderr, "%*c+ _gather_55[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_56"));
+ D(fprintf(stderr, "%*c+ _gather_56[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_57"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_55[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_56"));
+ D(fprintf(stderr, "%*c%s _gather_56[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_57"));
}
_res = NULL;
done:
@@ -27651,9 +28664,9 @@ _gather_55_rule(Parser *p)
return _res;
}
-// _loop0_58: ',' with_item
+// _loop0_59: ',' with_item
static asdl_seq *
-_loop0_58_rule(Parser *p)
+_loop0_59_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27679,7 +28692,7 @@ _loop0_58_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
+ D(fprintf(stderr, "%*c> _loop0_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' with_item"));
Token * _literal;
withitem_ty elem;
while (
@@ -27711,7 +28724,7 @@ _loop0_58_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_58[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_59[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' with_item"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -27728,9 +28741,9 @@ _loop0_58_rule(Parser *p)
return _seq;
}
-// _gather_57: with_item _loop0_58
+// _gather_58: with_item _loop0_59
static asdl_seq *
-_gather_57_rule(Parser *p)
+_gather_58_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27742,27 +28755,27 @@ _gather_57_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // with_item _loop0_58
+ { // with_item _loop0_59
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_57[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58"));
+ D(fprintf(stderr, "%*c> _gather_58[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59"));
withitem_ty elem;
asdl_seq * seq;
if (
(elem = with_item_rule(p)) // with_item
&&
- (seq = _loop0_58_rule(p)) // _loop0_58
+ (seq = _loop0_59_rule(p)) // _loop0_59
)
{
- D(fprintf(stderr, "%*c+ _gather_57[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_58"));
+ D(fprintf(stderr, "%*c+ _gather_58[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "with_item _loop0_59"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_57[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_58"));
+ D(fprintf(stderr, "%*c%s _gather_58[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "with_item _loop0_59"));
}
_res = NULL;
done:
@@ -27770,9 +28783,9 @@ _gather_57_rule(Parser *p)
return _res;
}
-// _tmp_59: ',' | ')' | ':'
+// _tmp_60: ',' | ')' | ':'
static void *
-_tmp_59_rule(Parser *p)
+_tmp_60_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27789,18 +28802,18 @@ _tmp_59_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
{ // ')'
@@ -27808,18 +28821,18 @@ _tmp_59_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
{ // ':'
@@ -27827,18 +28840,18 @@ _tmp_59_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_59[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_59[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_60[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_59[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_60[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
_res = NULL;
@@ -27847,9 +28860,9 @@ _tmp_59_rule(Parser *p)
return _res;
}
-// _loop1_60: except_block
+// _loop1_61: except_block
static asdl_seq *
-_loop1_60_rule(Parser *p)
+_loop1_61_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27875,7 +28888,7 @@ _loop1_60_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_60[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block"));
+ D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block"));
excepthandler_ty except_block_var;
while (
(except_block_var = except_block_rule(p)) // except_block
@@ -27898,7 +28911,7 @@ _loop1_60_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_60[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block"));
}
if (_n == 0 || p->error_indicator) {
@@ -27920,9 +28933,9 @@ _loop1_60_rule(Parser *p)
return _seq;
}
-// _loop1_61: except_star_block
+// _loop1_62: except_star_block
static asdl_seq *
-_loop1_61_rule(Parser *p)
+_loop1_62_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -27948,7 +28961,7 @@ _loop1_61_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_61[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block"));
+ D(fprintf(stderr, "%*c> _loop1_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block"));
excepthandler_ty except_star_block_var;
while (
(except_star_block_var = except_star_block_rule(p)) // except_star_block
@@ -27971,7 +28984,7 @@ _loop1_61_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_61[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_62[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block"));
}
if (_n == 0 || p->error_indicator) {
@@ -27993,9 +29006,9 @@ _loop1_61_rule(Parser *p)
return _seq;
}
-// _tmp_62: 'as' NAME
+// _tmp_63: 'as' NAME
static void *
-_tmp_62_rule(Parser *p)
+_tmp_63_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28012,16 +29025,16 @@ _tmp_62_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_62[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(z = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_62[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -28031,7 +29044,7 @@ _tmp_62_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_62[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -28040,9 +29053,9 @@ _tmp_62_rule(Parser *p)
return _res;
}
-// _tmp_63: 'as' NAME
+// _tmp_64: 'as' NAME
static void *
-_tmp_63_rule(Parser *p)
+_tmp_64_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28059,16 +29072,16 @@ _tmp_63_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_63[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(z = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_63[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_64[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -28078,7 +29091,7 @@ _tmp_63_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_63[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_64[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -28087,9 +29100,9 @@ _tmp_63_rule(Parser *p)
return _res;
}
-// _loop1_64: case_block
+// _loop1_65: case_block
static asdl_seq *
-_loop1_64_rule(Parser *p)
+_loop1_65_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28115,7 +29128,7 @@ _loop1_64_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_64[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block"));
+ D(fprintf(stderr, "%*c> _loop1_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "case_block"));
match_case_ty case_block_var;
while (
(case_block_var = case_block_rule(p)) // case_block
@@ -28138,7 +29151,7 @@ _loop1_64_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_64[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_65[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "case_block"));
}
if (_n == 0 || p->error_indicator) {
@@ -28160,9 +29173,9 @@ _loop1_64_rule(Parser *p)
return _seq;
}
-// _loop0_66: '|' closed_pattern
+// _loop0_67: '|' closed_pattern
static asdl_seq *
-_loop0_66_rule(Parser *p)
+_loop0_67_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28188,7 +29201,7 @@ _loop0_66_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern"));
+ D(fprintf(stderr, "%*c> _loop0_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'|' closed_pattern"));
Token * _literal;
pattern_ty elem;
while (
@@ -28220,7 +29233,7 @@ _loop0_66_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_66[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_67[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'|' closed_pattern"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -28237,9 +29250,9 @@ _loop0_66_rule(Parser *p)
return _seq;
}
-// _gather_65: closed_pattern _loop0_66
+// _gather_66: closed_pattern _loop0_67
static asdl_seq *
-_gather_65_rule(Parser *p)
+_gather_66_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28251,85 +29264,27 @@ _gather_65_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // closed_pattern _loop0_66
+ { // closed_pattern _loop0_67
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_65[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66"));
+ D(fprintf(stderr, "%*c> _gather_66[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67"));
pattern_ty elem;
asdl_seq * seq;
if (
(elem = closed_pattern_rule(p)) // closed_pattern
&&
- (seq = _loop0_66_rule(p)) // _loop0_66
+ (seq = _loop0_67_rule(p)) // _loop0_67
)
{
- D(fprintf(stderr, "%*c+ _gather_65[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_66"));
+ D(fprintf(stderr, "%*c+ _gather_66[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "closed_pattern _loop0_67"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_65[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_66"));
- }
- _res = NULL;
- done:
- p->level--;
- return _res;
-}
-
-// _tmp_67: '+' | '-'
-static void *
-_tmp_67_rule(Parser *p)
-{
- if (p->level++ == MAXSTACK) {
- p->error_indicator = 1;
- PyErr_NoMemory();
- }
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- void * _res = NULL;
- int _mark = p->mark;
- { // '+'
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'"));
- Token * _literal;
- if (
- (_literal = _PyPegen_expect_token(p, 14)) // token='+'
- )
- {
- D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'"));
- _res = _literal;
- goto done;
- }
- p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'"));
- }
- { // '-'
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- D(fprintf(stderr, "%*c> _tmp_67[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'"));
- Token * _literal;
- if (
- (_literal = _PyPegen_expect_token(p, 15)) // token='-'
- )
- {
- D(fprintf(stderr, "%*c+ _tmp_67[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'"));
- _res = _literal;
- goto done;
- }
- p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_67[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'"));
+ D(fprintf(stderr, "%*c%s _gather_66[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "closed_pattern _loop0_67"));
}
_res = NULL;
done:
@@ -28395,7 +29350,7 @@ _tmp_68_rule(Parser *p)
return _res;
}
-// _tmp_69: '.' | '(' | '='
+// _tmp_69: '+' | '-'
static void *
_tmp_69_rule(Parser *p)
{
@@ -28409,62 +29364,43 @@ _tmp_69_rule(Parser *p)
}
void * _res = NULL;
int _mark = p->mark;
- { // '.'
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
- Token * _literal;
- if (
- (_literal = _PyPegen_expect_token(p, 23)) // token='.'
- )
- {
- D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
- _res = _literal;
- goto done;
- }
- p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
- }
- { // '('
+ { // '+'
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
+ D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'+'"));
Token * _literal;
if (
- (_literal = _PyPegen_expect_token(p, 7)) // token='('
+ (_literal = _PyPegen_expect_token(p, 14)) // token='+'
)
{
- D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
+ D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'+'"));
_res = _literal;
goto done;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'+'"));
}
- { // '='
+ { // '-'
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c> _tmp_69[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'-'"));
Token * _literal;
if (
- (_literal = _PyPegen_expect_token(p, 22)) // token='='
+ (_literal = _PyPegen_expect_token(p, 15)) // token='-'
)
{
- D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c+ _tmp_69[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'-'"));
_res = _literal;
goto done;
}
p->mark = _mark;
D(fprintf(stderr, "%*c%s _tmp_69[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='"));
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'-'"));
}
_res = NULL;
done:
@@ -28549,9 +29485,86 @@ _tmp_70_rule(Parser *p)
return _res;
}
-// _loop0_72: ',' maybe_star_pattern
+// _tmp_71: '.' | '(' | '='
+static void *
+_tmp_71_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '.'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 23)) // token='.'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
+ }
+ { // '('
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 7)) // token='('
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('"));
+ }
+ { // '='
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 22)) // token='='
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_71[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _loop0_73: ',' maybe_star_pattern
static asdl_seq *
-_loop0_72_rule(Parser *p)
+_loop0_73_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28577,7 +29590,7 @@ _loop0_72_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern"));
+ D(fprintf(stderr, "%*c> _loop0_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' maybe_star_pattern"));
Token * _literal;
pattern_ty elem;
while (
@@ -28609,7 +29622,7 @@ _loop0_72_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_72[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_73[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' maybe_star_pattern"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -28626,9 +29639,9 @@ _loop0_72_rule(Parser *p)
return _seq;
}
-// _gather_71: maybe_star_pattern _loop0_72
+// _gather_72: maybe_star_pattern _loop0_73
static asdl_seq *
-_gather_71_rule(Parser *p)
+_gather_72_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28640,27 +29653,27 @@ _gather_71_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // maybe_star_pattern _loop0_72
+ { // maybe_star_pattern _loop0_73
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_71[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72"));
+ D(fprintf(stderr, "%*c> _gather_72[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73"));
pattern_ty elem;
asdl_seq * seq;
if (
(elem = maybe_star_pattern_rule(p)) // maybe_star_pattern
&&
- (seq = _loop0_72_rule(p)) // _loop0_72
+ (seq = _loop0_73_rule(p)) // _loop0_73
)
{
- D(fprintf(stderr, "%*c+ _gather_71[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_72"));
+ D(fprintf(stderr, "%*c+ _gather_72[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "maybe_star_pattern _loop0_73"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_71[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_72"));
+ D(fprintf(stderr, "%*c%s _gather_72[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "maybe_star_pattern _loop0_73"));
}
_res = NULL;
done:
@@ -28668,9 +29681,9 @@ _gather_71_rule(Parser *p)
return _res;
}
-// _loop0_74: ',' key_value_pattern
+// _loop0_75: ',' key_value_pattern
static asdl_seq *
-_loop0_74_rule(Parser *p)
+_loop0_75_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28696,7 +29709,7 @@ _loop0_74_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern"));
+ D(fprintf(stderr, "%*c> _loop0_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' key_value_pattern"));
Token * _literal;
KeyPatternPair* elem;
while (
@@ -28728,7 +29741,7 @@ _loop0_74_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_74[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_75[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' key_value_pattern"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -28745,9 +29758,9 @@ _loop0_74_rule(Parser *p)
return _seq;
}
-// _gather_73: key_value_pattern _loop0_74
+// _gather_74: key_value_pattern _loop0_75
static asdl_seq *
-_gather_73_rule(Parser *p)
+_gather_74_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28759,27 +29772,27 @@ _gather_73_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // key_value_pattern _loop0_74
+ { // key_value_pattern _loop0_75
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_73[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74"));
+ D(fprintf(stderr, "%*c> _gather_74[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75"));
KeyPatternPair* elem;
asdl_seq * seq;
if (
(elem = key_value_pattern_rule(p)) // key_value_pattern
&&
- (seq = _loop0_74_rule(p)) // _loop0_74
+ (seq = _loop0_75_rule(p)) // _loop0_75
)
{
- D(fprintf(stderr, "%*c+ _gather_73[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_74"));
+ D(fprintf(stderr, "%*c+ _gather_74[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "key_value_pattern _loop0_75"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_73[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_74"));
+ D(fprintf(stderr, "%*c%s _gather_74[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "key_value_pattern _loop0_75"));
}
_res = NULL;
done:
@@ -28787,9 +29800,9 @@ _gather_73_rule(Parser *p)
return _res;
}
-// _tmp_75: literal_expr | attr
+// _tmp_76: literal_expr | attr
static void *
-_tmp_75_rule(Parser *p)
+_tmp_76_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28806,18 +29819,18 @@ _tmp_75_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr"));
+ D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "literal_expr"));
expr_ty literal_expr_var;
if (
(literal_expr_var = literal_expr_rule(p)) // literal_expr
)
{
- D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr"));
+ D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "literal_expr"));
_res = literal_expr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "literal_expr"));
}
{ // attr
@@ -28825,18 +29838,18 @@ _tmp_75_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_75[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr"));
+ D(fprintf(stderr, "%*c> _tmp_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "attr"));
expr_ty attr_var;
if (
(attr_var = attr_rule(p)) // attr
)
{
- D(fprintf(stderr, "%*c+ _tmp_75[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr"));
+ D(fprintf(stderr, "%*c+ _tmp_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "attr"));
_res = attr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_75[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_76[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "attr"));
}
_res = NULL;
@@ -28845,9 +29858,9 @@ _tmp_75_rule(Parser *p)
return _res;
}
-// _loop0_77: ',' pattern
+// _loop0_78: ',' pattern
static asdl_seq *
-_loop0_77_rule(Parser *p)
+_loop0_78_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28873,7 +29886,7 @@ _loop0_77_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern"));
+ D(fprintf(stderr, "%*c> _loop0_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' pattern"));
Token * _literal;
pattern_ty elem;
while (
@@ -28905,7 +29918,7 @@ _loop0_77_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_77[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_78[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' pattern"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -28922,9 +29935,9 @@ _loop0_77_rule(Parser *p)
return _seq;
}
-// _gather_76: pattern _loop0_77
+// _gather_77: pattern _loop0_78
static asdl_seq *
-_gather_76_rule(Parser *p)
+_gather_77_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28936,27 +29949,27 @@ _gather_76_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // pattern _loop0_77
+ { // pattern _loop0_78
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_76[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77"));
+ D(fprintf(stderr, "%*c> _gather_77[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78"));
pattern_ty elem;
asdl_seq * seq;
if (
(elem = pattern_rule(p)) // pattern
&&
- (seq = _loop0_77_rule(p)) // _loop0_77
+ (seq = _loop0_78_rule(p)) // _loop0_78
)
{
- D(fprintf(stderr, "%*c+ _gather_76[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_77"));
+ D(fprintf(stderr, "%*c+ _gather_77[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "pattern _loop0_78"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_76[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_77"));
+ D(fprintf(stderr, "%*c%s _gather_77[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "pattern _loop0_78"));
}
_res = NULL;
done:
@@ -28964,9 +29977,9 @@ _gather_76_rule(Parser *p)
return _res;
}
-// _loop0_79: ',' keyword_pattern
+// _loop0_80: ',' keyword_pattern
static asdl_seq *
-_loop0_79_rule(Parser *p)
+_loop0_80_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -28992,7 +30005,7 @@ _loop0_79_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern"));
+ D(fprintf(stderr, "%*c> _loop0_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' keyword_pattern"));
Token * _literal;
KeyPatternPair* elem;
while (
@@ -29024,7 +30037,7 @@ _loop0_79_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_79[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_80[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' keyword_pattern"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -29041,9 +30054,9 @@ _loop0_79_rule(Parser *p)
return _seq;
}
-// _gather_78: keyword_pattern _loop0_79
+// _gather_79: keyword_pattern _loop0_80
static asdl_seq *
-_gather_78_rule(Parser *p)
+_gather_79_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29055,27 +30068,27 @@ _gather_78_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // keyword_pattern _loop0_79
+ { // keyword_pattern _loop0_80
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_78[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79"));
+ D(fprintf(stderr, "%*c> _gather_79[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80"));
KeyPatternPair* elem;
asdl_seq * seq;
if (
(elem = keyword_pattern_rule(p)) // keyword_pattern
&&
- (seq = _loop0_79_rule(p)) // _loop0_79
+ (seq = _loop0_80_rule(p)) // _loop0_80
)
{
- D(fprintf(stderr, "%*c+ _gather_78[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_79"));
+ D(fprintf(stderr, "%*c+ _gather_79[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "keyword_pattern _loop0_80"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_78[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_79"));
+ D(fprintf(stderr, "%*c%s _gather_79[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "keyword_pattern _loop0_80"));
}
_res = NULL;
done:
@@ -29083,9 +30096,9 @@ _gather_78_rule(Parser *p)
return _res;
}
-// _loop0_81: ',' type_param
+// _loop0_82: ',' type_param
static asdl_seq *
-_loop0_81_rule(Parser *p)
+_loop0_82_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29111,7 +30124,7 @@ _loop0_81_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param"));
+ D(fprintf(stderr, "%*c> _loop0_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' type_param"));
Token * _literal;
typeparam_ty elem;
while (
@@ -29143,7 +30156,7 @@ _loop0_81_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_81[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_82[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' type_param"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -29160,9 +30173,9 @@ _loop0_81_rule(Parser *p)
return _seq;
}
-// _gather_80: type_param _loop0_81
+// _gather_81: type_param _loop0_82
static asdl_seq *
-_gather_80_rule(Parser *p)
+_gather_81_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29174,27 +30187,27 @@ _gather_80_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // type_param _loop0_81
+ { // type_param _loop0_82
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_80[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_81"));
+ D(fprintf(stderr, "%*c> _gather_81[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82"));
typeparam_ty elem;
asdl_seq * seq;
if (
(elem = type_param_rule(p)) // type_param
&&
- (seq = _loop0_81_rule(p)) // _loop0_81
+ (seq = _loop0_82_rule(p)) // _loop0_82
)
{
- D(fprintf(stderr, "%*c+ _gather_80[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_81"));
+ D(fprintf(stderr, "%*c+ _gather_81[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "type_param _loop0_82"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_80[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_81"));
+ D(fprintf(stderr, "%*c%s _gather_81[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "type_param _loop0_82"));
}
_res = NULL;
done:
@@ -29202,9 +30215,9 @@ _gather_80_rule(Parser *p)
return _res;
}
-// _loop1_82: (',' expression)
+// _loop1_83: (',' expression)
static asdl_seq *
-_loop1_82_rule(Parser *p)
+_loop1_83_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29230,13 +30243,13 @@ _loop1_82_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_82[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)"));
- void *_tmp_230_var;
+ D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' expression)"));
+ void *_tmp_250_var;
while (
- (_tmp_230_var = _tmp_230_rule(p)) // ',' expression
+ (_tmp_250_var = _tmp_250_rule(p)) // ',' expression
)
{
- _res = _tmp_230_var;
+ _res = _tmp_250_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -29253,7 +30266,7 @@ _loop1_82_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_82[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' expression)"));
}
if (_n == 0 || p->error_indicator) {
@@ -29275,9 +30288,9 @@ _loop1_82_rule(Parser *p)
return _seq;
}
-// _loop1_83: (',' star_expression)
+// _loop1_84: (',' star_expression)
static asdl_seq *
-_loop1_83_rule(Parser *p)
+_loop1_84_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29303,13 +30316,13 @@ _loop1_83_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_83[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)"));
- void *_tmp_231_var;
+ D(fprintf(stderr, "%*c> _loop1_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_expression)"));
+ void *_tmp_251_var;
while (
- (_tmp_231_var = _tmp_231_rule(p)) // ',' star_expression
+ (_tmp_251_var = _tmp_251_rule(p)) // ',' star_expression
)
{
- _res = _tmp_231_var;
+ _res = _tmp_251_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -29326,7 +30339,7 @@ _loop1_83_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_83[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_84[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_expression)"));
}
if (_n == 0 || p->error_indicator) {
@@ -29348,9 +30361,9 @@ _loop1_83_rule(Parser *p)
return _seq;
}
-// _loop0_85: ',' star_named_expression
+// _loop0_86: ',' star_named_expression
static asdl_seq *
-_loop0_85_rule(Parser *p)
+_loop0_86_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29376,7 +30389,7 @@ _loop0_85_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression"));
+ D(fprintf(stderr, "%*c> _loop0_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_named_expression"));
Token * _literal;
expr_ty elem;
while (
@@ -29408,7 +30421,7 @@ _loop0_85_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_85[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_86[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_named_expression"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -29425,9 +30438,9 @@ _loop0_85_rule(Parser *p)
return _seq;
}
-// _gather_84: star_named_expression _loop0_85
+// _gather_85: star_named_expression _loop0_86
static asdl_seq *
-_gather_84_rule(Parser *p)
+_gather_85_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29439,27 +30452,27 @@ _gather_84_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // star_named_expression _loop0_85
+ { // star_named_expression _loop0_86
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_84[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_85"));
+ D(fprintf(stderr, "%*c> _gather_85[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = star_named_expression_rule(p)) // star_named_expression
&&
- (seq = _loop0_85_rule(p)) // _loop0_85
+ (seq = _loop0_86_rule(p)) // _loop0_86
)
{
- D(fprintf(stderr, "%*c+ _gather_84[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_85"));
+ D(fprintf(stderr, "%*c+ _gather_85[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression _loop0_86"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_84[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_85"));
+ D(fprintf(stderr, "%*c%s _gather_85[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression _loop0_86"));
}
_res = NULL;
done:
@@ -29467,9 +30480,9 @@ _gather_84_rule(Parser *p)
return _res;
}
-// _loop1_86: ('or' conjunction)
+// _loop1_87: ('or' conjunction)
static asdl_seq *
-_loop1_86_rule(Parser *p)
+_loop1_87_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29495,13 +30508,13 @@ _loop1_86_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_86[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)"));
- void *_tmp_232_var;
+ D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('or' conjunction)"));
+ void *_tmp_252_var;
while (
- (_tmp_232_var = _tmp_232_rule(p)) // 'or' conjunction
+ (_tmp_252_var = _tmp_252_rule(p)) // 'or' conjunction
)
{
- _res = _tmp_232_var;
+ _res = _tmp_252_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -29518,7 +30531,7 @@ _loop1_86_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_86[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('or' conjunction)"));
}
if (_n == 0 || p->error_indicator) {
@@ -29540,9 +30553,9 @@ _loop1_86_rule(Parser *p)
return _seq;
}
-// _loop1_87: ('and' inversion)
+// _loop1_88: ('and' inversion)
static asdl_seq *
-_loop1_87_rule(Parser *p)
+_loop1_88_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29568,13 +30581,13 @@ _loop1_87_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_87[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)"));
- void *_tmp_233_var;
+ D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('and' inversion)"));
+ void *_tmp_253_var;
while (
- (_tmp_233_var = _tmp_233_rule(p)) // 'and' inversion
+ (_tmp_253_var = _tmp_253_rule(p)) // 'and' inversion
)
{
- _res = _tmp_233_var;
+ _res = _tmp_253_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -29591,7 +30604,7 @@ _loop1_87_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_87[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_88[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('and' inversion)"));
}
if (_n == 0 || p->error_indicator) {
@@ -29613,9 +30626,9 @@ _loop1_87_rule(Parser *p)
return _seq;
}
-// _loop1_88: compare_op_bitwise_or_pair
+// _loop1_89: compare_op_bitwise_or_pair
static asdl_seq *
-_loop1_88_rule(Parser *p)
+_loop1_89_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29641,7 +30654,7 @@ _loop1_88_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_88[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair"));
+ D(fprintf(stderr, "%*c> _loop1_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "compare_op_bitwise_or_pair"));
CmpopExprPair* compare_op_bitwise_or_pair_var;
while (
(compare_op_bitwise_or_pair_var = compare_op_bitwise_or_pair_rule(p)) // compare_op_bitwise_or_pair
@@ -29664,7 +30677,7 @@ _loop1_88_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_88[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_89[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "compare_op_bitwise_or_pair"));
}
if (_n == 0 || p->error_indicator) {
@@ -29686,9 +30699,9 @@ _loop1_88_rule(Parser *p)
return _seq;
}
-// _tmp_89: '!='
+// _tmp_90: '!='
static void *
-_tmp_89_rule(Parser *p)
+_tmp_90_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29705,13 +30718,13 @@ _tmp_89_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_89[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='"));
+ D(fprintf(stderr, "%*c> _tmp_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!='"));
Token * tok;
if (
(tok = _PyPegen_expect_token(p, 28)) // token='!='
)
{
- D(fprintf(stderr, "%*c+ _tmp_89[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='"));
+ D(fprintf(stderr, "%*c+ _tmp_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!='"));
_res = _PyPegen_check_barry_as_flufl ( p , tok ) ? NULL : tok;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -29721,7 +30734,7 @@ _tmp_89_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_89[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_90[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!='"));
}
_res = NULL;
@@ -29730,9 +30743,9 @@ _tmp_89_rule(Parser *p)
return _res;
}
-// _loop0_91: ',' (slice | starred_expression)
+// _loop0_92: ',' (slice | starred_expression)
static asdl_seq *
-_loop0_91_rule(Parser *p)
+_loop0_92_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29758,13 +30771,13 @@ _loop0_91_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)"));
+ D(fprintf(stderr, "%*c> _loop0_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (slice | starred_expression)"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_234_rule(p)) // slice | starred_expression
+ (elem = _tmp_254_rule(p)) // slice | starred_expression
)
{
_res = elem;
@@ -29790,7 +30803,7 @@ _loop0_91_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_91[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_92[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (slice | starred_expression)"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -29807,9 +30820,9 @@ _loop0_91_rule(Parser *p)
return _seq;
}
-// _gather_90: (slice | starred_expression) _loop0_91
+// _gather_91: (slice | starred_expression) _loop0_92
static asdl_seq *
-_gather_90_rule(Parser *p)
+_gather_91_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29821,27 +30834,27 @@ _gather_90_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (slice | starred_expression) _loop0_91
+ { // (slice | starred_expression) _loop0_92
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_90[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_91"));
+ D(fprintf(stderr, "%*c> _gather_91[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_234_rule(p)) // slice | starred_expression
+ (elem = _tmp_254_rule(p)) // slice | starred_expression
&&
- (seq = _loop0_91_rule(p)) // _loop0_91
+ (seq = _loop0_92_rule(p)) // _loop0_92
)
{
- D(fprintf(stderr, "%*c+ _gather_90[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_91"));
+ D(fprintf(stderr, "%*c+ _gather_91[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(slice | starred_expression) _loop0_92"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_90[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_91"));
+ D(fprintf(stderr, "%*c%s _gather_91[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(slice | starred_expression) _loop0_92"));
}
_res = NULL;
done:
@@ -29849,9 +30862,9 @@ _gather_90_rule(Parser *p)
return _res;
}
-// _tmp_92: ':' expression?
+// _tmp_93: ':' expression?
static void *
-_tmp_92_rule(Parser *p)
+_tmp_93_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29868,7 +30881,7 @@ _tmp_92_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_92[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?"));
+ D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':' expression?"));
Token * _literal;
void *d;
if (
@@ -29877,7 +30890,7 @@ _tmp_92_rule(Parser *p)
(d = expression_rule(p), !p->error_indicator) // expression?
)
{
- D(fprintf(stderr, "%*c+ _tmp_92[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?"));
+ D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':' expression?"));
_res = d;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -29887,7 +30900,7 @@ _tmp_92_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_92[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':' expression?"));
}
_res = NULL;
@@ -29896,9 +30909,67 @@ _tmp_92_rule(Parser *p)
return _res;
}
-// _tmp_93: tuple | group | genexp
+// _tmp_94: STRING | FSTRING_START
static void *
-_tmp_93_rule(Parser *p)
+_tmp_94_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // STRING
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING"));
+ expr_ty string_var;
+ if (
+ (string_var = _PyPegen_string_token(p)) // STRING
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "STRING"));
+ _res = string_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING"));
+ }
+ { // FSTRING_START
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_START"));
+ Token * fstring_start_var;
+ if (
+ (fstring_start_var = _PyPegen_expect_token(p, FSTRING_START)) // token='FSTRING_START'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_START"));
+ _res = fstring_start_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_START"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_95: tuple | group | genexp
+static void *
+_tmp_95_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29915,18 +30986,18 @@ _tmp_93_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple"));
+ D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple"));
expr_ty tuple_var;
if (
(tuple_var = tuple_rule(p)) // tuple
)
{
- D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple"));
+ D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple"));
_res = tuple_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple"));
}
{ // group
@@ -29934,18 +31005,18 @@ _tmp_93_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group"));
+ D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "group"));
expr_ty group_var;
if (
(group_var = group_rule(p)) // group
)
{
- D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group"));
+ D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "group"));
_res = group_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "group"));
}
{ // genexp
@@ -29953,18 +31024,18 @@ _tmp_93_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_93[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp"));
+ D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp"));
expr_ty genexp_var;
if (
(genexp_var = genexp_rule(p)) // genexp
)
{
- D(fprintf(stderr, "%*c+ _tmp_93[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp"));
+ D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp"));
_res = genexp_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_93[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp"));
}
_res = NULL;
@@ -29973,9 +31044,9 @@ _tmp_93_rule(Parser *p)
return _res;
}
-// _tmp_94: list | listcomp
+// _tmp_96: list | listcomp
static void *
-_tmp_94_rule(Parser *p)
+_tmp_96_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -29992,18 +31063,18 @@ _tmp_94_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list"));
+ D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list"));
expr_ty list_var;
if (
(list_var = list_rule(p)) // list
)
{
- D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list"));
+ D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list"));
_res = list_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list"));
}
{ // listcomp
@@ -30011,18 +31082,18 @@ _tmp_94_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_94[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp"));
+ D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "listcomp"));
expr_ty listcomp_var;
if (
(listcomp_var = listcomp_rule(p)) // listcomp
)
{
- D(fprintf(stderr, "%*c+ _tmp_94[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp"));
+ D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "listcomp"));
_res = listcomp_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_94[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "listcomp"));
}
_res = NULL;
@@ -30031,9 +31102,9 @@ _tmp_94_rule(Parser *p)
return _res;
}
-// _tmp_95: dict | set | dictcomp | setcomp
+// _tmp_97: dict | set | dictcomp | setcomp
static void *
-_tmp_95_rule(Parser *p)
+_tmp_97_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30050,18 +31121,18 @@ _tmp_95_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict"));
+ D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dict"));
expr_ty dict_var;
if (
(dict_var = dict_rule(p)) // dict
)
{
- D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict"));
+ D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dict"));
_res = dict_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dict"));
}
{ // set
@@ -30069,18 +31140,18 @@ _tmp_95_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set"));
+ D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "set"));
expr_ty set_var;
if (
(set_var = set_rule(p)) // set
)
{
- D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set"));
+ D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "set"));
_res = set_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "set"));
}
{ // dictcomp
@@ -30088,18 +31159,18 @@ _tmp_95_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp"));
+ D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "dictcomp"));
expr_ty dictcomp_var;
if (
(dictcomp_var = dictcomp_rule(p)) // dictcomp
)
{
- D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp"));
+ D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "dictcomp"));
_res = dictcomp_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "dictcomp"));
}
{ // setcomp
@@ -30107,18 +31178,18 @@ _tmp_95_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_95[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp"));
+ D(fprintf(stderr, "%*c> _tmp_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "setcomp"));
expr_ty setcomp_var;
if (
(setcomp_var = setcomp_rule(p)) // setcomp
)
{
- D(fprintf(stderr, "%*c+ _tmp_95[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp"));
+ D(fprintf(stderr, "%*c+ _tmp_97[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "setcomp"));
_res = setcomp_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_95[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_97[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "setcomp"));
}
_res = NULL;
@@ -30127,9 +31198,9 @@ _tmp_95_rule(Parser *p)
return _res;
}
-// _tmp_96: yield_expr | named_expression
+// _tmp_98: yield_expr | named_expression
static void *
-_tmp_96_rule(Parser *p)
+_tmp_98_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30146,18 +31217,18 @@ _tmp_96_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
expr_ty yield_expr_var;
if (
(yield_expr_var = yield_expr_rule(p)) // yield_expr
)
{
- D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
_res = yield_expr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
}
{ // named_expression
@@ -30165,18 +31236,18 @@ _tmp_96_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_96[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression"));
+ D(fprintf(stderr, "%*c> _tmp_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "named_expression"));
expr_ty named_expression_var;
if (
(named_expression_var = named_expression_rule(p)) // named_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_96[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_98[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "named_expression"));
_res = named_expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_96[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_98[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "named_expression"));
}
_res = NULL;
@@ -30185,9 +31256,9 @@ _tmp_96_rule(Parser *p)
return _res;
}
-// _loop0_97: lambda_param_no_default
+// _loop0_99: lambda_param_no_default
static asdl_seq *
-_loop0_97_rule(Parser *p)
+_loop0_99_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30213,7 +31284,7 @@ _loop0_97_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_97[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30236,7 +31307,7 @@ _loop0_97_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_97[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30253,9 +31324,9 @@ _loop0_97_rule(Parser *p)
return _seq;
}
-// _loop0_98: lambda_param_with_default
+// _loop0_100: lambda_param_with_default
static asdl_seq *
-_loop0_98_rule(Parser *p)
+_loop0_100_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30281,7 +31352,7 @@ _loop0_98_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_98[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -30304,7 +31375,7 @@ _loop0_98_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_98[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_100[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30321,9 +31392,9 @@ _loop0_98_rule(Parser *p)
return _seq;
}
-// _loop0_99: lambda_param_with_default
+// _loop0_101: lambda_param_with_default
static asdl_seq *
-_loop0_99_rule(Parser *p)
+_loop0_101_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30349,7 +31420,7 @@ _loop0_99_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_99[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -30372,7 +31443,7 @@ _loop0_99_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_99[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30389,9 +31460,9 @@ _loop0_99_rule(Parser *p)
return _seq;
}
-// _loop1_100: lambda_param_no_default
+// _loop1_102: lambda_param_no_default
static asdl_seq *
-_loop1_100_rule(Parser *p)
+_loop1_102_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30417,7 +31488,7 @@ _loop1_100_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_100[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30440,7 +31511,7 @@ _loop1_100_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_100[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_102[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -30462,9 +31533,9 @@ _loop1_100_rule(Parser *p)
return _seq;
}
-// _loop0_101: lambda_param_with_default
+// _loop0_103: lambda_param_with_default
static asdl_seq *
-_loop0_101_rule(Parser *p)
+_loop0_103_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30490,7 +31561,7 @@ _loop0_101_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_101[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop0_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -30513,7 +31584,7 @@ _loop0_101_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_101[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_103[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30530,9 +31601,9 @@ _loop0_101_rule(Parser *p)
return _seq;
}
-// _loop1_102: lambda_param_with_default
+// _loop1_104: lambda_param_with_default
static asdl_seq *
-_loop1_102_rule(Parser *p)
+_loop1_104_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30558,7 +31629,7 @@ _loop1_102_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_102[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -30581,7 +31652,7 @@ _loop1_102_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_102[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -30603,9 +31674,9 @@ _loop1_102_rule(Parser *p)
return _seq;
}
-// _loop1_103: lambda_param_no_default
+// _loop1_105: lambda_param_no_default
static asdl_seq *
-_loop1_103_rule(Parser *p)
+_loop1_105_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30631,7 +31702,7 @@ _loop1_103_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_103[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30654,7 +31725,7 @@ _loop1_103_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_103[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_105[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -30676,9 +31747,9 @@ _loop1_103_rule(Parser *p)
return _seq;
}
-// _loop1_104: lambda_param_no_default
+// _loop1_106: lambda_param_no_default
static asdl_seq *
-_loop1_104_rule(Parser *p)
+_loop1_106_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30704,7 +31775,7 @@ _loop1_104_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_104[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30727,7 +31798,7 @@ _loop1_104_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_104[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_106[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -30749,9 +31820,9 @@ _loop1_104_rule(Parser *p)
return _seq;
}
-// _loop0_105: lambda_param_no_default
+// _loop0_107: lambda_param_no_default
static asdl_seq *
-_loop0_105_rule(Parser *p)
+_loop0_107_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30777,7 +31848,7 @@ _loop0_105_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_105[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30800,7 +31871,7 @@ _loop0_105_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_105[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30817,9 +31888,9 @@ _loop0_105_rule(Parser *p)
return _seq;
}
-// _loop1_106: lambda_param_with_default
+// _loop1_108: lambda_param_with_default
static asdl_seq *
-_loop1_106_rule(Parser *p)
+_loop1_108_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30845,7 +31916,7 @@ _loop1_106_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_106[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -30868,7 +31939,7 @@ _loop1_106_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_106[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -30890,9 +31961,9 @@ _loop1_106_rule(Parser *p)
return _seq;
}
-// _loop0_107: lambda_param_no_default
+// _loop0_109: lambda_param_no_default
static asdl_seq *
-_loop0_107_rule(Parser *p)
+_loop0_109_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30918,7 +31989,7 @@ _loop0_107_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_107[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -30941,7 +32012,7 @@ _loop0_107_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_107[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -30958,9 +32029,9 @@ _loop0_107_rule(Parser *p)
return _seq;
}
-// _loop1_108: lambda_param_with_default
+// _loop1_110: lambda_param_with_default
static asdl_seq *
-_loop1_108_rule(Parser *p)
+_loop1_110_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -30986,7 +32057,7 @@ _loop1_108_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_108[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -31009,7 +32080,7 @@ _loop1_108_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_108[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -31031,9 +32102,9 @@ _loop1_108_rule(Parser *p)
return _seq;
}
-// _loop0_109: lambda_param_maybe_default
+// _loop0_111: lambda_param_maybe_default
static asdl_seq *
-_loop0_109_rule(Parser *p)
+_loop0_111_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31059,7 +32130,7 @@ _loop0_109_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_109[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -31082,7 +32153,7 @@ _loop0_109_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_109[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_111[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31099,9 +32170,9 @@ _loop0_109_rule(Parser *p)
return _seq;
}
-// _loop1_110: lambda_param_maybe_default
+// _loop1_112: lambda_param_maybe_default
static asdl_seq *
-_loop1_110_rule(Parser *p)
+_loop1_112_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31127,7 +32198,7 @@ _loop1_110_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_110[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop1_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -31150,7 +32221,7 @@ _loop1_110_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_110[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_112[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -31172,82 +32243,208 @@ _loop1_110_rule(Parser *p)
return _seq;
}
-// _loop1_111: STRING
-static asdl_seq *
-_loop1_111_rule(Parser *p)
-{
- if (p->level++ == MAXSTACK) {
- p->error_indicator = 1;
- PyErr_NoMemory();
- }
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- void *_res = NULL;
- int _mark = p->mark;
- void **_children = PyMem_Malloc(sizeof(void *));
- if (!_children) {
- p->error_indicator = 1;
- PyErr_NoMemory();
- p->level--;
- return NULL;
- }
- Py_ssize_t _children_capacity = 1;
- Py_ssize_t _n = 0;
- { // STRING
- if (p->error_indicator) {
- p->level--;
- return NULL;
- }
- D(fprintf(stderr, "%*c> _loop1_111[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "STRING"));
- expr_ty string_var;
- while (
- (string_var = _PyPegen_string_token(p)) // STRING
- )
- {
- _res = string_var;
- if (_n == _children_capacity) {
- _children_capacity *= 2;
- void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
- if (!_new_children) {
- PyMem_Free(_children);
- p->error_indicator = 1;
- PyErr_NoMemory();
- p->level--;
- return NULL;
- }
- _children = _new_children;
- }
- _children[_n++] = _res;
- _mark = p->mark;
- }
- p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_111[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "STRING"));
- }
- if (_n == 0 || p->error_indicator) {
- PyMem_Free(_children);
- p->level--;
- return NULL;
- }
- asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
- if (!_seq) {
- PyMem_Free(_children);
- p->error_indicator = 1;
- PyErr_NoMemory();
- p->level--;
- return NULL;
- }
- for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);
- PyMem_Free(_children);
- p->level--;
- return _seq;
-}
-
-// _tmp_112: star_named_expression ',' star_named_expressions?
+// _tmp_113: yield_expr | star_expressions
static void *
-_tmp_112_rule(Parser *p)
+_tmp_113_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_113[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _loop0_114: fstring_format_spec
+static asdl_seq *
+_loop0_114_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void *_res = NULL;
+ int _mark = p->mark;
+ void **_children = PyMem_Malloc(sizeof(void *));
+ if (!_children) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ Py_ssize_t _children_capacity = 1;
+ Py_ssize_t _n = 0;
+ { // fstring_format_spec
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec"));
+ expr_ty fstring_format_spec_var;
+ while (
+ (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec
+ )
+ {
+ _res = fstring_format_spec_var;
+ if (_n == _children_capacity) {
+ _children_capacity *= 2;
+ void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
+ if (!_new_children) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ _children = _new_children;
+ }
+ _children[_n++] = _res;
+ _mark = p->mark;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec"));
+ }
+ asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
+ if (!_seq) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);
+ PyMem_Free(_children);
+ p->level--;
+ return _seq;
+}
+
+// _loop1_115: (fstring | string)
+static asdl_seq *
+_loop1_115_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void *_res = NULL;
+ int _mark = p->mark;
+ void **_children = PyMem_Malloc(sizeof(void *));
+ if (!_children) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ Py_ssize_t _children_capacity = 1;
+ Py_ssize_t _n = 0;
+ { // (fstring | string)
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(fstring | string)"));
+ void *_tmp_255_var;
+ while (
+ (_tmp_255_var = _tmp_255_rule(p)) // fstring | string
+ )
+ {
+ _res = _tmp_255_var;
+ if (_n == _children_capacity) {
+ _children_capacity *= 2;
+ void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
+ if (!_new_children) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ _children = _new_children;
+ }
+ _children[_n++] = _res;
+ _mark = p->mark;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _loop1_115[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(fstring | string)"));
+ }
+ if (_n == 0 || p->error_indicator) {
+ PyMem_Free(_children);
+ p->level--;
+ return NULL;
+ }
+ asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
+ if (!_seq) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);
+ PyMem_Free(_children);
+ p->level--;
+ return _seq;
+}
+
+// _tmp_116: star_named_expression ',' star_named_expressions?
+static void *
+_tmp_116_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31264,7 +32461,7 @@ _tmp_112_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_112[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?"));
+ D(fprintf(stderr, "%*c> _tmp_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?"));
Token * _literal;
expr_ty y;
void *z;
@@ -31276,7 +32473,7 @@ _tmp_112_rule(Parser *p)
(z = star_named_expressions_rule(p), !p->error_indicator) // star_named_expressions?
)
{
- D(fprintf(stderr, "%*c+ _tmp_112[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?"));
+ D(fprintf(stderr, "%*c+ _tmp_116[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_named_expression ',' star_named_expressions?"));
_res = _PyPegen_seq_insert_in_front ( p , y , z );
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -31286,7 +32483,7 @@ _tmp_112_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_112[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_116[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expression ',' star_named_expressions?"));
}
_res = NULL;
@@ -31295,9 +32492,9 @@ _tmp_112_rule(Parser *p)
return _res;
}
-// _loop0_114: ',' double_starred_kvpair
+// _loop0_118: ',' double_starred_kvpair
static asdl_seq *
-_loop0_114_rule(Parser *p)
+_loop0_118_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31323,7 +32520,7 @@ _loop0_114_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_114[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair"));
+ D(fprintf(stderr, "%*c> _loop0_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair"));
Token * _literal;
KeyValuePair* elem;
while (
@@ -31355,7 +32552,7 @@ _loop0_114_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_114[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_118[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31372,9 +32569,9 @@ _loop0_114_rule(Parser *p)
return _seq;
}
-// _gather_113: double_starred_kvpair _loop0_114
+// _gather_117: double_starred_kvpair _loop0_118
static asdl_seq *
-_gather_113_rule(Parser *p)
+_gather_117_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31386,27 +32583,27 @@ _gather_113_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // double_starred_kvpair _loop0_114
+ { // double_starred_kvpair _loop0_118
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_113[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_114"));
+ D(fprintf(stderr, "%*c> _gather_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_118"));
KeyValuePair* elem;
asdl_seq * seq;
if (
(elem = double_starred_kvpair_rule(p)) // double_starred_kvpair
&&
- (seq = _loop0_114_rule(p)) // _loop0_114
+ (seq = _loop0_118_rule(p)) // _loop0_118
)
{
- D(fprintf(stderr, "%*c+ _gather_113[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_114"));
+ D(fprintf(stderr, "%*c+ _gather_117[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_118"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_113[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_114"));
+ D(fprintf(stderr, "%*c%s _gather_117[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_118"));
}
_res = NULL;
done:
@@ -31414,9 +32611,9 @@ _gather_113_rule(Parser *p)
return _res;
}
-// _loop1_115: for_if_clause
+// _loop1_119: for_if_clause
static asdl_seq *
-_loop1_115_rule(Parser *p)
+_loop1_119_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31442,7 +32639,7 @@ _loop1_115_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_115[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause"));
+ D(fprintf(stderr, "%*c> _loop1_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "for_if_clause"));
comprehension_ty for_if_clause_var;
while (
(for_if_clause_var = for_if_clause_rule(p)) // for_if_clause
@@ -31465,7 +32662,7 @@ _loop1_115_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_115[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_119[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "for_if_clause"));
}
if (_n == 0 || p->error_indicator) {
@@ -31487,9 +32684,9 @@ _loop1_115_rule(Parser *p)
return _seq;
}
-// _loop0_116: ('if' disjunction)
+// _loop0_120: ('if' disjunction)
static asdl_seq *
-_loop0_116_rule(Parser *p)
+_loop0_120_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31515,13 +32712,13 @@ _loop0_116_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_116[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
- void *_tmp_235_var;
+ D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
+ void *_tmp_256_var;
while (
- (_tmp_235_var = _tmp_235_rule(p)) // 'if' disjunction
+ (_tmp_256_var = _tmp_256_rule(p)) // 'if' disjunction
)
{
- _res = _tmp_235_var;
+ _res = _tmp_256_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -31538,7 +32735,7 @@ _loop0_116_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_116[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_120[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31555,9 +32752,9 @@ _loop0_116_rule(Parser *p)
return _seq;
}
-// _loop0_117: ('if' disjunction)
+// _loop0_121: ('if' disjunction)
static asdl_seq *
-_loop0_117_rule(Parser *p)
+_loop0_121_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31583,13 +32780,13 @@ _loop0_117_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_117[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
- void *_tmp_236_var;
+ D(fprintf(stderr, "%*c> _loop0_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "('if' disjunction)"));
+ void *_tmp_257_var;
while (
- (_tmp_236_var = _tmp_236_rule(p)) // 'if' disjunction
+ (_tmp_257_var = _tmp_257_rule(p)) // 'if' disjunction
)
{
- _res = _tmp_236_var;
+ _res = _tmp_257_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -31606,7 +32803,7 @@ _loop0_117_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_117[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_121[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "('if' disjunction)"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31623,9 +32820,9 @@ _loop0_117_rule(Parser *p)
return _seq;
}
-// _tmp_118: assignment_expression | expression !':='
+// _tmp_122: assignment_expression | expression !':='
static void *
-_tmp_118_rule(Parser *p)
+_tmp_122_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31642,18 +32839,18 @@ _tmp_118_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
+ D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
expr_ty assignment_expression_var;
if (
(assignment_expression_var = assignment_expression_rule(p)) // assignment_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
_res = assignment_expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression"));
}
{ // expression !':='
@@ -31661,7 +32858,7 @@ _tmp_118_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_118[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='"));
+ D(fprintf(stderr, "%*c> _tmp_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='"));
expr_ty expression_var;
if (
(expression_var = expression_rule(p)) // expression
@@ -31669,12 +32866,12 @@ _tmp_118_rule(Parser *p)
_PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':='
)
{
- D(fprintf(stderr, "%*c+ _tmp_118[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='"));
+ D(fprintf(stderr, "%*c+ _tmp_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='"));
_res = expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_118[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_122[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='"));
}
_res = NULL;
@@ -31683,9 +32880,9 @@ _tmp_118_rule(Parser *p)
return _res;
}
-// _loop0_120: ',' (starred_expression | (assignment_expression | expression !':=') !'=')
+// _loop0_124: ',' (starred_expression | (assignment_expression | expression !':=') !'=')
static asdl_seq *
-_loop0_120_rule(Parser *p)
+_loop0_124_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31711,13 +32908,13 @@ _loop0_120_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_120[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')"));
+ D(fprintf(stderr, "%*c> _loop0_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_237_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'='
+ (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'='
)
{
_res = elem;
@@ -31743,7 +32940,7 @@ _loop0_120_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_120[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_124[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (starred_expression | (assignment_expression | expression !':=') !'=')"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31760,10 +32957,10 @@ _loop0_120_rule(Parser *p)
return _seq;
}
-// _gather_119:
-// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_120
+// _gather_123:
+// | (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124
static asdl_seq *
-_gather_119_rule(Parser *p)
+_gather_123_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31775,27 +32972,27 @@ _gather_119_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_120
+ { // (starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_119[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_120"));
+ D(fprintf(stderr, "%*c> _gather_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_237_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'='
+ (elem = _tmp_258_rule(p)) // starred_expression | (assignment_expression | expression !':=') !'='
&&
- (seq = _loop0_120_rule(p)) // _loop0_120
+ (seq = _loop0_124_rule(p)) // _loop0_124
)
{
- D(fprintf(stderr, "%*c+ _gather_119[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_120"));
+ D(fprintf(stderr, "%*c+ _gather_123[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_119[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_120"));
+ D(fprintf(stderr, "%*c%s _gather_123[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(starred_expression | (assignment_expression | expression !':=') !'=') _loop0_124"));
}
_res = NULL;
done:
@@ -31803,9 +33000,9 @@ _gather_119_rule(Parser *p)
return _res;
}
-// _tmp_121: ',' kwargs
+// _tmp_125: ',' kwargs
static void *
-_tmp_121_rule(Parser *p)
+_tmp_125_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31822,7 +33019,7 @@ _tmp_121_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_121[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs"));
+ D(fprintf(stderr, "%*c> _tmp_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwargs"));
Token * _literal;
asdl_seq* k;
if (
@@ -31831,7 +33028,7 @@ _tmp_121_rule(Parser *p)
(k = kwargs_rule(p)) // kwargs
)
{
- D(fprintf(stderr, "%*c+ _tmp_121[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs"));
+ D(fprintf(stderr, "%*c+ _tmp_125[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' kwargs"));
_res = k;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -31841,7 +33038,7 @@ _tmp_121_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_121[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_125[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwargs"));
}
_res = NULL;
@@ -31850,9 +33047,9 @@ _tmp_121_rule(Parser *p)
return _res;
}
-// _loop0_123: ',' kwarg_or_starred
+// _loop0_127: ',' kwarg_or_starred
static asdl_seq *
-_loop0_123_rule(Parser *p)
+_loop0_127_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31878,7 +33075,7 @@ _loop0_123_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_123[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred"));
+ D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred"));
Token * _literal;
KeywordOrStarred* elem;
while (
@@ -31910,7 +33107,7 @@ _loop0_123_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_123[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -31927,9 +33124,9 @@ _loop0_123_rule(Parser *p)
return _seq;
}
-// _gather_122: kwarg_or_starred _loop0_123
+// _gather_126: kwarg_or_starred _loop0_127
static asdl_seq *
-_gather_122_rule(Parser *p)
+_gather_126_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31941,27 +33138,27 @@ _gather_122_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // kwarg_or_starred _loop0_123
+ { // kwarg_or_starred _loop0_127
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_122[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_123"));
+ D(fprintf(stderr, "%*c> _gather_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127"));
KeywordOrStarred* elem;
asdl_seq * seq;
if (
(elem = kwarg_or_starred_rule(p)) // kwarg_or_starred
&&
- (seq = _loop0_123_rule(p)) // _loop0_123
+ (seq = _loop0_127_rule(p)) // _loop0_127
)
{
- D(fprintf(stderr, "%*c+ _gather_122[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_123"));
+ D(fprintf(stderr, "%*c+ _gather_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_122[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_123"));
+ D(fprintf(stderr, "%*c%s _gather_126[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_127"));
}
_res = NULL;
done:
@@ -31969,9 +33166,9 @@ _gather_122_rule(Parser *p)
return _res;
}
-// _loop0_125: ',' kwarg_or_double_starred
+// _loop0_129: ',' kwarg_or_double_starred
static asdl_seq *
-_loop0_125_rule(Parser *p)
+_loop0_129_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -31997,7 +33194,7 @@ _loop0_125_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_125[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred"));
+ D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred"));
Token * _literal;
KeywordOrStarred* elem;
while (
@@ -32029,7 +33226,7 @@ _loop0_125_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_125[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32046,9 +33243,9 @@ _loop0_125_rule(Parser *p)
return _seq;
}
-// _gather_124: kwarg_or_double_starred _loop0_125
+// _gather_128: kwarg_or_double_starred _loop0_129
static asdl_seq *
-_gather_124_rule(Parser *p)
+_gather_128_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32060,27 +33257,27 @@ _gather_124_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // kwarg_or_double_starred _loop0_125
+ { // kwarg_or_double_starred _loop0_129
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_124[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_125"));
+ D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
KeywordOrStarred* elem;
asdl_seq * seq;
if (
(elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred
&&
- (seq = _loop0_125_rule(p)) // _loop0_125
+ (seq = _loop0_129_rule(p)) // _loop0_129
)
{
- D(fprintf(stderr, "%*c+ _gather_124[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_125"));
+ D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_124[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_125"));
+ D(fprintf(stderr, "%*c%s _gather_128[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
}
_res = NULL;
done:
@@ -32088,9 +33285,9 @@ _gather_124_rule(Parser *p)
return _res;
}
-// _loop0_127: ',' kwarg_or_starred
+// _loop0_131: ',' kwarg_or_starred
static asdl_seq *
-_loop0_127_rule(Parser *p)
+_loop0_131_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32116,7 +33313,7 @@ _loop0_127_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_127[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred"));
+ D(fprintf(stderr, "%*c> _loop0_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_starred"));
Token * _literal;
KeywordOrStarred* elem;
while (
@@ -32148,7 +33345,7 @@ _loop0_127_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_127[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_131[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_starred"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32165,9 +33362,9 @@ _loop0_127_rule(Parser *p)
return _seq;
}
-// _gather_126: kwarg_or_starred _loop0_127
+// _gather_130: kwarg_or_starred _loop0_131
static asdl_seq *
-_gather_126_rule(Parser *p)
+_gather_130_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32179,27 +33376,27 @@ _gather_126_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // kwarg_or_starred _loop0_127
+ { // kwarg_or_starred _loop0_131
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_126[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127"));
+ D(fprintf(stderr, "%*c> _gather_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_131"));
KeywordOrStarred* elem;
asdl_seq * seq;
if (
(elem = kwarg_or_starred_rule(p)) // kwarg_or_starred
&&
- (seq = _loop0_127_rule(p)) // _loop0_127
+ (seq = _loop0_131_rule(p)) // _loop0_131
)
{
- D(fprintf(stderr, "%*c+ _gather_126[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_127"));
+ D(fprintf(stderr, "%*c+ _gather_130[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_starred _loop0_131"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_126[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_127"));
+ D(fprintf(stderr, "%*c%s _gather_130[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_starred _loop0_131"));
}
_res = NULL;
done:
@@ -32207,9 +33404,9 @@ _gather_126_rule(Parser *p)
return _res;
}
-// _loop0_129: ',' kwarg_or_double_starred
+// _loop0_133: ',' kwarg_or_double_starred
static asdl_seq *
-_loop0_129_rule(Parser *p)
+_loop0_133_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32235,7 +33432,7 @@ _loop0_129_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_129[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred"));
+ D(fprintf(stderr, "%*c> _loop0_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' kwarg_or_double_starred"));
Token * _literal;
KeywordOrStarred* elem;
while (
@@ -32267,7 +33464,7 @@ _loop0_129_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_129[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_133[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' kwarg_or_double_starred"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32284,9 +33481,9 @@ _loop0_129_rule(Parser *p)
return _seq;
}
-// _gather_128: kwarg_or_double_starred _loop0_129
+// _gather_132: kwarg_or_double_starred _loop0_133
static asdl_seq *
-_gather_128_rule(Parser *p)
+_gather_132_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32298,27 +33495,27 @@ _gather_128_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // kwarg_or_double_starred _loop0_129
+ { // kwarg_or_double_starred _loop0_133
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_128[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
+ D(fprintf(stderr, "%*c> _gather_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_133"));
KeywordOrStarred* elem;
asdl_seq * seq;
if (
(elem = kwarg_or_double_starred_rule(p)) // kwarg_or_double_starred
&&
- (seq = _loop0_129_rule(p)) // _loop0_129
+ (seq = _loop0_133_rule(p)) // _loop0_133
)
{
- D(fprintf(stderr, "%*c+ _gather_128[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
+ D(fprintf(stderr, "%*c+ _gather_132[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "kwarg_or_double_starred _loop0_133"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_128[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_129"));
+ D(fprintf(stderr, "%*c%s _gather_132[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "kwarg_or_double_starred _loop0_133"));
}
_res = NULL;
done:
@@ -32326,9 +33523,9 @@ _gather_128_rule(Parser *p)
return _res;
}
-// _loop0_130: (',' star_target)
+// _loop0_134: (',' star_target)
static asdl_seq *
-_loop0_130_rule(Parser *p)
+_loop0_134_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32354,13 +33551,13 @@ _loop0_130_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_130[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
- void *_tmp_238_var;
+ D(fprintf(stderr, "%*c> _loop0_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
+ void *_tmp_259_var;
while (
- (_tmp_238_var = _tmp_238_rule(p)) // ',' star_target
+ (_tmp_259_var = _tmp_259_rule(p)) // ',' star_target
)
{
- _res = _tmp_238_var;
+ _res = _tmp_259_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -32377,7 +33574,7 @@ _loop0_130_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_130[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_134[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32394,9 +33591,9 @@ _loop0_130_rule(Parser *p)
return _seq;
}
-// _loop0_132: ',' star_target
+// _loop0_136: ',' star_target
static asdl_seq *
-_loop0_132_rule(Parser *p)
+_loop0_136_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32422,7 +33619,7 @@ _loop0_132_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_132[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+ D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
Token * _literal;
expr_ty elem;
while (
@@ -32454,7 +33651,7 @@ _loop0_132_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_132[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_136[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32471,9 +33668,9 @@ _loop0_132_rule(Parser *p)
return _seq;
}
-// _gather_131: star_target _loop0_132
+// _gather_135: star_target _loop0_136
static asdl_seq *
-_gather_131_rule(Parser *p)
+_gather_135_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32485,27 +33682,27 @@ _gather_131_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // star_target _loop0_132
+ { // star_target _loop0_136
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_131[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_132"));
+ D(fprintf(stderr, "%*c> _gather_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_target _loop0_136"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = star_target_rule(p)) // star_target
&&
- (seq = _loop0_132_rule(p)) // _loop0_132
+ (seq = _loop0_136_rule(p)) // _loop0_136
)
{
- D(fprintf(stderr, "%*c+ _gather_131[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_132"));
+ D(fprintf(stderr, "%*c+ _gather_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_target _loop0_136"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_131[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_132"));
+ D(fprintf(stderr, "%*c%s _gather_135[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_target _loop0_136"));
}
_res = NULL;
done:
@@ -32513,9 +33710,9 @@ _gather_131_rule(Parser *p)
return _res;
}
-// _loop1_133: (',' star_target)
+// _loop1_137: (',' star_target)
static asdl_seq *
-_loop1_133_rule(Parser *p)
+_loop1_137_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32541,13 +33738,13 @@ _loop1_133_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_133[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
- void *_tmp_239_var;
+ D(fprintf(stderr, "%*c> _loop1_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(',' star_target)"));
+ void *_tmp_260_var;
while (
- (_tmp_239_var = _tmp_239_rule(p)) // ',' star_target
+ (_tmp_260_var = _tmp_260_rule(p)) // ',' star_target
)
{
- _res = _tmp_239_var;
+ _res = _tmp_260_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -32564,7 +33761,7 @@ _loop1_133_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_133[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_137[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(',' star_target)"));
}
if (_n == 0 || p->error_indicator) {
@@ -32586,9 +33783,9 @@ _loop1_133_rule(Parser *p)
return _seq;
}
-// _tmp_134: !'*' star_target
+// _tmp_138: !'*' star_target
static void *
-_tmp_134_rule(Parser *p)
+_tmp_138_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32605,7 +33802,7 @@ _tmp_134_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_134[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
expr_ty star_target_var;
if (
_PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 16) // token='*'
@@ -32613,12 +33810,12 @@ _tmp_134_rule(Parser *p)
(star_target_var = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_134[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_138[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "!'*' star_target"));
_res = star_target_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_134[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_138[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "!'*' star_target"));
}
_res = NULL;
@@ -32627,9 +33824,9 @@ _tmp_134_rule(Parser *p)
return _res;
}
-// _loop0_136: ',' del_target
+// _loop0_140: ',' del_target
static asdl_seq *
-_loop0_136_rule(Parser *p)
+_loop0_140_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32655,7 +33852,7 @@ _loop0_136_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_136[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target"));
+ D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' del_target"));
Token * _literal;
expr_ty elem;
while (
@@ -32687,7 +33884,7 @@ _loop0_136_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_136[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' del_target"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32704,9 +33901,9 @@ _loop0_136_rule(Parser *p)
return _seq;
}
-// _gather_135: del_target _loop0_136
+// _gather_139: del_target _loop0_140
static asdl_seq *
-_gather_135_rule(Parser *p)
+_gather_139_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32718,27 +33915,27 @@ _gather_135_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // del_target _loop0_136
+ { // del_target _loop0_140
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_135[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_136"));
+ D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "del_target _loop0_140"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = del_target_rule(p)) // del_target
&&
- (seq = _loop0_136_rule(p)) // _loop0_136
+ (seq = _loop0_140_rule(p)) // _loop0_140
)
{
- D(fprintf(stderr, "%*c+ _gather_135[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_136"));
+ D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "del_target _loop0_140"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_135[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_136"));
+ D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "del_target _loop0_140"));
}
_res = NULL;
done:
@@ -32746,9 +33943,9 @@ _gather_135_rule(Parser *p)
return _res;
}
-// _loop0_138: ',' expression
+// _loop0_142: ',' expression
static asdl_seq *
-_loop0_138_rule(Parser *p)
+_loop0_142_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32774,7 +33971,7 @@ _loop0_138_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_138[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty elem;
while (
@@ -32806,7 +34003,7 @@ _loop0_138_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_138[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32823,9 +34020,9 @@ _loop0_138_rule(Parser *p)
return _seq;
}
-// _gather_137: expression _loop0_138
+// _gather_141: expression _loop0_142
static asdl_seq *
-_gather_137_rule(Parser *p)
+_gather_141_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32837,27 +34034,27 @@ _gather_137_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // expression _loop0_138
+ { // expression _loop0_142
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_137[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_138"));
+ D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_142"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = expression_rule(p)) // expression
&&
- (seq = _loop0_138_rule(p)) // _loop0_138
+ (seq = _loop0_142_rule(p)) // _loop0_142
)
{
- D(fprintf(stderr, "%*c+ _gather_137[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_138"));
+ D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_137[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_138"));
+ D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142"));
}
_res = NULL;
done:
@@ -32865,9 +34062,9 @@ _gather_137_rule(Parser *p)
return _res;
}
-// _loop0_140: ',' expression
+// _loop0_144: ',' expression
static asdl_seq *
-_loop0_140_rule(Parser *p)
+_loop0_144_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32893,7 +34090,7 @@ _loop0_140_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_140[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _loop0_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty elem;
while (
@@ -32925,7 +34122,7 @@ _loop0_140_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_140[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_144[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -32942,9 +34139,9 @@ _loop0_140_rule(Parser *p)
return _seq;
}
-// _gather_139: expression _loop0_140
+// _gather_143: expression _loop0_144
static asdl_seq *
-_gather_139_rule(Parser *p)
+_gather_143_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -32956,27 +34153,27 @@ _gather_139_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // expression _loop0_140
+ { // expression _loop0_144
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_139[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_140"));
+ D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_144"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = expression_rule(p)) // expression
&&
- (seq = _loop0_140_rule(p)) // _loop0_140
+ (seq = _loop0_144_rule(p)) // _loop0_144
)
{
- D(fprintf(stderr, "%*c+ _gather_139[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_140"));
+ D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_144"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_139[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_140"));
+ D(fprintf(stderr, "%*c%s _gather_143[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_144"));
}
_res = NULL;
done:
@@ -32984,9 +34181,9 @@ _gather_139_rule(Parser *p)
return _res;
}
-// _loop0_142: ',' expression
+// _loop0_146: ',' expression
static asdl_seq *
-_loop0_142_rule(Parser *p)
+_loop0_146_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33012,7 +34209,7 @@ _loop0_142_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_142[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _loop0_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty elem;
while (
@@ -33044,7 +34241,7 @@ _loop0_142_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_142[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_146[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -33061,9 +34258,9 @@ _loop0_142_rule(Parser *p)
return _seq;
}
-// _gather_141: expression _loop0_142
+// _gather_145: expression _loop0_146
static asdl_seq *
-_gather_141_rule(Parser *p)
+_gather_145_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33075,27 +34272,27 @@ _gather_141_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // expression _loop0_142
+ { // expression _loop0_146
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_141[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_142"));
+ D(fprintf(stderr, "%*c> _gather_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_146"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = expression_rule(p)) // expression
&&
- (seq = _loop0_142_rule(p)) // _loop0_142
+ (seq = _loop0_146_rule(p)) // _loop0_146
)
{
- D(fprintf(stderr, "%*c+ _gather_141[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_142"));
+ D(fprintf(stderr, "%*c+ _gather_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_146"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_141[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_142"));
+ D(fprintf(stderr, "%*c%s _gather_145[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_146"));
}
_res = NULL;
done:
@@ -33103,9 +34300,9 @@ _gather_141_rule(Parser *p)
return _res;
}
-// _loop0_144: ',' expression
+// _loop0_148: ',' expression
static asdl_seq *
-_loop0_144_rule(Parser *p)
+_loop0_148_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33131,7 +34328,7 @@ _loop0_144_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_144[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _loop0_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty elem;
while (
@@ -33163,7 +34360,7 @@ _loop0_144_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_144[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_148[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -33180,9 +34377,9 @@ _loop0_144_rule(Parser *p)
return _seq;
}
-// _gather_143: expression _loop0_144
+// _gather_147: expression _loop0_148
static asdl_seq *
-_gather_143_rule(Parser *p)
+_gather_147_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33194,27 +34391,27 @@ _gather_143_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // expression _loop0_144
+ { // expression _loop0_148
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_143[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_144"));
+ D(fprintf(stderr, "%*c> _gather_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression _loop0_148"));
expr_ty elem;
asdl_seq * seq;
if (
(elem = expression_rule(p)) // expression
&&
- (seq = _loop0_144_rule(p)) // _loop0_144
+ (seq = _loop0_148_rule(p)) // _loop0_148
)
{
- D(fprintf(stderr, "%*c+ _gather_143[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_144"));
+ D(fprintf(stderr, "%*c+ _gather_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression _loop0_148"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_143[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_144"));
+ D(fprintf(stderr, "%*c%s _gather_147[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression _loop0_148"));
}
_res = NULL;
done:
@@ -33222,9 +34419,9 @@ _gather_143_rule(Parser *p)
return _res;
}
-// _tmp_145: NEWLINE INDENT
+// _tmp_149: NEWLINE INDENT
static void *
-_tmp_145_rule(Parser *p)
+_tmp_149_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33241,7 +34438,7 @@ _tmp_145_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_145[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT"));
+ D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT"));
Token * indent_var;
Token * newline_var;
if (
@@ -33250,12 +34447,12 @@ _tmp_145_rule(Parser *p)
(indent_var = _PyPegen_expect_token(p, INDENT)) // token='INDENT'
)
{
- D(fprintf(stderr, "%*c+ _tmp_145[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT"));
+ D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE INDENT"));
_res = _PyPegen_dummy_name(p, newline_var, indent_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_145[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE INDENT"));
}
_res = NULL;
@@ -33264,9 +34461,9 @@ _tmp_145_rule(Parser *p)
return _res;
}
-// _tmp_146: args | expression for_if_clauses
+// _tmp_150: args | expression for_if_clauses
static void *
-_tmp_146_rule(Parser *p)
+_tmp_150_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33283,18 +34480,18 @@ _tmp_146_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args"));
+ D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args"));
expr_ty args_var;
if (
(args_var = args_rule(p)) // args
)
{
- D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args"));
+ D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args"));
_res = args_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args"));
}
{ // expression for_if_clauses
@@ -33302,7 +34499,7 @@ _tmp_146_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_146[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
+ D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
expr_ty expression_var;
asdl_comprehension_seq* for_if_clauses_var;
if (
@@ -33311,12 +34508,12 @@ _tmp_146_rule(Parser *p)
(for_if_clauses_var = for_if_clauses_rule(p)) // for_if_clauses
)
{
- D(fprintf(stderr, "%*c+ _tmp_146[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
+ D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression for_if_clauses"));
_res = _PyPegen_dummy_name(p, expression_var, for_if_clauses_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_146[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression for_if_clauses"));
}
_res = NULL;
@@ -33325,9 +34522,9 @@ _tmp_146_rule(Parser *p)
return _res;
}
-// _tmp_147: args ','
+// _tmp_151: args ','
static void *
-_tmp_147_rule(Parser *p)
+_tmp_151_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33344,7 +34541,7 @@ _tmp_147_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_147[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','"));
+ D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "args ','"));
Token * _literal;
expr_ty args_var;
if (
@@ -33353,12 +34550,12 @@ _tmp_147_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_147[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','"));
+ D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "args ','"));
_res = _PyPegen_dummy_name(p, args_var, _literal);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_147[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "args ','"));
}
_res = NULL;
@@ -33367,9 +34564,9 @@ _tmp_147_rule(Parser *p)
return _res;
}
-// _tmp_148: ',' | ')'
+// _tmp_152: ',' | ')'
static void *
-_tmp_148_rule(Parser *p)
+_tmp_152_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33386,18 +34583,18 @@ _tmp_148_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
{ // ')'
@@ -33405,18 +34602,18 @@ _tmp_148_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_148[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_148[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_148[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
_res = NULL;
@@ -33425,9 +34622,9 @@ _tmp_148_rule(Parser *p)
return _res;
}
-// _tmp_149: 'True' | 'False' | 'None'
+// _tmp_153: 'True' | 'False' | 'None'
static void *
-_tmp_149_rule(Parser *p)
+_tmp_153_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33444,18 +34641,18 @@ _tmp_149_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
+ D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 600)) // token='True'
+ (_keyword = _PyPegen_expect_token(p, 601)) // token='True'
)
{
- D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
+ D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'"));
}
{ // 'False'
@@ -33463,18 +34660,18 @@ _tmp_149_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
+ D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 602)) // token='False'
+ (_keyword = _PyPegen_expect_token(p, 603)) // token='False'
)
{
- D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
+ D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'"));
}
{ // 'None'
@@ -33482,18 +34679,18 @@ _tmp_149_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_149[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
+ D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 601)) // token='None'
+ (_keyword = _PyPegen_expect_token(p, 602)) // token='None'
)
{
- D(fprintf(stderr, "%*c+ _tmp_149[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
+ D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_149[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'"));
}
_res = NULL;
@@ -33502,9 +34699,9 @@ _tmp_149_rule(Parser *p)
return _res;
}
-// _tmp_150: NAME '='
+// _tmp_154: NAME '='
static void *
-_tmp_150_rule(Parser *p)
+_tmp_154_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33521,7 +34718,7 @@ _tmp_150_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_150[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='"));
+ D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME '='"));
Token * _literal;
expr_ty name_var;
if (
@@ -33530,12 +34727,12 @@ _tmp_150_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_150[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='"));
+ D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME '='"));
_res = _PyPegen_dummy_name(p, name_var, _literal);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_150[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME '='"));
}
_res = NULL;
@@ -33544,9 +34741,9 @@ _tmp_150_rule(Parser *p)
return _res;
}
-// _tmp_151: NAME STRING | SOFT_KEYWORD
+// _tmp_155: NAME STRING | SOFT_KEYWORD
static void *
-_tmp_151_rule(Parser *p)
+_tmp_155_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33563,7 +34760,7 @@ _tmp_151_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING"));
+ D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NAME STRING"));
expr_ty name_var;
expr_ty string_var;
if (
@@ -33572,12 +34769,12 @@ _tmp_151_rule(Parser *p)
(string_var = _PyPegen_string_token(p)) // STRING
)
{
- D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING"));
+ D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NAME STRING"));
_res = _PyPegen_dummy_name(p, name_var, string_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NAME STRING"));
}
{ // SOFT_KEYWORD
@@ -33585,18 +34782,18 @@ _tmp_151_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_151[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD"));
+ D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD"));
expr_ty soft_keyword_var;
if (
(soft_keyword_var = _PyPegen_soft_keyword_token(p)) // SOFT_KEYWORD
)
{
- D(fprintf(stderr, "%*c+ _tmp_151[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD"));
+ D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "SOFT_KEYWORD"));
_res = soft_keyword_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_151[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "SOFT_KEYWORD"));
}
_res = NULL;
@@ -33605,9 +34802,9 @@ _tmp_151_rule(Parser *p)
return _res;
}
-// _tmp_152: 'else' | ':'
+// _tmp_156: 'else' | ':'
static void *
-_tmp_152_rule(Parser *p)
+_tmp_156_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33624,18 +34821,18 @@ _tmp_152_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'"));
+ D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'else'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 644)) // token='else'
+ (_keyword = _PyPegen_expect_token(p, 645)) // token='else'
)
{
- D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'"));
+ D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'else'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'else'"));
}
{ // ':'
@@ -33643,18 +34840,18 @@ _tmp_152_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_152[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_152[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_156[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_152[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_156[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
_res = NULL;
@@ -33663,9 +34860,67 @@ _tmp_152_rule(Parser *p)
return _res;
}
-// _tmp_153: '=' | ':='
+// _tmp_157: FSTRING_MIDDLE | fstring_replacement_field
static void *
-_tmp_153_rule(Parser *p)
+_tmp_157_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // FSTRING_MIDDLE
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ Token * fstring_middle_var;
+ if (
+ (fstring_middle_var = _PyPegen_expect_token(p, FSTRING_MIDDLE)) // token='FSTRING_MIDDLE'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "FSTRING_MIDDLE"));
+ _res = fstring_middle_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "FSTRING_MIDDLE"));
+ }
+ { // fstring_replacement_field
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ expr_ty fstring_replacement_field_var;
+ if (
+ (fstring_replacement_field_var = fstring_replacement_field_rule(p)) // fstring_replacement_field
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_157[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring_replacement_field"));
+ _res = fstring_replacement_field_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_157[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_replacement_field"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_158: '=' | ':='
+static void *
+_tmp_158_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33682,18 +34937,18 @@ _tmp_153_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='"));
}
{ // ':='
@@ -33701,18 +34956,18 @@ _tmp_153_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_153[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='"));
+ D(fprintf(stderr, "%*c> _tmp_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 53)) // token=':='
)
{
- D(fprintf(stderr, "%*c+ _tmp_153[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='"));
+ D(fprintf(stderr, "%*c+ _tmp_158[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_153[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_158[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='"));
}
_res = NULL;
@@ -33721,9 +34976,9 @@ _tmp_153_rule(Parser *p)
return _res;
}
-// _tmp_154: list | tuple | genexp | 'True' | 'None' | 'False'
+// _tmp_159: list | tuple | genexp | 'True' | 'None' | 'False'
static void *
-_tmp_154_rule(Parser *p)
+_tmp_159_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33740,18 +34995,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "list"));
expr_ty list_var;
if (
(list_var = list_rule(p)) // list
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "list"));
_res = list_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "list"));
}
{ // tuple
@@ -33759,18 +35014,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "tuple"));
expr_ty tuple_var;
if (
(tuple_var = tuple_rule(p)) // tuple
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "tuple"));
_res = tuple_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "tuple"));
}
{ // genexp
@@ -33778,18 +35033,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "genexp"));
expr_ty genexp_var;
if (
(genexp_var = genexp_rule(p)) // genexp
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "genexp"));
_res = genexp_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "genexp"));
}
{ // 'True'
@@ -33797,18 +35052,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'True'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 600)) // token='True'
+ (_keyword = _PyPegen_expect_token(p, 601)) // token='True'
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'True'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'True'"));
}
{ // 'None'
@@ -33816,18 +35071,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'None'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 601)) // token='None'
+ (_keyword = _PyPegen_expect_token(p, 602)) // token='None'
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'None'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'None'"));
}
{ // 'False'
@@ -33835,18 +35090,18 @@ _tmp_154_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_154[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
+ D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'False'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 602)) // token='False'
+ (_keyword = _PyPegen_expect_token(p, 603)) // token='False'
)
{
- D(fprintf(stderr, "%*c+ _tmp_154[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
+ D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'False'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_154[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'False'"));
}
_res = NULL;
@@ -33855,9 +35110,9 @@ _tmp_154_rule(Parser *p)
return _res;
}
-// _tmp_155: '=' | ':='
+// _tmp_160: '=' | ':='
static void *
-_tmp_155_rule(Parser *p)
+_tmp_160_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33874,18 +35129,18 @@ _tmp_155_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
+ D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='"));
}
{ // ':='
@@ -33893,18 +35148,18 @@ _tmp_155_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_155[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='"));
+ D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':='"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 53)) // token=':='
)
{
- D(fprintf(stderr, "%*c+ _tmp_155[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='"));
+ D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':='"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_155[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':='"));
}
_res = NULL;
@@ -33913,9 +35168,9 @@ _tmp_155_rule(Parser *p)
return _res;
}
-// _loop0_156: star_named_expressions
+// _loop0_161: star_named_expressions
static asdl_seq *
-_loop0_156_rule(Parser *p)
+_loop0_161_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -33941,7 +35196,7 @@ _loop0_156_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_156[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions"));
+ D(fprintf(stderr, "%*c> _loop0_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_named_expressions"));
asdl_expr_seq* star_named_expressions_var;
while (
(star_named_expressions_var = star_named_expressions_rule(p)) // star_named_expressions
@@ -33964,7 +35219,7 @@ _loop0_156_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_156[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_161[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_named_expressions"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -33981,9 +35236,9 @@ _loop0_156_rule(Parser *p)
return _seq;
}
-// _loop0_157: (star_targets '=')
+// _loop0_162: (star_targets '=')
static asdl_seq *
-_loop0_157_rule(Parser *p)
+_loop0_162_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34009,13 +35264,13 @@ _loop0_157_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_157[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
- void *_tmp_240_var;
+ D(fprintf(stderr, "%*c> _loop0_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
+ void *_tmp_261_var;
while (
- (_tmp_240_var = _tmp_240_rule(p)) // star_targets '='
+ (_tmp_261_var = _tmp_261_rule(p)) // star_targets '='
)
{
- _res = _tmp_240_var;
+ _res = _tmp_261_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -34032,7 +35287,7 @@ _loop0_157_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_157[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_162[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34049,9 +35304,9 @@ _loop0_157_rule(Parser *p)
return _seq;
}
-// _loop0_158: (star_targets '=')
+// _loop0_163: (star_targets '=')
static asdl_seq *
-_loop0_158_rule(Parser *p)
+_loop0_163_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34077,13 +35332,13 @@ _loop0_158_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_158[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
- void *_tmp_241_var;
+ D(fprintf(stderr, "%*c> _loop0_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(star_targets '=')"));
+ void *_tmp_262_var;
while (
- (_tmp_241_var = _tmp_241_rule(p)) // star_targets '='
+ (_tmp_262_var = _tmp_262_rule(p)) // star_targets '='
)
{
- _res = _tmp_241_var;
+ _res = _tmp_262_var;
if (_n == _children_capacity) {
_children_capacity *= 2;
void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
@@ -34100,7 +35355,7 @@ _loop0_158_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_158[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_163[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(star_targets '=')"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34117,9 +35372,9 @@ _loop0_158_rule(Parser *p)
return _seq;
}
-// _tmp_159: yield_expr | star_expressions
+// _tmp_164: yield_expr | star_expressions
static void *
-_tmp_159_rule(Parser *p)
+_tmp_164_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34136,18 +35391,18 @@ _tmp_159_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
expr_ty yield_expr_var;
if (
(yield_expr_var = yield_expr_rule(p)) // yield_expr
)
{
- D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
_res = yield_expr_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
}
{ // star_expressions
@@ -34155,18 +35410,18 @@ _tmp_159_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_159[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c> _tmp_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
expr_ty star_expressions_var;
if (
(star_expressions_var = star_expressions_rule(p)) // star_expressions
)
{
- D(fprintf(stderr, "%*c+ _tmp_159[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ D(fprintf(stderr, "%*c+ _tmp_164[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
_res = star_expressions_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_159[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_164[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
}
_res = NULL;
@@ -34175,9 +35430,9 @@ _tmp_159_rule(Parser *p)
return _res;
}
-// _tmp_160: '[' | '(' | '{'
+// _tmp_165: '[' | '(' | '{'
static void *
-_tmp_160_rule(Parser *p)
+_tmp_165_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34194,18 +35449,18 @@ _tmp_160_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 9)) // token='['
)
{
- D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['"));
}
{ // '('
@@ -34213,18 +35468,18 @@ _tmp_160_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
+ D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'('"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 7)) // token='('
)
{
- D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
+ D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'('"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'('"));
}
{ // '{'
@@ -34232,18 +35487,18 @@ _tmp_160_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_160[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c> _tmp_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 25)) // token='{'
)
{
- D(fprintf(stderr, "%*c+ _tmp_160[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c+ _tmp_165[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_160[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_165[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'"));
}
_res = NULL;
@@ -34252,9 +35507,9 @@ _tmp_160_rule(Parser *p)
return _res;
}
-// _tmp_161: '[' | '{'
+// _tmp_166: '[' | '{'
static void *
-_tmp_161_rule(Parser *p)
+_tmp_166_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34271,18 +35526,18 @@ _tmp_161_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 9)) // token='['
)
{
- D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['"));
}
{ // '{'
@@ -34290,18 +35545,18 @@ _tmp_161_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_161[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c> _tmp_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 25)) // token='{'
)
{
- D(fprintf(stderr, "%*c+ _tmp_161[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c+ _tmp_166[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_161[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_166[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'"));
}
_res = NULL;
@@ -34310,9 +35565,9 @@ _tmp_161_rule(Parser *p)
return _res;
}
-// _tmp_162: '[' | '{'
+// _tmp_167: '[' | '{'
static void *
-_tmp_162_rule(Parser *p)
+_tmp_167_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34329,18 +35584,18 @@ _tmp_162_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'['"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 9)) // token='['
)
{
- D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
+ D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'['"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'['"));
}
{ // '{'
@@ -34348,18 +35603,18 @@ _tmp_162_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_162[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c> _tmp_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'{'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 25)) // token='{'
)
{
- D(fprintf(stderr, "%*c+ _tmp_162[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
+ D(fprintf(stderr, "%*c+ _tmp_167[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'{'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_162[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_167[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'{'"));
}
_res = NULL;
@@ -34368,9 +35623,9 @@ _tmp_162_rule(Parser *p)
return _res;
}
-// _tmp_163: slash_no_default | slash_with_default
+// _tmp_168: slash_no_default | slash_with_default
static void *
-_tmp_163_rule(Parser *p)
+_tmp_168_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34387,18 +35642,18 @@ _tmp_163_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
asdl_arg_seq* slash_no_default_var;
if (
(slash_no_default_var = slash_no_default_rule(p)) // slash_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
_res = slash_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default"));
}
{ // slash_with_default
@@ -34406,18 +35661,18 @@ _tmp_163_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_163[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+ D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
SlashWithDefault* slash_with_default_var;
if (
(slash_with_default_var = slash_with_default_rule(p)) // slash_with_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_163[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+ D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
_res = slash_with_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_163[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default"));
}
_res = NULL;
@@ -34426,9 +35681,9 @@ _tmp_163_rule(Parser *p)
return _res;
}
-// _loop0_164: param_maybe_default
+// _loop0_169: param_maybe_default
static asdl_seq *
-_loop0_164_rule(Parser *p)
+_loop0_169_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34454,7 +35709,7 @@ _loop0_164_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_164[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -34477,7 +35732,7 @@ _loop0_164_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_164[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34494,9 +35749,9 @@ _loop0_164_rule(Parser *p)
return _seq;
}
-// _loop0_165: param_no_default
+// _loop0_170: param_no_default
static asdl_seq *
-_loop0_165_rule(Parser *p)
+_loop0_170_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34522,7 +35777,7 @@ _loop0_165_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_165[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -34545,7 +35800,7 @@ _loop0_165_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_165[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_170[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34562,9 +35817,9 @@ _loop0_165_rule(Parser *p)
return _seq;
}
-// _loop0_166: param_no_default
+// _loop0_171: param_no_default
static asdl_seq *
-_loop0_166_rule(Parser *p)
+_loop0_171_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34590,7 +35845,7 @@ _loop0_166_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_166[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -34613,7 +35868,7 @@ _loop0_166_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_166[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_171[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34630,9 +35885,9 @@ _loop0_166_rule(Parser *p)
return _seq;
}
-// _loop1_167: param_no_default
+// _loop1_172: param_no_default
static asdl_seq *
-_loop1_167_rule(Parser *p)
+_loop1_172_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34658,7 +35913,7 @@ _loop1_167_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_167[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _loop1_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
while (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
@@ -34681,7 +35936,7 @@ _loop1_167_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_167[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_172[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -34703,9 +35958,9 @@ _loop1_167_rule(Parser *p)
return _seq;
}
-// _tmp_168: slash_no_default | slash_with_default
+// _tmp_173: slash_no_default | slash_with_default
static void *
-_tmp_168_rule(Parser *p)
+_tmp_173_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34722,18 +35977,18 @@ _tmp_168_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
asdl_arg_seq* slash_no_default_var;
if (
(slash_no_default_var = slash_no_default_rule(p)) // slash_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_no_default"));
_res = slash_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_no_default"));
}
{ // slash_with_default
@@ -34741,18 +35996,18 @@ _tmp_168_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_168[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+ D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
SlashWithDefault* slash_with_default_var;
if (
(slash_with_default_var = slash_with_default_rule(p)) // slash_with_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_168[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
+ D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slash_with_default"));
_res = slash_with_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_168[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slash_with_default"));
}
_res = NULL;
@@ -34761,9 +36016,9 @@ _tmp_168_rule(Parser *p)
return _res;
}
-// _loop0_169: param_maybe_default
+// _loop0_174: param_maybe_default
static asdl_seq *
-_loop0_169_rule(Parser *p)
+_loop0_174_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34789,7 +36044,7 @@ _loop0_169_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_169[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -34812,7 +36067,7 @@ _loop0_169_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_169[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_174[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34829,9 +36084,9 @@ _loop0_169_rule(Parser *p)
return _seq;
}
-// _tmp_170: ',' | param_no_default
+// _tmp_175: ',' | param_no_default
static void *
-_tmp_170_rule(Parser *p)
+_tmp_175_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34848,18 +36103,18 @@ _tmp_170_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
{ // param_no_default
@@ -34867,18 +36122,18 @@ _tmp_170_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_170[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
if (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_170[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
_res = param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_170[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
_res = NULL;
@@ -34887,9 +36142,9 @@ _tmp_170_rule(Parser *p)
return _res;
}
-// _loop0_171: param_maybe_default
+// _loop0_176: param_maybe_default
static asdl_seq *
-_loop0_171_rule(Parser *p)
+_loop0_176_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34915,7 +36170,7 @@ _loop0_171_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_171[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -34938,7 +36193,7 @@ _loop0_171_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_171[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_176[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -34955,9 +36210,9 @@ _loop0_171_rule(Parser *p)
return _seq;
}
-// _loop1_172: param_maybe_default
+// _loop1_177: param_maybe_default
static asdl_seq *
-_loop1_172_rule(Parser *p)
+_loop1_177_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -34983,7 +36238,7 @@ _loop1_172_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_172[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop1_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -35006,7 +36261,7 @@ _loop1_172_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_172[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_177[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -35028,9 +36283,9 @@ _loop1_172_rule(Parser *p)
return _seq;
}
-// _tmp_173: ')' | ','
+// _tmp_178: ')' | ','
static void *
-_tmp_173_rule(Parser *p)
+_tmp_178_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35047,18 +36302,18 @@ _tmp_173_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
{ // ','
@@ -35066,18 +36321,18 @@ _tmp_173_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_173[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_173[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_173[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -35086,9 +36341,9 @@ _tmp_173_rule(Parser *p)
return _res;
}
-// _tmp_174: ')' | ',' (')' | '**')
+// _tmp_179: ')' | ',' (')' | '**')
static void *
-_tmp_174_rule(Parser *p)
+_tmp_179_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35105,18 +36360,18 @@ _tmp_174_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
{ // ',' (')' | '**')
@@ -35124,21 +36379,21 @@ _tmp_174_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_174[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
+ D(fprintf(stderr, "%*c> _tmp_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
Token * _literal;
- void *_tmp_242_var;
+ void *_tmp_263_var;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (_tmp_242_var = _tmp_242_rule(p)) // ')' | '**'
+ (_tmp_263_var = _tmp_263_rule(p)) // ')' | '**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_174[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
- _res = _PyPegen_dummy_name(p, _literal, _tmp_242_var);
+ D(fprintf(stderr, "%*c+ _tmp_179[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (')' | '**')"));
+ _res = _PyPegen_dummy_name(p, _literal, _tmp_263_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_174[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_179[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (')' | '**')"));
}
_res = NULL;
@@ -35147,9 +36402,9 @@ _tmp_174_rule(Parser *p)
return _res;
}
-// _tmp_175: param_no_default | ','
+// _tmp_180: param_no_default | ','
static void *
-_tmp_175_rule(Parser *p)
+_tmp_180_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35166,18 +36421,18 @@ _tmp_175_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
if (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
_res = param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
{ // ','
@@ -35185,18 +36440,18 @@ _tmp_175_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_175[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_175[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_175[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -35205,9 +36460,9 @@ _tmp_175_rule(Parser *p)
return _res;
}
-// _loop0_176: param_maybe_default
+// _loop0_181: param_maybe_default
static asdl_seq *
-_loop0_176_rule(Parser *p)
+_loop0_181_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35233,7 +36488,7 @@ _loop0_176_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_176[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_maybe_default"));
NameDefaultPair* param_maybe_default_var;
while (
(param_maybe_default_var = param_maybe_default_rule(p)) // param_maybe_default
@@ -35256,7 +36511,7 @@ _loop0_176_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_176[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_181[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35273,9 +36528,9 @@ _loop0_176_rule(Parser *p)
return _seq;
}
-// _tmp_177: param_no_default | ','
+// _tmp_182: param_no_default | ','
static void *
-_tmp_177_rule(Parser *p)
+_tmp_182_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35292,18 +36547,18 @@ _tmp_177_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_no_default"));
arg_ty param_no_default_var;
if (
(param_no_default_var = param_no_default_rule(p)) // param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "param_no_default"));
_res = param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_no_default"));
}
{ // ','
@@ -35311,18 +36566,18 @@ _tmp_177_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_177[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_177[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_182[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_177[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_182[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -35331,9 +36586,9 @@ _tmp_177_rule(Parser *p)
return _res;
}
-// _tmp_178: '*' | '**' | '/'
+// _tmp_183: '*' | '**' | '/'
static void *
-_tmp_178_rule(Parser *p)
+_tmp_183_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35350,18 +36605,18 @@ _tmp_178_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'"));
+ D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
)
{
- D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'"));
+ D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'"));
}
{ // '**'
@@ -35369,18 +36624,18 @@ _tmp_178_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 35)) // token='**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
}
{ // '/'
@@ -35388,18 +36643,18 @@ _tmp_178_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_178[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'"));
+ D(fprintf(stderr, "%*c> _tmp_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
)
{
- D(fprintf(stderr, "%*c+ _tmp_178[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'"));
+ D(fprintf(stderr, "%*c+ _tmp_183[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_178[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_183[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'"));
}
_res = NULL;
@@ -35408,9 +36663,9 @@ _tmp_178_rule(Parser *p)
return _res;
}
-// _loop1_179: param_with_default
+// _loop1_184: param_with_default
static asdl_seq *
-_loop1_179_rule(Parser *p)
+_loop1_184_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35436,7 +36691,7 @@ _loop1_179_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_179[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "param_with_default"));
NameDefaultPair* param_with_default_var;
while (
(param_with_default_var = param_with_default_rule(p)) // param_with_default
@@ -35459,7 +36714,7 @@ _loop1_179_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_179[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_184[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -35481,9 +36736,9 @@ _loop1_179_rule(Parser *p)
return _seq;
}
-// _tmp_180: lambda_slash_no_default | lambda_slash_with_default
+// _tmp_185: lambda_slash_no_default | lambda_slash_with_default
static void *
-_tmp_180_rule(Parser *p)
+_tmp_185_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35500,18 +36755,18 @@ _tmp_180_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
asdl_arg_seq* lambda_slash_no_default_var;
if (
(lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
_res = lambda_slash_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default"));
}
{ // lambda_slash_with_default
@@ -35519,18 +36774,18 @@ _tmp_180_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_180[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+ D(fprintf(stderr, "%*c> _tmp_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
SlashWithDefault* lambda_slash_with_default_var;
if (
(lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_180[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+ D(fprintf(stderr, "%*c+ _tmp_185[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
_res = lambda_slash_with_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_180[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_185[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default"));
}
_res = NULL;
@@ -35539,9 +36794,9 @@ _tmp_180_rule(Parser *p)
return _res;
}
-// _loop0_181: lambda_param_maybe_default
+// _loop0_186: lambda_param_maybe_default
static asdl_seq *
-_loop0_181_rule(Parser *p)
+_loop0_186_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35567,7 +36822,7 @@ _loop0_181_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_181[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -35590,7 +36845,7 @@ _loop0_181_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_181[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_186[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35607,9 +36862,9 @@ _loop0_181_rule(Parser *p)
return _seq;
}
-// _loop0_182: lambda_param_no_default
+// _loop0_187: lambda_param_no_default
static asdl_seq *
-_loop0_182_rule(Parser *p)
+_loop0_187_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35635,7 +36890,7 @@ _loop0_182_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_182[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -35658,7 +36913,7 @@ _loop0_182_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_182[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35675,9 +36930,9 @@ _loop0_182_rule(Parser *p)
return _seq;
}
-// _loop0_183: lambda_param_no_default
+// _loop0_188: lambda_param_no_default
static asdl_seq *
-_loop0_183_rule(Parser *p)
+_loop0_188_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35703,7 +36958,7 @@ _loop0_183_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_183[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _loop0_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
while (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
@@ -35726,7 +36981,7 @@ _loop0_183_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_183[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_188[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35743,9 +36998,9 @@ _loop0_183_rule(Parser *p)
return _seq;
}
-// _loop0_185: ',' lambda_param
+// _loop0_190: ',' lambda_param
static asdl_seq *
-_loop0_185_rule(Parser *p)
+_loop0_190_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35771,7 +37026,7 @@ _loop0_185_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_185[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param"));
+ D(fprintf(stderr, "%*c> _loop0_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' lambda_param"));
Token * _literal;
arg_ty elem;
while (
@@ -35803,7 +37058,7 @@ _loop0_185_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_185[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_190[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' lambda_param"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35820,9 +37075,9 @@ _loop0_185_rule(Parser *p)
return _seq;
}
-// _gather_184: lambda_param _loop0_185
+// _gather_189: lambda_param _loop0_190
static asdl_seq *
-_gather_184_rule(Parser *p)
+_gather_189_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35834,27 +37089,27 @@ _gather_184_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // lambda_param _loop0_185
+ { // lambda_param _loop0_190
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_184[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_185"));
+ D(fprintf(stderr, "%*c> _gather_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190"));
arg_ty elem;
asdl_seq * seq;
if (
(elem = lambda_param_rule(p)) // lambda_param
&&
- (seq = _loop0_185_rule(p)) // _loop0_185
+ (seq = _loop0_190_rule(p)) // _loop0_190
)
{
- D(fprintf(stderr, "%*c+ _gather_184[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_185"));
+ D(fprintf(stderr, "%*c+ _gather_189[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param _loop0_190"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_184[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_185"));
+ D(fprintf(stderr, "%*c%s _gather_189[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param _loop0_190"));
}
_res = NULL;
done:
@@ -35862,9 +37117,9 @@ _gather_184_rule(Parser *p)
return _res;
}
-// _tmp_186: lambda_slash_no_default | lambda_slash_with_default
+// _tmp_191: lambda_slash_no_default | lambda_slash_with_default
static void *
-_tmp_186_rule(Parser *p)
+_tmp_191_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35881,18 +37136,18 @@ _tmp_186_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
asdl_arg_seq* lambda_slash_no_default_var;
if (
(lambda_slash_no_default_var = lambda_slash_no_default_rule(p)) // lambda_slash_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_186[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_no_default"));
_res = lambda_slash_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_186[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_no_default"));
}
{ // lambda_slash_with_default
@@ -35900,18 +37155,18 @@ _tmp_186_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_186[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+ D(fprintf(stderr, "%*c> _tmp_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
SlashWithDefault* lambda_slash_with_default_var;
if (
(lambda_slash_with_default_var = lambda_slash_with_default_rule(p)) // lambda_slash_with_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_186[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
+ D(fprintf(stderr, "%*c+ _tmp_191[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_slash_with_default"));
_res = lambda_slash_with_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_186[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_191[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_slash_with_default"));
}
_res = NULL;
@@ -35920,9 +37175,9 @@ _tmp_186_rule(Parser *p)
return _res;
}
-// _loop0_187: lambda_param_maybe_default
+// _loop0_192: lambda_param_maybe_default
static asdl_seq *
-_loop0_187_rule(Parser *p)
+_loop0_192_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -35948,7 +37203,7 @@ _loop0_187_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_187[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -35971,7 +37226,7 @@ _loop0_187_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_187[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_192[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -35988,9 +37243,9 @@ _loop0_187_rule(Parser *p)
return _seq;
}
-// _tmp_188: ',' | lambda_param_no_default
+// _tmp_193: ',' | lambda_param_no_default
static void *
-_tmp_188_rule(Parser *p)
+_tmp_193_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36007,18 +37262,18 @@ _tmp_188_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_188[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_188[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
{ // lambda_param_no_default
@@ -36026,18 +37281,18 @@ _tmp_188_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_188[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
if (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_188[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
_res = lambda_param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_188[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
_res = NULL;
@@ -36046,9 +37301,9 @@ _tmp_188_rule(Parser *p)
return _res;
}
-// _loop0_189: lambda_param_maybe_default
+// _loop0_194: lambda_param_maybe_default
static asdl_seq *
-_loop0_189_rule(Parser *p)
+_loop0_194_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36074,7 +37329,7 @@ _loop0_189_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_189[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -36097,7 +37352,7 @@ _loop0_189_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_189[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_194[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -36114,9 +37369,9 @@ _loop0_189_rule(Parser *p)
return _seq;
}
-// _loop1_190: lambda_param_maybe_default
+// _loop1_195: lambda_param_maybe_default
static asdl_seq *
-_loop1_190_rule(Parser *p)
+_loop1_195_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36142,7 +37397,7 @@ _loop1_190_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_190[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop1_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -36165,7 +37420,7 @@ _loop1_190_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_190[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_195[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -36187,9 +37442,9 @@ _loop1_190_rule(Parser *p)
return _seq;
}
-// _loop1_191: lambda_param_with_default
+// _loop1_196: lambda_param_with_default
static asdl_seq *
-_loop1_191_rule(Parser *p)
+_loop1_196_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36215,7 +37470,7 @@ _loop1_191_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_191[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
+ D(fprintf(stderr, "%*c> _loop1_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_with_default"));
NameDefaultPair* lambda_param_with_default_var;
while (
(lambda_param_with_default_var = lambda_param_with_default_rule(p)) // lambda_param_with_default
@@ -36238,7 +37493,7 @@ _loop1_191_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_191[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_196[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_with_default"));
}
if (_n == 0 || p->error_indicator) {
@@ -36260,9 +37515,9 @@ _loop1_191_rule(Parser *p)
return _seq;
}
-// _tmp_192: ':' | ',' (':' | '**')
+// _tmp_197: ':' | ',' (':' | '**')
static void *
-_tmp_192_rule(Parser *p)
+_tmp_197_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36279,18 +37534,18 @@ _tmp_192_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
{ // ',' (':' | '**')
@@ -36298,21 +37553,21 @@ _tmp_192_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_192[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
+ D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
Token * _literal;
- void *_tmp_243_var;
+ void *_tmp_264_var;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (_tmp_243_var = _tmp_243_rule(p)) // ':' | '**'
+ (_tmp_264_var = _tmp_264_rule(p)) // ':' | '**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_192[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
- _res = _PyPegen_dummy_name(p, _literal, _tmp_243_var);
+ D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' (':' | '**')"));
+ _res = _PyPegen_dummy_name(p, _literal, _tmp_264_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_192[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (':' | '**')"));
}
_res = NULL;
@@ -36321,9 +37576,9 @@ _tmp_192_rule(Parser *p)
return _res;
}
-// _tmp_193: lambda_param_no_default | ','
+// _tmp_198: lambda_param_no_default | ','
static void *
-_tmp_193_rule(Parser *p)
+_tmp_198_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36340,18 +37595,18 @@ _tmp_193_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
if (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
_res = lambda_param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
{ // ','
@@ -36359,18 +37614,18 @@ _tmp_193_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_193[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_193[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_193[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_198[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -36379,9 +37634,9 @@ _tmp_193_rule(Parser *p)
return _res;
}
-// _loop0_194: lambda_param_maybe_default
+// _loop0_199: lambda_param_maybe_default
static asdl_seq *
-_loop0_194_rule(Parser *p)
+_loop0_199_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36407,7 +37662,7 @@ _loop0_194_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_194[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
+ D(fprintf(stderr, "%*c> _loop0_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_maybe_default"));
NameDefaultPair* lambda_param_maybe_default_var;
while (
(lambda_param_maybe_default_var = lambda_param_maybe_default_rule(p)) // lambda_param_maybe_default
@@ -36430,7 +37685,7 @@ _loop0_194_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_194[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_199[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_maybe_default"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -36447,9 +37702,9 @@ _loop0_194_rule(Parser *p)
return _seq;
}
-// _tmp_195: lambda_param_no_default | ','
+// _tmp_200: lambda_param_no_default | ','
static void *
-_tmp_195_rule(Parser *p)
+_tmp_200_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36466,18 +37721,18 @@ _tmp_195_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
arg_ty lambda_param_no_default_var;
if (
(lambda_param_no_default_var = lambda_param_no_default_rule(p)) // lambda_param_no_default
)
{
- D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
+ D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "lambda_param_no_default"));
_res = lambda_param_no_default_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "lambda_param_no_default"));
}
{ // ','
@@ -36485,18 +37740,18 @@ _tmp_195_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_195[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_195[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_195[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_200[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -36505,9 +37760,9 @@ _tmp_195_rule(Parser *p)
return _res;
}
-// _tmp_196: '*' | '**' | '/'
+// _tmp_201: '*' | '**' | '/'
static void *
-_tmp_196_rule(Parser *p)
+_tmp_201_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36524,18 +37779,18 @@ _tmp_196_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'"));
+ D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'*'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 16)) // token='*'
)
{
- D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'"));
+ D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'*'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'*'"));
}
{ // '**'
@@ -36543,18 +37798,18 @@ _tmp_196_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 35)) // token='**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
}
{ // '/'
@@ -36562,18 +37817,18 @@ _tmp_196_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_196[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'"));
+ D(fprintf(stderr, "%*c> _tmp_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'/'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 17)) // token='/'
)
{
- D(fprintf(stderr, "%*c+ _tmp_196[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'"));
+ D(fprintf(stderr, "%*c+ _tmp_201[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'/'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_196[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_201[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'/'"));
}
_res = NULL;
@@ -36582,9 +37837,9 @@ _tmp_196_rule(Parser *p)
return _res;
}
-// _tmp_197: ',' | ')' | ':'
+// _tmp_202: ',' | ')' | ':'
static void *
-_tmp_197_rule(Parser *p)
+_tmp_202_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36601,18 +37856,18 @@ _tmp_197_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
{ // ')'
@@ -36620,18 +37875,18 @@ _tmp_197_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
{ // ':'
@@ -36639,18 +37894,18 @@ _tmp_197_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_197[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_197[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_197[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_202[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
_res = NULL;
@@ -36659,9 +37914,9 @@ _tmp_197_rule(Parser *p)
return _res;
}
-// _loop0_199: ',' (expression ['as' star_target])
+// _loop0_204: ',' (expression ['as' star_target])
static asdl_seq *
-_loop0_199_rule(Parser *p)
+_loop0_204_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36687,13 +37942,13 @@ _loop0_199_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_199[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])"));
+ D(fprintf(stderr, "%*c> _loop0_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_244_rule(p)) // expression ['as' star_target]
+ (elem = _tmp_265_rule(p)) // expression ['as' star_target]
)
{
_res = elem;
@@ -36719,7 +37974,7 @@ _loop0_199_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_199[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_204[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -36736,9 +37991,9 @@ _loop0_199_rule(Parser *p)
return _seq;
}
-// _gather_198: (expression ['as' star_target]) _loop0_199
+// _gather_203: (expression ['as' star_target]) _loop0_204
static asdl_seq *
-_gather_198_rule(Parser *p)
+_gather_203_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36750,27 +38005,27 @@ _gather_198_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (expression ['as' star_target]) _loop0_199
+ { // (expression ['as' star_target]) _loop0_204
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_198[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_199"));
+ D(fprintf(stderr, "%*c> _gather_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_244_rule(p)) // expression ['as' star_target]
+ (elem = _tmp_265_rule(p)) // expression ['as' star_target]
&&
- (seq = _loop0_199_rule(p)) // _loop0_199
+ (seq = _loop0_204_rule(p)) // _loop0_204
)
{
- D(fprintf(stderr, "%*c+ _gather_198[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_199"));
+ D(fprintf(stderr, "%*c+ _gather_203[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_204"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_198[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_199"));
+ D(fprintf(stderr, "%*c%s _gather_203[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_204"));
}
_res = NULL;
done:
@@ -36778,9 +38033,9 @@ _gather_198_rule(Parser *p)
return _res;
}
-// _loop0_201: ',' (expressions ['as' star_target])
+// _loop0_206: ',' (expressions ['as' star_target])
static asdl_seq *
-_loop0_201_rule(Parser *p)
+_loop0_206_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36806,13 +38061,13 @@ _loop0_201_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_201[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])"));
+ D(fprintf(stderr, "%*c> _loop0_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_245_rule(p)) // expressions ['as' star_target]
+ (elem = _tmp_266_rule(p)) // expressions ['as' star_target]
)
{
_res = elem;
@@ -36838,7 +38093,7 @@ _loop0_201_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_201[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_206[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -36855,9 +38110,9 @@ _loop0_201_rule(Parser *p)
return _seq;
}
-// _gather_200: (expressions ['as' star_target]) _loop0_201
+// _gather_205: (expressions ['as' star_target]) _loop0_206
static asdl_seq *
-_gather_200_rule(Parser *p)
+_gather_205_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36869,27 +38124,27 @@ _gather_200_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (expressions ['as' star_target]) _loop0_201
+ { // (expressions ['as' star_target]) _loop0_206
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_200[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_201"));
+ D(fprintf(stderr, "%*c> _gather_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_245_rule(p)) // expressions ['as' star_target]
+ (elem = _tmp_266_rule(p)) // expressions ['as' star_target]
&&
- (seq = _loop0_201_rule(p)) // _loop0_201
+ (seq = _loop0_206_rule(p)) // _loop0_206
)
{
- D(fprintf(stderr, "%*c+ _gather_200[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_201"));
+ D(fprintf(stderr, "%*c+ _gather_205[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_206"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_200[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_201"));
+ D(fprintf(stderr, "%*c%s _gather_205[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_206"));
}
_res = NULL;
done:
@@ -36897,9 +38152,9 @@ _gather_200_rule(Parser *p)
return _res;
}
-// _loop0_203: ',' (expression ['as' star_target])
+// _loop0_208: ',' (expression ['as' star_target])
static asdl_seq *
-_loop0_203_rule(Parser *p)
+_loop0_208_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36925,13 +38180,13 @@ _loop0_203_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_203[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])"));
+ D(fprintf(stderr, "%*c> _loop0_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expression ['as' star_target])"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_246_rule(p)) // expression ['as' star_target]
+ (elem = _tmp_267_rule(p)) // expression ['as' star_target]
)
{
_res = elem;
@@ -36957,7 +38212,7 @@ _loop0_203_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_203[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_208[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expression ['as' star_target])"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -36974,9 +38229,9 @@ _loop0_203_rule(Parser *p)
return _seq;
}
-// _gather_202: (expression ['as' star_target]) _loop0_203
+// _gather_207: (expression ['as' star_target]) _loop0_208
static asdl_seq *
-_gather_202_rule(Parser *p)
+_gather_207_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -36988,27 +38243,27 @@ _gather_202_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (expression ['as' star_target]) _loop0_203
+ { // (expression ['as' star_target]) _loop0_208
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_202[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_203"));
+ D(fprintf(stderr, "%*c> _gather_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_246_rule(p)) // expression ['as' star_target]
+ (elem = _tmp_267_rule(p)) // expression ['as' star_target]
&&
- (seq = _loop0_203_rule(p)) // _loop0_203
+ (seq = _loop0_208_rule(p)) // _loop0_208
)
{
- D(fprintf(stderr, "%*c+ _gather_202[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_203"));
+ D(fprintf(stderr, "%*c+ _gather_207[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expression ['as' star_target]) _loop0_208"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_202[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_203"));
+ D(fprintf(stderr, "%*c%s _gather_207[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expression ['as' star_target]) _loop0_208"));
}
_res = NULL;
done:
@@ -37016,9 +38271,9 @@ _gather_202_rule(Parser *p)
return _res;
}
-// _loop0_205: ',' (expressions ['as' star_target])
+// _loop0_210: ',' (expressions ['as' star_target])
static asdl_seq *
-_loop0_205_rule(Parser *p)
+_loop0_210_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37044,13 +38299,13 @@ _loop0_205_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_205[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])"));
+ D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' (expressions ['as' star_target])"));
Token * _literal;
void *elem;
while (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
&&
- (elem = _tmp_247_rule(p)) // expressions ['as' star_target]
+ (elem = _tmp_268_rule(p)) // expressions ['as' star_target]
)
{
_res = elem;
@@ -37076,7 +38331,7 @@ _loop0_205_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_205[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' (expressions ['as' star_target])"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -37093,9 +38348,9 @@ _loop0_205_rule(Parser *p)
return _seq;
}
-// _gather_204: (expressions ['as' star_target]) _loop0_205
+// _gather_209: (expressions ['as' star_target]) _loop0_210
static asdl_seq *
-_gather_204_rule(Parser *p)
+_gather_209_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37107,27 +38362,27 @@ _gather_204_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // (expressions ['as' star_target]) _loop0_205
+ { // (expressions ['as' star_target]) _loop0_210
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_204[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_205"));
+ D(fprintf(stderr, "%*c> _gather_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210"));
void *elem;
asdl_seq * seq;
if (
- (elem = _tmp_247_rule(p)) // expressions ['as' star_target]
+ (elem = _tmp_268_rule(p)) // expressions ['as' star_target]
&&
- (seq = _loop0_205_rule(p)) // _loop0_205
+ (seq = _loop0_210_rule(p)) // _loop0_210
)
{
- D(fprintf(stderr, "%*c+ _gather_204[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_205"));
+ D(fprintf(stderr, "%*c+ _gather_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(expressions ['as' star_target]) _loop0_210"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_204[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_205"));
+ D(fprintf(stderr, "%*c%s _gather_209[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(expressions ['as' star_target]) _loop0_210"));
}
_res = NULL;
done:
@@ -37135,9 +38390,9 @@ _gather_204_rule(Parser *p)
return _res;
}
-// _tmp_206: 'except' | 'finally'
+// _tmp_211: 'except' | 'finally'
static void *
-_tmp_206_rule(Parser *p)
+_tmp_211_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37154,18 +38409,18 @@ _tmp_206_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'"));
+ D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'except'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 636)) // token='except'
+ (_keyword = _PyPegen_expect_token(p, 637)) // token='except'
)
{
- D(fprintf(stderr, "%*c+ _tmp_206[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'"));
+ D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'except'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_206[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'except'"));
}
{ // 'finally'
@@ -37173,18 +38428,18 @@ _tmp_206_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_206[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'"));
+ D(fprintf(stderr, "%*c> _tmp_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'finally'"));
Token * _keyword;
if (
- (_keyword = _PyPegen_expect_token(p, 632)) // token='finally'
+ (_keyword = _PyPegen_expect_token(p, 633)) // token='finally'
)
{
- D(fprintf(stderr, "%*c+ _tmp_206[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'"));
+ D(fprintf(stderr, "%*c+ _tmp_211[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'finally'"));
_res = _keyword;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_206[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_211[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'finally'"));
}
_res = NULL;
@@ -37193,9 +38448,9 @@ _tmp_206_rule(Parser *p)
return _res;
}
-// _loop0_207: block
+// _loop0_212: block
static asdl_seq *
-_loop0_207_rule(Parser *p)
+_loop0_212_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37221,7 +38476,7 @@ _loop0_207_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_207[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block"));
+ D(fprintf(stderr, "%*c> _loop0_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block"));
asdl_stmt_seq* block_var;
while (
(block_var = block_rule(p)) // block
@@ -37244,7 +38499,7 @@ _loop0_207_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_207[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_212[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -37261,9 +38516,9 @@ _loop0_207_rule(Parser *p)
return _seq;
}
-// _loop1_208: except_block
+// _loop1_213: except_block
static asdl_seq *
-_loop1_208_rule(Parser *p)
+_loop1_213_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37289,7 +38544,7 @@ _loop1_208_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_208[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block"));
+ D(fprintf(stderr, "%*c> _loop1_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_block"));
excepthandler_ty except_block_var;
while (
(except_block_var = except_block_rule(p)) // except_block
@@ -37312,7 +38567,7 @@ _loop1_208_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_208[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_213[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_block"));
}
if (_n == 0 || p->error_indicator) {
@@ -37334,9 +38589,9 @@ _loop1_208_rule(Parser *p)
return _seq;
}
-// _tmp_209: 'as' NAME
+// _tmp_214: 'as' NAME
static void *
-_tmp_209_rule(Parser *p)
+_tmp_214_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37353,21 +38608,21 @@ _tmp_209_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_209[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_209[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_214[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_209[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_214[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -37376,9 +38631,9 @@ _tmp_209_rule(Parser *p)
return _res;
}
-// _loop0_210: block
+// _loop0_215: block
static asdl_seq *
-_loop0_210_rule(Parser *p)
+_loop0_215_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37404,7 +38659,7 @@ _loop0_210_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_210[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block"));
+ D(fprintf(stderr, "%*c> _loop0_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "block"));
asdl_stmt_seq* block_var;
while (
(block_var = block_rule(p)) // block
@@ -37427,7 +38682,7 @@ _loop0_210_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_210[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_215[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "block"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -37444,9 +38699,9 @@ _loop0_210_rule(Parser *p)
return _seq;
}
-// _loop1_211: except_star_block
+// _loop1_216: except_star_block
static asdl_seq *
-_loop1_211_rule(Parser *p)
+_loop1_216_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37472,7 +38727,7 @@ _loop1_211_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop1_211[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block"));
+ D(fprintf(stderr, "%*c> _loop1_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "except_star_block"));
excepthandler_ty except_star_block_var;
while (
(except_star_block_var = except_star_block_rule(p)) // except_star_block
@@ -37495,7 +38750,7 @@ _loop1_211_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop1_211[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop1_216[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "except_star_block"));
}
if (_n == 0 || p->error_indicator) {
@@ -37517,9 +38772,9 @@ _loop1_211_rule(Parser *p)
return _seq;
}
-// _tmp_212: expression ['as' NAME]
+// _tmp_217: expression ['as' NAME]
static void *
-_tmp_212_rule(Parser *p)
+_tmp_217_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37536,22 +38791,22 @@ _tmp_212_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_212[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]"));
+ D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]"));
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
expr_ty expression_var;
if (
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_248_rule(p), !p->error_indicator) // ['as' NAME]
+ (_opt_var = _tmp_269_rule(p), !p->error_indicator) // ['as' NAME]
)
{
- D(fprintf(stderr, "%*c+ _tmp_212[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]"));
+ D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' NAME]"));
_res = _PyPegen_dummy_name(p, expression_var, _opt_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_212[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' NAME]"));
}
_res = NULL;
@@ -37560,9 +38815,9 @@ _tmp_212_rule(Parser *p)
return _res;
}
-// _tmp_213: 'as' NAME
+// _tmp_218: 'as' NAME
static void *
-_tmp_213_rule(Parser *p)
+_tmp_218_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37579,21 +38834,21 @@ _tmp_213_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_213[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_213[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_213[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -37602,9 +38857,9 @@ _tmp_213_rule(Parser *p)
return _res;
}
-// _tmp_214: 'as' NAME
+// _tmp_219: 'as' NAME
static void *
-_tmp_214_rule(Parser *p)
+_tmp_219_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37621,21 +38876,21 @@ _tmp_214_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_214[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_214[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_214[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -37644,9 +38899,9 @@ _tmp_214_rule(Parser *p)
return _res;
}
-// _tmp_215: NEWLINE | ':'
+// _tmp_220: NEWLINE | ':'
static void *
-_tmp_215_rule(Parser *p)
+_tmp_220_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37663,18 +38918,18 @@ _tmp_215_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
+ D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
Token * newline_var;
if (
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
{
- D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
+ D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "NEWLINE"));
_res = newline_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "NEWLINE"));
}
{ // ':'
@@ -37682,18 +38937,18 @@ _tmp_215_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_215[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_215[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_215[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
_res = NULL;
@@ -37702,9 +38957,9 @@ _tmp_215_rule(Parser *p)
return _res;
}
-// _tmp_216: 'as' NAME
+// _tmp_221: 'as' NAME
static void *
-_tmp_216_rule(Parser *p)
+_tmp_221_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37721,21 +38976,21 @@ _tmp_216_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_216[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_216[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_216[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -37744,9 +38999,9 @@ _tmp_216_rule(Parser *p)
return _res;
}
-// _tmp_217: 'as' NAME
+// _tmp_222: 'as' NAME
static void *
-_tmp_217_rule(Parser *p)
+_tmp_222_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37763,21 +39018,21 @@ _tmp_217_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_217[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_217[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_217[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_222[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -37786,9 +39041,9 @@ _tmp_217_rule(Parser *p)
return _res;
}
-// _tmp_218: positional_patterns ','
+// _tmp_223: positional_patterns ','
static void *
-_tmp_218_rule(Parser *p)
+_tmp_223_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37805,7 +39060,7 @@ _tmp_218_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_218[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','"));
+ D(fprintf(stderr, "%*c> _tmp_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "positional_patterns ','"));
Token * _literal;
asdl_pattern_seq* positional_patterns_var;
if (
@@ -37814,12 +39069,12 @@ _tmp_218_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_218[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','"));
+ D(fprintf(stderr, "%*c+ _tmp_223[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "positional_patterns ','"));
_res = _PyPegen_dummy_name(p, positional_patterns_var, _literal);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_218[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_223[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "positional_patterns ','"));
}
_res = NULL;
@@ -37828,9 +39083,9 @@ _tmp_218_rule(Parser *p)
return _res;
}
-// _tmp_219: '->' expression
+// _tmp_224: '->' expression
static void *
-_tmp_219_rule(Parser *p)
+_tmp_224_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37847,7 +39102,7 @@ _tmp_219_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_219[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'->' expression"));
Token * _literal;
expr_ty expression_var;
if (
@@ -37856,12 +39111,12 @@ _tmp_219_rule(Parser *p)
(expression_var = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_219[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'->' expression"));
_res = _PyPegen_dummy_name(p, _literal, expression_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_219[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'->' expression"));
}
_res = NULL;
@@ -37870,9 +39125,9 @@ _tmp_219_rule(Parser *p)
return _res;
}
-// _tmp_220: '(' arguments? ')'
+// _tmp_225: '(' arguments? ')'
static void *
-_tmp_220_rule(Parser *p)
+_tmp_225_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37889,7 +39144,7 @@ _tmp_220_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_220[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
Token * _literal;
Token * _literal_1;
void *_opt_var;
@@ -37902,12 +39157,12 @@ _tmp_220_rule(Parser *p)
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_220[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
_res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_220[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'"));
}
_res = NULL;
@@ -37916,9 +39171,9 @@ _tmp_220_rule(Parser *p)
return _res;
}
-// _tmp_221: '(' arguments? ')'
+// _tmp_226: '(' arguments? ')'
static void *
-_tmp_221_rule(Parser *p)
+_tmp_226_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37935,7 +39190,7 @@ _tmp_221_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_221[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
Token * _literal;
Token * _literal_1;
void *_opt_var;
@@ -37948,12 +39203,12 @@ _tmp_221_rule(Parser *p)
(_literal_1 = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_221[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
+ D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'(' arguments? ')'"));
_res = _PyPegen_dummy_name(p, _literal, _opt_var, _literal_1);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_221[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'(' arguments? ')'"));
}
_res = NULL;
@@ -37962,9 +39217,9 @@ _tmp_221_rule(Parser *p)
return _res;
}
-// _loop0_223: ',' double_starred_kvpair
+// _loop0_228: ',' double_starred_kvpair
static asdl_seq *
-_loop0_223_rule(Parser *p)
+_loop0_228_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -37990,7 +39245,7 @@ _loop0_223_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _loop0_223[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair"));
+ D(fprintf(stderr, "%*c> _loop0_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' double_starred_kvpair"));
Token * _literal;
KeyValuePair* elem;
while (
@@ -38022,7 +39277,7 @@ _loop0_223_rule(Parser *p)
_mark = p->mark;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _loop0_223[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _loop0_228[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' double_starred_kvpair"));
}
asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
@@ -38039,9 +39294,9 @@ _loop0_223_rule(Parser *p)
return _seq;
}
-// _gather_222: double_starred_kvpair _loop0_223
+// _gather_227: double_starred_kvpair _loop0_228
static asdl_seq *
-_gather_222_rule(Parser *p)
+_gather_227_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38053,27 +39308,27 @@ _gather_222_rule(Parser *p)
}
asdl_seq * _res = NULL;
int _mark = p->mark;
- { // double_starred_kvpair _loop0_223
+ { // double_starred_kvpair _loop0_228
if (p->error_indicator) {
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _gather_222[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_223"));
+ D(fprintf(stderr, "%*c> _gather_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228"));
KeyValuePair* elem;
asdl_seq * seq;
if (
(elem = double_starred_kvpair_rule(p)) // double_starred_kvpair
&&
- (seq = _loop0_223_rule(p)) // _loop0_223
+ (seq = _loop0_228_rule(p)) // _loop0_228
)
{
- D(fprintf(stderr, "%*c+ _gather_222[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_223"));
+ D(fprintf(stderr, "%*c+ _gather_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "double_starred_kvpair _loop0_228"));
_res = _PyPegen_seq_insert_in_front(p, elem, seq);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _gather_222[%d-%d]: %s failed!\n", p->level, ' ',
- p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_223"));
+ D(fprintf(stderr, "%*c%s _gather_227[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "double_starred_kvpair _loop0_228"));
}
_res = NULL;
done:
@@ -38081,9 +39336,9 @@ _gather_222_rule(Parser *p)
return _res;
}
-// _tmp_224: '}' | ','
+// _tmp_229: '}' | ','
static void *
-_tmp_224_rule(Parser *p)
+_tmp_229_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38100,18 +39355,18 @@ _tmp_224_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 26)) // token='}'
)
{
- D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
}
{ // ','
@@ -38119,18 +39374,18 @@ _tmp_224_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_224[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_224[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_224[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -38139,9 +39394,9 @@ _tmp_224_rule(Parser *p)
return _res;
}
-// _tmp_225: '}' | ','
+// _tmp_230: '}' | ','
static void *
-_tmp_225_rule(Parser *p)
+_tmp_230_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38158,18 +39413,18 @@ _tmp_225_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 26)) // token='}'
)
{
- D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
}
{ // ','
@@ -38177,18 +39432,18 @@ _tmp_225_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_225[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "','"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 12)) // token=','
)
{
- D(fprintf(stderr, "%*c+ _tmp_225[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
+ D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "','"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_225[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "','"));
}
_res = NULL;
@@ -38197,9 +39452,898 @@ _tmp_225_rule(Parser *p)
return _res;
}
-// _tmp_226: star_targets '='
+// _tmp_231: yield_expr | star_expressions
static void *
-_tmp_226_rule(Parser *p)
+_tmp_231_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_232: yield_expr | star_expressions
+static void *
+_tmp_232_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_233: '=' | '!' | ':' | '}'
+static void *
+_tmp_233_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '='
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'='"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 22)) // token='='
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'='"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'='"));
+ }
+ { // '!'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'"));
+ }
+ { // ':'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 11)) // token=':'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
+ }
+ { // '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_234: yield_expr | star_expressions
+static void *
+_tmp_234_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_235: '!' | ':' | '}'
+static void *
+_tmp_235_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '!'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!'"));
+ }
+ { // ':'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 11)) // token=':'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
+ }
+ { // '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_236: yield_expr | star_expressions
+static void *
+_tmp_236_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_237: yield_expr | star_expressions
+static void *
+_tmp_237_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_238: '!' NAME
+static void *
+_tmp_238_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '!' NAME
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ Token * _literal;
+ expr_ty name_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ (name_var = _PyPegen_name_token(p)) // NAME
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ _res = _PyPegen_dummy_name(p, _literal, name_var);
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_239: ':' | '}'
+static void *
+_tmp_239_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // ':'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 11)) // token=':'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
+ }
+ { // '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_240: yield_expr | star_expressions
+static void *
+_tmp_240_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_241: '!' NAME
+static void *
+_tmp_241_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '!' NAME
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ Token * _literal;
+ expr_ty name_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ (name_var = _PyPegen_name_token(p)) // NAME
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ _res = _PyPegen_dummy_name(p, _literal, name_var);
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _loop0_242: fstring_format_spec
+static asdl_seq *
+_loop0_242_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void *_res = NULL;
+ int _mark = p->mark;
+ void **_children = PyMem_Malloc(sizeof(void *));
+ if (!_children) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ Py_ssize_t _children_capacity = 1;
+ Py_ssize_t _n = 0;
+ { // fstring_format_spec
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _loop0_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring_format_spec"));
+ expr_ty fstring_format_spec_var;
+ while (
+ (fstring_format_spec_var = fstring_format_spec_rule(p)) // fstring_format_spec
+ )
+ {
+ _res = fstring_format_spec_var;
+ if (_n == _children_capacity) {
+ _children_capacity *= 2;
+ void **_new_children = PyMem_Realloc(_children, _children_capacity*sizeof(void *));
+ if (!_new_children) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ _children = _new_children;
+ }
+ _children[_n++] = _res;
+ _mark = p->mark;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _loop0_242[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring_format_spec"));
+ }
+ asdl_seq *_seq = (asdl_seq*)_Py_asdl_generic_seq_new(_n, p->arena);
+ if (!_seq) {
+ PyMem_Free(_children);
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ p->level--;
+ return NULL;
+ }
+ for (int i = 0; i < _n; i++) asdl_seq_SET_UNTYPED(_seq, i, _children[i]);
+ PyMem_Free(_children);
+ p->level--;
+ return _seq;
+}
+
+// _tmp_243: yield_expr | star_expressions
+static void *
+_tmp_243_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // yield_expr
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ expr_ty yield_expr_var;
+ if (
+ (yield_expr_var = yield_expr_rule(p)) // yield_expr
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "yield_expr"));
+ _res = yield_expr_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "yield_expr"));
+ }
+ { // star_expressions
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ expr_ty star_expressions_var;
+ if (
+ (star_expressions_var = star_expressions_rule(p)) // star_expressions
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_expressions"));
+ _res = star_expressions_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_expressions"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_244: '!' NAME
+static void *
+_tmp_244_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // '!' NAME
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ Token * _literal;
+ expr_ty name_var;
+ if (
+ (_literal = _PyPegen_expect_token(p, 54)) // token='!'
+ &&
+ (name_var = _PyPegen_name_token(p)) // NAME
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'!' NAME"));
+ _res = _PyPegen_dummy_name(p, _literal, name_var);
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'!' NAME"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_245: ':' | '}'
+static void *
+_tmp_245_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // ':'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 11)) // token=':'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
+ }
+ { // '}'
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'}'"));
+ Token * _literal;
+ if (
+ (_literal = _PyPegen_expect_token(p, 26)) // token='}'
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'}'"));
+ _res = _literal;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'}'"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_246: star_targets '='
+static void *
+_tmp_246_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38216,7 +40360,7 @@ _tmp_226_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_226[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
Token * _literal;
expr_ty z;
if (
@@ -38225,7 +40369,7 @@ _tmp_226_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_226[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38235,7 +40379,7 @@ _tmp_226_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_226[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
}
_res = NULL;
@@ -38244,9 +40388,9 @@ _tmp_226_rule(Parser *p)
return _res;
}
-// _tmp_227: '.' | '...'
+// _tmp_247: '.' | '...'
static void *
-_tmp_227_rule(Parser *p)
+_tmp_247_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38263,18 +40407,18 @@ _tmp_227_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
+ D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 23)) // token='.'
)
{
- D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
+ D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
}
{ // '...'
@@ -38282,18 +40426,18 @@ _tmp_227_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_227[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
+ D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 52)) // token='...'
)
{
- D(fprintf(stderr, "%*c+ _tmp_227[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
+ D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_227[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'"));
}
_res = NULL;
@@ -38302,9 +40446,9 @@ _tmp_227_rule(Parser *p)
return _res;
}
-// _tmp_228: '.' | '...'
+// _tmp_248: '.' | '...'
static void *
-_tmp_228_rule(Parser *p)
+_tmp_248_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38321,18 +40465,18 @@ _tmp_228_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
+ D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'.'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 23)) // token='.'
)
{
- D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
+ D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'.'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'.'"));
}
{ // '...'
@@ -38340,18 +40484,18 @@ _tmp_228_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_228[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
+ D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'...'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 52)) // token='...'
)
{
- D(fprintf(stderr, "%*c+ _tmp_228[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
+ D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'...'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_228[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'...'"));
}
_res = NULL;
@@ -38360,9 +40504,9 @@ _tmp_228_rule(Parser *p)
return _res;
}
-// _tmp_229: '@' named_expression NEWLINE
+// _tmp_249: '@' named_expression NEWLINE
static void *
-_tmp_229_rule(Parser *p)
+_tmp_249_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38379,7 +40523,7 @@ _tmp_229_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_229[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
+ D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
Token * _literal;
expr_ty f;
Token * newline_var;
@@ -38391,7 +40535,7 @@ _tmp_229_rule(Parser *p)
(newline_var = _PyPegen_expect_token(p, NEWLINE)) // token='NEWLINE'
)
{
- D(fprintf(stderr, "%*c+ _tmp_229[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
+ D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'@' named_expression NEWLINE"));
_res = f;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38401,7 +40545,7 @@ _tmp_229_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_229[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'@' named_expression NEWLINE"));
}
_res = NULL;
@@ -38410,9 +40554,9 @@ _tmp_229_rule(Parser *p)
return _res;
}
-// _tmp_230: ',' expression
+// _tmp_250: ',' expression
static void *
-_tmp_230_rule(Parser *p)
+_tmp_250_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38429,7 +40573,7 @@ _tmp_230_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_230[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' expression"));
Token * _literal;
expr_ty c;
if (
@@ -38438,7 +40582,7 @@ _tmp_230_rule(Parser *p)
(c = expression_rule(p)) // expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_230[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
+ D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' expression"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38448,7 +40592,7 @@ _tmp_230_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_230[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' expression"));
}
_res = NULL;
@@ -38457,9 +40601,9 @@ _tmp_230_rule(Parser *p)
return _res;
}
-// _tmp_231: ',' star_expression
+// _tmp_251: ',' star_expression
static void *
-_tmp_231_rule(Parser *p)
+_tmp_251_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38476,7 +40620,7 @@ _tmp_231_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_231[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
+ D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
Token * _literal;
expr_ty c;
if (
@@ -38485,7 +40629,7 @@ _tmp_231_rule(Parser *p)
(c = star_expression_rule(p)) // star_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_231[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_expression"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38495,7 +40639,7 @@ _tmp_231_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_231[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_expression"));
}
_res = NULL;
@@ -38504,9 +40648,9 @@ _tmp_231_rule(Parser *p)
return _res;
}
-// _tmp_232: 'or' conjunction
+// _tmp_252: 'or' conjunction
static void *
-_tmp_232_rule(Parser *p)
+_tmp_252_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38523,7 +40667,7 @@ _tmp_232_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_232[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
+ D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
Token * _keyword;
expr_ty c;
if (
@@ -38532,7 +40676,7 @@ _tmp_232_rule(Parser *p)
(c = conjunction_rule(p)) // conjunction
)
{
- D(fprintf(stderr, "%*c+ _tmp_232[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
+ D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'or' conjunction"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38542,7 +40686,7 @@ _tmp_232_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_232[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'or' conjunction"));
}
_res = NULL;
@@ -38551,9 +40695,9 @@ _tmp_232_rule(Parser *p)
return _res;
}
-// _tmp_233: 'and' inversion
+// _tmp_253: 'and' inversion
static void *
-_tmp_233_rule(Parser *p)
+_tmp_253_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38570,7 +40714,7 @@ _tmp_233_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_233[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
+ D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
Token * _keyword;
expr_ty c;
if (
@@ -38579,7 +40723,7 @@ _tmp_233_rule(Parser *p)
(c = inversion_rule(p)) // inversion
)
{
- D(fprintf(stderr, "%*c+ _tmp_233[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
+ D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'and' inversion"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38589,7 +40733,7 @@ _tmp_233_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_233[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'and' inversion"));
}
_res = NULL;
@@ -38598,9 +40742,9 @@ _tmp_233_rule(Parser *p)
return _res;
}
-// _tmp_234: slice | starred_expression
+// _tmp_254: slice | starred_expression
static void *
-_tmp_234_rule(Parser *p)
+_tmp_254_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38617,18 +40761,18 @@ _tmp_234_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice"));
+ D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "slice"));
expr_ty slice_var;
if (
(slice_var = slice_rule(p)) // slice
)
{
- D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice"));
+ D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "slice"));
_res = slice_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "slice"));
}
{ // starred_expression
@@ -38636,18 +40780,18 @@ _tmp_234_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_234[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+ D(fprintf(stderr, "%*c> _tmp_254[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
expr_ty starred_expression_var;
if (
(starred_expression_var = starred_expression_rule(p)) // starred_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_234[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_254[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
_res = starred_expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_234[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_254[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression"));
}
_res = NULL;
@@ -38656,9 +40800,67 @@ _tmp_234_rule(Parser *p)
return _res;
}
-// _tmp_235: 'if' disjunction
+// _tmp_255: fstring | string
static void *
-_tmp_235_rule(Parser *p)
+_tmp_255_rule(Parser *p)
+{
+ if (p->level++ == MAXSTACK) {
+ p->error_indicator = 1;
+ PyErr_NoMemory();
+ }
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ void * _res = NULL;
+ int _mark = p->mark;
+ { // fstring
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "fstring"));
+ expr_ty fstring_var;
+ if (
+ (fstring_var = fstring_rule(p)) // fstring
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "fstring"));
+ _res = fstring_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "fstring"));
+ }
+ { // string
+ if (p->error_indicator) {
+ p->level--;
+ return NULL;
+ }
+ D(fprintf(stderr, "%*c> _tmp_255[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "string"));
+ expr_ty string_var;
+ if (
+ (string_var = string_rule(p)) // string
+ )
+ {
+ D(fprintf(stderr, "%*c+ _tmp_255[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "string"));
+ _res = string_var;
+ goto done;
+ }
+ p->mark = _mark;
+ D(fprintf(stderr, "%*c%s _tmp_255[%d-%d]: %s failed!\n", p->level, ' ',
+ p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "string"));
+ }
+ _res = NULL;
+ done:
+ p->level--;
+ return _res;
+}
+
+// _tmp_256: 'if' disjunction
+static void *
+_tmp_256_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38675,16 +40877,16 @@ _tmp_235_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_235[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+ D(fprintf(stderr, "%*c> _tmp_256[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(z = disjunction_rule(p)) // disjunction
)
{
- D(fprintf(stderr, "%*c+ _tmp_235[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+ D(fprintf(stderr, "%*c+ _tmp_256[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38694,7 +40896,7 @@ _tmp_235_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_235[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_256[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction"));
}
_res = NULL;
@@ -38703,9 +40905,9 @@ _tmp_235_rule(Parser *p)
return _res;
}
-// _tmp_236: 'if' disjunction
+// _tmp_257: 'if' disjunction
static void *
-_tmp_236_rule(Parser *p)
+_tmp_257_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38722,16 +40924,16 @@ _tmp_236_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_236[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+ D(fprintf(stderr, "%*c> _tmp_257[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
Token * _keyword;
expr_ty z;
if (
- (_keyword = _PyPegen_expect_token(p, 641)) // token='if'
+ (_keyword = _PyPegen_expect_token(p, 642)) // token='if'
&&
(z = disjunction_rule(p)) // disjunction
)
{
- D(fprintf(stderr, "%*c+ _tmp_236[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
+ D(fprintf(stderr, "%*c+ _tmp_257[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'if' disjunction"));
_res = z;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38741,7 +40943,7 @@ _tmp_236_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_236[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_257[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'if' disjunction"));
}
_res = NULL;
@@ -38750,9 +40952,9 @@ _tmp_236_rule(Parser *p)
return _res;
}
-// _tmp_237: starred_expression | (assignment_expression | expression !':=') !'='
+// _tmp_258: starred_expression | (assignment_expression | expression !':=') !'='
static void *
-_tmp_237_rule(Parser *p)
+_tmp_258_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38769,18 +40971,18 @@ _tmp_237_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+ D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "starred_expression"));
expr_ty starred_expression_var;
if (
(starred_expression_var = starred_expression_rule(p)) // starred_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "starred_expression"));
_res = starred_expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "starred_expression"));
}
{ // (assignment_expression | expression !':=') !'='
@@ -38788,20 +40990,20 @@ _tmp_237_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_237[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='"));
- void *_tmp_249_var;
+ D(fprintf(stderr, "%*c> _tmp_258[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='"));
+ void *_tmp_270_var;
if (
- (_tmp_249_var = _tmp_249_rule(p)) // assignment_expression | expression !':='
+ (_tmp_270_var = _tmp_270_rule(p)) // assignment_expression | expression !':='
&&
_PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 22) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_237[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='"));
- _res = _tmp_249_var;
+ D(fprintf(stderr, "%*c+ _tmp_258[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "(assignment_expression | expression !':=') !'='"));
+ _res = _tmp_270_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_237[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_258[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "(assignment_expression | expression !':=') !'='"));
}
_res = NULL;
@@ -38810,9 +41012,9 @@ _tmp_237_rule(Parser *p)
return _res;
}
-// _tmp_238: ',' star_target
+// _tmp_259: ',' star_target
static void *
-_tmp_238_rule(Parser *p)
+_tmp_259_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38829,7 +41031,7 @@ _tmp_238_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_238[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_259[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
Token * _literal;
expr_ty c;
if (
@@ -38838,7 +41040,7 @@ _tmp_238_rule(Parser *p)
(c = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_238[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_259[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38848,7 +41050,7 @@ _tmp_238_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_238[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_259[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target"));
}
_res = NULL;
@@ -38857,9 +41059,9 @@ _tmp_238_rule(Parser *p)
return _res;
}
-// _tmp_239: ',' star_target
+// _tmp_260: ',' star_target
static void *
-_tmp_239_rule(Parser *p)
+_tmp_260_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38876,7 +41078,7 @@ _tmp_239_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_239[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_260[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "',' star_target"));
Token * _literal;
expr_ty c;
if (
@@ -38885,7 +41087,7 @@ _tmp_239_rule(Parser *p)
(c = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_239[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_260[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "',' star_target"));
_res = c;
if (_res == NULL && PyErr_Occurred()) {
p->error_indicator = 1;
@@ -38895,7 +41097,7 @@ _tmp_239_rule(Parser *p)
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_239[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_260[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "',' star_target"));
}
_res = NULL;
@@ -38904,9 +41106,9 @@ _tmp_239_rule(Parser *p)
return _res;
}
-// _tmp_240: star_targets '='
+// _tmp_261: star_targets '='
static void *
-_tmp_240_rule(Parser *p)
+_tmp_261_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38923,7 +41125,7 @@ _tmp_240_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_240[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c> _tmp_261[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
Token * _literal;
expr_ty star_targets_var;
if (
@@ -38932,12 +41134,12 @@ _tmp_240_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_240[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c+ _tmp_261[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
_res = _PyPegen_dummy_name(p, star_targets_var, _literal);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_240[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_261[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
}
_res = NULL;
@@ -38946,9 +41148,9 @@ _tmp_240_rule(Parser *p)
return _res;
}
-// _tmp_241: star_targets '='
+// _tmp_262: star_targets '='
static void *
-_tmp_241_rule(Parser *p)
+_tmp_262_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -38965,7 +41167,7 @@ _tmp_241_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_241[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c> _tmp_262[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
Token * _literal;
expr_ty star_targets_var;
if (
@@ -38974,12 +41176,12 @@ _tmp_241_rule(Parser *p)
(_literal = _PyPegen_expect_token(p, 22)) // token='='
)
{
- D(fprintf(stderr, "%*c+ _tmp_241[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
+ D(fprintf(stderr, "%*c+ _tmp_262[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "star_targets '='"));
_res = _PyPegen_dummy_name(p, star_targets_var, _literal);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_241[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_262[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "star_targets '='"));
}
_res = NULL;
@@ -38988,9 +41190,9 @@ _tmp_241_rule(Parser *p)
return _res;
}
-// _tmp_242: ')' | '**'
+// _tmp_263: ')' | '**'
static void *
-_tmp_242_rule(Parser *p)
+_tmp_263_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39007,18 +41209,18 @@ _tmp_242_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "')'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 8)) // token=')'
)
{
- D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
+ D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "')'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "')'"));
}
{ // '**'
@@ -39026,18 +41228,18 @@ _tmp_242_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_242[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c> _tmp_263[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 35)) // token='**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_242[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c+ _tmp_263[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_242[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_263[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
}
_res = NULL;
@@ -39046,9 +41248,9 @@ _tmp_242_rule(Parser *p)
return _res;
}
-// _tmp_243: ':' | '**'
+// _tmp_264: ':' | '**'
static void *
-_tmp_243_rule(Parser *p)
+_tmp_264_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39065,18 +41267,18 @@ _tmp_243_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "':'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 11)) // token=':'
)
{
- D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
+ D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "':'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "':'"));
}
{ // '**'
@@ -39084,18 +41286,18 @@ _tmp_243_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_243[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c> _tmp_264[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'**'"));
Token * _literal;
if (
(_literal = _PyPegen_expect_token(p, 35)) // token='**'
)
{
- D(fprintf(stderr, "%*c+ _tmp_243[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
+ D(fprintf(stderr, "%*c+ _tmp_264[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'**'"));
_res = _literal;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_243[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_264[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'**'"));
}
_res = NULL;
@@ -39104,9 +41306,9 @@ _tmp_243_rule(Parser *p)
return _res;
}
-// _tmp_244: expression ['as' star_target]
+// _tmp_265: expression ['as' star_target]
static void *
-_tmp_244_rule(Parser *p)
+_tmp_265_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39123,22 +41325,22 @@ _tmp_244_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_244[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
+ D(fprintf(stderr, "%*c> _tmp_265[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
expr_ty expression_var;
if (
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_250_rule(p), !p->error_indicator) // ['as' star_target]
+ (_opt_var = _tmp_271_rule(p), !p->error_indicator) // ['as' star_target]
)
{
- D(fprintf(stderr, "%*c+ _tmp_244[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
+ D(fprintf(stderr, "%*c+ _tmp_265[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
_res = _PyPegen_dummy_name(p, expression_var, _opt_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_244[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_265[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]"));
}
_res = NULL;
@@ -39147,9 +41349,9 @@ _tmp_244_rule(Parser *p)
return _res;
}
-// _tmp_245: expressions ['as' star_target]
+// _tmp_266: expressions ['as' star_target]
static void *
-_tmp_245_rule(Parser *p)
+_tmp_266_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39166,22 +41368,22 @@ _tmp_245_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_245[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
+ D(fprintf(stderr, "%*c> _tmp_266[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
expr_ty expressions_var;
if (
(expressions_var = expressions_rule(p)) // expressions
&&
- (_opt_var = _tmp_251_rule(p), !p->error_indicator) // ['as' star_target]
+ (_opt_var = _tmp_272_rule(p), !p->error_indicator) // ['as' star_target]
)
{
- D(fprintf(stderr, "%*c+ _tmp_245[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
+ D(fprintf(stderr, "%*c+ _tmp_266[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
_res = _PyPegen_dummy_name(p, expressions_var, _opt_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_245[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_266[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]"));
}
_res = NULL;
@@ -39190,9 +41392,9 @@ _tmp_245_rule(Parser *p)
return _res;
}
-// _tmp_246: expression ['as' star_target]
+// _tmp_267: expression ['as' star_target]
static void *
-_tmp_246_rule(Parser *p)
+_tmp_267_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39209,22 +41411,22 @@ _tmp_246_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_246[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
+ D(fprintf(stderr, "%*c> _tmp_267[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
expr_ty expression_var;
if (
(expression_var = expression_rule(p)) // expression
&&
- (_opt_var = _tmp_252_rule(p), !p->error_indicator) // ['as' star_target]
+ (_opt_var = _tmp_273_rule(p), !p->error_indicator) // ['as' star_target]
)
{
- D(fprintf(stderr, "%*c+ _tmp_246[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
+ D(fprintf(stderr, "%*c+ _tmp_267[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression ['as' star_target]"));
_res = _PyPegen_dummy_name(p, expression_var, _opt_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_246[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_267[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression ['as' star_target]"));
}
_res = NULL;
@@ -39233,9 +41435,9 @@ _tmp_246_rule(Parser *p)
return _res;
}
-// _tmp_247: expressions ['as' star_target]
+// _tmp_268: expressions ['as' star_target]
static void *
-_tmp_247_rule(Parser *p)
+_tmp_268_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39252,22 +41454,22 @@ _tmp_247_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_247[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
+ D(fprintf(stderr, "%*c> _tmp_268[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
void *_opt_var;
UNUSED(_opt_var); // Silence compiler warnings
expr_ty expressions_var;
if (
(expressions_var = expressions_rule(p)) // expressions
&&
- (_opt_var = _tmp_253_rule(p), !p->error_indicator) // ['as' star_target]
+ (_opt_var = _tmp_274_rule(p), !p->error_indicator) // ['as' star_target]
)
{
- D(fprintf(stderr, "%*c+ _tmp_247[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
+ D(fprintf(stderr, "%*c+ _tmp_268[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expressions ['as' star_target]"));
_res = _PyPegen_dummy_name(p, expressions_var, _opt_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_247[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_268[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expressions ['as' star_target]"));
}
_res = NULL;
@@ -39276,9 +41478,9 @@ _tmp_247_rule(Parser *p)
return _res;
}
-// _tmp_248: 'as' NAME
+// _tmp_269: 'as' NAME
static void *
-_tmp_248_rule(Parser *p)
+_tmp_269_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39295,21 +41497,21 @@ _tmp_248_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_248[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c> _tmp_269[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
Token * _keyword;
expr_ty name_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(name_var = _PyPegen_name_token(p)) // NAME
)
{
- D(fprintf(stderr, "%*c+ _tmp_248[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
+ D(fprintf(stderr, "%*c+ _tmp_269[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' NAME"));
_res = _PyPegen_dummy_name(p, _keyword, name_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_248[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_269[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' NAME"));
}
_res = NULL;
@@ -39318,9 +41520,9 @@ _tmp_248_rule(Parser *p)
return _res;
}
-// _tmp_249: assignment_expression | expression !':='
+// _tmp_270: assignment_expression | expression !':='
static void *
-_tmp_249_rule(Parser *p)
+_tmp_270_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39337,18 +41539,18 @@ _tmp_249_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
+ D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
expr_ty assignment_expression_var;
if (
(assignment_expression_var = assignment_expression_rule(p)) // assignment_expression
)
{
- D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
+ D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "assignment_expression"));
_res = assignment_expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "assignment_expression"));
}
{ // expression !':='
@@ -39356,7 +41558,7 @@ _tmp_249_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_249[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='"));
+ D(fprintf(stderr, "%*c> _tmp_270[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "expression !':='"));
expr_ty expression_var;
if (
(expression_var = expression_rule(p)) // expression
@@ -39364,12 +41566,12 @@ _tmp_249_rule(Parser *p)
_PyPegen_lookahead_with_int(0, _PyPegen_expect_token, p, 53) // token=':='
)
{
- D(fprintf(stderr, "%*c+ _tmp_249[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='"));
+ D(fprintf(stderr, "%*c+ _tmp_270[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "expression !':='"));
_res = expression_var;
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_249[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_270[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "expression !':='"));
}
_res = NULL;
@@ -39378,9 +41580,9 @@ _tmp_249_rule(Parser *p)
return _res;
}
-// _tmp_250: 'as' star_target
+// _tmp_271: 'as' star_target
static void *
-_tmp_250_rule(Parser *p)
+_tmp_271_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39397,21 +41599,21 @@ _tmp_250_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_250[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_271[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
Token * _keyword;
expr_ty star_target_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(star_target_var = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_250[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_271[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
_res = _PyPegen_dummy_name(p, _keyword, star_target_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_250[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_271[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target"));
}
_res = NULL;
@@ -39420,9 +41622,9 @@ _tmp_250_rule(Parser *p)
return _res;
}
-// _tmp_251: 'as' star_target
+// _tmp_272: 'as' star_target
static void *
-_tmp_251_rule(Parser *p)
+_tmp_272_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39439,21 +41641,21 @@ _tmp_251_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_251[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_272[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
Token * _keyword;
expr_ty star_target_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(star_target_var = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_251[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_272[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
_res = _PyPegen_dummy_name(p, _keyword, star_target_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_251[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_272[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target"));
}
_res = NULL;
@@ -39462,9 +41664,9 @@ _tmp_251_rule(Parser *p)
return _res;
}
-// _tmp_252: 'as' star_target
+// _tmp_273: 'as' star_target
static void *
-_tmp_252_rule(Parser *p)
+_tmp_273_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39481,21 +41683,21 @@ _tmp_252_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_252[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_273[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
Token * _keyword;
expr_ty star_target_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(star_target_var = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_252[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_273[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
_res = _PyPegen_dummy_name(p, _keyword, star_target_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_252[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_273[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target"));
}
_res = NULL;
@@ -39504,9 +41706,9 @@ _tmp_252_rule(Parser *p)
return _res;
}
-// _tmp_253: 'as' star_target
+// _tmp_274: 'as' star_target
static void *
-_tmp_253_rule(Parser *p)
+_tmp_274_rule(Parser *p)
{
if (p->level++ == MAXSTACK) {
p->error_indicator = 1;
@@ -39523,21 +41725,21 @@ _tmp_253_rule(Parser *p)
p->level--;
return NULL;
}
- D(fprintf(stderr, "%*c> _tmp_253[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c> _tmp_274[%d-%d]: %s\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
Token * _keyword;
expr_ty star_target_var;
if (
- (_keyword = _PyPegen_expect_token(p, 639)) // token='as'
+ (_keyword = _PyPegen_expect_token(p, 640)) // token='as'
&&
(star_target_var = star_target_rule(p)) // star_target
)
{
- D(fprintf(stderr, "%*c+ _tmp_253[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
+ D(fprintf(stderr, "%*c+ _tmp_274[%d-%d]: %s succeeded!\n", p->level, ' ', _mark, p->mark, "'as' star_target"));
_res = _PyPegen_dummy_name(p, _keyword, star_target_var);
goto done;
}
p->mark = _mark;
- D(fprintf(stderr, "%*c%s _tmp_253[%d-%d]: %s failed!\n", p->level, ' ',
+ D(fprintf(stderr, "%*c%s _tmp_274[%d-%d]: %s failed!\n", p->level, ' ',
p->error_indicator ? "ERROR!" : "-", _mark, p->mark, "'as' star_target"));
}
_res = NULL;
diff --git a/Parser/pegen.c b/Parser/pegen.c
index b79ae4cb1fb370..262bfabfba7a25 100644
--- a/Parser/pegen.c
+++ b/Parser/pegen.c
@@ -359,7 +359,7 @@ _PyPegen_expect_token(Parser *p, int type)
}
Token *t = p->tokens[p->mark];
if (t->type != type) {
- return NULL;
+ return NULL;
}
p->mark += 1;
return t;
diff --git a/Parser/pegen.h b/Parser/pegen.h
index ad5c97f5f7e5d1..6962013c2d18b4 100644
--- a/Parser/pegen.h
+++ b/Parser/pegen.h
@@ -138,6 +138,7 @@ void* _PyPegen_expect_forced_result(Parser *p, void* result, const char* expecte
Token *_PyPegen_expect_forced_token(Parser *p, int type, const char* expected);
expr_ty _PyPegen_expect_soft_keyword(Parser *p, const char *keyword);
expr_ty _PyPegen_soft_keyword_token(Parser *p);
+expr_ty _PyPegen_fstring_middle_token(Parser* p);
Token *_PyPegen_get_last_nonnwhitespace_token(Parser *);
int _PyPegen_fill_token(Parser *p);
expr_ty _PyPegen_name_token(Parser *p);
@@ -155,7 +156,7 @@ typedef enum {
int _Pypegen_raise_decode_error(Parser *p);
void _PyPegen_raise_tokenizer_init_error(PyObject *filename);
int _Pypegen_tokenizer_error(Parser *p);
-void *_PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...);
+void *_PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *errmsg, ...);
void *_PyPegen_raise_error_known_location(Parser *p, PyObject *errtype,
Py_ssize_t lineno, Py_ssize_t col_offset,
Py_ssize_t end_lineno, Py_ssize_t end_col_offset,
@@ -175,8 +176,9 @@ RAISE_ERROR_KNOWN_LOCATION(Parser *p, PyObject *errtype,
va_end(va);
return NULL;
}
-#define RAISE_SYNTAX_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, msg, ##__VA_ARGS__)
-#define RAISE_INDENTATION_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_IndentationError, msg, ##__VA_ARGS__)
+#define RAISE_SYNTAX_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, 0, msg, ##__VA_ARGS__)
+#define RAISE_INDENTATION_ERROR(msg, ...) _PyPegen_raise_error(p, PyExc_IndentationError, 0, msg, ##__VA_ARGS__)
+#define RAISE_SYNTAX_ERROR_ON_NEXT_TOKEN(msg, ...) _PyPegen_raise_error(p, PyExc_SyntaxError, 1, msg, ##__VA_ARGS__)
#define RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, msg, ...) \
RAISE_ERROR_KNOWN_LOCATION(p, PyExc_SyntaxError, (a)->lineno, (a)->col_offset, (b)->end_lineno, (b)->end_col_offset, msg, ##__VA_ARGS__)
#define RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, msg, ...) \
@@ -308,6 +310,7 @@ StarEtc *_PyPegen_star_etc(Parser *, arg_ty, asdl_seq *, arg_ty);
arguments_ty _PyPegen_make_arguments(Parser *, asdl_arg_seq *, SlashWithDefault *,
asdl_arg_seq *, asdl_seq *, StarEtc *);
arguments_ty _PyPegen_empty_arguments(Parser *);
+expr_ty _PyPegen_formatted_value(Parser *, expr_ty, Token *, expr_ty, expr_ty, int, int, int, int, PyArena *);
AugOperator *_PyPegen_augoperator(Parser*, operator_ty type);
stmt_ty _PyPegen_function_def_decorators(Parser *, asdl_expr_seq *, stmt_ty);
stmt_ty _PyPegen_class_def_decorators(Parser *, asdl_expr_seq *, stmt_ty);
@@ -317,12 +320,16 @@ asdl_keyword_seq *_PyPegen_seq_delete_starred_exprs(Parser *, asdl_seq *);
expr_ty _PyPegen_collect_call_seqs(Parser *, asdl_expr_seq *, asdl_seq *,
int lineno, int col_offset, int end_lineno,
int end_col_offset, PyArena *arena);
-expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_seq *);
+expr_ty _PyPegen_constant_from_token(Parser* p, Token* tok);
+expr_ty _PyPegen_constant_from_string(Parser* p, Token* tok);
+expr_ty _PyPegen_concatenate_strings(Parser *p, asdl_expr_seq *, int, int, int, int, PyArena *);
+expr_ty _PyPegen_FetchRawForm(Parser *p, int, int, int, int);
expr_ty _PyPegen_ensure_imaginary(Parser *p, expr_ty);
expr_ty _PyPegen_ensure_real(Parser *p, expr_ty);
asdl_seq *_PyPegen_join_sequences(Parser *, asdl_seq *, asdl_seq *);
int _PyPegen_check_barry_as_flufl(Parser *, Token *);
int _PyPegen_check_legacy_stmt(Parser *p, expr_ty t);
+expr_ty _PyPegen_check_fstring_conversion(Parser *p, Token *, expr_ty t);
mod_ty _PyPegen_make_module(Parser *, asdl_stmt_seq *);
void *_PyPegen_arguments_parsing_error(Parser *, expr_ty);
expr_ty _PyPegen_get_last_comprehension_item(comprehension_ty comprehension);
@@ -338,6 +345,9 @@ void *_PyPegen_run_parser(Parser *);
mod_ty _PyPegen_run_parser_from_string(const char *, int, PyObject *, PyCompilerFlags *, PyArena *);
asdl_stmt_seq *_PyPegen_interactive_exit(Parser *);
+// TODO: move to the correct place in this file
+expr_ty _PyPegen_joined_str(Parser *p, Token* a, asdl_expr_seq* expr, Token*b);
+
// Generated function in parse.c - function definition in python.gram
void *_PyPegen_parse(Parser *);
diff --git a/Parser/pegen_errors.c b/Parser/pegen_errors.c
index 6ea7600119b643..e26bad20a27575 100644
--- a/Parser/pegen_errors.c
+++ b/Parser/pegen_errors.c
@@ -192,7 +192,10 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) {
exit:
- if (PyErr_Occurred()) {
+ // If we're in an f-string, we want the syntax error in the expression part
+ // to propagate, so that tokenizer errors (like expecting '}') that happen afterwards
+ // do not swallow it.
+ if (PyErr_Occurred() && p->tok->tok_mode_stack_index <= 0) {
Py_XDECREF(value);
Py_XDECREF(type);
Py_XDECREF(traceback);
@@ -205,7 +208,7 @@ _PyPegen_tokenize_full_source_to_check_for_errors(Parser *p) {
// PARSER ERRORS
void *
-_PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...)
+_PyPegen_raise_error(Parser *p, PyObject *errtype, int use_mark, const char *errmsg, ...)
{
if (p->fill == 0) {
va_list va;
@@ -214,8 +217,13 @@ _PyPegen_raise_error(Parser *p, PyObject *errtype, const char *errmsg, ...)
va_end(va);
return NULL;
}
-
- Token *t = p->known_err_token != NULL ? p->known_err_token : p->tokens[p->fill - 1];
+ if (use_mark && p->mark == p->fill && _PyPegen_fill_token(p) < 0) {
+ p->error_indicator = 1;
+ return NULL;
+ }
+ Token *t = p->known_err_token != NULL
+ ? p->known_err_token
+ : p->tokens[use_mark ? p->mark : p->fill - 1];
Py_ssize_t col_offset;
Py_ssize_t end_col_offset = -1;
if (t->col_offset == -1) {
diff --git a/Parser/string_parser.c b/Parser/string_parser.c
index c096bea7426e5c..d4ce33850f7c58 100644
--- a/Parser/string_parser.c
+++ b/Parser/string_parser.c
@@ -135,7 +135,9 @@ decode_unicode_with_escapes(Parser *parser, const char *s, size_t len, Token *t)
const char *first_invalid_escape;
v = _PyUnicode_DecodeUnicodeEscapeInternal(s, len, NULL, NULL, &first_invalid_escape);
- if (v != NULL && first_invalid_escape != NULL) {
+ // HACK: later we can simply pass the line no, since we don't preserve the tokens
+ // when we are decoding the string but we preserve the line numbers.
+ if (v != NULL && first_invalid_escape != NULL && t != NULL) {
if (warn_invalid_escape_sequence(parser, first_invalid_escape, t) < 0) {
/* We have not decref u before because first_invalid_escape points
inside u. */
@@ -166,43 +168,43 @@ decode_bytes_with_escapes(Parser *p, const char *s, Py_ssize_t len, Token *t)
return result;
}
-/* s must include the bracketing quote characters, and r, b, u,
- &/or f prefixes (if any), and embedded escape sequences (if any).
- _PyPegen_parsestr parses it, and sets *result to decoded Python string object.
- If the string is an f-string, set *fstr and *fstrlen to the unparsed
- string object. Return 0 if no errors occurred. */
-int
-_PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
- const char **fstr, Py_ssize_t *fstrlen, Token *t)
+PyObject *
+_PyPegen_decode_string(Parser *p, int raw, const char *s, size_t len, Token *t)
+{
+ if (raw) {
+ return PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL);
+ }
+ return decode_unicode_with_escapes(p, s, len, t);
+}
+
+/* s must include the bracketing quote characters, and r, b &/or f prefixes
+ (if any), and embedded escape sequences (if any). (f-strings are handled by the parser)
+ _PyPegen_parse_string parses it, and returns the decoded Python string object. */
+PyObject *
+_PyPegen_parse_string(Parser *p, Token *t)
{
const char *s = PyBytes_AsString(t->bytes);
if (s == NULL) {
- return -1;
+ return NULL;
}
size_t len;
int quote = Py_CHARMASK(*s);
- int fmode = 0;
- *bytesmode = 0;
- *rawmode = 0;
- *result = NULL;
- *fstr = NULL;
+ int bytesmode = 0;
+ int rawmode = 0;
+
if (Py_ISALPHA(quote)) {
- while (!*bytesmode || !*rawmode) {
+ while (!bytesmode || !rawmode) {
if (quote == 'b' || quote == 'B') {
quote =(unsigned char)*++s;
- *bytesmode = 1;
+ bytesmode = 1;
}
else if (quote == 'u' || quote == 'U') {
quote = (unsigned char)*++s;
}
else if (quote == 'r' || quote == 'R') {
quote = (unsigned char)*++s;
- *rawmode = 1;
- }
- else if (quote == 'f' || quote == 'F') {
- quote = (unsigned char)*++s;
- fmode = 1;
+ rawmode = 1;
}
else {
break;
@@ -210,32 +212,21 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
}
}
- /* fstrings are only allowed in Python 3.6 and greater */
- if (fmode && p->feature_version < 6) {
- p->error_indicator = 1;
- RAISE_SYNTAX_ERROR("Format strings are only supported in Python 3.6 and greater");
- return -1;
- }
-
- if (fmode && *bytesmode) {
- PyErr_BadInternalCall();
- return -1;
- }
if (quote != '\'' && quote != '\"') {
PyErr_BadInternalCall();
- return -1;
+ return NULL;
}
/* Skip the leading quote char. */
s++;
len = strlen(s);
if (len > INT_MAX) {
PyErr_SetString(PyExc_OverflowError, "string to parse is too long");
- return -1;
+ return NULL;
}
if (s[--len] != quote) {
/* Last quote char must match the first. */
PyErr_BadInternalCall();
- return -1;
+ return NULL;
}
if (len >= 4 && s[0] == quote && s[1] == quote) {
/* A triple quoted string. We've already skipped one quote at
@@ -246,1037 +237,28 @@ _PyPegen_parsestr(Parser *p, int *bytesmode, int *rawmode, PyObject **result,
/* And check that the last two match. */
if (s[--len] != quote || s[--len] != quote) {
PyErr_BadInternalCall();
- return -1;
+ return NULL;
}
}
- if (fmode) {
- /* Just return the bytes. The caller will parse the resulting
- string. */
- *fstr = s;
- *fstrlen = len;
- return 0;
- }
-
- /* Not an f-string. */
/* Avoid invoking escape decoding routines if possible. */
- *rawmode = *rawmode || strchr(s, '\\') == NULL;
- if (*bytesmode) {
+ rawmode = rawmode || strchr(s, '\\') == NULL;
+ if (bytesmode) {
/* Disallow non-ASCII characters. */
const char *ch;
for (ch = s; *ch; ch++) {
if (Py_CHARMASK(*ch) >= 0x80) {
- RAISE_SYNTAX_ERROR(
+ RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
+ t,
"bytes can only contain ASCII "
"literal characters");
- return -1;
- }
- }
- if (*rawmode) {
- *result = PyBytes_FromStringAndSize(s, len);
- }
- else {
- *result = decode_bytes_with_escapes(p, s, len, t);
- }
- }
- else {
- if (*rawmode) {
- *result = PyUnicode_DecodeUTF8Stateful(s, len, NULL, NULL);
- }
- else {
- *result = decode_unicode_with_escapes(p, s, len, t);
- }
- }
- return *result == NULL ? -1 : 0;
-}
-
-
-
-// FSTRING STUFF
-
-/* Fix locations for the given node and its children.
-
- `parent` is the enclosing node.
- `expr_start` is the starting position of the expression (pointing to the open brace).
- `n` is the node which locations are going to be fixed relative to parent.
- `expr_str` is the child node's string representation, including braces.
-*/
-static bool
-fstring_find_expr_location(Token *parent, const char* expr_start, char *expr_str, int *p_lines, int *p_cols)
-{
- *p_lines = 0;
- *p_cols = 0;
- assert(expr_start != NULL && *expr_start == '{');
- if (parent && parent->bytes) {
- const char *parent_str = PyBytes_AsString(parent->bytes);
- if (!parent_str) {
- return false;
- }
- // The following is needed, in order to correctly shift the column
- // offset, in the case that (disregarding any whitespace) a newline
- // immediately follows the opening curly brace of the fstring expression.
- bool newline_after_brace = 1;
- const char *start = expr_start + 1;
- while (start && *start != '}' && *start != '\n') {
- if (*start != ' ' && *start != '\t' && *start != '\f') {
- newline_after_brace = 0;
- break;
- }
- start++;
- }
-
- // Account for the characters from the last newline character to our
- // left until the beginning of expr_start.
- if (!newline_after_brace) {
- start = expr_start;
- while (start > parent_str && *start != '\n') {
- start--;
- }
- *p_cols += (int)(expr_start - start);
- if (*start == '\n') {
- *p_cols -= 1;
- }
- }
- /* adjust the start based on the number of newlines encountered
- before the f-string expression */
- for (const char *p = parent_str; p < expr_start; p++) {
- if (*p == '\n') {
- (*p_lines)++;
- }
- }
- }
- return true;
-}
-
-
-/* Compile this expression in to an expr_ty. Add parens around the
- expression, in order to allow leading spaces in the expression. */
-static expr_ty
-fstring_compile_expr(Parser *p, const char *expr_start, const char *expr_end,
- Token *t)
-{
- expr_ty expr = NULL;
- char *str;
- Py_ssize_t len;
- const char *s;
- expr_ty result = NULL;
-
- assert(expr_end >= expr_start);
- assert(*(expr_start-1) == '{');
- assert(*expr_end == '}' || *expr_end == '!' || *expr_end == ':' ||
- *expr_end == '=');
-
- /* If the substring is all whitespace, it's an error. We need to catch this
- here, and not when we call PyParser_SimpleParseStringFlagsFilename,
- because turning the expression '' in to '()' would go from being invalid
- to valid. */
- for (s = expr_start; s != expr_end; s++) {
- char c = *s;
- /* The Python parser ignores only the following whitespace
- characters (\r already is converted to \n). */
- if (!(c == ' ' || c == '\t' || c == '\n' || c == '\f')) {
- break;
- }
- }
-
- if (s == expr_end) {
- if (*expr_end == '!' || *expr_end == ':' || *expr_end == '=') {
- RAISE_SYNTAX_ERROR("f-string: expression required before '%c'", *expr_end);
- return NULL;
- }
- RAISE_SYNTAX_ERROR("f-string: empty expression not allowed");
- return NULL;
- }
-
- len = expr_end - expr_start;
- /* Allocate 3 extra bytes: open paren, close paren, null byte. */
- str = PyMem_Calloc(len + 3, sizeof(char));
- if (str == NULL) {
- PyErr_NoMemory();
- return NULL;
- }
-
- // The call to fstring_find_expr_location is responsible for finding the column offset
- // the generated AST nodes need to be shifted to the right, which is equal to the number
- // of the f-string characters before the expression starts.
- memcpy(str+1, expr_start, len);
- int lines, cols;
- if (!fstring_find_expr_location(t, expr_start-1, str+1, &lines, &cols)) {
- PyMem_Free(str);
- return NULL;
- }
-
- // The parentheses are needed in order to allow for leading whitespace within
- // the f-string expression. This consequently gets parsed as a group (see the
- // group rule in python.gram).
- str[0] = '(';
- str[len+1] = ')';
-
- struct tok_state* tok = _PyTokenizer_FromString(str, 1);
- if (tok == NULL) {
- PyMem_Free(str);
- return NULL;
- }
- tok->filename = Py_NewRef(p->tok->filename);
- tok->lineno = t->lineno + lines - 1;
-
- Parser *p2 = _PyPegen_Parser_New(tok, Py_fstring_input, p->flags, p->feature_version,
- NULL, p->arena);
-
- p2->starting_lineno = t->lineno + lines;
- p2->starting_col_offset = lines != 0 ? cols : t->col_offset + cols;
-
- expr = _PyPegen_run_parser(p2);
-
- if (expr == NULL) {
- goto exit;
- }
- result = expr;
-
-exit:
- PyMem_Free(str);
- _PyPegen_Parser_Free(p2);
- _PyTokenizer_Free(tok);
- return result;
-}
-
-/* Return -1 on error.
-
- Return 0 if we reached the end of the literal.
-
- Return 1 if we haven't reached the end of the literal, but we want
- the caller to process the literal up to this point. Used for
- doubled braces.
-*/
-static int
-fstring_find_literal(Parser *p, const char **str, const char *end, int raw,
- PyObject **literal, int recurse_lvl, Token *t)
-{
- /* Get any literal string. It ends when we hit an un-doubled left
- brace (which isn't part of a unicode name escape such as
- "\N{EULER CONSTANT}"), or the end of the string. */
-
- const char *s = *str;
- const char *literal_start = s;
- int result = 0;
-
- assert(*literal == NULL);
- while (s < end) {
- char ch = *s++;
- if (!raw && ch == '\\' && s < end) {
- ch = *s++;
- if (ch == 'N') {
- /* We need to look at and skip matching braces for "\N{name}"
- sequences because otherwise we'll think the opening '{'
- starts an expression, which is not the case with "\N".
- Keep looking for either a matched '{' '}' pair, or the end
- of the string. */
-
- if (s < end && *s++ == '{') {
- while (s < end && *s++ != '}') {
- }
- continue;
- }
-
- /* This is an invalid "\N" sequence, since it's a "\N" not
- followed by a "{". Just keep parsing this literal. This
- error will be caught later by
- decode_unicode_with_escapes(). */
- continue;
- }
- if (ch == '{' && warn_invalid_escape_sequence(p, s-1, t) < 0) {
- return -1;
- }
- }
- if (ch == '{' || ch == '}') {
- /* Check for doubled braces, but only at the top level. If
- we checked at every level, then f'{0:{3}}' would fail
- with the two closing braces. */
- if (recurse_lvl == 0) {
- if (s < end && *s == ch) {
- /* We're going to tell the caller that the literal ends
- here, but that they should continue scanning. But also
- skip over the second brace when we resume scanning. */
- *str = s + 1;
- result = 1;
- goto done;
- }
-
- /* Where a single '{' is the start of a new expression, a
- single '}' is not allowed. */
- if (ch == '}') {
- *str = s - 1;
- RAISE_SYNTAX_ERROR("f-string: single '}' is not allowed");
- return -1;
- }
- }
- /* We're either at a '{', which means we're starting another
- expression; or a '}', which means we're at the end of this
- f-string (for a nested format_spec). */
- s--;
- break;
- }
- }
- *str = s;
- assert(s <= end);
- assert(s == end || *s == '{' || *s == '}');
-done:
- if (literal_start != s) {
- if (raw) {
- *literal = PyUnicode_DecodeUTF8Stateful(literal_start,
- s - literal_start,
- NULL, NULL);
- }
- else {
- *literal = decode_unicode_with_escapes(p, literal_start,
- s - literal_start, t);
- }
- if (!*literal) {
- return -1;
- }
- }
- return result;
-}
-
-/* Forward declaration because parsing is recursive. */
-static expr_ty
-fstring_parse(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
- Token *first_token, Token* t, Token *last_token);
-
-/* Parse the f-string at *str, ending at end. We know *str starts an
- expression (so it must be a '{'). Returns the FormattedValue node, which
- includes the expression, conversion character, format_spec expression, and
- optionally the text of the expression (if = is used).
-
- Note that I don't do a perfect job here: I don't make sure that a
- closing brace doesn't match an opening paren, for example. It
- doesn't need to error on all invalid expressions, just correctly
- find the end of all valid ones. Any errors inside the expression
- will be caught when we parse it later.
-
- *expression is set to the expression. For an '=' "debug" expression,
- *expr_text is set to the debug text (the original text of the expression,
- including the '=' and any whitespace around it, as a string object). If
- not a debug expression, *expr_text set to NULL. */
-static int
-fstring_find_expr(Parser *p, const char **str, const char *end, int raw, int recurse_lvl,
- PyObject **expr_text, expr_ty *expression, Token *first_token,
- Token *t, Token *last_token)
-{
- /* Return -1 on error, else 0. */
-
- const char *expr_start;
- const char *expr_end;
- expr_ty simple_expression;
- expr_ty format_spec = NULL; /* Optional format specifier. */
- int conversion = -1; /* The conversion char. Use default if not
- specified, or !r if using = and no format
- spec. */
-
- /* 0 if we're not in a string, else the quote char we're trying to
- match (single or double quote). */
- char quote_char = 0;
-
- /* If we're inside a string, 1=normal, 3=triple-quoted. */
- int string_type = 0;
-
- /* Keep track of nesting level for braces/parens/brackets in
- expressions. */
- Py_ssize_t nested_depth = 0;
- char parenstack[MAXLEVEL];
-
- *expr_text = NULL;
-
- /* Can only nest one level deep. */
- if (recurse_lvl >= 2) {
- RAISE_SYNTAX_ERROR("f-string: expressions nested too deeply");
- goto error;
- }
-
- /* The first char must be a left brace, or we wouldn't have gotten
- here. Skip over it. */
- assert(**str == '{');
- *str += 1;
-
- expr_start = *str;
- for (; *str < end; (*str)++) {
- char ch;
-
- /* Loop invariants. */
- assert(nested_depth >= 0);
- assert(*str >= expr_start && *str < end);
- if (quote_char) {
- assert(string_type == 1 || string_type == 3);
- } else {
- assert(string_type == 0);
- }
-
- ch = **str;
- /* Nowhere inside an expression is a backslash allowed. */
- if (ch == '\\') {
- /* Error: can't include a backslash character, inside
- parens or strings or not. */
- RAISE_SYNTAX_ERROR(
- "f-string expression part "
- "cannot include a backslash");
- goto error;
- }
- if (quote_char) {
- /* We're inside a string. See if we're at the end. */
- /* This code needs to implement the same non-error logic
- as tok_get from tokenizer.c, at the letter_quote
- label. To actually share that code would be a
- nightmare. But, it's unlikely to change and is small,
- so duplicate it here. Note we don't need to catch all
- of the errors, since they'll be caught when parsing the
- expression. We just need to match the non-error
- cases. Thus we can ignore \n in single-quoted strings,
- for example. Or non-terminated strings. */
- if (ch == quote_char) {
- /* Does this match the string_type (single or triple
- quoted)? */
- if (string_type == 3) {
- if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
- /* We're at the end of a triple quoted string. */
- *str += 2;
- string_type = 0;
- quote_char = 0;
- continue;
- }
- } else {
- /* We're at the end of a normal string. */
- quote_char = 0;
- string_type = 0;
- continue;
- }
- }
- } else if (ch == '\'' || ch == '"') {
- /* Is this a triple quoted string? */
- if (*str+2 < end && *(*str+1) == ch && *(*str+2) == ch) {
- string_type = 3;
- *str += 2;
- } else {
- /* Start of a normal string. */
- string_type = 1;
- }
- /* Start looking for the end of the string. */
- quote_char = ch;
- } else if (ch == '[' || ch == '{' || ch == '(') {
- if (nested_depth >= MAXLEVEL) {
- RAISE_SYNTAX_ERROR("f-string: too many nested parenthesis");
- goto error;
- }
- parenstack[nested_depth] = ch;
- nested_depth++;
- } else if (ch == '#') {
- /* Error: can't include a comment character, inside parens
- or not. */
- RAISE_SYNTAX_ERROR("f-string expression part cannot include '#'");
- goto error;
- } else if (nested_depth == 0 &&
- (ch == '!' || ch == ':' || ch == '}' ||
- ch == '=' || ch == '>' || ch == '<')) {
- /* See if there's a next character. */
- if (*str+1 < end) {
- char next = *(*str+1);
-
- /* For "!=". since '=' is not an allowed conversion character,
- nothing is lost in this test. */
- if ((ch == '!' && next == '=') || /* != */
- (ch == '=' && next == '=') || /* == */
- (ch == '<' && next == '=') || /* <= */
- (ch == '>' && next == '=') /* >= */
- ) {
- *str += 1;
- continue;
- }
- }
- /* Don't get out of the loop for these, if they're single
- chars (not part of 2-char tokens). If by themselves, they
- don't end an expression (unlike say '!'). */
- if (ch == '>' || ch == '<') {
- continue;
- }
-
- /* Normal way out of this loop. */
- break;
- } else if (ch == ']' || ch == '}' || ch == ')') {
- if (!nested_depth) {
- RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", ch);
- goto error;
- }
- nested_depth--;
- int opening = (unsigned char)parenstack[nested_depth];
- if (!((opening == '(' && ch == ')') ||
- (opening == '[' && ch == ']') ||
- (opening == '{' && ch == '}')))
- {
- RAISE_SYNTAX_ERROR(
- "f-string: closing parenthesis '%c' "
- "does not match opening parenthesis '%c'",
- ch, opening);
- goto error;
- }
- } else {
- /* Just consume this char and loop around. */
- }
- }
- expr_end = *str;
- /* If we leave the above loop in a string or with mismatched parens, we
- don't really care. We'll get a syntax error when compiling the
- expression. But, we can produce a better error message, so let's just
- do that.*/
- if (quote_char) {
- RAISE_SYNTAX_ERROR("f-string: unterminated string");
- goto error;
- }
- if (nested_depth) {
- int opening = (unsigned char)parenstack[nested_depth - 1];
- RAISE_SYNTAX_ERROR("f-string: unmatched '%c'", opening);
- goto error;
- }
-
- if (*str >= end) {
- goto unexpected_end_of_string;
- }
-
- /* Compile the expression as soon as possible, so we show errors
- related to the expression before errors related to the
- conversion or format_spec. */
- simple_expression = fstring_compile_expr(p, expr_start, expr_end, t);
- if (!simple_expression) {
- goto error;
- }
-
- /* Check for =, which puts the text value of the expression in
- expr_text. */
- if (**str == '=') {
- if (p->feature_version < 8) {
- RAISE_SYNTAX_ERROR("f-string: self documenting expressions are "
- "only supported in Python 3.8 and greater");
- goto error;
- }
- *str += 1;
-
- /* Skip over ASCII whitespace. No need to test for end of string
- here, since we know there's at least a trailing quote somewhere
- ahead. */
- while (Py_ISSPACE(**str)) {
- *str += 1;
- }
- if (*str >= end) {
- goto unexpected_end_of_string;
- }
- /* Set *expr_text to the text of the expression. */
- *expr_text = PyUnicode_FromStringAndSize(expr_start, *str-expr_start);
- if (!*expr_text) {
- goto error;
- }
- }
-
- /* Check for a conversion char, if present. */
- if (**str == '!') {
- *str += 1;
- const char *conv_start = *str;
- while (1) {
- if (*str >= end) {
- goto unexpected_end_of_string;
- }
- if (**str == '}' || **str == ':') {
- break;
- }
- *str += 1;
- }
- if (*str == conv_start) {
- RAISE_SYNTAX_ERROR(
- "f-string: missed conversion character");
- goto error;
- }
-
- conversion = (unsigned char)*conv_start;
- /* Validate the conversion. */
- if ((*str != conv_start + 1) ||
- !(conversion == 's' || conversion == 'r' || conversion == 'a'))
- {
- PyObject *conv_obj = PyUnicode_FromStringAndSize(conv_start,
- *str-conv_start);
- if (conv_obj) {
- RAISE_SYNTAX_ERROR(
- "f-string: invalid conversion character %R: "
- "expected 's', 'r', or 'a'",
- conv_obj);
- Py_DECREF(conv_obj);
- }
- goto error;
- }
-
- }
-
- /* Check for the format spec, if present. */
- assert(*str < end);
- if (**str == ':') {
- *str += 1;
- if (*str >= end) {
- goto unexpected_end_of_string;
- }
-
- /* Parse the format spec. */
- format_spec = fstring_parse(p, str, end, raw, recurse_lvl+1,
- first_token, t, last_token);
- if (!format_spec) {
- goto error;
- }
- }
-
- if (*str >= end || **str != '}') {
- goto unexpected_end_of_string;
- }
-
- /* We're at a right brace. Consume it. */
- assert(*str < end);
- assert(**str == '}');
- *str += 1;
-
- /* If we're in = mode (detected by non-NULL expr_text), and have no format
- spec and no explicit conversion, set the conversion to 'r'. */
- if (*expr_text && format_spec == NULL && conversion == -1) {
- conversion = 'r';
- }
-
- /* And now create the FormattedValue node that represents this
- entire expression with the conversion and format spec. */
- //TODO: Fix this
- *expression = _PyAST_FormattedValue(simple_expression, conversion,
- format_spec, first_token->lineno,
- first_token->col_offset,
- last_token->end_lineno,
- last_token->end_col_offset, p->arena);
- if (!*expression) {
- goto error;
- }
-
- return 0;
-
-unexpected_end_of_string:
- RAISE_SYNTAX_ERROR("f-string: expecting '}'");
- /* Falls through to error. */
-
-error:
- Py_XDECREF(*expr_text);
- return -1;
-
-}
-
-/* Return -1 on error.
-
- Return 0 if we have a literal (possible zero length) and an
- expression (zero length if at the end of the string.
-
- Return 1 if we have a literal, but no expression, and we want the
- caller to call us again. This is used to deal with doubled
- braces.
-
- When called multiple times on the string 'a{{b{0}c', this function
- will return:
-
- 1. the literal 'a{' with no expression, and a return value
- of 1. Despite the fact that there's no expression, the return
- value of 1 means we're not finished yet.
-
- 2. the literal 'b' and the expression '0', with a return value of
- 0. The fact that there's an expression means we're not finished.
-
- 3. literal 'c' with no expression and a return value of 0. The
- combination of the return value of 0 with no expression means
- we're finished.
-*/
-static int
-fstring_find_literal_and_expr(Parser *p, const char **str, const char *end, int raw,
- int recurse_lvl, PyObject **literal,
- PyObject **expr_text, expr_ty *expression,
- Token *first_token, Token *t, Token *last_token)
-{
- int result;
-
- assert(*literal == NULL && *expression == NULL);
-
- /* Get any literal string. */
- result = fstring_find_literal(p, str, end, raw, literal, recurse_lvl, t);
- if (result < 0) {
- goto error;
- }
-
- assert(result == 0 || result == 1);
-
- if (result == 1) {
- /* We have a literal, but don't look at the expression. */
- return 1;
- }
-
- if (*str >= end || **str == '}') {
- /* We're at the end of the string or the end of a nested
- f-string: no expression. The top-level error case where we
- expect to be at the end of the string but we're at a '}' is
- handled later. */
- return 0;
- }
-
- /* We must now be the start of an expression, on a '{'. */
- assert(**str == '{');
-
- if (fstring_find_expr(p, str, end, raw, recurse_lvl, expr_text,
- expression, first_token, t, last_token) < 0) {
- goto error;
- }
-
- return 0;
-
-error:
- Py_CLEAR(*literal);
- return -1;
-}
-
-#ifdef NDEBUG
-#define ExprList_check_invariants(l)
-#else
-static void
-ExprList_check_invariants(ExprList *l)
-{
- /* Check our invariants. Make sure this object is "live", and
- hasn't been deallocated. */
- assert(l->size >= 0);
- assert(l->p != NULL);
- if (l->size <= EXPRLIST_N_CACHED) {
- assert(l->data == l->p);
- }
-}
-#endif
-
-static void
-ExprList_Init(ExprList *l)
-{
- l->allocated = EXPRLIST_N_CACHED;
- l->size = 0;
-
- /* Until we start allocating dynamically, p points to data. */
- l->p = l->data;
-
- ExprList_check_invariants(l);
-}
-
-static int
-ExprList_Append(ExprList *l, expr_ty exp)
-{
- ExprList_check_invariants(l);
- if (l->size >= l->allocated) {
- /* We need to alloc (or realloc) the memory. */
- Py_ssize_t new_size = l->allocated * 2;
-
- /* See if we've ever allocated anything dynamically. */
- if (l->p == l->data) {
- Py_ssize_t i;
- /* We're still using the cached data. Switch to
- alloc-ing. */
- l->p = PyMem_Malloc(sizeof(expr_ty) * new_size);
- if (!l->p) {
- return -1;
- }
- /* Copy the cached data into the new buffer. */
- for (i = 0; i < l->size; i++) {
- l->p[i] = l->data[i];
- }
- } else {
- /* Just realloc. */
- expr_ty *tmp = PyMem_Realloc(l->p, sizeof(expr_ty) * new_size);
- if (!tmp) {
- PyMem_Free(l->p);
- l->p = NULL;
- return -1;
- }
- l->p = tmp;
- }
-
- l->allocated = new_size;
- assert(l->allocated == 2 * l->size);
- }
-
- l->p[l->size++] = exp;
-
- ExprList_check_invariants(l);
- return 0;
-}
-
-static void
-ExprList_Dealloc(ExprList *l)
-{
- ExprList_check_invariants(l);
-
- /* If there's been an error, or we've never dynamically allocated,
- do nothing. */
- if (!l->p || l->p == l->data) {
- /* Do nothing. */
- } else {
- /* We have dynamically allocated. Free the memory. */
- PyMem_Free(l->p);
- }
- l->p = NULL;
- l->size = -1;
-}
-
-static asdl_expr_seq *
-ExprList_Finish(ExprList *l, PyArena *arena)
-{
- asdl_expr_seq *seq;
-
- ExprList_check_invariants(l);
-
- /* Allocate the asdl_seq and copy the expressions in to it. */
- seq = _Py_asdl_expr_seq_new(l->size, arena);
- if (seq) {
- Py_ssize_t i;
- for (i = 0; i < l->size; i++) {
- asdl_seq_SET(seq, i, l->p[i]);
- }
- }
- ExprList_Dealloc(l);
- return seq;
-}
-
-#ifdef NDEBUG
-#define FstringParser_check_invariants(state)
-#else
-static void
-FstringParser_check_invariants(FstringParser *state)
-{
- if (state->last_str) {
- assert(PyUnicode_CheckExact(state->last_str));
- }
- ExprList_check_invariants(&state->expr_list);
-}
-#endif
-
-void
-_PyPegen_FstringParser_Init(FstringParser *state)
-{
- state->last_str = NULL;
- state->fmode = 0;
- ExprList_Init(&state->expr_list);
- FstringParser_check_invariants(state);
-}
-
-void
-_PyPegen_FstringParser_Dealloc(FstringParser *state)
-{
- FstringParser_check_invariants(state);
-
- Py_XDECREF(state->last_str);
- ExprList_Dealloc(&state->expr_list);
-}
-
-/* Make a Constant node, but decref the PyUnicode object being added. */
-static expr_ty
-make_str_node_and_del(Parser *p, PyObject **str, Token* first_token, Token *last_token)
-{
- PyObject *s = *str;
- PyObject *kind = NULL;
- *str = NULL;
- assert(PyUnicode_CheckExact(s));
- if (_PyArena_AddPyObject(p->arena, s) < 0) {
- Py_DECREF(s);
- return NULL;
- }
- const char* the_str = PyBytes_AsString(first_token->bytes);
- if (the_str && the_str[0] == 'u') {
- kind = _PyPegen_new_identifier(p, "u");
- }
-
- if (kind == NULL && PyErr_Occurred()) {
- return NULL;
- }
-
- return _PyAST_Constant(s, kind, first_token->lineno, first_token->col_offset,
- last_token->end_lineno, last_token->end_col_offset,
- p->arena);
-
-}
-
-
-/* Add a non-f-string (that is, a regular literal string). str is
- decref'd. */
-int
-_PyPegen_FstringParser_ConcatAndDel(FstringParser *state, PyObject *str)
-{
- FstringParser_check_invariants(state);
-
- assert(PyUnicode_CheckExact(str));
-
- if (PyUnicode_GET_LENGTH(str) == 0) {
- Py_DECREF(str);
- return 0;
- }
-
- if (!state->last_str) {
- /* We didn't have a string before, so just remember this one. */
- state->last_str = str;
- } else {
- /* Concatenate this with the previous string. */
- PyUnicode_AppendAndDel(&state->last_str, str);
- if (!state->last_str) {
- return -1;
- }
- }
- FstringParser_check_invariants(state);
- return 0;
-}
-
-/* Parse an f-string. The f-string is in *str to end, with no
- 'f' or quotes. */
-int
-_PyPegen_FstringParser_ConcatFstring(Parser *p, FstringParser *state, const char **str,
- const char *end, int raw, int recurse_lvl,
- Token *first_token, Token* t, Token *last_token)
-{
- FstringParser_check_invariants(state);
- state->fmode = 1;
-
- /* Parse the f-string. */
- while (1) {
- PyObject *literal = NULL;
- PyObject *expr_text = NULL;
- expr_ty expression = NULL;
-
- /* If there's a zero length literal in front of the
- expression, literal will be NULL. If we're at the end of
- the f-string, expression will be NULL (unless result == 1,
- see below). */
- int result = fstring_find_literal_and_expr(p, str, end, raw, recurse_lvl,
- &literal, &expr_text,
- &expression, first_token, t, last_token);
- if (result < 0) {
- return -1;
- }
-
- /* Add the literal, if any. */
- if (literal && _PyPegen_FstringParser_ConcatAndDel(state, literal) < 0) {
- Py_XDECREF(expr_text);
- return -1;
- }
- /* Add the expr_text, if any. */
- if (expr_text && _PyPegen_FstringParser_ConcatAndDel(state, expr_text) < 0) {
- return -1;
- }
-
- /* We've dealt with the literal and expr_text, their ownership has
- been transferred to the state object. Don't look at them again. */
-
- /* See if we should just loop around to get the next literal
- and expression, while ignoring the expression this
- time. This is used for un-doubling braces, as an
- optimization. */
- if (result == 1) {
- continue;
- }
-
- if (!expression) {
- /* We're done with this f-string. */
- break;
- }
-
- /* We know we have an expression. Convert any existing string
- to a Constant node. */
- if (state->last_str) {
- /* Convert the existing last_str literal to a Constant node. */
- expr_ty last_str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
- if (!last_str || ExprList_Append(&state->expr_list, last_str) < 0) {
- return -1;
- }
- }
-
- if (ExprList_Append(&state->expr_list, expression) < 0) {
- return -1;
- }
- }
-
- /* If recurse_lvl is zero, then we must be at the end of the
- string. Otherwise, we must be at a right brace. */
-
- if (recurse_lvl == 0 && *str < end-1) {
- RAISE_SYNTAX_ERROR("f-string: unexpected end of string");
- return -1;
- }
- if (recurse_lvl != 0 && **str != '}') {
- RAISE_SYNTAX_ERROR("f-string: expecting '}'");
- return -1;
- }
-
- FstringParser_check_invariants(state);
- return 0;
-}
-
-/* Convert the partial state reflected in last_str and expr_list to an
- expr_ty. The expr_ty can be a Constant, or a JoinedStr. */
-expr_ty
-_PyPegen_FstringParser_Finish(Parser *p, FstringParser *state, Token* first_token,
- Token *last_token)
-{
- asdl_expr_seq *seq;
-
- FstringParser_check_invariants(state);
-
- /* If we're just a constant string with no expressions, return
- that. */
- if (!state->fmode) {
- assert(!state->expr_list.size);
- if (!state->last_str) {
- /* Create a zero length string. */
- state->last_str = PyUnicode_FromStringAndSize(NULL, 0);
- if (!state->last_str) {
- goto error;
+ return NULL;
}
}
- return make_str_node_and_del(p, &state->last_str, first_token, last_token);
- }
-
- /* Create a Constant node out of last_str, if needed. It will be the
- last node in our expression list. */
- if (state->last_str) {
- expr_ty str = make_str_node_and_del(p, &state->last_str, first_token, last_token);
- if (!str || ExprList_Append(&state->expr_list, str) < 0) {
- goto error;
+ if (rawmode) {
+ return PyBytes_FromStringAndSize(s, len);
}
+ return decode_bytes_with_escapes(p, s, len, t);
}
- /* This has already been freed. */
- assert(state->last_str == NULL);
-
- seq = ExprList_Finish(&state->expr_list, p->arena);
- if (!seq) {
- goto error;
- }
-
- return _PyAST_JoinedStr(seq, first_token->lineno, first_token->col_offset,
- last_token->end_lineno, last_token->end_col_offset,
- p->arena);
-
-error:
- _PyPegen_FstringParser_Dealloc(state);
- return NULL;
-}
-
-/* Given an f-string (with no 'f' or quotes) that's in *str and ends
- at end, parse it into an expr_ty. Return NULL on error. Adjust
- str to point past the parsed portion. */
-static expr_ty
-fstring_parse(Parser *p, const char **str, const char *end, int raw,
- int recurse_lvl, Token *first_token, Token* t, Token *last_token)
-{
- FstringParser state;
-
- _PyPegen_FstringParser_Init(&state);
- if (_PyPegen_FstringParser_ConcatFstring(p, &state, str, end, raw, recurse_lvl,
- first_token, t, last_token) < 0) {
- _PyPegen_FstringParser_Dealloc(&state);
- return NULL;
- }
-
- return _PyPegen_FstringParser_Finish(p, &state, t, t);
+ return _PyPegen_decode_string(p, rawmode, s, len, t);
}
diff --git a/Parser/string_parser.h b/Parser/string_parser.h
index 4a22f3d3086f47..0b34de1b4e41e9 100644
--- a/Parser/string_parser.h
+++ b/Parser/string_parser.h
@@ -5,42 +5,7 @@
#include
#include "pegen.h"
-#define EXPRLIST_N_CACHED 64
-
-typedef struct {
- /* Incrementally build an array of expr_ty, so be used in an
- asdl_seq. Cache some small but reasonably sized number of
- expr_ty's, and then after that start dynamically allocating,
- doubling the number allocated each time. Note that the f-string
- f'{0}a{1}' contains 3 expr_ty's: 2 FormattedValue's, and one
- Constant for the literal 'a'. So you add expr_ty's about twice as
- fast as you add expressions in an f-string. */
-
- Py_ssize_t allocated; /* Number we've allocated. */
- Py_ssize_t size; /* Number we've used. */
- expr_ty *p; /* Pointer to the memory we're actually
- using. Will point to 'data' until we
- start dynamically allocating. */
- expr_ty data[EXPRLIST_N_CACHED];
-} ExprList;
-
-/* The FstringParser is designed to add a mix of strings and
- f-strings, and concat them together as needed. Ultimately, it
- generates an expr_ty. */
-typedef struct {
- PyObject *last_str;
- ExprList expr_list;
- int fmode;
-} FstringParser;
-
-void _PyPegen_FstringParser_Init(FstringParser *);
-int _PyPegen_parsestr(Parser *, int *, int *, PyObject **,
- const char **, Py_ssize_t *, Token *);
-int _PyPegen_FstringParser_ConcatFstring(Parser *, FstringParser *, const char **,
- const char *, int, int, Token *, Token *,
- Token *);
-int _PyPegen_FstringParser_ConcatAndDel(FstringParser *, PyObject *);
-expr_ty _PyPegen_FstringParser_Finish(Parser *, FstringParser *, Token *, Token *);
-void _PyPegen_FstringParser_Dealloc(FstringParser *);
+PyObject *_PyPegen_parse_string(Parser *, Token *);
+PyObject *_PyPegen_decode_string(Parser *, int, const char *, size_t, Token *);
#endif
diff --git a/Parser/token.c b/Parser/token.c
index 6299ad2f563144..82267fbfcd0c54 100644
--- a/Parser/token.c
+++ b/Parser/token.c
@@ -60,12 +60,16 @@ const char * const _PyParser_TokenNames[] = {
"RARROW",
"ELLIPSIS",
"COLONEQUAL",
+ "EXCLAMATION",
"OP",
"AWAIT",
"ASYNC",
"TYPE_IGNORE",
"TYPE_COMMENT",
"SOFT_KEYWORD",
+ "FSTRING_START",
+ "FSTRING_MIDDLE",
+ "FSTRING_END",
"",
"",
"",
@@ -79,6 +83,7 @@ int
_PyToken_OneChar(int c1)
{
switch (c1) {
+ case '!': return EXCLAMATION;
case '%': return PERCENT;
case '&': return AMPER;
case '(': return LPAR;
diff --git a/Parser/tokenizer.c b/Parser/tokenizer.c
index 463c0e00ca1411..a8649b8547e256 100644
--- a/Parser/tokenizer.c
+++ b/Parser/tokenizer.c
@@ -11,11 +11,6 @@
#include "tokenizer.h"
#include "errcode.h"
-#include "unicodeobject.h"
-#include "bytesobject.h"
-#include "fileobject.h"
-#include "abstract.h"
-
/* Alternate tab spacing */
#define ALTTABSIZE 1
@@ -43,6 +38,24 @@
tok->lineno++; \
tok->col_offset = 0;
+#define INSIDE_FSTRING(tok) (tok->tok_mode_stack_index > 0)
+#define INSIDE_FSTRING_EXPR(tok) (tok->curly_bracket_expr_start_depth >= 0)
+#ifdef Py_DEBUG
+static inline tokenizer_mode* TOK_GET_MODE(struct tok_state* tok) {
+ assert(tok->tok_mode_stack_index >= 0);
+ assert(tok->tok_mode_stack_index < MAXLEVEL);
+ return &(tok->tok_mode_stack[tok->tok_mode_stack_index]);
+}
+static inline tokenizer_mode* TOK_NEXT_MODE(struct tok_state* tok) {
+ assert(tok->tok_mode_stack_index >= 0);
+ assert(tok->tok_mode_stack_index < MAXLEVEL);
+ return &(tok->tok_mode_stack[++tok->tok_mode_stack_index]);
+}
+#else
+#define TOK_GET_MODE(tok) (&(tok->tok_mode_stack[tok->tok_mode_stack_index]))
+#define TOK_NEXT_MODE(tok) (&(tok->tok_mode_stack[++tok->tok_mode_stack_index]))
+#endif
+
/* Forward */
static struct tok_state *tok_new(void);
static int tok_nextc(struct tok_state *tok);
@@ -98,6 +111,9 @@ tok_new(void)
tok->interactive_underflow = IUNDERFLOW_NORMAL;
tok->str = NULL;
tok->report_warnings = 1;
+ tok->tok_mode_stack[0] = (tokenizer_mode){.kind =TOK_REGULAR_MODE, .f_string_quote='\0', .f_string_quote_size = 0};
+ tok->tok_mode_stack_index = 0;
+ tok->tok_report_warnings = 1;
#ifdef Py_DEBUG
tok->debug = _Py_GetConfig()->parser_debug;
#endif
@@ -345,6 +361,104 @@ tok_concatenate_interactive_new_line(struct tok_state *tok, const char *line) {
return 0;
}
+/* Traverse and remember all f-string buffers, in order to be able to restore
+ them after reallocating tok->buf */
+static void
+remember_fstring_buffers(struct tok_state *tok)
+{
+ int index;
+ tokenizer_mode *mode;
+
+ for (index = tok->tok_mode_stack_index; index >= 0; --index) {
+ mode = &(tok->tok_mode_stack[index]);
+ mode->f_string_start_offset = mode->f_string_start - tok->buf;
+ mode->f_string_multi_line_start_offset = mode->f_string_multi_line_start - tok->buf;
+ }
+}
+
+/* Traverse and restore all f-string buffers after reallocating tok->buf */
+static void
+restore_fstring_buffers(struct tok_state *tok)
+{
+ int index;
+ tokenizer_mode *mode;
+
+ for (index = tok->tok_mode_stack_index; index >= 0; --index) {
+ mode = &(tok->tok_mode_stack[index]);
+ mode->f_string_start = tok->buf + mode->f_string_start_offset;
+ mode->f_string_multi_line_start = tok->buf + mode->f_string_multi_line_start_offset;
+ }
+}
+
+static int
+update_fstring_expr(struct tok_state *tok, char cur)
+{
+ assert(tok->cur != NULL);
+
+ Py_ssize_t size = strlen(tok->cur);
+ tokenizer_mode *tok_mode = TOK_GET_MODE(tok);
+
+ switch (cur) {
+ case 0:
+ if (!tok_mode->last_expr_buffer || tok_mode->last_expr_end >= 0) {
+ return 1;
+ }
+ char *new_buffer = PyMem_Realloc(
+ tok_mode->last_expr_buffer,
+ tok_mode->last_expr_size + size
+ );
+ if (new_buffer == NULL) {
+ PyMem_Free(tok_mode->last_expr_buffer);
+ goto error;
+ }
+ tok_mode->last_expr_buffer = new_buffer;
+ strncpy(tok_mode->last_expr_buffer + tok_mode->last_expr_size, tok->cur, size);
+ tok_mode->last_expr_size += size;
+ break;
+ case '{':
+ if (tok_mode->last_expr_buffer != NULL) {
+ PyMem_Free(tok_mode->last_expr_buffer);
+ }
+ tok_mode->last_expr_buffer = PyMem_Malloc(size);
+ if (tok_mode->last_expr_buffer == NULL) {
+ goto error;
+ }
+ tok_mode->last_expr_size = size;
+ tok_mode->last_expr_end = -1;
+ strncpy(tok_mode->last_expr_buffer, tok->cur, size);
+ break;
+ case '}':
+ case '!':
+ case ':':
+ if (tok_mode->last_expr_end == -1) {
+ tok_mode->last_expr_end = strlen(tok->start);
+ }
+ break;
+ default:
+ Py_UNREACHABLE();
+ }
+ return 1;
+error:
+ tok->done = E_NOMEM;
+ return 0;
+}
+
+static void
+free_fstring_expressions(struct tok_state *tok)
+{
+ int index;
+ tokenizer_mode *mode;
+
+ for (index = tok->tok_mode_stack_index; index >= 0; --index) {
+ mode = &(tok->tok_mode_stack[index]);
+ if (mode->last_expr_buffer != NULL) {
+ PyMem_Free(mode->last_expr_buffer);
+ mode->last_expr_buffer = NULL;
+ mode->last_expr_size = 0;
+ mode->last_expr_end = -1;
+ }
+ }
+}
/* Read a line of text from TOK into S, using the stream in TOK.
Return NULL on failure, else S.
@@ -372,6 +486,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size)
Py_ssize_t start = tok->start == NULL ? -1 : tok->start - tok->buf;
Py_ssize_t line_start = tok->start == NULL ? -1 : tok->line_start - tok->buf;
Py_ssize_t multi_line_start = tok->multi_line_start - tok->buf;
+ remember_fstring_buffers(tok);
newbuf = (char *)PyMem_Realloc(newbuf, newsize);
if (newbuf == NULL) {
tok->done = E_NOMEM;
@@ -384,6 +499,7 @@ tok_reserve_buf(struct tok_state *tok, Py_ssize_t size)
tok->start = start < 0 ? NULL : tok->buf + start;
tok->line_start = line_start < 0 ? NULL : tok->buf + line_start;
tok->multi_line_start = multi_line_start < 0 ? NULL : tok->buf + multi_line_start;
+ restore_fstring_buffers(tok);
}
return 1;
}
@@ -838,6 +954,7 @@ _PyTokenizer_Free(struct tok_state *tok)
if (tok->interactive_src_start != NULL) {
PyMem_Free(tok->interactive_src_start);
}
+ free_fstring_expressions(tok);
PyMem_Free(tok);
}
@@ -854,6 +971,9 @@ tok_readline_raw(struct tok_state *tok)
if (line == NULL) {
return 1;
}
+ if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) {
+ return 0;
+ }
if (tok->fp_interactive &&
tok_concatenate_interactive_new_line(tok, line) == -1) {
return 0;
@@ -941,6 +1061,7 @@ tok_underflow_interactive(struct tok_state *tok) {
}
else if (tok->start != NULL) {
Py_ssize_t cur_multi_line_start = tok->multi_line_start - tok->buf;
+ remember_fstring_buffers(tok);
size_t size = strlen(newtok);
ADVANCE_LINENO();
if (!tok_reserve_buf(tok, size + 1)) {
@@ -953,8 +1074,10 @@ tok_underflow_interactive(struct tok_state *tok) {
PyMem_Free(newtok);
tok->inp += size;
tok->multi_line_start = tok->buf + cur_multi_line_start;
+ restore_fstring_buffers(tok);
}
else {
+ remember_fstring_buffers(tok);
ADVANCE_LINENO();
PyMem_Free(tok->buf);
tok->buf = newtok;
@@ -962,6 +1085,7 @@ tok_underflow_interactive(struct tok_state *tok) {
tok->line_start = tok->buf;
tok->inp = strchr(tok->buf, '\0');
tok->end = tok->inp + 1;
+ restore_fstring_buffers(tok);
}
if (tok->done != E_OK) {
if (tok->prompt != NULL) {
@@ -969,6 +1093,10 @@ tok_underflow_interactive(struct tok_state *tok) {
}
return 0;
}
+
+ if (tok->tok_mode_stack_index && !update_fstring_expr(tok, 0)) {
+ return 0;
+ }
return 1;
}
@@ -1073,7 +1201,7 @@ tok_nextc(struct tok_state *tok)
return Py_CHARMASK(*tok->cur++); /* Fast path */
}
if (tok->done != E_OK) {
- return EOF;
+ return EOF;
}
if (tok->fp == NULL) {
rc = tok_underflow_string(tok);
@@ -1115,7 +1243,7 @@ tok_backup(struct tok_state *tok, int c)
if (--tok->cur < tok->buf) {
Py_FatalError("tokenizer beginning of buffer");
}
- if ((int)(unsigned char)*tok->cur != c) {
+ if ((int)(unsigned char)*tok->cur != Py_CHARMASK(c)) {
Py_FatalError("tok_backup: wrong character");
}
tok->col_offset--;
@@ -1172,6 +1300,7 @@ _syntaxerror_range(struct tok_state *tok, const char *format,
static int
syntaxerror(struct tok_state *tok, const char *format, ...)
{
+ // This errors are cleaned on startup. Todo: Fix it.
va_list vargs;
va_start(vargs, format);
int ret = _syntaxerror_range(tok, format, -1, -1, vargs);
@@ -1234,6 +1363,41 @@ parser_warn(struct tok_state *tok, PyObject *category, const char *format, ...)
return -1;
}
+static int
+warn_invalid_escape_sequence(struct tok_state *tok, int first_invalid_escape_char)
+{
+
+ if (!tok->tok_report_warnings) {
+ return 0;
+ }
+
+ PyObject *msg = PyUnicode_FromFormat(
+ "invalid escape sequence '\\%c'",
+ (char) first_invalid_escape_char
+ );
+
+ if (msg == NULL) {
+ return -1;
+ }
+
+ if (PyErr_WarnExplicitObject(PyExc_DeprecationWarning, msg, tok->filename,
+ tok->lineno, NULL, NULL) < 0) {
+ Py_DECREF(msg);
+
+ if (PyErr_ExceptionMatches(PyExc_DeprecationWarning)) {
+ /* Replace the DeprecationWarning exception with a SyntaxError
+ to get a more accurate error report */
+ PyErr_Clear();
+ return syntaxerror(tok, "invalid escape sequence '\\%c'", (char) first_invalid_escape_char);
+ }
+
+ return -1;
+ }
+
+ Py_DECREF(msg);
+ return 0;
+}
+
static int
lookahead(struct tok_state *tok, const char *test)
{
@@ -1389,7 +1553,6 @@ tok_decimal_tail(struct tok_state *tok)
return c;
}
-/* Get next token, after space stripping etc. */
static inline int
tok_continuation_line(struct tok_state *tok) {
@@ -1427,7 +1590,12 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st
{
assert((start == NULL && end == NULL) || (start != NULL && end != NULL));
token->level = tok->level;
- token->lineno = type == STRING ? tok->first_lineno : tok->lineno;
+ if (ISSTRINGLIT(type)) {
+ token->lineno = tok->first_lineno;
+ }
+ else {
+ token->lineno = tok->lineno;
+ }
token->end_lineno = tok->lineno;
token->col_offset = token->end_col_offset = -1;
token->start = start;
@@ -1441,7 +1609,7 @@ token_setup(struct tok_state *tok, struct token *token, int type, const char *st
}
static int
-tok_get(struct tok_state *tok, struct token *token)
+tok_get_normal_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token)
{
int c;
int blankline, nonascii;
@@ -1602,6 +1770,11 @@ tok_get(struct tok_state *tok, struct token *token)
/* Skip comment, unless it's a type comment */
if (c == '#') {
+
+ if (INSIDE_FSTRING(tok)) {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string expression part cannot include '#'"));
+ }
+
const char *prefix, *p, *type_start;
int current_starting_col_offset;
@@ -1703,6 +1876,9 @@ tok_get(struct tok_state *tok, struct token *token)
}
c = tok_nextc(tok);
if (c == '"' || c == '\'') {
+ if (saw_f) {
+ goto f_string_quote;
+ }
goto letter_quote;
}
}
@@ -1748,7 +1924,9 @@ tok_get(struct tok_state *tok, struct token *token)
int ahead_tok_kind;
memcpy(&ahead_tok, tok, sizeof(ahead_tok));
- ahead_tok_kind = tok_get(&ahead_tok, &ahead_token);
+ ahead_tok_kind = tok_get_normal_mode(&ahead_tok,
+ current_tok,
+ &ahead_token);
if (ahead_tok_kind == NAME
&& ahead_tok.cur - ahead_tok.start == 3
@@ -2003,6 +2181,68 @@ tok_get(struct tok_state *tok, struct token *token)
return MAKE_TOKEN(NUMBER);
}
+ f_string_quote:
+ if (((tolower(*tok->start) == 'f' || tolower(*tok->start) == 'r') && (c == '\'' || c == '"'))) {
+ int quote = c;
+ int quote_size = 1; /* 1 or 3 */
+
+ /* Nodes of type STRING, especially multi line strings
+ must be handled differently in order to get both
+ the starting line number and the column offset right.
+ (cf. issue 16806) */
+ tok->first_lineno = tok->lineno;
+ tok->multi_line_start = tok->line_start;
+
+ /* Find the quote size and start of string */
+ int after_quote = tok_nextc(tok);
+ if (after_quote == quote) {
+ int after_after_quote = tok_nextc(tok);
+ if (after_after_quote == quote) {
+ quote_size = 3;
+ }
+ else {
+ // TODO: Check this
+ tok_backup(tok, after_after_quote);
+ tok_backup(tok, after_quote);
+ }
+ }
+ if (after_quote != quote) {
+ tok_backup(tok, after_quote);
+ }
+
+
+ p_start = tok->start;
+ p_end = tok->cur;
+ tokenizer_mode *the_current_tok = TOK_NEXT_MODE(tok);
+ the_current_tok->kind = TOK_FSTRING_MODE;
+ the_current_tok->f_string_quote = quote;
+ the_current_tok->f_string_quote_size = quote_size;
+ the_current_tok->f_string_start = tok->start;
+ the_current_tok->f_string_multi_line_start = tok->line_start;
+ the_current_tok->f_string_start_offset = -1;
+ the_current_tok->f_string_multi_line_start_offset = -1;
+ the_current_tok->last_expr_buffer = NULL;
+ the_current_tok->last_expr_size = 0;
+ the_current_tok->last_expr_end = -1;
+
+ switch (*tok->start) {
+ case 'F':
+ case 'f':
+ the_current_tok->f_string_raw = tolower(*(tok->start + 1)) == 'r';
+ break;
+ case 'R':
+ case 'r':
+ the_current_tok->f_string_raw = 1;
+ break;
+ default:
+ Py_UNREACHABLE();
+ }
+
+ the_current_tok->curly_bracket_depth = 0;
+ the_current_tok->curly_bracket_expr_start_depth = -1;
+ return MAKE_TOKEN(FSTRING_START);
+ }
+
letter_quote:
/* String */
if (c == '\'' || c == '"') {
@@ -2047,6 +2287,20 @@ tok_get(struct tok_state *tok, struct token *token)
tok->line_start = tok->multi_line_start;
int start = tok->lineno;
tok->lineno = tok->first_lineno;
+
+ if (INSIDE_FSTRING(tok)) {
+ /* When we are in an f-string, before raising the
+ * unterminated string literal error, check whether
+ * does the initial quote matches with f-strings quotes
+ * and if it is, then this must be a missing '}' token
+ * so raise the proper error */
+ tokenizer_mode *the_current_tok = TOK_GET_MODE(tok);
+ if (the_current_tok->f_string_quote == quote &&
+ the_current_tok->f_string_quote_size == quote_size) {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string: expecting '}'", start));
+ }
+ }
+
if (quote_size == 3) {
syntaxerror(tok, "unterminated triple-quoted string literal"
" (detected at line %d)", start);
@@ -2089,6 +2343,26 @@ tok_get(struct tok_state *tok, struct token *token)
goto again; /* Read next line */
}
+ /* Punctuation character */
+ int is_punctuation = (c == ':' || c == '}' || c == '!' || c == '{');
+ if (is_punctuation && INSIDE_FSTRING(tok) && INSIDE_FSTRING_EXPR(current_tok)) {
+ /* This code block gets executed before the curly_bracket_depth is incremented
+ * by the `{` case, so for ensuring that we are on the 0th level, we need
+ * to adjust it manually */
+ int cursor = current_tok->curly_bracket_depth - (c != '{');
+
+ if (cursor == 0 && !update_fstring_expr(tok, c)) {
+ return MAKE_TOKEN(ENDMARKER);
+ }
+
+ if (c == ':' && cursor == current_tok->curly_bracket_expr_start_depth) {
+ current_tok->kind = TOK_FSTRING_MODE;
+ p_start = tok->start;
+ p_end = tok->cur;
+ return MAKE_TOKEN(_PyToken_OneChar(c));
+ }
+ }
+
/* Check for two-character token */
{
int c2 = tok_nextc(tok);
@@ -2121,11 +2395,17 @@ tok_get(struct tok_state *tok, struct token *token)
tok->parenlinenostack[tok->level] = tok->lineno;
tok->parencolstack[tok->level] = (int)(tok->start - tok->line_start);
tok->level++;
+ if (INSIDE_FSTRING(tok)) {
+ current_tok->curly_bracket_depth++;
+ }
break;
case ')':
case ']':
case '}':
if (!tok->level) {
+ if (INSIDE_FSTRING(tok) && !current_tok->curly_bracket_depth && c == '}') {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string: single '}' is not allowed"));
+ }
return MAKE_TOKEN(syntaxerror(tok, "unmatched '%c'", c));
}
tok->level--;
@@ -2134,6 +2414,18 @@ tok_get(struct tok_state *tok, struct token *token)
(opening == '[' && c == ']') ||
(opening == '{' && c == '}')))
{
+ /* If the opening bracket belongs to an f-string's expression
+ part (e.g. f"{)}") and the closing bracket is an arbitrary
+ nested expression, then instead of matching a different
+ syntactical construct with it; we'll throw an unmatched
+ parentheses error. */
+ if (INSIDE_FSTRING(tok) && opening == '{') {
+ assert(current_tok->curly_bracket_depth >= 0);
+ int previous_bracket = current_tok->curly_bracket_depth - 1;
+ if (previous_bracket == current_tok->curly_bracket_expr_start_depth) {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string: unmatched '%c'", c));
+ }
+ }
if (tok->parenlinenostack[tok->level] != tok->lineno) {
return MAKE_TOKEN(syntaxerror(tok,
"closing parenthesis '%c' does not match "
@@ -2147,6 +2439,16 @@ tok_get(struct tok_state *tok, struct token *token)
c, opening));
}
}
+
+ if (INSIDE_FSTRING(tok)) {
+ current_tok->curly_bracket_depth--;
+ if (c == '}' && current_tok->curly_bracket_depth == current_tok->curly_bracket_expr_start_depth) {
+ current_tok->curly_bracket_expr_start_depth--;
+ current_tok->kind = TOK_FSTRING_MODE;
+ }
+ }
+ break;
+ default:
break;
}
@@ -2162,6 +2464,191 @@ tok_get(struct tok_state *tok, struct token *token)
return MAKE_TOKEN(_PyToken_OneChar(c));
}
+static int
+tok_get_fstring_mode(struct tok_state *tok, tokenizer_mode* current_tok, struct token *token)
+{
+ const char *p_start = NULL;
+ const char *p_end = NULL;
+ int end_quote_size = 0;
+ int unicode_escape = 0;
+
+ tok->start = tok->cur;
+ tok->first_lineno = tok->lineno;
+ tok->starting_col_offset = tok->col_offset;
+
+ // If we start with a bracket, we defer to the normal mode as there is nothing for us to tokenize
+ // before it.
+ int start_char = tok_nextc(tok);
+ if (start_char == '{') {
+ int peek1 = tok_nextc(tok);
+ tok_backup(tok, peek1);
+ tok_backup(tok, start_char);
+ if (peek1 != '{') {
+ current_tok->curly_bracket_expr_start_depth++;
+ if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply"));
+ }
+ TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE;
+ return tok_get_normal_mode(tok, current_tok, token);
+ }
+ }
+ else {
+ tok_backup(tok, start_char);
+ }
+
+ // Check if we are at the end of the string
+ for (int i = 0; i < current_tok->f_string_quote_size; i++) {
+ int quote = tok_nextc(tok);
+ if (quote != current_tok->f_string_quote) {
+ tok_backup(tok, quote);
+ goto f_string_middle;
+ }
+ }
+
+ if (current_tok->last_expr_buffer != NULL) {
+ PyMem_Free(current_tok->last_expr_buffer);
+ current_tok->last_expr_buffer = NULL;
+ current_tok->last_expr_size = 0;
+ current_tok->last_expr_end = -1;
+ }
+
+ p_start = tok->start;
+ p_end = tok->cur;
+ tok->tok_mode_stack_index--;
+ return MAKE_TOKEN(FSTRING_END);
+
+f_string_middle:
+
+ while (end_quote_size != current_tok->f_string_quote_size) {
+ int c = tok_nextc(tok);
+ if (c == EOF || (current_tok->f_string_quote_size == 1 && c == '\n')) {
+ assert(tok->multi_line_start != NULL);
+ // shift the tok_state's location into
+ // the start of string, and report the error
+ // from the initial quote character
+ tok->cur = (char *)current_tok->f_string_start;
+ tok->cur++;
+ tok->line_start = current_tok->f_string_multi_line_start;
+ int start = tok->lineno;
+ tok->lineno = tok->first_lineno;
+
+ if (current_tok->f_string_quote_size == 3) {
+ return MAKE_TOKEN(syntaxerror(tok,
+ "unterminated triple-quoted f-string literal"
+ " (detected at line %d)", start));
+ }
+ else {
+ return MAKE_TOKEN(syntaxerror(tok,
+ "unterminated f-string literal (detected at"
+ " line %d)", start));
+ }
+ }
+
+ if (c == current_tok->f_string_quote) {
+ end_quote_size += 1;
+ continue;
+ } else {
+ end_quote_size = 0;
+ }
+
+ int in_format_spec = (
+ current_tok->last_expr_end != -1
+ &&
+ INSIDE_FSTRING_EXPR(current_tok)
+ );
+ if (c == '{') {
+ int peek = tok_nextc(tok);
+ if (peek != '{' || in_format_spec) {
+ tok_backup(tok, peek);
+ tok_backup(tok, c);
+ current_tok->curly_bracket_expr_start_depth++;
+ if (current_tok->curly_bracket_expr_start_depth >= MAX_EXPR_NESTING) {
+ return MAKE_TOKEN(syntaxerror(tok, "f-string: expressions nested too deeply"));
+ }
+ TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE;
+ p_start = tok->start;
+ p_end = tok->cur;
+ } else {
+ p_start = tok->start;
+ p_end = tok->cur - 1;
+ }
+ return MAKE_TOKEN(FSTRING_MIDDLE);
+ } else if (c == '}') {
+ if (unicode_escape) {
+ p_start = tok->start;
+ p_end = tok->cur;
+ return MAKE_TOKEN(FSTRING_MIDDLE);
+ }
+ int peek = tok_nextc(tok);
+
+ // The tokenizer can only be in the format spec if we have already completed the expression
+ // scanning (indicated by the end of the expression being set) and we are not at the top level
+ // of the bracket stack (-1 is the top level). Since format specifiers can't legally use double
+ // brackets, we can bypass it here.
+ if (peek == '}' && !in_format_spec) {
+ p_start = tok->start;
+ p_end = tok->cur - 1;
+ } else {
+ tok_backup(tok, peek);
+ tok_backup(tok, c);
+ TOK_GET_MODE(tok)->kind = TOK_REGULAR_MODE;
+ p_start = tok->start;
+ p_end = tok->cur;
+ }
+ return MAKE_TOKEN(FSTRING_MIDDLE);
+ } else if (c == '\\') {
+ int peek = tok_nextc(tok);
+ // Special case when the backslash is right before a curly
+ // brace. We have to restore and return the control back
+ // to the loop for the next iteration.
+ if (peek == '{' || peek == '}') {
+ if (!current_tok->f_string_raw) {
+ if (warn_invalid_escape_sequence(tok, peek)) {
+ return MAKE_TOKEN(ERRORTOKEN);
+ }
+ }
+ tok_backup(tok, peek);
+ continue;
+ }
+
+ if (!current_tok->f_string_raw) {
+ if (peek == 'N') {
+ /* Handle named unicode escapes (\N{BULLET}) */
+ peek = tok_nextc(tok);
+ if (peek == '{') {
+ unicode_escape = 1;
+ } else {
+ tok_backup(tok, peek);
+ }
+ }
+ } /* else {
+ skip the escaped character
+ }*/
+ }
+ }
+
+ // Backup the f-string quotes to emit a final FSTRING_MIDDLE and
+ // add the quotes to the FSTRING_END in the next tokenizer iteration.
+ for (int i = 0; i < current_tok->f_string_quote_size; i++) {
+ tok_backup(tok, current_tok->f_string_quote);
+ }
+ p_start = tok->start;
+ p_end = tok->cur;
+ return MAKE_TOKEN(FSTRING_MIDDLE);
+}
+
+
+static int
+tok_get(struct tok_state *tok, struct token *token)
+{
+ tokenizer_mode *current_tok = TOK_GET_MODE(tok);
+ if (current_tok->kind == TOK_REGULAR_MODE) {
+ return tok_get_normal_mode(tok, current_tok, token);
+ } else {
+ return tok_get_fstring_mode(tok, current_tok, token);
+ }
+}
+
int
_PyTokenizer_Get(struct tok_state *tok, struct token *token)
{
diff --git a/Parser/tokenizer.h b/Parser/tokenizer.h
index 16a94d5f51d664..2b94aecce626c3 100644
--- a/Parser/tokenizer.h
+++ b/Parser/tokenizer.h
@@ -33,6 +33,33 @@ struct token {
const char *start, *end;
};
+enum tokenizer_mode_kind_t {
+ TOK_REGULAR_MODE,
+ TOK_FSTRING_MODE,
+};
+
+#define MAX_EXPR_NESTING 3
+
+typedef struct _tokenizer_mode {
+ enum tokenizer_mode_kind_t kind;
+
+ int curly_bracket_depth;
+ int curly_bracket_expr_start_depth;
+
+ char f_string_quote;
+ int f_string_quote_size;
+ int f_string_raw;
+ const char* f_string_start;
+ const char* f_string_multi_line_start;
+
+ Py_ssize_t f_string_start_offset;
+ Py_ssize_t f_string_multi_line_start_offset;
+
+ Py_ssize_t last_expr_size;
+ Py_ssize_t last_expr_end;
+ char* last_expr_buffer;
+} tokenizer_mode;
+
/* Tokenizer state */
struct tok_state {
/* Input state; buf <= cur <= inp <= end */
@@ -93,6 +120,10 @@ struct tok_state {
/* How to proceed when asked for a new token in interactive mode */
enum interactive_underflow_t interactive_underflow;
int report_warnings;
+ // TODO: Factor this into its own thing
+ tokenizer_mode tok_mode_stack[MAXLEVEL];
+ int tok_mode_stack_index;
+ int tok_report_warnings;
#ifdef Py_DEBUG
int debug;
#endif
diff --git a/Programs/_freeze_module.c b/Programs/_freeze_module.c
index 90fc2dc6e87da8..e55f1d56745c4d 100644
--- a/Programs/_freeze_module.c
+++ b/Programs/_freeze_module.c
@@ -1,6 +1,5 @@
/* This is built as a stand-alone executable by the Makefile, and helps turn
- modules into frozen modules (like Lib/importlib/_bootstrap.py
- into Python/importlib.h).
+ modules into frozen modules.
This is used directly by Tools/build/freeze_modules.py, and indirectly by "make regen-frozen".
diff --git a/Programs/_testembed.c b/Programs/_testembed.c
index 00717114b40286..f78ba41fe7b4eb 100644
--- a/Programs/_testembed.c
+++ b/Programs/_testembed.c
@@ -1911,14 +1911,13 @@ static int test_unicode_id_init(void)
str1 = _PyUnicode_FromId(&PyId_test_unicode_id_init);
assert(str1 != NULL);
- assert(Py_REFCNT(str1) == 1);
+ assert(_Py_IsImmortal(str1));
str2 = PyUnicode_FromString("test_unicode_id_init");
assert(str2 != NULL);
assert(PyUnicode_Compare(str1, str2) == 0);
- // str1 is a borrowed reference
Py_DECREF(str2);
Py_Finalize();
diff --git a/Programs/test_frozenmain.h b/Programs/test_frozenmain.h
index 4ac472a88261e1..cd9d1032629f49 100644
--- a/Programs/test_frozenmain.h
+++ b/Programs/test_frozenmain.h
@@ -27,12 +27,12 @@ unsigned char M_test_frozenmain[] = {
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,100,0,0,0,240,3,1,1,1,243,8,0,
+ 0,0,0,115,102,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,208,10,40,144,67,209,10,40,152,54,160,35,153,
- 59,209,10,40,213,4,41,241,15,7,1,42,114,16,0,0,
- 0,
+ 0,5,10,136,71,144,67,144,53,152,2,152,54,160,35,153,
+ 59,152,45,208,10,40,213,4,41,241,15,7,1,42,114,16,
+ 0,0,0,
};
diff --git a/Python/Python-tokenize.c b/Python/Python-tokenize.c
index 8daa9877254e2e..416dc5971bca3d 100644
--- a/Python/Python-tokenize.c
+++ b/Python/Python-tokenize.c
@@ -86,8 +86,8 @@ tokenizeriter_next(tokenizeriterobject *it)
Py_DECREF(str);
return NULL;
}
- const char *line_start = type == STRING ? it->tok->multi_line_start : it->tok->line_start;
- int lineno = type == STRING ? it->tok->first_lineno : it->tok->lineno;
+ const char *line_start = ISSTRINGLIT(type) ? it->tok->multi_line_start : it->tok->line_start;
+ int lineno = ISSTRINGLIT(type) ? it->tok->first_lineno : it->tok->lineno;
int end_lineno = it->tok->lineno;
int col_offset = -1;
int end_col_offset = -1;
diff --git a/Python/assemble.c b/Python/assemble.c
new file mode 100644
index 00000000000000..e5a361b230cf1c
--- /dev/null
+++ b/Python/assemble.c
@@ -0,0 +1,602 @@
+#include
+
+#include "Python.h"
+#include "pycore_flowgraph.h"
+#include "pycore_compile.h"
+#include "pycore_pymem.h" // _PyMem_IsPtrFreed()
+#include "pycore_code.h" // write_location_entry_start()
+
+
+#define DEFAULT_CODE_SIZE 128
+#define DEFAULT_LNOTAB_SIZE 16
+#define DEFAULT_CNOTAB_SIZE 32
+
+#undef SUCCESS
+#undef ERROR
+#define SUCCESS 0
+#define ERROR -1
+
+#define RETURN_IF_ERROR(X) \
+ if ((X) == -1) { \
+ return ERROR; \
+ }
+
+typedef _PyCompilerSrcLocation location;
+typedef _PyCfgInstruction cfg_instr;
+typedef _PyCfgBasicblock basicblock;
+
+static inline bool
+same_location(location a, location b)
+{
+ return a.lineno == b.lineno &&
+ a.end_lineno == b.end_lineno &&
+ a.col_offset == b.col_offset &&
+ a.end_col_offset == b.end_col_offset;
+}
+
+struct assembler {
+ PyObject *a_bytecode; /* bytes containing bytecode */
+ int a_offset; /* offset into bytecode */
+ PyObject *a_except_table; /* bytes containing exception table */
+ int a_except_table_off; /* offset into exception table */
+ /* Location Info */
+ int a_lineno; /* lineno of last emitted instruction */
+ PyObject* a_linetable; /* bytes containing location info */
+ int a_location_off; /* offset of last written location info frame */
+};
+
+static int
+assemble_init(struct assembler *a, int firstlineno)
+{
+ memset(a, 0, sizeof(struct assembler));
+ a->a_lineno = firstlineno;
+ a->a_linetable = NULL;
+ a->a_location_off = 0;
+ a->a_except_table = NULL;
+ a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
+ if (a->a_bytecode == NULL) {
+ goto error;
+ }
+ a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE);
+ if (a->a_linetable == NULL) {
+ goto error;
+ }
+ a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
+ if (a->a_except_table == NULL) {
+ goto error;
+ }
+ return SUCCESS;
+error:
+ Py_XDECREF(a->a_bytecode);
+ Py_XDECREF(a->a_linetable);
+ Py_XDECREF(a->a_except_table);
+ return ERROR;
+}
+
+static void
+assemble_free(struct assembler *a)
+{
+ Py_XDECREF(a->a_bytecode);
+ Py_XDECREF(a->a_linetable);
+ Py_XDECREF(a->a_except_table);
+}
+
+static inline void
+write_except_byte(struct assembler *a, int byte) {
+ unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table);
+ p[a->a_except_table_off++] = byte;
+}
+
+#define CONTINUATION_BIT 64
+
+static void
+assemble_emit_exception_table_item(struct assembler *a, int value, int msb)
+{
+ assert ((msb | 128) == 128);
+ assert(value >= 0 && value < (1 << 30));
+ if (value >= 1 << 24) {
+ write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb);
+ msb = 0;
+ }
+ if (value >= 1 << 18) {
+ write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb);
+ msb = 0;
+ }
+ if (value >= 1 << 12) {
+ write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb);
+ msb = 0;
+ }
+ if (value >= 1 << 6) {
+ write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb);
+ msb = 0;
+ }
+ write_except_byte(a, (value&0x3f) | msb);
+}
+
+/* See Objects/exception_handling_notes.txt for details of layout */
+#define MAX_SIZE_OF_ENTRY 20
+
+static int
+assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler)
+{
+ Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table);
+ if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) {
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2));
+ }
+ int size = end-start;
+ assert(end > start);
+ int target = handler->b_offset;
+ int depth = handler->b_startdepth - 1;
+ if (handler->b_preserve_lasti) {
+ depth -= 1;
+ }
+ assert(depth >= 0);
+ int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
+ assemble_emit_exception_table_item(a, start, (1<<7));
+ assemble_emit_exception_table_item(a, size, 0);
+ assemble_emit_exception_table_item(a, target, 0);
+ assemble_emit_exception_table_item(a, depth_lasti, 0);
+ return SUCCESS;
+}
+
+static int
+assemble_exception_table(struct assembler *a, basicblock *entryblock)
+{
+ basicblock *b;
+ int ioffset = 0;
+ basicblock *handler = NULL;
+ int start = -1;
+ for (b = entryblock; b != NULL; b = b->b_next) {
+ ioffset = b->b_offset;
+ for (int i = 0; i < b->b_iused; i++) {
+ cfg_instr *instr = &b->b_instr[i];
+ if (instr->i_except != handler) {
+ if (handler != NULL) {
+ RETURN_IF_ERROR(
+ assemble_emit_exception_table_entry(a, start, ioffset, handler));
+ }
+ start = ioffset;
+ handler = instr->i_except;
+ }
+ ioffset += _PyCfg_InstrSize(instr);
+ }
+ }
+ if (handler != NULL) {
+ RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, handler));
+ }
+ return SUCCESS;
+}
+
+
+/* Code location emitting code. See locations.md for a description of the format. */
+
+#define MSB 0x80
+
+static void
+write_location_byte(struct assembler* a, int val)
+{
+ PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255;
+ a->a_location_off++;
+}
+
+
+static uint8_t *
+location_pointer(struct assembler* a)
+{
+ return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) +
+ a->a_location_off;
+}
+
+static void
+write_location_first_byte(struct assembler* a, int code, int length)
+{
+ a->a_location_off += write_location_entry_start(
+ location_pointer(a), code, length);
+}
+
+static void
+write_location_varint(struct assembler* a, unsigned int val)
+{
+ uint8_t *ptr = location_pointer(a);
+ a->a_location_off += write_varint(ptr, val);
+}
+
+
+static void
+write_location_signed_varint(struct assembler* a, int val)
+{
+ uint8_t *ptr = location_pointer(a);
+ a->a_location_off += write_signed_varint(ptr, val);
+}
+
+static void
+write_location_info_short_form(struct assembler* a, int length, int column, int end_column)
+{
+ assert(length > 0 && length <= 8);
+ int column_low_bits = column & 7;
+ int column_group = column >> 3;
+ assert(column < 80);
+ assert(end_column >= column);
+ assert(end_column - column < 16);
+ write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
+ write_location_byte(a, (column_low_bits << 4) | (end_column - column));
+}
+
+static void
+write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column)
+{
+ assert(length > 0 && length <= 8);
+ assert(line_delta >= 0 && line_delta < 3);
+ assert(column < 128);
+ assert(end_column < 128);
+ write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length);
+ write_location_byte(a, column);
+ write_location_byte(a, end_column);
+}
+
+static void
+write_location_info_long_form(struct assembler* a, location loc, int length)
+{
+ assert(length > 0 && length <= 8);
+ write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length);
+ write_location_signed_varint(a, loc.lineno - a->a_lineno);
+ assert(loc.end_lineno >= loc.lineno);
+ write_location_varint(a, loc.end_lineno - loc.lineno);
+ write_location_varint(a, loc.col_offset + 1);
+ write_location_varint(a, loc.end_col_offset + 1);
+}
+
+static void
+write_location_info_none(struct assembler* a, int length)
+{
+ write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length);
+}
+
+static void
+write_location_info_no_column(struct assembler* a, int length, int line_delta)
+{
+ write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length);
+ write_location_signed_varint(a, line_delta);
+}
+
+#define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */
+
+
+static int
+write_location_info_entry(struct assembler* a, location loc, int isize)
+{
+ Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable);
+ if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) {
+ assert(len > THEORETICAL_MAX_ENTRY_SIZE);
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2));
+ }
+ if (loc.lineno < 0) {
+ write_location_info_none(a, isize);
+ return SUCCESS;
+ }
+ int line_delta = loc.lineno - a->a_lineno;
+ int column = loc.col_offset;
+ int end_column = loc.end_col_offset;
+ assert(column >= -1);
+ assert(end_column >= -1);
+ if (column < 0 || end_column < 0) {
+ if (loc.end_lineno == loc.lineno || loc.end_lineno == -1) {
+ write_location_info_no_column(a, isize, line_delta);
+ a->a_lineno = loc.lineno;
+ return SUCCESS;
+ }
+ }
+ else if (loc.end_lineno == loc.lineno) {
+ if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
+ write_location_info_short_form(a, isize, column, end_column);
+ return SUCCESS;
+ }
+ if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) {
+ write_location_info_oneline_form(a, isize, line_delta, column, end_column);
+ a->a_lineno = loc.lineno;
+ return SUCCESS;
+ }
+ }
+ write_location_info_long_form(a, loc, isize);
+ a->a_lineno = loc.lineno;
+ return SUCCESS;
+}
+
+static int
+assemble_emit_location(struct assembler* a, location loc, int isize)
+{
+ if (isize == 0) {
+ return SUCCESS;
+ }
+ while (isize > 8) {
+ RETURN_IF_ERROR(write_location_info_entry(a, loc, 8));
+ isize -= 8;
+ }
+ return write_location_info_entry(a, loc, isize);
+}
+
+static int
+assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno)
+{
+ a->a_lineno = firstlineno;
+ location loc = NO_LOCATION;
+ int size = 0;
+ for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
+ for (int j = 0; j < b->b_iused; j++) {
+ if (!same_location(loc, b->b_instr[j].i_loc)) {
+ RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
+ loc = b->b_instr[j].i_loc;
+ size = 0;
+ }
+ size += _PyCfg_InstrSize(&b->b_instr[j]);
+ }
+ }
+ RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
+ return SUCCESS;
+}
+
+static void
+write_instr(_Py_CODEUNIT *codestr, cfg_instr *instruction, int ilen)
+{
+ int opcode = instruction->i_opcode;
+ assert(!IS_PSEUDO_OPCODE(opcode));
+ int oparg = instruction->i_oparg;
+ assert(HAS_ARG(opcode) || oparg == 0);
+ int caches = _PyOpcode_Caches[opcode];
+ switch (ilen - caches) {
+ case 4:
+ codestr->op.code = EXTENDED_ARG;
+ codestr->op.arg = (oparg >> 24) & 0xFF;
+ codestr++;
+ /* fall through */
+ case 3:
+ codestr->op.code = EXTENDED_ARG;
+ codestr->op.arg = (oparg >> 16) & 0xFF;
+ codestr++;
+ /* fall through */
+ case 2:
+ codestr->op.code = EXTENDED_ARG;
+ codestr->op.arg = (oparg >> 8) & 0xFF;
+ codestr++;
+ /* fall through */
+ case 1:
+ codestr->op.code = opcode;
+ codestr->op.arg = oparg & 0xFF;
+ codestr++;
+ break;
+ default:
+ Py_UNREACHABLE();
+ }
+ while (caches--) {
+ codestr->op.code = CACHE;
+ codestr->op.arg = 0;
+ codestr++;
+ }
+}
+
+/* assemble_emit_instr()
+ Extend the bytecode with a new instruction.
+ Update lnotab if necessary.
+*/
+
+static int
+assemble_emit_instr(struct assembler *a, cfg_instr *i)
+{
+ Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
+ _Py_CODEUNIT *code;
+
+ int size = _PyCfg_InstrSize(i);
+ if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) {
+ if (len > PY_SSIZE_T_MAX / 2) {
+ return ERROR;
+ }
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2));
+ }
+ code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
+ a->a_offset += size;
+ write_instr(code, i, size);
+ return SUCCESS;
+}
+
+static int
+assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno,
+ PyObject *const_cache)
+{
+ RETURN_IF_ERROR(assemble_init(a, first_lineno));
+
+ for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
+ for (int j = 0; j < b->b_iused; j++) {
+ RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j]));
+ }
+ }
+
+ RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno));
+
+ RETURN_IF_ERROR(assemble_exception_table(a, entryblock));
+
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off));
+ RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table));
+
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off));
+ RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable));
+
+ RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT)));
+ RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode));
+ return SUCCESS;
+}
+
+static PyObject *
+dict_keys_inorder(PyObject *dict, Py_ssize_t offset)
+{
+ PyObject *tuple, *k, *v;
+ Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict);
+
+ tuple = PyTuple_New(size);
+ if (tuple == NULL)
+ return NULL;
+ while (PyDict_Next(dict, &pos, &k, &v)) {
+ i = PyLong_AS_LONG(v);
+ assert((i - offset) < size);
+ assert((i - offset) >= 0);
+ PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k));
+ }
+ return tuple;
+}
+
+// This is in codeobject.c.
+extern void _Py_set_localsplus_info(int, PyObject *, unsigned char,
+ PyObject *, PyObject *);
+
+static void
+compute_localsplus_info(_PyCompile_CodeUnitMetadata *umd, int nlocalsplus,
+ PyObject *names, PyObject *kinds)
+{
+ PyObject *k, *v;
+ Py_ssize_t pos = 0;
+ while (PyDict_Next(umd->u_varnames, &pos, &k, &v)) {
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ assert(offset < nlocalsplus);
+ // For now we do not distinguish arg kinds.
+ _PyLocals_Kind kind = CO_FAST_LOCAL;
+ if (PyDict_GetItem(umd->u_cellvars, k) != NULL) {
+ kind |= CO_FAST_CELL;
+ }
+ _Py_set_localsplus_info(offset, k, kind, names, kinds);
+ }
+ int nlocals = (int)PyDict_GET_SIZE(umd->u_varnames);
+
+ // This counter mirrors the fix done in fix_cell_offsets().
+ int numdropped = 0;
+ pos = 0;
+ while (PyDict_Next(umd->u_cellvars, &pos, &k, &v)) {
+ if (PyDict_GetItem(umd->u_varnames, k) != NULL) {
+ // Skip cells that are already covered by locals.
+ numdropped += 1;
+ continue;
+ }
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ offset += nlocals - numdropped;
+ assert(offset < nlocalsplus);
+ _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds);
+ }
+
+ pos = 0;
+ while (PyDict_Next(umd->u_freevars, &pos, &k, &v)) {
+ int offset = (int)PyLong_AS_LONG(v);
+ assert(offset >= 0);
+ offset += nlocals - numdropped;
+ assert(offset < nlocalsplus);
+ _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds);
+ }
+}
+
+static PyCodeObject *
+makecode(_PyCompile_CodeUnitMetadata *umd, struct assembler *a, PyObject *const_cache,
+ PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags,
+ PyObject *filename)
+{
+ PyCodeObject *co = NULL;
+ PyObject *names = NULL;
+ PyObject *consts = NULL;
+ PyObject *localsplusnames = NULL;
+ PyObject *localspluskinds = NULL;
+ names = dict_keys_inorder(umd->u_names, 0);
+ if (!names) {
+ goto error;
+ }
+ if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) {
+ goto error;
+ }
+
+ consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */
+ if (consts == NULL) {
+ goto error;
+ }
+ if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) {
+ goto error;
+ }
+
+ assert(umd->u_posonlyargcount < INT_MAX);
+ assert(umd->u_argcount < INT_MAX);
+ assert(umd->u_kwonlyargcount < INT_MAX);
+ int posonlyargcount = (int)umd->u_posonlyargcount;
+ int posorkwargcount = (int)umd->u_argcount;
+ assert(INT_MAX - posonlyargcount - posorkwargcount > 0);
+ int kwonlyargcount = (int)umd->u_kwonlyargcount;
+
+ localsplusnames = PyTuple_New(nlocalsplus);
+ if (localsplusnames == NULL) {
+ goto error;
+ }
+ localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
+ if (localspluskinds == NULL) {
+ goto error;
+ }
+ compute_localsplus_info(umd, nlocalsplus, localsplusnames, localspluskinds);
+
+ struct _PyCodeConstructor con = {
+ .filename = filename,
+ .name = umd->u_name,
+ .qualname = umd->u_qualname ? umd->u_qualname : umd->u_name,
+ .flags = code_flags,
+
+ .code = a->a_bytecode,
+ .firstlineno = umd->u_firstlineno,
+ .linetable = a->a_linetable,
+
+ .consts = consts,
+ .names = names,
+
+ .localsplusnames = localsplusnames,
+ .localspluskinds = localspluskinds,
+
+ .argcount = posonlyargcount + posorkwargcount,
+ .posonlyargcount = posonlyargcount,
+ .kwonlyargcount = kwonlyargcount,
+
+ .stacksize = maxdepth,
+
+ .exceptiontable = a->a_except_table,
+ };
+
+ if (_PyCode_Validate(&con) < 0) {
+ goto error;
+ }
+
+ if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) {
+ goto error;
+ }
+ con.localsplusnames = localsplusnames;
+
+ co = _PyCode_New(&con);
+ if (co == NULL) {
+ goto error;
+ }
+
+error:
+ Py_XDECREF(names);
+ Py_XDECREF(consts);
+ Py_XDECREF(localsplusnames);
+ Py_XDECREF(localspluskinds);
+ return co;
+}
+
+
+PyCodeObject *
+_PyAssemble_MakeCodeObject(_PyCompile_CodeUnitMetadata *umd, PyObject *const_cache,
+ PyObject *consts, int maxdepth, basicblock *entryblock,
+ int nlocalsplus, int code_flags, PyObject *filename)
+{
+ PyCodeObject *co = NULL;
+
+ struct assembler a;
+ int res = assemble_emit(&a, entryblock, umd->u_firstlineno, const_cache);
+ if (res == SUCCESS) {
+ co = makecode(umd, &a, const_cache, consts, maxdepth, nlocalsplus,
+ code_flags, filename);
+ }
+ assemble_free(&a);
+ return co;
+}
diff --git a/Python/bytecodes.c b/Python/bytecodes.c
index 72f85cc92b0c92..9de0d92e382d3d 100644
--- a/Python/bytecodes.c
+++ b/Python/bytecodes.c
@@ -14,6 +14,7 @@
#include "pycore_function.h"
#include "pycore_intrinsics.h"
#include "pycore_long.h" // _PyLong_GetZero()
+#include "pycore_instruments.h"
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_moduleobject.h" // PyModuleObject
#include "pycore_opcode.h" // EXTRA_CASES
@@ -24,6 +25,7 @@
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_typeobject.h" // _PySuper_Lookup()
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "pycore_dict.h"
@@ -134,11 +136,45 @@ dummy_func(
inst(RESUME, (--)) {
assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame);
- if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
+ /* Possibly combine this with eval breaker */
+ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) {
+ int err = _Py_Instrument(frame->f_code, tstate->interp);
+ ERROR_IF(err, error);
+ next_instr--;
+ }
+ else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
goto handle_eval_breaker;
}
}
+ inst(INSTRUMENTED_RESUME, (--)) {
+ /* Possible performance enhancement:
+ * We need to check the eval breaker anyway, can we
+ * combine the instrument verison check and the eval breaker test?
+ */
+ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) {
+ if (_Py_Instrument(frame->f_code, tstate->interp)) {
+ goto error;
+ }
+ next_instr--;
+ }
+ else {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ int err = _Py_call_instrumentation(
+ tstate, oparg > 0, frame, next_instr-1);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ ERROR_IF(err, error);
+ if (frame->prev_instr != next_instr-1) {
+ /* Instrumentation has jumped */
+ next_instr = frame->prev_instr;
+ DISPATCH();
+ }
+ if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
+ goto handle_eval_breaker;
+ }
+ }
+ }
+
inst(LOAD_CLOSURE, (-- value)) {
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
value = GETLOCAL(oparg);
@@ -183,6 +219,34 @@ dummy_func(
macro(END_FOR) = POP_TOP + POP_TOP;
+ inst(INSTRUMENTED_END_FOR, (receiver, value --)) {
+ /* Need to create a fake StopIteration error here,
+ * to conform to PEP 380 */
+ if (PyGen_Check(receiver)) {
+ PyErr_SetObject(PyExc_StopIteration, value);
+ if (monitor_stop_iteration(tstate, frame, next_instr-1)) {
+ goto error;
+ }
+ PyErr_SetRaisedException(NULL);
+ }
+ DECREF_INPUTS();
+ }
+
+ inst(END_SEND, (receiver, value -- value)) {
+ Py_DECREF(receiver);
+ }
+
+ inst(INSTRUMENTED_END_SEND, (receiver, value -- value)) {
+ if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) {
+ PyErr_SetObject(PyExc_StopIteration, value);
+ if (monitor_stop_iteration(tstate, frame, next_instr-1)) {
+ goto error;
+ }
+ PyErr_SetRaisedException(NULL);
+ }
+ Py_DECREF(receiver);
+ }
+
inst(UNARY_NEGATIVE, (value -- res)) {
res = PyNumber_Negative(value);
DECREF_INPUTS();
@@ -222,7 +286,6 @@ dummy_func(
inst(BINARY_OP_MULTIPLY_INT, (unused/1, left, right -- prod)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -233,7 +296,6 @@ dummy_func(
}
inst(BINARY_OP_MULTIPLY_FLOAT, (unused/1, left, right -- prod)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -243,7 +305,6 @@ dummy_func(
}
inst(BINARY_OP_SUBTRACT_INT, (unused/1, left, right -- sub)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -254,7 +315,6 @@ dummy_func(
}
inst(BINARY_OP_SUBTRACT_FLOAT, (unused/1, left, right -- sub)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -263,7 +323,6 @@ dummy_func(
}
inst(BINARY_OP_ADD_UNICODE, (unused/1, left, right -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -280,7 +339,6 @@ dummy_func(
// specializations, but there is no output.
// At the end we just skip over the STORE_FAST.
inst(BINARY_OP_INPLACE_ADD_UNICODE, (left, right --)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
@@ -310,7 +368,6 @@ dummy_func(
}
inst(BINARY_OP_ADD_FLOAT, (unused/1, left, right -- sum)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -320,7 +377,6 @@ dummy_func(
}
inst(BINARY_OP_ADD_INT, (unused/1, left, right -- sum)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -342,7 +398,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinarySubscr(container, sub, next_instr);
DISPATCH_SAME_OPARG();
@@ -386,7 +441,6 @@ dummy_func(
}
inst(BINARY_SUBSCR_LIST_INT, (unused/1, list, sub -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
@@ -403,7 +457,6 @@ dummy_func(
}
inst(BINARY_SUBSCR_TUPLE_INT, (unused/1, tuple, sub -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
@@ -420,7 +473,6 @@ dummy_func(
}
inst(BINARY_SUBSCR_DICT, (unused/1, dict, sub -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR);
STAT_INC(BINARY_SUBSCR, hit);
res = PyDict_GetItemWithError(dict, sub);
@@ -455,6 +507,7 @@ dummy_func(
new_frame->localsplus[0] = container;
new_frame->localsplus[1] = sub;
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
@@ -479,7 +532,6 @@ dummy_func(
inst(STORE_SUBSCR, (counter/1, v, container, sub -- )) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_StoreSubscr(container, sub, next_instr);
DISPATCH_SAME_OPARG();
@@ -497,7 +549,6 @@ dummy_func(
}
inst(STORE_SUBSCR_LIST_INT, (unused/1, value, list, sub -- )) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR);
DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
@@ -517,7 +568,6 @@ dummy_func(
}
inst(STORE_SUBSCR_DICT, (unused/1, value, dict, sub -- )) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR);
STAT_INC(STORE_SUBSCR, hit);
int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value);
@@ -573,7 +623,6 @@ dummy_func(
assert(EMPTY());
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCallTstate(tstate);
@@ -584,14 +633,32 @@ dummy_func(
STACK_SHRINK(1);
assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCallPy(tstate);
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = cframe.current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ }
+
+ inst(INSTRUMENTED_RETURN_VALUE, (retval --)) {
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_RETURN,
+ frame, next_instr-1, retval);
+ if (err) goto error;
+ STACK_SHRINK(1);
+ assert(EMPTY());
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _Py_LeaveRecursiveCallPy(tstate);
+ assert(frame != &entry_frame);
+ // GH-99729: We need to unlink the frame *before* clearing it:
+ _PyInterpreterFrame *dying = frame;
+ frame = cframe.current_frame = dying->previous;
+ _PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
@@ -601,14 +668,33 @@ dummy_func(
Py_INCREF(retval);
assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCallPy(tstate);
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = cframe.current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ }
+
+ inst(INSTRUMENTED_RETURN_CONST, (--)) {
+ PyObject *retval = GETITEM(frame->f_code->co_consts, oparg);
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_RETURN,
+ frame, next_instr-1, retval);
+ if (err) goto error;
+ Py_INCREF(retval);
+ assert(EMPTY());
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _Py_LeaveRecursiveCallPy(tstate);
+ assert(frame != &entry_frame);
+ // GH-99729: We need to unlink the frame *before* clearing it:
+ _PyInterpreterFrame *dying = frame;
+ frame = cframe.current_frame = dying->previous;
+ _PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
@@ -730,7 +816,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PySendCache *cache = (_PySendCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_Send(receiver, next_instr);
DISPATCH_SAME_OPARG();
@@ -739,6 +824,20 @@ dummy_func(
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
assert(frame != &entry_frame);
+ if ((Py_TYPE(receiver) == &PyGen_Type ||
+ Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING)
+ {
+ 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;
+ JUMPBY(INLINE_CACHE_ENTRIES_SEND);
+ DISPATCH_INLINED(gen_frame);
+ }
if (Py_IsNone(v) && PyIter_Check(receiver)) {
retval = Py_TYPE(receiver)->tp_iternext(receiver);
}
@@ -746,42 +845,57 @@ dummy_func(
retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
}
if (retval == NULL) {
- if (tstate->c_tracefunc != NULL
- && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
+ if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)
+ ) {
+ monitor_raise(tstate, frame, next_instr-1);
+ }
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
assert(retval != NULL);
JUMPBY(oparg);
}
else {
- assert(retval == NULL);
goto error;
}
}
- else {
- assert(retval != NULL);
- }
Py_DECREF(v);
}
inst(SEND_GEN, (unused/1, receiver, v -- receiver)) {
- assert(cframe.use_tracing == 0);
PyGenObject *gen = (PyGenObject *)receiver;
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type &&
Py_TYPE(gen) != &PyCoro_Type, SEND);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
STAT_INC(SEND, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->yield_offset = oparg;
+ 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;
- JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg);
+ JUMPBY(INLINE_CACHE_ENTRIES_SEND);
DISPATCH_INLINED(gen_frame);
}
+ inst(INSTRUMENTED_YIELD_VALUE, (retval -- unused)) {
+ assert(frame != &entry_frame);
+ PyGenObject *gen = _PyFrame_GetGenerator(frame);
+ gen->gi_frame_state = FRAME_SUSPENDED;
+ _PyFrame_SetStackPointer(frame, stack_pointer - 1);
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_YIELD,
+ frame, next_instr-1, retval);
+ if (err) goto error;
+ tstate->exc_info = gen->gi_exc_state.previous_item;
+ gen->gi_exc_state.previous_item = NULL;
+ _Py_LeaveRecursiveCallPy(tstate);
+ _PyInterpreterFrame *gen_frame = frame;
+ frame = cframe.current_frame = frame->previous;
+ gen_frame->previous = NULL;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ }
+
inst(YIELD_VALUE, (retval -- unused)) {
// NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close()
@@ -790,15 +904,12 @@ dummy_func(
PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = cframe.current_frame = frame->previous;
gen_frame->previous = NULL;
- frame->prev_instr -= frame->yield_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
}
@@ -930,7 +1041,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_UnpackSequence(seq, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -994,7 +1104,6 @@ dummy_func(
inst(STORE_ATTR, (counter/1, unused/3, v, owner --)) {
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
next_instr--;
_Py_Specialize_StoreAttr(owner, next_instr, name);
@@ -1111,7 +1220,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1);
next_instr--;
_Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name);
@@ -1163,7 +1271,6 @@ dummy_func(
}
inst(LOAD_GLOBAL_MODULE, (unused/1, index/1, version/1, unused/1 -- null if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
PyDictObject *dict = (PyDictObject *)GLOBALS();
DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL);
@@ -1177,11 +1284,11 @@ dummy_func(
}
inst(LOAD_GLOBAL_BUILTIN, (unused/1, index/1, mod_version/1, bltn_version/1 -- null if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL);
PyDictObject *mdict = (PyDictObject *)GLOBALS();
PyDictObject *bdict = (PyDictObject *)BUILTINS();
+ assert(opcode == LOAD_GLOBAL_BUILTIN);
DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL);
DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL);
assert(DK_IS_UNICODE(bdict->ma_keys));
@@ -1447,6 +1554,49 @@ dummy_func(
PREDICT(JUMP_BACKWARD);
}
+ family(load_super_attr, INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR) = {
+ LOAD_SUPER_ATTR,
+ LOAD_SUPER_ATTR_METHOD,
+ };
+
+ inst(LOAD_SUPER_ATTR, (unused/9, global_super, class, self -- res2 if (oparg & 1), res)) {
+ PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2);
+ int load_method = oparg & 1;
+ #if ENABLE_SPECIALIZATION
+ _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
+ if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
+ next_instr--;
+ _Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method);
+ DISPATCH_SAME_OPARG();
+ }
+ STAT_INC(LOAD_SUPER_ATTR, deferred);
+ DECREMENT_ADAPTIVE_COUNTER(cache->counter);
+ #endif /* ENABLE_SPECIALIZATION */
+
+ // we make no attempt to optimize here; specializations should
+ // handle any case whose performance we care about
+ PyObject *stack[] = {class, self};
+ PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
+ DECREF_INPUTS();
+ ERROR_IF(super == NULL, error);
+ res = PyObject_GetAttr(super, name);
+ Py_DECREF(super);
+ ERROR_IF(res == NULL, error);
+ }
+
+ inst(LOAD_SUPER_ATTR_METHOD, (unused/1, class_version/2, self_type_version/2, method/4, global_super, class, self -- res2, res)) {
+ DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
+ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
+ DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR);
+ PyTypeObject *self_type = Py_TYPE(self);
+ DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR);
+ res2 = method;
+ res = self; // transfer ownership
+ Py_INCREF(res2);
+ Py_DECREF(global_super);
+ Py_DECREF(class);
+ }
+
family(load_attr, INLINE_CACHE_ENTRIES_LOAD_ATTR) = {
LOAD_ATTR,
LOAD_ATTR_INSTANCE_VALUE,
@@ -1465,7 +1615,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1);
next_instr--;
_Py_Specialize_LoadAttr(owner, next_instr, name);
@@ -1511,7 +1660,6 @@ dummy_func(
}
inst(LOAD_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -1528,7 +1676,6 @@ dummy_func(
}
inst(LOAD_ATTR_MODULE, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR);
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict;
assert(dict != NULL);
@@ -1545,7 +1692,6 @@ dummy_func(
}
inst(LOAD_ATTR_WITH_HINT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -1576,7 +1722,6 @@ dummy_func(
}
inst(LOAD_ATTR_SLOT, (unused/1, type_version/2, index/1, unused/5, owner -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -1590,7 +1735,6 @@ dummy_func(
}
inst(LOAD_ATTR_CLASS, (unused/1, type_version/2, unused/2, descr/4, cls -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyType_Check(cls), LOAD_ATTR);
DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
@@ -1606,7 +1750,6 @@ dummy_func(
}
inst(LOAD_ATTR_PROPERTY, (unused/1, type_version/2, func_version/2, fget/4, owner -- unused if (oparg & 1), unused)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
@@ -1628,11 +1771,11 @@ dummy_func(
STACK_SHRINK(shrink_stack);
new_frame->localsplus[0] = owner;
JUMPBY(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)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -1656,11 +1799,11 @@ dummy_func(
new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
inst(STORE_ATTR_INSTANCE_VALUE, (unused/1, type_version/2, index/1, value, owner --)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -1681,7 +1824,6 @@ dummy_func(
}
inst(STORE_ATTR_WITH_HINT, (unused/1, type_version/2, hint/1, value, owner --)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -1723,7 +1865,6 @@ dummy_func(
}
inst(STORE_ATTR_SLOT, (unused/1, type_version/2, index/1, value, owner --)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -1746,7 +1887,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_CompareOp(left, right, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -1761,7 +1901,6 @@ dummy_func(
}
inst(COMPARE_OP_FLOAT, (unused/1, left, right -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
STAT_INC(COMPARE_OP, hit);
@@ -1777,7 +1916,6 @@ dummy_func(
// Similar to COMPARE_OP_FLOAT
inst(COMPARE_OP_INT, (unused/1, left, right -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP);
@@ -1797,7 +1935,6 @@ dummy_func(
// Similar to COMPARE_OP_FLOAT, but for ==, != only
inst(COMPARE_OP_STR, (unused/1, left, right -- res)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
STAT_INC(COMPARE_OP, hit);
@@ -2044,7 +2181,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyForIterCache *cache = (_PyForIterCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_ForIter(iter, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -2059,13 +2195,12 @@ dummy_func(
if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
goto error;
}
- else if (tstate->c_tracefunc != NULL) {
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
- }
+ monitor_raise(tstate, frame, next_instr-1);
_PyErr_Clear(tstate);
}
/* iterator ended normally */
- assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR);
+ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR ||
+ next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR);
Py_DECREF(iter);
STACK_SHRINK(1);
/* Jump forward oparg, then skip following END_FOR instruction */
@@ -2075,8 +2210,35 @@ dummy_func(
// Common case: no jump, leave it to the code generator
}
+ inst(INSTRUMENTED_FOR_ITER, ( -- )) {
+ _Py_CODEUNIT *here = next_instr-1;
+ _Py_CODEUNIT *target;
+ PyObject *iter = TOP();
+ PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
+ if (next != NULL) {
+ PUSH(next);
+ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER;
+ }
+ else {
+ if (_PyErr_Occurred(tstate)) {
+ if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
+ goto error;
+ }
+ monitor_raise(tstate, frame, here);
+ _PyErr_Clear(tstate);
+ }
+ /* iterator ended normally */
+ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR ||
+ next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR);
+ STACK_SHRINK(1);
+ Py_DECREF(iter);
+ /* Skip END_FOR */
+ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1;
+ }
+ INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH);
+ }
+
inst(FOR_ITER_LIST, (unused/1, iter -- iter, next)) {
- assert(cframe.use_tracing == 0);
DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER);
_PyListIterObject *it = (_PyListIterObject *)iter;
STAT_INC(FOR_ITER, hit);
@@ -2099,7 +2261,6 @@ dummy_func(
}
inst(FOR_ITER_TUPLE, (unused/1, iter -- iter, next)) {
- assert(cframe.use_tracing == 0);
_PyTupleIterObject *it = (_PyTupleIterObject *)iter;
DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
@@ -2122,7 +2283,6 @@ dummy_func(
}
inst(FOR_ITER_RANGE, (unused/1, iter -- iter, next)) {
- assert(cframe.use_tracing == 0);
_PyRangeIterObject *r = (_PyRangeIterObject *)iter;
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
@@ -2143,19 +2303,19 @@ dummy_func(
}
inst(FOR_ITER_GEN, (unused/1, iter -- iter, unused)) {
- assert(cframe.use_tracing == 0);
PyGenObject *gen = (PyGenObject *)iter;
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
STAT_INC(FOR_ITER, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->yield_offset = oparg;
+ frame->return_offset = oparg;
_PyFrame_StackPush(gen_frame, Py_NewRef(Py_None));
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
- JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg);
- assert(next_instr->op.code == END_FOR);
+ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER);
+ assert(next_instr[oparg].op.code == END_FOR ||
+ next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
DISPATCH_INLINED(gen_frame);
}
@@ -2264,7 +2424,6 @@ dummy_func(
inst(LOAD_ATTR_METHOD_WITH_VALUES, (unused/1, type_version/2, keys_version/2, descr/4, self -- res2 if (oparg & 1), res)) {
/* Cached method object */
- assert(cframe.use_tracing == 0);
PyTypeObject *self_cls = Py_TYPE(self);
assert(type_version != 0);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -2283,7 +2442,6 @@ dummy_func(
}
inst(LOAD_ATTR_METHOD_NO_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
PyTypeObject *self_cls = Py_TYPE(self);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
assert(self_cls->tp_dictoffset == 0);
@@ -2296,7 +2454,6 @@ dummy_func(
}
inst(LOAD_ATTR_METHOD_LAZY_DICT, (unused/1, type_version/2, unused/2, descr/4, self -- res2 if (oparg & 1), res)) {
- assert(cframe.use_tracing == 0);
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;
@@ -2318,6 +2475,21 @@ dummy_func(
kwnames = GETITEM(frame->f_code->co_consts, oparg);
}
+ inst(INSTRUMENTED_CALL, ( -- )) {
+ int is_meth = PEEK(oparg+2) != NULL;
+ int total_args = oparg + is_meth;
+ PyObject *function = PEEK(total_args + 1);
+ PyObject *arg = total_args == 0 ?
+ &_PyInstrumentation_MISSING : PEEK(total_args);
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_CALL,
+ frame, next_instr-1, function, arg);
+ ERROR_IF(err, error);
+ _PyCallCache *cache = (_PyCallCache *)next_instr;
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ GO_TO_INSTRUCTION(CALL);
+ }
+
// Cache layout: counter/1, func_version/2
// Neither CALL_INTRINSIC_1/2 nor CALL_FUNCTION_EX are members!
family(call, INLINE_CACHE_ENTRIES_CALL) = {
@@ -2359,7 +2531,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyCallCache *cache = (_PyCallCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_Call(callable, next_instr, total_args, kwnames);
DISPATCH_SAME_OPARG();
@@ -2399,19 +2570,30 @@ dummy_func(
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
/* Callable is not a normal Python function */
- if (cframe.use_tracing) {
- res = trace_call_function(
- tstate, callable, args,
- positional_args, kwnames);
- }
- else {
- res = PyObject_Vectorcall(
- callable, args,
- positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
- kwnames);
+ res = PyObject_Vectorcall(
+ callable, args,
+ positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
+ kwnames);
+ if (opcode == INSTRUMENTED_CALL) {
+ PyObject *arg = total_args == 0 ?
+ &_PyInstrumentation_MISSING : PEEK(total_args);
+ if (res == NULL) {
+ _Py_call_instrumentation_exc2(
+ tstate, PY_MONITORING_EVENT_C_RAISE,
+ frame, next_instr-1, callable, arg);
+ }
+ else {
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_C_RETURN,
+ frame, next_instr-1, callable, arg);
+ if (err < 0) {
+ Py_CLEAR(res);
+ }
+ }
}
kwnames = NULL;
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -2462,6 +2644,7 @@ dummy_func(
// Manipulate stack directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2);
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
@@ -2499,12 +2682,12 @@ dummy_func(
// Manipulate stack and cache directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2);
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
inst(CALL_NO_KW_TYPE_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
- assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
PyObject *obj = args[0];
@@ -2517,7 +2700,6 @@ dummy_func(
inst(CALL_NO_KW_STR_1, (unused/1, unused/2, null, callable, args[oparg] -- res)) {
assert(kwnames == NULL);
- assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
@@ -2570,7 +2752,6 @@ dummy_func(
}
inst(CALL_NO_KW_BUILTIN_O, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(cframe.use_tracing == 0);
/* Builtin METH_O functions */
assert(kwnames == NULL);
int is_meth = method != NULL;
@@ -2602,7 +2783,6 @@ dummy_func(
}
inst(CALL_NO_KW_BUILTIN_FAST, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL functions, without keywords */
assert(kwnames == NULL);
int is_meth = method != NULL;
@@ -2638,7 +2818,6 @@ dummy_func(
}
inst(CALL_BUILTIN_FAST_WITH_KEYWORDS, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(cframe.use_tracing == 0);
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
int is_meth = method != NULL;
int total_args = oparg;
@@ -2674,7 +2853,6 @@ dummy_func(
}
inst(CALL_NO_KW_LEN, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(cframe.use_tracing == 0);
assert(kwnames == NULL);
/* len(o) */
int is_meth = method != NULL;
@@ -2702,7 +2880,6 @@ dummy_func(
}
inst(CALL_NO_KW_ISINSTANCE, (unused/1, unused/2, method, callable, args[oparg] -- res)) {
- assert(cframe.use_tracing == 0);
assert(kwnames == NULL);
/* isinstance(o, o2) */
int is_meth = method != NULL;
@@ -2733,7 +2910,6 @@ dummy_func(
// This is secretly a super-instruction
inst(CALL_NO_KW_LIST_APPEND, (unused/1, unused/2, method, self, args[oparg] -- unused)) {
- assert(cframe.use_tracing == 0);
assert(kwnames == NULL);
assert(oparg == 1);
assert(method != NULL);
@@ -2882,12 +3058,14 @@ dummy_func(
CHECK_EVAL_BREAKER();
}
+ inst(INSTRUMENTED_CALL_FUNCTION_EX, ( -- )) {
+ GO_TO_INSTRUCTION(CALL_FUNCTION_EX);
+ }
+
inst(CALL_FUNCTION_EX, (unused, func, callargs, kwargs if (oparg & 1) -- result)) {
- if (oparg & 1) {
- // DICT_MERGE is called before this opcode if there are kwargs.
- // It converts all dict subtypes in kwargs into regular dicts.
- assert(PyDict_CheckExact(kwargs));
- }
+ // 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));
if (!PyTuple_CheckExact(callargs)) {
if (check_args_iterable(tstate, func, callargs) < 0) {
goto error;
@@ -2899,10 +3077,35 @@ dummy_func(
Py_SETREF(callargs, tuple);
}
assert(PyTuple_CheckExact(callargs));
-
- result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing);
+ EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func);
+ if (opcode == INSTRUMENTED_CALL_FUNCTION_EX &&
+ !PyFunction_Check(func) && !PyMethod_Check(func)
+ ) {
+ PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ?
+ PyTuple_GET_ITEM(callargs, 0) : Py_None;
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_CALL,
+ frame, next_instr-1, func, arg);
+ if (err) goto error;
+ result = PyObject_Call(func, callargs, kwargs);
+ if (result == NULL) {
+ _Py_call_instrumentation_exc2(
+ tstate, PY_MONITORING_EVENT_C_RAISE,
+ frame, next_instr-1, func, arg);
+ }
+ else {
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_C_RETURN,
+ frame, next_instr-1, func, arg);
+ if (err < 0) {
+ Py_CLEAR(result);
+ }
+ }
+ }
+ else {
+ result = PyObject_Call(func, callargs, kwargs);
+ }
DECREF_INPUTS();
-
assert(PEEK(3 + (oparg & 1)) == NULL);
ERROR_IF(result == NULL, error);
CHECK_EVAL_BREAKER();
@@ -3018,7 +3221,6 @@ dummy_func(
#if ENABLE_SPECIALIZATION
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0));
DISPATCH_SAME_OPARG();
@@ -3039,9 +3241,105 @@ dummy_func(
assert(oparg >= 2);
}
- inst(EXTENDED_ARG, (--)) {
+ inst(INSTRUMENTED_LINE, ( -- )) {
+ _Py_CODEUNIT *here = next_instr-1;
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ int original_opcode = _Py_call_instrumentation_line(
+ tstate, frame, here);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (original_opcode < 0) {
+ next_instr = here+1;
+ goto error;
+ }
+ next_instr = frame->prev_instr;
+ if (next_instr != here) {
+ DISPATCH();
+ }
+ if (_PyOpcode_Caches[original_opcode]) {
+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ }
+ opcode = original_opcode;
+ DISPATCH_GOTO();
+ }
+
+ inst(INSTRUMENTED_INSTRUCTION, ( -- )) {
+ int next_opcode = _Py_call_instrumentation_instruction(
+ tstate, frame, next_instr-1);
+ ERROR_IF(next_opcode < 0, error);
+ next_instr--;
+ if (_PyOpcode_Caches[next_opcode]) {
+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ }
+ assert(next_opcode > 0 && next_opcode < 256);
+ opcode = next_opcode;
+ DISPATCH_GOTO();
+ }
+
+ inst(INSTRUMENTED_JUMP_FORWARD, ( -- )) {
+ INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP);
+ }
+
+ inst(INSTRUMENTED_JUMP_BACKWARD, ( -- )) {
+ INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP);
+ CHECK_EVAL_BREAKER();
+ }
+
+ inst(INSTRUMENTED_POP_JUMP_IF_TRUE, ( -- )) {
+ PyObject *cond = POP();
+ int err = PyObject_IsTrue(cond);
+ Py_DECREF(cond);
+ ERROR_IF(err < 0, error);
+ _Py_CODEUNIT *here = next_instr-1;
+ assert(err == 0 || err == 1);
+ int offset = err*oparg;
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ }
+
+ inst(INSTRUMENTED_POP_JUMP_IF_FALSE, ( -- )) {
+ PyObject *cond = POP();
+ int err = PyObject_IsTrue(cond);
+ Py_DECREF(cond);
+ ERROR_IF(err < 0, error);
+ _Py_CODEUNIT *here = next_instr-1;
+ assert(err == 0 || err == 1);
+ int offset = (1-err)*oparg;
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ }
+
+ inst(INSTRUMENTED_POP_JUMP_IF_NONE, ( -- )) {
+ PyObject *value = POP();
+ _Py_CODEUNIT *here = next_instr-1;
+ int offset;
+ if (Py_IsNone(value)) {
+ _Py_DECREF_NO_DEALLOC(value);
+ offset = oparg;
+ }
+ else {
+ Py_DECREF(value);
+ offset = 0;
+ }
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ }
+
+ inst(INSTRUMENTED_POP_JUMP_IF_NOT_NONE, ( -- )) {
+ PyObject *value = POP();
+ _Py_CODEUNIT *here = next_instr-1;
+ int offset;
+ if (Py_IsNone(value)) {
+ _Py_DECREF_NO_DEALLOC(value);
+ offset = 0;
+ }
+ else {
+ Py_DECREF(value);
+ offset = oparg;
+ }
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ }
+
+ inst(EXTENDED_ARG, ( -- )) {
assert(oparg);
- assert(cframe.use_tracing == 0);
opcode = next_instr->op.code;
oparg = oparg << 8 | next_instr->op.arg;
PRE_DISPATCH_GOTO();
@@ -3049,6 +3347,12 @@ dummy_func(
}
inst(CACHE, (--)) {
+ assert(0 && "Executing a cache.");
+ Py_UNREACHABLE();
+ }
+
+ inst(RESERVED, (--)) {
+ assert(0 && "Executing RESERVED instruction.");
Py_UNREACHABLE();
}
diff --git a/Python/ceval.c b/Python/ceval.c
index 7d60cf987e9c47..5d5221b2e40990 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -10,6 +10,7 @@
#include "pycore_function.h"
#include "pycore_intrinsics.h"
#include "pycore_long.h" // _PyLong_GetZero()
+#include "pycore_instruments.h"
#include "pycore_object.h" // _PyObject_GC_TRACK()
#include "pycore_moduleobject.h" // PyModuleObject
#include "pycore_opcode.h" // EXTRA_CASES
@@ -20,6 +21,7 @@
#include "pycore_sliceobject.h" // _PyBuildSlice_ConsumeRefs
#include "pycore_sysmodule.h" // _PySys_Audit()
#include "pycore_tuple.h" // _PyTuple_ITEMS()
+#include "pycore_typeobject.h" // _PySuper_Lookup()
#include "pycore_emscripten_signal.h" // _Py_CHECK_EMSCRIPTEN_SIGNALS
#include "pycore_dict.h"
@@ -52,8 +54,11 @@
#undef Py_DECREF
#define Py_DECREF(arg) \
do { \
- _Py_DECREF_STAT_INC(); \
PyObject *op = _PyObject_CAST(arg); \
+ if (_Py_IsImmortal(op)) { \
+ break; \
+ } \
+ _Py_DECREF_STAT_INC(); \
if (--op->ob_refcnt == 0) { \
destructor dealloc = Py_TYPE(op)->tp_dealloc; \
(*dealloc)(op); \
@@ -76,8 +81,11 @@
#undef _Py_DECREF_SPECIALIZED
#define _Py_DECREF_SPECIALIZED(arg, dealloc) \
do { \
- _Py_DECREF_STAT_INC(); \
PyObject *op = _PyObject_CAST(arg); \
+ if (_Py_IsImmortal(op)) { \
+ break; \
+ } \
+ _Py_DECREF_STAT_INC(); \
if (--op->ob_refcnt == 0) { \
destructor d = (destructor)(dealloc); \
d(op); \
@@ -92,13 +100,6 @@
#define _Py_atomic_load_relaxed_int32(ATOMIC_VAL) _Py_atomic_load_relaxed(ATOMIC_VAL)
#endif
-/* Forward declarations */
-static PyObject *trace_call_function(
- PyThreadState *tstate, PyObject *callable, PyObject **stack,
- Py_ssize_t oparg, PyObject *kwnames);
-static PyObject * do_call_core(
- PyThreadState *tstate, PyObject *func,
- PyObject *callargs, PyObject *kwdict, int use_tracing);
#ifdef LLTRACE
static void
@@ -179,19 +180,22 @@ lltrace_resume_frame(_PyInterpreterFrame *frame)
PyErr_SetRaisedException(exc);
}
#endif
-static int call_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *,
- int, PyObject *);
-static int call_trace_protected(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *,
- int, PyObject *);
-static void call_exc_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *);
-static int maybe_call_line_trace(Py_tracefunc, PyObject *,
- PyThreadState *, _PyInterpreterFrame *, int);
-static void maybe_dtrace_line(_PyInterpreterFrame *, PyTraceInfo *, int);
-static void dtrace_function_entry(_PyInterpreterFrame *);
-static void dtrace_function_return(_PyInterpreterFrame *);
+
+static void monitor_raise(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static int monitor_stop_iteration(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static void monitor_unwind(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
+static void monitor_handled(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, PyObject *exc);
+static void monitor_throw(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr);
static PyObject * import_name(PyThreadState *, _PyInterpreterFrame *,
PyObject *, PyObject *, PyObject *);
@@ -217,21 +221,6 @@ _PyEvalFrameClearAndPop(PyThreadState *tstate, _PyInterpreterFrame *frame);
"cannot access free variable '%s' where it is not associated with a" \
" value in enclosing scope"
-#ifndef NDEBUG
-/* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and
- PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen
- when a thread continues to run after Python finalization, especially
- daemon threads. */
-static int
-is_tstate_valid(PyThreadState *tstate)
-{
- assert(!_PyMem_IsPtrFreed(tstate));
- assert(!_PyMem_IsPtrFreed(tstate->interp));
- return 1;
-}
-#endif
-
-
#ifdef HAVE_ERRNO_H
#include
#endif
@@ -434,7 +423,7 @@ match_class(PyThreadState *tstate, PyObject *subject, PyObject *type,
Py_ssize_t nargs, PyObject *kwargs)
{
if (!PyType_Check(type)) {
- const char *e = "called match pattern must be a type";
+ const char *e = "called match pattern must be a class";
_PyErr_Format(tstate, PyExc_TypeError, e);
return NULL;
}
@@ -596,63 +585,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
#include "ceval_macros.h"
-static int
-trace_function_entry(PyThreadState *tstate, _PyInterpreterFrame *frame)
-{
- if (tstate->c_tracefunc != NULL) {
- /* tstate->c_tracefunc, if defined, is a
- function that will be called on *every* entry
- to a code block. Its return value, if not
- None, is a function that will be called at
- the start of each executed line of code.
- (Actually, the function must return itself
- in order to continue tracing.) The trace
- functions are called with three arguments:
- a pointer to the current frame, a string
- indicating why the function is called, and
- an argument which depends on the situation.
- The global trace function is also called
- whenever an exception is detected. */
- if (call_trace_protected(tstate->c_tracefunc,
- tstate->c_traceobj,
- tstate, frame,
- PyTrace_CALL, Py_None)) {
- /* Trace function raised an error */
- return -1;
- }
- }
- if (tstate->c_profilefunc != NULL) {
- /* Similar for c_profilefunc, except it needn't
- return itself and isn't called for "line" events */
- if (call_trace_protected(tstate->c_profilefunc,
- tstate->c_profileobj,
- tstate, frame,
- PyTrace_CALL, Py_None)) {
- /* Profile function raised an error */
- return -1;
- }
- }
- return 0;
-}
-
-static int
-trace_function_exit(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *retval)
-{
- if (tstate->c_tracefunc) {
- if (call_trace_protected(tstate->c_tracefunc, tstate->c_traceobj,
- tstate, frame, PyTrace_RETURN, retval)) {
- return -1;
- }
- }
- if (tstate->c_profilefunc) {
- if (call_trace_protected(tstate->c_profilefunc, tstate->c_profileobj,
- tstate, frame, PyTrace_RETURN, retval)) {
- return -1;
- }
- }
- return 0;
-}
-
int _Py_CheckRecursiveCallPy(
PyThreadState *tstate)
@@ -730,7 +662,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
* strict stack discipline must be maintained.
*/
_PyCFrame *prev_cframe = tstate->cframe;
- cframe.use_tracing = prev_cframe->use_tracing;
cframe.previous = prev_cframe;
tstate->cframe = &cframe;
@@ -748,7 +679,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
_PyCode_CODE(tstate->interp->interpreter_trampoline);
entry_frame.stacktop = 0;
entry_frame.owner = FRAME_OWNED_BY_CSTACK;
- entry_frame.yield_offset = 0;
+ entry_frame.return_offset = 0;
/* Push frame */
entry_frame.previous = prev_cframe->current_frame;
frame->previous = &entry_frame;
@@ -765,8 +696,11 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
if (_Py_EnterRecursivePy(tstate)) {
goto exit_unwind;
}
- TRACE_FUNCTION_THROW_ENTRY();
- DTRACE_FUNCTION_ENTRY();
+ /* Because this avoids the RESUME,
+ * we need to update instrumentation */
+ _Py_Instrument(frame->f_code, tstate->interp);
+ monitor_throw(tstate, frame, frame->prev_instr);
+ /* TO DO -- Monitor throw entry. */
goto resume_with_error;
}
@@ -781,15 +715,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
assert(_PyInterpreterFrame_LASTI(frame) >= -1); \
/* Jump back to the last instruction executed... */ \
next_instr = frame->prev_instr + 1; \
- stack_pointer = _PyFrame_GetStackPointer(frame); \
- /* Set stackdepth to -1. \
- Update when returning or calling trace function. \
- Having stackdepth <= 0 ensures that invalid \
- values are not visible to the cycle GC. \
- We choose -1 rather than 0 to assist debugging. \
- */ \
- frame->stacktop = -1;
-
+ stack_pointer = _PyFrame_GetStackPointer(frame);
start_frame:
if (_Py_EnterRecursivePy(tstate)) {
@@ -845,91 +771,6 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
#include "generated_cases.c.h"
-#if USE_COMPUTED_GOTOS
- TARGET_DO_TRACING:
-#else
- case DO_TRACING:
-#endif
- {
- assert(cframe.use_tracing);
- assert(tstate->tracing == 0);
- if (INSTR_OFFSET() >= frame->f_code->_co_firsttraceable) {
- int instr_prev = _PyInterpreterFrame_LASTI(frame);
- frame->prev_instr = next_instr;
- NEXTOPARG();
- // No _PyOpcode_Deopt here, since RESUME has no optimized forms:
- if (opcode == RESUME) {
- if (oparg < 2) {
- CHECK_EVAL_BREAKER();
- }
- /* Call tracing */
- TRACE_FUNCTION_ENTRY();
- DTRACE_FUNCTION_ENTRY();
- }
- else {
- /* line-by-line tracing support */
- if (PyDTrace_LINE_ENABLED()) {
- maybe_dtrace_line(frame, &tstate->trace_info, instr_prev);
- }
-
- if (cframe.use_tracing &&
- tstate->c_tracefunc != NULL && !tstate->tracing) {
- int err;
- /* see maybe_call_line_trace()
- for expository comments */
- _PyFrame_SetStackPointer(frame, stack_pointer);
-
- err = maybe_call_line_trace(tstate->c_tracefunc,
- tstate->c_traceobj,
- tstate, frame, instr_prev);
- // Reload possibly changed frame fields:
- stack_pointer = _PyFrame_GetStackPointer(frame);
- frame->stacktop = -1;
- // next_instr is only reloaded if tracing *does not* raise.
- // This is consistent with the behavior of older Python
- // versions. If a trace function sets a new f_lineno and
- // *then* raises, we use the *old* location when searching
- // for an exception handler, displaying the traceback, and
- // so on:
- if (err) {
- // next_instr wasn't incremented at the start of this
- // instruction. Increment it before handling the error,
- // so that it looks the same as a "normal" instruction:
- next_instr++;
- goto error;
- }
- // Reload next_instr. Don't increment it, though, since
- // we're going to re-dispatch to the "true" instruction now:
- next_instr = frame->prev_instr;
- }
- }
- }
- NEXTOPARG();
- PRE_DISPATCH_GOTO();
- // No _PyOpcode_Deopt here, since EXTENDED_ARG has no optimized forms:
- while (opcode == EXTENDED_ARG) {
- // CPython hasn't ever traced the instruction after an EXTENDED_ARG.
- // Inline the EXTENDED_ARG here, so we can avoid branching there:
- INSTRUCTION_START(EXTENDED_ARG);
- opcode = next_instr->op.code;
- oparg = oparg << 8 | next_instr->op.arg;
- // Make sure the next instruction isn't a RESUME, since that needs
- // to trace properly (and shouldn't have an EXTENDED_ARG, anyways):
- assert(opcode != RESUME);
- PRE_DISPATCH_GOTO();
- }
- opcode = _PyOpcode_Deopt[opcode];
- if (_PyOpcode_Caches[opcode]) {
- uint16_t *counter = &next_instr[1].cache;
- // The instruction is going to decrement the counter, so we need to
- // increment it here to make sure it doesn't try to specialize:
- if (!ADAPTIVE_COUNTER_IS_MAX(*counter)) {
- INCREMENT_ADAPTIVE_COUNTER(*counter);
- }
- }
- DISPATCH_GOTO();
- }
-
#if USE_COMPUTED_GOTOS
_unknown_opcode:
#else
@@ -988,12 +829,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
PyTraceBack_Here(f);
}
}
-
- if (tstate->c_tracefunc != NULL) {
- /* Make sure state is set to FRAME_UNWINDING for tracing */
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj,
- tstate, frame);
- }
+ monitor_raise(tstate, frame, next_instr-1);
exception_unwind:
{
@@ -1012,8 +848,7 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
}
assert(STACK_LEVEL() == 0);
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_UNWIND();
- DTRACE_FUNCTION_EXIT();
+ monitor_unwind(tstate, frame, next_instr-1);
goto exit_unwind;
}
@@ -1036,8 +871,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
available to the handler,
so a program can emulate the
Python main loop. */
- PUSH(_PyErr_GetRaisedException(tstate));
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ PUSH(exc);
JUMPTO(handler);
+ monitor_handled(tstate, frame, next_instr, exc);
/* Resume normal execution */
DISPATCH();
}
@@ -1051,10 +888,10 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, _PyInterpreterFrame *frame, int
_PyInterpreterFrame *dying = frame;
frame = cframe.current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
+ frame->return_offset = 0;
if (frame == &entry_frame) {
/* Restore previous cframe and exit */
tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
_Py_LeaveRecursiveCallTstate(tstate);
return NULL;
@@ -2020,105 +1857,108 @@ unpack_iterable(PyThreadState *tstate, PyObject *v,
return 0;
}
-static void
-call_exc_trace(Py_tracefunc func, PyObject *self,
- PyThreadState *tstate,
- _PyInterpreterFrame *f)
+static int
+do_monitor_exc(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, int event)
{
- PyObject *exc = _PyErr_GetRaisedException(tstate);
- assert(exc && PyExceptionInstance_Check(exc));
- PyObject *type = PyExceptionInstance_Class(exc);
- PyObject *traceback = PyException_GetTraceback(exc);
- if (traceback == NULL) {
- traceback = Py_NewRef(Py_None);
+ assert(event < PY_MONITORING_UNGROUPED_EVENTS);
+ PyObject *exc = PyErr_GetRaisedException();
+ assert(exc != NULL);
+ int err = _Py_call_instrumentation_arg(tstate, event, frame, instr, exc);
+ if (err == 0) {
+ PyErr_SetRaisedException(exc);
}
- PyObject *arg = PyTuple_Pack(3, type, exc, traceback);
- Py_XDECREF(traceback);
-
- if (arg == NULL) {
- _PyErr_SetRaisedException(tstate, exc);
- return;
+ else {
+ Py_DECREF(exc);
}
- int err = call_trace(func, self, tstate, f, PyTrace_EXCEPTION, arg);
- Py_DECREF(arg);
- if (err == 0) {
- _PyErr_SetRaisedException(tstate, exc);
+ return err;
+}
+
+static inline int
+no_tools_for_event(PyThreadState *tstate, _PyInterpreterFrame *frame, int event)
+{
+ _PyCoMonitoringData *data = frame->f_code->_co_monitoring;
+ if (data) {
+ if (data->active_monitors.tools[event] == 0) {
+ return 1;
+ }
}
else {
- Py_XDECREF(exc);
+ if (tstate->interp->monitors.tools[event] == 0) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static void
+monitor_raise(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
+{
+ if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_RAISE)) {
+ return;
}
+ do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_RAISE);
}
static int
-call_trace_protected(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame,
- int what, PyObject *arg)
+monitor_stop_iteration(PyThreadState *tstate, _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
{
- PyObject *exc = _PyErr_GetRaisedException(tstate);
- int err = call_trace(func, obj, tstate, frame, what, arg);
- if (err == 0)
- {
- _PyErr_SetRaisedException(tstate, exc);
+ if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_STOP_ITERATION)) {
return 0;
}
- else {
- Py_XDECREF(exc);
- return -1;
+ return do_monitor_exc(tstate, frame, instr, PY_MONITORING_EVENT_STOP_ITERATION);
+}
+
+static void
+monitor_unwind(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
+{
+ if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_UNWIND)) {
+ return;
+ }
+ _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_UNWIND, frame, instr);
+}
+
+
+static void
+monitor_handled(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr, PyObject *exc)
+{
+ if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_EXCEPTION_HANDLED)) {
+ return;
}
+ _Py_call_instrumentation_arg(tstate, PY_MONITORING_EVENT_EXCEPTION_HANDLED, frame, instr, exc);
}
static void
-initialize_trace_info(PyTraceInfo *trace_info, _PyInterpreterFrame *frame)
+monitor_throw(PyThreadState *tstate,
+ _PyInterpreterFrame *frame,
+ _Py_CODEUNIT *instr)
{
- PyCodeObject *code = frame->f_code;
- if (trace_info->code != code) {
- trace_info->code = code;
- _PyCode_InitAddressRange(code, &trace_info->bounds);
+ if (no_tools_for_event(tstate, frame, PY_MONITORING_EVENT_PY_THROW)) {
+ return;
}
+ _Py_call_instrumentation_exc0(tstate, PY_MONITORING_EVENT_PY_THROW, frame, instr);
}
void
PyThreadState_EnterTracing(PyThreadState *tstate)
{
+ assert(tstate->tracing >= 0);
tstate->tracing++;
- tstate->cframe->use_tracing = 0;
}
void
PyThreadState_LeaveTracing(PyThreadState *tstate)
{
- assert(tstate->tracing > 0 && tstate->cframe->use_tracing == 0);
+ assert(tstate->tracing > 0);
tstate->tracing--;
- _PyThreadState_UpdateTracingState(tstate);
}
-static int
-call_trace(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame,
- int what, PyObject *arg)
-{
- int result;
- if (tstate->tracing) {
- return 0;
- }
- PyFrameObject *f = _PyFrame_GetFrameObject(frame);
- if (f == NULL) {
- return -1;
- }
- int old_what = tstate->tracing_what;
- tstate->tracing_what = what;
- PyThreadState_EnterTracing(tstate);
- assert(_PyInterpreterFrame_LASTI(frame) >= 0);
- if (_PyCode_InitLineArray(frame->f_code)) {
- return -1;
- }
- f->f_lineno = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame));
- result = func(obj, f, what, arg);
- f->f_lineno = 0;
- PyThreadState_LeaveTracing(tstate);
- tstate->tracing_what = old_what;
- return result;
-}
PyObject*
_PyEval_CallTracing(PyObject *func, PyObject *args)
@@ -2126,7 +1966,6 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
// Save and disable tracing
PyThreadState *tstate = _PyThreadState_GET();
int save_tracing = tstate->tracing;
- int save_use_tracing = tstate->cframe->use_tracing;
tstate->tracing = 0;
// Call the tracing function
@@ -2134,81 +1973,9 @@ _PyEval_CallTracing(PyObject *func, PyObject *args)
// Restore tracing
tstate->tracing = save_tracing;
- tstate->cframe->use_tracing = save_use_tracing;
- return result;
-}
-
-/* See Objects/lnotab_notes.txt for a description of how tracing works. */
-static int
-maybe_call_line_trace(Py_tracefunc func, PyObject *obj,
- PyThreadState *tstate, _PyInterpreterFrame *frame, int instr_prev)
-{
- int result = 0;
-
- /* If the last instruction falls at the start of a line or if it
- represents a jump backwards, update the frame's line number and
- then call the trace function if we're tracing source lines.
- */
- if (_PyCode_InitLineArray(frame->f_code)) {
- return -1;
- }
- int lastline;
- if (instr_prev <= frame->f_code->_co_firsttraceable) {
- lastline = -1;
- }
- else {
- lastline = _PyCode_LineNumberFromArray(frame->f_code, instr_prev);
- }
- int line = _PyCode_LineNumberFromArray(frame->f_code, _PyInterpreterFrame_LASTI(frame));
- PyFrameObject *f = _PyFrame_GetFrameObject(frame);
- if (f == NULL) {
- return -1;
- }
- if (line != -1 && f->f_trace_lines) {
- /* Trace backward edges (except in 'yield from') or if line number has changed */
- int trace = line != lastline ||
- (_PyInterpreterFrame_LASTI(frame) < instr_prev &&
- // SEND has no quickened forms, so no need to use _PyOpcode_Deopt
- // here:
- frame->prev_instr->op.code != SEND);
- if (trace) {
- result = call_trace(func, obj, tstate, frame, PyTrace_LINE, Py_None);
- }
- }
- /* Always emit an opcode event if we're tracing all opcodes. */
- if (f->f_trace_opcodes && result == 0) {
- result = call_trace(func, obj, tstate, frame, PyTrace_OPCODE, Py_None);
- }
return result;
}
-int
-_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
-{
- assert(is_tstate_valid(tstate));
- /* The caller must hold the GIL */
- assert(PyGILState_Check());
-
- /* Call _PySys_Audit() in the context of the current thread state,
- even if tstate is not the current thread state. */
- PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
- return -1;
- }
-
- tstate->c_profilefunc = func;
- PyObject *old_profileobj = tstate->c_profileobj;
- tstate->c_profileobj = Py_XNewRef(arg);
- /* Flag that tracing or profiling is turned on */
- _PyThreadState_UpdateTracingState(tstate);
-
- // gh-98257: Only call Py_XDECREF() once the new profile function is fully
- // set, so it's safe to call sys.setprofile() again (reentrant call).
- Py_XDECREF(old_profileobj);
-
- return 0;
-}
-
void
PyEval_SetProfile(Py_tracefunc func, PyObject *arg)
{
@@ -2240,33 +2007,6 @@ PyEval_SetProfileAllThreads(Py_tracefunc func, PyObject *arg)
}
}
-int
-_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
-{
- assert(is_tstate_valid(tstate));
- /* The caller must hold the GIL */
- assert(PyGILState_Check());
-
- /* Call _PySys_Audit() in the context of the current thread state,
- even if tstate is not the current thread state. */
- PyThreadState *current_tstate = _PyThreadState_GET();
- if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
- return -1;
- }
-
- tstate->c_tracefunc = func;
- PyObject *old_traceobj = tstate->c_traceobj;
- tstate->c_traceobj = Py_XNewRef(arg);
- /* Flag that tracing or profiling is turned on */
- _PyThreadState_UpdateTracingState(tstate);
-
- // gh-98257: Only call Py_XDECREF() once the new trace function is fully
- // set, so it's safe to call sys.settrace() again (reentrant call).
- Py_XDECREF(old_traceobj);
-
- return 0;
-}
-
void
PyEval_SetTrace(Py_tracefunc func, PyObject *arg)
{
@@ -2492,114 +2232,6 @@ PyEval_GetFuncDesc(PyObject *func)
return " object";
}
-#define C_TRACE(x, call) \
-if (use_tracing && tstate->c_profilefunc) { \
- if (call_trace(tstate->c_profilefunc, tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_CALL, func)) { \
- x = NULL; \
- } \
- else { \
- x = call; \
- if (tstate->c_profilefunc != NULL) { \
- if (x == NULL) { \
- call_trace_protected(tstate->c_profilefunc, \
- tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_EXCEPTION, func); \
- /* XXX should pass (type, value, tb) */ \
- } else { \
- if (call_trace(tstate->c_profilefunc, \
- tstate->c_profileobj, \
- tstate, tstate->cframe->current_frame, \
- PyTrace_C_RETURN, func)) { \
- Py_DECREF(x); \
- x = NULL; \
- } \
- } \
- } \
- } \
-} else { \
- x = call; \
- }
-
-
-static PyObject *
-trace_call_function(PyThreadState *tstate,
- PyObject *func,
- PyObject **args, Py_ssize_t nargs,
- PyObject *kwnames)
-{
- int use_tracing = 1;
- PyObject *x;
- if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) {
- C_TRACE(x, PyObject_Vectorcall(func, args, nargs, kwnames));
- return x;
- }
- else if (Py_IS_TYPE(func, &PyMethodDescr_Type) && nargs > 0) {
- /* We need to create a temporary bound method as argument
- for profiling.
-
- If nargs == 0, then this cannot work because we have no
- "self". In any case, the call itself would raise
- TypeError (foo needs an argument), so we just skip
- profiling. */
- PyObject *self = args[0];
- func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
- if (func == NULL) {
- return NULL;
- }
- C_TRACE(x, PyObject_Vectorcall(func,
- args+1, nargs-1,
- kwnames));
- Py_DECREF(func);
- return x;
- }
- return PyObject_Vectorcall(func, args, nargs | PY_VECTORCALL_ARGUMENTS_OFFSET, kwnames);
-}
-
-static PyObject *
-do_call_core(PyThreadState *tstate,
- PyObject *func,
- PyObject *callargs,
- PyObject *kwdict,
- int use_tracing
- )
-{
- PyObject *result;
- if (PyCFunction_CheckExact(func) || PyCMethod_CheckExact(func)) {
- C_TRACE(result, PyObject_Call(func, callargs, kwdict));
- return result;
- }
- else if (Py_IS_TYPE(func, &PyMethodDescr_Type)) {
- Py_ssize_t nargs = PyTuple_GET_SIZE(callargs);
- if (nargs > 0 && use_tracing) {
- /* We need to create a temporary bound method as argument
- for profiling.
-
- If nargs == 0, then this cannot work because we have no
- "self". In any case, the call itself would raise
- TypeError (foo needs an argument), so we just skip
- profiling. */
- PyObject *self = PyTuple_GET_ITEM(callargs, 0);
- func = Py_TYPE(func)->tp_descr_get(func, self, (PyObject*)Py_TYPE(self));
- if (func == NULL) {
- return NULL;
- }
-
- C_TRACE(result, _PyObject_FastCallDictTstate(
- tstate, func,
- &_PyTuple_ITEMS(callargs)[1],
- nargs - 1,
- kwdict));
- Py_DECREF(func);
- return result;
- }
- }
- EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func);
- return PyObject_Call(func, callargs, kwdict);
-}
-
/* Extract a slice index from a PyLong or an object with the
nb_index slot defined, and store in *pi.
Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX,
@@ -2973,69 +2605,6 @@ PyUnstable_Eval_RequestCodeExtraIndex(freefunc free)
return new_index;
}
-static void
-dtrace_function_entry(_PyInterpreterFrame *frame)
-{
- const char *filename;
- const char *funcname;
- int lineno;
-
- PyCodeObject *code = frame->f_code;
- filename = PyUnicode_AsUTF8(code->co_filename);
- funcname = PyUnicode_AsUTF8(code->co_name);
- lineno = _PyInterpreterFrame_GetLine(frame);
-
- PyDTrace_FUNCTION_ENTRY(filename, funcname, lineno);
-}
-
-static void
-dtrace_function_return(_PyInterpreterFrame *frame)
-{
- const char *filename;
- const char *funcname;
- int lineno;
-
- PyCodeObject *code = frame->f_code;
- filename = PyUnicode_AsUTF8(code->co_filename);
- funcname = PyUnicode_AsUTF8(code->co_name);
- lineno = _PyInterpreterFrame_GetLine(frame);
-
- PyDTrace_FUNCTION_RETURN(filename, funcname, lineno);
-}
-
-/* DTrace equivalent of maybe_call_line_trace. */
-static void
-maybe_dtrace_line(_PyInterpreterFrame *frame,
- PyTraceInfo *trace_info,
- int instr_prev)
-{
- const char *co_filename, *co_name;
-
- /* If the last instruction executed isn't in the current
- instruction window, reset the window.
- */
- initialize_trace_info(trace_info, frame);
- int lastline = _PyCode_CheckLineNumber(instr_prev*sizeof(_Py_CODEUNIT), &trace_info->bounds);
- int addr = _PyInterpreterFrame_LASTI(frame) * sizeof(_Py_CODEUNIT);
- int line = _PyCode_CheckLineNumber(addr, &trace_info->bounds);
- if (line != -1) {
- /* Trace backward edges or first instruction of a new line */
- if (_PyInterpreterFrame_LASTI(frame) < instr_prev ||
- (line != lastline && addr == trace_info->bounds.ar_start))
- {
- co_filename = PyUnicode_AsUTF8(frame->f_code->co_filename);
- if (!co_filename) {
- co_filename = "?";
- }
- co_name = PyUnicode_AsUTF8(frame->f_code->co_name);
- if (!co_name) {
- co_name = "?";
- }
- PyDTrace_LINE(co_filename, co_name, line);
- }
- }
-}
-
/* Implement Py_EnterRecursiveCall() and Py_LeaveRecursiveCall() as functions
for the limited API. */
diff --git a/Python/ceval_macros.h b/Python/ceval_macros.h
index c2257515a30599..485771ac65a767 100644
--- a/Python/ceval_macros.h
+++ b/Python/ceval_macros.h
@@ -93,8 +93,6 @@
{ \
NEXTOPARG(); \
PRE_DISPATCH_GOTO(); \
- assert(cframe.use_tracing == 0 || cframe.use_tracing == 255); \
- opcode |= cframe.use_tracing OR_DTRACE_LINE; \
DISPATCH_GOTO(); \
}
@@ -102,7 +100,6 @@
{ \
opcode = next_instr->op.code; \
PRE_DISPATCH_GOTO(); \
- opcode |= cframe.use_tracing OR_DTRACE_LINE; \
DISPATCH_GOTO(); \
}
@@ -183,7 +180,7 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define PREDICT(next_op) \
do { \
_Py_CODEUNIT word = *next_instr; \
- opcode = word.op.code | cframe.use_tracing OR_DTRACE_LINE; \
+ opcode = word.op.code; \
if (opcode == next_op) { \
oparg = word.op.arg; \
INSTRUCTION_START(next_op); \
@@ -283,47 +280,6 @@ GETITEM(PyObject *v, Py_ssize_t i) {
#define BUILTINS() frame->f_builtins
#define LOCALS() frame->f_locals
-/* Shared opcode macros */
-
-#define TRACE_FUNCTION_EXIT() \
- if (cframe.use_tracing) { \
- if (trace_function_exit(tstate, frame, retval)) { \
- Py_DECREF(retval); \
- goto exit_unwind; \
- } \
- }
-
-#define DTRACE_FUNCTION_EXIT() \
- if (PyDTrace_FUNCTION_RETURN_ENABLED()) { \
- dtrace_function_return(frame); \
- }
-
-#define TRACE_FUNCTION_UNWIND() \
- if (cframe.use_tracing) { \
- /* Since we are already unwinding, \
- * we don't care if this raises */ \
- trace_function_exit(tstate, frame, NULL); \
- }
-
-#define TRACE_FUNCTION_ENTRY() \
- if (cframe.use_tracing) { \
- _PyFrame_SetStackPointer(frame, stack_pointer); \
- int err = trace_function_entry(tstate, frame); \
- stack_pointer = _PyFrame_GetStackPointer(frame); \
- frame->stacktop = -1; \
- if (err) { \
- goto error; \
- } \
- }
-
-#define TRACE_FUNCTION_THROW_ENTRY() \
- if (cframe.use_tracing) { \
- assert(frame->stacktop >= 0); \
- if (trace_function_entry(tstate, frame)) { \
- goto exit_unwind; \
- } \
- }
-
#define DTRACE_FUNCTION_ENTRY() \
if (PyDTrace_FUNCTION_ENTRY_ENABLED()) { \
dtrace_function_entry(frame); \
@@ -371,3 +327,18 @@ do { \
_Py_DECREF_NO_DEALLOC(right); \
} \
} while (0)
+
+// If a trace function sets a new f_lineno and
+// *then* raises, we use the destination when searching
+// for an exception handler, displaying the traceback, and so on
+#define INSTRUMENTED_JUMP(src, dest, event) \
+do { \
+ _PyFrame_SetStackPointer(frame, stack_pointer); \
+ int err = _Py_call_instrumentation_jump(tstate, event, frame, src, dest); \
+ stack_pointer = _PyFrame_GetStackPointer(frame); \
+ if (err) { \
+ next_instr = (dest)+1; \
+ goto error; \
+ } \
+ next_instr = frame->prev_instr; \
+} while (0);
diff --git a/Python/clinic/instrumentation.c.h b/Python/clinic/instrumentation.c.h
new file mode 100644
index 00000000000000..cf3984ca24bbfe
--- /dev/null
+++ b/Python/clinic/instrumentation.c.h
@@ -0,0 +1,311 @@
+/*[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(monitoring_use_tool_id__doc__,
+"use_tool_id($module, tool_id, name, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_USE_TOOL_ID_METHODDEF \
+ {"use_tool_id", _PyCFunction_CAST(monitoring_use_tool_id), METH_FASTCALL, monitoring_use_tool_id__doc__},
+
+static PyObject *
+monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name);
+
+static PyObject *
+monitoring_use_tool_id(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ PyObject *name;
+
+ if (!_PyArg_CheckPositional("use_tool_id", nargs, 2, 2)) {
+ goto exit;
+ }
+ tool_id = _PyLong_AsInt(args[0]);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ name = args[1];
+ return_value = monitoring_use_tool_id_impl(module, tool_id, name);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_free_tool_id__doc__,
+"free_tool_id($module, tool_id, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_FREE_TOOL_ID_METHODDEF \
+ {"free_tool_id", (PyCFunction)monitoring_free_tool_id, METH_O, monitoring_free_tool_id__doc__},
+
+static PyObject *
+monitoring_free_tool_id_impl(PyObject *module, int tool_id);
+
+static PyObject *
+monitoring_free_tool_id(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+
+ tool_id = _PyLong_AsInt(arg);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = monitoring_free_tool_id_impl(module, tool_id);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_get_tool__doc__,
+"get_tool($module, tool_id, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_GET_TOOL_METHODDEF \
+ {"get_tool", (PyCFunction)monitoring_get_tool, METH_O, monitoring_get_tool__doc__},
+
+static PyObject *
+monitoring_get_tool_impl(PyObject *module, int tool_id);
+
+static PyObject *
+monitoring_get_tool(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+
+ tool_id = _PyLong_AsInt(arg);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = monitoring_get_tool_impl(module, tool_id);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_register_callback__doc__,
+"register_callback($module, tool_id, event, func, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_REGISTER_CALLBACK_METHODDEF \
+ {"register_callback", _PyCFunction_CAST(monitoring_register_callback), METH_FASTCALL, monitoring_register_callback__doc__},
+
+static PyObject *
+monitoring_register_callback_impl(PyObject *module, int tool_id, int event,
+ PyObject *func);
+
+static PyObject *
+monitoring_register_callback(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ int event;
+ PyObject *func;
+
+ if (!_PyArg_CheckPositional("register_callback", nargs, 3, 3)) {
+ goto exit;
+ }
+ tool_id = _PyLong_AsInt(args[0]);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ event = _PyLong_AsInt(args[1]);
+ if (event == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ func = args[2];
+ return_value = monitoring_register_callback_impl(module, tool_id, event, func);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_get_events__doc__,
+"get_events($module, tool_id, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_GET_EVENTS_METHODDEF \
+ {"get_events", (PyCFunction)monitoring_get_events, METH_O, monitoring_get_events__doc__},
+
+static int
+monitoring_get_events_impl(PyObject *module, int tool_id);
+
+static PyObject *
+monitoring_get_events(PyObject *module, PyObject *arg)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ int _return_value;
+
+ tool_id = _PyLong_AsInt(arg);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ _return_value = monitoring_get_events_impl(module, tool_id);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromLong((long)_return_value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_set_events__doc__,
+"set_events($module, tool_id, event_set, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_SET_EVENTS_METHODDEF \
+ {"set_events", _PyCFunction_CAST(monitoring_set_events), METH_FASTCALL, monitoring_set_events__doc__},
+
+static PyObject *
+monitoring_set_events_impl(PyObject *module, int tool_id, int event_set);
+
+static PyObject *
+monitoring_set_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ int event_set;
+
+ if (!_PyArg_CheckPositional("set_events", nargs, 2, 2)) {
+ goto exit;
+ }
+ tool_id = _PyLong_AsInt(args[0]);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ event_set = _PyLong_AsInt(args[1]);
+ if (event_set == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = monitoring_set_events_impl(module, tool_id, event_set);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_get_local_events__doc__,
+"get_local_events($module, tool_id, code, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_GET_LOCAL_EVENTS_METHODDEF \
+ {"get_local_events", _PyCFunction_CAST(monitoring_get_local_events), METH_FASTCALL, monitoring_get_local_events__doc__},
+
+static int
+monitoring_get_local_events_impl(PyObject *module, int tool_id,
+ PyObject *code);
+
+static PyObject *
+monitoring_get_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ PyObject *code;
+ int _return_value;
+
+ if (!_PyArg_CheckPositional("get_local_events", nargs, 2, 2)) {
+ goto exit;
+ }
+ tool_id = _PyLong_AsInt(args[0]);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ code = args[1];
+ _return_value = monitoring_get_local_events_impl(module, tool_id, code);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromLong((long)_return_value);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_set_local_events__doc__,
+"set_local_events($module, tool_id, code, event_set, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_SET_LOCAL_EVENTS_METHODDEF \
+ {"set_local_events", _PyCFunction_CAST(monitoring_set_local_events), METH_FASTCALL, monitoring_set_local_events__doc__},
+
+static PyObject *
+monitoring_set_local_events_impl(PyObject *module, int tool_id,
+ PyObject *code, int event_set);
+
+static PyObject *
+monitoring_set_local_events(PyObject *module, PyObject *const *args, Py_ssize_t nargs)
+{
+ PyObject *return_value = NULL;
+ int tool_id;
+ PyObject *code;
+ int event_set;
+
+ if (!_PyArg_CheckPositional("set_local_events", nargs, 3, 3)) {
+ goto exit;
+ }
+ tool_id = _PyLong_AsInt(args[0]);
+ if (tool_id == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ code = args[1];
+ event_set = _PyLong_AsInt(args[2]);
+ if (event_set == -1 && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = monitoring_set_local_events_impl(module, tool_id, code, event_set);
+
+exit:
+ return return_value;
+}
+
+PyDoc_STRVAR(monitoring_restart_events__doc__,
+"restart_events($module, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING_RESTART_EVENTS_METHODDEF \
+ {"restart_events", (PyCFunction)monitoring_restart_events, METH_NOARGS, monitoring_restart_events__doc__},
+
+static PyObject *
+monitoring_restart_events_impl(PyObject *module);
+
+static PyObject *
+monitoring_restart_events(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return monitoring_restart_events_impl(module);
+}
+
+PyDoc_STRVAR(monitoring__all_events__doc__,
+"_all_events($module, /)\n"
+"--\n"
+"\n");
+
+#define MONITORING__ALL_EVENTS_METHODDEF \
+ {"_all_events", (PyCFunction)monitoring__all_events, METH_NOARGS, monitoring__all_events__doc__},
+
+static PyObject *
+monitoring__all_events_impl(PyObject *module);
+
+static PyObject *
+monitoring__all_events(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ return monitoring__all_events_impl(module);
+}
+/*[clinic end generated code: output=11cc0803875b3ffa input=a9049054013a1b77]*/
diff --git a/Python/clinic/sysmodule.c.h b/Python/clinic/sysmodule.c.h
index 46252dd404325b..7a7c188bcccc37 100644
--- a/Python/clinic/sysmodule.c.h
+++ b/Python/clinic/sysmodule.c.h
@@ -912,6 +912,34 @@ sys_getallocatedblocks(PyObject *module, PyObject *Py_UNUSED(ignored))
return return_value;
}
+PyDoc_STRVAR(sys_getunicodeinternedsize__doc__,
+"getunicodeinternedsize($module, /)\n"
+"--\n"
+"\n"
+"Return the number of elements of the unicode interned dictionary");
+
+#define SYS_GETUNICODEINTERNEDSIZE_METHODDEF \
+ {"getunicodeinternedsize", (PyCFunction)sys_getunicodeinternedsize, METH_NOARGS, sys_getunicodeinternedsize__doc__},
+
+static Py_ssize_t
+sys_getunicodeinternedsize_impl(PyObject *module);
+
+static PyObject *
+sys_getunicodeinternedsize(PyObject *module, PyObject *Py_UNUSED(ignored))
+{
+ PyObject *return_value = NULL;
+ Py_ssize_t _return_value;
+
+ _return_value = sys_getunicodeinternedsize_impl(module);
+ if ((_return_value == -1) && PyErr_Occurred()) {
+ goto exit;
+ }
+ return_value = PyLong_FromSsize_t(_return_value);
+
+exit:
+ return return_value;
+}
+
PyDoc_STRVAR(sys__getframe__doc__,
"_getframe($module, depth=0, /)\n"
"--\n"
@@ -1387,4 +1415,4 @@ sys__getframemodulename(PyObject *module, PyObject *const *args, Py_ssize_t narg
#ifndef SYS_GETANDROIDAPILEVEL_METHODDEF
#define SYS_GETANDROIDAPILEVEL_METHODDEF
#endif /* !defined(SYS_GETANDROIDAPILEVEL_METHODDEF) */
-/*[clinic end generated code: output=5c761f14326ced54 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6d598acc26237fbe input=a9049054013a1b77]*/
diff --git a/Python/codecs.c b/Python/codecs.c
index 9d800f9856c2f7..1983f56ba204c1 100644
--- a/Python/codecs.c
+++ b/Python/codecs.c
@@ -11,6 +11,7 @@ Copyright (c) Corporation for National Research Initiatives.
#include "Python.h"
#include "pycore_call.h" // _PyObject_CallNoArgs()
#include "pycore_interp.h" // PyInterpreterState.codec_search_path
+#include "pycore_pyerrors.h" // _PyErr_FormatNote()
#include "pycore_pystate.h" // _PyInterpreterState_GET()
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
#include
@@ -382,29 +383,6 @@ PyObject *PyCodec_StreamWriter(const char *encoding,
return codec_getstreamcodec(encoding, stream, errors, 3);
}
-static void
-add_note_to_codec_error(const char *operation,
- const char *encoding)
-{
- PyObject *exc = PyErr_GetRaisedException();
- if (exc == NULL) {
- return;
- }
- PyObject *note = PyUnicode_FromFormat("%s with '%s' codec failed",
- operation, encoding);
- if (note == NULL) {
- _PyErr_ChainExceptions1(exc);
- return;
- }
- int res = _PyException_AddNote(exc, note);
- Py_DECREF(note);
- if (res < 0) {
- _PyErr_ChainExceptions1(exc);
- return;
- }
- PyErr_SetRaisedException(exc);
-}
-
/* Encode an object (e.g. a Unicode object) using the given encoding
and return the resulting encoded object (usually a Python string).
@@ -425,7 +403,7 @@ _PyCodec_EncodeInternal(PyObject *object,
result = PyObject_Call(encoder, args, NULL);
if (result == NULL) {
- add_note_to_codec_error("encoding", encoding);
+ _PyErr_FormatNote("%s with '%s' codec failed", "encoding", encoding);
goto onError;
}
@@ -470,7 +448,7 @@ _PyCodec_DecodeInternal(PyObject *object,
result = PyObject_Call(decoder, args, NULL);
if (result == NULL) {
- add_note_to_codec_error("decoding", encoding);
+ _PyErr_FormatNote("%s with '%s' codec failed", "decoding", encoding);
goto onError;
}
if (!PyTuple_Check(result) ||
diff --git a/Python/compile.c b/Python/compile.c
index fed9ae7066e4f0..a0ad3687f586d8 100644
--- a/Python/compile.c
+++ b/Python/compile.c
@@ -6,10 +6,10 @@
* object:
* 1. Checks for future statements. See future.c
* 2. Builds a symbol table. See symtable.c.
- * 3. Generate code for basic blocks. See compiler_mod() in this file.
- * 4. Assemble the basic blocks into final code. See assemble() in
- * this file.
- * 5. Optimize the byte code (peephole optimizations).
+ * 3. Generate an instruction sequence. See compiler_mod() in this file.
+ * 4. Generate a control flow graph and run optimizations on it. See flowgraph.c.
+ * 5. Assemble the basic blocks into final code. See optimize_and_assemble() in
+ * this file, and assembler.c.
*
* Note that compiler_mod() suggests module, but the module ast type
* (mod_ty) has cases for expressions and interactive statements.
@@ -101,15 +101,6 @@ location_is_after(location loc1, location loc2) {
(loc1.col_offset > loc2.end_col_offset));
}
-static inline bool
-same_location(location a, location b)
-{
- return a.lineno == b.lineno &&
- a.end_lineno == b.end_lineno &&
- a.col_offset == b.col_offset &&
- a.end_col_offset == b.end_col_offset;
-}
-
#define LOC(x) SRC_LOCATION_FROM_AST(x)
typedef _PyCfgJumpTargetLabel jump_target_label;
@@ -129,46 +120,6 @@ static jump_target_label NO_LABEL = {-1};
RETURN_IF_ERROR(instr_sequence_use_label(INSTR_SEQUENCE(C), (LBL).id))
-static void
-write_instr(_Py_CODEUNIT *codestr, cfg_instr *instruction, int ilen)
-{
- int opcode = instruction->i_opcode;
- assert(!IS_PSEUDO_OPCODE(opcode));
- int oparg = instruction->i_oparg;
- assert(HAS_ARG(opcode) || oparg == 0);
- int caches = _PyOpcode_Caches[opcode];
- switch (ilen - caches) {
- case 4:
- codestr->op.code = EXTENDED_ARG;
- codestr->op.arg = (oparg >> 24) & 0xFF;
- codestr++;
- /* fall through */
- case 3:
- codestr->op.code = EXTENDED_ARG;
- codestr->op.arg = (oparg >> 16) & 0xFF;
- codestr++;
- /* fall through */
- case 2:
- codestr->op.code = EXTENDED_ARG;
- codestr->op.arg = (oparg >> 8) & 0xFF;
- codestr++;
- /* fall through */
- case 1:
- codestr->op.code = opcode;
- codestr->op.arg = oparg & 0xFF;
- codestr++;
- break;
- default:
- Py_UNREACHABLE();
- }
- while (caches--) {
- codestr->op.code = CACHE;
- codestr->op.arg = 0;
- codestr++;
- }
-}
-
-
/* fblockinfo tracks the current frame block.
A frame block is used to handle loops, try/except, and try/finally.
@@ -198,21 +149,8 @@ enum {
COMPILER_SCOPE_COMPREHENSION,
};
-typedef struct {
- int i_opcode;
- int i_oparg;
- location i_loc;
-} instruction;
-
-typedef struct instr_sequence_ {
- instruction *s_instrs;
- int s_allocated;
- int s_used;
-
- int *s_labelmap; /* label id --> instr offset */
- int s_labelmap_size;
- int s_next_free_label; /* next free label id */
-} instr_sequence;
+typedef _PyCompilerInstruction instruction;
+typedef _PyCompile_InstructionSequence instr_sequence;
#define INITIAL_INSTR_SEQUENCE_SIZE 100
#define INITIAL_INSTR_SEQUENCE_LABELS_MAP_SIZE 10
@@ -314,7 +252,6 @@ static int
instr_sequence_addop(instr_sequence *seq, int opcode, int oparg, location loc)
{
assert(IS_WITHIN_OPCODE_RANGE(opcode));
- assert(!IS_ASSEMBLER_OPCODE(opcode));
assert(HAS_ARG(opcode) || HAS_TARGET(opcode) || oparg == 0);
assert(0 <= oparg && oparg < (1 << 30));
@@ -432,32 +369,17 @@ instr_sequence_to_cfg(instr_sequence *seq, cfg_builder *g) {
struct compiler_unit {
PySTEntryObject *u_ste;
- PyObject *u_name;
- PyObject *u_qualname; /* dot-separated qualified name (lazy) */
int u_scope_type;
- /* The following fields are dicts that map objects to
- the index of them in co_XXX. The index is used as
- the argument for opcodes that refer to those collections.
- */
- PyObject *u_consts; /* all constants */
- PyObject *u_names; /* all names */
- PyObject *u_varnames; /* local variables */
- PyObject *u_cellvars; /* cell variables */
- PyObject *u_freevars; /* free variables */
PyObject *u_private; /* for private name mangling */
- Py_ssize_t u_argcount; /* number of arguments for block */
- Py_ssize_t u_posonlyargcount; /* number of positional only arguments for block */
- Py_ssize_t u_kwonlyargcount; /* number of keyword only arguments for block */
-
instr_sequence u_instr_sequence; /* codegen output */
int u_nfblocks;
struct fblockinfo u_fblock[CO_MAXBLOCKS];
- int u_firstlineno; /* the first lineno of the block */
+ _PyCompile_CodeUnitMetadata u_metadata;
};
/* This struct captures the global state of a compilation.
@@ -566,7 +488,7 @@ static int compiler_match(struct compiler *, stmt_ty);
static int compiler_pattern_subpattern(struct compiler *,
pattern_ty, pattern_context *);
-static PyCodeObject *assemble(struct compiler *, int addNone);
+static PyCodeObject *optimize_and_assemble(struct compiler *, int addNone);
#define CAPSULE_NAME "compile.c compiler unit"
@@ -750,13 +672,13 @@ compiler_unit_free(struct compiler_unit *u)
{
instr_sequence_fini(&u->u_instr_sequence);
Py_CLEAR(u->u_ste);
- Py_CLEAR(u->u_name);
- Py_CLEAR(u->u_qualname);
- Py_CLEAR(u->u_consts);
- Py_CLEAR(u->u_names);
- Py_CLEAR(u->u_varnames);
- Py_CLEAR(u->u_freevars);
- Py_CLEAR(u->u_cellvars);
+ Py_CLEAR(u->u_metadata.u_name);
+ Py_CLEAR(u->u_metadata.u_qualname);
+ Py_CLEAR(u->u_metadata.u_consts);
+ Py_CLEAR(u->u_metadata.u_names);
+ Py_CLEAR(u->u_metadata.u_varnames);
+ Py_CLEAR(u->u_metadata.u_freevars);
+ Py_CLEAR(u->u_metadata.u_cellvars);
Py_CLEAR(u->u_private);
PyObject_Free(u);
}
@@ -783,8 +705,8 @@ compiler_set_qualname(struct compiler *c)
if (u->u_scope_type == COMPILER_SCOPE_FUNCTION
|| u->u_scope_type == COMPILER_SCOPE_ASYNC_FUNCTION
|| u->u_scope_type == COMPILER_SCOPE_CLASS) {
- assert(u->u_name);
- mangled = _Py_Mangle(parent->u_private, u->u_name);
+ assert(u->u_metadata.u_name);
+ mangled = _Py_Mangle(parent->u_private, u->u_metadata.u_name);
if (!mangled) {
return ERROR;
}
@@ -802,14 +724,14 @@ compiler_set_qualname(struct compiler *c)
|| parent->u_scope_type == COMPILER_SCOPE_LAMBDA)
{
_Py_DECLARE_STR(dot_locals, ".");
- base = PyUnicode_Concat(parent->u_qualname,
+ base = PyUnicode_Concat(parent->u_metadata.u_qualname,
&_Py_STR(dot_locals));
if (base == NULL) {
return ERROR;
}
}
else {
- base = Py_NewRef(parent->u_qualname);
+ base = Py_NewRef(parent->u_metadata.u_qualname);
}
}
}
@@ -821,15 +743,15 @@ compiler_set_qualname(struct compiler *c)
if (name == NULL) {
return ERROR;
}
- PyUnicode_Append(&name, u->u_name);
+ PyUnicode_Append(&name, u->u_metadata.u_name);
if (name == NULL) {
return ERROR;
}
}
else {
- name = Py_NewRef(u->u_name);
+ name = Py_NewRef(u->u_metadata.u_name);
}
- u->u_qualname = name;
+ u->u_metadata.u_qualname = name;
return SUCCESS;
}
@@ -907,6 +829,10 @@ stack_effect(int opcode, int oparg, int jump)
case LOAD_METHOD:
return 1;
+ case LOAD_SUPER_METHOD:
+ case LOAD_ZERO_SUPER_METHOD:
+ case LOAD_ZERO_SUPER_ATTR:
+ return -1;
default:
return PY_INVALID_STACK_EFFECT;
}
@@ -930,6 +856,7 @@ static int
codegen_addop_noarg(instr_sequence *seq, int opcode, location loc)
{
assert(!HAS_ARG(opcode));
+ assert(!IS_ASSEMBLER_OPCODE(opcode));
return instr_sequence_addop(seq, opcode, 0, loc);
}
@@ -1077,7 +1004,7 @@ compiler_add_const(PyObject *const_cache, struct compiler_unit *u, PyObject *o)
return ERROR;
}
- Py_ssize_t arg = dict_add_o(u->u_consts, key);
+ Py_ssize_t arg = dict_add_o(u->u_metadata.u_consts, key);
Py_DECREF(key);
return arg;
}
@@ -1124,6 +1051,24 @@ compiler_addop_name(struct compiler_unit *u, location loc,
arg <<= 1;
arg |= 1;
}
+ if (opcode == LOAD_SUPER_ATTR) {
+ arg <<= 2;
+ arg |= 2;
+ }
+ if (opcode == LOAD_SUPER_METHOD) {
+ opcode = LOAD_SUPER_ATTR;
+ arg <<= 2;
+ arg |= 3;
+ }
+ if (opcode == LOAD_ZERO_SUPER_ATTR) {
+ opcode = LOAD_SUPER_ATTR;
+ arg <<= 2;
+ }
+ if (opcode == LOAD_ZERO_SUPER_METHOD) {
+ opcode = LOAD_SUPER_ATTR;
+ arg <<= 2;
+ arg |= 1;
+ }
return codegen_addop_i(&u->u_instr_sequence, opcode, arg, loc);
}
@@ -1140,6 +1085,7 @@ codegen_addop_i(instr_sequence *seq, int opcode, Py_ssize_t oparg, location loc)
EXTENDED_ARG is used for 16, 24, and 32-bit arguments. */
int oparg_ = Py_SAFE_DOWNCAST(oparg, Py_ssize_t, int);
+ assert(!IS_ASSEMBLER_OPCODE(opcode));
return instr_sequence_addop(seq, opcode, oparg_, loc);
}
@@ -1149,6 +1095,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
{
assert(IS_LABEL(target));
assert(IS_JUMP_OPCODE(opcode) || IS_BLOCK_PUSH_OPCODE(opcode));
+ assert(!IS_ASSEMBLER_OPCODE(opcode));
return instr_sequence_addop(seq, opcode, target.id, loc);
}
@@ -1180,7 +1127,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
#define ADDOP_N(C, LOC, OP, O, TYPE) { \
assert(!HAS_CONST(OP)); /* use ADDOP_LOAD_CONST_NEW */ \
- if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O)) < 0) { \
+ if (compiler_addop_o((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)) < 0) { \
Py_DECREF((O)); \
return ERROR; \
} \
@@ -1188,7 +1135,7 @@ codegen_addop_j(instr_sequence *seq, location loc,
}
#define ADDOP_NAME(C, LOC, OP, O, TYPE) \
- RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_ ## TYPE, (O)))
+ RETURN_IF_ERROR(compiler_addop_name((C)->u, (LOC), (OP), (C)->u->u_metadata.u_ ## TYPE, (O)))
#define ADDOP_I(C, LOC, OP, O) \
RETURN_IF_ERROR(codegen_addop_i(INSTR_SEQUENCE(C), (OP), (O), (LOC)))
@@ -1265,18 +1212,18 @@ compiler_enter_scope(struct compiler *c, identifier name,
return ERROR;
}
u->u_scope_type = scope_type;
- u->u_argcount = 0;
- u->u_posonlyargcount = 0;
- u->u_kwonlyargcount = 0;
+ u->u_metadata.u_argcount = 0;
+ u->u_metadata.u_posonlyargcount = 0;
+ u->u_metadata.u_kwonlyargcount = 0;
u->u_ste = PySymtable_Lookup(c->c_st, key);
if (!u->u_ste) {
compiler_unit_free(u);
return ERROR;
}
- u->u_name = Py_NewRef(name);
- u->u_varnames = list2dict(u->u_ste->ste_varnames);
- u->u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0);
- if (!u->u_varnames || !u->u_cellvars) {
+ u->u_metadata.u_name = Py_NewRef(name);
+ u->u_metadata.u_varnames = list2dict(u->u_ste->ste_varnames);
+ u->u_metadata.u_cellvars = dictbytype(u->u_ste->ste_symbols, CELL, 0, 0);
+ if (!u->u_metadata.u_varnames || !u->u_metadata.u_cellvars) {
compiler_unit_free(u);
return ERROR;
}
@@ -1284,8 +1231,8 @@ compiler_enter_scope(struct compiler *c, identifier name,
/* Cook up an implicit __class__ cell. */
int res;
assert(u->u_scope_type == COMPILER_SCOPE_CLASS);
- assert(PyDict_GET_SIZE(u->u_cellvars) == 0);
- res = PyDict_SetItem(u->u_cellvars, &_Py_ID(__class__),
+ assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) == 0);
+ res = PyDict_SetItem(u->u_metadata.u_cellvars, &_Py_ID(__class__),
_PyLong_GetZero());
if (res < 0) {
compiler_unit_free(u);
@@ -1293,22 +1240,22 @@ compiler_enter_scope(struct compiler *c, identifier name,
}
}
- u->u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
- PyDict_GET_SIZE(u->u_cellvars));
- if (!u->u_freevars) {
+ u->u_metadata.u_freevars = dictbytype(u->u_ste->ste_symbols, FREE, DEF_FREE_CLASS,
+ PyDict_GET_SIZE(u->u_metadata.u_cellvars));
+ if (!u->u_metadata.u_freevars) {
compiler_unit_free(u);
return ERROR;
}
u->u_nfblocks = 0;
- u->u_firstlineno = lineno;
- u->u_consts = PyDict_New();
- if (!u->u_consts) {
+ u->u_metadata.u_firstlineno = lineno;
+ u->u_metadata.u_consts = PyDict_New();
+ if (!u->u_metadata.u_consts) {
compiler_unit_free(u);
return ERROR;
}
- u->u_names = PyDict_New();
- if (!u->u_names) {
+ u->u_metadata.u_names = PyDict_New();
+ if (!u->u_metadata.u_names) {
compiler_unit_free(u);
return ERROR;
}
@@ -1502,8 +1449,7 @@ compiler_add_yield_from(struct compiler *c, location loc, int await)
ADDOP(c, loc, CLEANUP_THROW);
USE_LABEL(c, exit);
- ADDOP_I(c, loc, SWAP, 2);
- ADDOP(c, loc, POP_TOP);
+ ADDOP(c, loc, END_SEND);
return SUCCESS;
}
@@ -1667,7 +1613,7 @@ compiler_body(struct compiler *c, location loc, asdl_stmt_seq *stmts)
/* Set current line number to the line number of first statement.
This way line number for SETUP_ANNOTATIONS will always
coincide with the line number of first "real" statement in module.
- If body is empty, then lineno will be set later in assemble. */
+ If body is empty, then lineno will be set later in optimize_and_assemble. */
if (c->u->u_scope_type == COMPILER_SCOPE_MODULE && asdl_seq_LEN(stmts)) {
st = (stmt_ty)asdl_seq_GET(stmts, 0);
loc = LOC(st);
@@ -1738,7 +1684,7 @@ compiler_mod(struct compiler *c, mod_ty mod)
if (compiler_codegen(c, mod) < 0) {
return NULL;
}
- PyCodeObject *co = assemble(c, addNone);
+ PyCodeObject *co = optimize_and_assemble(c, addNone);
compiler_exit_scope(c);
return co;
}
@@ -1762,8 +1708,8 @@ get_ref_type(struct compiler *c, PyObject *name)
"unknown scope in unit %S (%R); "
"symbols: %R; locals: %R; globals: %R",
name,
- c->u->u_name, c->u->u_ste->ste_id,
- c->u->u_ste->ste_symbols, c->u->u_varnames, c->u->u_names);
+ c->u->u_metadata.u_name, c->u->u_ste->ste_id,
+ c->u->u_ste->ste_symbols, c->u->u_metadata.u_varnames, c->u->u_metadata.u_names);
return ERROR;
}
return scope;
@@ -1803,10 +1749,10 @@ compiler_make_closure(struct compiler *c, location loc,
}
int arg;
if (reftype == CELL) {
- arg = compiler_lookup_arg(c->u->u_cellvars, name);
+ arg = compiler_lookup_arg(c->u->u_metadata.u_cellvars, name);
}
else {
- arg = compiler_lookup_arg(c->u->u_freevars, name);
+ arg = compiler_lookup_arg(c->u->u_metadata.u_freevars, name);
}
if (arg == -1) {
PyObject *freevars = _PyCode_GetFreevars(co);
@@ -1818,7 +1764,7 @@ compiler_make_closure(struct compiler *c, location loc,
"freevars of code %S: %R",
name,
reftype,
- c->u->u_name,
+ c->u->u_metadata.u_name,
co->co_name,
freevars);
Py_DECREF(freevars);
@@ -2187,9 +2133,9 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
return ERROR;
}
- c->u->u_argcount = asdl_seq_LEN(args->args);
- c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
- c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
+ c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args);
+ c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
+ c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
for (i = docstring ? 1 : 0; i < asdl_seq_LEN(body); i++) {
VISIT_IN_SCOPE(c, stmt, (stmt_ty)asdl_seq_GET(body, i));
}
@@ -2199,7 +2145,7 @@ compiler_function(struct compiler *c, stmt_ty s, int is_async)
return ERROR;
}
}
- co = assemble(c, 1);
+ co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (co == NULL) {
Py_XDECREF(co);
@@ -2259,8 +2205,8 @@ compiler_class(struct compiler *c, stmt_ty s)
compiler_exit_scope(c);
return ERROR;
}
- assert(c->u->u_qualname);
- ADDOP_LOAD_CONST(c, loc, c->u->u_qualname);
+ assert(c->u->u_metadata.u_qualname);
+ ADDOP_LOAD_CONST(c, loc, c->u->u_metadata.u_qualname);
if (compiler_nameop(c, loc, &_Py_ID(__qualname__), Store) < 0) {
compiler_exit_scope(c);
return ERROR;
@@ -2274,7 +2220,7 @@ compiler_class(struct compiler *c, stmt_ty s)
/* Return __classcell__ if it is referenced, otherwise return None */
if (c->u->u_ste->ste_needs_class_closure) {
/* Store __classcell__ into class namespace & return it */
- i = compiler_lookup_arg(c->u->u_cellvars, &_Py_ID(__class__));
+ i = compiler_lookup_arg(c->u->u_metadata.u_cellvars, &_Py_ID(__class__));
if (i < 0) {
compiler_exit_scope(c);
return ERROR;
@@ -2289,12 +2235,12 @@ compiler_class(struct compiler *c, stmt_ty s)
}
else {
/* No methods referenced __class__, so just return None */
- assert(PyDict_GET_SIZE(c->u->u_cellvars) == 0);
+ assert(PyDict_GET_SIZE(c->u->u_metadata.u_cellvars) == 0);
ADDOP_LOAD_CONST(c, NO_LOCATION, Py_None);
}
ADDOP_IN_SCOPE(c, NO_LOCATION, RETURN_VALUE);
/* create the code object */
- co = assemble(c, 1);
+ co = optimize_and_assemble(c, 1);
}
/* leave the new scope */
compiler_exit_scope(c);
@@ -2345,6 +2291,8 @@ check_is_arg(expr_ty e)
|| value == Py_Ellipsis);
}
+static PyTypeObject * infer_type(expr_ty e);
+
/* Check operands of identity checks ("is" and "is not").
Emit a warning if any operand is a constant except named singletons.
*/
@@ -2353,19 +2301,25 @@ check_compare(struct compiler *c, expr_ty e)
{
Py_ssize_t i, n;
bool left = check_is_arg(e->v.Compare.left);
+ expr_ty left_expr = e->v.Compare.left;
n = asdl_seq_LEN(e->v.Compare.ops);
for (i = 0; i < n; i++) {
cmpop_ty op = (cmpop_ty)asdl_seq_GET(e->v.Compare.ops, i);
- bool right = check_is_arg((expr_ty)asdl_seq_GET(e->v.Compare.comparators, i));
+ expr_ty right_expr = (expr_ty)asdl_seq_GET(e->v.Compare.comparators, i);
+ bool right = check_is_arg(right_expr);
if (op == Is || op == IsNot) {
if (!right || !left) {
const char *msg = (op == Is)
- ? "\"is\" with a literal. Did you mean \"==\"?"
- : "\"is not\" with a literal. Did you mean \"!=\"?";
- return compiler_warn(c, LOC(e), msg);
+ ? "\"is\" with '%.200s' literal. Did you mean \"==\"?"
+ : "\"is not\" with '%.200s' literal. Did you mean \"!=\"?";
+ expr_ty literal = !left ? left_expr : right_expr;
+ return compiler_warn(
+ c, LOC(e), msg, infer_type(literal)->tp_name
+ );
}
}
left = right;
+ left_expr = right_expr;
}
return SUCCESS;
}
@@ -2561,17 +2515,17 @@ compiler_lambda(struct compiler *c, expr_ty e)
docstring. */
RETURN_IF_ERROR(compiler_add_const(c->c_const_cache, c->u, Py_None));
- c->u->u_argcount = asdl_seq_LEN(args->args);
- c->u->u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
- c->u->u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
+ c->u->u_metadata.u_argcount = asdl_seq_LEN(args->args);
+ c->u->u_metadata.u_posonlyargcount = asdl_seq_LEN(args->posonlyargs);
+ c->u->u_metadata.u_kwonlyargcount = asdl_seq_LEN(args->kwonlyargs);
VISIT_IN_SCOPE(c, expr, e->v.Lambda.body);
if (c->u->u_ste->ste_generator) {
- co = assemble(c, 0);
+ co = optimize_and_assemble(c, 0);
}
else {
location loc = LOCATION(e->lineno, e->lineno, 0, 0);
ADDOP_IN_SCOPE(c, loc, RETURN_VALUE);
- co = assemble(c, 1);
+ co = optimize_and_assemble(c, 1);
}
compiler_exit_scope(c);
if (co == NULL) {
@@ -3121,11 +3075,9 @@ compiler_try_except(struct compiler *c, stmt_ty s)
[orig, res, exc]
[orig, res, exc, E1] CHECK_EG_MATCH
[orig, res, rest/exc, match?] COPY 1
- [orig, res, rest/exc, match?, match?] POP_JUMP_IF_NOT_NONE H1
- [orig, res, exc, None] POP_TOP
- [orig, res, exc] JUMP L2
+ [orig, res, rest/exc, match?, match?] POP_JUMP_IF_NONE C1
- [orig, res, rest, match] H1: (or POP if no V1)
+ [orig, res, rest, match] (or POP if no V1)
[orig, res, rest] SETUP_FINALLY R1
[orig, res, rest]
@@ -3133,8 +3085,14 @@ compiler_try_except(struct compiler *c, stmt_ty s)
[orig, res, rest, i, v] R1: LIST_APPEND 3 ) exc raised in except* body - add to res
[orig, res, rest, i] POP
+ [orig, res, rest] JUMP LE2
+
+ [orig, res, rest] L2: NOP ) for lineno
+ [orig, res, rest] JUMP LE2
- [orig, res, rest] L2:
+ [orig, res, rest/exc, None] C1: POP
+
+ [orig, res, rest] LE2:
.............................etc.......................
[orig, res, rest] Ln+1: LIST_APPEND 1 ) add unhandled exc to res (could be None)
@@ -3190,7 +3148,8 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
location loc = LOC(handler);
NEW_JUMP_TARGET_LABEL(c, next_except);
except = next_except;
- NEW_JUMP_TARGET_LABEL(c, handle_match);
+ NEW_JUMP_TARGET_LABEL(c, except_with_error);
+ NEW_JUMP_TARGET_LABEL(c, no_match);
if (i == 0) {
/* create empty list for exceptions raised/reraise in the except* blocks */
/*
@@ -3208,13 +3167,9 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
VISIT(c, expr, handler->v.ExceptHandler.type);
ADDOP(c, loc, CHECK_EG_MATCH);
ADDOP_I(c, loc, COPY, 1);
- ADDOP_JUMP(c, loc, POP_JUMP_IF_NOT_NONE, handle_match);
- ADDOP(c, loc, POP_TOP); // match
- ADDOP_JUMP(c, loc, JUMP, except);
+ ADDOP_JUMP(c, loc, POP_JUMP_IF_NONE, no_match);
}
- USE_LABEL(c, handle_match);
-
NEW_JUMP_TARGET_LABEL(c, cleanup_end);
NEW_JUMP_TARGET_LABEL(c, cleanup_body);
@@ -3273,9 +3228,16 @@ compiler_try_star_except(struct compiler *c, stmt_ty s)
/* add exception raised to the res list */
ADDOP_I(c, NO_LOCATION, LIST_APPEND, 3); // exc
ADDOP(c, NO_LOCATION, POP_TOP); // lasti
- ADDOP_JUMP(c, NO_LOCATION, JUMP, except);
+ ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error);
USE_LABEL(c, except);
+ ADDOP(c, NO_LOCATION, NOP); // to hold a propagated location info
+ ADDOP_JUMP(c, NO_LOCATION, JUMP, except_with_error);
+
+ USE_LABEL(c, no_match);
+ ADDOP(c, loc, POP_TOP); // match (None)
+
+ USE_LABEL(c, except_with_error);
if (i == n - 1) {
/* Add exc to the list (if not None it's the unhandled part of the EG) */
@@ -3717,7 +3679,7 @@ compiler_nameop(struct compiler *c, location loc,
Py_ssize_t arg;
enum { OP_FAST, OP_GLOBAL, OP_DEREF, OP_NAME } optype;
- PyObject *dict = c->u->u_names;
+ PyObject *dict = c->u->u_metadata.u_names;
PyObject *mangled;
assert(!_PyUnicode_EqualToASCIIString(name, "None") &&
@@ -3738,11 +3700,11 @@ compiler_nameop(struct compiler *c, location loc,
scope = _PyST_GetScope(c->u->u_ste, mangled);
switch (scope) {
case FREE:
- dict = c->u->u_freevars;
+ dict = c->u->u_metadata.u_freevars;
optype = OP_DEREF;
break;
case CELL:
- dict = c->u->u_cellvars;
+ dict = c->u->u_metadata.u_cellvars;
optype = OP_DEREF;
break;
case LOCAL:
@@ -4290,6 +4252,89 @@ is_import_originated(struct compiler *c, expr_ty e)
return flags & DEF_IMPORT;
}
+static int
+can_optimize_super_call(struct compiler *c, expr_ty attr)
+{
+ expr_ty e = attr->v.Attribute.value;
+ if (e->kind != Call_kind ||
+ e->v.Call.func->kind != Name_kind ||
+ !_PyUnicode_EqualToASCIIString(e->v.Call.func->v.Name.id, "super") ||
+ _PyUnicode_EqualToASCIIString(attr->v.Attribute.attr, "__class__") ||
+ asdl_seq_LEN(e->v.Call.keywords) != 0) {
+ return 0;
+ }
+ Py_ssize_t num_args = asdl_seq_LEN(e->v.Call.args);
+
+ PyObject *super_name = e->v.Call.func->v.Name.id;
+ // detect statically-visible shadowing of 'super' name
+ int scope = _PyST_GetScope(c->u->u_ste, super_name);
+ if (scope != GLOBAL_IMPLICIT) {
+ return 0;
+ }
+ scope = _PyST_GetScope(c->c_st->st_top, super_name);
+ if (scope != 0) {
+ return 0;
+ }
+
+ if (num_args == 2) {
+ for (Py_ssize_t i = 0; i < num_args; i++) {
+ expr_ty elt = asdl_seq_GET(e->v.Call.args, i);
+ if (elt->kind == Starred_kind) {
+ return 0;
+ }
+ }
+ // exactly two non-starred args; we can just load
+ // the provided args
+ return 1;
+ }
+
+ if (num_args != 0) {
+ return 0;
+ }
+ // we need the following for zero-arg super():
+
+ // enclosing function should have at least one argument
+ if (c->u->u_metadata.u_argcount == 0 &&
+ c->u->u_metadata.u_posonlyargcount == 0) {
+ return 0;
+ }
+ // __class__ cell should be available
+ if (get_ref_type(c, &_Py_ID(__class__)) == FREE) {
+ return 1;
+ }
+ return 0;
+}
+
+static int
+load_args_for_super(struct compiler *c, expr_ty e) {
+ location loc = LOC(e);
+
+ // load super() global
+ PyObject *super_name = e->v.Call.func->v.Name.id;
+ RETURN_IF_ERROR(compiler_nameop(c, loc, super_name, Load));
+
+ if (asdl_seq_LEN(e->v.Call.args) == 2) {
+ VISIT(c, expr, asdl_seq_GET(e->v.Call.args, 0));
+ VISIT(c, expr, asdl_seq_GET(e->v.Call.args, 1));
+ return SUCCESS;
+ }
+
+ // load __class__ cell
+ PyObject *name = &_Py_ID(__class__);
+ assert(get_ref_type(c, name) == FREE);
+ RETURN_IF_ERROR(compiler_nameop(c, loc, name, Load));
+
+ // load self (first argument)
+ Py_ssize_t i = 0;
+ PyObject *key, *value;
+ if (!PyDict_Next(c->u->u_metadata.u_varnames, &i, &key, &value)) {
+ return ERROR;
+ }
+ RETURN_IF_ERROR(compiler_nameop(c, loc, key, Load));
+
+ return SUCCESS;
+}
+
// If an attribute access spans multiple lines, update the current start
// location to point to the attribute name.
static location
@@ -4357,11 +4402,21 @@ maybe_optimize_method_call(struct compiler *c, expr_ty e)
return 0;
}
}
+
/* Alright, we can optimize the code. */
- VISIT(c, expr, meth->v.Attribute.value);
location loc = LOC(meth);
- loc = update_start_location_to_match_attr(c, loc, meth);
- ADDOP_NAME(c, loc, LOAD_METHOD, meth->v.Attribute.attr, names);
+
+ if (can_optimize_super_call(c, meth)) {
+ RETURN_IF_ERROR(load_args_for_super(c, meth->v.Attribute.value));
+ int opcode = asdl_seq_LEN(meth->v.Attribute.value->v.Call.args) ?
+ LOAD_SUPER_METHOD : LOAD_ZERO_SUPER_METHOD;
+ ADDOP_NAME(c, loc, opcode, meth->v.Attribute.attr, names);
+ } else {
+ VISIT(c, expr, meth->v.Attribute.value);
+ loc = update_start_location_to_match_attr(c, loc, meth);
+ ADDOP_NAME(c, loc, LOAD_METHOD, meth->v.Attribute.attr, names);
+ }
+
VISIT_SEQ(c, expr, e->v.Call.args);
if (kwdsl) {
@@ -4708,7 +4763,7 @@ compiler_sync_comprehension_generator(struct compiler *c, location loc,
if (gen_index == 0) {
/* Receive outermost iter as an implicit argument */
- c->u->u_argcount = 1;
+ c->u->u_metadata.u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
else {
@@ -4821,7 +4876,7 @@ compiler_async_comprehension_generator(struct compiler *c, location loc,
if (gen_index == 0) {
/* Receive outermost iter as an implicit argument */
- c->u->u_argcount = 1;
+ c->u->u_metadata.u_argcount = 1;
ADDOP_I(c, loc, LOAD_FAST, 0);
}
else {
@@ -4969,7 +5024,7 @@ compiler_comprehension(struct compiler *c, expr_ty e, int type,
}
}
- co = assemble(c, 1);
+ co = optimize_and_assemble(c, 1);
compiler_exit_scope(c);
if (is_top_level_await && is_async_generator){
c->u->u_ste->ste_coroutine = 1;
@@ -5369,6 +5424,13 @@ compiler_visit_expr1(struct compiler *c, expr_ty e)
return compiler_formatted_value(c, e);
/* The following exprs can be assignment targets. */
case Attribute_kind:
+ if (e->v.Attribute.ctx == Load && can_optimize_super_call(c, e)) {
+ RETURN_IF_ERROR(load_args_for_super(c, e->v.Attribute.value));
+ int opcode = asdl_seq_LEN(e->v.Attribute.value->v.Call.args) ?
+ LOAD_SUPER_ATTR : LOAD_ZERO_SUPER_ATTR;
+ ADDOP_NAME(c, loc, opcode, e->v.Attribute.attr, names);
+ return SUCCESS;
+ }
VISIT(c, expr, e->v.Attribute.value);
loc = LOC(e);
loc = update_start_location_to_match_attr(c, loc, e);
@@ -6592,378 +6654,6 @@ compiler_match(struct compiler *c, stmt_ty s)
#undef WILDCARD_CHECK
#undef WILDCARD_STAR_CHECK
-
-/* End of the compiler section, beginning of the assembler section */
-
-
-struct assembler {
- PyObject *a_bytecode; /* bytes containing bytecode */
- int a_offset; /* offset into bytecode */
- PyObject *a_except_table; /* bytes containing exception table */
- int a_except_table_off; /* offset into exception table */
- /* Location Info */
- int a_lineno; /* lineno of last emitted instruction */
- PyObject* a_linetable; /* bytes containing location info */
- int a_location_off; /* offset of last written location info frame */
-};
-
-static int
-assemble_init(struct assembler *a, int firstlineno)
-{
- memset(a, 0, sizeof(struct assembler));
- a->a_lineno = firstlineno;
- a->a_linetable = NULL;
- a->a_location_off = 0;
- a->a_except_table = NULL;
- a->a_bytecode = PyBytes_FromStringAndSize(NULL, DEFAULT_CODE_SIZE);
- if (a->a_bytecode == NULL) {
- goto error;
- }
- a->a_linetable = PyBytes_FromStringAndSize(NULL, DEFAULT_CNOTAB_SIZE);
- if (a->a_linetable == NULL) {
- goto error;
- }
- a->a_except_table = PyBytes_FromStringAndSize(NULL, DEFAULT_LNOTAB_SIZE);
- if (a->a_except_table == NULL) {
- goto error;
- }
- return SUCCESS;
-error:
- Py_XDECREF(a->a_bytecode);
- Py_XDECREF(a->a_linetable);
- Py_XDECREF(a->a_except_table);
- return ERROR;
-}
-
-static void
-assemble_free(struct assembler *a)
-{
- Py_XDECREF(a->a_bytecode);
- Py_XDECREF(a->a_linetable);
- Py_XDECREF(a->a_except_table);
-}
-
-static inline void
-write_except_byte(struct assembler *a, int byte) {
- unsigned char *p = (unsigned char *) PyBytes_AS_STRING(a->a_except_table);
- p[a->a_except_table_off++] = byte;
-}
-
-#define CONTINUATION_BIT 64
-
-static void
-assemble_emit_exception_table_item(struct assembler *a, int value, int msb)
-{
- assert ((msb | 128) == 128);
- assert(value >= 0 && value < (1 << 30));
- if (value >= 1 << 24) {
- write_except_byte(a, (value >> 24) | CONTINUATION_BIT | msb);
- msb = 0;
- }
- if (value >= 1 << 18) {
- write_except_byte(a, ((value >> 18)&0x3f) | CONTINUATION_BIT | msb);
- msb = 0;
- }
- if (value >= 1 << 12) {
- write_except_byte(a, ((value >> 12)&0x3f) | CONTINUATION_BIT | msb);
- msb = 0;
- }
- if (value >= 1 << 6) {
- write_except_byte(a, ((value >> 6)&0x3f) | CONTINUATION_BIT | msb);
- msb = 0;
- }
- write_except_byte(a, (value&0x3f) | msb);
-}
-
-/* See Objects/exception_handling_notes.txt for details of layout */
-#define MAX_SIZE_OF_ENTRY 20
-
-static int
-assemble_emit_exception_table_entry(struct assembler *a, int start, int end, basicblock *handler)
-{
- Py_ssize_t len = PyBytes_GET_SIZE(a->a_except_table);
- if (a->a_except_table_off + MAX_SIZE_OF_ENTRY >= len) {
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, len * 2));
- }
- int size = end-start;
- assert(end > start);
- int target = handler->b_offset;
- int depth = handler->b_startdepth - 1;
- if (handler->b_preserve_lasti) {
- depth -= 1;
- }
- assert(depth >= 0);
- int depth_lasti = (depth<<1) | handler->b_preserve_lasti;
- assemble_emit_exception_table_item(a, start, (1<<7));
- assemble_emit_exception_table_item(a, size, 0);
- assemble_emit_exception_table_item(a, target, 0);
- assemble_emit_exception_table_item(a, depth_lasti, 0);
- return SUCCESS;
-}
-
-static int
-assemble_exception_table(struct assembler *a, basicblock *entryblock)
-{
- basicblock *b;
- int ioffset = 0;
- basicblock *handler = NULL;
- int start = -1;
- for (b = entryblock; b != NULL; b = b->b_next) {
- ioffset = b->b_offset;
- for (int i = 0; i < b->b_iused; i++) {
- cfg_instr *instr = &b->b_instr[i];
- if (instr->i_except != handler) {
- if (handler != NULL) {
- RETURN_IF_ERROR(
- assemble_emit_exception_table_entry(a, start, ioffset, handler));
- }
- start = ioffset;
- handler = instr->i_except;
- }
- ioffset += _PyCfg_InstrSize(instr);
- }
- }
- if (handler != NULL) {
- RETURN_IF_ERROR(assemble_emit_exception_table_entry(a, start, ioffset, handler));
- }
- return SUCCESS;
-}
-
-/* Code location emitting code. See locations.md for a description of the format. */
-
-#define MSB 0x80
-
-static void
-write_location_byte(struct assembler* a, int val)
-{
- PyBytes_AS_STRING(a->a_linetable)[a->a_location_off] = val&255;
- a->a_location_off++;
-}
-
-
-static uint8_t *
-location_pointer(struct assembler* a)
-{
- return (uint8_t *)PyBytes_AS_STRING(a->a_linetable) +
- a->a_location_off;
-}
-
-static void
-write_location_first_byte(struct assembler* a, int code, int length)
-{
- a->a_location_off += write_location_entry_start(
- location_pointer(a), code, length);
-}
-
-static void
-write_location_varint(struct assembler* a, unsigned int val)
-{
- uint8_t *ptr = location_pointer(a);
- a->a_location_off += write_varint(ptr, val);
-}
-
-
-static void
-write_location_signed_varint(struct assembler* a, int val)
-{
- uint8_t *ptr = location_pointer(a);
- a->a_location_off += write_signed_varint(ptr, val);
-}
-
-static void
-write_location_info_short_form(struct assembler* a, int length, int column, int end_column)
-{
- assert(length > 0 && length <= 8);
- int column_low_bits = column & 7;
- int column_group = column >> 3;
- assert(column < 80);
- assert(end_column >= column);
- assert(end_column - column < 16);
- write_location_first_byte(a, PY_CODE_LOCATION_INFO_SHORT0 + column_group, length);
- write_location_byte(a, (column_low_bits << 4) | (end_column - column));
-}
-
-static void
-write_location_info_oneline_form(struct assembler* a, int length, int line_delta, int column, int end_column)
-{
- assert(length > 0 && length <= 8);
- assert(line_delta >= 0 && line_delta < 3);
- assert(column < 128);
- assert(end_column < 128);
- write_location_first_byte(a, PY_CODE_LOCATION_INFO_ONE_LINE0 + line_delta, length);
- write_location_byte(a, column);
- write_location_byte(a, end_column);
-}
-
-static void
-write_location_info_long_form(struct assembler* a, location loc, int length)
-{
- assert(length > 0 && length <= 8);
- write_location_first_byte(a, PY_CODE_LOCATION_INFO_LONG, length);
- write_location_signed_varint(a, loc.lineno - a->a_lineno);
- assert(loc.end_lineno >= loc.lineno);
- write_location_varint(a, loc.end_lineno - loc.lineno);
- write_location_varint(a, loc.col_offset + 1);
- write_location_varint(a, loc.end_col_offset + 1);
-}
-
-static void
-write_location_info_none(struct assembler* a, int length)
-{
- write_location_first_byte(a, PY_CODE_LOCATION_INFO_NONE, length);
-}
-
-static void
-write_location_info_no_column(struct assembler* a, int length, int line_delta)
-{
- write_location_first_byte(a, PY_CODE_LOCATION_INFO_NO_COLUMNS, length);
- write_location_signed_varint(a, line_delta);
-}
-
-#define THEORETICAL_MAX_ENTRY_SIZE 25 /* 1 + 6 + 6 + 6 + 6 */
-
-static int
-write_location_info_entry(struct assembler* a, location loc, int isize)
-{
- Py_ssize_t len = PyBytes_GET_SIZE(a->a_linetable);
- if (a->a_location_off + THEORETICAL_MAX_ENTRY_SIZE >= len) {
- assert(len > THEORETICAL_MAX_ENTRY_SIZE);
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, len*2));
- }
- if (loc.lineno < 0) {
- write_location_info_none(a, isize);
- return SUCCESS;
- }
- int line_delta = loc.lineno - a->a_lineno;
- int column = loc.col_offset;
- int end_column = loc.end_col_offset;
- assert(column >= -1);
- assert(end_column >= -1);
- if (column < 0 || end_column < 0) {
- if (loc.end_lineno == loc.lineno || loc.end_lineno == -1) {
- write_location_info_no_column(a, isize, line_delta);
- a->a_lineno = loc.lineno;
- return SUCCESS;
- }
- }
- else if (loc.end_lineno == loc.lineno) {
- if (line_delta == 0 && column < 80 && end_column - column < 16 && end_column >= column) {
- write_location_info_short_form(a, isize, column, end_column);
- return SUCCESS;
- }
- if (line_delta >= 0 && line_delta < 3 && column < 128 && end_column < 128) {
- write_location_info_oneline_form(a, isize, line_delta, column, end_column);
- a->a_lineno = loc.lineno;
- return SUCCESS;
- }
- }
- write_location_info_long_form(a, loc, isize);
- a->a_lineno = loc.lineno;
- return SUCCESS;
-}
-
-static int
-assemble_emit_location(struct assembler* a, location loc, int isize)
-{
- if (isize == 0) {
- return SUCCESS;
- }
- while (isize > 8) {
- RETURN_IF_ERROR(write_location_info_entry(a, loc, 8));
- isize -= 8;
- }
- return write_location_info_entry(a, loc, isize);
-}
-
-static int
-assemble_location_info(struct assembler *a, basicblock *entryblock, int firstlineno)
-{
- a->a_lineno = firstlineno;
- location loc = NO_LOCATION;
- int size = 0;
- for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- for (int j = 0; j < b->b_iused; j++) {
- if (!same_location(loc, b->b_instr[j].i_loc)) {
- RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
- loc = b->b_instr[j].i_loc;
- size = 0;
- }
- size += _PyCfg_InstrSize(&b->b_instr[j]);
- }
- }
- RETURN_IF_ERROR(assemble_emit_location(a, loc, size));
- return SUCCESS;
-}
-
-/* assemble_emit_instr()
- Extend the bytecode with a new instruction.
- Update lnotab if necessary.
-*/
-
-static int
-assemble_emit_instr(struct assembler *a, cfg_instr *i)
-{
- Py_ssize_t len = PyBytes_GET_SIZE(a->a_bytecode);
- _Py_CODEUNIT *code;
-
- int size = _PyCfg_InstrSize(i);
- if (a->a_offset + size >= len / (int)sizeof(_Py_CODEUNIT)) {
- if (len > PY_SSIZE_T_MAX / 2) {
- return ERROR;
- }
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, len * 2));
- }
- code = (_Py_CODEUNIT *)PyBytes_AS_STRING(a->a_bytecode) + a->a_offset;
- a->a_offset += size;
- write_instr(code, i, size);
- return SUCCESS;
-}
-
-static int
-assemble_emit(struct assembler *a, basicblock *entryblock, int first_lineno,
- PyObject *const_cache)
-{
- RETURN_IF_ERROR(assemble_init(a, first_lineno));
-
- for (basicblock *b = entryblock; b != NULL; b = b->b_next) {
- for (int j = 0; j < b->b_iused; j++) {
- RETURN_IF_ERROR(assemble_emit_instr(a, &b->b_instr[j]));
- }
- }
-
- RETURN_IF_ERROR(assemble_location_info(a, entryblock, a->a_lineno));
-
- RETURN_IF_ERROR(assemble_exception_table(a, entryblock));
-
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_except_table, a->a_except_table_off));
- RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_except_table));
-
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_linetable, a->a_location_off));
- RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_linetable));
-
- RETURN_IF_ERROR(_PyBytes_Resize(&a->a_bytecode, a->a_offset * sizeof(_Py_CODEUNIT)));
- RETURN_IF_ERROR(_PyCompile_ConstCacheMergeOne(const_cache, &a->a_bytecode));
- return SUCCESS;
-}
-
-static PyObject *
-dict_keys_inorder(PyObject *dict, Py_ssize_t offset)
-{
- PyObject *tuple, *k, *v;
- Py_ssize_t i, pos = 0, size = PyDict_GET_SIZE(dict);
-
- tuple = PyTuple_New(size);
- if (tuple == NULL)
- return NULL;
- while (PyDict_Next(dict, &pos, &k, &v)) {
- i = PyLong_AS_LONG(v);
- assert((i - offset) < size);
- assert((i - offset) >= 0);
- PyTuple_SET_ITEM(tuple, i - offset, Py_NewRef(k));
- }
- return tuple;
-}
-
static PyObject *
consts_dict_keys_inorder(PyObject *dict)
{
@@ -7051,153 +6741,13 @@ _PyCompile_ConstCacheMergeOne(PyObject *const_cache, PyObject **obj)
return SUCCESS;
}
-// This is in codeobject.c.
-extern void _Py_set_localsplus_info(int, PyObject *, unsigned char,
- PyObject *, PyObject *);
-
-static void
-compute_localsplus_info(struct compiler_unit *u, int nlocalsplus,
- PyObject *names, PyObject *kinds)
-{
- PyObject *k, *v;
- Py_ssize_t pos = 0;
- while (PyDict_Next(u->u_varnames, &pos, &k, &v)) {
- int offset = (int)PyLong_AS_LONG(v);
- assert(offset >= 0);
- assert(offset < nlocalsplus);
- // For now we do not distinguish arg kinds.
- _PyLocals_Kind kind = CO_FAST_LOCAL;
- if (PyDict_GetItem(u->u_cellvars, k) != NULL) {
- kind |= CO_FAST_CELL;
- }
- _Py_set_localsplus_info(offset, k, kind, names, kinds);
- }
- int nlocals = (int)PyDict_GET_SIZE(u->u_varnames);
-
- // This counter mirrors the fix done in fix_cell_offsets().
- int numdropped = 0;
- pos = 0;
- while (PyDict_Next(u->u_cellvars, &pos, &k, &v)) {
- if (PyDict_GetItem(u->u_varnames, k) != NULL) {
- // Skip cells that are already covered by locals.
- numdropped += 1;
- continue;
- }
- int offset = (int)PyLong_AS_LONG(v);
- assert(offset >= 0);
- offset += nlocals - numdropped;
- assert(offset < nlocalsplus);
- _Py_set_localsplus_info(offset, k, CO_FAST_CELL, names, kinds);
- }
-
- pos = 0;
- while (PyDict_Next(u->u_freevars, &pos, &k, &v)) {
- int offset = (int)PyLong_AS_LONG(v);
- assert(offset >= 0);
- offset += nlocals - numdropped;
- assert(offset < nlocalsplus);
- _Py_set_localsplus_info(offset, k, CO_FAST_FREE, names, kinds);
- }
-}
-
-static PyCodeObject *
-makecode(struct compiler_unit *u, struct assembler *a, PyObject *const_cache,
- PyObject *constslist, int maxdepth, int nlocalsplus, int code_flags,
- PyObject *filename)
-{
- PyCodeObject *co = NULL;
- PyObject *names = NULL;
- PyObject *consts = NULL;
- PyObject *localsplusnames = NULL;
- PyObject *localspluskinds = NULL;
- names = dict_keys_inorder(u->u_names, 0);
- if (!names) {
- goto error;
- }
- if (_PyCompile_ConstCacheMergeOne(const_cache, &names) < 0) {
- goto error;
- }
-
- consts = PyList_AsTuple(constslist); /* PyCode_New requires a tuple */
- if (consts == NULL) {
- goto error;
- }
- if (_PyCompile_ConstCacheMergeOne(const_cache, &consts) < 0) {
- goto error;
- }
-
- assert(u->u_posonlyargcount < INT_MAX);
- assert(u->u_argcount < INT_MAX);
- assert(u->u_kwonlyargcount < INT_MAX);
- int posonlyargcount = (int)u->u_posonlyargcount;
- int posorkwargcount = (int)u->u_argcount;
- assert(INT_MAX - posonlyargcount - posorkwargcount > 0);
- int kwonlyargcount = (int)u->u_kwonlyargcount;
-
- localsplusnames = PyTuple_New(nlocalsplus);
- if (localsplusnames == NULL) {
- goto error;
- }
- localspluskinds = PyBytes_FromStringAndSize(NULL, nlocalsplus);
- if (localspluskinds == NULL) {
- goto error;
- }
- compute_localsplus_info(u, nlocalsplus, localsplusnames, localspluskinds);
-
- struct _PyCodeConstructor con = {
- .filename = filename,
- .name = u->u_name,
- .qualname = u->u_qualname ? u->u_qualname : u->u_name,
- .flags = code_flags,
-
- .code = a->a_bytecode,
- .firstlineno = u->u_firstlineno,
- .linetable = a->a_linetable,
-
- .consts = consts,
- .names = names,
-
- .localsplusnames = localsplusnames,
- .localspluskinds = localspluskinds,
-
- .argcount = posonlyargcount + posorkwargcount,
- .posonlyargcount = posonlyargcount,
- .kwonlyargcount = kwonlyargcount,
-
- .stacksize = maxdepth,
-
- .exceptiontable = a->a_except_table,
- };
-
- if (_PyCode_Validate(&con) < 0) {
- goto error;
- }
-
- if (_PyCompile_ConstCacheMergeOne(const_cache, &localsplusnames) < 0) {
- goto error;
- }
- con.localsplusnames = localsplusnames;
-
- co = _PyCode_New(&con);
- if (co == NULL) {
- goto error;
- }
-
- error:
- Py_XDECREF(names);
- Py_XDECREF(consts);
- Py_XDECREF(localsplusnames);
- Py_XDECREF(localspluskinds);
- return co;
-}
-
static int *
build_cellfixedoffsets(struct compiler_unit *u)
{
- int nlocals = (int)PyDict_GET_SIZE(u->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars);
+ int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars);
int noffsets = ncellvars + nfreevars;
int *fixed = PyMem_New(int, noffsets);
@@ -7211,8 +6761,8 @@ build_cellfixedoffsets(struct compiler_unit *u)
PyObject *varname, *cellindex;
Py_ssize_t pos = 0;
- while (PyDict_Next(u->u_cellvars, &pos, &varname, &cellindex)) {
- PyObject *varindex = PyDict_GetItem(u->u_varnames, varname);
+ while (PyDict_Next(u->u_metadata.u_cellvars, &pos, &varname, &cellindex)) {
+ PyObject *varindex = PyDict_GetItem(u->u_metadata.u_varnames, varname);
if (varindex != NULL) {
assert(PyLong_AS_LONG(cellindex) < INT_MAX);
assert(PyLong_AS_LONG(varindex) < INT_MAX);
@@ -7229,14 +6779,14 @@ static int
insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock,
int *fixed, int nfreevars, int code_flags)
{
- assert(u->u_firstlineno > 0);
+ assert(u->u_metadata.u_firstlineno > 0);
/* Add the generator prefix instructions. */
if (code_flags & (CO_GENERATOR | CO_COROUTINE | CO_ASYNC_GENERATOR)) {
cfg_instr make_gen = {
.i_opcode = RETURN_GENERATOR,
.i_oparg = 0,
- .i_loc = LOCATION(u->u_firstlineno, u->u_firstlineno, -1, -1),
+ .i_loc = LOCATION(u->u_metadata.u_firstlineno, u->u_metadata.u_firstlineno, -1, -1),
.i_target = NULL,
};
RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, 0, &make_gen));
@@ -7250,12 +6800,12 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock,
}
/* Set up cells for any variable that escapes, to be put in a closure. */
- const int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars);
+ const int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars);
if (ncellvars) {
- // u->u_cellvars has the cells out of order so we sort them
+ // u->u_metadata.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(u->u_varnames);
+ const int nvars = ncellvars + (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
int *sorted = PyMem_RawCalloc(nvars, sizeof(int));
if (sorted == NULL) {
PyErr_NoMemory();
@@ -7276,7 +6826,10 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock,
.i_loc = NO_LOCATION,
.i_target = NULL,
};
- RETURN_IF_ERROR(_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell));
+ if (_PyBasicblock_InsertInstruction(entryblock, ncellsused, &make_cell) < 0) {
+ PyMem_RawFree(sorted);
+ return ERROR;
+ }
ncellsused += 1;
}
PyMem_RawFree(sorted);
@@ -7298,9 +6851,9 @@ insert_prefix_instructions(struct compiler_unit *u, basicblock *entryblock,
static int
fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap)
{
- int nlocals = (int)PyDict_GET_SIZE(u->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars);
+ int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars);
int noffsets = ncellvars + nfreevars;
// First deal with duplicates (arg cells).
@@ -7344,12 +6897,12 @@ fix_cell_offsets(struct compiler_unit *u, basicblock *entryblock, int *fixedmap)
static int
prepare_localsplus(struct compiler_unit* u, cfg_builder *g, int code_flags)
{
- assert(PyDict_GET_SIZE(u->u_varnames) < INT_MAX);
- assert(PyDict_GET_SIZE(u->u_cellvars) < INT_MAX);
- assert(PyDict_GET_SIZE(u->u_freevars) < INT_MAX);
- int nlocals = (int)PyDict_GET_SIZE(u->u_varnames);
- int ncellvars = (int)PyDict_GET_SIZE(u->u_cellvars);
- int nfreevars = (int)PyDict_GET_SIZE(u->u_freevars);
+ assert(PyDict_GET_SIZE(u->u_metadata.u_varnames) < INT_MAX);
+ assert(PyDict_GET_SIZE(u->u_metadata.u_cellvars) < INT_MAX);
+ assert(PyDict_GET_SIZE(u->u_metadata.u_freevars) < INT_MAX);
+ int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
+ int ncellvars = (int)PyDict_GET_SIZE(u->u_metadata.u_cellvars);
+ int nfreevars = (int)PyDict_GET_SIZE(u->u_metadata.u_freevars);
assert(INT_MAX - nlocals - ncellvars > 0);
assert(INT_MAX - nlocals - ncellvars - nfreevars > 0);
int nlocalsplus = nlocals + ncellvars + nfreevars;
@@ -7389,13 +6942,17 @@ 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 *
-assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
+optimize_and_assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
int code_flags, PyObject *filename)
{
+ instr_sequence optimized_instrs;
+ memset(&optimized_instrs, 0, sizeof(instr_sequence));
+
PyCodeObject *co = NULL;
- PyObject *consts = consts_dict_keys_inorder(u->u_consts);
+ PyObject *consts = consts_dict_keys_inorder(u->u_metadata.u_consts);
if (consts == NULL) {
goto error;
}
@@ -7404,25 +6961,18 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
goto error;
}
int nparams = (int)PyList_GET_SIZE(u->u_ste->ste_varnames);
- int nlocals = (int)PyDict_GET_SIZE(u->u_varnames);
- if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) {
+ int nlocals = (int)PyDict_GET_SIZE(u->u_metadata.u_varnames);
+ assert(u->u_metadata.u_firstlineno);
+ if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals,
+ nparams, u->u_metadata.u_firstlineno) < 0) {
goto error;
}
- /** Assembly **/
- /* Set firstlineno if it wasn't explicitly set. */
- if (!u->u_firstlineno) {
- if (g.g_entryblock->b_instr && g.g_entryblock->b_instr->i_loc.lineno) {
- u->u_firstlineno = g.g_entryblock->b_instr->i_loc.lineno;
- }
- else {
- u->u_firstlineno = 1;
- }
- }
- if (_PyCfg_ResolveLineNumbers(&g, u->u_firstlineno) < 0) {
+ if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) {
goto error;
}
+ /** Assembly **/
int nlocalsplus = prepare_localsplus(u, &g, code_flags);
if (nlocalsplus < 0) {
goto error;
@@ -7432,7 +6982,6 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
if (maxdepth < 0) {
goto error;
}
- /* TO DO -- For 3.12, make sure that `maxdepth <= MAX_ALLOWED_STACK_USE` */
_PyCfg_ConvertExceptionHandlersToNops(g.g_entryblock);
@@ -7441,25 +6990,26 @@ assemble_code_unit(struct compiler_unit *u, PyObject *const_cache,
if (_PyCfg_ResolveJumps(&g) < 0) {
goto error;
}
+ if (cfg_to_instr_sequence(&g, &optimized_instrs) < 0) {
+ goto error;
+ }
+
/* Can't modify the bytecode after computing jump offsets. */
- struct assembler a;
- int res = assemble_emit(&a, g.g_entryblock, u->u_firstlineno, const_cache);
- if (res == SUCCESS) {
- co = makecode(u, &a, const_cache, consts, maxdepth, nlocalsplus,
- code_flags, filename);
- }
- assemble_free(&a);
+ co = _PyAssemble_MakeCodeObject(&u->u_metadata, const_cache, consts,
+ maxdepth, g.g_entryblock, nlocalsplus,
+ code_flags, filename);
- error:
+error:
Py_XDECREF(consts);
+ instr_sequence_fini(&optimized_instrs);
_PyCfgBuilder_Fini(&g);
return co;
}
static PyCodeObject *
-assemble(struct compiler *c, int addNone)
+optimize_and_assemble(struct compiler *c, int addNone)
{
struct compiler_unit *u = c->u;
PyObject *const_cache = c->c_const_cache;
@@ -7474,9 +7024,32 @@ assemble(struct compiler *c, int addNone)
return NULL;
}
- return assemble_code_unit(u, const_cache, code_flags, filename);
+ 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];
+ int arg = HAS_TARGET(instr->i_opcode) ?
+ instr->i_target->b_label.id :
+ instr->i_oparg;
+ RETURN_IF_ERROR(
+ instr_sequence_addop(seq, instr->i_opcode, arg, instr->i_loc));
+ }
+ }
+ return SUCCESS;
}
+
/* Access to compiler optimizations for unit tests.
*
* _PyCompile_CodeGen takes and AST, applies code-gen and
@@ -7492,7 +7065,7 @@ assemble(struct compiler *c, int addNone)
*/
static int
-instructions_to_cfg(PyObject *instructions, cfg_builder *g)
+instructions_to_instr_sequence(PyObject *instructions, instr_sequence *seq)
{
assert(PyList_Check(instructions));
@@ -7526,8 +7099,9 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g)
for (int i = 0; i < num_insts; i++) {
if (is_target[i]) {
- jump_target_label lbl = {i};
- RETURN_IF_ERROR(_PyCfgBuilder_UseLabel(g, lbl));
+ if (instr_sequence_use_label(seq, i) < 0) {
+ goto error;
+ }
}
PyObject *item = PyList_GET_ITEM(instructions, i);
if (!PyTuple_Check(item) || PyTuple_GET_SIZE(item) != 6) {
@@ -7565,11 +7139,14 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g)
if (PyErr_Occurred()) {
goto error;
}
- RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, opcode, oparg, loc));
+ if (instr_sequence_addop(seq, opcode, oparg, loc) < 0) {
+ goto error;
+ }
}
- cfg_instr *last = _PyCfg_BasicblockLastInstr(g->g_curblock);
- if (last && !IS_TERMINATOR_OPCODE(last->i_opcode)) {
- RETURN_IF_ERROR(_PyCfgBuilder_Addop(g, RETURN_VALUE, 0, NO_LOCATION));
+ if (seq->s_used && !IS_TERMINATOR_OPCODE(seq->s_instrs[seq->s_used-1].i_opcode)) {
+ if (instr_sequence_addop(seq, RETURN_VALUE, 0, NO_LOCATION) < 0) {
+ goto error;
+ }
}
PyMem_Free(is_target);
return SUCCESS;
@@ -7578,8 +7155,28 @@ instructions_to_cfg(PyObject *instructions, cfg_builder *g)
return ERROR;
}
+static int
+instructions_to_cfg(PyObject *instructions, cfg_builder *g)
+{
+ 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) {
+ goto error;
+ }
+ instr_sequence_fini(&seq);
+ return SUCCESS;
+error:
+ instr_sequence_fini(&seq);
+ return ERROR;
+}
+
static PyObject *
-instr_sequence_to_instructions(instr_sequence *seq) {
+instr_sequence_to_instructions(instr_sequence *seq)
+{
PyObject *instructions = PyList_New(0);
if (instructions == NULL) {
return NULL;
@@ -7702,15 +7299,12 @@ _PyCompile_OptimizeCfg(PyObject *instructions, PyObject *consts)
}
cfg_builder g;
- memset(&g, 0, sizeof(cfg_builder));
- if (_PyCfgBuilder_Init(&g) < 0) {
- goto error;
- }
if (instructions_to_cfg(instructions, &g) < 0) {
goto error;
}
- int code_flags = 0, nlocals = 0, nparams = 0;
- if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals, nparams) < 0) {
+ int code_flags = 0, nlocals = 0, nparams = 0, firstlineno = 1;
+ if (_PyCfg_OptimizeCodeUnit(&g, consts, const_cache, code_flags, nlocals,
+ nparams, firstlineno) < 0) {
goto error;
}
res = cfg_to_instructions(&g);
diff --git a/Python/errors.c b/Python/errors.c
index ab14770c6e810c..0ff6a0d5985f0f 100644
--- a/Python/errors.c
+++ b/Python/errors.c
@@ -1200,6 +1200,33 @@ PyErr_Format(PyObject *exception, const char *format, ...)
}
+/* Adds a note to the current exception (if any) */
+void
+_PyErr_FormatNote(const char *format, ...)
+{
+ PyObject *exc = PyErr_GetRaisedException();
+ if (exc == NULL) {
+ return;
+ }
+ va_list vargs;
+ va_start(vargs, format);
+ PyObject *note = PyUnicode_FromFormatV(format, vargs);
+ va_end(vargs);
+ if (note == NULL) {
+ goto error;
+ }
+ int res = _PyException_AddNote(exc, note);
+ Py_DECREF(note);
+ if (res < 0) {
+ goto error;
+ }
+ PyErr_SetRaisedException(exc);
+ return;
+error:
+ _PyErr_ChainExceptions1(exc);
+}
+
+
PyObject *
PyErr_NewException(const char *name, PyObject *base, PyObject *dict)
{
diff --git a/Python/flowgraph.c b/Python/flowgraph.c
index cecddbd39c94b3..67cc5c5e88be10 100644
--- a/Python/flowgraph.c
+++ b/Python/flowgraph.c
@@ -42,12 +42,6 @@ is_block_push(cfg_instr *i)
return IS_BLOCK_PUSH_OPCODE(i->i_opcode);
}
-static inline int
-is_relative_jump(cfg_instr *i)
-{
- return IS_RELATIVE_JUMP(i->i_opcode);
-}
-
static inline int
is_jump(cfg_instr *i)
{
@@ -199,8 +193,7 @@ blocksize(basicblock *b)
static void
dump_instr(cfg_instr *i)
{
- const char *jrel = (is_relative_jump(i)) ? "jrel " : "";
- const char *jabs = (is_jump(i) && !is_relative_jump(i))? "jabs " : "";
+ const char *jump = is_jump(i) ? "jump " : "";
char arg[128];
@@ -211,8 +204,8 @@ dump_instr(cfg_instr *i)
if (HAS_TARGET(i->i_opcode)) {
sprintf(arg, "target: %p [%d] ", i->i_target, i->i_oparg);
}
- fprintf(stderr, "line: %d, opcode: %d %s%s%s\n",
- i->i_loc.lineno, i->i_opcode, arg, jabs, jrel);
+ fprintf(stderr, "line: %d, opcode: %d %s%s\n",
+ i->i_loc.lineno, i->i_opcode, arg, jump);
}
static inline int
@@ -500,25 +493,20 @@ resolve_jump_offsets(basicblock *entryblock)
for (int i = 0; i < b->b_iused; i++) {
cfg_instr *instr = &b->b_instr[i];
int isize = _PyCfg_InstrSize(instr);
- /* Relative jumps are computed relative to
- the instruction pointer after fetching
- the jump instruction.
- */
+ /* jump offsets are computed relative to
+ * the instruction pointer after fetching
+ * the jump instruction.
+ */
bsize += isize;
if (is_jump(instr)) {
instr->i_oparg = instr->i_target->b_offset;
- if (is_relative_jump(instr)) {
- if (instr->i_oparg < bsize) {
- assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
- instr->i_oparg = bsize - instr->i_oparg;
- }
- else {
- assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
- instr->i_oparg -= bsize;
- }
+ if (instr->i_oparg < bsize) {
+ assert(IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
+ instr->i_oparg = bsize - instr->i_oparg;
}
else {
assert(!IS_BACKWARDS_JUMP_OPCODE(instr->i_opcode));
+ instr->i_oparg -= bsize;
}
if (_PyCfg_InstrSize(instr) != isize) {
extended_arg_recompile = 1;
@@ -1978,28 +1966,6 @@ push_cold_blocks_to_end(cfg_builder *g, int code_flags) {
return SUCCESS;
}
-int
-_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
- int code_flags, int nlocals, int nparams)
-{
- assert(cfg_builder_check(g));
- /** Preprocessing **/
- /* Map labels to targets and mark exception handlers */
- RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock));
- RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock));
- RETURN_IF_ERROR(label_exception_targets(g->g_entryblock));
-
- /** Optimization **/
- RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache));
- RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts));
- RETURN_IF_ERROR(
- add_checks_for_loads_of_uninitialized_variables(
- g->g_entryblock, nlocals, nparams));
-
- RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags));
- return SUCCESS;
-}
-
void
_PyCfg_ConvertExceptionHandlersToNops(basicblock *entryblock)
{
@@ -2149,8 +2115,8 @@ guarantee_lineno_for_exits(basicblock *entryblock, int firstlineno) {
}
}
-int
-_PyCfg_ResolveLineNumbers(cfg_builder *g, int firstlineno)
+static int
+resolve_line_numbers(cfg_builder *g, int firstlineno)
{
RETURN_IF_ERROR(duplicate_exits_without_lineno(g));
propagate_line_numbers(g->g_entryblock);
@@ -2158,3 +2124,25 @@ _PyCfg_ResolveLineNumbers(cfg_builder *g, int firstlineno)
return SUCCESS;
}
+int
+_PyCfg_OptimizeCodeUnit(cfg_builder *g, PyObject *consts, PyObject *const_cache,
+ int code_flags, int nlocals, int nparams, int firstlineno)
+{
+ assert(cfg_builder_check(g));
+ /** Preprocessing **/
+ /* Map labels to targets and mark exception handlers */
+ RETURN_IF_ERROR(translate_jump_labels_to_targets(g->g_entryblock));
+ RETURN_IF_ERROR(mark_except_handlers(g->g_entryblock));
+ RETURN_IF_ERROR(label_exception_targets(g->g_entryblock));
+
+ /** Optimization **/
+ RETURN_IF_ERROR(optimize_cfg(g, consts, const_cache));
+ RETURN_IF_ERROR(remove_unused_consts(g->g_entryblock, consts));
+ RETURN_IF_ERROR(
+ add_checks_for_loads_of_uninitialized_variables(
+ g->g_entryblock, nlocals, nparams));
+
+ RETURN_IF_ERROR(push_cold_blocks_to_end(g, code_flags));
+ RETURN_IF_ERROR(resolve_line_numbers(g, firstlineno));
+ return SUCCESS;
+}
diff --git a/Python/frozen.c b/Python/frozen.c
index 48b429519b6606..6b977710e6e342 100644
--- a/Python/frozen.c
+++ b/Python/frozen.c
@@ -41,6 +41,29 @@
#include
/* Includes for frozen modules: */
+#include "frozen_modules/importlib._bootstrap.h"
+#include "frozen_modules/importlib._bootstrap_external.h"
+#include "frozen_modules/zipimport.h"
+#include "frozen_modules/abc.h"
+#include "frozen_modules/codecs.h"
+#include "frozen_modules/io.h"
+#include "frozen_modules/_collections_abc.h"
+#include "frozen_modules/_sitebuiltins.h"
+#include "frozen_modules/genericpath.h"
+#include "frozen_modules/ntpath.h"
+#include "frozen_modules/posixpath.h"
+#include "frozen_modules/os.h"
+#include "frozen_modules/site.h"
+#include "frozen_modules/stat.h"
+#include "frozen_modules/importlib.util.h"
+#include "frozen_modules/importlib.machinery.h"
+#include "frozen_modules/runpy.h"
+#include "frozen_modules/__hello__.h"
+#include "frozen_modules/__phello__.h"
+#include "frozen_modules/__phello__.ham.h"
+#include "frozen_modules/__phello__.ham.eggs.h"
+#include "frozen_modules/__phello__.spam.h"
+#include "frozen_modules/frozen_only.h"
/* End includes */
#define GET_CODE(name) _Py_get_##name##_toplevel
@@ -78,46 +101,46 @@ extern PyObject *_Py_get_frozen_only_toplevel(void);
/* End extern declarations */
static const struct _frozen bootstrap_modules[] = {
- {"_frozen_importlib", NULL, 0, false, GET_CODE(importlib__bootstrap)},
- {"_frozen_importlib_external", NULL, 0, false, GET_CODE(importlib__bootstrap_external)},
- {"zipimport", NULL, 0, false, GET_CODE(zipimport)},
+ {"_frozen_importlib", _Py_M__importlib__bootstrap, (int)sizeof(_Py_M__importlib__bootstrap), false, GET_CODE(importlib__bootstrap)},
+ {"_frozen_importlib_external", _Py_M__importlib__bootstrap_external, (int)sizeof(_Py_M__importlib__bootstrap_external), false, GET_CODE(importlib__bootstrap_external)},
+ {"zipimport", _Py_M__zipimport, (int)sizeof(_Py_M__zipimport), false, GET_CODE(zipimport)},
{0, 0, 0} /* bootstrap sentinel */
};
static const struct _frozen stdlib_modules[] = {
/* stdlib - startup, without site (python -S) */
- {"abc", NULL, 0, false, GET_CODE(abc)},
- {"codecs", NULL, 0, false, GET_CODE(codecs)},
- {"io", NULL, 0, false, GET_CODE(io)},
+ {"abc", _Py_M__abc, (int)sizeof(_Py_M__abc), false, GET_CODE(abc)},
+ {"codecs", _Py_M__codecs, (int)sizeof(_Py_M__codecs), false, GET_CODE(codecs)},
+ {"io", _Py_M__io, (int)sizeof(_Py_M__io), false, GET_CODE(io)},
/* stdlib - startup, with site */
- {"_collections_abc", NULL, 0, false, GET_CODE(_collections_abc)},
- {"_sitebuiltins", NULL, 0, false, GET_CODE(_sitebuiltins)},
- {"genericpath", NULL, 0, false, GET_CODE(genericpath)},
- {"ntpath", NULL, 0, false, GET_CODE(ntpath)},
- {"posixpath", NULL, 0, false, GET_CODE(posixpath)},
- {"os.path", NULL, 0, false, GET_CODE(posixpath)},
- {"os", NULL, 0, false, GET_CODE(os)},
- {"site", NULL, 0, false, GET_CODE(site)},
- {"stat", NULL, 0, false, GET_CODE(stat)},
+ {"_collections_abc", _Py_M___collections_abc, (int)sizeof(_Py_M___collections_abc), false, GET_CODE(_collections_abc)},
+ {"_sitebuiltins", _Py_M___sitebuiltins, (int)sizeof(_Py_M___sitebuiltins), false, GET_CODE(_sitebuiltins)},
+ {"genericpath", _Py_M__genericpath, (int)sizeof(_Py_M__genericpath), false, GET_CODE(genericpath)},
+ {"ntpath", _Py_M__ntpath, (int)sizeof(_Py_M__ntpath), false, GET_CODE(ntpath)},
+ {"posixpath", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false, GET_CODE(posixpath)},
+ {"os.path", _Py_M__posixpath, (int)sizeof(_Py_M__posixpath), false, GET_CODE(posixpath)},
+ {"os", _Py_M__os, (int)sizeof(_Py_M__os), false, GET_CODE(os)},
+ {"site", _Py_M__site, (int)sizeof(_Py_M__site), false, GET_CODE(site)},
+ {"stat", _Py_M__stat, (int)sizeof(_Py_M__stat), false, GET_CODE(stat)},
/* runpy - run module with -m */
- {"importlib.util", NULL, 0, false, GET_CODE(importlib_util)},
- {"importlib.machinery", NULL, 0, false, GET_CODE(importlib_machinery)},
- {"runpy", NULL, 0, false, GET_CODE(runpy)},
+ {"importlib.util", _Py_M__importlib_util, (int)sizeof(_Py_M__importlib_util), false, GET_CODE(importlib_util)},
+ {"importlib.machinery", _Py_M__importlib_machinery, (int)sizeof(_Py_M__importlib_machinery), false, GET_CODE(importlib_machinery)},
+ {"runpy", _Py_M__runpy, (int)sizeof(_Py_M__runpy), false, GET_CODE(runpy)},
{0, 0, 0} /* stdlib sentinel */
};
static const struct _frozen test_modules[] = {
- {"__hello__", NULL, 0, false, GET_CODE(__hello__)},
- {"__hello_alias__", NULL, 0, false, GET_CODE(__hello__)},
- {"__phello_alias__", NULL, 0, true, GET_CODE(__hello__)},
- {"__phello_alias__.spam", NULL, 0, false, GET_CODE(__hello__)},
- {"__phello__", NULL, 0, true, GET_CODE(__phello__)},
- {"__phello__.__init__", NULL, 0, false, GET_CODE(__phello__)},
- {"__phello__.ham", NULL, 0, true, GET_CODE(__phello___ham)},
- {"__phello__.ham.__init__", NULL, 0, false, GET_CODE(__phello___ham)},
- {"__phello__.ham.eggs", NULL, 0, false, GET_CODE(__phello___ham_eggs)},
- {"__phello__.spam", NULL, 0, false, GET_CODE(__phello___spam)},
- {"__hello_only__", NULL, 0, false, GET_CODE(frozen_only)},
+ {"__hello__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)},
+ {"__hello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)},
+ {"__phello_alias__", _Py_M____hello__, (int)sizeof(_Py_M____hello__), true, GET_CODE(__hello__)},
+ {"__phello_alias__.spam", _Py_M____hello__, (int)sizeof(_Py_M____hello__), false, GET_CODE(__hello__)},
+ {"__phello__", _Py_M____phello__, (int)sizeof(_Py_M____phello__), true, GET_CODE(__phello__)},
+ {"__phello__.__init__", _Py_M____phello__, (int)sizeof(_Py_M____phello__), false, GET_CODE(__phello__)},
+ {"__phello__.ham", _Py_M____phello___ham, (int)sizeof(_Py_M____phello___ham), true, GET_CODE(__phello___ham)},
+ {"__phello__.ham.__init__", _Py_M____phello___ham, (int)sizeof(_Py_M____phello___ham), false, GET_CODE(__phello___ham)},
+ {"__phello__.ham.eggs", _Py_M____phello___ham_eggs, (int)sizeof(_Py_M____phello___ham_eggs), false, GET_CODE(__phello___ham_eggs)},
+ {"__phello__.spam", _Py_M____phello___spam, (int)sizeof(_Py_M____phello___spam), false, GET_CODE(__phello___spam)},
+ {"__hello_only__", _Py_M__frozen_only, (int)sizeof(_Py_M__frozen_only), false, GET_CODE(frozen_only)},
{0, 0, 0} /* test sentinel */
};
const struct _frozen *_PyImport_FrozenBootstrap = bootstrap_modules;
diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h
index 420d136bb98158..864a4f7bcaff0f 100644
--- a/Python/generated_cases.c.h
+++ b/Python/generated_cases.c.h
@@ -8,24 +8,61 @@
}
TARGET(RESUME) {
- #line 135 "Python/bytecodes.c"
+ #line 137 "Python/bytecodes.c"
assert(tstate->cframe == &cframe);
assert(frame == cframe.current_frame);
- if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
+ /* Possibly combine this with eval breaker */
+ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) {
+ int err = _Py_Instrument(frame->f_code, tstate->interp);
+ if (err) goto error;
+ next_instr--;
+ }
+ else if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
goto handle_eval_breaker;
}
- #line 18 "Python/generated_cases.c.h"
+ #line 24 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_RESUME) {
+ #line 151 "Python/bytecodes.c"
+ /* Possible performance enhancement:
+ * We need to check the eval breaker anyway, can we
+ * combine the instrument verison check and the eval breaker test?
+ */
+ if (frame->f_code->_co_instrumentation_version != tstate->interp->monitoring_version) {
+ if (_Py_Instrument(frame->f_code, tstate->interp)) {
+ goto error;
+ }
+ next_instr--;
+ }
+ else {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ int err = _Py_call_instrumentation(
+ tstate, oparg > 0, frame, next_instr-1);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (err) goto error;
+ if (frame->prev_instr != next_instr-1) {
+ /* Instrumentation has jumped */
+ next_instr = frame->prev_instr;
+ DISPATCH();
+ }
+ if (_Py_atomic_load_relaxed_int32(eval_breaker) && oparg < 2) {
+ goto handle_eval_breaker;
+ }
+ }
+ #line 55 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(LOAD_CLOSURE) {
PyObject *value;
- #line 143 "Python/bytecodes.c"
+ #line 179 "Python/bytecodes.c"
/* We keep LOAD_CLOSURE so that the bytecode stays more readable. */
value = GETLOCAL(oparg);
if (value == NULL) goto unbound_local_error;
Py_INCREF(value);
- #line 29 "Python/generated_cases.c.h"
+ #line 66 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -33,11 +70,11 @@
TARGET(LOAD_FAST_CHECK) {
PyObject *value;
- #line 150 "Python/bytecodes.c"
+ #line 186 "Python/bytecodes.c"
value = GETLOCAL(oparg);
if (value == NULL) goto unbound_local_error;
Py_INCREF(value);
- #line 41 "Python/generated_cases.c.h"
+ #line 78 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -45,11 +82,11 @@
TARGET(LOAD_FAST) {
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 53 "Python/generated_cases.c.h"
+ #line 90 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -58,10 +95,10 @@
TARGET(LOAD_CONST) {
PREDICTED(LOAD_CONST);
PyObject *value;
- #line 162 "Python/bytecodes.c"
+ #line 198 "Python/bytecodes.c"
value = GETITEM(frame->f_code->co_consts, oparg);
Py_INCREF(value);
- #line 65 "Python/generated_cases.c.h"
+ #line 102 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -69,9 +106,9 @@
TARGET(STORE_FAST) {
PyObject *value = stack_pointer[-1];
- #line 167 "Python/bytecodes.c"
+ #line 203 "Python/bytecodes.c"
SETLOCAL(oparg, value);
- #line 75 "Python/generated_cases.c.h"
+ #line 112 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
@@ -81,21 +118,21 @@
PyObject *_tmp_2;
{
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 89 "Python/generated_cases.c.h"
+ #line 126 "Python/generated_cases.c.h"
_tmp_2 = value;
}
oparg = (next_instr++)->op.arg;
{
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 99 "Python/generated_cases.c.h"
+ #line 136 "Python/generated_cases.c.h"
_tmp_1 = value;
}
STACK_GROW(2);
@@ -109,20 +146,20 @@
PyObject *_tmp_2;
{
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 117 "Python/generated_cases.c.h"
+ #line 154 "Python/generated_cases.c.h"
_tmp_2 = value;
}
oparg = (next_instr++)->op.arg;
{
PyObject *value;
- #line 162 "Python/bytecodes.c"
+ #line 198 "Python/bytecodes.c"
value = GETITEM(frame->f_code->co_consts, oparg);
Py_INCREF(value);
- #line 126 "Python/generated_cases.c.h"
+ #line 163 "Python/generated_cases.c.h"
_tmp_1 = value;
}
STACK_GROW(2);
@@ -135,18 +172,18 @@
PyObject *_tmp_1 = stack_pointer[-1];
{
PyObject *value = _tmp_1;
- #line 167 "Python/bytecodes.c"
+ #line 203 "Python/bytecodes.c"
SETLOCAL(oparg, value);
- #line 141 "Python/generated_cases.c.h"
+ #line 178 "Python/generated_cases.c.h"
}
oparg = (next_instr++)->op.arg;
{
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 150 "Python/generated_cases.c.h"
+ #line 187 "Python/generated_cases.c.h"
_tmp_1 = value;
}
stack_pointer[-1] = _tmp_1;
@@ -158,16 +195,16 @@
PyObject *_tmp_2 = stack_pointer[-2];
{
PyObject *value = _tmp_1;
- #line 167 "Python/bytecodes.c"
+ #line 203 "Python/bytecodes.c"
SETLOCAL(oparg, value);
- #line 164 "Python/generated_cases.c.h"
+ #line 201 "Python/generated_cases.c.h"
}
oparg = (next_instr++)->op.arg;
{
PyObject *value = _tmp_2;
- #line 167 "Python/bytecodes.c"
+ #line 203 "Python/bytecodes.c"
SETLOCAL(oparg, value);
- #line 171 "Python/generated_cases.c.h"
+ #line 208 "Python/generated_cases.c.h"
}
STACK_SHRINK(2);
DISPATCH();
@@ -178,20 +215,20 @@
PyObject *_tmp_2;
{
PyObject *value;
- #line 162 "Python/bytecodes.c"
+ #line 198 "Python/bytecodes.c"
value = GETITEM(frame->f_code->co_consts, oparg);
Py_INCREF(value);
- #line 185 "Python/generated_cases.c.h"
+ #line 222 "Python/generated_cases.c.h"
_tmp_2 = value;
}
oparg = (next_instr++)->op.arg;
{
PyObject *value;
- #line 156 "Python/bytecodes.c"
+ #line 192 "Python/bytecodes.c"
value = GETLOCAL(oparg);
assert(value != NULL);
Py_INCREF(value);
- #line 195 "Python/generated_cases.c.h"
+ #line 232 "Python/generated_cases.c.h"
_tmp_1 = value;
}
STACK_GROW(2);
@@ -202,8 +239,8 @@
TARGET(POP_TOP) {
PyObject *value = stack_pointer[-1];
- #line 177 "Python/bytecodes.c"
- #line 207 "Python/generated_cases.c.h"
+ #line 213 "Python/bytecodes.c"
+ #line 244 "Python/generated_cases.c.h"
Py_DECREF(value);
STACK_SHRINK(1);
DISPATCH();
@@ -211,9 +248,9 @@
TARGET(PUSH_NULL) {
PyObject *res;
- #line 181 "Python/bytecodes.c"
+ #line 217 "Python/bytecodes.c"
res = NULL;
- #line 217 "Python/generated_cases.c.h"
+ #line 254 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
DISPATCH();
@@ -224,30 +261,79 @@
PyObject *_tmp_2 = stack_pointer[-2];
{
PyObject *value = _tmp_1;
- #line 177 "Python/bytecodes.c"
- #line 229 "Python/generated_cases.c.h"
+ #line 213 "Python/bytecodes.c"
+ #line 266 "Python/generated_cases.c.h"
Py_DECREF(value);
}
{
PyObject *value = _tmp_2;
- #line 177 "Python/bytecodes.c"
- #line 235 "Python/generated_cases.c.h"
+ #line 213 "Python/bytecodes.c"
+ #line 272 "Python/generated_cases.c.h"
Py_DECREF(value);
}
STACK_SHRINK(2);
DISPATCH();
}
+ TARGET(INSTRUMENTED_END_FOR) {
+ PyObject *value = stack_pointer[-1];
+ PyObject *receiver = stack_pointer[-2];
+ #line 223 "Python/bytecodes.c"
+ /* Need to create a fake StopIteration error here,
+ * to conform to PEP 380 */
+ if (PyGen_Check(receiver)) {
+ PyErr_SetObject(PyExc_StopIteration, value);
+ if (monitor_stop_iteration(tstate, frame, next_instr-1)) {
+ goto error;
+ }
+ PyErr_SetRaisedException(NULL);
+ }
+ #line 292 "Python/generated_cases.c.h"
+ Py_DECREF(receiver);
+ Py_DECREF(value);
+ STACK_SHRINK(2);
+ DISPATCH();
+ }
+
+ TARGET(END_SEND) {
+ PyObject *value = stack_pointer[-1];
+ PyObject *receiver = stack_pointer[-2];
+ #line 236 "Python/bytecodes.c"
+ Py_DECREF(receiver);
+ #line 304 "Python/generated_cases.c.h"
+ STACK_SHRINK(1);
+ stack_pointer[-1] = value;
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_END_SEND) {
+ PyObject *value = stack_pointer[-1];
+ PyObject *receiver = stack_pointer[-2];
+ #line 240 "Python/bytecodes.c"
+ if (PyGen_Check(receiver) || PyCoro_CheckExact(receiver)) {
+ PyErr_SetObject(PyExc_StopIteration, value);
+ if (monitor_stop_iteration(tstate, frame, next_instr-1)) {
+ goto error;
+ }
+ PyErr_SetRaisedException(NULL);
+ }
+ Py_DECREF(receiver);
+ #line 322 "Python/generated_cases.c.h"
+ STACK_SHRINK(1);
+ stack_pointer[-1] = value;
+ DISPATCH();
+ }
+
TARGET(UNARY_NEGATIVE) {
PyObject *value = stack_pointer[-1];
PyObject *res;
- #line 187 "Python/bytecodes.c"
+ #line 251 "Python/bytecodes.c"
res = PyNumber_Negative(value);
- #line 247 "Python/generated_cases.c.h"
+ #line 333 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 189 "Python/bytecodes.c"
+ #line 253 "Python/bytecodes.c"
if (res == NULL) goto pop_1_error;
- #line 251 "Python/generated_cases.c.h"
+ #line 337 "Python/generated_cases.c.h"
stack_pointer[-1] = res;
DISPATCH();
}
@@ -255,11 +341,11 @@
TARGET(UNARY_NOT) {
PyObject *value = stack_pointer[-1];
PyObject *res;
- #line 193 "Python/bytecodes.c"
+ #line 257 "Python/bytecodes.c"
int err = PyObject_IsTrue(value);
- #line 261 "Python/generated_cases.c.h"
+ #line 347 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 195 "Python/bytecodes.c"
+ #line 259 "Python/bytecodes.c"
if (err < 0) goto pop_1_error;
if (err == 0) {
res = Py_True;
@@ -268,7 +354,7 @@
res = Py_False;
}
Py_INCREF(res);
- #line 272 "Python/generated_cases.c.h"
+ #line 358 "Python/generated_cases.c.h"
stack_pointer[-1] = res;
DISPATCH();
}
@@ -276,13 +362,13 @@
TARGET(UNARY_INVERT) {
PyObject *value = stack_pointer[-1];
PyObject *res;
- #line 206 "Python/bytecodes.c"
+ #line 270 "Python/bytecodes.c"
res = PyNumber_Invert(value);
- #line 282 "Python/generated_cases.c.h"
+ #line 368 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 208 "Python/bytecodes.c"
+ #line 272 "Python/bytecodes.c"
if (res == NULL) goto pop_1_error;
- #line 286 "Python/generated_cases.c.h"
+ #line 372 "Python/generated_cases.c.h"
stack_pointer[-1] = res;
DISPATCH();
}
@@ -291,8 +377,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *prod;
- #line 225 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 289 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -300,7 +385,7 @@
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
if (prod == NULL) goto pop_2_error;
- #line 304 "Python/generated_cases.c.h"
+ #line 389 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = prod;
next_instr += 1;
@@ -311,15 +396,14 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *prod;
- #line 236 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 299 "Python/bytecodes.c"
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
double dprod = ((PyFloatObject *)left)->ob_fval *
((PyFloatObject *)right)->ob_fval;
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dprod, prod);
- #line 323 "Python/generated_cases.c.h"
+ #line 407 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = prod;
next_instr += 1;
@@ -330,8 +414,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *sub;
- #line 246 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 308 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyLong_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -339,7 +422,7 @@
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
if (sub == NULL) goto pop_2_error;
- #line 343 "Python/generated_cases.c.h"
+ #line 426 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = sub;
next_instr += 1;
@@ -350,14 +433,13 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *sub;
- #line 257 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 318 "Python/bytecodes.c"
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(!PyFloat_CheckExact(right), BINARY_OP);
STAT_INC(BINARY_OP, hit);
double dsub = ((PyFloatObject *)left)->ob_fval - ((PyFloatObject *)right)->ob_fval;
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsub, sub);
- #line 361 "Python/generated_cases.c.h"
+ #line 443 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = sub;
next_instr += 1;
@@ -368,8 +450,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res;
- #line 266 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 326 "Python/bytecodes.c"
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -377,7 +458,7 @@
_Py_DECREF_SPECIALIZED(left, _PyUnicode_ExactDealloc);
_Py_DECREF_SPECIALIZED(right, _PyUnicode_ExactDealloc);
if (res == NULL) goto pop_2_error;
- #line 381 "Python/generated_cases.c.h"
+ #line 462 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -387,8 +468,7 @@
TARGET(BINARY_OP_INPLACE_ADD_UNICODE) {
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
- #line 283 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 342 "Python/bytecodes.c"
DEOPT_IF(!PyUnicode_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
_Py_CODEUNIT true_next = next_instr[INLINE_CACHE_ENTRIES_BINARY_OP];
@@ -415,7 +495,7 @@
if (*target_local == NULL) goto pop_2_error;
// The STORE_FAST is already done.
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_OP + 1);
- #line 419 "Python/generated_cases.c.h"
+ #line 499 "Python/generated_cases.c.h"
STACK_SHRINK(2);
DISPATCH();
}
@@ -424,15 +504,14 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *sum;
- #line 313 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 371 "Python/bytecodes.c"
DEOPT_IF(!PyFloat_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
double dsum = ((PyFloatObject *)left)->ob_fval +
((PyFloatObject *)right)->ob_fval;
DECREF_INPUTS_AND_REUSE_FLOAT(left, right, dsum, sum);
- #line 436 "Python/generated_cases.c.h"
+ #line 515 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = sum;
next_instr += 1;
@@ -443,8 +522,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *sum;
- #line 323 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 380 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(left), BINARY_OP);
DEOPT_IF(Py_TYPE(right) != Py_TYPE(left), BINARY_OP);
STAT_INC(BINARY_OP, hit);
@@ -452,7 +530,7 @@
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
_Py_DECREF_SPECIALIZED(left, (destructor)PyObject_Free);
if (sum == NULL) goto pop_2_error;
- #line 456 "Python/generated_cases.c.h"
+ #line 534 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = sum;
next_instr += 1;
@@ -465,11 +543,10 @@
PyObject *sub = stack_pointer[-1];
PyObject *container = stack_pointer[-2];
PyObject *res;
- #line 342 "Python/bytecodes.c"
+ #line 398 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyBinarySubscrCache *cache = (_PyBinarySubscrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinarySubscr(container, sub, next_instr);
DISPATCH_SAME_OPARG();
@@ -478,12 +555,12 @@
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
res = PyObject_GetItem(container, sub);
- #line 482 "Python/generated_cases.c.h"
+ #line 559 "Python/generated_cases.c.h"
Py_DECREF(container);
Py_DECREF(sub);
- #line 355 "Python/bytecodes.c"
+ #line 410 "Python/bytecodes.c"
if (res == NULL) goto pop_2_error;
- #line 487 "Python/generated_cases.c.h"
+ #line 564 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -495,7 +572,7 @@
PyObject *start = stack_pointer[-2];
PyObject *container = stack_pointer[-3];
PyObject *res;
- #line 359 "Python/bytecodes.c"
+ #line 414 "Python/bytecodes.c"
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
// Can't use ERROR_IF() here, because we haven't
// DECREF'ed container yet, and we still own slice.
@@ -508,7 +585,7 @@
}
Py_DECREF(container);
if (res == NULL) goto pop_3_error;
- #line 512 "Python/generated_cases.c.h"
+ #line 589 "Python/generated_cases.c.h"
STACK_SHRINK(2);
stack_pointer[-1] = res;
DISPATCH();
@@ -519,7 +596,7 @@
PyObject *start = stack_pointer[-2];
PyObject *container = stack_pointer[-3];
PyObject *v = stack_pointer[-4];
- #line 374 "Python/bytecodes.c"
+ #line 429 "Python/bytecodes.c"
PyObject *slice = _PyBuildSlice_ConsumeRefs(start, stop);
int err;
if (slice == NULL) {
@@ -532,7 +609,7 @@
Py_DECREF(v);
Py_DECREF(container);
if (err) goto pop_4_error;
- #line 536 "Python/generated_cases.c.h"
+ #line 613 "Python/generated_cases.c.h"
STACK_SHRINK(4);
DISPATCH();
}
@@ -541,8 +618,7 @@
PyObject *sub = stack_pointer[-1];
PyObject *list = stack_pointer[-2];
PyObject *res;
- #line 389 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 444 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
DEOPT_IF(!PyList_CheckExact(list), BINARY_SUBSCR);
@@ -556,7 +632,7 @@
Py_INCREF(res);
_Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
Py_DECREF(list);
- #line 560 "Python/generated_cases.c.h"
+ #line 636 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -567,8 +643,7 @@
PyObject *sub = stack_pointer[-1];
PyObject *tuple = stack_pointer[-2];
PyObject *res;
- #line 406 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 460 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(sub), BINARY_SUBSCR);
DEOPT_IF(!PyTuple_CheckExact(tuple), BINARY_SUBSCR);
@@ -582,7 +657,7 @@
Py_INCREF(res);
_Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
Py_DECREF(tuple);
- #line 586 "Python/generated_cases.c.h"
+ #line 661 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -593,8 +668,7 @@
PyObject *sub = stack_pointer[-1];
PyObject *dict = stack_pointer[-2];
PyObject *res;
- #line 423 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 476 "Python/bytecodes.c"
DEOPT_IF(!PyDict_CheckExact(dict), BINARY_SUBSCR);
STAT_INC(BINARY_SUBSCR, hit);
res = PyDict_GetItemWithError(dict, sub);
@@ -602,14 +676,14 @@
if (!_PyErr_Occurred(tstate)) {
_PyErr_SetKeyError(sub);
}
- #line 606 "Python/generated_cases.c.h"
+ #line 680 "Python/generated_cases.c.h"
Py_DECREF(dict);
Py_DECREF(sub);
- #line 432 "Python/bytecodes.c"
+ #line 484 "Python/bytecodes.c"
if (true) goto pop_2_error;
}
Py_INCREF(res); // Do this before DECREF'ing dict, sub
- #line 613 "Python/generated_cases.c.h"
+ #line 687 "Python/generated_cases.c.h"
Py_DECREF(dict);
Py_DECREF(sub);
STACK_SHRINK(1);
@@ -621,7 +695,7 @@
TARGET(BINARY_SUBSCR_GETITEM) {
PyObject *sub = stack_pointer[-1];
PyObject *container = stack_pointer[-2];
- #line 439 "Python/bytecodes.c"
+ #line 491 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(container);
DEOPT_IF(!PyType_HasFeature(tp, Py_TPFLAGS_HEAPTYPE), BINARY_SUBSCR);
PyHeapTypeObject *ht = (PyHeapTypeObject *)tp;
@@ -641,16 +715,17 @@
new_frame->localsplus[0] = container;
new_frame->localsplus[1] = sub;
JUMPBY(INLINE_CACHE_ENTRIES_BINARY_SUBSCR);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- #line 646 "Python/generated_cases.c.h"
+ #line 721 "Python/generated_cases.c.h"
}
TARGET(LIST_APPEND) {
PyObject *v = stack_pointer[-1];
PyObject *list = stack_pointer[-(2 + (oparg-1))];
- #line 462 "Python/bytecodes.c"
+ #line 515 "Python/bytecodes.c"
if (_PyList_AppendTakeRef((PyListObject *)list, v) < 0) goto pop_1_error;
- #line 654 "Python/generated_cases.c.h"
+ #line 729 "Python/generated_cases.c.h"
STACK_SHRINK(1);
PREDICT(JUMP_BACKWARD);
DISPATCH();
@@ -659,13 +734,13 @@
TARGET(SET_ADD) {
PyObject *v = stack_pointer[-1];
PyObject *set = stack_pointer[-(2 + (oparg-1))];
- #line 467 "Python/bytecodes.c"
+ #line 520 "Python/bytecodes.c"
int err = PySet_Add(set, v);
- #line 665 "Python/generated_cases.c.h"
+ #line 740 "Python/generated_cases.c.h"
Py_DECREF(v);
- #line 469 "Python/bytecodes.c"
+ #line 522 "Python/bytecodes.c"
if (err) goto pop_1_error;
- #line 669 "Python/generated_cases.c.h"
+ #line 744 "Python/generated_cases.c.h"
STACK_SHRINK(1);
PREDICT(JUMP_BACKWARD);
DISPATCH();
@@ -678,10 +753,9 @@
PyObject *container = stack_pointer[-2];
PyObject *v = stack_pointer[-3];
uint16_t counter = read_u16(&next_instr[0].cache);
- #line 480 "Python/bytecodes.c"
+ #line 533 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_StoreSubscr(container, sub, next_instr);
DISPATCH_SAME_OPARG();
@@ -694,13 +768,13 @@
#endif /* ENABLE_SPECIALIZATION */
/* container[sub] = v */
int err = PyObject_SetItem(container, sub, v);
- #line 698 "Python/generated_cases.c.h"
+ #line 772 "Python/generated_cases.c.h"
Py_DECREF(v);
Py_DECREF(container);
Py_DECREF(sub);
- #line 496 "Python/bytecodes.c"
+ #line 548 "Python/bytecodes.c"
if (err) goto pop_3_error;
- #line 704 "Python/generated_cases.c.h"
+ #line 778 "Python/generated_cases.c.h"
STACK_SHRINK(3);
next_instr += 1;
DISPATCH();
@@ -710,8 +784,7 @@
PyObject *sub = stack_pointer[-1];
PyObject *list = stack_pointer[-2];
PyObject *value = stack_pointer[-3];
- #line 500 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 552 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(sub), STORE_SUBSCR);
DEOPT_IF(!PyList_CheckExact(list), STORE_SUBSCR);
@@ -728,7 +801,7 @@
Py_DECREF(old_value);
_Py_DECREF_SPECIALIZED(sub, (destructor)PyObject_Free);
Py_DECREF(list);
- #line 732 "Python/generated_cases.c.h"
+ #line 805 "Python/generated_cases.c.h"
STACK_SHRINK(3);
next_instr += 1;
DISPATCH();
@@ -738,14 +811,13 @@
PyObject *sub = stack_pointer[-1];
PyObject *dict = stack_pointer[-2];
PyObject *value = stack_pointer[-3];
- #line 520 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 571 "Python/bytecodes.c"
DEOPT_IF(!PyDict_CheckExact(dict), STORE_SUBSCR);
STAT_INC(STORE_SUBSCR, hit);
int err = _PyDict_SetItem_Take2((PyDictObject *)dict, sub, value);
Py_DECREF(dict);
if (err) goto pop_3_error;
- #line 749 "Python/generated_cases.c.h"
+ #line 821 "Python/generated_cases.c.h"
STACK_SHRINK(3);
next_instr += 1;
DISPATCH();
@@ -754,15 +826,15 @@
TARGET(DELETE_SUBSCR) {
PyObject *sub = stack_pointer[-1];
PyObject *container = stack_pointer[-2];
- #line 529 "Python/bytecodes.c"
+ #line 579 "Python/bytecodes.c"
/* del container[sub] */
int err = PyObject_DelItem(container, sub);
- #line 761 "Python/generated_cases.c.h"
+ #line 833 "Python/generated_cases.c.h"
Py_DECREF(container);
Py_DECREF(sub);
- #line 532 "Python/bytecodes.c"
+ #line 582 "Python/bytecodes.c"
if (err) goto pop_2_error;
- #line 766 "Python/generated_cases.c.h"
+ #line 838 "Python/generated_cases.c.h"
STACK_SHRINK(2);
DISPATCH();
}
@@ -770,14 +842,14 @@
TARGET(CALL_INTRINSIC_1) {
PyObject *value = stack_pointer[-1];
PyObject *res;
- #line 536 "Python/bytecodes.c"
+ #line 586 "Python/bytecodes.c"
assert(oparg <= MAX_INTRINSIC_1);
res = _PyIntrinsics_UnaryFunctions[oparg](tstate, value);
- #line 777 "Python/generated_cases.c.h"
+ #line 849 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 539 "Python/bytecodes.c"
+ #line 589 "Python/bytecodes.c"
if (res == NULL) goto pop_1_error;
- #line 781 "Python/generated_cases.c.h"
+ #line 853 "Python/generated_cases.c.h"
stack_pointer[-1] = res;
DISPATCH();
}
@@ -786,15 +858,15 @@
PyObject *value1 = stack_pointer[-1];
PyObject *value2 = stack_pointer[-2];
PyObject *res;
- #line 543 "Python/bytecodes.c"
+ #line 593 "Python/bytecodes.c"
assert(oparg <= MAX_INTRINSIC_2);
res = _PyIntrinsics_BinaryFunctions[oparg](tstate, value2, value1);
- #line 793 "Python/generated_cases.c.h"
+ #line 865 "Python/generated_cases.c.h"
Py_DECREF(value2);
Py_DECREF(value1);
- #line 546 "Python/bytecodes.c"
+ #line 596 "Python/bytecodes.c"
if (res == NULL) goto pop_2_error;
- #line 798 "Python/generated_cases.c.h"
+ #line 870 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
DISPATCH();
@@ -802,7 +874,7 @@
TARGET(RAISE_VARARGS) {
PyObject **args = (stack_pointer - oparg);
- #line 550 "Python/bytecodes.c"
+ #line 600 "Python/bytecodes.c"
PyObject *cause = NULL, *exc = NULL;
switch (oparg) {
case 2:
@@ -820,68 +892,109 @@
break;
}
if (true) { STACK_SHRINK(oparg); goto error; }
- #line 824 "Python/generated_cases.c.h"
+ #line 896 "Python/generated_cases.c.h"
}
TARGET(INTERPRETER_EXIT) {
PyObject *retval = stack_pointer[-1];
- #line 570 "Python/bytecodes.c"
+ #line 620 "Python/bytecodes.c"
assert(frame == &entry_frame);
assert(_PyFrame_IsIncomplete(frame));
STACK_SHRINK(1); // Since we're not going to DISPATCH()
assert(EMPTY());
/* Restore previous cframe and return. */
tstate->cframe = cframe.previous;
- tstate->cframe->use_tracing = cframe.use_tracing;
assert(tstate->cframe->current_frame == frame->previous);
assert(!_PyErr_Occurred(tstate));
_Py_LeaveRecursiveCallTstate(tstate);
return retval;
- #line 841 "Python/generated_cases.c.h"
+ #line 912 "Python/generated_cases.c.h"
}
TARGET(RETURN_VALUE) {
PyObject *retval = stack_pointer[-1];
- #line 584 "Python/bytecodes.c"
+ #line 633 "Python/bytecodes.c"
STACK_SHRINK(1);
assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCallPy(tstate);
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = cframe.current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
- #line 860 "Python/generated_cases.c.h"
+ #line 930 "Python/generated_cases.c.h"
+ }
+
+ TARGET(INSTRUMENTED_RETURN_VALUE) {
+ PyObject *retval = stack_pointer[-1];
+ #line 648 "Python/bytecodes.c"
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_RETURN,
+ frame, next_instr-1, retval);
+ if (err) goto error;
+ STACK_SHRINK(1);
+ assert(EMPTY());
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _Py_LeaveRecursiveCallPy(tstate);
+ assert(frame != &entry_frame);
+ // GH-99729: We need to unlink the frame *before* clearing it:
+ _PyInterpreterFrame *dying = frame;
+ frame = cframe.current_frame = dying->previous;
+ _PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ #line 952 "Python/generated_cases.c.h"
}
TARGET(RETURN_CONST) {
- #line 600 "Python/bytecodes.c"
+ #line 667 "Python/bytecodes.c"
+ PyObject *retval = GETITEM(frame->f_code->co_consts, oparg);
+ Py_INCREF(retval);
+ assert(EMPTY());
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _Py_LeaveRecursiveCallPy(tstate);
+ assert(frame != &entry_frame);
+ // GH-99729: We need to unlink the frame *before* clearing it:
+ _PyInterpreterFrame *dying = frame;
+ frame = cframe.current_frame = dying->previous;
+ _PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ #line 970 "Python/generated_cases.c.h"
+ }
+
+ TARGET(INSTRUMENTED_RETURN_CONST) {
+ #line 683 "Python/bytecodes.c"
PyObject *retval = GETITEM(frame->f_code->co_consts, oparg);
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_RETURN,
+ frame, next_instr-1, retval);
+ if (err) goto error;
Py_INCREF(retval);
assert(EMPTY());
_PyFrame_SetStackPointer(frame, stack_pointer);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
_Py_LeaveRecursiveCallPy(tstate);
assert(frame != &entry_frame);
// GH-99729: We need to unlink the frame *before* clearing it:
_PyInterpreterFrame *dying = frame;
frame = cframe.current_frame = dying->previous;
_PyEvalFrameClearAndPop(tstate, dying);
+ frame->prev_instr += frame->return_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
- #line 879 "Python/generated_cases.c.h"
+ #line 992 "Python/generated_cases.c.h"
}
TARGET(GET_AITER) {
PyObject *obj = stack_pointer[-1];
PyObject *iter;
- #line 617 "Python/bytecodes.c"
+ #line 703 "Python/bytecodes.c"
unaryfunc getter = NULL;
PyTypeObject *type = Py_TYPE(obj);
@@ -894,16 +1007,16 @@
"'async for' requires an object with "
"__aiter__ method, got %.100s",
type->tp_name);
- #line 898 "Python/generated_cases.c.h"
+ #line 1011 "Python/generated_cases.c.h"
Py_DECREF(obj);
- #line 630 "Python/bytecodes.c"
+ #line 716 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
iter = (*getter)(obj);
- #line 905 "Python/generated_cases.c.h"
+ #line 1018 "Python/generated_cases.c.h"
Py_DECREF(obj);
- #line 635 "Python/bytecodes.c"
+ #line 721 "Python/bytecodes.c"
if (iter == NULL) goto pop_1_error;
if (Py_TYPE(iter)->tp_as_async == NULL ||
@@ -916,7 +1029,7 @@
Py_DECREF(iter);
if (true) goto pop_1_error;
}
- #line 920 "Python/generated_cases.c.h"
+ #line 1033 "Python/generated_cases.c.h"
stack_pointer[-1] = iter;
DISPATCH();
}
@@ -924,7 +1037,7 @@
TARGET(GET_ANEXT) {
PyObject *aiter = stack_pointer[-1];
PyObject *awaitable;
- #line 650 "Python/bytecodes.c"
+ #line 736 "Python/bytecodes.c"
unaryfunc getter = NULL;
PyObject *next_iter = NULL;
PyTypeObject *type = Py_TYPE(aiter);
@@ -968,7 +1081,7 @@
}
}
- #line 972 "Python/generated_cases.c.h"
+ #line 1085 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = awaitable;
PREDICT(LOAD_CONST);
@@ -979,16 +1092,16 @@
PREDICTED(GET_AWAITABLE);
PyObject *iterable = stack_pointer[-1];
PyObject *iter;
- #line 697 "Python/bytecodes.c"
+ #line 783 "Python/bytecodes.c"
iter = _PyCoro_GetAwaitableIter(iterable);
if (iter == NULL) {
format_awaitable_error(tstate, Py_TYPE(iterable), oparg);
}
- #line 990 "Python/generated_cases.c.h"
+ #line 1103 "Python/generated_cases.c.h"
Py_DECREF(iterable);
- #line 704 "Python/bytecodes.c"
+ #line 790 "Python/bytecodes.c"
if (iter != NULL && PyCoro_CheckExact(iter)) {
PyObject *yf = _PyGen_yf((PyGenObject*)iter);
@@ -1006,7 +1119,7 @@
if (iter == NULL) goto pop_1_error;
- #line 1010 "Python/generated_cases.c.h"
+ #line 1123 "Python/generated_cases.c.h"
stack_pointer[-1] = iter;
PREDICT(LOAD_CONST);
DISPATCH();
@@ -1017,11 +1130,10 @@
PyObject *v = stack_pointer[-1];
PyObject *receiver = stack_pointer[-2];
PyObject *retval;
- #line 730 "Python/bytecodes.c"
+ #line 816 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PySendCache *cache = (_PySendCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_Send(receiver, next_instr);
DISPATCH_SAME_OPARG();
@@ -1030,6 +1142,20 @@
DECREMENT_ADAPTIVE_COUNTER(cache->counter);
#endif /* ENABLE_SPECIALIZATION */
assert(frame != &entry_frame);
+ if ((Py_TYPE(receiver) == &PyGen_Type ||
+ Py_TYPE(receiver) == &PyCoro_Type) && ((PyGenObject *)receiver)->gi_frame_state < FRAME_EXECUTING)
+ {
+ 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;
+ JUMPBY(INLINE_CACHE_ENTRIES_SEND);
+ DISPATCH_INLINED(gen_frame);
+ }
if (Py_IsNone(v) && PyIter_Check(receiver)) {
retval = Py_TYPE(receiver)->tp_iternext(receiver);
}
@@ -1037,23 +1163,20 @@
retval = PyObject_CallMethodOneArg(receiver, &_Py_ID(send), v);
}
if (retval == NULL) {
- if (tstate->c_tracefunc != NULL
- && _PyErr_ExceptionMatches(tstate, PyExc_StopIteration))
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
+ if (_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)
+ ) {
+ monitor_raise(tstate, frame, next_instr-1);
+ }
if (_PyGen_FetchStopIterationValue(&retval) == 0) {
assert(retval != NULL);
JUMPBY(oparg);
}
else {
- assert(retval == NULL);
goto error;
}
}
- else {
- assert(retval != NULL);
- }
Py_DECREF(v);
- #line 1057 "Python/generated_cases.c.h"
+ #line 1180 "Python/generated_cases.c.h"
stack_pointer[-1] = retval;
next_instr += 1;
DISPATCH();
@@ -1062,28 +1185,49 @@
TARGET(SEND_GEN) {
PyObject *v = stack_pointer[-1];
PyObject *receiver = stack_pointer[-2];
- #line 768 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 864 "Python/bytecodes.c"
PyGenObject *gen = (PyGenObject *)receiver;
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type &&
Py_TYPE(gen) != &PyCoro_Type, SEND);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, SEND);
STAT_INC(SEND, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->yield_offset = oparg;
+ 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;
- JUMPBY(INLINE_CACHE_ENTRIES_SEND + oparg);
+ JUMPBY(INLINE_CACHE_ENTRIES_SEND);
DISPATCH_INLINED(gen_frame);
- #line 1082 "Python/generated_cases.c.h"
+ #line 1204 "Python/generated_cases.c.h"
+ }
+
+ TARGET(INSTRUMENTED_YIELD_VALUE) {
+ PyObject *retval = stack_pointer[-1];
+ #line 881 "Python/bytecodes.c"
+ assert(frame != &entry_frame);
+ PyGenObject *gen = _PyFrame_GetGenerator(frame);
+ gen->gi_frame_state = FRAME_SUSPENDED;
+ _PyFrame_SetStackPointer(frame, stack_pointer - 1);
+ int err = _Py_call_instrumentation_arg(
+ tstate, PY_MONITORING_EVENT_PY_YIELD,
+ frame, next_instr-1, retval);
+ if (err) goto error;
+ tstate->exc_info = gen->gi_exc_state.previous_item;
+ gen->gi_exc_state.previous_item = NULL;
+ _Py_LeaveRecursiveCallPy(tstate);
+ _PyInterpreterFrame *gen_frame = frame;
+ frame = cframe.current_frame = frame->previous;
+ gen_frame->previous = NULL;
+ _PyFrame_StackPush(frame, retval);
+ goto resume_frame;
+ #line 1226 "Python/generated_cases.c.h"
}
TARGET(YIELD_VALUE) {
PyObject *retval = stack_pointer[-1];
- #line 786 "Python/bytecodes.c"
+ #line 900 "Python/bytecodes.c"
// NOTE: It's important that YIELD_VALUE never raises an exception!
// The compiler treats any exception raised here as a failed close()
// or throw() call.
@@ -1091,26 +1235,23 @@
PyGenObject *gen = _PyFrame_GetGenerator(frame);
gen->gi_frame_state = FRAME_SUSPENDED;
_PyFrame_SetStackPointer(frame, stack_pointer - 1);
- TRACE_FUNCTION_EXIT();
- DTRACE_FUNCTION_EXIT();
tstate->exc_info = gen->gi_exc_state.previous_item;
gen->gi_exc_state.previous_item = NULL;
_Py_LeaveRecursiveCallPy(tstate);
_PyInterpreterFrame *gen_frame = frame;
frame = cframe.current_frame = frame->previous;
gen_frame->previous = NULL;
- frame->prev_instr -= frame->yield_offset;
_PyFrame_StackPush(frame, retval);
goto resume_frame;
- #line 1106 "Python/generated_cases.c.h"
+ #line 1247 "Python/generated_cases.c.h"
}
TARGET(POP_EXCEPT) {
PyObject *exc_value = stack_pointer[-1];
- #line 807 "Python/bytecodes.c"
+ #line 918 "Python/bytecodes.c"
_PyErr_StackItem *exc_info = tstate->exc_info;
Py_XSETREF(exc_info->exc_value, exc_value);
- #line 1114 "Python/generated_cases.c.h"
+ #line 1255 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
@@ -1118,7 +1259,7 @@
TARGET(RERAISE) {
PyObject *exc = stack_pointer[-1];
PyObject **values = (stack_pointer - (1 + oparg));
- #line 812 "Python/bytecodes.c"
+ #line 923 "Python/bytecodes.c"
assert(oparg >= 0 && oparg <= 2);
if (oparg) {
PyObject *lasti = values[0];
@@ -1136,26 +1277,26 @@
Py_INCREF(exc);
_PyErr_SetRaisedException(tstate, exc);
goto exception_unwind;
- #line 1140 "Python/generated_cases.c.h"
+ #line 1281 "Python/generated_cases.c.h"
}
TARGET(END_ASYNC_FOR) {
PyObject *exc = stack_pointer[-1];
PyObject *awaitable = stack_pointer[-2];
- #line 832 "Python/bytecodes.c"
+ #line 943 "Python/bytecodes.c"
assert(exc && PyExceptionInstance_Check(exc));
if (PyErr_GivenExceptionMatches(exc, PyExc_StopAsyncIteration)) {
- #line 1149 "Python/generated_cases.c.h"
+ #line 1290 "Python/generated_cases.c.h"
Py_DECREF(awaitable);
Py_DECREF(exc);
- #line 835 "Python/bytecodes.c"
+ #line 946 "Python/bytecodes.c"
}
else {
Py_INCREF(exc);
_PyErr_SetRaisedException(tstate, exc);
goto exception_unwind;
}
- #line 1159 "Python/generated_cases.c.h"
+ #line 1300 "Python/generated_cases.c.h"
STACK_SHRINK(2);
DISPATCH();
}
@@ -1166,23 +1307,23 @@
PyObject *sub_iter = stack_pointer[-3];
PyObject *none;
PyObject *value;
- #line 844 "Python/bytecodes.c"
+ #line 955 "Python/bytecodes.c"
assert(throwflag);
assert(exc_value && PyExceptionInstance_Check(exc_value));
if (PyErr_GivenExceptionMatches(exc_value, PyExc_StopIteration)) {
value = Py_NewRef(((PyStopIterationObject *)exc_value)->value);
- #line 1175 "Python/generated_cases.c.h"
+ #line 1316 "Python/generated_cases.c.h"
Py_DECREF(sub_iter);
Py_DECREF(last_sent_val);
Py_DECREF(exc_value);
- #line 849 "Python/bytecodes.c"
+ #line 960 "Python/bytecodes.c"
none = Py_NewRef(Py_None);
}
else {
_PyErr_SetRaisedException(tstate, Py_NewRef(exc_value));
goto exception_unwind;
}
- #line 1186 "Python/generated_cases.c.h"
+ #line 1327 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = value;
stack_pointer[-2] = none;
@@ -1191,9 +1332,9 @@
TARGET(LOAD_ASSERTION_ERROR) {
PyObject *value;
- #line 858 "Python/bytecodes.c"
+ #line 969 "Python/bytecodes.c"
value = Py_NewRef(PyExc_AssertionError);
- #line 1197 "Python/generated_cases.c.h"
+ #line 1338 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -1201,7 +1342,7 @@
TARGET(LOAD_BUILD_CLASS) {
PyObject *bc;
- #line 862 "Python/bytecodes.c"
+ #line 973 "Python/bytecodes.c"
if (PyDict_CheckExact(BUILTINS())) {
bc = _PyDict_GetItemWithError(BUILTINS(),
&_Py_ID(__build_class__));
@@ -1223,7 +1364,7 @@
if (true) goto error;
}
}
- #line 1227 "Python/generated_cases.c.h"
+ #line 1368 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = bc;
DISPATCH();
@@ -1231,33 +1372,33 @@
TARGET(STORE_NAME) {
PyObject *v = stack_pointer[-1];
- #line 886 "Python/bytecodes.c"
+ #line 997 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
PyObject *ns = LOCALS();
int err;
if (ns == NULL) {
_PyErr_Format(tstate, PyExc_SystemError,
"no locals found when storing %R", name);
- #line 1242 "Python/generated_cases.c.h"
+ #line 1383 "Python/generated_cases.c.h"
Py_DECREF(v);
- #line 893 "Python/bytecodes.c"
+ #line 1004 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
if (PyDict_CheckExact(ns))
err = PyDict_SetItem(ns, name, v);
else
err = PyObject_SetItem(ns, name, v);
- #line 1251 "Python/generated_cases.c.h"
+ #line 1392 "Python/generated_cases.c.h"
Py_DECREF(v);
- #line 900 "Python/bytecodes.c"
+ #line 1011 "Python/bytecodes.c"
if (err) goto pop_1_error;
- #line 1255 "Python/generated_cases.c.h"
+ #line 1396 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(DELETE_NAME) {
- #line 904 "Python/bytecodes.c"
+ #line 1015 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
PyObject *ns = LOCALS();
int err;
@@ -1274,7 +1415,7 @@
name);
goto error;
}
- #line 1278 "Python/generated_cases.c.h"
+ #line 1419 "Python/generated_cases.c.h"
DISPATCH();
}
@@ -1282,11 +1423,10 @@
PREDICTED(UNPACK_SEQUENCE);
static_assert(INLINE_CACHE_ENTRIES_UNPACK_SEQUENCE == 1, "incorrect cache size");
PyObject *seq = stack_pointer[-1];
- #line 930 "Python/bytecodes.c"
+ #line 1041 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyUnpackSequenceCache *cache = (_PyUnpackSequenceCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_UnpackSequence(seq, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -1296,11 +1436,11 @@
#endif /* ENABLE_SPECIALIZATION */
PyObject **top = stack_pointer + oparg - 1;
int res = unpack_iterable(tstate, seq, oparg, -1, top);
- #line 1300 "Python/generated_cases.c.h"
+ #line 1440 "Python/generated_cases.c.h"
Py_DECREF(seq);
- #line 944 "Python/bytecodes.c"
+ #line 1054 "Python/bytecodes.c"
if (res == 0) goto pop_1_error;
- #line 1304 "Python/generated_cases.c.h"
+ #line 1444 "Python/generated_cases.c.h"
STACK_SHRINK(1);
STACK_GROW(oparg);
next_instr += 1;
@@ -1310,14 +1450,14 @@
TARGET(UNPACK_SEQUENCE_TWO_TUPLE) {
PyObject *seq = stack_pointer[-1];
PyObject **values = stack_pointer - (1);
- #line 948 "Python/bytecodes.c"
+ #line 1058 "Python/bytecodes.c"
DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyTuple_GET_SIZE(seq) != 2, UNPACK_SEQUENCE);
assert(oparg == 2);
STAT_INC(UNPACK_SEQUENCE, hit);
values[0] = Py_NewRef(PyTuple_GET_ITEM(seq, 1));
values[1] = Py_NewRef(PyTuple_GET_ITEM(seq, 0));
- #line 1321 "Python/generated_cases.c.h"
+ #line 1461 "Python/generated_cases.c.h"
Py_DECREF(seq);
STACK_SHRINK(1);
STACK_GROW(oparg);
@@ -1328,7 +1468,7 @@
TARGET(UNPACK_SEQUENCE_TUPLE) {
PyObject *seq = stack_pointer[-1];
PyObject **values = stack_pointer - (1);
- #line 958 "Python/bytecodes.c"
+ #line 1068 "Python/bytecodes.c"
DEOPT_IF(!PyTuple_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyTuple_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
STAT_INC(UNPACK_SEQUENCE, hit);
@@ -1336,7 +1476,7 @@
for (int i = oparg; --i >= 0; ) {
*values++ = Py_NewRef(items[i]);
}
- #line 1340 "Python/generated_cases.c.h"
+ #line 1480 "Python/generated_cases.c.h"
Py_DECREF(seq);
STACK_SHRINK(1);
STACK_GROW(oparg);
@@ -1347,7 +1487,7 @@
TARGET(UNPACK_SEQUENCE_LIST) {
PyObject *seq = stack_pointer[-1];
PyObject **values = stack_pointer - (1);
- #line 969 "Python/bytecodes.c"
+ #line 1079 "Python/bytecodes.c"
DEOPT_IF(!PyList_CheckExact(seq), UNPACK_SEQUENCE);
DEOPT_IF(PyList_GET_SIZE(seq) != oparg, UNPACK_SEQUENCE);
STAT_INC(UNPACK_SEQUENCE, hit);
@@ -1355,7 +1495,7 @@
for (int i = oparg; --i >= 0; ) {
*values++ = Py_NewRef(items[i]);
}
- #line 1359 "Python/generated_cases.c.h"
+ #line 1499 "Python/generated_cases.c.h"
Py_DECREF(seq);
STACK_SHRINK(1);
STACK_GROW(oparg);
@@ -1365,15 +1505,15 @@
TARGET(UNPACK_EX) {
PyObject *seq = stack_pointer[-1];
- #line 980 "Python/bytecodes.c"
+ #line 1090 "Python/bytecodes.c"
int totalargs = 1 + (oparg & 0xFF) + (oparg >> 8);
PyObject **top = stack_pointer + totalargs - 1;
int res = unpack_iterable(tstate, seq, oparg & 0xFF, oparg >> 8, top);
- #line 1373 "Python/generated_cases.c.h"
+ #line 1513 "Python/generated_cases.c.h"
Py_DECREF(seq);
- #line 984 "Python/bytecodes.c"
+ #line 1094 "Python/bytecodes.c"
if (res == 0) goto pop_1_error;
- #line 1377 "Python/generated_cases.c.h"
+ #line 1517 "Python/generated_cases.c.h"
STACK_GROW((oparg & 0xFF) + (oparg >> 8));
DISPATCH();
}
@@ -1384,10 +1524,9 @@
PyObject *owner = stack_pointer[-1];
PyObject *v = stack_pointer[-2];
uint16_t counter = read_u16(&next_instr[0].cache);
- #line 995 "Python/bytecodes.c"
+ #line 1105 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
if (ADAPTIVE_COUNTER_IS_ZERO(counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
next_instr--;
_Py_Specialize_StoreAttr(owner, next_instr, name);
@@ -1401,12 +1540,12 @@
#endif /* ENABLE_SPECIALIZATION */
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
int err = PyObject_SetAttr(owner, name, v);
- #line 1405 "Python/generated_cases.c.h"
+ #line 1544 "Python/generated_cases.c.h"
Py_DECREF(v);
Py_DECREF(owner);
- #line 1012 "Python/bytecodes.c"
+ #line 1121 "Python/bytecodes.c"
if (err) goto pop_2_error;
- #line 1410 "Python/generated_cases.c.h"
+ #line 1549 "Python/generated_cases.c.h"
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -1414,34 +1553,34 @@
TARGET(DELETE_ATTR) {
PyObject *owner = stack_pointer[-1];
- #line 1016 "Python/bytecodes.c"
+ #line 1125 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
int err = PyObject_SetAttr(owner, name, (PyObject *)NULL);
- #line 1421 "Python/generated_cases.c.h"
+ #line 1560 "Python/generated_cases.c.h"
Py_DECREF(owner);
- #line 1019 "Python/bytecodes.c"
+ #line 1128 "Python/bytecodes.c"
if (err) goto pop_1_error;
- #line 1425 "Python/generated_cases.c.h"
+ #line 1564 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(STORE_GLOBAL) {
PyObject *v = stack_pointer[-1];
- #line 1023 "Python/bytecodes.c"
+ #line 1132 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
int err = PyDict_SetItem(GLOBALS(), name, v);
- #line 1435 "Python/generated_cases.c.h"
+ #line 1574 "Python/generated_cases.c.h"
Py_DECREF(v);
- #line 1026 "Python/bytecodes.c"
+ #line 1135 "Python/bytecodes.c"
if (err) goto pop_1_error;
- #line 1439 "Python/generated_cases.c.h"
+ #line 1578 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(DELETE_GLOBAL) {
- #line 1030 "Python/bytecodes.c"
+ #line 1139 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
int err;
err = PyDict_DelItem(GLOBALS(), name);
@@ -1453,13 +1592,13 @@
}
goto error;
}
- #line 1457 "Python/generated_cases.c.h"
+ #line 1596 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(LOAD_NAME) {
PyObject *v;
- #line 1044 "Python/bytecodes.c"
+ #line 1153 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
PyObject *locals = LOCALS();
if (locals == NULL) {
@@ -1518,7 +1657,7 @@
}
}
}
- #line 1522 "Python/generated_cases.c.h"
+ #line 1661 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = v;
DISPATCH();
@@ -1529,11 +1668,10 @@
static_assert(INLINE_CACHE_ENTRIES_LOAD_GLOBAL == 4, "incorrect cache size");
PyObject *null = NULL;
PyObject *v;
- #line 1111 "Python/bytecodes.c"
+ #line 1220 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyLoadGlobalCache *cache = (_PyLoadGlobalCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1);
next_instr--;
_Py_Specialize_LoadGlobal(GLOBALS(), BUILTINS(), next_instr, name);
@@ -1582,7 +1720,7 @@
}
}
null = NULL;
- #line 1586 "Python/generated_cases.c.h"
+ #line 1724 "Python/generated_cases.c.h"
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = v;
@@ -1596,8 +1734,7 @@
PyObject *res;
uint16_t index = read_u16(&next_instr[1].cache);
uint16_t version = read_u16(&next_instr[2].cache);
- #line 1166 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1274 "Python/bytecodes.c"
DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
PyDictObject *dict = (PyDictObject *)GLOBALS();
DEOPT_IF(dict->ma_keys->dk_version != version, LOAD_GLOBAL);
@@ -1608,7 +1745,7 @@
Py_INCREF(res);
STAT_INC(LOAD_GLOBAL, hit);
null = NULL;
- #line 1612 "Python/generated_cases.c.h"
+ #line 1749 "Python/generated_cases.c.h"
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -1623,12 +1760,12 @@
uint16_t index = read_u16(&next_instr[1].cache);
uint16_t mod_version = read_u16(&next_instr[2].cache);
uint16_t bltn_version = read_u16(&next_instr[3].cache);
- #line 1180 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1287 "Python/bytecodes.c"
DEOPT_IF(!PyDict_CheckExact(GLOBALS()), LOAD_GLOBAL);
DEOPT_IF(!PyDict_CheckExact(BUILTINS()), LOAD_GLOBAL);
PyDictObject *mdict = (PyDictObject *)GLOBALS();
PyDictObject *bdict = (PyDictObject *)BUILTINS();
+ assert(opcode == LOAD_GLOBAL_BUILTIN);
DEOPT_IF(mdict->ma_keys->dk_version != mod_version, LOAD_GLOBAL);
DEOPT_IF(bdict->ma_keys->dk_version != bltn_version, LOAD_GLOBAL);
assert(DK_IS_UNICODE(bdict->ma_keys));
@@ -1638,7 +1775,7 @@
Py_INCREF(res);
STAT_INC(LOAD_GLOBAL, hit);
null = NULL;
- #line 1642 "Python/generated_cases.c.h"
+ #line 1779 "Python/generated_cases.c.h"
STACK_GROW(1);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -1648,16 +1785,16 @@
}
TARGET(DELETE_FAST) {
- #line 1197 "Python/bytecodes.c"
+ #line 1304 "Python/bytecodes.c"
PyObject *v = GETLOCAL(oparg);
if (v == NULL) goto unbound_local_error;
SETLOCAL(oparg, NULL);
- #line 1656 "Python/generated_cases.c.h"
+ #line 1793 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(MAKE_CELL) {
- #line 1203 "Python/bytecodes.c"
+ #line 1310 "Python/bytecodes.c"
// "initial" is probably NULL but not if it's an arg (or set
// via PyFrame_LocalsToFast() before MAKE_CELL has run).
PyObject *initial = GETLOCAL(oparg);
@@ -1666,12 +1803,12 @@
goto resume_with_error;
}
SETLOCAL(oparg, cell);
- #line 1670 "Python/generated_cases.c.h"
+ #line 1807 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(DELETE_DEREF) {
- #line 1214 "Python/bytecodes.c"
+ #line 1321 "Python/bytecodes.c"
PyObject *cell = GETLOCAL(oparg);
PyObject *oldobj = PyCell_GET(cell);
// Can't use ERROR_IF here.
@@ -1682,13 +1819,13 @@
}
PyCell_SET(cell, NULL);
Py_DECREF(oldobj);
- #line 1686 "Python/generated_cases.c.h"
+ #line 1823 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(LOAD_CLASSDEREF) {
PyObject *value;
- #line 1227 "Python/bytecodes.c"
+ #line 1334 "Python/bytecodes.c"
PyObject *name, *locals = LOCALS();
assert(locals);
assert(oparg >= 0 && oparg < frame->f_code->co_nlocalsplus);
@@ -1720,7 +1857,7 @@
}
Py_INCREF(value);
}
- #line 1724 "Python/generated_cases.c.h"
+ #line 1861 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -1728,7 +1865,7 @@
TARGET(LOAD_DEREF) {
PyObject *value;
- #line 1261 "Python/bytecodes.c"
+ #line 1368 "Python/bytecodes.c"
PyObject *cell = GETLOCAL(oparg);
value = PyCell_GET(cell);
if (value == NULL) {
@@ -1736,7 +1873,7 @@
if (true) goto error;
}
Py_INCREF(value);
- #line 1740 "Python/generated_cases.c.h"
+ #line 1877 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = value;
DISPATCH();
@@ -1744,18 +1881,18 @@
TARGET(STORE_DEREF) {
PyObject *v = stack_pointer[-1];
- #line 1271 "Python/bytecodes.c"
+ #line 1378 "Python/bytecodes.c"
PyObject *cell = GETLOCAL(oparg);
PyObject *oldobj = PyCell_GET(cell);
PyCell_SET(cell, v);
Py_XDECREF(oldobj);
- #line 1753 "Python/generated_cases.c.h"
+ #line 1890 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(COPY_FREE_VARS) {
- #line 1278 "Python/bytecodes.c"
+ #line 1385 "Python/bytecodes.c"
/* Copy closure variables to free variables */
PyCodeObject *co = frame->f_code;
assert(PyFunction_Check(frame->f_funcobj));
@@ -1766,22 +1903,22 @@
PyObject *o = PyTuple_GET_ITEM(closure, i);
frame->localsplus[offset + i] = Py_NewRef(o);
}
- #line 1770 "Python/generated_cases.c.h"
+ #line 1907 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(BUILD_STRING) {
PyObject **pieces = (stack_pointer - oparg);
PyObject *str;
- #line 1291 "Python/bytecodes.c"
+ #line 1398 "Python/bytecodes.c"
str = _PyUnicode_JoinArray(&_Py_STR(empty), pieces, oparg);
- #line 1779 "Python/generated_cases.c.h"
+ #line 1916 "Python/generated_cases.c.h"
for (int _i = oparg; --_i >= 0;) {
Py_DECREF(pieces[_i]);
}
- #line 1293 "Python/bytecodes.c"
+ #line 1400 "Python/bytecodes.c"
if (str == NULL) { STACK_SHRINK(oparg); goto error; }
- #line 1785 "Python/generated_cases.c.h"
+ #line 1922 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_GROW(1);
stack_pointer[-1] = str;
@@ -1791,10 +1928,10 @@
TARGET(BUILD_TUPLE) {
PyObject **values = (stack_pointer - oparg);
PyObject *tup;
- #line 1297 "Python/bytecodes.c"
+ #line 1404 "Python/bytecodes.c"
tup = _PyTuple_FromArraySteal(values, oparg);
if (tup == NULL) { STACK_SHRINK(oparg); goto error; }
- #line 1798 "Python/generated_cases.c.h"
+ #line 1935 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_GROW(1);
stack_pointer[-1] = tup;
@@ -1804,10 +1941,10 @@
TARGET(BUILD_LIST) {
PyObject **values = (stack_pointer - oparg);
PyObject *list;
- #line 1302 "Python/bytecodes.c"
+ #line 1409 "Python/bytecodes.c"
list = _PyList_FromArraySteal(values, oparg);
if (list == NULL) { STACK_SHRINK(oparg); goto error; }
- #line 1811 "Python/generated_cases.c.h"
+ #line 1948 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_GROW(1);
stack_pointer[-1] = list;
@@ -1817,7 +1954,7 @@
TARGET(LIST_EXTEND) {
PyObject *iterable = stack_pointer[-1];
PyObject *list = stack_pointer[-(2 + (oparg-1))];
- #line 1307 "Python/bytecodes.c"
+ #line 1414 "Python/bytecodes.c"
PyObject *none_val = _PyList_Extend((PyListObject *)list, iterable);
if (none_val == NULL) {
if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError) &&
@@ -1828,13 +1965,13 @@
"Value after * must be an iterable, not %.200s",
Py_TYPE(iterable)->tp_name);
}
- #line 1832 "Python/generated_cases.c.h"
+ #line 1969 "Python/generated_cases.c.h"
Py_DECREF(iterable);
- #line 1318 "Python/bytecodes.c"
+ #line 1425 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
Py_DECREF(none_val);
- #line 1838 "Python/generated_cases.c.h"
+ #line 1975 "Python/generated_cases.c.h"
Py_DECREF(iterable);
STACK_SHRINK(1);
DISPATCH();
@@ -1843,13 +1980,13 @@
TARGET(SET_UPDATE) {
PyObject *iterable = stack_pointer[-1];
PyObject *set = stack_pointer[-(2 + (oparg-1))];
- #line 1325 "Python/bytecodes.c"
+ #line 1432 "Python/bytecodes.c"
int err = _PySet_Update(set, iterable);
- #line 1849 "Python/generated_cases.c.h"
+ #line 1986 "Python/generated_cases.c.h"
Py_DECREF(iterable);
- #line 1327 "Python/bytecodes.c"
+ #line 1434 "Python/bytecodes.c"
if (err < 0) goto pop_1_error;
- #line 1853 "Python/generated_cases.c.h"
+ #line 1990 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
@@ -1857,7 +1994,7 @@
TARGET(BUILD_SET) {
PyObject **values = (stack_pointer - oparg);
PyObject *set;
- #line 1331 "Python/bytecodes.c"
+ #line 1438 "Python/bytecodes.c"
set = PySet_New(NULL);
if (set == NULL)
goto error;
@@ -1872,7 +2009,7 @@
Py_DECREF(set);
if (true) { STACK_SHRINK(oparg); goto error; }
}
- #line 1876 "Python/generated_cases.c.h"
+ #line 2013 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_GROW(1);
stack_pointer[-1] = set;
@@ -1882,7 +2019,7 @@
TARGET(BUILD_MAP) {
PyObject **values = (stack_pointer - oparg*2);
PyObject *map;
- #line 1348 "Python/bytecodes.c"
+ #line 1455 "Python/bytecodes.c"
map = _PyDict_FromItems(
values, 2,
values+1, 2,
@@ -1890,13 +2027,13 @@
if (map == NULL)
goto error;
- #line 1894 "Python/generated_cases.c.h"
+ #line 2031 "Python/generated_cases.c.h"
for (int _i = oparg*2; --_i >= 0;) {
Py_DECREF(values[_i]);
}
- #line 1356 "Python/bytecodes.c"
+ #line 1463 "Python/bytecodes.c"
if (map == NULL) { STACK_SHRINK(oparg*2); goto error; }
- #line 1900 "Python/generated_cases.c.h"
+ #line 2037 "Python/generated_cases.c.h"
STACK_SHRINK(oparg*2);
STACK_GROW(1);
stack_pointer[-1] = map;
@@ -1904,7 +2041,7 @@
}
TARGET(SETUP_ANNOTATIONS) {
- #line 1360 "Python/bytecodes.c"
+ #line 1467 "Python/bytecodes.c"
int err;
PyObject *ann_dict;
if (LOCALS() == NULL) {
@@ -1944,7 +2081,7 @@
Py_DECREF(ann_dict);
}
}
- #line 1948 "Python/generated_cases.c.h"
+ #line 2085 "Python/generated_cases.c.h"
DISPATCH();
}
@@ -1952,7 +2089,7 @@
PyObject *keys = stack_pointer[-1];
PyObject **values = (stack_pointer - (1 + oparg));
PyObject *map;
- #line 1402 "Python/bytecodes.c"
+ #line 1509 "Python/bytecodes.c"
if (!PyTuple_CheckExact(keys) ||
PyTuple_GET_SIZE(keys) != (Py_ssize_t)oparg) {
_PyErr_SetString(tstate, PyExc_SystemError,
@@ -1962,14 +2099,14 @@
map = _PyDict_FromItems(
&PyTuple_GET_ITEM(keys, 0), 1,
values, 1, oparg);
- #line 1966 "Python/generated_cases.c.h"
+ #line 2103 "Python/generated_cases.c.h"
for (int _i = oparg; --_i >= 0;) {
Py_DECREF(values[_i]);
}
Py_DECREF(keys);
- #line 1412 "Python/bytecodes.c"
+ #line 1519 "Python/bytecodes.c"
if (map == NULL) { STACK_SHRINK(oparg); goto pop_1_error; }
- #line 1973 "Python/generated_cases.c.h"
+ #line 2110 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
stack_pointer[-1] = map;
DISPATCH();
@@ -1977,7 +2114,7 @@
TARGET(DICT_UPDATE) {
PyObject *update = stack_pointer[-1];
- #line 1416 "Python/bytecodes.c"
+ #line 1523 "Python/bytecodes.c"
PyObject *dict = PEEK(oparg + 1); // update is still on the stack
if (PyDict_Update(dict, update) < 0) {
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
@@ -1985,12 +2122,12 @@
"'%.200s' object is not a mapping",
Py_TYPE(update)->tp_name);
}
- #line 1989 "Python/generated_cases.c.h"
+ #line 2126 "Python/generated_cases.c.h"
Py_DECREF(update);
- #line 1424 "Python/bytecodes.c"
+ #line 1531 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
- #line 1994 "Python/generated_cases.c.h"
+ #line 2131 "Python/generated_cases.c.h"
Py_DECREF(update);
STACK_SHRINK(1);
DISPATCH();
@@ -1998,17 +2135,17 @@
TARGET(DICT_MERGE) {
PyObject *update = stack_pointer[-1];
- #line 1430 "Python/bytecodes.c"
+ #line 1537 "Python/bytecodes.c"
PyObject *dict = PEEK(oparg + 1); // update is still on the stack
if (_PyDict_MergeEx(dict, update, 2) < 0) {
format_kwargs_error(tstate, PEEK(3 + oparg), update);
- #line 2007 "Python/generated_cases.c.h"
+ #line 2144 "Python/generated_cases.c.h"
Py_DECREF(update);
- #line 1435 "Python/bytecodes.c"
+ #line 1542 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
- #line 2012 "Python/generated_cases.c.h"
+ #line 2149 "Python/generated_cases.c.h"
Py_DECREF(update);
STACK_SHRINK(1);
PREDICT(CALL_FUNCTION_EX);
@@ -2018,29 +2155,100 @@
TARGET(MAP_ADD) {
PyObject *value = stack_pointer[-1];
PyObject *key = stack_pointer[-2];
- #line 1442 "Python/bytecodes.c"
+ #line 1549 "Python/bytecodes.c"
PyObject *dict = PEEK(oparg + 2); // key, value are still on the stack
assert(PyDict_CheckExact(dict));
/* dict[key] = value */
// Do not DECREF INPUTS because the function steals the references
if (_PyDict_SetItem_Take2((PyDictObject *)dict, key, value) != 0) goto pop_2_error;
- #line 2028 "Python/generated_cases.c.h"
+ #line 2165 "Python/generated_cases.c.h"
STACK_SHRINK(2);
PREDICT(JUMP_BACKWARD);
DISPATCH();
}
+ TARGET(LOAD_SUPER_ATTR) {
+ PREDICTED(LOAD_SUPER_ATTR);
+ static_assert(INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR == 9, "incorrect cache size");
+ PyObject *self = stack_pointer[-1];
+ PyObject *class = stack_pointer[-2];
+ PyObject *global_super = stack_pointer[-3];
+ PyObject *res2 = NULL;
+ PyObject *res;
+ #line 1563 "Python/bytecodes.c"
+ PyObject *name = GETITEM(frame->f_code->co_names, oparg >> 2);
+ int load_method = oparg & 1;
+ #if ENABLE_SPECIALIZATION
+ _PySuperAttrCache *cache = (_PySuperAttrCache *)next_instr;
+ if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
+ next_instr--;
+ _Py_Specialize_LoadSuperAttr(global_super, class, self, next_instr, name, load_method);
+ DISPATCH_SAME_OPARG();
+ }
+ STAT_INC(LOAD_SUPER_ATTR, deferred);
+ DECREMENT_ADAPTIVE_COUNTER(cache->counter);
+ #endif /* ENABLE_SPECIALIZATION */
+
+ // we make no attempt to optimize here; specializations should
+ // handle any case whose performance we care about
+ PyObject *stack[] = {class, self};
+ PyObject *super = PyObject_Vectorcall(global_super, stack, oparg & 2, NULL);
+ #line 2197 "Python/generated_cases.c.h"
+ Py_DECREF(global_super);
+ Py_DECREF(class);
+ Py_DECREF(self);
+ #line 1581 "Python/bytecodes.c"
+ if (super == NULL) goto pop_3_error;
+ res = PyObject_GetAttr(super, name);
+ Py_DECREF(super);
+ if (res == NULL) goto pop_3_error;
+ #line 2206 "Python/generated_cases.c.h"
+ STACK_SHRINK(2);
+ STACK_GROW(((oparg & 1) ? 1 : 0));
+ stack_pointer[-1] = res;
+ if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
+ next_instr += 9;
+ DISPATCH();
+ }
+
+ TARGET(LOAD_SUPER_ATTR_METHOD) {
+ PyObject *self = stack_pointer[-1];
+ PyObject *class = stack_pointer[-2];
+ PyObject *global_super = stack_pointer[-3];
+ PyObject *res2;
+ PyObject *res;
+ uint32_t class_version = read_u32(&next_instr[1].cache);
+ uint32_t self_type_version = read_u32(&next_instr[3].cache);
+ PyObject *method = read_obj(&next_instr[5].cache);
+ #line 1588 "Python/bytecodes.c"
+ DEOPT_IF(global_super != (PyObject *)&PySuper_Type, LOAD_SUPER_ATTR);
+ DEOPT_IF(!PyType_Check(class), LOAD_SUPER_ATTR);
+ DEOPT_IF(((PyTypeObject *)class)->tp_version_tag != class_version, LOAD_SUPER_ATTR);
+ PyTypeObject *self_type = Py_TYPE(self);
+ DEOPT_IF(self_type->tp_version_tag != self_type_version, LOAD_SUPER_ATTR);
+ res2 = method;
+ res = self; // transfer ownership
+ Py_INCREF(res2);
+ Py_DECREF(global_super);
+ Py_DECREF(class);
+ #line 2235 "Python/generated_cases.c.h"
+ STACK_SHRINK(1);
+ stack_pointer[-1] = res;
+ stack_pointer[-2] = res2;
+ next_instr += 9;
+ DISPATCH();
+ }
+
TARGET(LOAD_ATTR) {
PREDICTED(LOAD_ATTR);
static_assert(INLINE_CACHE_ENTRIES_LOAD_ATTR == 9, "incorrect cache size");
PyObject *owner = stack_pointer[-1];
PyObject *res2 = NULL;
PyObject *res;
- #line 1465 "Python/bytecodes.c"
+ #line 1615 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyAttrCache *cache = (_PyAttrCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
PyObject *name = GETITEM(frame->f_code->co_names, oparg>>1);
next_instr--;
_Py_Specialize_LoadAttr(owner, next_instr, name);
@@ -2071,9 +2279,9 @@
NULL | meth | arg1 | ... | argN
*/
- #line 2075 "Python/generated_cases.c.h"
+ #line 2283 "Python/generated_cases.c.h"
Py_DECREF(owner);
- #line 1500 "Python/bytecodes.c"
+ #line 1649 "Python/bytecodes.c"
if (meth == NULL) goto pop_1_error;
res2 = NULL;
res = meth;
@@ -2082,12 +2290,12 @@
else {
/* Classic, pushes one value. */
res = PyObject_GetAttr(owner, name);
- #line 2086 "Python/generated_cases.c.h"
+ #line 2294 "Python/generated_cases.c.h"
Py_DECREF(owner);
- #line 1509 "Python/bytecodes.c"
+ #line 1658 "Python/bytecodes.c"
if (res == NULL) goto pop_1_error;
}
- #line 2091 "Python/generated_cases.c.h"
+ #line 2299 "Python/generated_cases.c.h"
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -2101,8 +2309,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1514 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1663 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2115,7 +2322,7 @@
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
res2 = NULL;
- #line 2119 "Python/generated_cases.c.h"
+ #line 2326 "Python/generated_cases.c.h"
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -2130,8 +2337,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1531 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1679 "Python/bytecodes.c"
DEOPT_IF(!PyModule_CheckExact(owner), LOAD_ATTR);
PyDictObject *dict = (PyDictObject *)((PyModuleObject *)owner)->md_dict;
assert(dict != NULL);
@@ -2144,7 +2350,7 @@
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
res2 = NULL;
- #line 2148 "Python/generated_cases.c.h"
+ #line 2354 "Python/generated_cases.c.h"
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -2159,8 +2365,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1548 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1695 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2187,7 +2392,7 @@
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
res2 = NULL;
- #line 2191 "Python/generated_cases.c.h"
+ #line 2396 "Python/generated_cases.c.h"
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -2202,8 +2407,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1579 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1725 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, LOAD_ATTR);
@@ -2213,7 +2417,7 @@
STAT_INC(LOAD_ATTR, hit);
Py_INCREF(res);
res2 = NULL;
- #line 2217 "Python/generated_cases.c.h"
+ #line 2421 "Python/generated_cases.c.h"
Py_DECREF(owner);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -2228,8 +2432,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
- #line 1593 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1738 "Python/bytecodes.c"
DEOPT_IF(!PyType_Check(cls), LOAD_ATTR);
DEOPT_IF(((PyTypeObject *)cls)->tp_version_tag != type_version,
@@ -2241,7 +2444,7 @@
res = descr;
assert(res != NULL);
Py_INCREF(res);
- #line 2245 "Python/generated_cases.c.h"
+ #line 2448 "Python/generated_cases.c.h"
Py_DECREF(cls);
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
@@ -2255,8 +2458,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);
- #line 1609 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1753 "Python/bytecodes.c"
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
@@ -2278,8 +2480,9 @@
STACK_SHRINK(shrink_stack);
new_frame->localsplus[0] = owner;
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- #line 2283 "Python/generated_cases.c.h"
+ #line 2486 "Python/generated_cases.c.h"
}
TARGET(LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN) {
@@ -2287,8 +2490,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);
- #line 1635 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1779 "Python/bytecodes.c"
DEOPT_IF(tstate->interp->eval_frame, LOAD_ATTR);
PyTypeObject *cls = Py_TYPE(owner);
DEOPT_IF(cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -2312,8 +2514,9 @@
new_frame->localsplus[0] = owner;
new_frame->localsplus[1] = Py_NewRef(name);
JUMPBY(INLINE_CACHE_ENTRIES_LOAD_ATTR);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- #line 2317 "Python/generated_cases.c.h"
+ #line 2520 "Python/generated_cases.c.h"
}
TARGET(STORE_ATTR_INSTANCE_VALUE) {
@@ -2321,8 +2524,7 @@
PyObject *value = stack_pointer[-2];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1663 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1807 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2340,7 +2542,7 @@
Py_DECREF(old_value);
}
Py_DECREF(owner);
- #line 2344 "Python/generated_cases.c.h"
+ #line 2546 "Python/generated_cases.c.h"
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -2351,8 +2553,7 @@
PyObject *value = stack_pointer[-2];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t hint = read_u16(&next_instr[3].cache);
- #line 1684 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1827 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2391,7 +2592,7 @@
/* PEP 509 */
dict->ma_version_tag = new_version;
Py_DECREF(owner);
- #line 2395 "Python/generated_cases.c.h"
+ #line 2596 "Python/generated_cases.c.h"
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -2402,8 +2603,7 @@
PyObject *value = stack_pointer[-2];
uint32_t type_version = read_u32(&next_instr[1].cache);
uint16_t index = read_u16(&next_instr[3].cache);
- #line 1726 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1868 "Python/bytecodes.c"
PyTypeObject *tp = Py_TYPE(owner);
assert(type_version != 0);
DEOPT_IF(tp->tp_version_tag != type_version, STORE_ATTR);
@@ -2413,7 +2613,7 @@
*(PyObject **)addr = value;
Py_XDECREF(old_value);
Py_DECREF(owner);
- #line 2417 "Python/generated_cases.c.h"
+ #line 2617 "Python/generated_cases.c.h"
STACK_SHRINK(2);
next_instr += 4;
DISPATCH();
@@ -2425,11 +2625,10 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res;
- #line 1746 "Python/bytecodes.c"
+ #line 1887 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyCompareOpCache *cache = (_PyCompareOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_CompareOp(left, right, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -2439,12 +2638,12 @@
#endif /* ENABLE_SPECIALIZATION */
assert((oparg >> 4) <= Py_GE);
res = PyObject_RichCompare(left, right, oparg>>4);
- #line 2443 "Python/generated_cases.c.h"
+ #line 2642 "Python/generated_cases.c.h"
Py_DECREF(left);
Py_DECREF(right);
- #line 1760 "Python/bytecodes.c"
+ #line 1900 "Python/bytecodes.c"
if (res == NULL) goto pop_2_error;
- #line 2448 "Python/generated_cases.c.h"
+ #line 2647 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -2455,8 +2654,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res;
- #line 1764 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1904 "Python/bytecodes.c"
DEOPT_IF(!PyFloat_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyFloat_CheckExact(right), COMPARE_OP);
STAT_INC(COMPARE_OP, hit);
@@ -2468,7 +2666,7 @@
_Py_DECREF_SPECIALIZED(right, _PyFloat_ExactDealloc);
res = (sign_ish & oparg) ? Py_True : Py_False;
Py_INCREF(res);
- #line 2472 "Python/generated_cases.c.h"
+ #line 2670 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -2479,8 +2677,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res;
- #line 1780 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1919 "Python/bytecodes.c"
DEOPT_IF(!PyLong_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyLong_CheckExact(right), COMPARE_OP);
DEOPT_IF(!_PyLong_IsCompact((PyLongObject *)left), COMPARE_OP);
@@ -2496,7 +2693,7 @@
_Py_DECREF_SPECIALIZED(right, (destructor)PyObject_Free);
res = (sign_ish & oparg) ? Py_True : Py_False;
Py_INCREF(res);
- #line 2500 "Python/generated_cases.c.h"
+ #line 2697 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -2507,8 +2704,7 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *res;
- #line 1800 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 1938 "Python/bytecodes.c"
DEOPT_IF(!PyUnicode_CheckExact(left), COMPARE_OP);
DEOPT_IF(!PyUnicode_CheckExact(right), COMPARE_OP);
STAT_INC(COMPARE_OP, hit);
@@ -2521,7 +2717,7 @@
assert(COMPARISON_NOT_EQUALS + 1 == COMPARISON_EQUALS);
res = ((COMPARISON_NOT_EQUALS + eq) & oparg) ? Py_True : Py_False;
Py_INCREF(res);
- #line 2525 "Python/generated_cases.c.h"
+ #line 2721 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -2532,14 +2728,14 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *b;
- #line 1816 "Python/bytecodes.c"
+ #line 1953 "Python/bytecodes.c"
int res = Py_Is(left, right) ^ oparg;
- #line 2538 "Python/generated_cases.c.h"
+ #line 2734 "Python/generated_cases.c.h"
Py_DECREF(left);
Py_DECREF(right);
- #line 1818 "Python/bytecodes.c"
+ #line 1955 "Python/bytecodes.c"
b = Py_NewRef(res ? Py_True : Py_False);
- #line 2543 "Python/generated_cases.c.h"
+ #line 2739 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = b;
DISPATCH();
@@ -2549,15 +2745,15 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *b;
- #line 1822 "Python/bytecodes.c"
+ #line 1959 "Python/bytecodes.c"
int res = PySequence_Contains(right, left);
- #line 2555 "Python/generated_cases.c.h"
+ #line 2751 "Python/generated_cases.c.h"
Py_DECREF(left);
Py_DECREF(right);
- #line 1824 "Python/bytecodes.c"
+ #line 1961 "Python/bytecodes.c"
if (res < 0) goto pop_2_error;
b = Py_NewRef((res^oparg) ? Py_True : Py_False);
- #line 2561 "Python/generated_cases.c.h"
+ #line 2757 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = b;
DISPATCH();
@@ -2568,12 +2764,12 @@
PyObject *exc_value = stack_pointer[-2];
PyObject *rest;
PyObject *match;
- #line 1829 "Python/bytecodes.c"
+ #line 1966 "Python/bytecodes.c"
if (check_except_star_type_valid(tstate, match_type) < 0) {
- #line 2574 "Python/generated_cases.c.h"
+ #line 2770 "Python/generated_cases.c.h"
Py_DECREF(exc_value);
Py_DECREF(match_type);
- #line 1831 "Python/bytecodes.c"
+ #line 1968 "Python/bytecodes.c"
if (true) goto pop_2_error;
}
@@ -2581,10 +2777,10 @@
rest = NULL;
int res = exception_group_match(exc_value, match_type,
&match, &rest);
- #line 2585 "Python/generated_cases.c.h"
+ #line 2781 "Python/generated_cases.c.h"
Py_DECREF(exc_value);
Py_DECREF(match_type);
- #line 1839 "Python/bytecodes.c"
+ #line 1976 "Python/bytecodes.c"
if (res < 0) goto pop_2_error;
assert((match == NULL) == (rest == NULL));
@@ -2593,7 +2789,7 @@
if (!Py_IsNone(match)) {
PyErr_SetHandledException(match);
}
- #line 2597 "Python/generated_cases.c.h"
+ #line 2793 "Python/generated_cases.c.h"
stack_pointer[-1] = match;
stack_pointer[-2] = rest;
DISPATCH();
@@ -2603,21 +2799,21 @@
PyObject *right = stack_pointer[-1];
PyObject *left = stack_pointer[-2];
PyObject *b;
- #line 1850 "Python/bytecodes.c"
+ #line 1987 "Python/bytecodes.c"
assert(PyExceptionInstance_Check(left));
if (check_except_type_valid(tstate, right) < 0) {
- #line 2610 "Python/generated_cases.c.h"
+ #line 2806 "Python/generated_cases.c.h"
Py_DECREF(right);
- #line 1853 "Python/bytecodes.c"
+ #line 1990 "Python/bytecodes.c"
if (true) goto pop_1_error;
}
int res = PyErr_GivenExceptionMatches(left, right);
- #line 2617 "Python/generated_cases.c.h"
+ #line 2813 "Python/generated_cases.c.h"
Py_DECREF(right);
- #line 1858 "Python/bytecodes.c"
+ #line 1995 "Python/bytecodes.c"
b = Py_NewRef(res ? Py_True : Py_False);
- #line 2621 "Python/generated_cases.c.h"
+ #line 2817 "Python/generated_cases.c.h"
stack_pointer[-1] = b;
DISPATCH();
}
@@ -2626,15 +2822,15 @@
PyObject *fromlist = stack_pointer[-1];
PyObject *level = stack_pointer[-2];
PyObject *res;
- #line 1862 "Python/bytecodes.c"
+ #line 1999 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
res = import_name(tstate, frame, name, fromlist, level);
- #line 2633 "Python/generated_cases.c.h"
+ #line 2829 "Python/generated_cases.c.h"
Py_DECREF(level);
Py_DECREF(fromlist);
- #line 1865 "Python/bytecodes.c"
+ #line 2002 "Python/bytecodes.c"
if (res == NULL) goto pop_2_error;
- #line 2638 "Python/generated_cases.c.h"
+ #line 2834 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
DISPATCH();
@@ -2643,29 +2839,29 @@
TARGET(IMPORT_FROM) {
PyObject *from = stack_pointer[-1];
PyObject *res;
- #line 1869 "Python/bytecodes.c"
+ #line 2006 "Python/bytecodes.c"
PyObject *name = GETITEM(frame->f_code->co_names, oparg);
res = import_from(tstate, from, name);
if (res == NULL) goto error;
- #line 2651 "Python/generated_cases.c.h"
+ #line 2847 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
DISPATCH();
}
TARGET(JUMP_FORWARD) {
- #line 1875 "Python/bytecodes.c"
+ #line 2012 "Python/bytecodes.c"
JUMPBY(oparg);
- #line 2660 "Python/generated_cases.c.h"
+ #line 2856 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(JUMP_BACKWARD) {
PREDICTED(JUMP_BACKWARD);
- #line 1879 "Python/bytecodes.c"
+ #line 2016 "Python/bytecodes.c"
assert(oparg < INSTR_OFFSET());
JUMPBY(-oparg);
- #line 2669 "Python/generated_cases.c.h"
+ #line 2865 "Python/generated_cases.c.h"
CHECK_EVAL_BREAKER();
DISPATCH();
}
@@ -2673,7 +2869,7 @@
TARGET(POP_JUMP_IF_FALSE) {
PREDICTED(POP_JUMP_IF_FALSE);
PyObject *cond = stack_pointer[-1];
- #line 1885 "Python/bytecodes.c"
+ #line 2022 "Python/bytecodes.c"
if (Py_IsTrue(cond)) {
_Py_DECREF_NO_DEALLOC(cond);
}
@@ -2683,9 +2879,9 @@
}
else {
int err = PyObject_IsTrue(cond);
- #line 2687 "Python/generated_cases.c.h"
+ #line 2883 "Python/generated_cases.c.h"
Py_DECREF(cond);
- #line 1895 "Python/bytecodes.c"
+ #line 2032 "Python/bytecodes.c"
if (err == 0) {
JUMPBY(oparg);
}
@@ -2693,14 +2889,14 @@
if (err < 0) goto pop_1_error;
}
}
- #line 2697 "Python/generated_cases.c.h"
+ #line 2893 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(POP_JUMP_IF_TRUE) {
PyObject *cond = stack_pointer[-1];
- #line 1905 "Python/bytecodes.c"
+ #line 2042 "Python/bytecodes.c"
if (Py_IsFalse(cond)) {
_Py_DECREF_NO_DEALLOC(cond);
}
@@ -2710,9 +2906,9 @@
}
else {
int err = PyObject_IsTrue(cond);
- #line 2714 "Python/generated_cases.c.h"
+ #line 2910 "Python/generated_cases.c.h"
Py_DECREF(cond);
- #line 1915 "Python/bytecodes.c"
+ #line 2052 "Python/bytecodes.c"
if (err > 0) {
JUMPBY(oparg);
}
@@ -2720,67 +2916,67 @@
if (err < 0) goto pop_1_error;
}
}
- #line 2724 "Python/generated_cases.c.h"
+ #line 2920 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(POP_JUMP_IF_NOT_NONE) {
PyObject *value = stack_pointer[-1];
- #line 1925 "Python/bytecodes.c"
+ #line 2062 "Python/bytecodes.c"
if (!Py_IsNone(value)) {
- #line 2733 "Python/generated_cases.c.h"
+ #line 2929 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 1927 "Python/bytecodes.c"
+ #line 2064 "Python/bytecodes.c"
JUMPBY(oparg);
}
else {
_Py_DECREF_NO_DEALLOC(value);
}
- #line 2741 "Python/generated_cases.c.h"
+ #line 2937 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(POP_JUMP_IF_NONE) {
PyObject *value = stack_pointer[-1];
- #line 1935 "Python/bytecodes.c"
+ #line 2072 "Python/bytecodes.c"
if (Py_IsNone(value)) {
_Py_DECREF_NO_DEALLOC(value);
JUMPBY(oparg);
}
else {
- #line 2754 "Python/generated_cases.c.h"
+ #line 2950 "Python/generated_cases.c.h"
Py_DECREF(value);
- #line 1941 "Python/bytecodes.c"
+ #line 2078 "Python/bytecodes.c"
}
- #line 2758 "Python/generated_cases.c.h"
+ #line 2954 "Python/generated_cases.c.h"
STACK_SHRINK(1);
DISPATCH();
}
TARGET(JUMP_BACKWARD_NO_INTERRUPT) {
- #line 1945 "Python/bytecodes.c"
+ #line 2082 "Python/bytecodes.c"
/* This bytecode is used in the `yield from` or `await` loop.
* If there is an interrupt, we want it handled in the innermost
* generator or coroutine, so we deliberately do not check it here.
* (see bpo-30039).
*/
JUMPBY(-oparg);
- #line 2771 "Python/generated_cases.c.h"
+ #line 2967 "Python/generated_cases.c.h"
DISPATCH();
}
TARGET(GET_LEN) {
PyObject *obj = stack_pointer[-1];
PyObject *len_o;
- #line 1954 "Python/bytecodes.c"
+ #line 2091 "Python/bytecodes.c"
// PUSH(len(TOS))
Py_ssize_t len_i = PyObject_Length(obj);
if (len_i < 0) goto error;
len_o = PyLong_FromSsize_t(len_i);
if (len_o == NULL) goto error;
- #line 2784 "Python/generated_cases.c.h"
+ #line 2980 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = len_o;
DISPATCH();
@@ -2791,16 +2987,16 @@
PyObject *type = stack_pointer[-2];
PyObject *subject = stack_pointer[-3];
PyObject *attrs;
- #line 1962 "Python/bytecodes.c"
+ #line 2099 "Python/bytecodes.c"
// Pop TOS and TOS1. Set TOS to a tuple of attributes on success, or
// None on failure.
assert(PyTuple_CheckExact(names));
attrs = match_class(tstate, subject, type, oparg, names);
- #line 2800 "Python/generated_cases.c.h"
+ #line 2996 "Python/generated_cases.c.h"
Py_DECREF(subject);
Py_DECREF(type);
Py_DECREF(names);
- #line 1967 "Python/bytecodes.c"
+ #line 2104 "Python/bytecodes.c"
if (attrs) {
assert(PyTuple_CheckExact(attrs)); // Success!
}
@@ -2808,7 +3004,7 @@
if (_PyErr_Occurred(tstate)) goto pop_3_error;
attrs = Py_NewRef(Py_None); // Failure!
}
- #line 2812 "Python/generated_cases.c.h"
+ #line 3008 "Python/generated_cases.c.h"
STACK_SHRINK(2);
stack_pointer[-1] = attrs;
DISPATCH();
@@ -2817,10 +3013,10 @@
TARGET(MATCH_MAPPING) {
PyObject *subject = stack_pointer[-1];
PyObject *res;
- #line 1977 "Python/bytecodes.c"
+ #line 2114 "Python/bytecodes.c"
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_MAPPING;
res = Py_NewRef(match ? Py_True : Py_False);
- #line 2824 "Python/generated_cases.c.h"
+ #line 3020 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
PREDICT(POP_JUMP_IF_FALSE);
@@ -2830,10 +3026,10 @@
TARGET(MATCH_SEQUENCE) {
PyObject *subject = stack_pointer[-1];
PyObject *res;
- #line 1983 "Python/bytecodes.c"
+ #line 2120 "Python/bytecodes.c"
int match = Py_TYPE(subject)->tp_flags & Py_TPFLAGS_SEQUENCE;
res = Py_NewRef(match ? Py_True : Py_False);
- #line 2837 "Python/generated_cases.c.h"
+ #line 3033 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
PREDICT(POP_JUMP_IF_FALSE);
@@ -2844,11 +3040,11 @@
PyObject *keys = stack_pointer[-1];
PyObject *subject = stack_pointer[-2];
PyObject *values_or_none;
- #line 1989 "Python/bytecodes.c"
+ #line 2126 "Python/bytecodes.c"
// On successful match, PUSH(values). Otherwise, PUSH(None).
values_or_none = match_keys(tstate, subject, keys);
if (values_or_none == NULL) goto error;
- #line 2852 "Python/generated_cases.c.h"
+ #line 3048 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = values_or_none;
DISPATCH();
@@ -2857,14 +3053,14 @@
TARGET(GET_ITER) {
PyObject *iterable = stack_pointer[-1];
PyObject *iter;
- #line 1995 "Python/bytecodes.c"
+ #line 2132 "Python/bytecodes.c"
/* before: [obj]; after [getiter(obj)] */
iter = PyObject_GetIter(iterable);
- #line 2864 "Python/generated_cases.c.h"
+ #line 3060 "Python/generated_cases.c.h"
Py_DECREF(iterable);
- #line 1998 "Python/bytecodes.c"
+ #line 2135 "Python/bytecodes.c"
if (iter == NULL) goto pop_1_error;
- #line 2868 "Python/generated_cases.c.h"
+ #line 3064 "Python/generated_cases.c.h"
stack_pointer[-1] = iter;
DISPATCH();
}
@@ -2872,7 +3068,7 @@
TARGET(GET_YIELD_FROM_ITER) {
PyObject *iterable = stack_pointer[-1];
PyObject *iter;
- #line 2002 "Python/bytecodes.c"
+ #line 2139 "Python/bytecodes.c"
/* before: [obj]; after [getiter(obj)] */
if (PyCoro_CheckExact(iterable)) {
/* `iterable` is a coroutine */
@@ -2895,11 +3091,11 @@
if (iter == NULL) {
goto error;
}
- #line 2899 "Python/generated_cases.c.h"
+ #line 3095 "Python/generated_cases.c.h"
Py_DECREF(iterable);
- #line 2025 "Python/bytecodes.c"
+ #line 2162 "Python/bytecodes.c"
}
- #line 2903 "Python/generated_cases.c.h"
+ #line 3099 "Python/generated_cases.c.h"
stack_pointer[-1] = iter;
PREDICT(LOAD_CONST);
DISPATCH();
@@ -2910,11 +3106,10 @@
static_assert(INLINE_CACHE_ENTRIES_FOR_ITER == 1, "incorrect cache size");
PyObject *iter = stack_pointer[-1];
PyObject *next;
- #line 2044 "Python/bytecodes.c"
+ #line 2181 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyForIterCache *cache = (_PyForIterCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_ForIter(iter, next_instr, oparg);
DISPATCH_SAME_OPARG();
@@ -2929,13 +3124,12 @@
if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
goto error;
}
- else if (tstate->c_tracefunc != NULL) {
- call_exc_trace(tstate->c_tracefunc, tstate->c_traceobj, tstate, frame);
- }
+ monitor_raise(tstate, frame, next_instr-1);
_PyErr_Clear(tstate);
}
/* iterator ended normally */
- assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR);
+ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR ||
+ next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR);
Py_DECREF(iter);
STACK_SHRINK(1);
/* Jump forward oparg, then skip following END_FOR instruction */
@@ -2943,18 +3137,48 @@
DISPATCH();
}
// Common case: no jump, leave it to the code generator
- #line 2947 "Python/generated_cases.c.h"
+ #line 3141 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = next;
next_instr += 1;
DISPATCH();
}
+ TARGET(INSTRUMENTED_FOR_ITER) {
+ #line 2214 "Python/bytecodes.c"
+ _Py_CODEUNIT *here = next_instr-1;
+ _Py_CODEUNIT *target;
+ PyObject *iter = TOP();
+ PyObject *next = (*Py_TYPE(iter)->tp_iternext)(iter);
+ if (next != NULL) {
+ PUSH(next);
+ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER;
+ }
+ else {
+ if (_PyErr_Occurred(tstate)) {
+ if (!_PyErr_ExceptionMatches(tstate, PyExc_StopIteration)) {
+ goto error;
+ }
+ monitor_raise(tstate, frame, here);
+ _PyErr_Clear(tstate);
+ }
+ /* iterator ended normally */
+ assert(next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == END_FOR ||
+ next_instr[INLINE_CACHE_ENTRIES_FOR_ITER + oparg].op.code == INSTRUMENTED_END_FOR);
+ STACK_SHRINK(1);
+ Py_DECREF(iter);
+ /* Skip END_FOR */
+ target = next_instr + INLINE_CACHE_ENTRIES_FOR_ITER + oparg + 1;
+ }
+ INSTRUMENTED_JUMP(here, target, PY_MONITORING_EVENT_BRANCH);
+ #line 3175 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
TARGET(FOR_ITER_LIST) {
PyObject *iter = stack_pointer[-1];
PyObject *next;
- #line 2079 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2242 "Python/bytecodes.c"
DEOPT_IF(Py_TYPE(iter) != &PyListIter_Type, FOR_ITER);
_PyListIterObject *it = (_PyListIterObject *)iter;
STAT_INC(FOR_ITER, hit);
@@ -2974,7 +3198,7 @@
DISPATCH();
end_for_iter_list:
// Common case: no jump, leave it to the code generator
- #line 2978 "Python/generated_cases.c.h"
+ #line 3202 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = next;
next_instr += 1;
@@ -2984,8 +3208,7 @@
TARGET(FOR_ITER_TUPLE) {
PyObject *iter = stack_pointer[-1];
PyObject *next;
- #line 2102 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2264 "Python/bytecodes.c"
_PyTupleIterObject *it = (_PyTupleIterObject *)iter;
DEOPT_IF(Py_TYPE(it) != &PyTupleIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
@@ -3005,7 +3228,7 @@
DISPATCH();
end_for_iter_tuple:
// Common case: no jump, leave it to the code generator
- #line 3009 "Python/generated_cases.c.h"
+ #line 3232 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = next;
next_instr += 1;
@@ -3015,8 +3238,7 @@
TARGET(FOR_ITER_RANGE) {
PyObject *iter = stack_pointer[-1];
PyObject *next;
- #line 2125 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2286 "Python/bytecodes.c"
_PyRangeIterObject *r = (_PyRangeIterObject *)iter;
DEOPT_IF(Py_TYPE(r) != &PyRangeIter_Type, FOR_ITER);
STAT_INC(FOR_ITER, hit);
@@ -3034,7 +3256,7 @@
if (next == NULL) {
goto error;
}
- #line 3038 "Python/generated_cases.c.h"
+ #line 3260 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = next;
next_instr += 1;
@@ -3043,29 +3265,29 @@
TARGET(FOR_ITER_GEN) {
PyObject *iter = stack_pointer[-1];
- #line 2146 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2306 "Python/bytecodes.c"
PyGenObject *gen = (PyGenObject *)iter;
DEOPT_IF(Py_TYPE(gen) != &PyGen_Type, FOR_ITER);
DEOPT_IF(gen->gi_frame_state >= FRAME_EXECUTING, FOR_ITER);
STAT_INC(FOR_ITER, hit);
_PyInterpreterFrame *gen_frame = (_PyInterpreterFrame *)gen->gi_iframe;
- frame->yield_offset = oparg;
+ frame->return_offset = oparg;
_PyFrame_StackPush(gen_frame, Py_NewRef(Py_None));
gen->gi_frame_state = FRAME_EXECUTING;
gen->gi_exc_state.previous_item = tstate->exc_info;
tstate->exc_info = &gen->gi_exc_state;
- JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER + oparg);
- assert(next_instr->op.code == END_FOR);
+ JUMPBY(INLINE_CACHE_ENTRIES_FOR_ITER);
+ assert(next_instr[oparg].op.code == END_FOR ||
+ next_instr[oparg].op.code == INSTRUMENTED_END_FOR);
DISPATCH_INLINED(gen_frame);
- #line 3062 "Python/generated_cases.c.h"
+ #line 3284 "Python/generated_cases.c.h"
}
TARGET(BEFORE_ASYNC_WITH) {
PyObject *mgr = stack_pointer[-1];
PyObject *exit;
PyObject *res;
- #line 2163 "Python/bytecodes.c"
+ #line 2323 "Python/bytecodes.c"
PyObject *enter = _PyObject_LookupSpecial(mgr, &_Py_ID(__aenter__));
if (enter == NULL) {
if (!_PyErr_Occurred(tstate)) {
@@ -3088,16 +3310,16 @@
Py_DECREF(enter);
goto error;
}
- #line 3092 "Python/generated_cases.c.h"
+ #line 3314 "Python/generated_cases.c.h"
Py_DECREF(mgr);
- #line 2186 "Python/bytecodes.c"
+ #line 2346 "Python/bytecodes.c"
res = _PyObject_CallNoArgs(enter);
Py_DECREF(enter);
if (res == NULL) {
Py_DECREF(exit);
if (true) goto pop_1_error;
}
- #line 3101 "Python/generated_cases.c.h"
+ #line 3323 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
stack_pointer[-2] = exit;
@@ -3109,7 +3331,7 @@
PyObject *mgr = stack_pointer[-1];
PyObject *exit;
PyObject *res;
- #line 2196 "Python/bytecodes.c"
+ #line 2356 "Python/bytecodes.c"
/* pop the context manager, push its __exit__ and the
* value returned from calling its __enter__
*/
@@ -3135,16 +3357,16 @@
Py_DECREF(enter);
goto error;
}
- #line 3139 "Python/generated_cases.c.h"
+ #line 3361 "Python/generated_cases.c.h"
Py_DECREF(mgr);
- #line 2222 "Python/bytecodes.c"
+ #line 2382 "Python/bytecodes.c"
res = _PyObject_CallNoArgs(enter);
Py_DECREF(enter);
if (res == NULL) {
Py_DECREF(exit);
if (true) goto pop_1_error;
}
- #line 3148 "Python/generated_cases.c.h"
+ #line 3370 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
stack_pointer[-2] = exit;
@@ -3156,7 +3378,7 @@
PyObject *lasti = stack_pointer[-3];
PyObject *exit_func = stack_pointer[-4];
PyObject *res;
- #line 2231 "Python/bytecodes.c"
+ #line 2391 "Python/bytecodes.c"
/* At the top of the stack are 4 values:
- val: TOP = exc_info()
- unused: SECOND = previous exception
@@ -3177,7 +3399,7 @@
res = PyObject_Vectorcall(exit_func, stack + 1,
3 | PY_VECTORCALL_ARGUMENTS_OFFSET, NULL);
if (res == NULL) goto error;
- #line 3181 "Python/generated_cases.c.h"
+ #line 3403 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = res;
DISPATCH();
@@ -3186,7 +3408,7 @@
TARGET(PUSH_EXC_INFO) {
PyObject *new_exc = stack_pointer[-1];
PyObject *prev_exc;
- #line 2254 "Python/bytecodes.c"
+ #line 2414 "Python/bytecodes.c"
_PyErr_StackItem *exc_info = tstate->exc_info;
if (exc_info->exc_value != NULL) {
prev_exc = exc_info->exc_value;
@@ -3196,7 +3418,7 @@
}
assert(PyExceptionInstance_Check(new_exc));
exc_info->exc_value = Py_NewRef(new_exc);
- #line 3200 "Python/generated_cases.c.h"
+ #line 3422 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = new_exc;
stack_pointer[-2] = prev_exc;
@@ -3210,9 +3432,8 @@
uint32_t type_version = read_u32(&next_instr[1].cache);
uint32_t keys_version = read_u32(&next_instr[3].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
- #line 2266 "Python/bytecodes.c"
+ #line 2426 "Python/bytecodes.c"
/* Cached method object */
- assert(cframe.use_tracing == 0);
PyTypeObject *self_cls = Py_TYPE(self);
assert(type_version != 0);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
@@ -3228,7 +3449,7 @@
assert(_PyType_HasFeature(Py_TYPE(res2), Py_TPFLAGS_METHOD_DESCRIPTOR));
res = self;
assert(oparg & 1);
- #line 3232 "Python/generated_cases.c.h"
+ #line 3453 "Python/generated_cases.c.h"
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3242,8 +3463,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
- #line 2286 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2445 "Python/bytecodes.c"
PyTypeObject *self_cls = Py_TYPE(self);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
assert(self_cls->tp_dictoffset == 0);
@@ -3253,7 +3473,7 @@
res2 = Py_NewRef(descr);
res = self;
assert(oparg & 1);
- #line 3257 "Python/generated_cases.c.h"
+ #line 3477 "Python/generated_cases.c.h"
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3267,8 +3487,7 @@
PyObject *res;
uint32_t type_version = read_u32(&next_instr[1].cache);
PyObject *descr = read_obj(&next_instr[5].cache);
- #line 2299 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2457 "Python/bytecodes.c"
PyTypeObject *self_cls = Py_TYPE(self);
DEOPT_IF(self_cls->tp_version_tag != type_version, LOAD_ATTR);
Py_ssize_t dictoffset = self_cls->tp_dictoffset;
@@ -3282,7 +3501,7 @@
res2 = Py_NewRef(descr);
res = self;
assert(oparg & 1);
- #line 3286 "Python/generated_cases.c.h"
+ #line 3505 "Python/generated_cases.c.h"
STACK_GROW(((oparg & 1) ? 1 : 0));
stack_pointer[-1] = res;
if (oparg & 1) { stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))] = res2; }
@@ -3291,14 +3510,31 @@
}
TARGET(KW_NAMES) {
- #line 2316 "Python/bytecodes.c"
+ #line 2473 "Python/bytecodes.c"
assert(kwnames == NULL);
assert(oparg < PyTuple_GET_SIZE(frame->f_code->co_consts));
kwnames = GETITEM(frame->f_code->co_consts, oparg);
- #line 3299 "Python/generated_cases.c.h"
+ #line 3518 "Python/generated_cases.c.h"
DISPATCH();
}
+ TARGET(INSTRUMENTED_CALL) {
+ #line 2479 "Python/bytecodes.c"
+ int is_meth = PEEK(oparg+2) != NULL;
+ int total_args = oparg + is_meth;
+ PyObject *function = PEEK(total_args + 1);
+ PyObject *arg = total_args == 0 ?
+ &_PyInstrumentation_MISSING : PEEK(total_args);
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_CALL,
+ frame, next_instr-1, function, arg);
+ if (err) goto error;
+ _PyCallCache *cache = (_PyCallCache *)next_instr;
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ GO_TO_INSTRUCTION(CALL);
+ #line 3536 "Python/generated_cases.c.h"
+ }
+
TARGET(CALL) {
PREDICTED(CALL);
static_assert(INLINE_CACHE_ENTRIES_CALL == 3, "incorrect cache size");
@@ -3306,7 +3542,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2352 "Python/bytecodes.c"
+ #line 2524 "Python/bytecodes.c"
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3317,7 +3553,6 @@
#if ENABLE_SPECIALIZATION
_PyCallCache *cache = (_PyCallCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_Call(callable, next_instr, total_args, kwnames);
DISPATCH_SAME_OPARG();
@@ -3357,19 +3592,30 @@
goto error;
}
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
}
/* Callable is not a normal Python function */
- if (cframe.use_tracing) {
- res = trace_call_function(
- tstate, callable, args,
- positional_args, kwnames);
- }
- else {
- res = PyObject_Vectorcall(
- callable, args,
- positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
- kwnames);
+ res = PyObject_Vectorcall(
+ callable, args,
+ positional_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
+ kwnames);
+ if (opcode == INSTRUMENTED_CALL) {
+ PyObject *arg = total_args == 0 ?
+ &_PyInstrumentation_MISSING : PEEK(total_args);
+ if (res == NULL) {
+ _Py_call_instrumentation_exc2(
+ tstate, PY_MONITORING_EVENT_C_RAISE,
+ frame, next_instr-1, callable, arg);
+ }
+ else {
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_C_RETURN,
+ frame, next_instr-1, callable, arg);
+ if (err < 0) {
+ Py_CLEAR(res);
+ }
+ }
}
kwnames = NULL;
assert((res != NULL) ^ (_PyErr_Occurred(tstate) != NULL));
@@ -3378,7 +3624,7 @@
Py_DECREF(args[i]);
}
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3382 "Python/generated_cases.c.h"
+ #line 3628 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3390,7 +3636,7 @@
TARGET(CALL_BOUND_METHOD_EXACT_ARGS) {
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
- #line 2430 "Python/bytecodes.c"
+ #line 2612 "Python/bytecodes.c"
DEOPT_IF(method != NULL, CALL);
DEOPT_IF(Py_TYPE(callable) != &PyMethod_Type, CALL);
STAT_INC(CALL, hit);
@@ -3400,7 +3646,7 @@
PEEK(oparg + 2) = Py_NewRef(meth); // method
Py_DECREF(callable);
GO_TO_INSTRUCTION(CALL_PY_EXACT_ARGS);
- #line 3404 "Python/generated_cases.c.h"
+ #line 3650 "Python/generated_cases.c.h"
}
TARGET(CALL_PY_EXACT_ARGS) {
@@ -3409,7 +3655,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
uint32_t func_version = read_u32(&next_instr[1].cache);
- #line 2442 "Python/bytecodes.c"
+ #line 2624 "Python/bytecodes.c"
assert(kwnames == NULL);
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
@@ -3433,8 +3679,9 @@
// Manipulate stack directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2);
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- #line 3438 "Python/generated_cases.c.h"
+ #line 3685 "Python/generated_cases.c.h"
}
TARGET(CALL_PY_WITH_DEFAULTS) {
@@ -3442,7 +3689,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
uint32_t func_version = read_u32(&next_instr[1].cache);
- #line 2469 "Python/bytecodes.c"
+ #line 2652 "Python/bytecodes.c"
assert(kwnames == NULL);
DEOPT_IF(tstate->interp->eval_frame, CALL);
int is_meth = method != NULL;
@@ -3476,8 +3723,9 @@
// Manipulate stack and cache directly since we leave using DISPATCH_INLINED().
STACK_SHRINK(oparg + 2);
JUMPBY(INLINE_CACHE_ENTRIES_CALL);
+ frame->return_offset = 0;
DISPATCH_INLINED(new_frame);
- #line 3481 "Python/generated_cases.c.h"
+ #line 3729 "Python/generated_cases.c.h"
}
TARGET(CALL_NO_KW_TYPE_1) {
@@ -3485,9 +3733,8 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2506 "Python/bytecodes.c"
+ #line 2690 "Python/bytecodes.c"
assert(kwnames == NULL);
- assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
PyObject *obj = args[0];
@@ -3496,7 +3743,7 @@
res = Py_NewRef(Py_TYPE(obj));
Py_DECREF(obj);
Py_DECREF(&PyType_Type); // I.e., callable
- #line 3500 "Python/generated_cases.c.h"
+ #line 3747 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3509,9 +3756,8 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2519 "Python/bytecodes.c"
+ #line 2702 "Python/bytecodes.c"
assert(kwnames == NULL);
- assert(cframe.use_tracing == 0);
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
DEOPT_IF(callable != (PyObject *)&PyUnicode_Type, CALL);
@@ -3521,7 +3767,7 @@
Py_DECREF(arg);
Py_DECREF(&PyUnicode_Type); // I.e., callable
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3525 "Python/generated_cases.c.h"
+ #line 3771 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3535,7 +3781,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *null = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2534 "Python/bytecodes.c"
+ #line 2716 "Python/bytecodes.c"
assert(kwnames == NULL);
assert(oparg == 1);
DEOPT_IF(null != NULL, CALL);
@@ -3546,7 +3792,7 @@
Py_DECREF(arg);
Py_DECREF(&PyTuple_Type); // I.e., tuple
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3550 "Python/generated_cases.c.h"
+ #line 3796 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3560,7 +3806,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2548 "Python/bytecodes.c"
+ #line 2730 "Python/bytecodes.c"
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3582,7 +3828,7 @@
}
Py_DECREF(tp);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3586 "Python/generated_cases.c.h"
+ #line 3832 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3596,8 +3842,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2573 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2755 "Python/bytecodes.c"
/* Builtin METH_O functions */
assert(kwnames == NULL);
int is_meth = method != NULL;
@@ -3625,7 +3870,7 @@
Py_DECREF(arg);
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3629 "Python/generated_cases.c.h"
+ #line 3874 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3639,8 +3884,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2605 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2786 "Python/bytecodes.c"
/* Builtin METH_FASTCALL functions, without keywords */
assert(kwnames == NULL);
int is_meth = method != NULL;
@@ -3672,7 +3916,7 @@
'invalid'). In those cases an exception is set, so we must
handle it.
*/
- #line 3676 "Python/generated_cases.c.h"
+ #line 3920 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3686,8 +3930,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2641 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2821 "Python/bytecodes.c"
/* Builtin METH_FASTCALL | METH_KEYWORDS functions */
int is_meth = method != NULL;
int total_args = oparg;
@@ -3719,7 +3962,7 @@
}
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3723 "Python/generated_cases.c.h"
+ #line 3966 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3733,8 +3976,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2677 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2856 "Python/bytecodes.c"
assert(kwnames == NULL);
/* len(o) */
int is_meth = method != NULL;
@@ -3759,7 +4001,7 @@
Py_DECREF(callable);
Py_DECREF(arg);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3763 "Python/generated_cases.c.h"
+ #line 4005 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3772,8 +4014,7 @@
PyObject *callable = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2705 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2883 "Python/bytecodes.c"
assert(kwnames == NULL);
/* isinstance(o, o2) */
int is_meth = method != NULL;
@@ -3800,7 +4041,7 @@
Py_DECREF(cls);
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3804 "Python/generated_cases.c.h"
+ #line 4045 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3812,8 +4053,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *self = stack_pointer[-(1 + oparg)];
PyObject *method = stack_pointer[-(2 + oparg)];
- #line 2736 "Python/bytecodes.c"
- assert(cframe.use_tracing == 0);
+ #line 2913 "Python/bytecodes.c"
assert(kwnames == NULL);
assert(oparg == 1);
assert(method != NULL);
@@ -3831,14 +4071,14 @@
JUMPBY(INLINE_CACHE_ENTRIES_CALL + 1);
assert(next_instr[-1].op.code == POP_TOP);
DISPATCH();
- #line 3835 "Python/generated_cases.c.h"
+ #line 4075 "Python/generated_cases.c.h"
}
TARGET(CALL_NO_KW_METHOD_DESCRIPTOR_O) {
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2757 "Python/bytecodes.c"
+ #line 2933 "Python/bytecodes.c"
assert(kwnames == NULL);
int is_meth = method != NULL;
int total_args = oparg;
@@ -3869,7 +4109,7 @@
Py_DECREF(arg);
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3873 "Python/generated_cases.c.h"
+ #line 4113 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3882,7 +4122,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2791 "Python/bytecodes.c"
+ #line 2967 "Python/bytecodes.c"
int is_meth = method != NULL;
int total_args = oparg;
if (is_meth) {
@@ -3911,7 +4151,7 @@
}
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3915 "Python/generated_cases.c.h"
+ #line 4155 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3924,7 +4164,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2823 "Python/bytecodes.c"
+ #line 2999 "Python/bytecodes.c"
assert(kwnames == NULL);
assert(oparg == 0 || oparg == 1);
int is_meth = method != NULL;
@@ -3953,7 +4193,7 @@
Py_DECREF(self);
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3957 "Python/generated_cases.c.h"
+ #line 4197 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -3966,7 +4206,7 @@
PyObject **args = (stack_pointer - oparg);
PyObject *method = stack_pointer[-(2 + oparg)];
PyObject *res;
- #line 2855 "Python/bytecodes.c"
+ #line 3031 "Python/bytecodes.c"
assert(kwnames == NULL);
int is_meth = method != NULL;
int total_args = oparg;
@@ -3994,7 +4234,7 @@
}
Py_DECREF(callable);
if (res == NULL) { STACK_SHRINK(oparg); goto pop_2_error; }
- #line 3998 "Python/generated_cases.c.h"
+ #line 4238 "Python/generated_cases.c.h"
STACK_SHRINK(oparg);
STACK_SHRINK(1);
stack_pointer[-1] = res;
@@ -4003,18 +4243,22 @@
DISPATCH();
}
+ TARGET(INSTRUMENTED_CALL_FUNCTION_EX) {
+ #line 3062 "Python/bytecodes.c"
+ GO_TO_INSTRUCTION(CALL_FUNCTION_EX);
+ #line 4250 "Python/generated_cases.c.h"
+ }
+
TARGET(CALL_FUNCTION_EX) {
PREDICTED(CALL_FUNCTION_EX);
PyObject *kwargs = (oparg & 1) ? stack_pointer[-(((oparg & 1) ? 1 : 0))] : NULL;
PyObject *callargs = stack_pointer[-(1 + ((oparg & 1) ? 1 : 0))];
PyObject *func = stack_pointer[-(2 + ((oparg & 1) ? 1 : 0))];
PyObject *result;
- #line 2886 "Python/bytecodes.c"
- if (oparg & 1) {
- // DICT_MERGE is called before this opcode if there are kwargs.
- // It converts all dict subtypes in kwargs into regular dicts.
- assert(PyDict_CheckExact(kwargs));
- }
+ #line 3066 "Python/bytecodes.c"
+ // DICT_MERGE is called before this opcode if there are kwargs.
+ // It converts all dict subtypes in kwargs into regular dicts.
+ assert(kwargs == NULL || PyDict_CheckExact(kwargs));
if (!PyTuple_CheckExact(callargs)) {
if (check_args_iterable(tstate, func, callargs) < 0) {
goto error;
@@ -4026,17 +4270,42 @@
Py_SETREF(callargs, tuple);
}
assert(PyTuple_CheckExact(callargs));
-
- result = do_call_core(tstate, func, callargs, kwargs, cframe.use_tracing);
- #line 4032 "Python/generated_cases.c.h"
+ EVAL_CALL_STAT_INC_IF_FUNCTION(EVAL_CALL_FUNCTION_EX, func);
+ if (opcode == INSTRUMENTED_CALL_FUNCTION_EX &&
+ !PyFunction_Check(func) && !PyMethod_Check(func)
+ ) {
+ PyObject *arg = PyTuple_GET_SIZE(callargs) > 0 ?
+ PyTuple_GET_ITEM(callargs, 0) : Py_None;
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_CALL,
+ frame, next_instr-1, func, arg);
+ if (err) goto error;
+ result = PyObject_Call(func, callargs, kwargs);
+ if (result == NULL) {
+ _Py_call_instrumentation_exc2(
+ tstate, PY_MONITORING_EVENT_C_RAISE,
+ frame, next_instr-1, func, arg);
+ }
+ else {
+ int err = _Py_call_instrumentation_2args(
+ tstate, PY_MONITORING_EVENT_C_RETURN,
+ frame, next_instr-1, func, arg);
+ if (err < 0) {
+ Py_CLEAR(result);
+ }
+ }
+ }
+ else {
+ result = PyObject_Call(func, callargs, kwargs);
+ }
+ #line 4302 "Python/generated_cases.c.h"
Py_DECREF(func);
Py_DECREF(callargs);
Py_XDECREF(kwargs);
- #line 2905 "Python/bytecodes.c"
-
+ #line 3109 "Python/bytecodes.c"
assert(PEEK(3 + (oparg & 1)) == NULL);
if (result == NULL) { STACK_SHRINK(((oparg & 1) ? 1 : 0)); goto pop_3_error; }
- #line 4040 "Python/generated_cases.c.h"
+ #line 4309 "Python/generated_cases.c.h"
STACK_SHRINK(((oparg & 1) ? 1 : 0));
STACK_SHRINK(2);
stack_pointer[-1] = result;
@@ -4051,7 +4320,7 @@
PyObject *kwdefaults = (oparg & 0x02) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0))] : NULL;
PyObject *defaults = (oparg & 0x01) ? stack_pointer[-(1 + ((oparg & 0x08) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x01) ? 1 : 0))] : NULL;
PyObject *func;
- #line 2916 "Python/bytecodes.c"
+ #line 3119 "Python/bytecodes.c"
PyFunctionObject *func_obj = (PyFunctionObject *)
PyFunction_New(codeobj, GLOBALS());
@@ -4080,14 +4349,14 @@
func_obj->func_version = ((PyCodeObject *)codeobj)->co_version;
func = (PyObject *)func_obj;
- #line 4084 "Python/generated_cases.c.h"
+ #line 4353 "Python/generated_cases.c.h"
STACK_SHRINK(((oparg & 0x01) ? 1 : 0) + ((oparg & 0x02) ? 1 : 0) + ((oparg & 0x04) ? 1 : 0) + ((oparg & 0x08) ? 1 : 0));
stack_pointer[-1] = func;
DISPATCH();
}
TARGET(RETURN_GENERATOR) {
- #line 2947 "Python/bytecodes.c"
+ #line 3150 "Python/bytecodes.c"
assert(PyFunction_Check(frame->f_funcobj));
PyFunctionObject *func = (PyFunctionObject *)frame->f_funcobj;
PyGenObject *gen = (PyGenObject *)_Py_MakeCoro(func);
@@ -4108,7 +4377,7 @@
frame = cframe.current_frame = prev;
_PyFrame_StackPush(frame, (PyObject *)gen);
goto resume_frame;
- #line 4112 "Python/generated_cases.c.h"
+ #line 4381 "Python/generated_cases.c.h"
}
TARGET(BUILD_SLICE) {
@@ -4116,15 +4385,15 @@
PyObject *stop = stack_pointer[-(1 + ((oparg == 3) ? 1 : 0))];
PyObject *start = stack_pointer[-(2 + ((oparg == 3) ? 1 : 0))];
PyObject *slice;
- #line 2970 "Python/bytecodes.c"
+ #line 3173 "Python/bytecodes.c"
slice = PySlice_New(start, stop, step);
- #line 4122 "Python/generated_cases.c.h"
+ #line 4391 "Python/generated_cases.c.h"
Py_DECREF(start);
Py_DECREF(stop);
Py_XDECREF(step);
- #line 2972 "Python/bytecodes.c"
+ #line 3175 "Python/bytecodes.c"
if (slice == NULL) { STACK_SHRINK(((oparg == 3) ? 1 : 0)); goto pop_2_error; }
- #line 4128 "Python/generated_cases.c.h"
+ #line 4397 "Python/generated_cases.c.h"
STACK_SHRINK(((oparg == 3) ? 1 : 0));
STACK_SHRINK(1);
stack_pointer[-1] = slice;
@@ -4135,7 +4404,7 @@
PyObject *fmt_spec = ((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? stack_pointer[-((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))] : NULL;
PyObject *value = stack_pointer[-(1 + (((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0))];
PyObject *result;
- #line 2976 "Python/bytecodes.c"
+ #line 3179 "Python/bytecodes.c"
/* Handles f-string value formatting. */
PyObject *(*conv_fn)(PyObject *);
int which_conversion = oparg & FVC_MASK;
@@ -4170,7 +4439,7 @@
Py_DECREF(value);
Py_XDECREF(fmt_spec);
if (result == NULL) { STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0)); goto pop_1_error; }
- #line 4174 "Python/generated_cases.c.h"
+ #line 4443 "Python/generated_cases.c.h"
STACK_SHRINK((((oparg & FVS_MASK) == FVS_HAVE_SPEC) ? 1 : 0));
stack_pointer[-1] = result;
DISPATCH();
@@ -4179,10 +4448,10 @@
TARGET(COPY) {
PyObject *bottom = stack_pointer[-(1 + (oparg-1))];
PyObject *top;
- #line 3013 "Python/bytecodes.c"
+ #line 3216 "Python/bytecodes.c"
assert(oparg > 0);
top = Py_NewRef(bottom);
- #line 4186 "Python/generated_cases.c.h"
+ #line 4455 "Python/generated_cases.c.h"
STACK_GROW(1);
stack_pointer[-1] = top;
DISPATCH();
@@ -4194,11 +4463,10 @@
PyObject *rhs = stack_pointer[-1];
PyObject *lhs = stack_pointer[-2];
PyObject *res;
- #line 3018 "Python/bytecodes.c"
+ #line 3221 "Python/bytecodes.c"
#if ENABLE_SPECIALIZATION
_PyBinaryOpCache *cache = (_PyBinaryOpCache *)next_instr;
if (ADAPTIVE_COUNTER_IS_ZERO(cache->counter)) {
- assert(cframe.use_tracing == 0);
next_instr--;
_Py_Specialize_BinaryOp(lhs, rhs, next_instr, oparg, &GETLOCAL(0));
DISPATCH_SAME_OPARG();
@@ -4210,12 +4478,12 @@
assert((unsigned)oparg < Py_ARRAY_LENGTH(binary_ops));
assert(binary_ops[oparg]);
res = binary_ops[oparg](lhs, rhs);
- #line 4214 "Python/generated_cases.c.h"
+ #line 4482 "Python/generated_cases.c.h"
Py_DECREF(lhs);
Py_DECREF(rhs);
- #line 3034 "Python/bytecodes.c"
+ #line 3236 "Python/bytecodes.c"
if (res == NULL) goto pop_2_error;
- #line 4219 "Python/generated_cases.c.h"
+ #line 4487 "Python/generated_cases.c.h"
STACK_SHRINK(1);
stack_pointer[-1] = res;
next_instr += 1;
@@ -4225,27 +4493,153 @@
TARGET(SWAP) {
PyObject *top = stack_pointer[-1];
PyObject *bottom = stack_pointer[-(2 + (oparg-2))];
- #line 3039 "Python/bytecodes.c"
+ #line 3241 "Python/bytecodes.c"
assert(oparg >= 2);
- #line 4231 "Python/generated_cases.c.h"
+ #line 4499 "Python/generated_cases.c.h"
stack_pointer[-1] = bottom;
stack_pointer[-(2 + (oparg-2))] = top;
DISPATCH();
}
+ TARGET(INSTRUMENTED_LINE) {
+ #line 3245 "Python/bytecodes.c"
+ _Py_CODEUNIT *here = next_instr-1;
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ int original_opcode = _Py_call_instrumentation_line(
+ tstate, frame, here);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (original_opcode < 0) {
+ next_instr = here+1;
+ goto error;
+ }
+ next_instr = frame->prev_instr;
+ if (next_instr != here) {
+ DISPATCH();
+ }
+ if (_PyOpcode_Caches[original_opcode]) {
+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ }
+ opcode = original_opcode;
+ DISPATCH_GOTO();
+ #line 4526 "Python/generated_cases.c.h"
+ }
+
+ TARGET(INSTRUMENTED_INSTRUCTION) {
+ #line 3267 "Python/bytecodes.c"
+ int next_opcode = _Py_call_instrumentation_instruction(
+ tstate, frame, next_instr-1);
+ if (next_opcode < 0) goto error;
+ next_instr--;
+ if (_PyOpcode_Caches[next_opcode]) {
+ _PyBinaryOpCache *cache = (_PyBinaryOpCache *)(next_instr+1);
+ INCREMENT_ADAPTIVE_COUNTER(cache->counter);
+ }
+ assert(next_opcode > 0 && next_opcode < 256);
+ opcode = next_opcode;
+ DISPATCH_GOTO();
+ #line 4542 "Python/generated_cases.c.h"
+ }
+
+ TARGET(INSTRUMENTED_JUMP_FORWARD) {
+ #line 3281 "Python/bytecodes.c"
+ INSTRUMENTED_JUMP(next_instr-1, next_instr+oparg, PY_MONITORING_EVENT_JUMP);
+ #line 4548 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_JUMP_BACKWARD) {
+ #line 3285 "Python/bytecodes.c"
+ INSTRUMENTED_JUMP(next_instr-1, next_instr-oparg, PY_MONITORING_EVENT_JUMP);
+ #line 4555 "Python/generated_cases.c.h"
+ CHECK_EVAL_BREAKER();
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_POP_JUMP_IF_TRUE) {
+ #line 3290 "Python/bytecodes.c"
+ PyObject *cond = POP();
+ int err = PyObject_IsTrue(cond);
+ Py_DECREF(cond);
+ if (err < 0) goto error;
+ _Py_CODEUNIT *here = next_instr-1;
+ assert(err == 0 || err == 1);
+ int offset = err*oparg;
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ #line 4570 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_POP_JUMP_IF_FALSE) {
+ #line 3301 "Python/bytecodes.c"
+ PyObject *cond = POP();
+ int err = PyObject_IsTrue(cond);
+ Py_DECREF(cond);
+ if (err < 0) goto error;
+ _Py_CODEUNIT *here = next_instr-1;
+ assert(err == 0 || err == 1);
+ int offset = (1-err)*oparg;
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ #line 4584 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_POP_JUMP_IF_NONE) {
+ #line 3312 "Python/bytecodes.c"
+ PyObject *value = POP();
+ _Py_CODEUNIT *here = next_instr-1;
+ int offset;
+ if (Py_IsNone(value)) {
+ _Py_DECREF_NO_DEALLOC(value);
+ offset = oparg;
+ }
+ else {
+ Py_DECREF(value);
+ offset = 0;
+ }
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ #line 4602 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
+ TARGET(INSTRUMENTED_POP_JUMP_IF_NOT_NONE) {
+ #line 3327 "Python/bytecodes.c"
+ PyObject *value = POP();
+ _Py_CODEUNIT *here = next_instr-1;
+ int offset;
+ if (Py_IsNone(value)) {
+ _Py_DECREF_NO_DEALLOC(value);
+ offset = 0;
+ }
+ else {
+ Py_DECREF(value);
+ offset = oparg;
+ }
+ INSTRUMENTED_JUMP(here, next_instr + offset, PY_MONITORING_EVENT_BRANCH);
+ #line 4620 "Python/generated_cases.c.h"
+ DISPATCH();
+ }
+
TARGET(EXTENDED_ARG) {
- #line 3043 "Python/bytecodes.c"
+ #line 3342 "Python/bytecodes.c"
assert(oparg);
- assert(cframe.use_tracing == 0);
opcode = next_instr->op.code;
oparg = oparg << 8 | next_instr->op.arg;
PRE_DISPATCH_GOTO();
DISPATCH_GOTO();
- #line 4245 "Python/generated_cases.c.h"
+ #line 4631 "Python/generated_cases.c.h"
}
TARGET(CACHE) {
- #line 3052 "Python/bytecodes.c"
+ #line 3350 "Python/bytecodes.c"
+ assert(0 && "Executing a cache.");
+ Py_UNREACHABLE();
+ #line 4638 "Python/generated_cases.c.h"
+ }
+
+ TARGET(RESERVED) {
+ #line 3355 "Python/bytecodes.c"
+ assert(0 && "Executing RESERVED instruction.");
Py_UNREACHABLE();
- #line 4251 "Python/generated_cases.c.h"
+ #line 4645 "Python/generated_cases.c.h"
}
diff --git a/Python/import.c b/Python/import.c
index 1db5b9333bbba1..daec64ea4adaad 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -413,8 +413,11 @@ remove_module(PyThreadState *tstate, PyObject *name)
Py_ssize_t
_PyImport_GetNextModuleIndex(void)
{
+ PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
LAST_MODULE_INDEX++;
- return LAST_MODULE_INDEX;
+ Py_ssize_t index = LAST_MODULE_INDEX;
+ PyThread_release_lock(EXTENSIONS.mutex);
+ return index;
}
static const char *
@@ -703,6 +706,7 @@ _PyImport_ClearModulesByIndex(PyInterpreterState *interp)
const char *
_PyImport_ResolveNameWithPackageContext(const char *name)
{
+ PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
if (PKGCONTEXT != NULL) {
const char *p = strrchr(PKGCONTEXT, '.');
if (p != NULL && strcmp(name, p+1) == 0) {
@@ -710,14 +714,17 @@ _PyImport_ResolveNameWithPackageContext(const char *name)
PKGCONTEXT = NULL;
}
}
+ PyThread_release_lock(EXTENSIONS.mutex);
return name;
}
const char *
_PyImport_SwapPackageContext(const char *newcontext)
{
+ PyThread_acquire_lock(EXTENSIONS.mutex, WAIT_LOCK);
const char *oldcontext = PKGCONTEXT;
PKGCONTEXT = newcontext;
+ PyThread_release_lock(EXTENSIONS.mutex);
return oldcontext;
}
@@ -865,13 +872,13 @@ gets even messier.
static inline void
extensions_lock_acquire(void)
{
- // XXX For now the GIL is sufficient.
+ PyThread_acquire_lock(_PyRuntime.imports.extensions.mutex, WAIT_LOCK);
}
static inline void
extensions_lock_release(void)
{
- // XXX For now the GIL is sufficient.
+ PyThread_release_lock(_PyRuntime.imports.extensions.mutex);
}
/* Magic for extension modules (built-in as well as dynamically
@@ -2021,9 +2028,9 @@ find_frozen(PyObject *nameobj, struct frozen_info *info)
}
static PyObject *
-unmarshal_frozen_code(struct frozen_info *info)
+unmarshal_frozen_code(PyInterpreterState *interp, struct frozen_info *info)
{
- if (info->get_code) {
+ if (info->get_code && _Py_IsMainInterpreter(interp)) {
PyObject *code = info->get_code();
assert(code != NULL);
return code;
@@ -2070,7 +2077,7 @@ PyImport_ImportFrozenModuleObject(PyObject *name)
set_frozen_error(status, name);
return -1;
}
- co = unmarshal_frozen_code(&info);
+ co = unmarshal_frozen_code(tstate->interp, &info);
if (co == NULL) {
return -1;
}
@@ -3528,7 +3535,8 @@ _imp_get_frozen_object_impl(PyObject *module, PyObject *name,
return NULL;
}
- PyObject *codeobj = unmarshal_frozen_code(&info);
+ PyInterpreterState *interp = _PyInterpreterState_GET();
+ PyObject *codeobj = unmarshal_frozen_code(interp, &info);
if (dataobj != Py_None) {
PyBuffer_Release(&buf);
}
diff --git a/Python/importlib.h b/Python/importlib.h
deleted file mode 100644
index 586f3b21f46246..00000000000000
--- a/Python/importlib.h
+++ /dev/null
@@ -1,1783 +0,0 @@
-/* Auto-generated by Programs/_freeze_importlib.c */
-const unsigned char _Py_M__importlib_bootstrap[] = {
- 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,4,0,0,0,64,0,0,0,115,194,1,0,0,100,0,
- 90,0,100,1,97,1,100,2,100,3,132,0,90,2,100,4,
- 100,5,132,0,90,3,105,0,90,4,105,0,90,5,71,0,
- 100,6,100,7,132,0,100,7,101,6,131,3,90,7,71,0,
- 100,8,100,9,132,0,100,9,131,2,90,8,71,0,100,10,
- 100,11,132,0,100,11,131,2,90,9,71,0,100,12,100,13,
- 132,0,100,13,131,2,90,10,100,14,100,15,132,0,90,11,
- 100,16,100,17,132,0,90,12,100,18,100,19,132,0,90,13,
- 100,20,100,21,156,1,100,22,100,23,132,2,90,14,100,24,
- 100,25,132,0,90,15,100,26,100,27,132,0,90,16,100,28,
- 100,29,132,0,90,17,100,30,100,31,132,0,90,18,71,0,
- 100,32,100,33,132,0,100,33,131,2,90,19,100,1,100,1,
- 100,34,156,2,100,35,100,36,132,2,90,20,100,94,100,37,
- 100,38,132,1,90,21,100,39,100,40,156,1,100,41,100,42,
- 132,2,90,22,100,43,100,44,132,0,90,23,100,45,100,46,
- 132,0,90,24,100,47,100,48,132,0,90,25,100,49,100,50,
- 132,0,90,26,100,51,100,52,132,0,90,27,100,53,100,54,
- 132,0,90,28,71,0,100,55,100,56,132,0,100,56,131,2,
- 90,29,71,0,100,57,100,58,132,0,100,58,131,2,90,30,
- 71,0,100,59,100,60,132,0,100,60,131,2,90,31,100,61,
- 100,62,132,0,90,32,100,63,100,64,132,0,90,33,100,95,
- 100,65,100,66,132,1,90,34,100,67,100,68,132,0,90,35,
- 100,69,90,36,101,36,100,70,23,0,90,37,100,71,100,72,
- 132,0,90,38,101,39,131,0,90,40,100,73,100,74,132,0,
- 90,41,100,96,100,76,100,77,132,1,90,42,100,39,100,78,
- 156,1,100,79,100,80,132,2,90,43,100,81,100,82,132,0,
- 90,44,100,97,100,84,100,85,132,1,90,45,100,86,100,87,
- 132,0,90,46,100,88,100,89,132,0,90,47,100,90,100,91,
- 132,0,90,48,100,92,100,93,132,0,90,49,100,1,83,0,
- 41,98,97,83,1,0,0,67,111,114,101,32,105,109,112,108,
- 101,109,101,110,116,97,116,105,111,110,32,111,102,32,105,109,
- 112,111,114,116,46,10,10,84,104,105,115,32,109,111,100,117,
- 108,101,32,105,115,32,78,79,84,32,109,101,97,110,116,32,
- 116,111,32,98,101,32,100,105,114,101,99,116,108,121,32,105,
- 109,112,111,114,116,101,100,33,32,73,116,32,104,97,115,32,
- 98,101,101,110,32,100,101,115,105,103,110,101,100,32,115,117,
- 99,104,10,116,104,97,116,32,105,116,32,99,97,110,32,98,
- 101,32,98,111,111,116,115,116,114,97,112,112,101,100,32,105,
- 110,116,111,32,80,121,116,104,111,110,32,97,115,32,116,104,
- 101,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,
- 32,111,102,32,105,109,112,111,114,116,46,32,65,115,10,115,
- 117,99,104,32,105,116,32,114,101,113,117,105,114,101,115,32,
- 116,104,101,32,105,110,106,101,99,116,105,111,110,32,111,102,
- 32,115,112,101,99,105,102,105,99,32,109,111,100,117,108,101,
- 115,32,97,110,100,32,97,116,116,114,105,98,117,116,101,115,
- 32,105,110,32,111,114,100,101,114,32,116,111,10,119,111,114,
- 107,46,32,79,110,101,32,115,104,111,117,108,100,32,117,115,
- 101,32,105,109,112,111,114,116,108,105,98,32,97,115,32,116,
- 104,101,32,112,117,98,108,105,99,45,102,97,99,105,110,103,
- 32,118,101,114,115,105,111,110,32,111,102,32,116,104,105,115,
- 32,109,111,100,117,108,101,46,10,10,78,99,2,0,0,0,
- 0,0,0,0,0,0,0,0,3,0,0,0,7,0,0,0,
- 67,0,0,0,115,56,0,0,0,100,1,68,0,93,32,125,
- 2,116,0,124,1,124,2,131,2,114,4,116,1,124,0,124,
- 2,116,2,124,1,124,2,131,2,131,3,1,0,113,4,124,
- 0,106,3,160,4,124,1,106,3,161,1,1,0,100,2,83,
- 0,41,3,122,47,83,105,109,112,108,101,32,115,117,98,115,
- 116,105,116,117,116,101,32,102,111,114,32,102,117,110,99,116,
- 111,111,108,115,46,117,112,100,97,116,101,95,119,114,97,112,
- 112,101,114,46,41,4,218,10,95,95,109,111,100,117,108,101,
- 95,95,218,8,95,95,110,97,109,101,95,95,218,12,95,95,
- 113,117,97,108,110,97,109,101,95,95,218,7,95,95,100,111,
- 99,95,95,78,41,5,218,7,104,97,115,97,116,116,114,218,
- 7,115,101,116,97,116,116,114,218,7,103,101,116,97,116,116,
- 114,218,8,95,95,100,105,99,116,95,95,218,6,117,112,100,
- 97,116,101,41,3,90,3,110,101,119,90,3,111,108,100,218,
- 7,114,101,112,108,97,99,101,169,0,114,10,0,0,0,250,
- 29,60,102,114,111,122,101,110,32,105,109,112,111,114,116,108,
- 105,98,46,95,98,111,111,116,115,116,114,97,112,62,218,5,
- 95,119,114,97,112,27,0,0,0,115,8,0,0,0,0,2,
- 8,1,10,1,20,1,114,12,0,0,0,99,1,0,0,0,
- 0,0,0,0,0,0,0,0,1,0,0,0,2,0,0,0,
- 67,0,0,0,115,12,0,0,0,116,0,116,1,131,1,124,
- 0,131,1,83,0,169,1,78,41,2,218,4,116,121,112,101,
- 218,3,115,121,115,169,1,218,4,110,97,109,101,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,218,11,95,110,
- 101,119,95,109,111,100,117,108,101,35,0,0,0,115,2,0,
- 0,0,0,1,114,18,0,0,0,99,0,0,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,1,0,0,0,64,0,
- 0,0,115,12,0,0,0,101,0,90,1,100,0,90,2,100,
- 1,83,0,41,2,218,14,95,68,101,97,100,108,111,99,107,
- 69,114,114,111,114,78,41,3,114,1,0,0,0,114,0,0,
- 0,0,114,2,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,10,0,0,0,114,11,0,0,0,114,19,0,0,0,
- 48,0,0,0,115,2,0,0,0,8,1,114,19,0,0,0,
- 99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,2,0,0,0,64,0,0,0,115,56,0,0,0,101,0,
- 90,1,100,0,90,2,100,1,90,3,100,2,100,3,132,0,
- 90,4,100,4,100,5,132,0,90,5,100,6,100,7,132,0,
- 90,6,100,8,100,9,132,0,90,7,100,10,100,11,132,0,
- 90,8,100,12,83,0,41,13,218,11,95,77,111,100,117,108,
- 101,76,111,99,107,122,169,65,32,114,101,99,117,114,115,105,
- 118,101,32,108,111,99,107,32,105,109,112,108,101,109,101,110,
- 116,97,116,105,111,110,32,119,104,105,99,104,32,105,115,32,
- 97,98,108,101,32,116,111,32,100,101,116,101,99,116,32,100,
- 101,97,100,108,111,99,107,115,10,32,32,32,32,40,101,46,
- 103,46,32,116,104,114,101,97,100,32,49,32,116,114,121,105,
- 110,103,32,116,111,32,116,97,107,101,32,108,111,99,107,115,
- 32,65,32,116,104,101,110,32,66,44,32,97,110,100,32,116,
- 104,114,101,97,100,32,50,32,116,114,121,105,110,103,32,116,
- 111,10,32,32,32,32,116,97,107,101,32,108,111,99,107,115,
- 32,66,32,116,104,101,110,32,65,41,46,10,32,32,32,32,
- 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
- 0,2,0,0,0,67,0,0,0,115,48,0,0,0,116,0,
- 160,1,161,0,124,0,95,2,116,0,160,1,161,0,124,0,
- 95,3,124,1,124,0,95,4,100,0,124,0,95,5,100,1,
- 124,0,95,6,100,1,124,0,95,7,100,0,83,0,169,2,
- 78,233,0,0,0,0,41,8,218,7,95,116,104,114,101,97,
- 100,90,13,97,108,108,111,99,97,116,101,95,108,111,99,107,
- 218,4,108,111,99,107,218,6,119,97,107,101,117,112,114,17,
- 0,0,0,218,5,111,119,110,101,114,218,5,99,111,117,110,
- 116,218,7,119,97,105,116,101,114,115,169,2,218,4,115,101,
- 108,102,114,17,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,11,0,0,0,218,8,95,95,105,110,105,116,95,95,
- 58,0,0,0,115,12,0,0,0,0,1,10,1,10,1,6,
- 1,6,1,6,1,122,20,95,77,111,100,117,108,101,76,111,
- 99,107,46,95,95,105,110,105,116,95,95,99,1,0,0,0,
- 0,0,0,0,0,0,0,0,4,0,0,0,3,0,0,0,
- 67,0,0,0,115,60,0,0,0,116,0,160,1,161,0,125,
- 1,124,0,106,2,125,2,116,3,160,4,124,2,161,1,125,
- 3,124,3,100,0,107,8,114,36,100,1,83,0,124,3,106,
- 2,125,2,124,2,124,1,107,2,114,14,100,2,83,0,113,
- 14,100,0,83,0,41,3,78,70,84,41,5,114,23,0,0,
- 0,218,9,103,101,116,95,105,100,101,110,116,114,26,0,0,
- 0,218,12,95,98,108,111,99,107,105,110,103,95,111,110,218,
- 3,103,101,116,41,4,114,30,0,0,0,90,2,109,101,218,
- 3,116,105,100,114,24,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,218,12,104,97,115,95,100,101,
- 97,100,108,111,99,107,66,0,0,0,115,16,0,0,0,0,
- 2,8,1,6,2,10,1,8,1,4,1,6,1,8,1,122,
- 24,95,77,111,100,117,108,101,76,111,99,107,46,104,97,115,
- 95,100,101,97,100,108,111,99,107,99,1,0,0,0,0,0,
- 0,0,0,0,0,0,2,0,0,0,9,0,0,0,67,0,
- 0,0,115,178,0,0,0,116,0,160,1,161,0,125,1,124,
- 0,116,2,124,1,60,0,122,148,124,0,106,3,143,110,1,
- 0,124,0,106,4,100,1,107,2,115,46,124,0,106,5,124,
- 1,107,2,114,84,124,1,124,0,95,5,124,0,4,0,106,
- 4,100,2,55,0,2,0,95,4,87,0,53,0,81,0,82,
- 0,163,0,87,0,162,86,100,3,83,0,124,0,160,6,161,
- 0,114,104,116,7,100,4,124,0,22,0,131,1,130,1,124,
- 0,106,8,160,9,100,5,161,1,114,130,124,0,4,0,106,
- 10,100,2,55,0,2,0,95,10,87,0,53,0,81,0,82,
- 0,88,0,124,0,106,8,160,9,161,0,1,0,124,0,106,
- 8,160,11,161,0,1,0,113,18,87,0,53,0,116,2,124,
- 1,61,0,88,0,100,6,83,0,41,7,122,185,10,32,32,
- 32,32,32,32,32,32,65,99,113,117,105,114,101,32,116,104,
- 101,32,109,111,100,117,108,101,32,108,111,99,107,46,32,32,
- 73,102,32,97,32,112,111,116,101,110,116,105,97,108,32,100,
- 101,97,100,108,111,99,107,32,105,115,32,100,101,116,101,99,
- 116,101,100,44,10,32,32,32,32,32,32,32,32,97,32,95,
- 68,101,97,100,108,111,99,107,69,114,114,111,114,32,105,115,
- 32,114,97,105,115,101,100,46,10,32,32,32,32,32,32,32,
- 32,79,116,104,101,114,119,105,115,101,44,32,116,104,101,32,
- 108,111,99,107,32,105,115,32,97,108,119,97,121,115,32,97,
- 99,113,117,105,114,101,100,32,97,110,100,32,84,114,117,101,
- 32,105,115,32,114,101,116,117,114,110,101,100,46,10,32,32,
- 32,32,32,32,32,32,114,22,0,0,0,233,1,0,0,0,
- 84,122,23,100,101,97,100,108,111,99,107,32,100,101,116,101,
- 99,116,101,100,32,98,121,32,37,114,70,78,41,12,114,23,
- 0,0,0,114,32,0,0,0,114,33,0,0,0,114,24,0,
- 0,0,114,27,0,0,0,114,26,0,0,0,114,36,0,0,
- 0,114,19,0,0,0,114,25,0,0,0,218,7,97,99,113,
- 117,105,114,101,114,28,0,0,0,218,7,114,101,108,101,97,
- 115,101,169,2,114,30,0,0,0,114,35,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,114,38,0,
- 0,0,78,0,0,0,115,30,0,0,0,0,6,8,1,8,
- 1,2,2,8,1,20,1,6,1,14,1,18,1,8,1,12,
- 1,12,1,24,2,10,1,16,2,122,19,95,77,111,100,117,
- 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1,
- 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,9,
- 0,0,0,67,0,0,0,115,122,0,0,0,116,0,160,1,
- 161,0,125,1,124,0,106,2,143,98,1,0,124,0,106,3,
- 124,1,107,3,114,34,116,4,100,1,131,1,130,1,124,0,
- 106,5,100,2,107,4,115,48,74,0,130,1,124,0,4,0,
- 106,5,100,3,56,0,2,0,95,5,124,0,106,5,100,2,
- 107,2,114,108,100,0,124,0,95,3,124,0,106,6,114,108,
- 124,0,4,0,106,6,100,3,56,0,2,0,95,6,124,0,
- 106,7,160,8,161,0,1,0,87,0,53,0,81,0,82,0,
- 88,0,100,0,83,0,41,4,78,250,31,99,97,110,110,111,
- 116,32,114,101,108,101,97,115,101,32,117,110,45,97,99,113,
- 117,105,114,101,100,32,108,111,99,107,114,22,0,0,0,114,
- 37,0,0,0,41,9,114,23,0,0,0,114,32,0,0,0,
- 114,24,0,0,0,114,26,0,0,0,218,12,82,117,110,116,
- 105,109,101,69,114,114,111,114,114,27,0,0,0,114,28,0,
- 0,0,114,25,0,0,0,114,39,0,0,0,114,40,0,0,
- 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,
- 114,39,0,0,0,103,0,0,0,115,22,0,0,0,0,1,
- 8,1,8,1,10,1,8,1,14,1,14,1,10,1,6,1,
- 6,1,14,1,122,19,95,77,111,100,117,108,101,76,111,99,
- 107,46,114,101,108,101,97,115,101,99,1,0,0,0,0,0,
- 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0,
- 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100,
- 2,116,1,124,0,131,1,155,0,157,4,83,0,41,3,78,
- 122,12,95,77,111,100,117,108,101,76,111,99,107,40,250,5,
- 41,32,97,116,32,169,2,114,17,0,0,0,218,2,105,100,
- 169,1,114,30,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,11,0,0,0,218,8,95,95,114,101,112,114,95,95,
- 116,0,0,0,115,2,0,0,0,0,1,122,20,95,77,111,
- 100,117,108,101,76,111,99,107,46,95,95,114,101,112,114,95,
- 95,78,41,9,114,1,0,0,0,114,0,0,0,0,114,2,
- 0,0,0,114,3,0,0,0,114,31,0,0,0,114,36,0,
- 0,0,114,38,0,0,0,114,39,0,0,0,114,47,0,0,
- 0,114,10,0,0,0,114,10,0,0,0,114,10,0,0,0,
- 114,11,0,0,0,114,20,0,0,0,52,0,0,0,115,12,
- 0,0,0,8,1,4,5,8,8,8,12,8,25,8,13,114,
- 20,0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,0,2,0,0,0,64,0,0,0,115,48,0,
- 0,0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,
- 100,3,132,0,90,4,100,4,100,5,132,0,90,5,100,6,
- 100,7,132,0,90,6,100,8,100,9,132,0,90,7,100,10,
- 83,0,41,11,218,16,95,68,117,109,109,121,77,111,100,117,
- 108,101,76,111,99,107,122,86,65,32,115,105,109,112,108,101,
- 32,95,77,111,100,117,108,101,76,111,99,107,32,101,113,117,
- 105,118,97,108,101,110,116,32,102,111,114,32,80,121,116,104,
- 111,110,32,98,117,105,108,100,115,32,119,105,116,104,111,117,
- 116,10,32,32,32,32,109,117,108,116,105,45,116,104,114,101,
- 97,100,105,110,103,32,115,117,112,112,111,114,116,46,99,2,
- 0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,2,
- 0,0,0,67,0,0,0,115,16,0,0,0,124,1,124,0,
- 95,0,100,1,124,0,95,1,100,0,83,0,114,21,0,0,
- 0,41,2,114,17,0,0,0,114,27,0,0,0,114,29,0,
- 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,
- 0,114,31,0,0,0,124,0,0,0,115,4,0,0,0,0,
- 1,6,1,122,25,95,68,117,109,109,121,77,111,100,117,108,
- 101,76,111,99,107,46,95,95,105,110,105,116,95,95,99,1,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,
- 0,0,0,67,0,0,0,115,18,0,0,0,124,0,4,0,
- 106,0,100,1,55,0,2,0,95,0,100,2,83,0,41,3,
- 78,114,37,0,0,0,84,41,1,114,27,0,0,0,114,46,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,114,38,0,0,0,128,0,0,0,115,4,0,0,0,
- 0,1,14,1,122,24,95,68,117,109,109,121,77,111,100,117,
- 108,101,76,111,99,107,46,97,99,113,117,105,114,101,99,1,
- 0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,3,
- 0,0,0,67,0,0,0,115,36,0,0,0,124,0,106,0,
- 100,1,107,2,114,18,116,1,100,2,131,1,130,1,124,0,
- 4,0,106,0,100,3,56,0,2,0,95,0,100,0,83,0,
- 41,4,78,114,22,0,0,0,114,41,0,0,0,114,37,0,
- 0,0,41,2,114,27,0,0,0,114,42,0,0,0,114,46,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,114,39,0,0,0,132,0,0,0,115,6,0,0,0,
- 0,1,10,1,8,1,122,24,95,68,117,109,109,121,77,111,
- 100,117,108,101,76,111,99,107,46,114,101,108,101,97,115,101,
- 99,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,
- 0,5,0,0,0,67,0,0,0,115,22,0,0,0,100,1,
- 124,0,106,0,155,2,100,2,116,1,124,0,131,1,155,0,
- 157,4,83,0,41,3,78,122,17,95,68,117,109,109,121,77,
- 111,100,117,108,101,76,111,99,107,40,114,43,0,0,0,114,
- 44,0,0,0,114,46,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,114,47,0,0,0,137,0,0,
- 0,115,2,0,0,0,0,1,122,25,95,68,117,109,109,121,
- 77,111,100,117,108,101,76,111,99,107,46,95,95,114,101,112,
- 114,95,95,78,41,8,114,1,0,0,0,114,0,0,0,0,
- 114,2,0,0,0,114,3,0,0,0,114,31,0,0,0,114,
- 38,0,0,0,114,39,0,0,0,114,47,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,114,48,0,0,0,120,0,0,0,115,10,0,0,0,
- 8,1,4,3,8,4,8,4,8,5,114,48,0,0,0,99,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 2,0,0,0,64,0,0,0,115,36,0,0,0,101,0,90,
- 1,100,0,90,2,100,1,100,2,132,0,90,3,100,3,100,
- 4,132,0,90,4,100,5,100,6,132,0,90,5,100,7,83,
- 0,41,8,218,18,95,77,111,100,117,108,101,76,111,99,107,
- 77,97,110,97,103,101,114,99,2,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,0,0,2,0,0,0,67,0,0,0,
- 115,16,0,0,0,124,1,124,0,95,0,100,0,124,0,95,
- 1,100,0,83,0,114,13,0,0,0,41,2,218,5,95,110,
- 97,109,101,218,5,95,108,111,99,107,114,29,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,31,
- 0,0,0,143,0,0,0,115,4,0,0,0,0,1,6,1,
- 122,27,95,77,111,100,117,108,101,76,111,99,107,77,97,110,
- 97,103,101,114,46,95,95,105,110,105,116,95,95,99,1,0,
- 0,0,0,0,0,0,0,0,0,0,1,0,0,0,2,0,
- 0,0,67,0,0,0,115,26,0,0,0,116,0,124,0,106,
- 1,131,1,124,0,95,2,124,0,106,2,160,3,161,0,1,
- 0,100,0,83,0,114,13,0,0,0,41,4,218,16,95,103,
- 101,116,95,109,111,100,117,108,101,95,108,111,99,107,114,50,
- 0,0,0,114,51,0,0,0,114,38,0,0,0,114,46,0,
- 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,
- 0,218,9,95,95,101,110,116,101,114,95,95,147,0,0,0,
- 115,4,0,0,0,0,1,12,1,122,28,95,77,111,100,117,
- 108,101,76,111,99,107,77,97,110,97,103,101,114,46,95,95,
- 101,110,116,101,114,95,95,99,1,0,0,0,0,0,0,0,
- 0,0,0,0,3,0,0,0,2,0,0,0,79,0,0,0,
- 115,14,0,0,0,124,0,106,0,160,1,161,0,1,0,100,
- 0,83,0,114,13,0,0,0,41,2,114,51,0,0,0,114,
- 39,0,0,0,41,3,114,30,0,0,0,218,4,97,114,103,
- 115,90,6,107,119,97,114,103,115,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,218,8,95,95,101,120,105,116,
- 95,95,151,0,0,0,115,2,0,0,0,0,1,122,27,95,
- 77,111,100,117,108,101,76,111,99,107,77,97,110,97,103,101,
- 114,46,95,95,101,120,105,116,95,95,78,41,6,114,1,0,
- 0,0,114,0,0,0,0,114,2,0,0,0,114,31,0,0,
- 0,114,53,0,0,0,114,55,0,0,0,114,10,0,0,0,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,
- 49,0,0,0,141,0,0,0,115,6,0,0,0,8,2,8,
- 4,8,4,114,49,0,0,0,99,1,0,0,0,0,0,0,
- 0,0,0,0,0,3,0,0,0,8,0,0,0,67,0,0,
- 0,115,130,0,0,0,116,0,160,1,161,0,1,0,122,106,
- 122,14,116,3,124,0,25,0,131,0,125,1,87,0,110,24,
- 4,0,116,4,107,10,114,48,1,0,1,0,1,0,100,1,
- 125,1,89,0,110,2,88,0,124,1,100,1,107,8,114,112,
- 116,5,100,1,107,8,114,76,116,6,124,0,131,1,125,1,
- 110,8,116,7,124,0,131,1,125,1,124,0,102,1,100,2,
- 100,3,132,1,125,2,116,8,160,9,124,1,124,2,161,2,
- 116,3,124,0,60,0,87,0,53,0,116,0,160,2,161,0,
- 1,0,88,0,124,1,83,0,41,4,122,139,71,101,116,32,
- 111,114,32,99,114,101,97,116,101,32,116,104,101,32,109,111,
- 100,117,108,101,32,108,111,99,107,32,102,111,114,32,97,32,
- 103,105,118,101,110,32,109,111,100,117,108,101,32,110,97,109,
- 101,46,10,10,32,32,32,32,65,99,113,117,105,114,101,47,
- 114,101,108,101,97,115,101,32,105,110,116,101,114,110,97,108,
- 108,121,32,116,104,101,32,103,108,111,98,97,108,32,105,109,
- 112,111,114,116,32,108,111,99,107,32,116,111,32,112,114,111,
- 116,101,99,116,10,32,32,32,32,95,109,111,100,117,108,101,
- 95,108,111,99,107,115,46,78,99,2,0,0,0,0,0,0,
- 0,0,0,0,0,2,0,0,0,8,0,0,0,83,0,0,
- 0,115,48,0,0,0,116,0,160,1,161,0,1,0,122,24,
- 116,3,160,4,124,1,161,1,124,0,107,8,114,30,116,3,
- 124,1,61,0,87,0,53,0,116,0,160,2,161,0,1,0,
- 88,0,100,0,83,0,114,13,0,0,0,41,5,218,4,95,
- 105,109,112,218,12,97,99,113,117,105,114,101,95,108,111,99,
- 107,218,12,114,101,108,101,97,115,101,95,108,111,99,107,218,
- 13,95,109,111,100,117,108,101,95,108,111,99,107,115,114,34,
- 0,0,0,41,2,218,3,114,101,102,114,17,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,2,
- 99,98,176,0,0,0,115,10,0,0,0,0,1,8,1,2,
- 4,14,1,10,2,122,28,95,103,101,116,95,109,111,100,117,
- 108,101,95,108,111,99,107,46,60,108,111,99,97,108,115,62,
- 46,99,98,41,10,114,56,0,0,0,114,57,0,0,0,114,
- 58,0,0,0,114,59,0,0,0,218,8,75,101,121,69,114,
- 114,111,114,114,23,0,0,0,114,48,0,0,0,114,20,0,
- 0,0,218,8,95,119,101,97,107,114,101,102,114,60,0,0,
- 0,41,3,114,17,0,0,0,114,24,0,0,0,114,61,0,
- 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,
- 0,114,52,0,0,0,157,0,0,0,115,28,0,0,0,0,
- 6,8,1,2,1,2,1,14,1,14,1,10,2,8,1,8,
- 1,10,2,8,2,12,11,20,2,10,2,114,52,0,0,0,
- 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
- 0,8,0,0,0,67,0,0,0,115,54,0,0,0,116,0,
- 124,0,131,1,125,1,122,12,124,1,160,1,161,0,1,0,
- 87,0,110,20,4,0,116,2,107,10,114,40,1,0,1,0,
- 1,0,89,0,110,10,88,0,124,1,160,3,161,0,1,0,
- 100,1,83,0,41,2,122,189,65,99,113,117,105,114,101,115,
- 32,116,104,101,110,32,114,101,108,101,97,115,101,115,32,116,
- 104,101,32,109,111,100,117,108,101,32,108,111,99,107,32,102,
- 111,114,32,97,32,103,105,118,101,110,32,109,111,100,117,108,
- 101,32,110,97,109,101,46,10,10,32,32,32,32,84,104,105,
- 115,32,105,115,32,117,115,101,100,32,116,111,32,101,110,115,
- 117,114,101,32,97,32,109,111,100,117,108,101,32,105,115,32,
- 99,111,109,112,108,101,116,101,108,121,32,105,110,105,116,105,
- 97,108,105,122,101,100,44,32,105,110,32,116,104,101,10,32,
- 32,32,32,101,118,101,110,116,32,105,116,32,105,115,32,98,
- 101,105,110,103,32,105,109,112,111,114,116,101,100,32,98,121,
- 32,97,110,111,116,104,101,114,32,116,104,114,101,97,100,46,
- 10,32,32,32,32,78,41,4,114,52,0,0,0,114,38,0,
- 0,0,114,19,0,0,0,114,39,0,0,0,41,2,114,17,
- 0,0,0,114,24,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,19,95,108,111,99,107,95,117,
- 110,108,111,99,107,95,109,111,100,117,108,101,194,0,0,0,
- 115,12,0,0,0,0,6,8,1,2,1,12,1,14,3,6,
- 2,114,64,0,0,0,99,1,0,0,0,0,0,0,0,0,
- 0,0,0,3,0,0,0,3,0,0,0,79,0,0,0,115,
- 10,0,0,0,124,0,124,1,124,2,142,1,83,0,41,1,
- 97,46,1,0,0,114,101,109,111,118,101,95,105,109,112,111,
- 114,116,108,105,98,95,102,114,97,109,101,115,32,105,110,32,
- 105,109,112,111,114,116,46,99,32,119,105,108,108,32,97,108,
- 119,97,121,115,32,114,101,109,111,118,101,32,115,101,113,117,
- 101,110,99,101,115,10,32,32,32,32,111,102,32,105,109,112,
- 111,114,116,108,105,98,32,102,114,97,109,101,115,32,116,104,
- 97,116,32,101,110,100,32,119,105,116,104,32,97,32,99,97,
- 108,108,32,116,111,32,116,104,105,115,32,102,117,110,99,116,
- 105,111,110,10,10,32,32,32,32,85,115,101,32,105,116,32,
- 105,110,115,116,101,97,100,32,111,102,32,97,32,110,111,114,
- 109,97,108,32,99,97,108,108,32,105,110,32,112,108,97,99,
- 101,115,32,119,104,101,114,101,32,105,110,99,108,117,100,105,
- 110,103,32,116,104,101,32,105,109,112,111,114,116,108,105,98,
- 10,32,32,32,32,102,114,97,109,101,115,32,105,110,116,114,
- 111,100,117,99,101,115,32,117,110,119,97,110,116,101,100,32,
- 110,111,105,115,101,32,105,110,116,111,32,116,104,101,32,116,
- 114,97,99,101,98,97,99,107,32,40,101,46,103,46,32,119,
- 104,101,110,32,101,120,101,99,117,116,105,110,103,10,32,32,
- 32,32,109,111,100,117,108,101,32,99,111,100,101,41,10,32,
- 32,32,32,114,10,0,0,0,41,3,218,1,102,114,54,0,
- 0,0,90,4,107,119,100,115,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,25,95,99,97,108,108,95,119,
- 105,116,104,95,102,114,97,109,101,115,95,114,101,109,111,118,
- 101,100,211,0,0,0,115,2,0,0,0,0,8,114,66,0,
- 0,0,114,37,0,0,0,41,1,218,9,118,101,114,98,111,
- 115,105,116,121,99,1,0,0,0,0,0,0,0,1,0,0,
- 0,3,0,0,0,4,0,0,0,71,0,0,0,115,54,0,
- 0,0,116,0,106,1,106,2,124,1,107,5,114,50,124,0,
- 160,3,100,1,161,1,115,30,100,2,124,0,23,0,125,0,
- 116,4,124,0,106,5,124,2,142,0,116,0,106,6,100,3,
- 141,2,1,0,100,4,83,0,41,5,122,61,80,114,105,110,
- 116,32,116,104,101,32,109,101,115,115,97,103,101,32,116,111,
- 32,115,116,100,101,114,114,32,105,102,32,45,118,47,80,89,
- 84,72,79,78,86,69,82,66,79,83,69,32,105,115,32,116,
- 117,114,110,101,100,32,111,110,46,41,2,250,1,35,122,7,
- 105,109,112,111,114,116,32,122,2,35,32,41,1,90,4,102,
- 105,108,101,78,41,7,114,15,0,0,0,218,5,102,108,97,
- 103,115,218,7,118,101,114,98,111,115,101,218,10,115,116,97,
- 114,116,115,119,105,116,104,218,5,112,114,105,110,116,218,6,
- 102,111,114,109,97,116,218,6,115,116,100,101,114,114,41,3,
- 218,7,109,101,115,115,97,103,101,114,67,0,0,0,114,54,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,218,16,95,118,101,114,98,111,115,101,95,109,101,115,
- 115,97,103,101,222,0,0,0,115,8,0,0,0,0,2,12,
- 1,10,1,8,1,114,76,0,0,0,99,1,0,0,0,0,
- 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,3,
- 0,0,0,115,26,0,0,0,135,0,102,1,100,1,100,2,
- 132,8,125,1,116,0,124,1,136,0,131,2,1,0,124,1,
- 83,0,41,3,122,49,68,101,99,111,114,97,116,111,114,32,
- 116,111,32,118,101,114,105,102,121,32,116,104,101,32,110,97,
- 109,101,100,32,109,111,100,117,108,101,32,105,115,32,98,117,
- 105,108,116,45,105,110,46,99,2,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,0,0,4,0,0,0,19,0,0,0,
- 115,38,0,0,0,124,1,116,0,106,1,107,7,114,28,116,
- 2,124,1,155,2,100,1,157,2,124,1,100,2,141,2,130,
- 1,136,0,124,0,124,1,131,2,83,0,41,3,78,250,25,
- 32,105,115,32,110,111,116,32,97,32,98,117,105,108,116,45,
- 105,110,32,109,111,100,117,108,101,114,16,0,0,0,41,3,
- 114,15,0,0,0,218,20,98,117,105,108,116,105,110,95,109,
- 111,100,117,108,101,95,110,97,109,101,115,218,11,73,109,112,
- 111,114,116,69,114,114,111,114,169,2,114,30,0,0,0,218,
- 8,102,117,108,108,110,97,109,101,169,1,218,3,102,120,110,
- 114,10,0,0,0,114,11,0,0,0,218,25,95,114,101,113,
- 117,105,114,101,115,95,98,117,105,108,116,105,110,95,119,114,
- 97,112,112,101,114,232,0,0,0,115,10,0,0,0,0,1,
- 10,1,10,1,2,255,6,2,122,52,95,114,101,113,117,105,
- 114,101,115,95,98,117,105,108,116,105,110,46,60,108,111,99,
- 97,108,115,62,46,95,114,101,113,117,105,114,101,115,95,98,
- 117,105,108,116,105,110,95,119,114,97,112,112,101,114,169,1,
- 114,12,0,0,0,41,2,114,83,0,0,0,114,84,0,0,
- 0,114,10,0,0,0,114,82,0,0,0,114,11,0,0,0,
- 218,17,95,114,101,113,117,105,114,101,115,95,98,117,105,108,
- 116,105,110,230,0,0,0,115,6,0,0,0,0,2,12,5,
- 10,1,114,86,0,0,0,99,1,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,0,0,3,0,0,0,3,0,0,0,
- 115,26,0,0,0,135,0,102,1,100,1,100,2,132,8,125,
- 1,116,0,124,1,136,0,131,2,1,0,124,1,83,0,41,
- 3,122,47,68,101,99,111,114,97,116,111,114,32,116,111,32,
- 118,101,114,105,102,121,32,116,104,101,32,110,97,109,101,100,
- 32,109,111,100,117,108,101,32,105,115,32,102,114,111,122,101,
- 110,46,99,2,0,0,0,0,0,0,0,0,0,0,0,2,
- 0,0,0,4,0,0,0,19,0,0,0,115,38,0,0,0,
- 116,0,160,1,124,1,161,1,115,28,116,2,124,1,155,2,
- 100,1,157,2,124,1,100,2,141,2,130,1,136,0,124,0,
- 124,1,131,2,83,0,169,3,78,122,23,32,105,115,32,110,
- 111,116,32,97,32,102,114,111,122,101,110,32,109,111,100,117,
- 108,101,114,16,0,0,0,41,3,114,56,0,0,0,218,9,
- 105,115,95,102,114,111,122,101,110,114,79,0,0,0,114,80,
- 0,0,0,114,82,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,218,24,95,114,101,113,117,105,114,101,115,95,102,114,
- 111,122,101,110,95,119,114,97,112,112,101,114,243,0,0,0,
- 115,10,0,0,0,0,1,10,1,10,1,2,255,6,2,122,
- 50,95,114,101,113,117,105,114,101,115,95,102,114,111,122,101,
- 110,46,60,108,111,99,97,108,115,62,46,95,114,101,113,117,
- 105,114,101,115,95,102,114,111,122,101,110,95,119,114,97,112,
- 112,101,114,114,85,0,0,0,41,2,114,83,0,0,0,114,
- 89,0,0,0,114,10,0,0,0,114,82,0,0,0,114,11,
- 0,0,0,218,16,95,114,101,113,117,105,114,101,115,95,102,
- 114,111,122,101,110,241,0,0,0,115,6,0,0,0,0,2,
- 12,5,10,1,114,90,0,0,0,99,2,0,0,0,0,0,
- 0,0,0,0,0,0,4,0,0,0,3,0,0,0,67,0,
- 0,0,115,62,0,0,0,116,0,124,1,124,0,131,2,125,
- 2,124,1,116,1,106,2,107,6,114,50,116,1,106,2,124,
- 1,25,0,125,3,116,3,124,2,124,3,131,2,1,0,116,
- 1,106,2,124,1,25,0,83,0,116,4,124,2,131,1,83,
- 0,100,1,83,0,41,2,122,128,76,111,97,100,32,116,104,
- 101,32,115,112,101,99,105,102,105,101,100,32,109,111,100,117,
- 108,101,32,105,110,116,111,32,115,121,115,46,109,111,100,117,
- 108,101,115,32,97,110,100,32,114,101,116,117,114,110,32,105,
- 116,46,10,10,32,32,32,32,84,104,105,115,32,109,101,116,
- 104,111,100,32,105,115,32,100,101,112,114,101,99,97,116,101,
- 100,46,32,32,85,115,101,32,108,111,97,100,101,114,46,101,
- 120,101,99,95,109,111,100,117,108,101,32,105,110,115,116,101,
- 97,100,46,10,10,32,32,32,32,78,41,5,218,16,115,112,
- 101,99,95,102,114,111,109,95,108,111,97,100,101,114,114,15,
- 0,0,0,218,7,109,111,100,117,108,101,115,218,5,95,101,
- 120,101,99,218,5,95,108,111,97,100,41,4,114,30,0,0,
- 0,114,81,0,0,0,218,4,115,112,101,99,218,6,109,111,
- 100,117,108,101,114,10,0,0,0,114,10,0,0,0,114,11,
- 0,0,0,218,17,95,108,111,97,100,95,109,111,100,117,108,
- 101,95,115,104,105,109,253,0,0,0,115,12,0,0,0,0,
- 6,10,1,10,1,10,1,10,1,10,2,114,97,0,0,0,
- 99,1,0,0,0,0,0,0,0,0,0,0,0,5,0,0,
- 0,8,0,0,0,67,0,0,0,115,240,0,0,0,116,0,
- 124,0,100,1,100,0,131,3,125,1,116,1,124,1,100,2,
- 131,2,114,56,122,12,124,1,160,2,124,0,161,1,87,0,
- 83,0,4,0,116,3,107,10,114,54,1,0,1,0,1,0,
- 89,0,110,2,88,0,122,10,124,0,106,4,125,2,87,0,
- 110,20,4,0,116,5,107,10,114,86,1,0,1,0,1,0,
- 89,0,110,18,88,0,124,2,100,0,107,9,114,104,116,6,
- 124,2,131,1,83,0,122,10,124,0,106,7,125,3,87,0,
- 110,24,4,0,116,5,107,10,114,138,1,0,1,0,1,0,
- 100,3,125,3,89,0,110,2,88,0,122,10,124,0,106,8,
- 125,4,87,0,110,66,4,0,116,5,107,10,114,216,1,0,
- 1,0,1,0,124,1,100,0,107,8,114,190,100,4,124,3,
- 155,2,100,5,157,3,6,0,89,0,83,0,100,4,124,3,
- 155,2,100,6,124,1,155,2,100,7,157,5,6,0,89,0,
- 83,0,89,0,110,20,88,0,100,4,124,3,155,2,100,8,
- 124,4,155,2,100,5,157,5,83,0,100,0,83,0,41,9,
- 78,218,10,95,95,108,111,97,100,101,114,95,95,218,11,109,
- 111,100,117,108,101,95,114,101,112,114,250,1,63,250,8,60,
- 109,111,100,117,108,101,32,250,1,62,250,2,32,40,250,2,
- 41,62,250,6,32,102,114,111,109,32,41,9,114,6,0,0,
- 0,114,4,0,0,0,114,99,0,0,0,218,9,69,120,99,
- 101,112,116,105,111,110,218,8,95,95,115,112,101,99,95,95,
- 218,14,65,116,116,114,105,98,117,116,101,69,114,114,111,114,
- 218,22,95,109,111,100,117,108,101,95,114,101,112,114,95,102,
- 114,111,109,95,115,112,101,99,114,1,0,0,0,218,8,95,
- 95,102,105,108,101,95,95,41,5,114,96,0,0,0,218,6,
- 108,111,97,100,101,114,114,95,0,0,0,114,17,0,0,0,
- 218,8,102,105,108,101,110,97,109,101,114,10,0,0,0,114,
- 10,0,0,0,114,11,0,0,0,218,12,95,109,111,100,117,
- 108,101,95,114,101,112,114,13,1,0,0,115,46,0,0,0,
- 0,2,12,1,10,4,2,1,12,1,14,1,6,1,2,1,
- 10,1,14,1,6,2,8,1,8,4,2,1,10,1,14,1,
- 10,1,2,1,10,1,14,1,8,1,16,2,28,2,114,113,
- 0,0,0,99,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,0,0,4,0,0,0,64,0,0,0,115,114,0,0,
- 0,101,0,90,1,100,0,90,2,100,1,90,3,100,2,100,
- 2,100,2,100,3,156,3,100,4,100,5,132,2,90,4,100,
- 6,100,7,132,0,90,5,100,8,100,9,132,0,90,6,101,
- 7,100,10,100,11,132,0,131,1,90,8,101,8,106,9,100,
- 12,100,11,132,0,131,1,90,8,101,7,100,13,100,14,132,
- 0,131,1,90,10,101,7,100,15,100,16,132,0,131,1,90,
- 11,101,11,106,9,100,17,100,16,132,0,131,1,90,11,100,
- 2,83,0,41,18,218,10,77,111,100,117,108,101,83,112,101,
- 99,97,208,5,0,0,84,104,101,32,115,112,101,99,105,102,
- 105,99,97,116,105,111,110,32,102,111,114,32,97,32,109,111,
- 100,117,108,101,44,32,117,115,101,100,32,102,111,114,32,108,
- 111,97,100,105,110,103,46,10,10,32,32,32,32,65,32,109,
- 111,100,117,108,101,39,115,32,115,112,101,99,32,105,115,32,
- 116,104,101,32,115,111,117,114,99,101,32,102,111,114,32,105,
- 110,102,111,114,109,97,116,105,111,110,32,97,98,111,117,116,
- 32,116,104,101,32,109,111,100,117,108,101,46,32,32,70,111,
- 114,10,32,32,32,32,100,97,116,97,32,97,115,115,111,99,
- 105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,109,
- 111,100,117,108,101,44,32,105,110,99,108,117,100,105,110,103,
- 32,115,111,117,114,99,101,44,32,117,115,101,32,116,104,101,
- 32,115,112,101,99,39,115,10,32,32,32,32,108,111,97,100,
- 101,114,46,10,10,32,32,32,32,96,110,97,109,101,96,32,
- 105,115,32,116,104,101,32,97,98,115,111,108,117,116,101,32,
- 110,97,109,101,32,111,102,32,116,104,101,32,109,111,100,117,
- 108,101,46,32,32,96,108,111,97,100,101,114,96,32,105,115,
- 32,116,104,101,32,108,111,97,100,101,114,10,32,32,32,32,
- 116,111,32,117,115,101,32,119,104,101,110,32,108,111,97,100,
- 105,110,103,32,116,104,101,32,109,111,100,117,108,101,46,32,
- 32,96,112,97,114,101,110,116,96,32,105,115,32,116,104,101,
- 32,110,97,109,101,32,111,102,32,116,104,101,10,32,32,32,
- 32,112,97,99,107,97,103,101,32,116,104,101,32,109,111,100,
- 117,108,101,32,105,115,32,105,110,46,32,32,84,104,101,32,
- 112,97,114,101,110,116,32,105,115,32,100,101,114,105,118,101,
- 100,32,102,114,111,109,32,116,104,101,32,110,97,109,101,46,
- 10,10,32,32,32,32,96,105,115,95,112,97,99,107,97,103,
- 101,96,32,100,101,116,101,114,109,105,110,101,115,32,105,102,
- 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,99,
- 111,110,115,105,100,101,114,101,100,32,97,32,112,97,99,107,
- 97,103,101,32,111,114,10,32,32,32,32,110,111,116,46,32,
- 32,79,110,32,109,111,100,117,108,101,115,32,116,104,105,115,
- 32,105,115,32,114,101,102,108,101,99,116,101,100,32,98,121,
- 32,116,104,101,32,96,95,95,112,97,116,104,95,95,96,32,
- 97,116,116,114,105,98,117,116,101,46,10,10,32,32,32,32,
- 96,111,114,105,103,105,110,96,32,105,115,32,116,104,101,32,
- 115,112,101,99,105,102,105,99,32,108,111,99,97,116,105,111,
- 110,32,117,115,101,100,32,98,121,32,116,104,101,32,108,111,
- 97,100,101,114,32,102,114,111,109,32,119,104,105,99,104,32,
- 116,111,10,32,32,32,32,108,111,97,100,32,116,104,101,32,
- 109,111,100,117,108,101,44,32,105,102,32,116,104,97,116,32,
- 105,110,102,111,114,109,97,116,105,111,110,32,105,115,32,97,
- 118,97,105,108,97,98,108,101,46,32,32,87,104,101,110,32,
- 102,105,108,101,110,97,109,101,32,105,115,10,32,32,32,32,
- 115,101,116,44,32,111,114,105,103,105,110,32,119,105,108,108,
- 32,109,97,116,99,104,46,10,10,32,32,32,32,96,104,97,
- 115,95,108,111,99,97,116,105,111,110,96,32,105,110,100,105,
- 99,97,116,101,115,32,116,104,97,116,32,97,32,115,112,101,
- 99,39,115,32,34,111,114,105,103,105,110,34,32,114,101,102,
- 108,101,99,116,115,32,97,32,108,111,99,97,116,105,111,110,
- 46,10,32,32,32,32,87,104,101,110,32,116,104,105,115,32,
- 105,115,32,84,114,117,101,44,32,96,95,95,102,105,108,101,
- 95,95,96,32,97,116,116,114,105,98,117,116,101,32,111,102,
- 32,116,104,101,32,109,111,100,117,108,101,32,105,115,32,115,
- 101,116,46,10,10,32,32,32,32,96,99,97,99,104,101,100,
- 96,32,105,115,32,116,104,101,32,108,111,99,97,116,105,111,
- 110,32,111,102,32,116,104,101,32,99,97,99,104,101,100,32,
- 98,121,116,101,99,111,100,101,32,102,105,108,101,44,32,105,
- 102,32,97,110,121,46,32,32,73,116,10,32,32,32,32,99,
- 111,114,114,101,115,112,111,110,100,115,32,116,111,32,116,104,
- 101,32,96,95,95,99,97,99,104,101,100,95,95,96,32,97,
- 116,116,114,105,98,117,116,101,46,10,10,32,32,32,32,96,
- 115,117,98,109,111,100,117,108,101,95,115,101,97,114,99,104,
- 95,108,111,99,97,116,105,111,110,115,96,32,105,115,32,116,
- 104,101,32,115,101,113,117,101,110,99,101,32,111,102,32,112,
- 97,116,104,32,101,110,116,114,105,101,115,32,116,111,10,32,
- 32,32,32,115,101,97,114,99,104,32,119,104,101,110,32,105,
- 109,112,111,114,116,105,110,103,32,115,117,98,109,111,100,117,
- 108,101,115,46,32,32,73,102,32,115,101,116,44,32,105,115,
- 95,112,97,99,107,97,103,101,32,115,104,111,117,108,100,32,
- 98,101,10,32,32,32,32,84,114,117,101,45,45,97,110,100,
- 32,70,97,108,115,101,32,111,116,104,101,114,119,105,115,101,
- 46,10,10,32,32,32,32,80,97,99,107,97,103,101,115,32,
- 97,114,101,32,115,105,109,112,108,121,32,109,111,100,117,108,
- 101,115,32,116,104,97,116,32,40,109,97,121,41,32,104,97,
- 118,101,32,115,117,98,109,111,100,117,108,101,115,46,32,32,
- 73,102,32,97,32,115,112,101,99,10,32,32,32,32,104,97,
- 115,32,97,32,110,111,110,45,78,111,110,101,32,118,97,108,
- 117,101,32,105,110,32,96,115,117,98,109,111,100,117,108,101,
- 95,115,101,97,114,99,104,95,108,111,99,97,116,105,111,110,
- 115,96,44,32,116,104,101,32,105,109,112,111,114,116,10,32,
- 32,32,32,115,121,115,116,101,109,32,119,105,108,108,32,99,
- 111,110,115,105,100,101,114,32,109,111,100,117,108,101,115,32,
- 108,111,97,100,101,100,32,102,114,111,109,32,116,104,101,32,
- 115,112,101,99,32,97,115,32,112,97,99,107,97,103,101,115,
- 46,10,10,32,32,32,32,79,110,108,121,32,102,105,110,100,
- 101,114,115,32,40,115,101,101,32,105,109,112,111,114,116,108,
- 105,98,46,97,98,99,46,77,101,116,97,80,97,116,104,70,
- 105,110,100,101,114,32,97,110,100,10,32,32,32,32,105,109,
- 112,111,114,116,108,105,98,46,97,98,99,46,80,97,116,104,
- 69,110,116,114,121,70,105,110,100,101,114,41,32,115,104,111,
- 117,108,100,32,109,111,100,105,102,121,32,77,111,100,117,108,
- 101,83,112,101,99,32,105,110,115,116,97,110,99,101,115,46,
- 10,10,32,32,32,32,78,41,3,218,6,111,114,105,103,105,
- 110,218,12,108,111,97,100,101,114,95,115,116,97,116,101,218,
- 10,105,115,95,112,97,99,107,97,103,101,99,3,0,0,0,
- 0,0,0,0,3,0,0,0,6,0,0,0,2,0,0,0,
- 67,0,0,0,115,54,0,0,0,124,1,124,0,95,0,124,
- 2,124,0,95,1,124,3,124,0,95,2,124,4,124,0,95,
- 3,124,5,114,32,103,0,110,2,100,0,124,0,95,4,100,
- 1,124,0,95,5,100,0,124,0,95,6,100,0,83,0,41,
- 2,78,70,41,7,114,17,0,0,0,114,111,0,0,0,114,
- 115,0,0,0,114,116,0,0,0,218,26,115,117,98,109,111,
- 100,117,108,101,95,115,101,97,114,99,104,95,108,111,99,97,
- 116,105,111,110,115,218,13,95,115,101,116,95,102,105,108,101,
- 97,116,116,114,218,7,95,99,97,99,104,101,100,41,6,114,
- 30,0,0,0,114,17,0,0,0,114,111,0,0,0,114,115,
- 0,0,0,114,116,0,0,0,114,117,0,0,0,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,114,31,0,0,
- 0,86,1,0,0,115,14,0,0,0,0,2,6,1,6,1,
- 6,1,6,1,14,3,6,1,122,19,77,111,100,117,108,101,
- 83,112,101,99,46,95,95,105,110,105,116,95,95,99,1,0,
- 0,0,0,0,0,0,0,0,0,0,2,0,0,0,5,0,
- 0,0,67,0,0,0,115,106,0,0,0,100,1,124,0,106,
- 0,155,2,157,2,100,2,124,0,106,1,155,2,157,2,103,
- 2,125,1,124,0,106,2,100,0,107,9,114,52,124,1,160,
- 3,100,3,124,0,106,2,155,2,157,2,161,1,1,0,124,
- 0,106,4,100,0,107,9,114,80,124,1,160,3,100,4,124,
- 0,106,4,155,0,157,2,161,1,1,0,124,0,106,5,106,
- 6,155,0,100,5,100,6,160,7,124,1,161,1,155,0,100,
- 7,157,4,83,0,41,8,78,122,5,110,97,109,101,61,122,
- 7,108,111,97,100,101,114,61,122,7,111,114,105,103,105,110,
- 61,122,27,115,117,98,109,111,100,117,108,101,95,115,101,97,
- 114,99,104,95,108,111,99,97,116,105,111,110,115,61,250,1,
- 40,122,2,44,32,250,1,41,41,8,114,17,0,0,0,114,
- 111,0,0,0,114,115,0,0,0,218,6,97,112,112,101,110,
- 100,114,118,0,0,0,218,9,95,95,99,108,97,115,115,95,
- 95,114,1,0,0,0,218,4,106,111,105,110,41,2,114,30,
- 0,0,0,114,54,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,114,47,0,0,0,98,1,0,0,
- 115,16,0,0,0,0,1,10,1,10,255,4,2,10,1,18,
- 1,10,1,18,1,122,19,77,111,100,117,108,101,83,112,101,
- 99,46,95,95,114,101,112,114,95,95,99,2,0,0,0,0,
- 0,0,0,0,0,0,0,3,0,0,0,8,0,0,0,67,
- 0,0,0,115,108,0,0,0,124,0,106,0,125,2,122,72,
- 124,0,106,1,124,1,106,1,107,2,111,76,124,0,106,2,
- 124,1,106,2,107,2,111,76,124,0,106,3,124,1,106,3,
- 107,2,111,76,124,2,124,1,106,0,107,2,111,76,124,0,
- 106,4,124,1,106,4,107,2,111,76,124,0,106,5,124,1,
- 106,5,107,2,87,0,83,0,4,0,116,6,107,10,114,102,
- 1,0,1,0,1,0,116,7,6,0,89,0,83,0,88,0,
- 100,0,83,0,114,13,0,0,0,41,8,114,118,0,0,0,
- 114,17,0,0,0,114,111,0,0,0,114,115,0,0,0,218,
- 6,99,97,99,104,101,100,218,12,104,97,115,95,108,111,99,
- 97,116,105,111,110,114,108,0,0,0,218,14,78,111,116,73,
- 109,112,108,101,109,101,110,116,101,100,41,3,114,30,0,0,
- 0,90,5,111,116,104,101,114,90,4,115,109,115,108,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,218,6,95,
- 95,101,113,95,95,107,1,0,0,115,30,0,0,0,0,1,
- 6,1,2,1,12,1,10,255,2,2,10,254,2,3,8,253,
- 2,4,10,252,2,5,10,251,4,6,14,1,122,17,77,111,
- 100,117,108,101,83,112,101,99,46,95,95,101,113,95,95,99,
- 1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,
- 3,0,0,0,67,0,0,0,115,58,0,0,0,124,0,106,
- 0,100,0,107,8,114,52,124,0,106,1,100,0,107,9,114,
- 52,124,0,106,2,114,52,116,3,100,0,107,8,114,38,116,
- 4,130,1,116,3,160,5,124,0,106,1,161,1,124,0,95,
- 0,124,0,106,0,83,0,114,13,0,0,0,41,6,114,120,
- 0,0,0,114,115,0,0,0,114,119,0,0,0,218,19,95,
- 98,111,111,116,115,116,114,97,112,95,101,120,116,101,114,110,
- 97,108,218,19,78,111,116,73,109,112,108,101,109,101,110,116,
- 101,100,69,114,114,111,114,90,11,95,103,101,116,95,99,97,
- 99,104,101,100,114,46,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,114,126,0,0,0,119,1,0,
- 0,115,12,0,0,0,0,2,10,1,16,1,8,1,4,1,
- 14,1,122,17,77,111,100,117,108,101,83,112,101,99,46,99,
- 97,99,104,101,100,99,2,0,0,0,0,0,0,0,0,0,
- 0,0,2,0,0,0,2,0,0,0,67,0,0,0,115,10,
- 0,0,0,124,1,124,0,95,0,100,0,83,0,114,13,0,
- 0,0,41,1,114,120,0,0,0,41,2,114,30,0,0,0,
- 114,126,0,0,0,114,10,0,0,0,114,10,0,0,0,114,
- 11,0,0,0,114,126,0,0,0,128,1,0,0,115,2,0,
- 0,0,0,2,99,1,0,0,0,0,0,0,0,0,0,0,
- 0,1,0,0,0,3,0,0,0,67,0,0,0,115,36,0,
- 0,0,124,0,106,0,100,1,107,8,114,26,124,0,106,1,
- 160,2,100,2,161,1,100,3,25,0,83,0,124,0,106,1,
- 83,0,100,1,83,0,41,4,122,32,84,104,101,32,110,97,
- 109,101,32,111,102,32,116,104,101,32,109,111,100,117,108,101,
- 39,115,32,112,97,114,101,110,116,46,78,218,1,46,114,22,
- 0,0,0,41,3,114,118,0,0,0,114,17,0,0,0,218,
- 10,114,112,97,114,116,105,116,105,111,110,114,46,0,0,0,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,
- 6,112,97,114,101,110,116,132,1,0,0,115,6,0,0,0,
- 0,3,10,1,16,2,122,17,77,111,100,117,108,101,83,112,
- 101,99,46,112,97,114,101,110,116,99,1,0,0,0,0,0,
- 0,0,0,0,0,0,1,0,0,0,1,0,0,0,67,0,
- 0,0,115,6,0,0,0,124,0,106,0,83,0,114,13,0,
- 0,0,41,1,114,119,0,0,0,114,46,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,114,127,0,
- 0,0,140,1,0,0,115,2,0,0,0,0,2,122,23,77,
- 111,100,117,108,101,83,112,101,99,46,104,97,115,95,108,111,
- 99,97,116,105,111,110,99,2,0,0,0,0,0,0,0,0,
- 0,0,0,2,0,0,0,2,0,0,0,67,0,0,0,115,
- 14,0,0,0,116,0,124,1,131,1,124,0,95,1,100,0,
- 83,0,114,13,0,0,0,41,2,218,4,98,111,111,108,114,
- 119,0,0,0,41,2,114,30,0,0,0,218,5,118,97,108,
- 117,101,114,10,0,0,0,114,10,0,0,0,114,11,0,0,
- 0,114,127,0,0,0,144,1,0,0,115,2,0,0,0,0,
- 2,41,12,114,1,0,0,0,114,0,0,0,0,114,2,0,
- 0,0,114,3,0,0,0,114,31,0,0,0,114,47,0,0,
- 0,114,129,0,0,0,218,8,112,114,111,112,101,114,116,121,
- 114,126,0,0,0,218,6,115,101,116,116,101,114,114,134,0,
- 0,0,114,127,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,10,0,0,0,114,11,0,0,0,114,114,0,0,0,
- 49,1,0,0,115,32,0,0,0,8,1,4,36,4,1,2,
- 255,12,12,8,9,8,12,2,1,10,8,4,1,10,3,2,
- 1,10,7,2,1,10,3,4,1,114,114,0,0,0,169,2,
- 114,115,0,0,0,114,117,0,0,0,99,2,0,0,0,0,
- 0,0,0,2,0,0,0,6,0,0,0,8,0,0,0,67,
- 0,0,0,115,154,0,0,0,116,0,124,1,100,1,131,2,
- 114,74,116,1,100,2,107,8,114,22,116,2,130,1,116,1,
- 106,3,125,4,124,3,100,2,107,8,114,48,124,4,124,0,
- 124,1,100,3,141,2,83,0,124,3,114,56,103,0,110,2,
- 100,2,125,5,124,4,124,0,124,1,124,5,100,4,141,3,
- 83,0,124,3,100,2,107,8,114,138,116,0,124,1,100,5,
- 131,2,114,134,122,14,124,1,160,4,124,0,161,1,125,3,
- 87,0,113,138,4,0,116,5,107,10,114,130,1,0,1,0,
- 1,0,100,2,125,3,89,0,113,138,88,0,110,4,100,6,
- 125,3,116,6,124,0,124,1,124,2,124,3,100,7,141,4,
- 83,0,41,8,122,53,82,101,116,117,114,110,32,97,32,109,
- 111,100,117,108,101,32,115,112,101,99,32,98,97,115,101,100,
- 32,111,110,32,118,97,114,105,111,117,115,32,108,111,97,100,
- 101,114,32,109,101,116,104,111,100,115,46,90,12,103,101,116,
- 95,102,105,108,101,110,97,109,101,78,41,1,114,111,0,0,
- 0,41,2,114,111,0,0,0,114,118,0,0,0,114,117,0,
- 0,0,70,114,139,0,0,0,41,7,114,4,0,0,0,114,
- 130,0,0,0,114,131,0,0,0,218,23,115,112,101,99,95,
- 102,114,111,109,95,102,105,108,101,95,108,111,99,97,116,105,
- 111,110,114,117,0,0,0,114,79,0,0,0,114,114,0,0,
- 0,41,6,114,17,0,0,0,114,111,0,0,0,114,115,0,
- 0,0,114,117,0,0,0,114,140,0,0,0,90,6,115,101,
- 97,114,99,104,114,10,0,0,0,114,10,0,0,0,114,11,
- 0,0,0,114,91,0,0,0,149,1,0,0,115,36,0,0,
- 0,0,2,10,1,8,1,4,1,6,2,8,1,12,1,12,
- 1,6,1,2,255,6,3,8,1,10,1,2,1,14,1,14,
- 1,12,3,4,2,114,91,0,0,0,99,3,0,0,0,0,
- 0,0,0,0,0,0,0,8,0,0,0,8,0,0,0,67,
- 0,0,0,115,56,1,0,0,122,10,124,0,106,0,125,3,
- 87,0,110,20,4,0,116,1,107,10,114,30,1,0,1,0,
- 1,0,89,0,110,14,88,0,124,3,100,0,107,9,114,44,
- 124,3,83,0,124,0,106,2,125,4,124,1,100,0,107,8,
- 114,90,122,10,124,0,106,3,125,1,87,0,110,20,4,0,
- 116,1,107,10,114,88,1,0,1,0,1,0,89,0,110,2,
- 88,0,122,10,124,0,106,4,125,5,87,0,110,24,4,0,
- 116,1,107,10,114,124,1,0,1,0,1,0,100,0,125,5,
- 89,0,110,2,88,0,124,2,100,0,107,8,114,184,124,5,
- 100,0,107,8,114,180,122,10,124,1,106,5,125,2,87,0,
- 113,184,4,0,116,1,107,10,114,176,1,0,1,0,1,0,
- 100,0,125,2,89,0,113,184,88,0,110,4,124,5,125,2,
- 122,10,124,0,106,6,125,6,87,0,110,24,4,0,116,1,
- 107,10,114,218,1,0,1,0,1,0,100,0,125,6,89,0,
- 110,2,88,0,122,14,116,7,124,0,106,8,131,1,125,7,
- 87,0,110,26,4,0,116,1,107,10,144,1,114,4,1,0,
- 1,0,1,0,100,0,125,7,89,0,110,2,88,0,116,9,
- 124,4,124,1,124,2,100,1,141,3,125,3,124,5,100,0,
- 107,8,144,1,114,34,100,2,110,2,100,3,124,3,95,10,
- 124,6,124,3,95,11,124,7,124,3,95,12,124,3,83,0,
- 41,4,78,169,1,114,115,0,0,0,70,84,41,13,114,107,
- 0,0,0,114,108,0,0,0,114,1,0,0,0,114,98,0,
- 0,0,114,110,0,0,0,218,7,95,79,82,73,71,73,78,
- 218,10,95,95,99,97,99,104,101,100,95,95,218,4,108,105,
- 115,116,218,8,95,95,112,97,116,104,95,95,114,114,0,0,
- 0,114,119,0,0,0,114,126,0,0,0,114,118,0,0,0,
- 41,8,114,96,0,0,0,114,111,0,0,0,114,115,0,0,
- 0,114,95,0,0,0,114,17,0,0,0,90,8,108,111,99,
- 97,116,105,111,110,114,126,0,0,0,114,118,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,17,
- 95,115,112,101,99,95,102,114,111,109,95,109,111,100,117,108,
- 101,175,1,0,0,115,72,0,0,0,0,2,2,1,10,1,
- 14,1,6,2,8,1,4,2,6,1,8,1,2,1,10,1,
- 14,2,6,1,2,1,10,1,14,1,10,1,8,1,8,1,
- 2,1,10,1,14,1,12,2,4,1,2,1,10,1,14,1,
- 10,1,2,1,14,1,16,1,10,2,14,1,20,1,6,1,
- 6,1,114,146,0,0,0,70,169,1,218,8,111,118,101,114,
- 114,105,100,101,99,2,0,0,0,0,0,0,0,1,0,0,
- 0,5,0,0,0,8,0,0,0,67,0,0,0,115,226,1,
- 0,0,124,2,115,20,116,0,124,1,100,1,100,0,131,3,
- 100,0,107,8,114,54,122,12,124,0,106,1,124,1,95,2,
- 87,0,110,20,4,0,116,3,107,10,114,52,1,0,1,0,
- 1,0,89,0,110,2,88,0,124,2,115,74,116,0,124,1,
- 100,2,100,0,131,3,100,0,107,8,114,178,124,0,106,4,
- 125,3,124,3,100,0,107,8,114,146,124,0,106,5,100,0,
- 107,9,114,146,116,6,100,0,107,8,114,110,116,7,130,1,
- 116,6,106,8,125,4,124,4,160,9,124,4,161,1,125,3,
- 124,0,106,5,124,3,95,10,124,3,124,0,95,4,100,0,
- 124,1,95,11,122,10,124,3,124,1,95,12,87,0,110,20,
- 4,0,116,3,107,10,114,176,1,0,1,0,1,0,89,0,
- 110,2,88,0,124,2,115,198,116,0,124,1,100,3,100,0,
- 131,3,100,0,107,8,114,232,122,12,124,0,106,13,124,1,
- 95,14,87,0,110,20,4,0,116,3,107,10,114,230,1,0,
- 1,0,1,0,89,0,110,2,88,0,122,10,124,0,124,1,
- 95,15,87,0,110,22,4,0,116,3,107,10,144,1,114,8,
- 1,0,1,0,1,0,89,0,110,2,88,0,124,2,144,1,
- 115,34,116,0,124,1,100,4,100,0,131,3,100,0,107,8,
- 144,1,114,82,124,0,106,5,100,0,107,9,144,1,114,82,
- 122,12,124,0,106,5,124,1,95,16,87,0,110,22,4,0,
- 116,3,107,10,144,1,114,80,1,0,1,0,1,0,89,0,
- 110,2,88,0,124,0,106,17,144,1,114,222,124,2,144,1,
- 115,114,116,0,124,1,100,5,100,0,131,3,100,0,107,8,
- 144,1,114,150,122,12,124,0,106,18,124,1,95,11,87,0,
- 110,22,4,0,116,3,107,10,144,1,114,148,1,0,1,0,
- 1,0,89,0,110,2,88,0,124,2,144,1,115,174,116,0,
- 124,1,100,6,100,0,131,3,100,0,107,8,144,1,114,222,
- 124,0,106,19,100,0,107,9,144,1,114,222,122,12,124,0,
- 106,19,124,1,95,20,87,0,110,22,4,0,116,3,107,10,
- 144,1,114,220,1,0,1,0,1,0,89,0,110,2,88,0,
- 124,1,83,0,41,7,78,114,1,0,0,0,114,98,0,0,
- 0,218,11,95,95,112,97,99,107,97,103,101,95,95,114,145,
- 0,0,0,114,110,0,0,0,114,143,0,0,0,41,21,114,
- 6,0,0,0,114,17,0,0,0,114,1,0,0,0,114,108,
- 0,0,0,114,111,0,0,0,114,118,0,0,0,114,130,0,
- 0,0,114,131,0,0,0,218,16,95,78,97,109,101,115,112,
- 97,99,101,76,111,97,100,101,114,218,7,95,95,110,101,119,
- 95,95,90,5,95,112,97,116,104,114,110,0,0,0,114,98,
- 0,0,0,114,134,0,0,0,114,149,0,0,0,114,107,0,
- 0,0,114,145,0,0,0,114,127,0,0,0,114,115,0,0,
- 0,114,126,0,0,0,114,143,0,0,0,41,5,114,95,0,
- 0,0,114,96,0,0,0,114,148,0,0,0,114,111,0,0,
- 0,114,150,0,0,0,114,10,0,0,0,114,10,0,0,0,
- 114,11,0,0,0,218,18,95,105,110,105,116,95,109,111,100,
- 117,108,101,95,97,116,116,114,115,220,1,0,0,115,96,0,
- 0,0,0,4,20,1,2,1,12,1,14,1,6,2,20,1,
- 6,1,8,2,10,1,8,1,4,1,6,2,10,1,8,1,
- 6,11,6,1,2,1,10,1,14,1,6,2,20,1,2,1,
- 12,1,14,1,6,2,2,1,10,1,16,1,6,2,24,1,
- 12,1,2,1,12,1,16,1,6,2,8,1,24,1,2,1,
- 12,1,16,1,6,2,24,1,12,1,2,1,12,1,16,1,
- 6,1,114,152,0,0,0,99,1,0,0,0,0,0,0,0,
- 0,0,0,0,2,0,0,0,3,0,0,0,67,0,0,0,
- 115,82,0,0,0,100,1,125,1,116,0,124,0,106,1,100,
- 2,131,2,114,30,124,0,106,1,160,2,124,0,161,1,125,
- 1,110,20,116,0,124,0,106,1,100,3,131,2,114,50,116,
- 3,100,4,131,1,130,1,124,1,100,1,107,8,114,68,116,
- 4,124,0,106,5,131,1,125,1,116,6,124,0,124,1,131,
- 2,1,0,124,1,83,0,41,5,122,43,67,114,101,97,116,
- 101,32,97,32,109,111,100,117,108,101,32,98,97,115,101,100,
- 32,111,110,32,116,104,101,32,112,114,111,118,105,100,101,100,
- 32,115,112,101,99,46,78,218,13,99,114,101,97,116,101,95,
- 109,111,100,117,108,101,218,11,101,120,101,99,95,109,111,100,
- 117,108,101,122,66,108,111,97,100,101,114,115,32,116,104,97,
- 116,32,100,101,102,105,110,101,32,101,120,101,99,95,109,111,
- 100,117,108,101,40,41,32,109,117,115,116,32,97,108,115,111,
- 32,100,101,102,105,110,101,32,99,114,101,97,116,101,95,109,
- 111,100,117,108,101,40,41,41,7,114,4,0,0,0,114,111,
- 0,0,0,114,153,0,0,0,114,79,0,0,0,114,18,0,
- 0,0,114,17,0,0,0,114,152,0,0,0,169,2,114,95,
- 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,16,109,111,100,117,108,101,95,
- 102,114,111,109,95,115,112,101,99,36,2,0,0,115,18,0,
- 0,0,0,3,4,1,12,3,14,1,12,1,8,2,8,1,
- 10,1,10,1,114,156,0,0,0,99,1,0,0,0,0,0,
- 0,0,0,0,0,0,2,0,0,0,5,0,0,0,67,0,
- 0,0,115,126,0,0,0,124,0,106,0,100,1,107,8,114,
- 14,100,2,110,4,124,0,106,0,125,1,124,0,106,1,100,
- 1,107,8,114,74,124,0,106,2,100,1,107,8,114,52,100,
- 3,124,1,155,2,100,4,157,3,83,0,100,3,124,1,155,
- 2,100,5,124,0,106,2,155,2,100,6,157,5,83,0,110,
- 48,124,0,106,3,114,100,100,3,124,1,155,2,100,7,124,
- 0,106,1,155,2,100,4,157,5,83,0,100,3,124,0,106,
- 0,155,2,100,5,124,0,106,1,155,0,100,6,157,5,83,
- 0,100,1,83,0,41,8,122,38,82,101,116,117,114,110,32,
- 116,104,101,32,114,101,112,114,32,116,111,32,117,115,101,32,
- 102,111,114,32,116,104,101,32,109,111,100,117,108,101,46,78,
- 114,100,0,0,0,114,101,0,0,0,114,102,0,0,0,114,
- 103,0,0,0,114,104,0,0,0,114,105,0,0,0,41,4,
- 114,17,0,0,0,114,115,0,0,0,114,111,0,0,0,114,
- 127,0,0,0,41,2,114,95,0,0,0,114,17,0,0,0,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,
- 109,0,0,0,53,2,0,0,115,16,0,0,0,0,3,20,
- 1,10,1,10,1,12,2,22,2,6,1,20,2,114,109,0,
- 0,0,99,2,0,0,0,0,0,0,0,0,0,0,0,4,
- 0,0,0,10,0,0,0,67,0,0,0,115,206,0,0,0,
- 124,0,106,0,125,2,116,1,124,2,131,1,143,182,1,0,
- 116,2,106,3,160,4,124,2,161,1,124,1,107,9,114,56,
- 100,1,124,2,155,2,100,2,157,3,125,3,116,5,124,3,
- 124,2,100,3,141,2,130,1,122,106,124,0,106,7,100,4,
- 107,8,114,108,124,0,106,8,100,4,107,8,114,92,116,5,
- 100,5,124,0,106,0,100,3,141,2,130,1,116,9,124,0,
- 124,1,100,6,100,7,141,3,1,0,110,52,116,9,124,0,
- 124,1,100,6,100,7,141,3,1,0,116,10,124,0,106,7,
- 100,8,131,2,115,148,124,0,106,7,160,11,124,2,161,1,
- 1,0,110,12,124,0,106,7,160,12,124,1,161,1,1,0,
- 87,0,53,0,116,2,106,3,160,6,124,0,106,0,161,1,
- 125,1,124,1,116,2,106,3,124,0,106,0,60,0,88,0,
- 87,0,53,0,81,0,82,0,88,0,124,1,83,0,41,9,
- 122,70,69,120,101,99,117,116,101,32,116,104,101,32,115,112,
- 101,99,39,115,32,115,112,101,99,105,102,105,101,100,32,109,
- 111,100,117,108,101,32,105,110,32,97,110,32,101,120,105,115,
- 116,105,110,103,32,109,111,100,117,108,101,39,115,32,110,97,
- 109,101,115,112,97,99,101,46,122,7,109,111,100,117,108,101,
- 32,122,19,32,110,111,116,32,105,110,32,115,121,115,46,109,
- 111,100,117,108,101,115,114,16,0,0,0,78,250,14,109,105,
- 115,115,105,110,103,32,108,111,97,100,101,114,84,114,147,0,
- 0,0,114,154,0,0,0,41,13,114,17,0,0,0,114,49,
- 0,0,0,114,15,0,0,0,114,92,0,0,0,114,34,0,
- 0,0,114,79,0,0,0,218,3,112,111,112,114,111,0,0,
- 0,114,118,0,0,0,114,152,0,0,0,114,4,0,0,0,
- 218,11,108,111,97,100,95,109,111,100,117,108,101,114,154,0,
- 0,0,41,4,114,95,0,0,0,114,96,0,0,0,114,17,
- 0,0,0,218,3,109,115,103,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,114,93,0,0,0,70,2,0,0,
- 115,34,0,0,0,0,2,6,1,10,1,16,1,12,1,12,
- 1,2,1,10,1,10,1,14,2,16,2,14,1,12,4,14,
- 2,16,4,14,1,24,1,114,93,0,0,0,99,1,0,0,
- 0,0,0,0,0,0,0,0,0,2,0,0,0,8,0,0,
- 0,67,0,0,0,115,26,1,0,0,122,18,124,0,106,0,
- 160,1,124,0,106,2,161,1,1,0,87,0,110,52,1,0,
- 1,0,1,0,124,0,106,2,116,3,106,4,107,6,114,64,
- 116,3,106,4,160,5,124,0,106,2,161,1,125,1,124,1,
- 116,3,106,4,124,0,106,2,60,0,130,0,89,0,110,2,
- 88,0,116,3,106,4,160,5,124,0,106,2,161,1,125,1,
- 124,1,116,3,106,4,124,0,106,2,60,0,116,6,124,1,
- 100,1,100,0,131,3,100,0,107,8,114,148,122,12,124,0,
- 106,0,124,1,95,7,87,0,110,20,4,0,116,8,107,10,
- 114,146,1,0,1,0,1,0,89,0,110,2,88,0,116,6,
- 124,1,100,2,100,0,131,3,100,0,107,8,114,226,122,40,
- 124,1,106,9,124,1,95,10,116,11,124,1,100,3,131,2,
- 115,202,124,0,106,2,160,12,100,4,161,1,100,5,25,0,
- 124,1,95,10,87,0,110,20,4,0,116,8,107,10,114,224,
- 1,0,1,0,1,0,89,0,110,2,88,0,116,6,124,1,
- 100,6,100,0,131,3,100,0,107,8,144,1,114,22,122,10,
- 124,0,124,1,95,13,87,0,110,22,4,0,116,8,107,10,
- 144,1,114,20,1,0,1,0,1,0,89,0,110,2,88,0,
- 124,1,83,0,41,7,78,114,98,0,0,0,114,149,0,0,
- 0,114,145,0,0,0,114,132,0,0,0,114,22,0,0,0,
- 114,107,0,0,0,41,14,114,111,0,0,0,114,159,0,0,
- 0,114,17,0,0,0,114,15,0,0,0,114,92,0,0,0,
- 114,158,0,0,0,114,6,0,0,0,114,98,0,0,0,114,
- 108,0,0,0,114,1,0,0,0,114,149,0,0,0,114,4,
- 0,0,0,114,133,0,0,0,114,107,0,0,0,114,155,0,
- 0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,
- 0,218,25,95,108,111,97,100,95,98,97,99,107,119,97,114,
- 100,95,99,111,109,112,97,116,105,98,108,101,100,2,0,0,
- 115,54,0,0,0,0,4,2,1,18,1,6,1,12,1,14,
- 1,12,1,8,3,14,1,12,1,16,1,2,1,12,1,14,
- 1,6,1,16,1,2,4,8,1,10,1,22,1,14,1,6,
- 1,18,1,2,1,10,1,16,1,6,1,114,161,0,0,0,
- 99,1,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
- 0,11,0,0,0,67,0,0,0,115,220,0,0,0,124,0,
- 106,0,100,0,107,9,114,30,116,1,124,0,106,0,100,1,
- 131,2,115,30,116,2,124,0,131,1,83,0,116,3,124,0,
- 131,1,125,1,100,2,124,0,95,4,122,162,124,1,116,5,
- 106,6,124,0,106,7,60,0,122,52,124,0,106,0,100,0,
- 107,8,114,96,124,0,106,8,100,0,107,8,114,108,116,9,
- 100,4,124,0,106,7,100,5,141,2,130,1,110,12,124,0,
- 106,0,160,10,124,1,161,1,1,0,87,0,110,50,1,0,
- 1,0,1,0,122,14,116,5,106,6,124,0,106,7,61,0,
- 87,0,110,20,4,0,116,11,107,10,114,152,1,0,1,0,
- 1,0,89,0,110,2,88,0,130,0,89,0,110,2,88,0,
- 116,5,106,6,160,12,124,0,106,7,161,1,125,1,124,1,
- 116,5,106,6,124,0,106,7,60,0,116,13,100,6,124,0,
- 106,7,124,0,106,0,131,3,1,0,87,0,53,0,100,3,
- 124,0,95,4,88,0,124,1,83,0,41,7,78,114,154,0,
- 0,0,84,70,114,157,0,0,0,114,16,0,0,0,122,18,
- 105,109,112,111,114,116,32,123,33,114,125,32,35,32,123,33,
- 114,125,41,14,114,111,0,0,0,114,4,0,0,0,114,161,
- 0,0,0,114,156,0,0,0,90,13,95,105,110,105,116,105,
- 97,108,105,122,105,110,103,114,15,0,0,0,114,92,0,0,
- 0,114,17,0,0,0,114,118,0,0,0,114,79,0,0,0,
- 114,154,0,0,0,114,62,0,0,0,114,158,0,0,0,114,
- 76,0,0,0,114,155,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,218,14,95,108,111,97,100,95,
- 117,110,108,111,99,107,101,100,137,2,0,0,115,46,0,0,
- 0,0,2,10,2,12,1,8,2,8,5,6,1,2,1,12,
- 1,2,1,10,1,10,1,16,3,16,1,6,1,2,1,14,
- 1,14,1,6,1,8,5,14,1,12,1,20,2,8,2,114,
- 162,0,0,0,99,1,0,0,0,0,0,0,0,0,0,0,
- 0,1,0,0,0,10,0,0,0,67,0,0,0,115,42,0,
- 0,0,116,0,124,0,106,1,131,1,143,22,1,0,116,2,
- 124,0,131,1,87,0,2,0,53,0,81,0,82,0,163,0,
- 83,0,81,0,82,0,88,0,100,1,83,0,41,2,122,191,
- 82,101,116,117,114,110,32,97,32,110,101,119,32,109,111,100,
- 117,108,101,32,111,98,106,101,99,116,44,32,108,111,97,100,
- 101,100,32,98,121,32,116,104,101,32,115,112,101,99,39,115,
- 32,108,111,97,100,101,114,46,10,10,32,32,32,32,84,104,
- 101,32,109,111,100,117,108,101,32,105,115,32,110,111,116,32,
- 97,100,100,101,100,32,116,111,32,105,116,115,32,112,97,114,
- 101,110,116,46,10,10,32,32,32,32,73,102,32,97,32,109,
- 111,100,117,108,101,32,105,115,32,97,108,114,101,97,100,121,
- 32,105,110,32,115,121,115,46,109,111,100,117,108,101,115,44,
- 32,116,104,97,116,32,101,120,105,115,116,105,110,103,32,109,
- 111,100,117,108,101,32,103,101,116,115,10,32,32,32,32,99,
- 108,111,98,98,101,114,101,100,46,10,10,32,32,32,32,78,
- 41,3,114,49,0,0,0,114,17,0,0,0,114,162,0,0,
- 0,41,1,114,95,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,114,94,0,0,0,179,2,0,0,
- 115,4,0,0,0,0,9,12,1,114,94,0,0,0,99,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,
- 0,0,0,64,0,0,0,115,140,0,0,0,101,0,90,1,
- 100,0,90,2,100,1,90,3,100,2,90,4,101,5,100,3,
- 100,4,132,0,131,1,90,6,101,7,100,20,100,6,100,7,
- 132,1,131,1,90,8,101,7,100,21,100,8,100,9,132,1,
- 131,1,90,9,101,7,100,10,100,11,132,0,131,1,90,10,
- 101,7,100,12,100,13,132,0,131,1,90,11,101,7,101,12,
- 100,14,100,15,132,0,131,1,131,1,90,13,101,7,101,12,
- 100,16,100,17,132,0,131,1,131,1,90,14,101,7,101,12,
- 100,18,100,19,132,0,131,1,131,1,90,15,101,7,101,16,
- 131,1,90,17,100,5,83,0,41,22,218,15,66,117,105,108,
- 116,105,110,73,109,112,111,114,116,101,114,122,144,77,101,116,
- 97,32,112,97,116,104,32,105,109,112,111,114,116,32,102,111,
- 114,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108,
- 101,115,46,10,10,32,32,32,32,65,108,108,32,109,101,116,
- 104,111,100,115,32,97,114,101,32,101,105,116,104,101,114,32,
- 99,108,97,115,115,32,111,114,32,115,116,97,116,105,99,32,
- 109,101,116,104,111,100,115,32,116,111,32,97,118,111,105,100,
- 32,116,104,101,32,110,101,101,100,32,116,111,10,32,32,32,
- 32,105,110,115,116,97,110,116,105,97,116,101,32,116,104,101,
- 32,99,108,97,115,115,46,10,10,32,32,32,32,122,8,98,
- 117,105,108,116,45,105,110,99,1,0,0,0,0,0,0,0,
- 0,0,0,0,1,0,0,0,5,0,0,0,67,0,0,0,
- 115,22,0,0,0,100,1,124,0,106,0,155,2,100,2,116,
- 1,106,2,155,0,100,3,157,5,83,0,169,4,122,115,82,
- 101,116,117,114,110,32,114,101,112,114,32,102,111,114,32,116,
- 104,101,32,109,111,100,117,108,101,46,10,10,32,32,32,32,
- 32,32,32,32,84,104,101,32,109,101,116,104,111,100,32,105,
- 115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,84,
- 104,101,32,105,109,112,111,114,116,32,109,97,99,104,105,110,
- 101,114,121,32,100,111,101,115,32,116,104,101,32,106,111,98,
- 32,105,116,115,101,108,102,46,10,10,32,32,32,32,32,32,
- 32,32,114,101,0,0,0,114,103,0,0,0,114,104,0,0,
- 0,41,3,114,1,0,0,0,114,163,0,0,0,114,142,0,
- 0,0,41,1,114,96,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,11,0,0,0,114,99,0,0,0,205,2,0,
- 0,115,2,0,0,0,0,7,122,27,66,117,105,108,116,105,
- 110,73,109,112,111,114,116,101,114,46,109,111,100,117,108,101,
- 95,114,101,112,114,78,99,4,0,0,0,0,0,0,0,0,
- 0,0,0,4,0,0,0,5,0,0,0,67,0,0,0,115,
- 46,0,0,0,124,2,100,0,107,9,114,12,100,0,83,0,
- 116,0,160,1,124,1,161,1,114,38,116,2,124,1,124,0,
- 124,0,106,3,100,1,141,3,83,0,100,0,83,0,100,0,
- 83,0,169,2,78,114,141,0,0,0,41,4,114,56,0,0,
- 0,90,10,105,115,95,98,117,105,108,116,105,110,114,91,0,
- 0,0,114,142,0,0,0,169,4,218,3,99,108,115,114,81,
- 0,0,0,218,4,112,97,116,104,218,6,116,97,114,103,101,
- 116,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,
- 218,9,102,105,110,100,95,115,112,101,99,214,2,0,0,115,
- 10,0,0,0,0,2,8,1,4,1,10,1,16,2,122,25,
- 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46,
- 102,105,110,100,95,115,112,101,99,99,3,0,0,0,0,0,
- 0,0,0,0,0,0,4,0,0,0,4,0,0,0,67,0,
- 0,0,115,30,0,0,0,124,0,160,0,124,1,124,2,161,
- 2,125,3,124,3,100,1,107,9,114,26,124,3,106,1,83,
- 0,100,1,83,0,41,2,122,175,70,105,110,100,32,116,104,
- 101,32,98,117,105,108,116,45,105,110,32,109,111,100,117,108,
- 101,46,10,10,32,32,32,32,32,32,32,32,73,102,32,39,
- 112,97,116,104,39,32,105,115,32,101,118,101,114,32,115,112,
- 101,99,105,102,105,101,100,32,116,104,101,110,32,116,104,101,
- 32,115,101,97,114,99,104,32,105,115,32,99,111,110,115,105,
- 100,101,114,101,100,32,97,32,102,97,105,108,117,114,101,46,
- 10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,109,
- 101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,97,
- 116,101,100,46,32,32,85,115,101,32,102,105,110,100,95,115,
- 112,101,99,40,41,32,105,110,115,116,101,97,100,46,10,10,
- 32,32,32,32,32,32,32,32,78,41,2,114,170,0,0,0,
- 114,111,0,0,0,41,4,114,167,0,0,0,114,81,0,0,
- 0,114,168,0,0,0,114,95,0,0,0,114,10,0,0,0,
- 114,10,0,0,0,114,11,0,0,0,218,11,102,105,110,100,
- 95,109,111,100,117,108,101,223,2,0,0,115,4,0,0,0,
- 0,9,12,1,122,27,66,117,105,108,116,105,110,73,109,112,
- 111,114,116,101,114,46,102,105,110,100,95,109,111,100,117,108,
- 101,99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,
- 0,0,4,0,0,0,67,0,0,0,115,46,0,0,0,124,
- 1,106,0,116,1,106,2,107,7,114,34,116,3,124,1,106,
- 0,155,2,100,1,157,2,124,1,106,0,100,2,141,2,130,
- 1,116,4,116,5,106,6,124,1,131,2,83,0,41,3,122,
- 24,67,114,101,97,116,101,32,97,32,98,117,105,108,116,45,
- 105,110,32,109,111,100,117,108,101,114,77,0,0,0,114,16,
- 0,0,0,41,7,114,17,0,0,0,114,15,0,0,0,114,
- 78,0,0,0,114,79,0,0,0,114,66,0,0,0,114,56,
- 0,0,0,90,14,99,114,101,97,116,101,95,98,117,105,108,
- 116,105,110,41,2,114,30,0,0,0,114,95,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,153,
- 0,0,0,235,2,0,0,115,10,0,0,0,0,3,12,1,
- 12,1,4,255,6,2,122,29,66,117,105,108,116,105,110,73,
- 109,112,111,114,116,101,114,46,99,114,101,97,116,101,95,109,
- 111,100,117,108,101,99,2,0,0,0,0,0,0,0,0,0,
- 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,16,
- 0,0,0,116,0,116,1,106,2,124,1,131,2,1,0,100,
- 1,83,0,41,2,122,22,69,120,101,99,32,97,32,98,117,
- 105,108,116,45,105,110,32,109,111,100,117,108,101,78,41,3,
- 114,66,0,0,0,114,56,0,0,0,90,12,101,120,101,99,
- 95,98,117,105,108,116,105,110,41,2,114,30,0,0,0,114,
- 96,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,
- 0,0,0,114,154,0,0,0,243,2,0,0,115,2,0,0,
- 0,0,3,122,27,66,117,105,108,116,105,110,73,109,112,111,
- 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101,
- 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
- 0,1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,
- 83,0,41,2,122,57,82,101,116,117,114,110,32,78,111,110,
- 101,32,97,115,32,98,117,105,108,116,45,105,110,32,109,111,
- 100,117,108,101,115,32,100,111,32,110,111,116,32,104,97,118,
- 101,32,99,111,100,101,32,111,98,106,101,99,116,115,46,78,
- 114,10,0,0,0,169,2,114,167,0,0,0,114,81,0,0,
- 0,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,
- 218,8,103,101,116,95,99,111,100,101,248,2,0,0,115,2,
- 0,0,0,0,4,122,24,66,117,105,108,116,105,110,73,109,
- 112,111,114,116,101,114,46,103,101,116,95,99,111,100,101,99,
- 2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,
- 1,0,0,0,67,0,0,0,115,4,0,0,0,100,1,83,
- 0,41,2,122,56,82,101,116,117,114,110,32,78,111,110,101,
- 32,97,115,32,98,117,105,108,116,45,105,110,32,109,111,100,
- 117,108,101,115,32,100,111,32,110,111,116,32,104,97,118,101,
- 32,115,111,117,114,99,101,32,99,111,100,101,46,78,114,10,
- 0,0,0,114,172,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,10,103,101,116,95,115,111,117,
- 114,99,101,254,2,0,0,115,2,0,0,0,0,4,122,26,
- 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46,
- 103,101,116,95,115,111,117,114,99,101,99,2,0,0,0,0,
- 0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,67,
- 0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,52,
- 82,101,116,117,114,110,32,70,97,108,115,101,32,97,115,32,
- 98,117,105,108,116,45,105,110,32,109,111,100,117,108,101,115,
- 32,97,114,101,32,110,101,118,101,114,32,112,97,99,107,97,
- 103,101,115,46,70,114,10,0,0,0,114,172,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,117,
- 0,0,0,4,3,0,0,115,2,0,0,0,0,4,122,26,
- 66,117,105,108,116,105,110,73,109,112,111,114,116,101,114,46,
- 105,115,95,112,97,99,107,97,103,101,41,2,78,78,41,1,
- 78,41,18,114,1,0,0,0,114,0,0,0,0,114,2,0,
- 0,0,114,3,0,0,0,114,142,0,0,0,218,12,115,116,
- 97,116,105,99,109,101,116,104,111,100,114,99,0,0,0,218,
- 11,99,108,97,115,115,109,101,116,104,111,100,114,170,0,0,
- 0,114,171,0,0,0,114,153,0,0,0,114,154,0,0,0,
- 114,86,0,0,0,114,173,0,0,0,114,174,0,0,0,114,
- 117,0,0,0,114,97,0,0,0,114,159,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,114,163,0,0,0,194,2,0,0,115,44,0,0,0,
- 8,2,4,7,4,2,2,1,10,8,2,1,12,8,2,1,
- 12,11,2,1,10,7,2,1,10,4,2,1,2,1,12,4,
- 2,1,2,1,12,4,2,1,2,1,12,4,114,163,0,0,
- 0,99,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
- 0,0,4,0,0,0,64,0,0,0,115,144,0,0,0,101,
- 0,90,1,100,0,90,2,100,1,90,3,100,2,90,4,101,
- 5,100,3,100,4,132,0,131,1,90,6,101,7,100,22,100,
- 6,100,7,132,1,131,1,90,8,101,7,100,23,100,8,100,
- 9,132,1,131,1,90,9,101,7,100,10,100,11,132,0,131,
- 1,90,10,101,5,100,12,100,13,132,0,131,1,90,11,101,
- 7,100,14,100,15,132,0,131,1,90,12,101,7,101,13,100,
- 16,100,17,132,0,131,1,131,1,90,14,101,7,101,13,100,
- 18,100,19,132,0,131,1,131,1,90,15,101,7,101,13,100,
- 20,100,21,132,0,131,1,131,1,90,16,100,5,83,0,41,
- 24,218,14,70,114,111,122,101,110,73,109,112,111,114,116,101,
- 114,122,142,77,101,116,97,32,112,97,116,104,32,105,109,112,
- 111,114,116,32,102,111,114,32,102,114,111,122,101,110,32,109,
- 111,100,117,108,101,115,46,10,10,32,32,32,32,65,108,108,
- 32,109,101,116,104,111,100,115,32,97,114,101,32,101,105,116,
- 104,101,114,32,99,108,97,115,115,32,111,114,32,115,116,97,
- 116,105,99,32,109,101,116,104,111,100,115,32,116,111,32,97,
- 118,111,105,100,32,116,104,101,32,110,101,101,100,32,116,111,
- 10,32,32,32,32,105,110,115,116,97,110,116,105,97,116,101,
- 32,116,104,101,32,99,108,97,115,115,46,10,10,32,32,32,
- 32,90,6,102,114,111,122,101,110,99,1,0,0,0,0,0,
- 0,0,0,0,0,0,1,0,0,0,5,0,0,0,67,0,
- 0,0,115,22,0,0,0,100,1,124,0,106,0,155,2,100,
- 2,116,1,106,2,155,0,100,3,157,5,83,0,114,164,0,
- 0,0,41,3,114,1,0,0,0,114,177,0,0,0,114,142,
- 0,0,0,41,1,218,1,109,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,114,99,0,0,0,24,3,0,0,
- 115,2,0,0,0,0,7,122,26,70,114,111,122,101,110,73,
- 109,112,111,114,116,101,114,46,109,111,100,117,108,101,95,114,
- 101,112,114,78,99,4,0,0,0,0,0,0,0,0,0,0,
- 0,4,0,0,0,5,0,0,0,67,0,0,0,115,34,0,
- 0,0,116,0,160,1,124,1,161,1,114,26,116,2,124,1,
- 124,0,124,0,106,3,100,1,141,3,83,0,100,0,83,0,
- 100,0,83,0,114,165,0,0,0,41,4,114,56,0,0,0,
- 114,88,0,0,0,114,91,0,0,0,114,142,0,0,0,114,
- 166,0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,
- 0,0,0,114,170,0,0,0,33,3,0,0,115,6,0,0,
- 0,0,2,10,1,16,2,122,24,70,114,111,122,101,110,73,
- 109,112,111,114,116,101,114,46,102,105,110,100,95,115,112,101,
- 99,99,3,0,0,0,0,0,0,0,0,0,0,0,3,0,
- 0,0,3,0,0,0,67,0,0,0,115,18,0,0,0,116,
- 0,160,1,124,1,161,1,114,14,124,0,83,0,100,1,83,
- 0,41,2,122,93,70,105,110,100,32,97,32,102,114,111,122,
- 101,110,32,109,111,100,117,108,101,46,10,10,32,32,32,32,
- 32,32,32,32,84,104,105,115,32,109,101,116,104,111,100,32,
- 105,115,32,100,101,112,114,101,99,97,116,101,100,46,32,32,
- 85,115,101,32,102,105,110,100,95,115,112,101,99,40,41,32,
- 105,110,115,116,101,97,100,46,10,10,32,32,32,32,32,32,
- 32,32,78,41,2,114,56,0,0,0,114,88,0,0,0,41,
- 3,114,167,0,0,0,114,81,0,0,0,114,168,0,0,0,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,
- 171,0,0,0,40,3,0,0,115,2,0,0,0,0,7,122,
- 26,70,114,111,122,101,110,73,109,112,111,114,116,101,114,46,
- 102,105,110,100,95,109,111,100,117,108,101,99,2,0,0,0,
- 0,0,0,0,0,0,0,0,2,0,0,0,1,0,0,0,
- 67,0,0,0,115,4,0,0,0,100,1,83,0,41,2,122,
- 42,85,115,101,32,100,101,102,97,117,108,116,32,115,101,109,
- 97,110,116,105,99,115,32,102,111,114,32,109,111,100,117,108,
- 101,32,99,114,101,97,116,105,111,110,46,78,114,10,0,0,
- 0,41,2,114,167,0,0,0,114,95,0,0,0,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,114,153,0,0,
- 0,49,3,0,0,115,2,0,0,0,0,2,122,28,70,114,
- 111,122,101,110,73,109,112,111,114,116,101,114,46,99,114,101,
- 97,116,101,95,109,111,100,117,108,101,99,1,0,0,0,0,
- 0,0,0,0,0,0,0,3,0,0,0,4,0,0,0,67,
- 0,0,0,115,64,0,0,0,124,0,106,0,106,1,125,1,
- 116,2,160,3,124,1,161,1,115,36,116,4,124,1,155,2,
- 100,1,157,2,124,1,100,2,141,2,130,1,116,5,116,2,
- 106,6,124,1,131,2,125,2,116,7,124,2,124,0,106,8,
- 131,2,1,0,100,0,83,0,114,87,0,0,0,41,9,114,
- 107,0,0,0,114,17,0,0,0,114,56,0,0,0,114,88,
- 0,0,0,114,79,0,0,0,114,66,0,0,0,218,17,103,
- 101,116,95,102,114,111,122,101,110,95,111,98,106,101,99,116,
- 218,4,101,120,101,99,114,7,0,0,0,41,3,114,96,0,
- 0,0,114,17,0,0,0,218,4,99,111,100,101,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,114,154,0,0,
- 0,53,3,0,0,115,10,0,0,0,0,2,8,1,10,1,
- 18,1,12,1,122,26,70,114,111,122,101,110,73,109,112,111,
- 114,116,101,114,46,101,120,101,99,95,109,111,100,117,108,101,
- 99,2,0,0,0,0,0,0,0,0,0,0,0,2,0,0,
- 0,3,0,0,0,67,0,0,0,115,10,0,0,0,116,0,
- 124,0,124,1,131,2,83,0,41,1,122,95,76,111,97,100,
- 32,97,32,102,114,111,122,101,110,32,109,111,100,117,108,101,
- 46,10,10,32,32,32,32,32,32,32,32,84,104,105,115,32,
- 109,101,116,104,111,100,32,105,115,32,100,101,112,114,101,99,
- 97,116,101,100,46,32,32,85,115,101,32,101,120,101,99,95,
- 109,111,100,117,108,101,40,41,32,105,110,115,116,101,97,100,
- 46,10,10,32,32,32,32,32,32,32,32,41,1,114,97,0,
- 0,0,114,172,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,11,0,0,0,114,159,0,0,0,61,3,0,0,115,
- 2,0,0,0,0,7,122,26,70,114,111,122,101,110,73,109,
- 112,111,114,116,101,114,46,108,111,97,100,95,109,111,100,117,
- 108,101,99,2,0,0,0,0,0,0,0,0,0,0,0,2,
- 0,0,0,3,0,0,0,67,0,0,0,115,10,0,0,0,
- 116,0,160,1,124,1,161,1,83,0,41,1,122,45,82,101,
- 116,117,114,110,32,116,104,101,32,99,111,100,101,32,111,98,
- 106,101,99,116,32,102,111,114,32,116,104,101,32,102,114,111,
- 122,101,110,32,109,111,100,117,108,101,46,41,2,114,56,0,
- 0,0,114,179,0,0,0,114,172,0,0,0,114,10,0,0,
- 0,114,10,0,0,0,114,11,0,0,0,114,173,0,0,0,
- 70,3,0,0,115,2,0,0,0,0,4,122,23,70,114,111,
- 122,101,110,73,109,112,111,114,116,101,114,46,103,101,116,95,
- 99,111,100,101,99,2,0,0,0,0,0,0,0,0,0,0,
- 0,2,0,0,0,1,0,0,0,67,0,0,0,115,4,0,
- 0,0,100,1,83,0,41,2,122,54,82,101,116,117,114,110,
- 32,78,111,110,101,32,97,115,32,102,114,111,122,101,110,32,
- 109,111,100,117,108,101,115,32,100,111,32,110,111,116,32,104,
- 97,118,101,32,115,111,117,114,99,101,32,99,111,100,101,46,
- 78,114,10,0,0,0,114,172,0,0,0,114,10,0,0,0,
- 114,10,0,0,0,114,11,0,0,0,114,174,0,0,0,76,
- 3,0,0,115,2,0,0,0,0,4,122,25,70,114,111,122,
- 101,110,73,109,112,111,114,116,101,114,46,103,101,116,95,115,
- 111,117,114,99,101,99,2,0,0,0,0,0,0,0,0,0,
- 0,0,2,0,0,0,3,0,0,0,67,0,0,0,115,10,
- 0,0,0,116,0,160,1,124,1,161,1,83,0,41,1,122,
- 46,82,101,116,117,114,110,32,84,114,117,101,32,105,102,32,
- 116,104,101,32,102,114,111,122,101,110,32,109,111,100,117,108,
- 101,32,105,115,32,97,32,112,97,99,107,97,103,101,46,41,
- 2,114,56,0,0,0,90,17,105,115,95,102,114,111,122,101,
- 110,95,112,97,99,107,97,103,101,114,172,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,114,117,0,
- 0,0,82,3,0,0,115,2,0,0,0,0,4,122,25,70,
- 114,111,122,101,110,73,109,112,111,114,116,101,114,46,105,115,
- 95,112,97,99,107,97,103,101,41,2,78,78,41,1,78,41,
- 17,114,1,0,0,0,114,0,0,0,0,114,2,0,0,0,
- 114,3,0,0,0,114,142,0,0,0,114,175,0,0,0,114,
- 99,0,0,0,114,176,0,0,0,114,170,0,0,0,114,171,
- 0,0,0,114,153,0,0,0,114,154,0,0,0,114,159,0,
- 0,0,114,90,0,0,0,114,173,0,0,0,114,174,0,0,
- 0,114,117,0,0,0,114,10,0,0,0,114,10,0,0,0,
- 114,10,0,0,0,114,11,0,0,0,114,177,0,0,0,13,
- 3,0,0,115,46,0,0,0,8,2,4,7,4,2,2,1,
- 10,8,2,1,12,6,2,1,12,8,2,1,10,3,2,1,
- 10,7,2,1,10,8,2,1,2,1,12,4,2,1,2,1,
- 12,4,2,1,2,1,114,177,0,0,0,99,0,0,0,0,
- 0,0,0,0,0,0,0,0,0,0,0,0,2,0,0,0,
- 64,0,0,0,115,32,0,0,0,101,0,90,1,100,0,90,
- 2,100,1,90,3,100,2,100,3,132,0,90,4,100,4,100,
- 5,132,0,90,5,100,6,83,0,41,7,218,18,95,73,109,
- 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,122,
- 36,67,111,110,116,101,120,116,32,109,97,110,97,103,101,114,
- 32,102,111,114,32,116,104,101,32,105,109,112,111,114,116,32,
- 108,111,99,107,46,99,1,0,0,0,0,0,0,0,0,0,
- 0,0,1,0,0,0,2,0,0,0,67,0,0,0,115,12,
- 0,0,0,116,0,160,1,161,0,1,0,100,1,83,0,41,
- 2,122,24,65,99,113,117,105,114,101,32,116,104,101,32,105,
- 109,112,111,114,116,32,108,111,99,107,46,78,41,2,114,56,
- 0,0,0,114,57,0,0,0,114,46,0,0,0,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,114,53,0,0,
- 0,95,3,0,0,115,2,0,0,0,0,2,122,28,95,73,
- 109,112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,
- 46,95,95,101,110,116,101,114,95,95,99,4,0,0,0,0,
- 0,0,0,0,0,0,0,4,0,0,0,2,0,0,0,67,
- 0,0,0,115,12,0,0,0,116,0,160,1,161,0,1,0,
- 100,1,83,0,41,2,122,60,82,101,108,101,97,115,101,32,
- 116,104,101,32,105,109,112,111,114,116,32,108,111,99,107,32,
- 114,101,103,97,114,100,108,101,115,115,32,111,102,32,97,110,
- 121,32,114,97,105,115,101,100,32,101,120,99,101,112,116,105,
- 111,110,115,46,78,41,2,114,56,0,0,0,114,58,0,0,
- 0,41,4,114,30,0,0,0,218,8,101,120,99,95,116,121,
- 112,101,218,9,101,120,99,95,118,97,108,117,101,218,13,101,
- 120,99,95,116,114,97,99,101,98,97,99,107,114,10,0,0,
- 0,114,10,0,0,0,114,11,0,0,0,114,55,0,0,0,
- 99,3,0,0,115,2,0,0,0,0,2,122,27,95,73,109,
- 112,111,114,116,76,111,99,107,67,111,110,116,101,120,116,46,
- 95,95,101,120,105,116,95,95,78,41,6,114,1,0,0,0,
- 114,0,0,0,0,114,2,0,0,0,114,3,0,0,0,114,
- 53,0,0,0,114,55,0,0,0,114,10,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,114,182,0,
- 0,0,91,3,0,0,115,6,0,0,0,8,2,4,2,8,
- 4,114,182,0,0,0,99,3,0,0,0,0,0,0,0,0,
- 0,0,0,5,0,0,0,5,0,0,0,67,0,0,0,115,
- 66,0,0,0,124,1,160,0,100,1,124,2,100,2,24,0,
- 161,2,125,3,116,1,124,3,131,1,124,2,107,0,114,36,
- 116,2,100,3,131,1,130,1,124,3,100,4,25,0,125,4,
- 124,0,114,62,124,4,155,0,100,1,124,0,155,0,157,3,
- 83,0,124,4,83,0,41,5,122,50,82,101,115,111,108,118,
- 101,32,97,32,114,101,108,97,116,105,118,101,32,109,111,100,
- 117,108,101,32,110,97,109,101,32,116,111,32,97,110,32,97,
- 98,115,111,108,117,116,101,32,111,110,101,46,114,132,0,0,
- 0,114,37,0,0,0,122,50,97,116,116,101,109,112,116,101,
- 100,32,114,101,108,97,116,105,118,101,32,105,109,112,111,114,
- 116,32,98,101,121,111,110,100,32,116,111,112,45,108,101,118,
- 101,108,32,112,97,99,107,97,103,101,114,22,0,0,0,41,
- 3,218,6,114,115,112,108,105,116,218,3,108,101,110,114,79,
- 0,0,0,41,5,114,17,0,0,0,218,7,112,97,99,107,
- 97,103,101,218,5,108,101,118,101,108,90,4,98,105,116,115,
- 90,4,98,97,115,101,114,10,0,0,0,114,10,0,0,0,
- 114,11,0,0,0,218,13,95,114,101,115,111,108,118,101,95,
- 110,97,109,101,104,3,0,0,115,10,0,0,0,0,2,16,
- 1,12,1,8,1,8,1,114,190,0,0,0,99,3,0,0,
- 0,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,
- 0,67,0,0,0,115,34,0,0,0,124,0,160,0,124,1,
- 124,2,161,2,125,3,124,3,100,0,107,8,114,24,100,0,
- 83,0,116,1,124,1,124,3,131,2,83,0,114,13,0,0,
- 0,41,2,114,171,0,0,0,114,91,0,0,0,41,4,218,
- 6,102,105,110,100,101,114,114,17,0,0,0,114,168,0,0,
- 0,114,111,0,0,0,114,10,0,0,0,114,10,0,0,0,
- 114,11,0,0,0,218,17,95,102,105,110,100,95,115,112,101,
- 99,95,108,101,103,97,99,121,113,3,0,0,115,8,0,0,
- 0,0,3,12,1,8,1,4,1,114,192,0,0,0,99,3,
- 0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,10,
- 0,0,0,67,0,0,0,115,12,1,0,0,116,0,106,1,
- 125,3,124,3,100,1,107,8,114,22,116,2,100,2,131,1,
- 130,1,124,3,115,38,116,3,160,4,100,3,116,5,161,2,
- 1,0,124,0,116,0,106,6,107,6,125,4,124,3,68,0,
- 93,210,125,5,116,7,131,0,143,84,1,0,122,10,124,5,
- 106,8,125,6,87,0,110,54,4,0,116,9,107,10,114,128,
- 1,0,1,0,1,0,116,10,124,5,124,0,124,1,131,3,
- 125,7,124,7,100,1,107,8,114,124,89,0,87,0,53,0,
- 81,0,82,0,163,0,113,52,89,0,110,14,88,0,124,6,
- 124,0,124,1,124,2,131,3,125,7,87,0,53,0,81,0,
- 82,0,88,0,124,7,100,1,107,9,114,52,124,4,144,0,
- 115,254,124,0,116,0,106,6,107,6,144,0,114,254,116,0,
- 106,6,124,0,25,0,125,8,122,10,124,8,106,11,125,9,
- 87,0,110,28,4,0,116,9,107,10,114,226,1,0,1,0,
- 1,0,124,7,6,0,89,0,2,0,1,0,83,0,88,0,
- 124,9,100,1,107,8,114,244,124,7,2,0,1,0,83,0,
- 124,9,2,0,1,0,83,0,113,52,124,7,2,0,1,0,
- 83,0,113,52,100,1,83,0,41,4,122,21,70,105,110,100,
- 32,97,32,109,111,100,117,108,101,39,115,32,115,112,101,99,
- 46,78,122,53,115,121,115,46,109,101,116,97,95,112,97,116,
- 104,32,105,115,32,78,111,110,101,44,32,80,121,116,104,111,
- 110,32,105,115,32,108,105,107,101,108,121,32,115,104,117,116,
- 116,105,110,103,32,100,111,119,110,122,22,115,121,115,46,109,
- 101,116,97,95,112,97,116,104,32,105,115,32,101,109,112,116,
- 121,41,12,114,15,0,0,0,218,9,109,101,116,97,95,112,
- 97,116,104,114,79,0,0,0,218,9,95,119,97,114,110,105,
- 110,103,115,218,4,119,97,114,110,218,13,73,109,112,111,114,
- 116,87,97,114,110,105,110,103,114,92,0,0,0,114,182,0,
- 0,0,114,170,0,0,0,114,108,0,0,0,114,192,0,0,
- 0,114,107,0,0,0,41,10,114,17,0,0,0,114,168,0,
- 0,0,114,169,0,0,0,114,193,0,0,0,90,9,105,115,
- 95,114,101,108,111,97,100,114,191,0,0,0,114,170,0,0,
- 0,114,95,0,0,0,114,96,0,0,0,114,107,0,0,0,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,
- 10,95,102,105,110,100,95,115,112,101,99,122,3,0,0,115,
- 54,0,0,0,0,2,6,1,8,2,8,3,4,1,12,5,
- 10,1,8,1,8,1,2,1,10,1,14,1,12,1,8,1,
- 20,2,22,1,8,2,18,1,10,1,2,1,10,1,14,4,
- 14,2,8,1,8,2,10,2,10,2,114,197,0,0,0,99,
- 3,0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,
- 4,0,0,0,67,0,0,0,115,108,0,0,0,116,0,124,
- 0,116,1,131,2,115,28,116,2,100,1,116,3,124,0,131,
- 1,155,0,157,2,131,1,130,1,124,2,100,2,107,0,114,
- 44,116,4,100,3,131,1,130,1,124,2,100,2,107,4,114,
- 84,116,0,124,1,116,1,131,2,115,72,116,2,100,4,131,
- 1,130,1,110,12,124,1,115,84,116,5,100,5,131,1,130,
- 1,124,0,115,104,124,2,100,2,107,2,114,104,116,4,100,
- 6,131,1,130,1,100,7,83,0,41,8,122,28,86,101,114,
- 105,102,121,32,97,114,103,117,109,101,110,116,115,32,97,114,
- 101,32,34,115,97,110,101,34,46,122,29,109,111,100,117,108,
- 101,32,110,97,109,101,32,109,117,115,116,32,98,101,32,115,
- 116,114,44,32,110,111,116,32,114,22,0,0,0,122,18,108,
- 101,118,101,108,32,109,117,115,116,32,98,101,32,62,61,32,
- 48,122,31,95,95,112,97,99,107,97,103,101,95,95,32,110,
- 111,116,32,115,101,116,32,116,111,32,97,32,115,116,114,105,
- 110,103,122,54,97,116,116,101,109,112,116,101,100,32,114,101,
- 108,97,116,105,118,101,32,105,109,112,111,114,116,32,119,105,
- 116,104,32,110,111,32,107,110,111,119,110,32,112,97,114,101,
- 110,116,32,112,97,99,107,97,103,101,122,17,69,109,112,116,
- 121,32,109,111,100,117,108,101,32,110,97,109,101,78,41,6,
- 218,10,105,115,105,110,115,116,97,110,99,101,218,3,115,116,
- 114,218,9,84,121,112,101,69,114,114,111,114,114,14,0,0,
- 0,218,10,86,97,108,117,101,69,114,114,111,114,114,79,0,
- 0,0,169,3,114,17,0,0,0,114,188,0,0,0,114,189,
- 0,0,0,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,218,13,95,115,97,110,105,116,121,95,99,104,101,99,
- 107,169,3,0,0,115,22,0,0,0,0,2,10,1,18,1,
- 8,1,8,1,8,1,10,1,10,1,4,1,8,2,12,1,
- 114,203,0,0,0,250,16,78,111,32,109,111,100,117,108,101,
- 32,110,97,109,101,100,32,122,4,123,33,114,125,99,2,0,
- 0,0,0,0,0,0,0,0,0,0,8,0,0,0,8,0,
- 0,0,67,0,0,0,115,222,0,0,0,100,0,125,2,124,
- 0,160,0,100,1,161,1,100,2,25,0,125,3,124,3,114,
- 136,124,3,116,1,106,2,107,7,114,42,116,3,124,1,124,
- 3,131,2,1,0,124,0,116,1,106,2,107,6,114,62,116,
- 1,106,2,124,0,25,0,83,0,116,1,106,2,124,3,25,
- 0,125,4,122,10,124,4,106,4,125,2,87,0,110,52,4,
- 0,116,5,107,10,114,134,1,0,1,0,1,0,100,3,124,
- 0,155,2,100,4,124,3,155,2,100,5,157,5,125,5,116,
- 6,124,5,124,0,100,6,141,2,100,0,130,2,89,0,110,
- 2,88,0,116,7,124,0,124,2,131,2,125,6,124,6,100,
- 0,107,8,114,174,116,6,100,3,124,0,155,2,157,2,124,
- 0,100,6,141,2,130,1,110,8,116,8,124,6,131,1,125,
- 7,124,3,114,218,116,1,106,2,124,3,25,0,125,4,116,
- 9,124,4,124,0,160,0,100,1,161,1,100,7,25,0,124,
- 7,131,3,1,0,124,7,83,0,41,8,78,114,132,0,0,
- 0,114,22,0,0,0,114,204,0,0,0,122,2,59,32,122,
- 17,32,105,115,32,110,111,116,32,97,32,112,97,99,107,97,
- 103,101,114,16,0,0,0,233,2,0,0,0,41,10,114,133,
- 0,0,0,114,15,0,0,0,114,92,0,0,0,114,66,0,
- 0,0,114,145,0,0,0,114,108,0,0,0,218,19,77,111,
- 100,117,108,101,78,111,116,70,111,117,110,100,69,114,114,111,
- 114,114,197,0,0,0,114,162,0,0,0,114,5,0,0,0,
- 41,8,114,17,0,0,0,218,7,105,109,112,111,114,116,95,
- 114,168,0,0,0,114,134,0,0,0,90,13,112,97,114,101,
- 110,116,95,109,111,100,117,108,101,114,160,0,0,0,114,95,
- 0,0,0,114,96,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,23,95,102,105,110,100,95,97,
- 110,100,95,108,111,97,100,95,117,110,108,111,99,107,101,100,
- 188,3,0,0,115,42,0,0,0,0,1,4,1,14,1,4,
- 1,10,1,10,2,10,1,10,1,10,1,2,1,10,1,14,
- 1,18,1,20,1,10,1,8,1,20,2,8,1,4,2,10,
- 1,22,1,114,208,0,0,0,99,2,0,0,0,0,0,0,
- 0,0,0,0,0,4,0,0,0,10,0,0,0,67,0,0,
- 0,115,108,0,0,0,116,0,124,0,131,1,143,50,1,0,
- 116,1,106,2,160,3,124,0,116,4,161,2,125,2,124,2,
- 116,4,107,8,114,54,116,5,124,0,124,1,131,2,87,0,
- 2,0,53,0,81,0,82,0,163,0,83,0,87,0,53,0,
- 81,0,82,0,88,0,124,2,100,1,107,8,114,96,100,2,
- 124,0,155,0,100,3,157,3,125,3,116,6,124,3,124,0,
- 100,4,141,2,130,1,116,7,124,0,131,1,1,0,124,2,
- 83,0,41,5,122,25,70,105,110,100,32,97,110,100,32,108,
- 111,97,100,32,116,104,101,32,109,111,100,117,108,101,46,78,
- 122,10,105,109,112,111,114,116,32,111,102,32,122,28,32,104,
- 97,108,116,101,100,59,32,78,111,110,101,32,105,110,32,115,
- 121,115,46,109,111,100,117,108,101,115,114,16,0,0,0,41,
- 8,114,49,0,0,0,114,15,0,0,0,114,92,0,0,0,
- 114,34,0,0,0,218,14,95,78,69,69,68,83,95,76,79,
- 65,68,73,78,71,114,208,0,0,0,114,206,0,0,0,114,
- 64,0,0,0,41,4,114,17,0,0,0,114,207,0,0,0,
- 114,96,0,0,0,114,75,0,0,0,114,10,0,0,0,114,
- 10,0,0,0,114,11,0,0,0,218,14,95,102,105,110,100,
- 95,97,110,100,95,108,111,97,100,218,3,0,0,115,18,0,
- 0,0,0,2,10,1,14,1,8,1,32,2,8,1,12,2,
- 12,2,8,1,114,210,0,0,0,114,22,0,0,0,99,3,
- 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,4,
- 0,0,0,67,0,0,0,115,42,0,0,0,116,0,124,0,
- 124,1,124,2,131,3,1,0,124,2,100,1,107,4,114,32,
- 116,1,124,0,124,1,124,2,131,3,125,0,116,2,124,0,
- 116,3,131,2,83,0,41,2,97,50,1,0,0,73,109,112,
- 111,114,116,32,97,110,100,32,114,101,116,117,114,110,32,116,
- 104,101,32,109,111,100,117,108,101,32,98,97,115,101,100,32,
- 111,110,32,105,116,115,32,110,97,109,101,44,32,116,104,101,
- 32,112,97,99,107,97,103,101,32,116,104,101,32,99,97,108,
- 108,32,105,115,10,32,32,32,32,98,101,105,110,103,32,109,
- 97,100,101,32,102,114,111,109,44,32,97,110,100,32,116,104,
- 101,32,108,101,118,101,108,32,97,100,106,117,115,116,109,101,
- 110,116,46,10,10,32,32,32,32,84,104,105,115,32,102,117,
- 110,99,116,105,111,110,32,114,101,112,114,101,115,101,110,116,
- 115,32,116,104,101,32,103,114,101,97,116,101,115,116,32,99,
- 111,109,109,111,110,32,100,101,110,111,109,105,110,97,116,111,
- 114,32,111,102,32,102,117,110,99,116,105,111,110,97,108,105,
- 116,121,10,32,32,32,32,98,101,116,119,101,101,110,32,105,
- 109,112,111,114,116,95,109,111,100,117,108,101,32,97,110,100,
- 32,95,95,105,109,112,111,114,116,95,95,46,32,84,104,105,
- 115,32,105,110,99,108,117,100,101,115,32,115,101,116,116,105,
- 110,103,32,95,95,112,97,99,107,97,103,101,95,95,32,105,
- 102,10,32,32,32,32,116,104,101,32,108,111,97,100,101,114,
- 32,100,105,100,32,110,111,116,46,10,10,32,32,32,32,114,
- 22,0,0,0,41,4,114,203,0,0,0,114,190,0,0,0,
- 114,210,0,0,0,218,11,95,103,99,100,95,105,109,112,111,
- 114,116,114,202,0,0,0,114,10,0,0,0,114,10,0,0,
- 0,114,11,0,0,0,114,211,0,0,0,234,3,0,0,115,
- 8,0,0,0,0,9,12,1,8,1,12,1,114,211,0,0,
- 0,169,1,218,9,114,101,99,117,114,115,105,118,101,99,3,
- 0,0,0,0,0,0,0,1,0,0,0,8,0,0,0,11,
- 0,0,0,67,0,0,0,115,228,0,0,0,124,1,68,0,
- 93,218,125,4,116,0,124,4,116,1,131,2,115,66,124,3,
- 114,34,124,0,106,2,100,1,23,0,125,5,110,4,100,2,
- 125,5,116,3,100,3,124,5,155,0,100,4,116,4,124,4,
- 131,1,106,2,155,0,157,4,131,1,130,1,113,4,124,4,
- 100,5,107,2,114,108,124,3,115,222,116,5,124,0,100,6,
- 131,2,114,222,116,6,124,0,124,0,106,7,124,2,100,7,
- 100,8,141,4,1,0,113,4,116,5,124,0,124,4,131,2,
- 115,4,124,0,106,2,155,0,100,9,124,4,155,0,157,3,
- 125,6,122,14,116,8,124,2,124,6,131,2,1,0,87,0,
- 113,4,4,0,116,9,107,10,114,220,1,0,125,7,1,0,
- 122,42,124,7,106,10,124,6,107,2,114,202,116,11,106,12,
- 160,13,124,6,116,14,161,2,100,10,107,9,114,202,87,0,
- 89,0,162,8,113,4,130,0,87,0,53,0,100,10,125,7,
- 126,7,88,0,89,0,113,4,88,0,113,4,124,0,83,0,
- 41,11,122,238,70,105,103,117,114,101,32,111,117,116,32,119,
- 104,97,116,32,95,95,105,109,112,111,114,116,95,95,32,115,
- 104,111,117,108,100,32,114,101,116,117,114,110,46,10,10,32,
- 32,32,32,84,104,101,32,105,109,112,111,114,116,95,32,112,
- 97,114,97,109,101,116,101,114,32,105,115,32,97,32,99,97,
- 108,108,97,98,108,101,32,119,104,105,99,104,32,116,97,107,
- 101,115,32,116,104,101,32,110,97,109,101,32,111,102,32,109,
- 111,100,117,108,101,32,116,111,10,32,32,32,32,105,109,112,
- 111,114,116,46,32,73,116,32,105,115,32,114,101,113,117,105,
- 114,101,100,32,116,111,32,100,101,99,111,117,112,108,101,32,
- 116,104,101,32,102,117,110,99,116,105,111,110,32,102,114,111,
- 109,32,97,115,115,117,109,105,110,103,32,105,109,112,111,114,
- 116,108,105,98,39,115,10,32,32,32,32,105,109,112,111,114,
- 116,32,105,109,112,108,101,109,101,110,116,97,116,105,111,110,
- 32,105,115,32,100,101,115,105,114,101,100,46,10,10,32,32,
- 32,32,122,8,46,95,95,97,108,108,95,95,122,13,96,96,
- 102,114,111,109,32,108,105,115,116,39,39,122,8,73,116,101,
- 109,32,105,110,32,122,18,32,109,117,115,116,32,98,101,32,
- 115,116,114,44,32,110,111,116,32,250,1,42,218,7,95,95,
- 97,108,108,95,95,84,114,212,0,0,0,114,132,0,0,0,
- 78,41,15,114,198,0,0,0,114,199,0,0,0,114,1,0,
- 0,0,114,200,0,0,0,114,14,0,0,0,114,4,0,0,
- 0,218,16,95,104,97,110,100,108,101,95,102,114,111,109,108,
- 105,115,116,114,215,0,0,0,114,66,0,0,0,114,206,0,
- 0,0,114,17,0,0,0,114,15,0,0,0,114,92,0,0,
- 0,114,34,0,0,0,114,209,0,0,0,41,8,114,96,0,
- 0,0,218,8,102,114,111,109,108,105,115,116,114,207,0,0,
- 0,114,213,0,0,0,218,1,120,90,5,119,104,101,114,101,
- 90,9,102,114,111,109,95,110,97,109,101,90,3,101,120,99,
- 114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,114,
- 216,0,0,0,249,3,0,0,115,44,0,0,0,0,10,8,
- 1,10,1,4,1,12,2,4,1,28,2,8,1,14,1,10,
- 1,2,255,8,2,10,1,16,1,2,1,14,1,16,4,10,
- 1,16,255,2,2,8,1,22,1,114,216,0,0,0,99,1,
- 0,0,0,0,0,0,0,0,0,0,0,3,0,0,0,6,
- 0,0,0,67,0,0,0,115,146,0,0,0,124,0,160,0,
- 100,1,161,1,125,1,124,0,160,0,100,2,161,1,125,2,
- 124,1,100,3,107,9,114,82,124,2,100,3,107,9,114,78,
- 124,1,124,2,106,1,107,3,114,78,116,2,106,3,100,4,
- 124,1,155,2,100,5,124,2,106,1,155,2,100,6,157,5,
- 116,4,100,7,100,8,141,3,1,0,124,1,83,0,124,2,
- 100,3,107,9,114,96,124,2,106,1,83,0,116,2,106,3,
- 100,9,116,4,100,7,100,8,141,3,1,0,124,0,100,10,
- 25,0,125,1,100,11,124,0,107,7,114,142,124,1,160,5,
- 100,12,161,1,100,13,25,0,125,1,124,1,83,0,41,14,
- 122,167,67,97,108,99,117,108,97,116,101,32,119,104,97,116,
- 32,95,95,112,97,99,107,97,103,101,95,95,32,115,104,111,
- 117,108,100,32,98,101,46,10,10,32,32,32,32,95,95,112,
- 97,99,107,97,103,101,95,95,32,105,115,32,110,111,116,32,
- 103,117,97,114,97,110,116,101,101,100,32,116,111,32,98,101,
- 32,100,101,102,105,110,101,100,32,111,114,32,99,111,117,108,
- 100,32,98,101,32,115,101,116,32,116,111,32,78,111,110,101,
- 10,32,32,32,32,116,111,32,114,101,112,114,101,115,101,110,
- 116,32,116,104,97,116,32,105,116,115,32,112,114,111,112,101,
- 114,32,118,97,108,117,101,32,105,115,32,117,110,107,110,111,
- 119,110,46,10,10,32,32,32,32,114,149,0,0,0,114,107,
- 0,0,0,78,122,32,95,95,112,97,99,107,97,103,101,95,
- 95,32,33,61,32,95,95,115,112,101,99,95,95,46,112,97,
- 114,101,110,116,32,40,122,4,32,33,61,32,114,122,0,0,
- 0,233,3,0,0,0,41,1,90,10,115,116,97,99,107,108,
- 101,118,101,108,122,89,99,97,110,39,116,32,114,101,115,111,
- 108,118,101,32,112,97,99,107,97,103,101,32,102,114,111,109,
- 32,95,95,115,112,101,99,95,95,32,111,114,32,95,95,112,
- 97,99,107,97,103,101,95,95,44,32,102,97,108,108,105,110,
- 103,32,98,97,99,107,32,111,110,32,95,95,110,97,109,101,
- 95,95,32,97,110,100,32,95,95,112,97,116,104,95,95,114,
- 1,0,0,0,114,145,0,0,0,114,132,0,0,0,114,22,
- 0,0,0,41,6,114,34,0,0,0,114,134,0,0,0,114,
- 194,0,0,0,114,195,0,0,0,114,196,0,0,0,114,133,
- 0,0,0,41,3,218,7,103,108,111,98,97,108,115,114,188,
- 0,0,0,114,95,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,11,0,0,0,218,17,95,99,97,108,99,95,95,
- 95,112,97,99,107,97,103,101,95,95,30,4,0,0,115,38,
- 0,0,0,0,7,10,1,10,1,8,1,18,1,22,2,2,
- 0,2,254,6,3,4,1,8,1,6,2,6,2,2,0,2,
- 254,6,3,8,1,8,1,14,1,114,221,0,0,0,114,10,
- 0,0,0,99,5,0,0,0,0,0,0,0,0,0,0,0,
- 9,0,0,0,5,0,0,0,67,0,0,0,115,180,0,0,
- 0,124,4,100,1,107,2,114,18,116,0,124,0,131,1,125,
- 5,110,36,124,1,100,2,107,9,114,30,124,1,110,2,105,
- 0,125,6,116,1,124,6,131,1,125,7,116,0,124,0,124,
- 7,124,4,131,3,125,5,124,3,115,150,124,4,100,1,107,
- 2,114,84,116,0,124,0,160,2,100,3,161,1,100,1,25,
- 0,131,1,83,0,124,0,115,92,124,5,83,0,116,3,124,
- 0,131,1,116,3,124,0,160,2,100,3,161,1,100,1,25,
- 0,131,1,24,0,125,8,116,4,106,5,124,5,106,6,100,
- 2,116,3,124,5,106,6,131,1,124,8,24,0,133,2,25,
- 0,25,0,83,0,110,26,116,7,124,5,100,4,131,2,114,
- 172,116,8,124,5,124,3,116,0,131,3,83,0,124,5,83,
- 0,100,2,83,0,41,5,97,215,1,0,0,73,109,112,111,
- 114,116,32,97,32,109,111,100,117,108,101,46,10,10,32,32,
- 32,32,84,104,101,32,39,103,108,111,98,97,108,115,39,32,
- 97,114,103,117,109,101,110,116,32,105,115,32,117,115,101,100,
- 32,116,111,32,105,110,102,101,114,32,119,104,101,114,101,32,
- 116,104,101,32,105,109,112,111,114,116,32,105,115,32,111,99,
- 99,117,114,114,105,110,103,32,102,114,111,109,10,32,32,32,
- 32,116,111,32,104,97,110,100,108,101,32,114,101,108,97,116,
- 105,118,101,32,105,109,112,111,114,116,115,46,32,84,104,101,
- 32,39,108,111,99,97,108,115,39,32,97,114,103,117,109,101,
- 110,116,32,105,115,32,105,103,110,111,114,101,100,46,32,84,
- 104,101,10,32,32,32,32,39,102,114,111,109,108,105,115,116,
- 39,32,97,114,103,117,109,101,110,116,32,115,112,101,99,105,
- 102,105,101,115,32,119,104,97,116,32,115,104,111,117,108,100,
- 32,101,120,105,115,116,32,97,115,32,97,116,116,114,105,98,
- 117,116,101,115,32,111,110,32,116,104,101,32,109,111,100,117,
- 108,101,10,32,32,32,32,98,101,105,110,103,32,105,109,112,
- 111,114,116,101,100,32,40,101,46,103,46,32,96,96,102,114,
- 111,109,32,109,111,100,117,108,101,32,105,109,112,111,114,116,
- 32,60,102,114,111,109,108,105,115,116,62,96,96,41,46,32,
- 32,84,104,101,32,39,108,101,118,101,108,39,10,32,32,32,
- 32,97,114,103,117,109,101,110,116,32,114,101,112,114,101,115,
- 101,110,116,115,32,116,104,101,32,112,97,99,107,97,103,101,
- 32,108,111,99,97,116,105,111,110,32,116,111,32,105,109,112,
- 111,114,116,32,102,114,111,109,32,105,110,32,97,32,114,101,
- 108,97,116,105,118,101,10,32,32,32,32,105,109,112,111,114,
- 116,32,40,101,46,103,46,32,96,96,102,114,111,109,32,46,
- 46,112,107,103,32,105,109,112,111,114,116,32,109,111,100,96,
- 96,32,119,111,117,108,100,32,104,97,118,101,32,97,32,39,
- 108,101,118,101,108,39,32,111,102,32,50,41,46,10,10,32,
- 32,32,32,114,22,0,0,0,78,114,132,0,0,0,114,145,
- 0,0,0,41,9,114,211,0,0,0,114,221,0,0,0,218,
- 9,112,97,114,116,105,116,105,111,110,114,187,0,0,0,114,
- 15,0,0,0,114,92,0,0,0,114,1,0,0,0,114,4,
- 0,0,0,114,216,0,0,0,41,9,114,17,0,0,0,114,
- 220,0,0,0,218,6,108,111,99,97,108,115,114,217,0,0,
- 0,114,189,0,0,0,114,96,0,0,0,90,8,103,108,111,
- 98,97,108,115,95,114,188,0,0,0,90,7,99,117,116,95,
- 111,102,102,114,10,0,0,0,114,10,0,0,0,114,11,0,
- 0,0,218,10,95,95,105,109,112,111,114,116,95,95,57,4,
- 0,0,115,30,0,0,0,0,11,8,1,10,2,16,1,8,
- 1,12,1,4,3,8,1,18,1,4,1,4,4,26,3,32,
- 1,10,1,12,2,114,224,0,0,0,99,1,0,0,0,0,
- 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67,
- 0,0,0,115,38,0,0,0,116,0,160,1,124,0,161,1,
- 125,1,124,1,100,0,107,8,114,30,116,2,100,1,124,0,
- 23,0,131,1,130,1,116,3,124,1,131,1,83,0,41,2,
- 78,122,25,110,111,32,98,117,105,108,116,45,105,110,32,109,
- 111,100,117,108,101,32,110,97,109,101,100,32,41,4,114,163,
- 0,0,0,114,170,0,0,0,114,79,0,0,0,114,162,0,
- 0,0,41,2,114,17,0,0,0,114,95,0,0,0,114,10,
- 0,0,0,114,10,0,0,0,114,11,0,0,0,218,18,95,
- 98,117,105,108,116,105,110,95,102,114,111,109,95,110,97,109,
- 101,94,4,0,0,115,8,0,0,0,0,1,10,1,8,1,
- 12,1,114,225,0,0,0,99,2,0,0,0,0,0,0,0,
- 0,0,0,0,10,0,0,0,5,0,0,0,67,0,0,0,
- 115,166,0,0,0,124,1,97,0,124,0,97,1,116,2,116,
- 1,131,1,125,2,116,1,106,3,160,4,161,0,68,0,93,
- 72,92,2,125,3,125,4,116,5,124,4,124,2,131,2,114,
- 26,124,3,116,1,106,6,107,6,114,60,116,7,125,5,110,
- 18,116,0,160,8,124,3,161,1,114,26,116,9,125,5,110,
- 2,113,26,116,10,124,4,124,5,131,2,125,6,116,11,124,
- 6,124,4,131,2,1,0,113,26,116,1,106,3,116,12,25,
- 0,125,7,100,1,68,0,93,46,125,8,124,8,116,1,106,
- 3,107,7,114,138,116,13,124,8,131,1,125,9,110,10,116,
- 1,106,3,124,8,25,0,125,9,116,14,124,7,124,8,124,
- 9,131,3,1,0,113,114,100,2,83,0,41,3,122,250,83,
- 101,116,117,112,32,105,109,112,111,114,116,108,105,98,32,98,
- 121,32,105,109,112,111,114,116,105,110,103,32,110,101,101,100,
- 101,100,32,98,117,105,108,116,45,105,110,32,109,111,100,117,
- 108,101,115,32,97,110,100,32,105,110,106,101,99,116,105,110,
- 103,32,116,104,101,109,10,32,32,32,32,105,110,116,111,32,
- 116,104,101,32,103,108,111,98,97,108,32,110,97,109,101,115,
- 112,97,99,101,46,10,10,32,32,32,32,65,115,32,115,121,
- 115,32,105,115,32,110,101,101,100,101,100,32,102,111,114,32,
- 115,121,115,46,109,111,100,117,108,101,115,32,97,99,99,101,
- 115,115,32,97,110,100,32,95,105,109,112,32,105,115,32,110,
- 101,101,100,101,100,32,116,111,32,108,111,97,100,32,98,117,
- 105,108,116,45,105,110,10,32,32,32,32,109,111,100,117,108,
- 101,115,44,32,116,104,111,115,101,32,116,119,111,32,109,111,
- 100,117,108,101,115,32,109,117,115,116,32,98,101,32,101,120,
- 112,108,105,99,105,116,108,121,32,112,97,115,115,101,100,32,
- 105,110,46,10,10,32,32,32,32,41,3,114,23,0,0,0,
- 114,194,0,0,0,114,63,0,0,0,78,41,15,114,56,0,
- 0,0,114,15,0,0,0,114,14,0,0,0,114,92,0,0,
- 0,218,5,105,116,101,109,115,114,198,0,0,0,114,78,0,
- 0,0,114,163,0,0,0,114,88,0,0,0,114,177,0,0,
- 0,114,146,0,0,0,114,152,0,0,0,114,1,0,0,0,
- 114,225,0,0,0,114,5,0,0,0,41,10,218,10,115,121,
- 115,95,109,111,100,117,108,101,218,11,95,105,109,112,95,109,
- 111,100,117,108,101,90,11,109,111,100,117,108,101,95,116,121,
- 112,101,114,17,0,0,0,114,96,0,0,0,114,111,0,0,
- 0,114,95,0,0,0,90,11,115,101,108,102,95,109,111,100,
- 117,108,101,90,12,98,117,105,108,116,105,110,95,110,97,109,
- 101,90,14,98,117,105,108,116,105,110,95,109,111,100,117,108,
- 101,114,10,0,0,0,114,10,0,0,0,114,11,0,0,0,
- 218,6,95,115,101,116,117,112,101,4,0,0,115,36,0,0,
- 0,0,9,4,1,4,3,8,1,18,1,10,1,10,1,6,
- 1,10,1,6,2,2,1,10,1,12,3,10,1,8,1,10,
- 1,10,2,10,1,114,229,0,0,0,99,2,0,0,0,0,
- 0,0,0,0,0,0,0,2,0,0,0,3,0,0,0,67,
- 0,0,0,115,38,0,0,0,116,0,124,0,124,1,131,2,
- 1,0,116,1,106,2,160,3,116,4,161,1,1,0,116,1,
- 106,2,160,3,116,5,161,1,1,0,100,1,83,0,41,2,
- 122,48,73,110,115,116,97,108,108,32,105,109,112,111,114,116,
- 101,114,115,32,102,111,114,32,98,117,105,108,116,105,110,32,
- 97,110,100,32,102,114,111,122,101,110,32,109,111,100,117,108,
- 101,115,78,41,6,114,229,0,0,0,114,15,0,0,0,114,
- 193,0,0,0,114,123,0,0,0,114,163,0,0,0,114,177,
- 0,0,0,41,2,114,227,0,0,0,114,228,0,0,0,114,
- 10,0,0,0,114,10,0,0,0,114,11,0,0,0,218,8,
- 95,105,110,115,116,97,108,108,136,4,0,0,115,6,0,0,
- 0,0,2,10,2,12,1,114,230,0,0,0,99,0,0,0,
- 0,0,0,0,0,0,0,0,0,1,0,0,0,4,0,0,
- 0,67,0,0,0,115,32,0,0,0,100,1,100,2,108,0,
- 125,0,124,0,97,1,124,0,160,2,116,3,106,4,116,5,
- 25,0,161,1,1,0,100,2,83,0,41,3,122,57,73,110,
- 115,116,97,108,108,32,105,109,112,111,114,116,101,114,115,32,
- 116,104,97,116,32,114,101,113,117,105,114,101,32,101,120,116,
- 101,114,110,97,108,32,102,105,108,101,115,121,115,116,101,109,
- 32,97,99,99,101,115,115,114,22,0,0,0,78,41,6,218,
- 26,95,102,114,111,122,101,110,95,105,109,112,111,114,116,108,
- 105,98,95,101,120,116,101,114,110,97,108,114,130,0,0,0,
- 114,230,0,0,0,114,15,0,0,0,114,92,0,0,0,114,
- 1,0,0,0,41,1,114,231,0,0,0,114,10,0,0,0,
- 114,10,0,0,0,114,11,0,0,0,218,27,95,105,110,115,
- 116,97,108,108,95,101,120,116,101,114,110,97,108,95,105,109,
- 112,111,114,116,101,114,115,144,4,0,0,115,6,0,0,0,
- 0,3,8,1,4,1,114,232,0,0,0,41,2,78,78,41,
- 1,78,41,2,78,114,22,0,0,0,41,4,78,78,114,10,
- 0,0,0,114,22,0,0,0,41,50,114,3,0,0,0,114,
- 130,0,0,0,114,12,0,0,0,114,18,0,0,0,114,59,
- 0,0,0,114,33,0,0,0,114,42,0,0,0,114,19,0,
- 0,0,114,20,0,0,0,114,48,0,0,0,114,49,0,0,
- 0,114,52,0,0,0,114,64,0,0,0,114,66,0,0,0,
- 114,76,0,0,0,114,86,0,0,0,114,90,0,0,0,114,
- 97,0,0,0,114,113,0,0,0,114,114,0,0,0,114,91,
- 0,0,0,114,146,0,0,0,114,152,0,0,0,114,156,0,
- 0,0,114,109,0,0,0,114,93,0,0,0,114,161,0,0,
- 0,114,162,0,0,0,114,94,0,0,0,114,163,0,0,0,
- 114,177,0,0,0,114,182,0,0,0,114,190,0,0,0,114,
- 192,0,0,0,114,197,0,0,0,114,203,0,0,0,90,15,
- 95,69,82,82,95,77,83,71,95,80,82,69,70,73,88,90,
- 8,95,69,82,82,95,77,83,71,114,208,0,0,0,218,6,
- 111,98,106,101,99,116,114,209,0,0,0,114,210,0,0,0,
- 114,211,0,0,0,114,216,0,0,0,114,221,0,0,0,114,
- 224,0,0,0,114,225,0,0,0,114,229,0,0,0,114,230,
- 0,0,0,114,232,0,0,0,114,10,0,0,0,114,10,0,
- 0,0,114,10,0,0,0,114,11,0,0,0,218,8,60,109,
- 111,100,117,108,101,62,1,0,0,0,115,94,0,0,0,4,
- 24,4,2,8,8,8,8,4,2,4,3,16,4,14,68,14,
- 21,14,16,8,37,8,17,8,11,14,8,8,11,8,12,8,
- 16,8,36,14,100,16,26,10,45,14,72,8,17,8,17,8,
- 30,8,37,8,42,8,15,14,75,14,78,14,13,8,9,8,
- 9,10,47,8,16,4,1,8,2,8,27,6,3,8,16,10,
- 15,14,37,8,27,10,37,8,7,8,35,8,8,
-};
diff --git a/Python/instrumentation.c b/Python/instrumentation.c
new file mode 100644
index 00000000000000..8334f596eb3e19
--- /dev/null
+++ b/Python/instrumentation.c
@@ -0,0 +1,2027 @@
+
+
+#include "Python.h"
+#include "pycore_call.h"
+#include "pycore_frame.h"
+#include "pycore_interp.h"
+#include "pycore_long.h"
+#include "pycore_namespace.h"
+#include "pycore_object.h"
+#include "pycore_opcode.h"
+#include "pycore_pyerrors.h"
+#include "pycore_pystate.h"
+
+/* Uncomment this to dump debugging output when assertions fail */
+// #define INSTRUMENT_DEBUG 1
+
+static PyObject DISABLE =
+{
+ .ob_refcnt = _Py_IMMORTAL_REFCNT,
+ .ob_type = &PyBaseObject_Type
+};
+
+PyObject _PyInstrumentation_MISSING =
+{
+ .ob_refcnt = _Py_IMMORTAL_REFCNT,
+ .ob_type = &PyBaseObject_Type
+};
+
+static const int8_t EVENT_FOR_OPCODE[256] = {
+ [RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN,
+ [INSTRUMENTED_RETURN_CONST] = PY_MONITORING_EVENT_PY_RETURN,
+ [RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN,
+ [INSTRUMENTED_RETURN_VALUE] = PY_MONITORING_EVENT_PY_RETURN,
+ [CALL] = PY_MONITORING_EVENT_CALL,
+ [INSTRUMENTED_CALL] = PY_MONITORING_EVENT_CALL,
+ [CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
+ [INSTRUMENTED_CALL_FUNCTION_EX] = PY_MONITORING_EVENT_CALL,
+ [RESUME] = -1,
+ [YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
+ [INSTRUMENTED_YIELD_VALUE] = PY_MONITORING_EVENT_PY_YIELD,
+ [JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP,
+ [JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP,
+ [POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH,
+ [POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH,
+ [POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH,
+ [POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH,
+ [INSTRUMENTED_JUMP_FORWARD] = PY_MONITORING_EVENT_JUMP,
+ [INSTRUMENTED_JUMP_BACKWARD] = PY_MONITORING_EVENT_JUMP,
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = PY_MONITORING_EVENT_BRANCH,
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = PY_MONITORING_EVENT_BRANCH,
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = PY_MONITORING_EVENT_BRANCH,
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = PY_MONITORING_EVENT_BRANCH,
+ [FOR_ITER] = PY_MONITORING_EVENT_BRANCH,
+ [INSTRUMENTED_FOR_ITER] = PY_MONITORING_EVENT_BRANCH,
+ [END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION,
+ [INSTRUMENTED_END_FOR] = PY_MONITORING_EVENT_STOP_ITERATION,
+ [END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION,
+ [INSTRUMENTED_END_SEND] = PY_MONITORING_EVENT_STOP_ITERATION,
+};
+
+static const uint8_t DE_INSTRUMENT[256] = {
+ [INSTRUMENTED_RESUME] = RESUME,
+ [INSTRUMENTED_RETURN_VALUE] = RETURN_VALUE,
+ [INSTRUMENTED_RETURN_CONST] = RETURN_CONST,
+ [INSTRUMENTED_CALL] = CALL,
+ [INSTRUMENTED_CALL_FUNCTION_EX] = CALL_FUNCTION_EX,
+ [INSTRUMENTED_YIELD_VALUE] = YIELD_VALUE,
+ [INSTRUMENTED_JUMP_FORWARD] = JUMP_FORWARD,
+ [INSTRUMENTED_JUMP_BACKWARD] = JUMP_BACKWARD,
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = POP_JUMP_IF_FALSE,
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = POP_JUMP_IF_TRUE,
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = POP_JUMP_IF_NONE,
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = POP_JUMP_IF_NOT_NONE,
+ [INSTRUMENTED_FOR_ITER] = FOR_ITER,
+ [INSTRUMENTED_END_FOR] = END_FOR,
+ [INSTRUMENTED_END_SEND] = END_SEND,
+};
+
+static const uint8_t INSTRUMENTED_OPCODES[256] = {
+ [RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
+ [INSTRUMENTED_RETURN_CONST] = INSTRUMENTED_RETURN_CONST,
+ [RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
+ [INSTRUMENTED_RETURN_VALUE] = INSTRUMENTED_RETURN_VALUE,
+ [CALL] = INSTRUMENTED_CALL,
+ [INSTRUMENTED_CALL] = INSTRUMENTED_CALL,
+ [CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
+ [INSTRUMENTED_CALL_FUNCTION_EX] = INSTRUMENTED_CALL_FUNCTION_EX,
+ [YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
+ [INSTRUMENTED_YIELD_VALUE] = INSTRUMENTED_YIELD_VALUE,
+ [RESUME] = INSTRUMENTED_RESUME,
+ [INSTRUMENTED_RESUME] = INSTRUMENTED_RESUME,
+ [JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
+ [INSTRUMENTED_JUMP_FORWARD] = INSTRUMENTED_JUMP_FORWARD,
+ [JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
+ [INSTRUMENTED_JUMP_BACKWARD] = INSTRUMENTED_JUMP_BACKWARD,
+ [POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = INSTRUMENTED_POP_JUMP_IF_FALSE,
+ [POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = INSTRUMENTED_POP_JUMP_IF_TRUE,
+ [POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = INSTRUMENTED_POP_JUMP_IF_NONE,
+ [POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
+ [END_FOR] = INSTRUMENTED_END_FOR,
+ [INSTRUMENTED_END_FOR] = INSTRUMENTED_END_FOR,
+ [END_SEND] = INSTRUMENTED_END_SEND,
+ [INSTRUMENTED_END_SEND] = INSTRUMENTED_END_SEND,
+ [FOR_ITER] = INSTRUMENTED_FOR_ITER,
+ [INSTRUMENTED_FOR_ITER] = INSTRUMENTED_FOR_ITER,
+
+ [INSTRUMENTED_LINE] = INSTRUMENTED_LINE,
+ [INSTRUMENTED_INSTRUCTION] = INSTRUMENTED_INSTRUCTION,
+};
+
+static inline bool
+opcode_has_event(int opcode) {
+ return opcode < INSTRUMENTED_LINE &&
+ INSTRUMENTED_OPCODES[opcode] > 0;
+}
+
+static inline bool
+is_instrumented(int opcode) {
+ assert(opcode != 0);
+ assert(opcode != RESERVED);
+ return opcode >= MIN_INSTRUMENTED_OPCODE;
+}
+
+#ifndef NDEBUG
+static inline bool
+monitors_equals(_Py_Monitors a, _Py_Monitors b)
+{
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ if (a.tools[i] != b.tools[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+#endif
+
+static inline _Py_Monitors
+monitors_sub(_Py_Monitors a, _Py_Monitors b)
+{
+ _Py_Monitors res;
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ res.tools[i] = a.tools[i] & ~b.tools[i];
+ }
+ return res;
+}
+
+#ifndef NDEBUG
+static inline _Py_Monitors
+monitors_and(_Py_Monitors a, _Py_Monitors b)
+{
+ _Py_Monitors res;
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ res.tools[i] = a.tools[i] & b.tools[i];
+ }
+ return res;
+}
+#endif
+
+static inline _Py_Monitors
+monitors_or(_Py_Monitors a, _Py_Monitors b)
+{
+ _Py_Monitors res;
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ res.tools[i] = a.tools[i] | b.tools[i];
+ }
+ return res;
+}
+
+static inline bool
+monitors_are_empty(_Py_Monitors m)
+{
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ if (m.tools[i]) {
+ return false;
+ }
+ }
+ return true;
+}
+
+static inline bool
+multiple_tools(_Py_Monitors *m)
+{
+ for (int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ if (_Py_popcount32(m->tools[i]) > 1) {
+ return true;
+ }
+ }
+ return false;
+}
+
+static inline _PyMonitoringEventSet
+get_events(_Py_Monitors *m, int tool_id)
+{
+ _PyMonitoringEventSet result = 0;
+ for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) {
+ if ((m->tools[e] >> tool_id) & 1) {
+ result |= (1 << e);
+ }
+ }
+ return result;
+}
+
+/* Line delta.
+ * 8 bit value.
+ * if line_delta == -128:
+ * line = None # represented as -1
+ * elif line_delta == -127:
+ * line = PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
+ * else:
+ * line = first_line + (offset >> OFFSET_SHIFT) + line_delta;
+ */
+
+#define NO_LINE -128
+#define COMPUTED_LINE -127
+
+#define OFFSET_SHIFT 4
+
+static int8_t
+compute_line_delta(PyCodeObject *code, int offset, int line)
+{
+ if (line < 0) {
+ return NO_LINE;
+ }
+ int delta = line - code->co_firstlineno - (offset >> OFFSET_SHIFT);
+ if (delta <= INT8_MAX && delta > COMPUTED_LINE) {
+ return delta;
+ }
+ return COMPUTED_LINE;
+}
+
+static int
+compute_line(PyCodeObject *code, int offset, int8_t line_delta)
+{
+ if (line_delta > COMPUTED_LINE) {
+ return code->co_firstlineno + (offset >> OFFSET_SHIFT) + line_delta;
+ }
+ if (line_delta == NO_LINE) {
+
+ return -1;
+ }
+ assert(line_delta == COMPUTED_LINE);
+ /* Look it up */
+ return PyCode_Addr2Line(code, offset * sizeof(_Py_CODEUNIT));
+}
+
+static int
+instruction_length(PyCodeObject *code, int offset)
+{
+ int opcode = _PyCode_CODE(code)[offset].op.code;
+ assert(opcode != 0);
+ assert(opcode != RESERVED);
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode = code->_co_monitoring->lines[offset].original_opcode;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode = code->_co_monitoring->per_instruction_opcodes[offset];
+ }
+ int deinstrumented = DE_INSTRUMENT[opcode];
+ if (deinstrumented) {
+ opcode = deinstrumented;
+ }
+ else {
+ opcode = _PyOpcode_Deopt[opcode];
+ }
+ assert(opcode != 0);
+ assert(!is_instrumented(opcode));
+ assert(opcode == _PyOpcode_Deopt[opcode]);
+ return 1 + _PyOpcode_Caches[opcode];
+}
+
+#ifdef INSTRUMENT_DEBUG
+
+static void
+dump_instrumentation_data_tools(PyCodeObject *code, uint8_t *tools, int i, FILE*out)
+{
+ if (tools == NULL) {
+ fprintf(out, "tools = NULL");
+ }
+ else {
+ fprintf(out, "tools = %d", tools[i]);
+ }
+}
+
+static void
+dump_instrumentation_data_lines(PyCodeObject *code, _PyCoLineInstrumentationData *lines, int i, FILE*out)
+{
+ if (lines == NULL) {
+ fprintf(out, ", lines = NULL");
+ }
+ else if (lines[i].original_opcode == 0) {
+ fprintf(out, ", lines = {original_opcode = No LINE (0), line_delta = %d)", lines[i].line_delta);
+ }
+ else {
+ fprintf(out, ", lines = {original_opcode = %s, line_delta = %d)", _PyOpcode_OpName[lines[i].original_opcode], lines[i].line_delta);
+ }
+}
+
+static void
+dump_instrumentation_data_line_tools(PyCodeObject *code, uint8_t *line_tools, int i, FILE*out)
+{
+ if (line_tools == NULL) {
+ fprintf(out, ", line_tools = NULL");
+ }
+ else {
+ fprintf(out, ", line_tools = %d", line_tools[i]);
+ }
+}
+
+static void
+dump_instrumentation_data_per_instruction(PyCodeObject *code, _PyCoMonitoringData *data, int i, FILE*out)
+{
+ if (data->per_instruction_opcodes == NULL) {
+ fprintf(out, ", per-inst opcode = NULL");
+ }
+ else {
+ fprintf(out, ", per-inst opcode = %s", _PyOpcode_OpName[data->per_instruction_opcodes[i]]);
+ }
+ if (data->per_instruction_tools == NULL) {
+ fprintf(out, ", per-inst tools = NULL");
+ }
+ else {
+ fprintf(out, ", per-inst tools = %d", data->per_instruction_tools[i]);
+ }
+}
+
+static void
+dump_monitors(const char *prefix, _Py_Monitors monitors, FILE*out)
+{
+ fprintf(out, "%s monitors:\n", prefix);
+ for (int event = 0; event < PY_MONITORING_UNGROUPED_EVENTS; event++) {
+ fprintf(out, " Event %d: Tools %x\n", event, monitors.tools[event]);
+ }
+}
+
+/* Like _Py_GetBaseOpcode but without asserts.
+ * Does its best to give the right answer, but won't abort
+ * if something is wrong */
+int get_base_opcode_best_attempt(PyCodeObject *code, int offset)
+{
+ int opcode = _Py_OPCODE(_PyCode_CODE(code)[offset]);
+ if (INSTRUMENTED_OPCODES[opcode] != opcode) {
+ /* Not instrumented */
+ return _PyOpcode_Deopt[opcode] == 0 ? opcode : _PyOpcode_Deopt[opcode];
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ if (code->_co_monitoring->per_instruction_opcodes[offset] == 0) {
+ return opcode;
+ }
+ opcode = code->_co_monitoring->per_instruction_opcodes[offset];
+ }
+ if (opcode == INSTRUMENTED_LINE) {
+ if (code->_co_monitoring->lines[offset].original_opcode == 0) {
+ return opcode;
+ }
+ opcode = code->_co_monitoring->lines[offset].original_opcode;
+ }
+ int deinstrumented = DE_INSTRUMENT[opcode];
+ if (deinstrumented) {
+ return deinstrumented;
+ }
+ if (_PyOpcode_Deopt[opcode] == 0) {
+ return opcode;
+ }
+ return _PyOpcode_Deopt[opcode];
+}
+
+/* No error checking -- Don't use this for anything but experimental debugging */
+static void
+dump_instrumentation_data(PyCodeObject *code, int star, FILE*out)
+{
+ _PyCoMonitoringData *data = code->_co_monitoring;
+ fprintf(out, "\n");
+ PyObject_Print(code->co_name, out, Py_PRINT_RAW);
+ fprintf(out, "\n");
+ if (data == NULL) {
+ fprintf(out, "NULL\n");
+ return;
+ }
+ dump_monitors("Global", PyInterpreterState_Get()->monitors, out);
+ dump_monitors("Code", data->local_monitors, out);
+ dump_monitors("Active", data->active_monitors, out);
+ int code_len = (int)Py_SIZE(code);
+ bool starred = false;
+ for (int i = 0; i < code_len; i += instruction_length(code, i)) {
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ int opcode = instr->op.code;
+ if (i == star) {
+ fprintf(out, "** ");
+ starred = true;
+ }
+ fprintf(out, "Offset: %d, line: %d %s: ", i, PyCode_Addr2Line(code, i*2), _PyOpcode_OpName[opcode]);
+ dump_instrumentation_data_tools(code, data->tools, i, out);
+ dump_instrumentation_data_lines(code, data->lines, i, out);
+ dump_instrumentation_data_line_tools(code, data->line_tools, i, out);
+ dump_instrumentation_data_per_instruction(code, data, i, out);
+ fprintf(out, "\n");
+ ;
+ }
+ if (!starred && star >= 0) {
+ fprintf(out, "Error offset not at valid instruction offset: %d\n", star);
+ fprintf(out, " ");
+ dump_instrumentation_data_tools(code, data->tools, star, out);
+ dump_instrumentation_data_lines(code, data->lines, star, out);
+ dump_instrumentation_data_line_tools(code, data->line_tools, star, out);
+ dump_instrumentation_data_per_instruction(code, data, star, out);
+ fprintf(out, "\n");
+ }
+}
+
+#define CHECK(test) do { \
+ if (!(test)) { \
+ dump_instrumentation_data(code, i, stderr); \
+ } \
+ assert(test); \
+} while (0)
+
+bool valid_opcode(int opcode) {
+ if (opcode > 0 &&
+ opcode != RESERVED &&
+ opcode < 255 &&
+ _PyOpcode_OpName[opcode] &&
+ _PyOpcode_OpName[opcode][0] != '<'
+ ) {
+ return true;
+ }
+ return false;
+}
+
+static void
+sanity_check_instrumentation(PyCodeObject *code)
+{
+ _PyCoMonitoringData *data = code->_co_monitoring;
+ if (data == NULL) {
+ return;
+ }
+ _Py_Monitors active_monitors = PyInterpreterState_Get()->monitors;
+ if (code->_co_monitoring) {
+ _Py_Monitors local_monitors = code->_co_monitoring->local_monitors;
+ active_monitors = monitors_or(active_monitors, local_monitors);
+ }
+ assert(monitors_equals(
+ code->_co_monitoring->active_monitors,
+ active_monitors)
+ );
+ int code_len = (int)Py_SIZE(code);
+ for (int i = 0; i < code_len;) {
+ int opcode = _PyCode_CODE(code)[i].op.code;
+ int base_opcode = _Py_GetBaseOpcode(code, i);
+ CHECK(valid_opcode(opcode));
+ CHECK(valid_opcode(base_opcode));
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode = data->per_instruction_opcodes[i];
+ if (!is_instrumented(opcode)) {
+ CHECK(_PyOpcode_Deopt[opcode] == opcode);
+ }
+ if (data->per_instruction_tools) {
+ uint8_t tools = active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION];
+ CHECK((tools & data->per_instruction_tools[i]) == data->per_instruction_tools[i]);
+ }
+ }
+ if (opcode == INSTRUMENTED_LINE) {
+ CHECK(data->lines);
+ CHECK(valid_opcode(data->lines[i].original_opcode));
+ opcode = data->lines[i].original_opcode;
+ CHECK(opcode != END_FOR);
+ CHECK(opcode != RESUME);
+ CHECK(opcode != INSTRUMENTED_RESUME);
+ if (!is_instrumented(opcode)) {
+ CHECK(_PyOpcode_Deopt[opcode] == opcode);
+ }
+ CHECK(opcode != INSTRUMENTED_LINE);
+ }
+ else if (data->lines && !is_instrumented(opcode)) {
+ CHECK(data->lines[i].original_opcode == 0 ||
+ data->lines[i].original_opcode == base_opcode ||
+ DE_INSTRUMENT[data->lines[i].original_opcode] == base_opcode);
+ }
+ if (is_instrumented(opcode)) {
+ CHECK(DE_INSTRUMENT[opcode] == base_opcode);
+ int event = EVENT_FOR_OPCODE[DE_INSTRUMENT[opcode]];
+ if (event < 0) {
+ /* RESUME fixup */
+ event = _PyCode_CODE(code)[i].op.arg;
+ }
+ CHECK(active_monitors.tools[event] != 0);
+ }
+ if (data->lines && base_opcode != END_FOR) {
+ int line1 = compute_line(code, i, data->lines[i].line_delta);
+ int line2 = PyCode_Addr2Line(code, i*sizeof(_Py_CODEUNIT));
+ CHECK(line1 == line2);
+ }
+ CHECK(valid_opcode(opcode));
+ if (data->tools) {
+ uint8_t local_tools = data->tools[i];
+ if (opcode_has_event(base_opcode)) {
+ int event = EVENT_FOR_OPCODE[base_opcode];
+ if (event == -1) {
+ /* RESUME fixup */
+ event = _PyCode_CODE(code)[i].op.arg;
+ }
+ CHECK((active_monitors.tools[event] & local_tools) == local_tools);
+ }
+ else {
+ CHECK(local_tools == 0xff);
+ }
+ }
+ i += instruction_length(code, i);
+ assert(i <= code_len);
+ }
+}
+#else
+
+#define CHECK(test) assert(test)
+
+#endif
+
+/* Get the underlying opcode, stripping instrumentation */
+int _Py_GetBaseOpcode(PyCodeObject *code, int i)
+{
+ int opcode = _PyCode_CODE(code)[i].op.code;
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode = code->_co_monitoring->lines[i].original_opcode;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode = code->_co_monitoring->per_instruction_opcodes[i];
+ }
+ CHECK(opcode != INSTRUMENTED_INSTRUCTION);
+ CHECK(opcode != INSTRUMENTED_LINE);
+ int deinstrumented = DE_INSTRUMENT[opcode];
+ if (deinstrumented) {
+ return deinstrumented;
+ }
+ return _PyOpcode_Deopt[opcode];
+}
+
+static void
+de_instrument(PyCodeObject *code, int i, int event)
+{
+ assert(event != PY_MONITORING_EVENT_INSTRUCTION);
+ assert(event != PY_MONITORING_EVENT_LINE);
+
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ uint8_t *opcode_ptr = &instr->op.code;
+ int opcode = *opcode_ptr;
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
+ opcode = *opcode_ptr;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i];
+ opcode = *opcode_ptr;
+ }
+ int deinstrumented = DE_INSTRUMENT[opcode];
+ if (deinstrumented == 0) {
+ return;
+ }
+ CHECK(_PyOpcode_Deopt[deinstrumented] == deinstrumented);
+ *opcode_ptr = deinstrumented;
+ if (_PyOpcode_Caches[deinstrumented]) {
+ instr[1].cache = adaptive_counter_warmup();
+ }
+}
+
+static void
+de_instrument_line(PyCodeObject *code, int i)
+{
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ uint8_t *opcode_ptr = &instr->op.code;
+ int opcode =*opcode_ptr;
+ if (opcode != INSTRUMENTED_LINE) {
+ return;
+ }
+ _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
+ int original_opcode = lines->original_opcode;
+ CHECK(original_opcode != 0);
+ CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
+ *opcode_ptr = instr->op.code = original_opcode;
+ if (_PyOpcode_Caches[original_opcode]) {
+ instr[1].cache = adaptive_counter_warmup();
+ }
+ assert(*opcode_ptr != INSTRUMENTED_LINE);
+ assert(instr->op.code != INSTRUMENTED_LINE);
+}
+
+
+static void
+de_instrument_per_instruction(PyCodeObject *code, int i)
+{
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ uint8_t *opcode_ptr = &instr->op.code;
+ int opcode =*opcode_ptr;
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode_ptr = &code->_co_monitoring->lines[i].original_opcode;
+ opcode = *opcode_ptr;
+ }
+ if (opcode != INSTRUMENTED_INSTRUCTION) {
+ return;
+ }
+ int original_opcode = code->_co_monitoring->per_instruction_opcodes[i];
+ CHECK(original_opcode != 0);
+ CHECK(original_opcode == _PyOpcode_Deopt[original_opcode]);
+ instr->op.code = original_opcode;
+ if (_PyOpcode_Caches[original_opcode]) {
+ instr[1].cache = adaptive_counter_warmup();
+ }
+ assert(instr->op.code != INSTRUMENTED_INSTRUCTION);
+ /* Keep things clean for sanity check */
+ code->_co_monitoring->per_instruction_opcodes[i] = 0;
+}
+
+
+static void
+instrument(PyCodeObject *code, int i)
+{
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ uint8_t *opcode_ptr = &instr->op.code;
+ int opcode =*opcode_ptr;
+ if (opcode == INSTRUMENTED_LINE) {
+ _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
+ opcode_ptr = &lines->original_opcode;
+ opcode = *opcode_ptr;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode_ptr = &code->_co_monitoring->per_instruction_opcodes[i];
+ opcode = *opcode_ptr;
+ CHECK(!is_instrumented(opcode));
+ CHECK(opcode == _PyOpcode_Deopt[opcode]);
+ }
+ CHECK(opcode != 0);
+ if (!is_instrumented(opcode)) {
+ int deopt = _PyOpcode_Deopt[opcode];
+ int instrumented = INSTRUMENTED_OPCODES[deopt];
+ assert(instrumented);
+ *opcode_ptr = instrumented;
+ if (_PyOpcode_Caches[deopt]) {
+ instr[1].cache = adaptive_counter_warmup();
+ }
+ }
+}
+
+static void
+instrument_line(PyCodeObject *code, int i)
+{
+ uint8_t *opcode_ptr = &_PyCode_CODE(code)[i].op.code;
+ int opcode =*opcode_ptr;
+ if (opcode == INSTRUMENTED_LINE) {
+ return;
+ }
+ _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
+ lines->original_opcode = _PyOpcode_Deopt[opcode];
+ CHECK(lines->original_opcode > 0);
+ *opcode_ptr = INSTRUMENTED_LINE;
+}
+
+static void
+instrument_per_instruction(PyCodeObject *code, int i)
+{
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ uint8_t *opcode_ptr = &instr->op.code;
+ int opcode =*opcode_ptr;
+ if (opcode == INSTRUMENTED_LINE) {
+ _PyCoLineInstrumentationData *lines = &code->_co_monitoring->lines[i];
+ opcode_ptr = &lines->original_opcode;
+ opcode = *opcode_ptr;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ return;
+ }
+ CHECK(opcode != 0);
+ if (is_instrumented(opcode)) {
+ code->_co_monitoring->per_instruction_opcodes[i] = opcode;
+ }
+ else {
+ assert(opcode != 0);
+ assert(_PyOpcode_Deopt[opcode] != 0);
+ assert(_PyOpcode_Deopt[opcode] != RESUME);
+ code->_co_monitoring->per_instruction_opcodes[i] = _PyOpcode_Deopt[opcode];
+ }
+ assert(code->_co_monitoring->per_instruction_opcodes[i] > 0);
+ *opcode_ptr = INSTRUMENTED_INSTRUCTION;
+}
+
+#ifndef NDEBUG
+static bool
+instruction_has_event(PyCodeObject *code, int offset)
+{
+ _Py_CODEUNIT instr = _PyCode_CODE(code)[offset];
+ int opcode = instr.op.code;
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode = code->_co_monitoring->lines[offset].original_opcode;
+ }
+ if (opcode == INSTRUMENTED_INSTRUCTION) {
+ opcode = code->_co_monitoring->per_instruction_opcodes[offset];
+ }
+ return opcode_has_event(opcode);
+}
+#endif
+
+static void
+remove_tools(PyCodeObject * code, int offset, int event, int tools)
+{
+ assert(event != PY_MONITORING_EVENT_LINE);
+ assert(event != PY_MONITORING_EVENT_INSTRUCTION);
+ assert(event < PY_MONITORING_INSTRUMENTED_EVENTS);
+ assert(instruction_has_event(code, offset));
+ _PyCoMonitoringData *monitoring = code->_co_monitoring;
+ if (monitoring && monitoring->tools) {
+ monitoring->tools[offset] &= ~tools;
+ if (monitoring->tools[offset] == 0) {
+ de_instrument(code, offset, event);
+ }
+ }
+ else {
+ /* Single tool */
+ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[event];
+ assert(_Py_popcount32(single_tool) <= 1);
+ if (((single_tool & tools) == single_tool)) {
+ de_instrument(code, offset, event);
+ }
+ }
+}
+
+#ifndef NDEBUG
+static bool
+tools_is_subset_for_event(PyCodeObject * code, int event, int tools)
+{
+ int global_tools = PyInterpreterState_Get()->monitors.tools[event];
+ int local_tools = code->_co_monitoring->local_monitors.tools[event];
+ return tools == ((global_tools | local_tools) & tools);
+}
+#endif
+
+static void
+remove_line_tools(PyCodeObject * code, int offset, int tools)
+{
+ assert(code->_co_monitoring);
+ if (code->_co_monitoring->line_tools)
+ {
+ uint8_t *toolsptr = &code->_co_monitoring->line_tools[offset];
+ *toolsptr &= ~tools;
+ if (*toolsptr == 0 ) {
+ de_instrument_line(code, offset);
+ }
+ }
+ else {
+ /* Single tool */
+ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_LINE];
+ assert(_Py_popcount32(single_tool) <= 1);
+ if (((single_tool & tools) == single_tool)) {
+ de_instrument_line(code, offset);
+ }
+ }
+}
+
+static void
+add_tools(PyCodeObject * code, int offset, int event, int tools)
+{
+ assert(event != PY_MONITORING_EVENT_LINE);
+ assert(event != PY_MONITORING_EVENT_INSTRUCTION);
+ assert(event < PY_MONITORING_INSTRUMENTED_EVENTS);
+ assert(code->_co_monitoring);
+ if (code->_co_monitoring &&
+ code->_co_monitoring->tools
+ ) {
+ code->_co_monitoring->tools[offset] |= tools;
+ }
+ else {
+ /* Single tool */
+ assert(_Py_popcount32(tools) == 1);
+ assert(tools_is_subset_for_event(code, event, tools));
+ }
+ instrument(code, offset);
+}
+
+static void
+add_line_tools(PyCodeObject * code, int offset, int tools)
+{
+ assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_LINE, tools));
+ assert(code->_co_monitoring);
+ if (code->_co_monitoring->line_tools
+ ) {
+ code->_co_monitoring->line_tools[offset] |= tools;
+ }
+ else {
+ /* Single tool */
+ assert(_Py_popcount32(tools) == 1);
+ }
+ instrument_line(code, offset);
+}
+
+
+static void
+add_per_instruction_tools(PyCodeObject * code, int offset, int tools)
+{
+ assert(tools_is_subset_for_event(code, PY_MONITORING_EVENT_INSTRUCTION, tools));
+ assert(code->_co_monitoring);
+ if (code->_co_monitoring->per_instruction_tools
+ ) {
+ code->_co_monitoring->per_instruction_tools[offset] |= tools;
+ }
+ else {
+ /* Single tool */
+ assert(_Py_popcount32(tools) == 1);
+ }
+ instrument_per_instruction(code, offset);
+}
+
+
+static void
+remove_per_instruction_tools(PyCodeObject * code, int offset, int tools)
+{
+ assert(code->_co_monitoring);
+ if (code->_co_monitoring->per_instruction_tools)
+ {
+ uint8_t *toolsptr = &code->_co_monitoring->per_instruction_tools[offset];
+ *toolsptr &= ~tools;
+ if (*toolsptr == 0 ) {
+ de_instrument_per_instruction(code, offset);
+ }
+ }
+ else {
+ /* Single tool */
+ uint8_t single_tool = code->_co_monitoring->active_monitors.tools[PY_MONITORING_EVENT_INSTRUCTION];
+ assert(_Py_popcount32(single_tool) <= 1);
+ if (((single_tool & tools) == single_tool)) {
+ de_instrument_per_instruction(code, offset);
+ }
+ }
+}
+
+
+/* Return 1 if DISABLE returned, -1 if error, 0 otherwise */
+static int
+call_one_instrument(
+ PyInterpreterState *interp, PyThreadState *tstate, PyObject **args,
+ Py_ssize_t nargsf, int8_t tool, int event)
+{
+ assert(0 <= tool && tool < 8);
+ assert(tstate->tracing == 0);
+ PyObject *instrument = interp->monitoring_callables[tool][event];
+ if (instrument == NULL) {
+ return 0;
+ }
+ int old_what = tstate->what_event;
+ tstate->what_event = event;
+ tstate->tracing++;
+ PyObject *res = _PyObject_VectorcallTstate(tstate, instrument, args, nargsf, NULL);
+ tstate->tracing--;
+ tstate->what_event = old_what;
+ if (res == NULL) {
+ return -1;
+ }
+ Py_DECREF(res);
+ return (res == &DISABLE);
+}
+
+static const int8_t MOST_SIGNIFICANT_BITS[16] = {
+ -1, 0, 1, 1,
+ 2, 2, 2, 2,
+ 3, 3, 3, 3,
+ 3, 3, 3, 3,
+};
+
+/* We could use _Py_bit_length here, but that is designed for larger (32/64) bit ints,
+ and can perform relatively poorly on platforms without the necessary intrinsics. */
+static inline int most_significant_bit(uint8_t bits) {
+ assert(bits != 0);
+ if (bits > 15) {
+ return MOST_SIGNIFICANT_BITS[bits>>4]+4;
+ }
+ else {
+ return MOST_SIGNIFICANT_BITS[bits];
+ }
+}
+
+static bool
+is_version_up_to_date(PyCodeObject *code, PyInterpreterState *interp)
+{
+ return interp->monitoring_version == code->_co_instrumentation_version;
+}
+
+#ifndef NDEBUG
+static bool
+instrumentation_cross_checks(PyInterpreterState *interp, PyCodeObject *code)
+{
+ _Py_Monitors expected = monitors_or(
+ interp->monitors,
+ code->_co_monitoring->local_monitors);
+ return monitors_equals(code->_co_monitoring->active_monitors, expected);
+}
+#endif
+
+static inline uint8_t
+get_tools_for_instruction(PyCodeObject * code, int i, int event)
+{
+ uint8_t tools;
+ assert(event != PY_MONITORING_EVENT_LINE);
+ assert(event != PY_MONITORING_EVENT_INSTRUCTION);
+ assert(instrumentation_cross_checks(PyThreadState_GET()->interp, code));
+ _PyCoMonitoringData *monitoring = code->_co_monitoring;
+ if (event >= PY_MONITORING_UNGROUPED_EVENTS) {
+ assert(event == PY_MONITORING_EVENT_C_RAISE ||
+ event == PY_MONITORING_EVENT_C_RETURN);
+ event = PY_MONITORING_EVENT_CALL;
+ }
+ if (event < PY_MONITORING_INSTRUMENTED_EVENTS && monitoring->tools) {
+ tools = monitoring->tools[i];
+ }
+ else {
+ tools = code->_co_monitoring->active_monitors.tools[event];
+ }
+ CHECK(tools_is_subset_for_event(code, event, tools));
+ CHECK((tools & code->_co_monitoring->active_monitors.tools[event]) == tools);
+ return tools;
+}
+
+static int
+call_instrumentation_vector(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[])
+{
+ if (tstate->tracing) {
+ return 0;
+ }
+ assert(!_PyErr_Occurred(tstate));
+ assert(args[0] == NULL);
+ PyCodeObject *code = frame->f_code;
+ assert(code->_co_instrumentation_version == tstate->interp->monitoring_version);
+ assert(is_version_up_to_date(code, tstate->interp));
+ assert(instrumentation_cross_checks(tstate->interp, code));
+ assert(args[1] == NULL);
+ args[1] = (PyObject *)code;
+ int offset = (int)(instr - _PyCode_CODE(code));
+ /* 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);
+ if (offset_obj == NULL) {
+ return -1;
+ }
+ assert(args[2] == NULL);
+ args[2] = offset_obj;
+ uint8_t tools = get_tools_for_instruction(code, offset, event);
+ Py_ssize_t nargsf = nargs | PY_VECTORCALL_ARGUMENTS_OFFSET;
+ PyObject **callargs = &args[1];
+ int err = 0;
+ PyInterpreterState *interp = tstate->interp;
+ while (tools) {
+ int tool = most_significant_bit(tools);
+ assert(tool >= 0 && tool < 8);
+ assert(tools & (1 << tool));
+ tools ^= (1 << tool);
+ int res = call_one_instrument(interp, tstate, callargs, nargsf, tool, event);
+ if (res == 0) {
+ /* Nothing to do */
+ }
+ else if (res < 0) {
+ /* error */
+ err = -1;
+ break;
+ }
+ else {
+ /* DISABLE */
+ remove_tools(code, offset, event, 1 << tool);
+ }
+ }
+ Py_DECREF(offset_obj);
+ return err;
+}
+
+int
+_Py_call_instrumentation(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr)
+{
+ PyObject *args[3] = { NULL, NULL, NULL };
+ return call_instrumentation_vector(tstate, event, frame, instr, 2, args);
+}
+
+int
+_Py_call_instrumentation_arg(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg)
+{
+ PyObject *args[4] = { NULL, NULL, NULL, arg };
+ return call_instrumentation_vector(tstate, event, frame, instr, 3, args);
+}
+
+int
+_Py_call_instrumentation_2args(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1)
+{
+ PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 };
+ return call_instrumentation_vector(tstate, event, frame, instr, 4, args);
+}
+
+int
+_Py_call_instrumentation_jump(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, _Py_CODEUNIT *target
+) {
+ assert(event == PY_MONITORING_EVENT_JUMP ||
+ event == PY_MONITORING_EVENT_BRANCH);
+ assert(frame->prev_instr == instr);
+ frame->prev_instr = target;
+ PyCodeObject *code = frame->f_code;
+ int to = (int)(target - _PyCode_CODE(code));
+ PyObject *to_obj = PyLong_FromLong(to * (int)sizeof(_Py_CODEUNIT));
+ if (to_obj == NULL) {
+ return -1;
+ }
+ PyObject *args[4] = { NULL, NULL, NULL, to_obj };
+ int err = call_instrumentation_vector(tstate, event, frame, instr, 3, args);
+ Py_DECREF(to_obj);
+ return err;
+}
+
+static void
+call_instrumentation_vector_protected(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, Py_ssize_t nargs, PyObject *args[])
+{
+ assert(_PyErr_Occurred(tstate));
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int err = call_instrumentation_vector(tstate, event, frame, instr, nargs, args);
+ if (err) {
+ Py_XDECREF(exc);
+ }
+ else {
+ _PyErr_SetRaisedException(tstate, exc);
+ }
+ assert(_PyErr_Occurred(tstate));
+}
+
+void
+_Py_call_instrumentation_exc0(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr)
+{
+ assert(_PyErr_Occurred(tstate));
+ PyObject *args[3] = { NULL, NULL, NULL };
+ call_instrumentation_vector_protected(tstate, event, frame, instr, 2, args);
+}
+
+void
+_Py_call_instrumentation_exc2(
+ PyThreadState *tstate, int event,
+ _PyInterpreterFrame *frame, _Py_CODEUNIT *instr, PyObject *arg0, PyObject *arg1)
+{
+ assert(_PyErr_Occurred(tstate));
+ PyObject *args[5] = { NULL, NULL, NULL, arg0, arg1 };
+ call_instrumentation_vector_protected(tstate, event, frame, instr, 4, args);
+}
+
+
+int
+_Py_Instrumentation_GetLine(PyCodeObject *code, int index)
+{
+ _PyCoMonitoringData *monitoring = code->_co_monitoring;
+ assert(monitoring != NULL);
+ assert(monitoring->lines != NULL);
+ assert(index >= code->_co_firsttraceable);
+ assert(index < Py_SIZE(code));
+ _PyCoLineInstrumentationData *line_data = &monitoring->lines[index];
+ int8_t line_delta = line_data->line_delta;
+ int line = compute_line(code, index, line_delta);
+ return line;
+}
+
+int
+_Py_call_instrumentation_line(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr)
+{
+ frame->prev_instr = instr;
+ PyCodeObject *code = frame->f_code;
+ assert(is_version_up_to_date(code, tstate->interp));
+ assert(instrumentation_cross_checks(tstate->interp, code));
+ int i = (int)(instr - _PyCode_CODE(code));
+ _PyCoMonitoringData *monitoring = code->_co_monitoring;
+ _PyCoLineInstrumentationData *line_data = &monitoring->lines[i];
+ uint8_t original_opcode = line_data->original_opcode;
+ if (tstate->tracing) {
+ goto done;
+ }
+ PyInterpreterState *interp = tstate->interp;
+ int8_t line_delta = line_data->line_delta;
+ int line = compute_line(code, i, line_delta);
+ uint8_t tools = code->_co_monitoring->line_tools != NULL ?
+ code->_co_monitoring->line_tools[i] :
+ (interp->monitors.tools[PY_MONITORING_EVENT_LINE] |
+ code->_co_monitoring->local_monitors.tools[PY_MONITORING_EVENT_LINE]
+ );
+ PyObject *line_obj = PyLong_FromSsize_t(line);
+ if (line_obj == NULL) {
+ return -1;
+ }
+ PyObject *args[3] = { NULL, (PyObject *)code, line_obj };
+ while (tools) {
+ int tool = most_significant_bit(tools);
+ assert(tool >= 0 && tool < 8);
+ assert(tools & (1 << tool));
+ tools &= ~(1 << tool);
+ int res = call_one_instrument(interp, tstate, &args[1],
+ 2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
+ tool, PY_MONITORING_EVENT_LINE);
+ if (res == 0) {
+ /* Nothing to do */
+ }
+ else if (res < 0) {
+ /* error */
+ Py_DECREF(line_obj);
+ return -1;
+ }
+ else {
+ /* DISABLE */
+ remove_line_tools(code, i, 1 << tool);
+ }
+ }
+ Py_DECREF(line_obj);
+done:
+ assert(original_opcode != 0);
+ assert(original_opcode < INSTRUMENTED_LINE);
+ assert(_PyOpcode_Deopt[original_opcode] == original_opcode);
+ return original_opcode;
+}
+
+int
+_Py_call_instrumentation_instruction(PyThreadState *tstate, _PyInterpreterFrame* frame, _Py_CODEUNIT *instr)
+{
+ PyCodeObject *code = frame->f_code;
+ assert(is_version_up_to_date(code, tstate->interp));
+ assert(instrumentation_cross_checks(tstate->interp, code));
+ int offset = (int)(instr - _PyCode_CODE(code));
+ _PyCoMonitoringData *instrumentation_data = code->_co_monitoring;
+ assert(instrumentation_data->per_instruction_opcodes);
+ int next_opcode = instrumentation_data->per_instruction_opcodes[offset];
+ if (tstate->tracing) {
+ return next_opcode;
+ }
+ PyInterpreterState *interp = tstate->interp;
+ uint8_t tools = instrumentation_data->per_instruction_tools != NULL ?
+ instrumentation_data->per_instruction_tools[offset] :
+ (interp->monitors.tools[PY_MONITORING_EVENT_INSTRUCTION] |
+ 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);
+ if (offset_obj == NULL) {
+ return -1;
+ }
+ PyObject *args[3] = { NULL, (PyObject *)code, offset_obj };
+ while (tools) {
+ int tool = most_significant_bit(tools);
+ assert(tool >= 0 && tool < 8);
+ assert(tools & (1 << tool));
+ tools &= ~(1 << tool);
+ int res = call_one_instrument(interp, tstate, &args[1],
+ 2 | PY_VECTORCALL_ARGUMENTS_OFFSET,
+ tool, PY_MONITORING_EVENT_INSTRUCTION);
+ if (res == 0) {
+ /* Nothing to do */
+ }
+ else if (res < 0) {
+ /* error */
+ Py_DECREF(offset_obj);
+ return -1;
+ }
+ else {
+ /* DISABLE */
+ remove_per_instruction_tools(code, offset, 1 << tool);
+ }
+ }
+ Py_DECREF(offset_obj);
+ assert(next_opcode != 0);
+ return next_opcode;
+}
+
+
+PyObject *
+_PyMonitoring_RegisterCallback(int tool_id, int event_id, PyObject *obj)
+{
+ PyInterpreterState *is = _PyInterpreterState_Get();
+ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
+ assert(0 <= event_id && event_id < PY_MONITORING_EVENTS);
+ PyObject *callback = is->monitoring_callables[tool_id][event_id];
+ is->monitoring_callables[tool_id][event_id] = Py_XNewRef(obj);
+ return callback;
+}
+
+static void
+initialize_tools(PyCodeObject *code)
+{
+ uint8_t* tools = code->_co_monitoring->tools;
+ assert(tools != NULL);
+ int code_len = (int)Py_SIZE(code);
+ for (int i = 0; i < code_len; i++) {
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ int opcode = instr->op.code;
+ if (opcode == INSTRUMENTED_LINE) {
+ opcode = code->_co_monitoring->lines[i].original_opcode;
+ }
+ bool instrumented = is_instrumented(opcode);
+ if (instrumented) {
+ opcode = DE_INSTRUMENT[opcode];
+ assert(opcode != 0);
+ }
+ opcode = _PyOpcode_Deopt[opcode];
+ if (opcode_has_event(opcode)) {
+ if (instrumented) {
+ int8_t event;
+ if (opcode == RESUME) {
+ event = instr->op.arg != 0;
+ }
+ else {
+ event = EVENT_FOR_OPCODE[opcode];
+ assert(event > 0);
+ }
+ assert(event >= 0);
+ assert(event < PY_MONITORING_INSTRUMENTED_EVENTS);
+ tools[i] = code->_co_monitoring->active_monitors.tools[event];
+ CHECK(tools[i] != 0);
+ }
+ else {
+ tools[i] = 0;
+ }
+ }
+#ifdef Py_DEBUG
+ /* Initialize tools for invalid locations to all ones to try to catch errors */
+ else {
+ tools[i] = 0xff;
+ }
+ for (int j = 1; j <= _PyOpcode_Caches[opcode]; j++) {
+ tools[i+j] = 0xff;
+ }
+#endif
+ i += _PyOpcode_Caches[opcode];
+ }
+}
+
+#define NO_LINE -128
+
+static void
+initialize_lines(PyCodeObject *code)
+{
+ _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
+ assert(line_data != NULL);
+ int code_len = (int)Py_SIZE(code);
+ PyCodeAddressRange range;
+ _PyCode_InitAddressRange(code, &range);
+ for (int i = 0; i < code->_co_firsttraceable && i < code_len; i++) {
+ line_data[i].original_opcode = 0;
+ line_data[i].line_delta = -127;
+ }
+ int current_line = -1;
+ for (int i = code->_co_firsttraceable; i < code_len; ) {
+ int opcode = _Py_GetBaseOpcode(code, i);
+ int line = _PyCode_CheckLineNumber(i*(int)sizeof(_Py_CODEUNIT), &range);
+ line_data[i].line_delta = compute_line_delta(code, i, line);
+ int length = instruction_length(code, i);
+ switch (opcode) {
+ case END_ASYNC_FOR:
+ case END_FOR:
+ case END_SEND:
+ case RESUME:
+ /* END_FOR cannot start a line, as it is skipped by FOR_ITER
+ * END_SEND cannot start a line, as it is skipped by SEND
+ * RESUME must not be instrumented with INSTRUMENT_LINE */
+ line_data[i].original_opcode = 0;
+ break;
+ default:
+ if (line != current_line && line >= 0) {
+ line_data[i].original_opcode = opcode;
+ }
+ else {
+ line_data[i].original_opcode = 0;
+ }
+ if (line >= 0) {
+ current_line = line;
+ }
+ }
+ for (int j = 1; j < length; j++) {
+ line_data[i+j].original_opcode = 0;
+ line_data[i+j].line_delta = NO_LINE;
+ }
+ switch (opcode) {
+ case RETURN_VALUE:
+ case RAISE_VARARGS:
+ case RERAISE:
+ /* Blocks of code after these terminators
+ * should be treated as different lines */
+ current_line = -1;
+ }
+ i += length;
+ }
+}
+
+static void
+initialize_line_tools(PyCodeObject *code, _Py_Monitors *all_events)
+{
+ uint8_t *line_tools = code->_co_monitoring->line_tools;
+ assert(line_tools != NULL);
+ int code_len = (int)Py_SIZE(code);
+ for (int i = 0; i < code_len; i++) {
+ line_tools[i] = all_events->tools[PY_MONITORING_EVENT_LINE];
+ }
+}
+
+static
+int allocate_instrumentation_data(PyCodeObject *code)
+{
+
+ if (code->_co_monitoring == NULL) {
+ code->_co_monitoring = PyMem_Malloc(sizeof(_PyCoMonitoringData));
+ if (code->_co_monitoring == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ code->_co_monitoring->local_monitors = (_Py_Monitors){ 0 };
+ code->_co_monitoring->active_monitors = (_Py_Monitors){ 0 };
+ code->_co_monitoring->tools = NULL;
+ code->_co_monitoring->lines = NULL;
+ code->_co_monitoring->line_tools = NULL;
+ code->_co_monitoring->per_instruction_opcodes = NULL;
+ code->_co_monitoring->per_instruction_tools = NULL;
+ }
+ return 0;
+}
+
+static int
+update_instrumentation_data(PyCodeObject *code, PyInterpreterState *interp)
+{
+ int code_len = (int)Py_SIZE(code);
+ if (allocate_instrumentation_data(code)) {
+ return -1;
+ }
+ _Py_Monitors all_events = monitors_or(
+ interp->monitors,
+ code->_co_monitoring->local_monitors);
+ bool multitools = multiple_tools(&all_events);
+ if (code->_co_monitoring->tools == NULL && multitools) {
+ code->_co_monitoring->tools = PyMem_Malloc(code_len);
+ if (code->_co_monitoring->tools == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ initialize_tools(code);
+ }
+ if (all_events.tools[PY_MONITORING_EVENT_LINE]) {
+ if (code->_co_monitoring->lines == NULL) {
+ code->_co_monitoring->lines = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData));
+ if (code->_co_monitoring->lines == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ initialize_lines(code);
+ }
+ if (multitools && code->_co_monitoring->line_tools == NULL) {
+ code->_co_monitoring->line_tools = PyMem_Malloc(code_len);
+ if (code->_co_monitoring->line_tools == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ initialize_line_tools(code, &all_events);
+ }
+ }
+ if (all_events.tools[PY_MONITORING_EVENT_INSTRUCTION]) {
+ if (code->_co_monitoring->per_instruction_opcodes == NULL) {
+ code->_co_monitoring->per_instruction_opcodes = PyMem_Malloc(code_len * sizeof(_PyCoLineInstrumentationData));
+ if (code->_co_monitoring->per_instruction_opcodes == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */
+ for (int i = 0; i < code_len; i++) {
+ code->_co_monitoring->per_instruction_opcodes[i] = 0;
+ }
+ }
+ if (multitools && code->_co_monitoring->per_instruction_tools == NULL) {
+ code->_co_monitoring->per_instruction_tools = PyMem_Malloc(code_len);
+ if (code->_co_monitoring->per_instruction_tools == NULL) {
+ PyErr_NoMemory();
+ return -1;
+ }
+ /* This may not be necessary, as we can initialize this memory lazily, but it helps catch errors. */
+ for (int i = 0; i < code_len; i++) {
+ code->_co_monitoring->per_instruction_tools[i] = 0;
+ }
+ }
+ }
+ return 0;
+}
+
+static const uint8_t super_instructions[256] = {
+ [LOAD_FAST__LOAD_FAST] = 1,
+ [LOAD_FAST__LOAD_CONST] = 1,
+ [STORE_FAST__LOAD_FAST] = 1,
+ [STORE_FAST__STORE_FAST] = 1,
+ [LOAD_CONST__LOAD_FAST] = 1,
+};
+
+/* Should use instruction metadata for this */
+static bool
+is_super_instruction(int opcode) {
+ return super_instructions[opcode] != 0;
+}
+
+int
+_Py_Instrument(PyCodeObject *code, PyInterpreterState *interp)
+{
+
+ if (is_version_up_to_date(code, interp)) {
+ assert(
+ interp->monitoring_version == 0 ||
+ instrumentation_cross_checks(interp, code)
+ );
+ return 0;
+ }
+ int code_len = (int)Py_SIZE(code);
+ if (update_instrumentation_data(code, interp)) {
+ return -1;
+ }
+ _Py_Monitors active_events = monitors_or(
+ interp->monitors,
+ code->_co_monitoring->local_monitors);
+ _Py_Monitors new_events;
+ _Py_Monitors removed_events;
+
+ bool restarted = interp->last_restart_version > code->_co_instrumentation_version;
+ if (restarted) {
+ removed_events = code->_co_monitoring->active_monitors;
+ new_events = active_events;
+ }
+ else {
+ removed_events = monitors_sub(code->_co_monitoring->active_monitors, active_events);
+ new_events = monitors_sub(active_events, code->_co_monitoring->active_monitors);
+ assert(monitors_are_empty(monitors_and(new_events, removed_events)));
+ }
+ code->_co_monitoring->active_monitors = active_events;
+ code->_co_instrumentation_version = interp->monitoring_version;
+ if (monitors_are_empty(new_events) && monitors_are_empty(removed_events)) {
+#ifdef INSTRUMENT_DEBUG
+ sanity_check_instrumentation(code);
+#endif
+ return 0;
+ }
+ /* Insert instrumentation */
+ for (int i = 0; i < code_len; i+= instruction_length(code, i)) {
+ _Py_CODEUNIT *instr = &_PyCode_CODE(code)[i];
+ if (is_super_instruction(instr->op.code)) {
+ instr->op.code = _PyOpcode_Deopt[instr->op.code];
+ }
+ CHECK(instr->op.code != 0);
+ int base_opcode = _Py_GetBaseOpcode(code, i);
+ if (opcode_has_event(base_opcode)) {
+ int8_t event;
+ if (base_opcode == RESUME) {
+ event = instr->op.arg > 0;
+ }
+ else {
+ event = EVENT_FOR_OPCODE[base_opcode];
+ assert(event > 0);
+ }
+ uint8_t removed_tools = removed_events.tools[event];
+ if (removed_tools) {
+ remove_tools(code, i, event, removed_tools);
+ }
+ uint8_t new_tools = new_events.tools[event];
+ if (new_tools) {
+ add_tools(code, i, event, new_tools);
+ }
+ }
+ }
+ uint8_t new_line_tools = new_events.tools[PY_MONITORING_EVENT_LINE];
+ uint8_t removed_line_tools = removed_events.tools[PY_MONITORING_EVENT_LINE];
+ if (new_line_tools | removed_line_tools) {
+ _PyCoLineInstrumentationData *line_data = code->_co_monitoring->lines;
+ for (int i = code->_co_firsttraceable; i < code_len;) {
+ if (line_data[i].original_opcode) {
+ if (removed_line_tools) {
+ remove_line_tools(code, i, removed_line_tools);
+ }
+ if (new_line_tools) {
+ add_line_tools(code, i, new_line_tools);
+ }
+ }
+ i += instruction_length(code, i);
+ }
+ }
+ uint8_t new_per_instruction_tools = new_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
+ uint8_t removed_per_instruction_tools = removed_events.tools[PY_MONITORING_EVENT_INSTRUCTION];
+ if (new_per_instruction_tools | removed_per_instruction_tools) {
+ for (int i = code->_co_firsttraceable; i < code_len;) {
+ int opcode = _Py_GetBaseOpcode(code, i);
+ if (opcode == RESUME || opcode == END_FOR) {
+ i += instruction_length(code, i);
+ continue;
+ }
+ if (removed_per_instruction_tools) {
+ remove_per_instruction_tools(code, i, removed_per_instruction_tools);
+ }
+ if (new_per_instruction_tools) {
+ add_per_instruction_tools(code, i, new_per_instruction_tools);
+ }
+ i += instruction_length(code, i);
+ }
+ }
+#ifdef INSTRUMENT_DEBUG
+ sanity_check_instrumentation(code);
+#endif
+ return 0;
+}
+
+#define C_RETURN_EVENTS \
+ ((1 << PY_MONITORING_EVENT_C_RETURN) | \
+ (1 << PY_MONITORING_EVENT_C_RAISE))
+
+#define C_CALL_EVENTS \
+ (C_RETURN_EVENTS | (1 << PY_MONITORING_EVENT_CALL))
+
+
+static int
+instrument_all_executing_code_objects(PyInterpreterState *interp) {
+ _PyRuntimeState *runtime = &_PyRuntime;
+ HEAD_LOCK(runtime);
+ PyThreadState* ts = PyInterpreterState_ThreadHead(interp);
+ HEAD_UNLOCK(runtime);
+ while (ts) {
+ _PyInterpreterFrame *frame = ts->cframe->current_frame;
+ while (frame) {
+ if (frame->owner != FRAME_OWNED_BY_CSTACK) {
+ if (_Py_Instrument(frame->f_code, interp)) {
+ return -1;
+ }
+ }
+ frame = frame->previous;
+ }
+ HEAD_LOCK(runtime);
+ ts = PyThreadState_Next(ts);
+ HEAD_UNLOCK(runtime);
+ }
+ return 0;
+}
+
+static void
+set_events(_Py_Monitors *m, int tool_id, _PyMonitoringEventSet events)
+{
+ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
+ for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) {
+ uint8_t *tools = &m->tools[e];
+ int val = (events >> e) & 1;
+ *tools &= ~(1 << tool_id);
+ *tools |= (val << tool_id);
+ }
+}
+
+static int
+check_tool(PyInterpreterState *interp, int tool_id)
+{
+ if (tool_id < PY_MONITORING_SYS_PROFILE_ID &&
+ interp->monitoring_tool_names[tool_id] == NULL
+ ) {
+ PyErr_Format(PyExc_ValueError, "tool %d is not in use", tool_id);
+ return -1;
+ }
+ return 0;
+}
+
+int
+_PyMonitoring_SetEvents(int tool_id, _PyMonitoringEventSet events)
+{
+ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS));
+ if (check_tool(interp, tool_id)) {
+ return -1;
+ }
+ uint32_t existing_events = get_events(&interp->monitors, tool_id);
+ if (existing_events == events) {
+ return 0;
+ }
+ set_events(&interp->monitors, tool_id, events);
+ interp->monitoring_version++;
+ return instrument_all_executing_code_objects(interp);
+}
+
+int
+_PyMonitoring_SetLocalEvents(PyCodeObject *code, int tool_id, _PyMonitoringEventSet events)
+{
+ assert(0 <= tool_id && tool_id < PY_MONITORING_TOOL_IDS);
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ assert(events < (1 << PY_MONITORING_UNGROUPED_EVENTS));
+ if (check_tool(interp, tool_id)) {
+ return -1;
+ }
+ if (allocate_instrumentation_data(code)) {
+ return -1;
+ }
+ _Py_Monitors *local = &code->_co_monitoring->local_monitors;
+ uint32_t existing_events = get_events(local, tool_id);
+ if (existing_events == events) {
+ return 0;
+ }
+ set_events(local, tool_id, events);
+ if (is_version_up_to_date(code, interp)) {
+ /* Force instrumentation update */
+ code->_co_instrumentation_version = UINT64_MAX;
+ }
+ if (_Py_Instrument(code, interp)) {
+ return -1;
+ }
+ return 0;
+}
+
+/*[clinic input]
+module monitoring
+[clinic start generated code]*/
+/*[clinic end generated code: output=da39a3ee5e6b4b0d input=37257f5987a360cf]*/
+/*[clinic end generated code]*/
+
+#include "clinic/instrumentation.c.h"
+
+static int
+check_valid_tool(int tool_id)
+{
+ if (tool_id < 0 || tool_id >= PY_MONITORING_SYS_PROFILE_ID) {
+ PyErr_Format(PyExc_ValueError, "invalid tool %d (must be between 0 and 5)", tool_id);
+ return -1;
+ }
+ return 0;
+}
+
+/*[clinic input]
+monitoring.use_tool_id
+
+ tool_id: int
+ name: object
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_use_tool_id_impl(PyObject *module, int tool_id, PyObject *name)
+/*[clinic end generated code: output=30d76dc92b7cd653 input=ebc453761c621be1]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ if (!PyUnicode_Check(name)) {
+ PyErr_SetString(PyExc_ValueError, "tool name must be a str");
+ return NULL;
+ }
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ if (interp->monitoring_tool_names[tool_id] != NULL) {
+ PyErr_Format(PyExc_ValueError, "tool %d is already in use", tool_id);
+ return NULL;
+ }
+ interp->monitoring_tool_names[tool_id] = Py_NewRef(name);
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+monitoring.free_tool_id
+
+ tool_id: int
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_free_tool_id_impl(PyObject *module, int tool_id)
+/*[clinic end generated code: output=86c2d2a1219a8591 input=a23fb6be3a8618e9]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ Py_CLEAR(interp->monitoring_tool_names[tool_id]);
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+monitoring.get_tool
+
+ tool_id: int
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_get_tool_impl(PyObject *module, int tool_id)
+/*[clinic end generated code: output=1c05a98b404a9a16 input=eeee9bebd0bcae9d]*/
+
+/*[clinic end generated code]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ PyObject *name = interp->monitoring_tool_names[tool_id];
+ if (name == NULL) {
+ Py_RETURN_NONE;
+ }
+ return Py_NewRef(name);
+}
+
+/*[clinic input]
+monitoring.register_callback
+
+
+ tool_id: int
+ event: int
+ func: object
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_register_callback_impl(PyObject *module, int tool_id, int event,
+ PyObject *func)
+/*[clinic end generated code: output=e64daa363004030c input=df6d70ea4cf81007]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ if (_Py_popcount32(event) != 1) {
+ PyErr_SetString(PyExc_ValueError, "The callback can only be set for one event at a time");
+ return NULL;
+ }
+ int event_id = _Py_bit_length(event)-1;
+ if (event_id < 0 || event_id >= PY_MONITORING_EVENTS) {
+ PyErr_Format(PyExc_ValueError, "invalid event %d", event);
+ return NULL;
+ }
+ if (func == Py_None) {
+ func = NULL;
+ }
+ func = _PyMonitoring_RegisterCallback(tool_id, event_id, func);
+ if (func == NULL) {
+ Py_RETURN_NONE;
+ }
+ return func;
+}
+
+/*[clinic input]
+monitoring.get_events -> int
+
+ tool_id: int
+ /
+
+[clinic start generated code]*/
+
+static int
+monitoring_get_events_impl(PyObject *module, int tool_id)
+/*[clinic end generated code: output=4450cc13f826c8c0 input=a64b238f76c4b2f7]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return -1;
+ }
+ _Py_Monitors *m = &_PyInterpreterState_Get()->monitors;
+ _PyMonitoringEventSet event_set = get_events(m, tool_id);
+ return event_set;
+}
+
+/*[clinic input]
+monitoring.set_events
+
+ tool_id: int
+ event_set: int
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_set_events_impl(PyObject *module, int tool_id, int event_set)
+/*[clinic end generated code: output=1916c1e49cfb5bdb input=a77ba729a242142b]*/
+{
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) {
+ PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set);
+ return NULL;
+ }
+ if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) {
+ PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently");
+ return NULL;
+ }
+ event_set &= ~C_RETURN_EVENTS;
+ if (_PyMonitoring_SetEvents(tool_id, event_set)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+monitoring.get_local_events -> int
+
+ tool_id: int
+ code: object
+ /
+
+[clinic start generated code]*/
+
+static int
+monitoring_get_local_events_impl(PyObject *module, int tool_id,
+ PyObject *code)
+/*[clinic end generated code: output=d3e92c1c9c1de8f9 input=bb0f927530386a94]*/
+{
+ if (!PyCode_Check(code)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "code must be a code object"
+ );
+ return -1;
+ }
+ if (check_valid_tool(tool_id)) {
+ return -1;
+ }
+ _PyMonitoringEventSet event_set = 0;
+ _PyCoMonitoringData *data = ((PyCodeObject *)code)->_co_monitoring;
+ if (data != NULL) {
+ for (int e = 0; e < PY_MONITORING_UNGROUPED_EVENTS; e++) {
+ if ((data->local_monitors.tools[e] >> tool_id) & 1) {
+ event_set |= (1 << e);
+ }
+ }
+ }
+ return event_set;
+}
+
+/*[clinic input]
+monitoring.set_local_events
+
+ tool_id: int
+ code: object
+ event_set: int
+ /
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_set_local_events_impl(PyObject *module, int tool_id,
+ PyObject *code, int event_set)
+/*[clinic end generated code: output=68cc755a65dfea99 input=5655ecd78d937a29]*/
+{
+ if (!PyCode_Check(code)) {
+ PyErr_Format(
+ PyExc_TypeError,
+ "code must be a code object"
+ );
+ return NULL;
+ }
+ if (check_valid_tool(tool_id)) {
+ return NULL;
+ }
+ if (event_set < 0 || event_set >= (1 << PY_MONITORING_EVENTS)) {
+ PyErr_Format(PyExc_ValueError, "invalid event set 0x%x", event_set);
+ return NULL;
+ }
+ if ((event_set & C_RETURN_EVENTS) && (event_set & C_CALL_EVENTS) != C_CALL_EVENTS) {
+ PyErr_Format(PyExc_ValueError, "cannot set C_RETURN or C_RAISE events independently");
+ return NULL;
+ }
+ event_set &= ~C_RETURN_EVENTS;
+ if (_PyMonitoring_SetLocalEvents((PyCodeObject*)code, tool_id, event_set)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+/*[clinic input]
+monitoring.restart_events
+
+[clinic start generated code]*/
+
+static PyObject *
+monitoring_restart_events_impl(PyObject *module)
+/*[clinic end generated code: output=e025dd5ba33314c4 input=add8a855063c8008]*/
+{
+ /* We want to ensure that:
+ * last restart version > instrumented version for all code objects
+ * last restart version < current version
+ */
+ PyInterpreterState *interp = _PyInterpreterState_Get();
+ interp->last_restart_version = interp->monitoring_version + 1;
+ interp->monitoring_version = interp->last_restart_version + 1;
+ if (instrument_all_executing_code_objects(interp)) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static int
+add_power2_constant(PyObject *obj, const char *name, int i)
+{
+ PyObject *val = PyLong_FromLong(1<monitors.tools[e];
+ if (tools == 0) {
+ continue;
+ }
+ PyObject *tools_obj = PyLong_FromLong(tools);
+ assert(tools_obj != NULL);
+ int err = PyDict_SetItemString(res, event_names[e], tools_obj);
+ Py_DECREF(tools_obj);
+ if (err < 0) {
+ Py_DECREF(res);
+ return NULL;
+ }
+ }
+ return res;
+}
+
+static PyMethodDef methods[] = {
+ MONITORING_USE_TOOL_ID_METHODDEF
+ MONITORING_FREE_TOOL_ID_METHODDEF
+ MONITORING_GET_TOOL_METHODDEF
+ MONITORING_REGISTER_CALLBACK_METHODDEF
+ MONITORING_GET_EVENTS_METHODDEF
+ MONITORING_SET_EVENTS_METHODDEF
+ MONITORING_GET_LOCAL_EVENTS_METHODDEF
+ MONITORING_SET_LOCAL_EVENTS_METHODDEF
+ MONITORING_RESTART_EVENTS_METHODDEF
+ MONITORING__ALL_EVENTS_METHODDEF
+ {NULL, NULL} // sentinel
+};
+
+static struct PyModuleDef monitoring_module = {
+ PyModuleDef_HEAD_INIT,
+ .m_name = "sys.monitoring",
+ .m_size = -1, /* multiple "initialization" just copies the module dict. */
+ .m_methods = methods,
+};
+
+PyObject *_Py_CreateMonitoringObject(void)
+{
+ PyObject *mod = _PyModule_CreateInitialized(&monitoring_module, PYTHON_API_VERSION);
+ if (mod == NULL) {
+ return NULL;
+ }
+ if (PyObject_SetAttrString(mod, "DISABLE", &DISABLE)) {
+ goto error;
+ }
+ if (PyObject_SetAttrString(mod, "MISSING", &_PyInstrumentation_MISSING)) {
+ goto error;
+ }
+ PyObject *events = _PyNamespace_New(NULL);
+ if (events == NULL) {
+ goto error;
+ }
+ int err = PyObject_SetAttrString(mod, "events", events);
+ Py_DECREF(events);
+ if (err) {
+ goto error;
+ }
+ for (int i = 0; i < PY_MONITORING_EVENTS; i++) {
+ if (add_power2_constant(events, event_names[i], i)) {
+ goto error;
+ }
+ }
+ err = PyObject_SetAttrString(events, "NO_EVENTS", _PyLong_GetZero());
+ if (err) goto error;
+ PyObject *val = PyLong_FromLong(PY_MONITORING_DEBUGGER_ID);
+ err = PyObject_SetAttrString(mod, "DEBUGGER_ID", val);
+ Py_DECREF(val);
+ if (err) goto error;
+ val = PyLong_FromLong(PY_MONITORING_COVERAGE_ID);
+ err = PyObject_SetAttrString(mod, "COVERAGE_ID", val);
+ Py_DECREF(val);
+ if (err) goto error;
+ val = PyLong_FromLong(PY_MONITORING_PROFILER_ID);
+ err = PyObject_SetAttrString(mod, "PROFILER_ID", val);
+ Py_DECREF(val);
+ if (err) goto error;
+ val = PyLong_FromLong(PY_MONITORING_OPTIMIZER_ID);
+ err = PyObject_SetAttrString(mod, "OPTIMIZER_ID", val);
+ Py_DECREF(val);
+ if (err) goto error;
+ return mod;
+error:
+ Py_DECREF(mod);
+ return NULL;
+}
diff --git a/Python/legacy_tracing.c b/Python/legacy_tracing.c
new file mode 100644
index 00000000000000..e509e63a087a52
--- /dev/null
+++ b/Python/legacy_tracing.c
@@ -0,0 +1,528 @@
+/* Support for legacy tracing on top of PEP 669 instrumentation
+ * Provides callables to forward PEP 669 events to legacy events.
+ */
+
+#include
+#include "Python.h"
+#include "pycore_ceval.h"
+#include "pycore_object.h"
+#include "pycore_sysmodule.h"
+
+typedef struct _PyLegacyEventHandler {
+ PyObject_HEAD
+ vectorcallfunc vectorcall;
+ int event;
+} _PyLegacyEventHandler;
+
+/* The Py_tracefunc function expects the following arguments:
+ * obj: the trace object (PyObject *)
+ * frame: the current frame (PyFrameObject *)
+ * kind: the kind of event, see PyTrace_XXX #defines (int)
+ * arg: The arg (a PyObject *)
+ */
+
+static PyObject *
+call_profile_func(_PyLegacyEventHandler *self, PyObject *arg)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate->c_profilefunc == NULL) {
+ Py_RETURN_NONE;
+ }
+ PyFrameObject *frame = PyEval_GetFrame();
+ if (frame == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Missing frame when calling profile function.");
+ return NULL;
+ }
+ Py_INCREF(frame);
+ int err = tstate->c_profilefunc(tstate->c_profileobj, frame, self->event, arg);
+ Py_DECREF(frame);
+ if (err) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+sys_profile_func2(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 2);
+ return call_profile_func(self, Py_None);
+}
+
+static PyObject *
+sys_profile_func3(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ return call_profile_func(self, args[2]);
+}
+
+static PyObject *
+sys_profile_call_or_return(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 4);
+ PyObject *callable = args[2];
+ if (PyCFunction_Check(callable)) {
+ return call_profile_func(self, callable);
+ }
+ if (Py_TYPE(callable) == &PyMethodDescr_Type) {
+ PyObject *self_arg = args[3];
+ /* For backwards compatibility need to
+ * convert to builtin method */
+
+ /* If no arg, skip */
+ if (self_arg == &_PyInstrumentation_MISSING) {
+ Py_RETURN_NONE;
+ }
+ PyObject *meth = Py_TYPE(callable)->tp_descr_get(
+ callable, self_arg, (PyObject*)Py_TYPE(self_arg));
+ if (meth == NULL) {
+ return NULL;
+ }
+ PyObject *res = call_profile_func(self, meth);
+ Py_DECREF(meth);
+ return res;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+call_trace_func(_PyLegacyEventHandler *self, PyObject *arg)
+{
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate->c_tracefunc == NULL) {
+ Py_RETURN_NONE;
+ }
+ PyFrameObject *frame = PyEval_GetFrame();
+ if (frame == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Missing frame when calling trace function.");
+ return NULL;
+ }
+ Py_INCREF(frame);
+ int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, arg);
+ Py_DECREF(frame);
+ if (err) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+sys_trace_exception_func(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ PyObject *exc = args[2];
+ assert(PyExceptionInstance_Check(exc));
+ PyObject *type = (PyObject *)Py_TYPE(exc);
+ PyObject *tb = PyException_GetTraceback(exc);
+ if (tb == NULL) {
+ tb = Py_NewRef(Py_None);
+ }
+ PyObject *tuple = PyTuple_Pack(3, type, exc, tb);
+ Py_DECREF(tb);
+ if (tuple == NULL) {
+ return NULL;
+ }
+ PyObject *res = call_trace_func(self, tuple);
+ Py_DECREF(tuple);
+ return res;
+}
+
+static PyObject *
+sys_trace_func2(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 2);
+ return call_trace_func(self, Py_None);
+}
+
+static PyObject *
+sys_trace_return(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(!PyErr_Occurred());
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ assert(PyCode_Check(args[0]));
+ PyObject *val = args[2];
+ PyObject *res = call_trace_func(self, val);
+ return res;
+}
+
+static PyObject *
+sys_trace_yield(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ return call_trace_func(self, args[2]);
+}
+
+static PyObject *
+sys_trace_instruction_func(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ assert(PyVectorcall_NARGS(nargsf) == 2);
+ PyFrameObject *frame = PyEval_GetFrame();
+ if (frame == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Missing frame when calling trace function.");
+ return NULL;
+ }
+ if (!frame->f_trace_opcodes) {
+ Py_RETURN_NONE;
+ }
+ Py_INCREF(frame);
+ PyThreadState *tstate = _PyThreadState_GET();
+ int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None);
+ frame->f_lineno = 0;
+ Py_DECREF(frame);
+ if (err) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+trace_line(
+ PyThreadState *tstate, _PyLegacyEventHandler *self,
+ PyFrameObject *frame, int line
+) {
+ if (!frame->f_trace_lines) {
+ Py_RETURN_NONE;
+ }
+ if (line < 0) {
+ Py_RETURN_NONE;
+ }
+ frame ->f_last_traced_line = line;
+ Py_INCREF(frame);
+ frame->f_lineno = line;
+ int err = tstate->c_tracefunc(tstate->c_traceobj, frame, self->event, Py_None);
+ frame->f_lineno = 0;
+ Py_DECREF(frame);
+ if (err) {
+ return NULL;
+ }
+ Py_RETURN_NONE;
+}
+
+static PyObject *
+sys_trace_line_func(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate->c_tracefunc == NULL) {
+ Py_RETURN_NONE;
+ }
+ assert(PyVectorcall_NARGS(nargsf) == 2);
+ int line = _PyLong_AsInt(args[1]);
+ assert(line >= 0);
+ PyFrameObject *frame = PyEval_GetFrame();
+ if (frame == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Missing frame when calling trace function.");
+ return NULL;
+ }
+ assert(args[0] == (PyObject *)frame->f_frame->f_code);
+ if (frame ->f_last_traced_line == line) {
+ /* Already traced this line */
+ Py_RETURN_NONE;
+ }
+ return trace_line(tstate, self, frame, line);
+}
+
+
+static PyObject *
+sys_trace_jump_func(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate->c_tracefunc == NULL) {
+ Py_RETURN_NONE;
+ }
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ int from = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT);
+ assert(from >= 0);
+ int to = _PyLong_AsInt(args[2])/sizeof(_Py_CODEUNIT);
+ assert(to >= 0);
+ PyFrameObject *frame = PyEval_GetFrame();
+ if (frame == NULL) {
+ PyErr_SetString(PyExc_SystemError,
+ "Missing frame when calling trace function.");
+ return NULL;
+ }
+ if (!frame->f_trace_lines) {
+ Py_RETURN_NONE;
+ }
+ PyCodeObject *code = (PyCodeObject *)args[0];
+ assert(PyCode_Check(code));
+ assert(code == frame->f_frame->f_code);
+ /* We can call _Py_Instrumentation_GetLine because we always set
+ * line events for tracing */
+ int to_line = _Py_Instrumentation_GetLine(code, to);
+ /* Backward jump: Always generate event
+ * Forward jump: Only generate event if jumping to different line. */
+ if (to > from && frame->f_last_traced_line == to_line) {
+ /* Already traced this line */
+ Py_RETURN_NONE;
+ }
+ return trace_line(tstate, self, frame, to_line);
+}
+
+/* We don't care about the exception here,
+ * we just treat it as a possible new line
+ */
+static PyObject *
+sys_trace_exception_handled(
+ _PyLegacyEventHandler *self, PyObject *const *args,
+ size_t nargsf, PyObject *kwnames
+) {
+ assert(kwnames == NULL);
+ PyThreadState *tstate = _PyThreadState_GET();
+ if (tstate->c_tracefunc == NULL) {
+ Py_RETURN_NONE;
+ }
+ assert(PyVectorcall_NARGS(nargsf) == 3);
+ PyFrameObject *frame = PyEval_GetFrame();
+ PyCodeObject *code = (PyCodeObject *)args[0];
+ assert(PyCode_Check(code));
+ assert(code == frame->f_frame->f_code);
+ assert(PyLong_Check(args[1]));
+ int offset = _PyLong_AsInt(args[1])/sizeof(_Py_CODEUNIT);
+ /* We can call _Py_Instrumentation_GetLine because we always set
+ * line events for tracing */
+ int line = _Py_Instrumentation_GetLine(code, offset);
+ if (frame->f_last_traced_line == line) {
+ /* Already traced this line */
+ Py_RETURN_NONE;
+ }
+ return trace_line(tstate, self, frame, line);
+}
+
+
+PyTypeObject _PyLegacyEventHandler_Type = {
+ PyVarObject_HEAD_INIT(&PyType_Type, 0)
+ "sys.legacy_event_handler",
+ sizeof(_PyLegacyEventHandler),
+ .tp_dealloc = (destructor)PyObject_Free,
+ .tp_vectorcall_offset = offsetof(_PyLegacyEventHandler, vectorcall),
+ .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE |
+ Py_TPFLAGS_HAVE_VECTORCALL | Py_TPFLAGS_DISALLOW_INSTANTIATION,
+ .tp_call = PyVectorcall_Call,
+};
+
+static int
+set_callbacks(int tool, vectorcallfunc vectorcall, int legacy_event, int event1, int event2)
+{
+ _PyLegacyEventHandler *callback =
+ PyObject_NEW(_PyLegacyEventHandler, &_PyLegacyEventHandler_Type);
+ if (callback == NULL) {
+ return -1;
+ }
+ callback->vectorcall = vectorcall;
+ callback->event = legacy_event;
+ Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event1, (PyObject *)callback));
+ if (event2 >= 0) {
+ Py_XDECREF(_PyMonitoring_RegisterCallback(tool, event2, (PyObject *)callback));
+ }
+ Py_DECREF(callback);
+ return 0;
+}
+
+#ifndef NDEBUG
+/* Ensure that tstate is valid: sanity check for PyEval_AcquireThread() and
+ PyEval_RestoreThread(). Detect if tstate memory was freed. It can happen
+ when a thread continues to run after Python finalization, especially
+ daemon threads. */
+static int
+is_tstate_valid(PyThreadState *tstate)
+{
+ assert(!_PyMem_IsPtrFreed(tstate));
+ assert(!_PyMem_IsPtrFreed(tstate->interp));
+ return 1;
+}
+#endif
+
+int
+_PyEval_SetProfile(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+{
+ assert(is_tstate_valid(tstate));
+ /* The caller must hold the GIL */
+ assert(PyGILState_Check());
+
+ /* Call _PySys_Audit() in the context of the current thread state,
+ even if tstate is not the current thread state. */
+ PyThreadState *current_tstate = _PyThreadState_GET();
+ if (_PySys_Audit(current_tstate, "sys.setprofile", NULL) < 0) {
+ return -1;
+ }
+ /* Setup PEP 669 monitoring callbacks and events. */
+ if (!tstate->interp->sys_profile_initialized) {
+ tstate->interp->sys_profile_initialized = true;
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_func2, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_func3, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_RETURN, PY_MONITORING_EVENT_PY_YIELD)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_func2, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_CALL,
+ PY_MONITORING_EVENT_CALL, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_RETURN,
+ PY_MONITORING_EVENT_C_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_PROFILE_ID,
+ (vectorcallfunc)sys_profile_call_or_return, PyTrace_C_EXCEPTION,
+ PY_MONITORING_EVENT_C_RAISE, -1)) {
+ return -1;
+ }
+ }
+
+ int delta = (func != NULL) - (tstate->c_profilefunc != NULL);
+ tstate->c_profilefunc = func;
+ PyObject *old_profileobj = tstate->c_profileobj;
+ tstate->c_profileobj = Py_XNewRef(arg);
+ Py_XDECREF(old_profileobj);
+ tstate->interp->sys_profiling_threads += delta;
+ assert(tstate->interp->sys_profiling_threads >= 0);
+
+ uint32_t events = 0;
+ if (tstate->interp->sys_profiling_threads) {
+ events =
+ (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
+ (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
+ (1 << PY_MONITORING_EVENT_CALL) | (1 << PY_MONITORING_EVENT_PY_UNWIND);
+ }
+ return _PyMonitoring_SetEvents(PY_MONITORING_SYS_PROFILE_ID, events);
+}
+
+int
+_PyEval_SetTrace(PyThreadState *tstate, Py_tracefunc func, PyObject *arg)
+{
+ assert(is_tstate_valid(tstate));
+ /* The caller must hold the GIL */
+ assert(PyGILState_Check());
+
+ /* Call _PySys_Audit() in the context of the current thread state,
+ even if tstate is not the current thread state. */
+ PyThreadState *current_tstate = _PyThreadState_GET();
+ if (_PySys_Audit(current_tstate, "sys.settrace", NULL) < 0) {
+ return -1;
+ }
+
+ assert(tstate->interp->sys_tracing_threads >= 0);
+ /* Setup PEP 669 monitoring callbacks and events. */
+ if (!tstate->interp->sys_trace_initialized) {
+ tstate->interp->sys_trace_initialized = true;
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_func2, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_START, PY_MONITORING_EVENT_PY_RESUME)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_func2, PyTrace_CALL,
+ PY_MONITORING_EVENT_PY_THROW, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_return, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_RETURN, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_yield, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_YIELD, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_exception_func, PyTrace_EXCEPTION,
+ PY_MONITORING_EVENT_RAISE, PY_MONITORING_EVENT_STOP_ITERATION)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_line_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_LINE, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_func2, PyTrace_RETURN,
+ PY_MONITORING_EVENT_PY_UNWIND, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_jump_func, PyTrace_LINE,
+ PY_MONITORING_EVENT_JUMP, PY_MONITORING_EVENT_BRANCH)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_instruction_func, PyTrace_OPCODE,
+ PY_MONITORING_EVENT_INSTRUCTION, -1)) {
+ return -1;
+ }
+ if (set_callbacks(PY_MONITORING_SYS_TRACE_ID,
+ (vectorcallfunc)sys_trace_exception_handled, PyTrace_LINE,
+ PY_MONITORING_EVENT_EXCEPTION_HANDLED, -1)) {
+ return -1;
+ }
+ }
+
+ int delta = (func != NULL) - (tstate->c_tracefunc != NULL);
+ tstate->c_tracefunc = func;
+ PyObject *old_traceobj = tstate->c_traceobj;
+ tstate->c_traceobj = Py_XNewRef(arg);
+ Py_XDECREF(old_traceobj);
+ tstate->interp->sys_tracing_threads += delta;
+ assert(tstate->interp->sys_tracing_threads >= 0);
+
+ uint32_t events = 0;
+ if (tstate->interp->sys_tracing_threads) {
+ events =
+ (1 << PY_MONITORING_EVENT_PY_START) | (1 << PY_MONITORING_EVENT_PY_RESUME) |
+ (1 << PY_MONITORING_EVENT_PY_RETURN) | (1 << PY_MONITORING_EVENT_PY_YIELD) |
+ (1 << PY_MONITORING_EVENT_RAISE) | (1 << PY_MONITORING_EVENT_LINE) |
+ (1 << PY_MONITORING_EVENT_JUMP) | (1 << PY_MONITORING_EVENT_BRANCH) |
+ (1 << PY_MONITORING_EVENT_PY_UNWIND) | (1 << PY_MONITORING_EVENT_PY_THROW) |
+ (1 << PY_MONITORING_EVENT_STOP_ITERATION) |
+ (1 << PY_MONITORING_EVENT_EXCEPTION_HANDLED);
+ if (tstate->interp->f_opcode_trace_set) {
+ events |= (1 << PY_MONITORING_EVENT_INSTRUCTION);
+ }
+ }
+ return _PyMonitoring_SetEvents(PY_MONITORING_SYS_TRACE_ID, events);
+}
diff --git a/Python/makeopcodetargets.py b/Python/makeopcodetargets.py
index 33a4b4a76a1253..5aa31803397ce4 100755
--- a/Python/makeopcodetargets.py
+++ b/Python/makeopcodetargets.py
@@ -32,7 +32,6 @@ def write_contents(f):
"""
opcode = find_module('opcode')
targets = ['_unknown_opcode'] * 256
- targets[255] = "TARGET_DO_TRACING"
for opname, op in opcode.opmap.items():
if not opcode.is_pseudo(op):
targets[op] = "TARGET_%s" % opname
diff --git a/Python/opcode_metadata.h b/Python/opcode_metadata.h
index f57b76aeb31050..77f0ae0c1a4c30 100644
--- a/Python/opcode_metadata.h
+++ b/Python/opcode_metadata.h
@@ -13,6 +13,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case RESUME:
return 0;
+ case INSTRUMENTED_RESUME:
+ return 0;
case LOAD_CLOSURE:
return 0;
case LOAD_FAST_CHECK:
@@ -39,6 +41,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 0;
case END_FOR:
return 1+1;
+ case INSTRUMENTED_END_FOR:
+ return 2;
+ case END_SEND:
+ return 2;
+ case INSTRUMENTED_END_SEND:
+ return 2;
case UNARY_NEGATIVE:
return 1;
case UNARY_NOT:
@@ -97,8 +105,12 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case RETURN_VALUE:
return 1;
+ case INSTRUMENTED_RETURN_VALUE:
+ return 1;
case RETURN_CONST:
return 0;
+ case INSTRUMENTED_RETURN_CONST:
+ return 0;
case GET_AITER:
return 1;
case GET_ANEXT:
@@ -109,6 +121,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 2;
case SEND_GEN:
return 2;
+ case INSTRUMENTED_YIELD_VALUE:
+ return 1;
case YIELD_VALUE:
return 1;
case POP_EXCEPT:
@@ -191,6 +205,10 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case MAP_ADD:
return 2;
+ case LOAD_SUPER_ATTR:
+ return 3;
+ case LOAD_SUPER_ATTR_METHOD:
+ return 3;
case LOAD_ATTR:
return 1;
case LOAD_ATTR_INSTANCE_VALUE:
@@ -263,6 +281,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case FOR_ITER:
return 1;
+ case INSTRUMENTED_FOR_ITER:
+ return 0;
case FOR_ITER_LIST:
return 1;
case FOR_ITER_TUPLE:
@@ -287,6 +307,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 1;
case KW_NAMES:
return 0;
+ case INSTRUMENTED_CALL:
+ return 0;
case CALL:
return oparg + 2;
case CALL_BOUND_METHOD_EXACT_ARGS:
@@ -323,6 +345,8 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return oparg + 2;
case CALL_NO_KW_METHOD_DESCRIPTOR_FAST:
return oparg + 2;
+ case INSTRUMENTED_CALL_FUNCTION_EX:
+ return 0;
case CALL_FUNCTION_EX:
return ((oparg & 1) ? 1 : 0) + 3;
case MAKE_FUNCTION:
@@ -339,10 +363,28 @@ _PyOpcode_num_popped(int opcode, int oparg, bool jump) {
return 2;
case SWAP:
return (oparg-2) + 2;
+ case INSTRUMENTED_LINE:
+ return 0;
+ case INSTRUMENTED_INSTRUCTION:
+ return 0;
+ case INSTRUMENTED_JUMP_FORWARD:
+ return 0;
+ case INSTRUMENTED_JUMP_BACKWARD:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_TRUE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_FALSE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_NONE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_NOT_NONE:
+ return 0;
case EXTENDED_ARG:
return 0;
case CACHE:
return 0;
+ case RESERVED:
+ return 0;
default:
return -1;
}
@@ -359,6 +401,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case RESUME:
return 0;
+ case INSTRUMENTED_RESUME:
+ return 0;
case LOAD_CLOSURE:
return 1;
case LOAD_FAST_CHECK:
@@ -385,6 +429,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case END_FOR:
return 0+0;
+ case INSTRUMENTED_END_FOR:
+ return 0;
+ case END_SEND:
+ return 1;
+ case INSTRUMENTED_END_SEND:
+ return 1;
case UNARY_NEGATIVE:
return 1;
case UNARY_NOT:
@@ -443,8 +493,12 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case RETURN_VALUE:
return 0;
+ case INSTRUMENTED_RETURN_VALUE:
+ return 0;
case RETURN_CONST:
return 0;
+ case INSTRUMENTED_RETURN_CONST:
+ return 0;
case GET_AITER:
return 1;
case GET_ANEXT:
@@ -455,6 +509,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 2;
case SEND_GEN:
return 1;
+ case INSTRUMENTED_YIELD_VALUE:
+ return 1;
case YIELD_VALUE:
return 1;
case POP_EXCEPT:
@@ -537,6 +593,10 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 0;
case MAP_ADD:
return 0;
+ case LOAD_SUPER_ATTR:
+ return ((oparg & 1) ? 1 : 0) + 1;
+ case LOAD_SUPER_ATTR_METHOD:
+ return 2;
case LOAD_ATTR:
return ((oparg & 1) ? 1 : 0) + 1;
case LOAD_ATTR_INSTANCE_VALUE:
@@ -609,6 +669,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case FOR_ITER:
return 2;
+ case INSTRUMENTED_FOR_ITER:
+ return 0;
case FOR_ITER_LIST:
return 2;
case FOR_ITER_TUPLE:
@@ -633,6 +695,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return ((oparg & 1) ? 1 : 0) + 1;
case KW_NAMES:
return 0;
+ case INSTRUMENTED_CALL:
+ return 0;
case CALL:
return 1;
case CALL_BOUND_METHOD_EXACT_ARGS:
@@ -669,6 +733,8 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case CALL_NO_KW_METHOD_DESCRIPTOR_FAST:
return 1;
+ case INSTRUMENTED_CALL_FUNCTION_EX:
+ return 0;
case CALL_FUNCTION_EX:
return 1;
case MAKE_FUNCTION:
@@ -685,17 +751,35 @@ _PyOpcode_num_pushed(int opcode, int oparg, bool jump) {
return 1;
case SWAP:
return (oparg-2) + 2;
+ case INSTRUMENTED_LINE:
+ return 0;
+ case INSTRUMENTED_INSTRUCTION:
+ return 0;
+ case INSTRUMENTED_JUMP_FORWARD:
+ return 0;
+ case INSTRUMENTED_JUMP_BACKWARD:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_TRUE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_FALSE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_NONE:
+ return 0;
+ case INSTRUMENTED_POP_JUMP_IF_NOT_NONE:
+ return 0;
case EXTENDED_ARG:
return 0;
case CACHE:
return 0;
+ case RESERVED:
+ return 0;
default:
return -1;
}
}
#endif
-enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000 };
+enum InstructionFormat { INSTR_FMT_IB, INSTR_FMT_IBC, INSTR_FMT_IBC00, INSTR_FMT_IBC000, INSTR_FMT_IBC00000000, INSTR_FMT_IBIB, INSTR_FMT_IX, INSTR_FMT_IXC, INSTR_FMT_IXC000, INSTR_FMT_IXC00000000 };
struct opcode_metadata {
bool valid_entry;
enum InstructionFormat instr_format;
@@ -707,6 +791,7 @@ extern const struct opcode_metadata _PyOpcode_opcode_metadata[256];
const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[NOP] = { true, INSTR_FMT_IX },
[RESUME] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_RESUME] = { true, INSTR_FMT_IB },
[LOAD_CLOSURE] = { true, INSTR_FMT_IB },
[LOAD_FAST_CHECK] = { true, INSTR_FMT_IB },
[LOAD_FAST] = { true, INSTR_FMT_IB },
@@ -720,6 +805,9 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[POP_TOP] = { true, INSTR_FMT_IX },
[PUSH_NULL] = { true, INSTR_FMT_IX },
[END_FOR] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_END_FOR] = { true, INSTR_FMT_IX },
+ [END_SEND] = { true, INSTR_FMT_IX },
+ [INSTRUMENTED_END_SEND] = { true, INSTR_FMT_IX },
[UNARY_NEGATIVE] = { true, INSTR_FMT_IX },
[UNARY_NOT] = { true, INSTR_FMT_IX },
[UNARY_INVERT] = { true, INSTR_FMT_IX },
@@ -749,12 +837,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[RAISE_VARARGS] = { true, INSTR_FMT_IB },
[INTERPRETER_EXIT] = { true, INSTR_FMT_IX },
[RETURN_VALUE] = { true, INSTR_FMT_IX },
+ [INSTRUMENTED_RETURN_VALUE] = { true, INSTR_FMT_IX },
[RETURN_CONST] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_RETURN_CONST] = { true, INSTR_FMT_IB },
[GET_AITER] = { true, INSTR_FMT_IX },
[GET_ANEXT] = { true, INSTR_FMT_IX },
[GET_AWAITABLE] = { true, INSTR_FMT_IB },
[SEND] = { true, INSTR_FMT_IBC },
[SEND_GEN] = { true, INSTR_FMT_IBC },
+ [INSTRUMENTED_YIELD_VALUE] = { true, INSTR_FMT_IX },
[YIELD_VALUE] = { true, INSTR_FMT_IX },
[POP_EXCEPT] = { true, INSTR_FMT_IX },
[RERAISE] = { true, INSTR_FMT_IB },
@@ -796,6 +887,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[DICT_UPDATE] = { true, INSTR_FMT_IB },
[DICT_MERGE] = { true, INSTR_FMT_IB },
[MAP_ADD] = { true, INSTR_FMT_IB },
+ [LOAD_SUPER_ATTR] = { true, INSTR_FMT_IBC00000000 },
+ [LOAD_SUPER_ATTR_METHOD] = { true, INSTR_FMT_IXC00000000 },
[LOAD_ATTR] = { true, INSTR_FMT_IBC00000000 },
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000 },
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000 },
@@ -832,6 +925,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[GET_ITER] = { true, INSTR_FMT_IX },
[GET_YIELD_FROM_ITER] = { true, INSTR_FMT_IX },
[FOR_ITER] = { true, INSTR_FMT_IBC },
+ [INSTRUMENTED_FOR_ITER] = { true, INSTR_FMT_IB },
[FOR_ITER_LIST] = { true, INSTR_FMT_IBC },
[FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC },
[FOR_ITER_RANGE] = { true, INSTR_FMT_IBC },
@@ -844,6 +938,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000 },
[LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000 },
[KW_NAMES] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_CALL] = { true, INSTR_FMT_IB },
[CALL] = { true, INSTR_FMT_IBC00 },
[CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00 },
[CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00 },
@@ -862,6 +957,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00 },
[CALL_NO_KW_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00 },
[CALL_NO_KW_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00 },
+ [INSTRUMENTED_CALL_FUNCTION_EX] = { true, INSTR_FMT_IX },
[CALL_FUNCTION_EX] = { true, INSTR_FMT_IB },
[MAKE_FUNCTION] = { true, INSTR_FMT_IB },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX },
@@ -870,7 +966,16 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[256] = {
[COPY] = { true, INSTR_FMT_IB },
[BINARY_OP] = { true, INSTR_FMT_IBC },
[SWAP] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_LINE] = { true, INSTR_FMT_IX },
+ [INSTRUMENTED_INSTRUCTION] = { true, INSTR_FMT_IX },
+ [INSTRUMENTED_JUMP_FORWARD] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_JUMP_BACKWARD] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_POP_JUMP_IF_TRUE] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_POP_JUMP_IF_FALSE] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_POP_JUMP_IF_NONE] = { true, INSTR_FMT_IB },
+ [INSTRUMENTED_POP_JUMP_IF_NOT_NONE] = { true, INSTR_FMT_IB },
[EXTENDED_ARG] = { true, INSTR_FMT_IB },
[CACHE] = { true, INSTR_FMT_IX },
+ [RESERVED] = { true, INSTR_FMT_IX },
};
#endif
diff --git a/Python/opcode_targets.h b/Python/opcode_targets.h
index c502471bcd17b6..042cee222f705c 100644
--- a/Python/opcode_targets.h
+++ b/Python/opcode_targets.h
@@ -4,17 +4,19 @@ static void *opcode_targets[256] = {
&&TARGET_PUSH_NULL,
&&TARGET_INTERPRETER_EXIT,
&&TARGET_END_FOR,
+ &&TARGET_END_SEND,
&&TARGET_BINARY_OP_ADD_FLOAT,
&&TARGET_BINARY_OP_ADD_INT,
&&TARGET_BINARY_OP_ADD_UNICODE,
- &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE,
&&TARGET_NOP,
- &&TARGET_BINARY_OP_MULTIPLY_FLOAT,
+ &&TARGET_BINARY_OP_INPLACE_ADD_UNICODE,
&&TARGET_UNARY_NEGATIVE,
&&TARGET_UNARY_NOT,
+ &&TARGET_BINARY_OP_MULTIPLY_FLOAT,
&&TARGET_BINARY_OP_MULTIPLY_INT,
- &&TARGET_BINARY_OP_SUBTRACT_FLOAT,
&&TARGET_UNARY_INVERT,
+ &&TARGET_BINARY_OP_SUBTRACT_FLOAT,
+ &&TARGET_RESERVED,
&&TARGET_BINARY_OP_SUBTRACT_INT,
&&TARGET_BINARY_SUBSCR_DICT,
&&TARGET_BINARY_SUBSCR_GETITEM,
@@ -22,21 +24,21 @@ static void *opcode_targets[256] = {
&&TARGET_BINARY_SUBSCR_TUPLE_INT,
&&TARGET_CALL_PY_EXACT_ARGS,
&&TARGET_CALL_PY_WITH_DEFAULTS,
- &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS,
- &&TARGET_CALL_BUILTIN_CLASS,
&&TARGET_BINARY_SUBSCR,
&&TARGET_BINARY_SLICE,
&&TARGET_STORE_SLICE,
- &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
- &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
+ &&TARGET_CALL_BOUND_METHOD_EXACT_ARGS,
+ &&TARGET_CALL_BUILTIN_CLASS,
&&TARGET_GET_LEN,
&&TARGET_MATCH_MAPPING,
&&TARGET_MATCH_SEQUENCE,
&&TARGET_MATCH_KEYS,
- &&TARGET_CALL_NO_KW_BUILTIN_FAST,
+ &&TARGET_CALL_BUILTIN_FAST_WITH_KEYWORDS,
&&TARGET_PUSH_EXC_INFO,
&&TARGET_CHECK_EXC_MATCH,
&&TARGET_CHECK_EG_MATCH,
+ &&TARGET_CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS,
+ &&TARGET_CALL_NO_KW_BUILTIN_FAST,
&&TARGET_CALL_NO_KW_BUILTIN_O,
&&TARGET_CALL_NO_KW_ISINSTANCE,
&&TARGET_CALL_NO_KW_LEN,
@@ -46,8 +48,6 @@ static void *opcode_targets[256] = {
&&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_COMPARE_OP_FLOAT,
&&TARGET_WITH_EXCEPT_START,
&&TARGET_GET_AITER,
&&TARGET_GET_ANEXT,
@@ -55,39 +55,39 @@ static void *opcode_targets[256] = {
&&TARGET_BEFORE_WITH,
&&TARGET_END_ASYNC_FOR,
&&TARGET_CLEANUP_THROW,
+ &&TARGET_CALL_NO_KW_TYPE_1,
+ &&TARGET_COMPARE_OP_FLOAT,
&&TARGET_COMPARE_OP_INT,
&&TARGET_COMPARE_OP_STR,
- &&TARGET_FOR_ITER_LIST,
- &&TARGET_FOR_ITER_TUPLE,
&&TARGET_STORE_SUBSCR,
&&TARGET_DELETE_SUBSCR,
+ &&TARGET_FOR_ITER_LIST,
+ &&TARGET_FOR_ITER_TUPLE,
&&TARGET_FOR_ITER_RANGE,
&&TARGET_FOR_ITER_GEN,
+ &&TARGET_LOAD_SUPER_ATTR_METHOD,
&&TARGET_LOAD_ATTR_CLASS,
+ &&TARGET_GET_ITER,
+ &&TARGET_GET_YIELD_FROM_ITER,
&&TARGET_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN,
+ &&TARGET_LOAD_BUILD_CLASS,
&&TARGET_LOAD_ATTR_INSTANCE_VALUE,
&&TARGET_LOAD_ATTR_MODULE,
- &&TARGET_GET_ITER,
- &&TARGET_GET_YIELD_FROM_ITER,
+ &&TARGET_LOAD_ASSERTION_ERROR,
+ &&TARGET_RETURN_GENERATOR,
&&TARGET_LOAD_ATTR_PROPERTY,
- &&TARGET_LOAD_BUILD_CLASS,
&&TARGET_LOAD_ATTR_SLOT,
&&TARGET_LOAD_ATTR_WITH_HINT,
- &&TARGET_LOAD_ASSERTION_ERROR,
- &&TARGET_RETURN_GENERATOR,
&&TARGET_LOAD_ATTR_METHOD_LAZY_DICT,
&&TARGET_LOAD_ATTR_METHOD_NO_DICT,
&&TARGET_LOAD_ATTR_METHOD_WITH_VALUES,
&&TARGET_LOAD_CONST__LOAD_FAST,
+ &&TARGET_RETURN_VALUE,
&&TARGET_LOAD_FAST__LOAD_CONST,
+ &&TARGET_SETUP_ANNOTATIONS,
&&TARGET_LOAD_FAST__LOAD_FAST,
&&TARGET_LOAD_GLOBAL_BUILTIN,
- &&TARGET_RETURN_VALUE,
&&TARGET_LOAD_GLOBAL_MODULE,
- &&TARGET_SETUP_ANNOTATIONS,
- &&TARGET_STORE_ATTR_INSTANCE_VALUE,
- &&TARGET_STORE_ATTR_SLOT,
- &&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_POP_EXCEPT,
&&TARGET_STORE_NAME,
&&TARGET_DELETE_NAME,
@@ -110,9 +110,9 @@ static void *opcode_targets[256] = {
&&TARGET_IMPORT_NAME,
&&TARGET_IMPORT_FROM,
&&TARGET_JUMP_FORWARD,
- &&TARGET_STORE_FAST__LOAD_FAST,
- &&TARGET_STORE_FAST__STORE_FAST,
- &&TARGET_STORE_SUBSCR_DICT,
+ &&TARGET_STORE_ATTR_INSTANCE_VALUE,
+ &&TARGET_STORE_ATTR_SLOT,
+ &&TARGET_STORE_ATTR_WITH_HINT,
&&TARGET_POP_JUMP_IF_FALSE,
&&TARGET_POP_JUMP_IF_TRUE,
&&TARGET_LOAD_GLOBAL,
@@ -140,9 +140,9 @@ static void *opcode_targets[256] = {
&&TARGET_STORE_DEREF,
&&TARGET_DELETE_DEREF,
&&TARGET_JUMP_BACKWARD,
- &&TARGET_STORE_SUBSCR_LIST_INT,
+ &&TARGET_LOAD_SUPER_ATTR,
&&TARGET_CALL_FUNCTION_EX,
- &&TARGET_UNPACK_SEQUENCE_LIST,
+ &&TARGET_STORE_FAST__LOAD_FAST,
&&TARGET_EXTENDED_ARG,
&&TARGET_LIST_APPEND,
&&TARGET_SET_ADD,
@@ -152,20 +152,20 @@ static void *opcode_targets[256] = {
&&TARGET_YIELD_VALUE,
&&TARGET_RESUME,
&&TARGET_MATCH_CLASS,
- &&TARGET_UNPACK_SEQUENCE_TUPLE,
- &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
+ &&TARGET_STORE_FAST__STORE_FAST,
+ &&TARGET_STORE_SUBSCR_DICT,
&&TARGET_FORMAT_VALUE,
&&TARGET_BUILD_CONST_KEY_MAP,
&&TARGET_BUILD_STRING,
- &&TARGET_SEND_GEN,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
+ &&TARGET_STORE_SUBSCR_LIST_INT,
+ &&TARGET_UNPACK_SEQUENCE_LIST,
+ &&TARGET_UNPACK_SEQUENCE_TUPLE,
+ &&TARGET_UNPACK_SEQUENCE_TWO_TUPLE,
&&TARGET_LIST_EXTEND,
&&TARGET_SET_UPDATE,
&&TARGET_DICT_MERGE,
&&TARGET_DICT_UPDATE,
- &&_unknown_opcode,
+ &&TARGET_SEND_GEN,
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
@@ -237,22 +237,22 @@ static void *opcode_targets[256] = {
&&_unknown_opcode,
&&_unknown_opcode,
&&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&_unknown_opcode,
- &&TARGET_DO_TRACING
+ &&TARGET_INSTRUMENTED_POP_JUMP_IF_NONE,
+ &&TARGET_INSTRUMENTED_POP_JUMP_IF_NOT_NONE,
+ &&TARGET_INSTRUMENTED_RESUME,
+ &&TARGET_INSTRUMENTED_CALL,
+ &&TARGET_INSTRUMENTED_RETURN_VALUE,
+ &&TARGET_INSTRUMENTED_YIELD_VALUE,
+ &&TARGET_INSTRUMENTED_CALL_FUNCTION_EX,
+ &&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_LINE,
+ &&_unknown_opcode
};
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index d6627bc6b7e86b..ebf1a0bff54eb0 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -547,11 +547,21 @@ pycore_init_runtime(_PyRuntimeState *runtime,
}
-static void
+static PyStatus
init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *config)
{
assert(interp->feature_flags == 0);
+ if (config->use_main_obmalloc) {
+ interp->feature_flags |= Py_RTFLAGS_USE_MAIN_OBMALLOC;
+ }
+ else if (!config->check_multi_interp_extensions) {
+ /* The reason: PyModuleDef.m_base.m_copy leaks objects between
+ interpreters. */
+ return _PyStatus_ERR("per-interpreter obmalloc does not support "
+ "single-phase init extension modules");
+ }
+
if (config->allow_fork) {
interp->feature_flags |= Py_RTFLAGS_FORK;
}
@@ -570,6 +580,8 @@ init_interp_settings(PyInterpreterState *interp, const _PyInterpreterConfig *con
if (config->check_multi_interp_extensions) {
interp->feature_flags |= Py_RTFLAGS_MULTI_INTERP_EXTENSIONS;
}
+
+ return _PyStatus_OK();
}
@@ -622,7 +634,10 @@ pycore_create_interpreter(_PyRuntimeState *runtime,
}
const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
- init_interp_settings(interp, &config);
+ status = init_interp_settings(interp, &config);
+ if (_PyStatus_EXCEPTION(status)) {
+ return status;
+ }
PyThreadState *tstate = _PyThreadState_New(interp);
if (tstate == NULL) {
@@ -808,11 +823,6 @@ pycore_interp_init(PyThreadState *tstate)
PyStatus status;
PyObject *sysmod = NULL;
- // This is a temporary fix until we have immortal objects.
- // (See _PyType_InitCache() in typeobject.c.)
- extern void _PyType_FixCacheRefcounts(void);
- _PyType_FixCacheRefcounts();
-
// Create singletons before the first PyType_Ready() call, since
// PyType_Ready() uses singletons like the Unicode empty string (tp_doc)
// and the empty tuple singletons (tp_bases).
@@ -1673,6 +1683,8 @@ finalize_interp_types(PyInterpreterState *interp)
_PyFloat_FiniType(interp);
_PyLong_FiniTypes(interp);
_PyThread_FiniType(interp);
+ // XXX fini collections module static types (_PyStaticType_Dealloc())
+ // XXX fini IO module static types (_PyStaticType_Dealloc())
_PyErr_FiniTypes(interp);
_PyTypes_FiniTypes(interp);
@@ -1941,6 +1953,7 @@ Py_FinalizeEx(void)
}
_Py_FinalizeRefTotal(runtime);
#endif
+ _Py_FinalizeAllocatedBlocks(runtime);
#ifdef Py_TRACE_REFS
/* Display addresses (& refcnts) of all objects still alive.
@@ -2041,7 +2054,10 @@ new_interpreter(PyThreadState **tstate_p, const _PyInterpreterConfig *config)
goto error;
}
- init_interp_settings(interp, config);
+ status = init_interp_settings(interp, config);
+ if (_PyStatus_EXCEPTION(status)) {
+ goto error;
+ }
status = init_interp_create_gil(tstate);
if (_PyStatus_EXCEPTION(status)) {
diff --git a/Python/pystate.c b/Python/pystate.c
index d09c1d5743a4c6..ffab301f3171b2 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -60,23 +60,43 @@ extern "C" {
For each of these functions, the GIL must be held by the current thread.
*/
+
+#ifdef HAVE_THREAD_LOCAL
+_Py_thread_local PyThreadState *_Py_tss_tstate = NULL;
+#endif
+
static inline PyThreadState *
-current_fast_get(_PyRuntimeState *runtime)
+current_fast_get(_PyRuntimeState *Py_UNUSED(runtime))
{
- return (PyThreadState*)_Py_atomic_load_relaxed(&runtime->tstate_current);
+#ifdef HAVE_THREAD_LOCAL
+ return _Py_tss_tstate;
+#else
+ // XXX Fall back to the PyThread_tss_*() API.
+# error "no supported thread-local variable storage classifier"
+#endif
}
static inline void
-current_fast_set(_PyRuntimeState *runtime, PyThreadState *tstate)
+current_fast_set(_PyRuntimeState *Py_UNUSED(runtime), PyThreadState *tstate)
{
assert(tstate != NULL);
- _Py_atomic_store_relaxed(&runtime->tstate_current, (uintptr_t)tstate);
+#ifdef HAVE_THREAD_LOCAL
+ _Py_tss_tstate = tstate;
+#else
+ // XXX Fall back to the PyThread_tss_*() API.
+# error "no supported thread-local variable storage classifier"
+#endif
}
static inline void
-current_fast_clear(_PyRuntimeState *runtime)
+current_fast_clear(_PyRuntimeState *Py_UNUSED(runtime))
{
- _Py_atomic_store_relaxed(&runtime->tstate_current, (uintptr_t)NULL);
+#ifdef HAVE_THREAD_LOCAL
+ _Py_tss_tstate = NULL;
+#else
+ // XXX Fall back to the PyThread_tss_*() API.
+# error "no supported thread-local variable storage classifier"
+#endif
}
#define tstate_verify_not_active(tstate) \
@@ -84,6 +104,12 @@ current_fast_clear(_PyRuntimeState *runtime)
_Py_FatalErrorFormat(__func__, "tstate %p is still current", tstate); \
}
+PyThreadState *
+_PyThreadState_GetCurrent(void)
+{
+ return current_fast_get(&_PyRuntime);
+}
+
//------------------------------------------------
// the thread state bound to the current OS thread
@@ -354,7 +380,7 @@ _Py_COMP_DIAG_IGNORE_DEPR_DECLS
static const _PyRuntimeState initial = _PyRuntimeState_INIT(_PyRuntime);
_Py_COMP_DIAG_POP
-#define NUMLOCKS 4
+#define NUMLOCKS 5
static int
alloc_for_runtime(PyThread_type_lock locks[NUMLOCKS])
@@ -408,6 +434,7 @@ init_runtime(_PyRuntimeState *runtime,
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
+ &runtime->imports.extensions.mutex,
};
for (int i = 0; i < NUMLOCKS; i++) {
assert(locks[i] != NULL);
@@ -492,6 +519,7 @@ _PyRuntimeState_Fini(_PyRuntimeState *runtime)
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
+ &runtime->imports.extensions.mutex,
};
for (int i = 0; i < NUMLOCKS; i++) {
FREE_LOCK(*lockptrs[i]);
@@ -520,6 +548,7 @@ _PyRuntimeState_ReInitThreads(_PyRuntimeState *runtime)
&runtime->xidregistry.mutex,
&runtime->getargs.mutex,
&runtime->unicode_state.ids.lock,
+ &runtime->imports.extensions.mutex,
};
int reinit_err = 0;
for (int i = 0; i < NUMLOCKS; i++) {
@@ -625,7 +654,6 @@ free_interpreter(PyInterpreterState *interp)
main interpreter. We fix those fields here, in addition
to the other dynamically initialized fields.
*/
-
static void
init_interpreter(PyInterpreterState *interp,
_PyRuntimeState *runtime, int64_t id,
@@ -646,16 +674,34 @@ init_interpreter(PyInterpreterState *interp,
assert(next != NULL || (interp == runtime->interpreters.main));
interp->next = next;
+ /* Initialize obmalloc, but only for subinterpreters,
+ since the main interpreter is initialized statically. */
+ if (interp != &runtime->_main_interpreter) {
+ poolp temp[OBMALLOC_USED_POOLS_SIZE] = \
+ _obmalloc_pools_INIT(interp->obmalloc.pools);
+ memcpy(&interp->obmalloc.pools.used, temp, sizeof(temp));
+ }
+
_PyEval_InitState(&interp->ceval, pending_lock);
_PyGC_InitState(&interp->gc);
PyConfig_InitPythonConfig(&interp->config);
_PyType_InitCache(interp);
+ for(int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ interp->monitors.tools[i] = 0;
+ }
+ for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) {
+ for(int e = 0; e < PY_MONITORING_EVENTS; e++) {
+ interp->monitoring_callables[t][e] = NULL;
+ }
+ }
+ interp->sys_profile_initialized = false;
+ interp->sys_trace_initialized = false;
if (interp != &runtime->_main_interpreter) {
/* Fix the self-referential, statically initialized fields. */
interp->dtoa = (struct _dtoa_state)_dtoa_state_INIT(interp);
}
-
+ interp->f_opcode_trace_set = false;
interp->_initialized = 1;
}
@@ -788,6 +834,20 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
Py_CLEAR(interp->audit_hooks);
+ for(int i = 0; i < PY_MONITORING_UNGROUPED_EVENTS; i++) {
+ interp->monitors.tools[i] = 0;
+ }
+ for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) {
+ for(int e = 0; e < PY_MONITORING_EVENTS; e++) {
+ Py_CLEAR(interp->monitoring_callables[t][e]);
+ }
+ }
+ interp->sys_profile_initialized = false;
+ interp->sys_trace_initialized = false;
+ for (int t = 0; t < PY_MONITORING_TOOL_IDS; t++) {
+ Py_CLEAR(interp->monitoring_tool_names[t]);
+ }
+
PyConfig_Clear(&interp->config);
Py_CLEAR(interp->codec_search_path);
Py_CLEAR(interp->codec_search_cache);
@@ -845,7 +905,7 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate)
interp->code_watchers[i] = NULL;
}
interp->active_code_watchers = 0;
-
+ interp->f_opcode_trace_set = false;
// XXX Once we have one allocator per interpreter (i.e.
// per-interpreter GC) we must ensure that all of the interpreter's
// objects have been cleaned up at the point.
@@ -892,11 +952,12 @@ PyInterpreterState_Delete(PyInterpreterState *interp)
_PyEval_FiniState(&interp->ceval);
-#ifdef Py_REF_DEBUG
- // XXX This call should be done at the end of clear_interpreter(),
+ // XXX These two calls should be done at the end of clear_interpreter(),
// but currently some objects get decref'ed after that.
+#ifdef Py_REF_DEBUG
_PyInterpreterState_FinalizeRefTotal(interp);
#endif
+ _PyInterpreterState_FinalizeAllocatedBlocks(interp);
HEAD_LOCK(runtime);
PyInterpreterState **p;
@@ -1237,6 +1298,7 @@ init_threadstate(PyThreadState *tstate,
tstate->datastack_chunk = NULL;
tstate->datastack_top = NULL;
tstate->datastack_limit = NULL;
+ tstate->what_event = -1;
tstate->_status.initialized = 1;
}
@@ -1412,8 +1474,14 @@ PyThreadState_Clear(PyThreadState *tstate)
"PyThreadState_Clear: warning: thread still has a generator\n");
}
- tstate->c_profilefunc = NULL;
- tstate->c_tracefunc = NULL;
+ if (tstate->c_profilefunc != NULL) {
+ tstate->interp->sys_profiling_threads--;
+ tstate->c_profilefunc = NULL;
+ }
+ if (tstate->c_tracefunc != NULL) {
+ tstate->interp->sys_tracing_threads--;
+ tstate->c_tracefunc = NULL;
+ }
Py_CLEAR(tstate->c_profileobj);
Py_CLEAR(tstate->c_traceobj);
@@ -1986,14 +2054,13 @@ _PyThread_CurrentExceptions(void)
if (id == NULL) {
goto fail;
}
- PyObject *exc_info = _PyErr_StackItemToExcInfoTuple(err_info);
- if (exc_info == NULL) {
- Py_DECREF(id);
- goto fail;
- }
- int stat = PyDict_SetItem(result, id, exc_info);
+ PyObject *exc = err_info->exc_value;
+ assert(exc == NULL ||
+ exc == Py_None ||
+ PyExceptionInstance_Check(exc));
+
+ int stat = PyDict_SetItem(result, id, exc == NULL ? Py_None : exc);
Py_DECREF(id);
- Py_DECREF(exc_info);
if (stat < 0) {
goto fail;
}
@@ -2265,11 +2332,11 @@ _PyCrossInterpreterData_InitWithSize(_PyCrossInterpreterData *data,
// where it was allocated, so the interpreter is required.
assert(interp != NULL);
_PyCrossInterpreterData_Init(data, interp, NULL, obj, new_object);
- data->data = PyMem_Malloc(size);
+ data->data = PyMem_RawMalloc(size);
if (data->data == NULL) {
return -1;
}
- data->free = PyMem_Free;
+ data->free = PyMem_RawFree;
return 0;
}
diff --git a/Python/specialize.c b/Python/specialize.c
index a9d3226ee39f5f..9230087a78beac 100644
--- a/Python/specialize.c
+++ b/Python/specialize.c
@@ -96,6 +96,7 @@ _Py_GetSpecializationStats(void) {
return NULL;
}
int err = 0;
+ err += add_stat_dict(stats, LOAD_SUPER_ATTR, "load_super_attr");
err += add_stat_dict(stats, LOAD_ATTR, "load_attr");
err += add_stat_dict(stats, LOAD_GLOBAL, "load_global");
err += add_stat_dict(stats, BINARY_SUBSCR, "binary_subscr");
@@ -273,7 +274,8 @@ _PyCode_Quicken(PyCodeObject *code)
_Py_CODEUNIT *instructions = _PyCode_CODE(code);
for (int i = 0; i < Py_SIZE(code); i++) {
int previous_opcode = opcode;
- opcode = _PyOpcode_Deopt[instructions[i].op.code];
+ opcode = _Py_GetBaseOpcode(code, i);
+ assert(opcode < MIN_INSTRUMENTED_OPCODE);
int caches = _PyOpcode_Caches[opcode];
if (caches) {
instructions[i + 1].cache = adaptive_counter_warmup();
@@ -319,6 +321,14 @@ _PyCode_Quicken(PyCodeObject *code)
#define SPEC_FAIL_LOAD_GLOBAL_NON_DICT 17
#define SPEC_FAIL_LOAD_GLOBAL_NON_STRING_OR_SPLIT 18
+/* Super */
+
+#define SPEC_FAIL_SUPER_NOT_LOAD_METHOD 9
+#define SPEC_FAIL_SUPER_BAD_CLASS 10
+#define SPEC_FAIL_SUPER_SHADOWED 11
+#define SPEC_FAIL_SUPER_NOT_METHOD 12
+#define SPEC_FAIL_SUPER_ERROR_OR_NOT_FOUND 13
+
/* Attributes */
#define SPEC_FAIL_ATTR_OVERRIDING_DESCRIPTOR 9
@@ -504,6 +514,52 @@ specialize_module_load_attr(
/* Attribute specialization */
+void
+_Py_Specialize_LoadSuperAttr(PyObject *global_super, PyObject *class, PyObject *self,
+ _Py_CODEUNIT *instr, PyObject *name, int load_method) {
+ assert(ENABLE_SPECIALIZATION);
+ assert(_PyOpcode_Caches[LOAD_SUPER_ATTR] == INLINE_CACHE_ENTRIES_LOAD_SUPER_ATTR);
+ _PySuperAttrCache *cache = (_PySuperAttrCache *)(instr + 1);
+ if (!load_method) {
+ SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_NOT_LOAD_METHOD);
+ goto fail;
+ }
+ if (global_super != (PyObject *)&PySuper_Type) {
+ SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_SHADOWED);
+ goto fail;
+ }
+ if (!PyType_Check(class)) {
+ SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_BAD_CLASS);
+ goto fail;
+ }
+ PyTypeObject *tp = (PyTypeObject *)class;
+ PyObject *res = _PySuper_LookupDescr(tp, self, name);
+ if (res == NULL) {
+ SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_ERROR_OR_NOT_FOUND);
+ PyErr_Clear();
+ goto fail;
+ }
+ if (_PyType_HasFeature(Py_TYPE(res), Py_TPFLAGS_METHOD_DESCRIPTOR)) {
+ write_u32(cache->class_version, tp->tp_version_tag);
+ write_u32(cache->self_type_version, Py_TYPE(self)->tp_version_tag);
+ write_obj(cache->method, res); // borrowed
+ instr->op.code = LOAD_SUPER_ATTR_METHOD;
+ goto success;
+ }
+ SPECIALIZATION_FAIL(LOAD_SUPER_ATTR, SPEC_FAIL_SUPER_NOT_METHOD);
+
+fail:
+ STAT_INC(LOAD_SUPER_ATTR, failure);
+ assert(!PyErr_Occurred());
+ instr->op.code = LOAD_SUPER_ATTR;
+ cache->counter = adaptive_counter_backoff(cache->counter);
+ return;
+success:
+ STAT_INC(LOAD_SUPER_ATTR, success);
+ assert(!PyErr_Occurred());
+ cache->counter = adaptive_counter_cooldown();
+}
+
typedef enum {
OVERRIDING, /* Is an overriding descriptor, and will remain so. */
METHOD, /* Attribute has Py_TPFLAGS_METHOD_DESCRIPTOR set */
@@ -1737,6 +1793,7 @@ _Py_Specialize_Call(PyObject *callable, _Py_CODEUNIT *instr, int nargs,
{
assert(ENABLE_SPECIALIZATION);
assert(_PyOpcode_Caches[CALL] == INLINE_CACHE_ENTRIES_CALL);
+ assert(_Py_OPCODE(*instr) != INSTRUMENTED_CALL);
_PyCallCache *cache = (_PyCallCache *)(instr + 1);
int fail;
if (PyCFunction_CheckExact(callable)) {
@@ -2149,7 +2206,9 @@ _Py_Specialize_ForIter(PyObject *iter, _Py_CODEUNIT *instr, int oparg)
goto success;
}
else if (tp == &PyGen_Type && oparg <= SHRT_MAX) {
- assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR);
+ assert(instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == END_FOR ||
+ instr[oparg + INLINE_CACHE_ENTRIES_FOR_ITER + 1].op.code == INSTRUMENTED_END_FOR
+ );
instr->op.code = FOR_ITER_GEN;
goto success;
}
diff --git a/Python/sysmodule.c b/Python/sysmodule.c
index f1a294de598420..58ed48859b5f3a 100644
--- a/Python/sysmodule.c
+++ b/Python/sysmodule.c
@@ -1871,9 +1871,23 @@ static Py_ssize_t
sys_getallocatedblocks_impl(PyObject *module)
/*[clinic end generated code: output=f0c4e873f0b6dcf7 input=dab13ee346a0673e]*/
{
- return _Py_GetAllocatedBlocks();
+ // It might make sense to return the count
+ // for just the current interpreter.
+ return _Py_GetGlobalAllocatedBlocks();
}
+/*[clinic input]
+sys.getunicodeinternedsize -> Py_ssize_t
+
+Return the number of elements of the unicode interned dictionary
+[clinic start generated code]*/
+
+static Py_ssize_t
+sys_getunicodeinternedsize_impl(PyObject *module)
+/*[clinic end generated code: output=ad0e4c9738ed4129 input=726298eaa063347a]*/
+{
+ return _PyUnicode_InternedSize();
+}
/*[clinic input]
sys._getframe
@@ -2243,6 +2257,7 @@ static PyMethodDef sys_methods[] = {
SYS_GETDEFAULTENCODING_METHODDEF
SYS_GETDLOPENFLAGS_METHODDEF
SYS_GETALLOCATEDBLOCKS_METHODDEF
+ SYS_GETUNICODEINTERNEDSIZE_METHODDEF
SYS_GETFILESYSTEMENCODING_METHODDEF
SYS_GETFILESYSTEMENCODEERRORS_METHODDEF
#ifdef Py_TRACE_REFS
@@ -3409,6 +3424,7 @@ _PySys_SetPreliminaryStderr(PyObject *sysdict)
return _PyStatus_ERR("can't set preliminary stderr");
}
+PyObject *_Py_CreateMonitoringObject(void);
/* Create sys module without all attributes.
_PySys_UpdateConfig() should be called later to add remaining attributes. */
@@ -3458,6 +3474,16 @@ _PySys_Create(PyThreadState *tstate, PyObject **sysmod_p)
goto error;
}
+ PyObject *monitoring = _Py_CreateMonitoringObject();
+ if (monitoring == NULL) {
+ goto error;
+ }
+ int err = PyDict_SetItemString(sysdict, "monitoring", monitoring);
+ Py_DECREF(monitoring);
+ if (err < 0) {
+ goto error;
+ }
+
assert(!_PyErr_Occurred(tstate));
*sysmod_p = sysmod;
diff --git a/Tools/build/deepfreeze.py b/Tools/build/deepfreeze.py
index ec808526b7bbb7..5cfef5c572c4ae 100644
--- a/Tools/build/deepfreeze.py
+++ b/Tools/build/deepfreeze.py
@@ -142,7 +142,7 @@ def block(self, prefix: str, suffix: str = "") -> None:
def object_head(self, typename: str) -> None:
with self.block(".ob_base =", ","):
- self.write(f".ob_refcnt = 999999999,")
+ self.write(f".ob_refcnt = _Py_IMMORTAL_REFCNT,")
self.write(f".ob_type = &{typename},")
def object_var_head(self, typename: str, size: int) -> None:
@@ -255,7 +255,6 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.write(f".co_names = {co_names},")
self.write(f".co_exceptiontable = {co_exceptiontable},")
self.field(code, "co_flags")
- self.write("._co_linearray_entry_size = 0,")
self.field(code, "co_argcount")
self.field(code, "co_posonlyargcount")
self.field(code, "co_kwonlyargcount")
@@ -276,7 +275,6 @@ def generate_code(self, name: str, code: types.CodeType) -> str:
self.write(f".co_qualname = {co_qualname},")
self.write(f".co_linetable = {co_linetable},")
self.write(f"._co_cached = NULL,")
- self.write("._co_linearray = NULL,")
self.write(f".co_code_adaptive = {co_code_adaptive},")
for i, op in enumerate(code.co_code[::2]):
if op == RESUME:
diff --git a/Tools/build/generate_opcode_h.py b/Tools/build/generate_opcode_h.py
index 614b17df740929..645b9f1de1170b 100644
--- a/Tools/build/generate_opcode_h.py
+++ b/Tools/build/generate_opcode_h.py
@@ -89,6 +89,7 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
HAVE_ARGUMENT = opcode["HAVE_ARGUMENT"]
MIN_PSEUDO_OPCODE = opcode["MIN_PSEUDO_OPCODE"]
MAX_PSEUDO_OPCODE = opcode["MAX_PSEUDO_OPCODE"]
+ MIN_INSTRUMENTED_OPCODE = opcode["MIN_INSTRUMENTED_OPCODE"]
NUM_OPCODES = len(opname)
used = [ False ] * len(opname)
@@ -105,9 +106,6 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
specialized_opmap[name] = next_op
opname_including_specialized[next_op] = name
used[next_op] = True
- specialized_opmap['DO_TRACING'] = 255
- opname_including_specialized[255] = 'DO_TRACING'
- used[255] = True
with open(outfile, 'w') as fobj, open(internaloutfile, 'w') as iobj:
fobj.write(header)
@@ -120,6 +118,8 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
fobj.write(DEFINE.format("HAVE_ARGUMENT", HAVE_ARGUMENT))
if op == MIN_PSEUDO_OPCODE:
fobj.write(DEFINE.format("MIN_PSEUDO_OPCODE", MIN_PSEUDO_OPCODE))
+ if op == MIN_INSTRUMENTED_OPCODE:
+ fobj.write(DEFINE.format("MIN_INSTRUMENTED_OPCODE", MIN_INSTRUMENTED_OPCODE))
fobj.write(DEFINE.format(name, op))
@@ -130,12 +130,10 @@ def main(opcode_py, outfile='Include/opcode.h', internaloutfile='Include/interna
for name, op in specialized_opmap.items():
fobj.write(DEFINE.format(name, op))
- iobj.write("\nextern const uint32_t _PyOpcode_RelativeJump[9];\n")
iobj.write("\nextern const uint32_t _PyOpcode_Jump[9];\n")
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")
- write_int_array_from_ops("_PyOpcode_RelativeJump", opcode['hasjrel'], iobj)
write_int_array_from_ops("_PyOpcode_Jump", opcode['hasjrel'] + opcode['hasjabs'], iobj)
iobj.write("\nconst uint8_t _PyOpcode_Caches[256] = {\n")
diff --git a/Tools/build/generate_token.py b/Tools/build/generate_token.py
index fc12835b7762ad..3bd307c1733867 100755
--- a/Tools/build/generate_token.py
+++ b/Tools/build/generate_token.py
@@ -80,6 +80,8 @@ def update_file(file, content):
(x) == NEWLINE || \\
(x) == INDENT || \\
(x) == DEDENT)
+#define ISSTRINGLIT(x) ((x) == STRING || \\
+ (x) == FSTRING_MIDDLE)
// Symbols exported for test_peg_generator
diff --git a/Tools/build/verify_ensurepip_wheels.py b/Tools/build/verify_ensurepip_wheels.py
index 044d1fd6b3cf2d..09fd5d9e3103ac 100755
--- a/Tools/build/verify_ensurepip_wheels.py
+++ b/Tools/build/verify_ensurepip_wheels.py
@@ -14,7 +14,7 @@
from pathlib import Path
from urllib.request import urlopen
-PACKAGE_NAMES = ("pip", "setuptools")
+PACKAGE_NAMES = ("pip",)
ENSURE_PIP_ROOT = Path(__file__).parent.parent.parent / "Lib/ensurepip"
WHEEL_DIR = ENSURE_PIP_ROOT / "_bundled"
ENSURE_PIP_INIT_PY_TEXT = (ENSURE_PIP_ROOT / "__init__.py").read_text(encoding="utf-8")
diff --git a/Tools/c-analyzer/cpython/_parser.py b/Tools/c-analyzer/cpython/_parser.py
index acf30e2c4020b3..5924ab7860d8d5 100644
--- a/Tools/c-analyzer/cpython/_parser.py
+++ b/Tools/c-analyzer/cpython/_parser.py
@@ -47,6 +47,7 @@ def clean_lines(text):
'''
# XXX Handle these.
+# Tab separated:
EXCLUDED = clean_lines('''
# @begin=conf@
@@ -327,7 +328,6 @@ def clean_lines(text):
_abs('Python/frozen_modules/*.h'): (20_000, 500),
_abs('Python/opcode_targets.h'): (10_000, 500),
_abs('Python/stdlib_module_names.h'): (5_000, 500),
- _abs('Python/importlib.h'): (200_000, 5000),
# These large files are currently ignored (see above).
_abs('Modules/_ssl_data.h'): (80_000, 10_000),
diff --git a/Tools/c-analyzer/cpython/globals-to-fix.tsv b/Tools/c-analyzer/cpython/globals-to-fix.tsv
index 0620c7e13925b5..849fd5d9a1e8d5 100644
--- a/Tools/c-analyzer/cpython/globals-to-fix.tsv
+++ b/Tools/c-analyzer/cpython/globals-to-fix.tsv
@@ -135,6 +135,9 @@ Objects/stringlib/unicode_format.h - PyFieldNameIter_Type -
Objects/unicodeobject.c - EncodingMapType -
#Objects/unicodeobject.c - PyFieldNameIter_Type -
#Objects/unicodeobject.c - PyFormatterIter_Type -
+Python/legacy_tracing.c - _PyLegacyEventHandler_Type -
+Objects/object.c - _PyLegacyEventHandler_Type -
+
##-----------------------
## static builtin structseq
@@ -297,6 +300,8 @@ Objects/object.c - _Py_NotImplementedStruct -
Objects/setobject.c - _dummy_struct -
Objects/setobject.c - _PySet_Dummy -
Objects/sliceobject.c - _Py_EllipsisObject -
+Python/instrumentation.c - DISABLE -
+Python/instrumentation.c - _PyInstrumentation_MISSING -
##################################
@@ -311,11 +316,6 @@ Objects/sliceobject.c - _Py_EllipsisObject -
##-----------------------
## static types
-Modules/_collectionsmodule.c - defdict_type -
-Modules/_collectionsmodule.c - deque_type -
-Modules/_collectionsmodule.c - dequeiter_type -
-Modules/_collectionsmodule.c - dequereviter_type -
-Modules/_collectionsmodule.c - tuplegetter_type -
Modules/_io/bufferedio.c - PyBufferedIOBase_Type -
Modules/_io/bytesio.c - _PyBytesIOBuffer_Type -
Modules/_io/iobase.c - PyIOBase_Type -
@@ -392,7 +392,6 @@ Modules/_decimal/_decimal.c - PyDecSignalDictMixin_Type -
Modules/_decimal/_decimal.c - PyDec_Type -
Modules/ossaudiodev.c - OSSAudioType -
Modules/ossaudiodev.c - OSSMixerType -
-Modules/socketmodule.c - sock_type -
Modules/xxmodule.c - Null_Type -
Modules/xxmodule.c - Str_Type -
Modules/xxmodule.c - Xxo_Type -
@@ -416,8 +415,6 @@ Modules/_cursesmodule.c - PyCursesError -
Modules/_decimal/_decimal.c - DecimalException -
Modules/_tkinter.c - Tkinter_TclError -
Modules/ossaudiodev.c - OSSAudioError -
-Modules/socketmodule.c - socket_herror -
-Modules/socketmodule.c - socket_gaierror -
Modules/xxlimited_35.c - ErrorObject -
Modules/xxmodule.c - ErrorObject -
@@ -509,13 +506,9 @@ Modules/cjkcodecs/_codecs_iso2022.c jisx0208_init initialized -
Modules/cjkcodecs/_codecs_iso2022.c jisx0212_init initialized -
Modules/cjkcodecs/_codecs_iso2022.c jisx0213_init initialized -
Modules/cjkcodecs/_codecs_iso2022.c gb2312_init initialized -
-Modules/cjkcodecs/cjkcodecs.h - codec_list -
-Modules/cjkcodecs/cjkcodecs.h - mapping_list -
Modules/readline.c - libedit_append_replace_history_offset -
Modules/readline.c - using_libedit_emulation -
Modules/readline.c - libedit_history_start -
-Modules/socketmodule.c - accept4_works -
-Modules/socketmodule.c - sock_cloexec_works -
##-----------------------
## state
@@ -541,4 +534,3 @@ Modules/readline.c - sigwinch_ohandler -
Modules/readline.c - completed_input_string -
Modules/rotatingtree.c - random_stream -
Modules/rotatingtree.c - random_value -
-Modules/socketmodule.c - defaulttimeout -
diff --git a/Tools/c-analyzer/cpython/ignored.tsv b/Tools/c-analyzer/cpython/ignored.tsv
index a8ba88efc732fb..7a5d7d45f5184b 100644
--- a/Tools/c-analyzer/cpython/ignored.tsv
+++ b/Tools/c-analyzer/cpython/ignored.tsv
@@ -309,6 +309,7 @@ Objects/obmalloc.c - _PyMem -
Objects/obmalloc.c - _PyMem_Debug -
Objects/obmalloc.c - _PyMem_Raw -
Objects/obmalloc.c - _PyObject -
+Objects/obmalloc.c - last_final_leaks -
Objects/obmalloc.c - usedpools -
Objects/typeobject.c - name_op -
Objects/typeobject.c - slotdefs -
diff --git a/Tools/cases_generator/interpreter_definition.md b/Tools/cases_generator/interpreter_definition.md
index c7bd38d32ff411..6f902f60c68ee7 100644
--- a/Tools/cases_generator/interpreter_definition.md
+++ b/Tools/cases_generator/interpreter_definition.md
@@ -137,9 +137,9 @@ The following definitions may occur:
`foo_1` is legal. `$` is not legal, nor is `struct` or `class`.
The optional `type` in an `object` is the C type. It defaults to `PyObject *`.
-The objects before the "--" are the objects on top of the the stack at the start
-of the instruction. Those after the "--" are the objects on top of the the stack
-at the end of the instruction.
+The objects before the "--" are the objects on top of the stack at the start of
+the instruction. Those after the "--" are the objects on top of the stack at the
+end of the instruction.
An `inst` without `stack_effect` is a transitional form to allow the original C code
definitions to be copied. It lacks information to generate anything other than the
diff --git a/Tools/patchcheck/patchcheck.py b/Tools/patchcheck/patchcheck.py
index 6dcf612066199c..fa3a43af6e6048 100755
--- a/Tools/patchcheck/patchcheck.py
+++ b/Tools/patchcheck/patchcheck.py
@@ -130,9 +130,10 @@ def changed_files(base_branch=None):
with subprocess.Popen(cmd.split(),
stdout=subprocess.PIPE,
cwd=SRCDIR) as st:
- if st.wait() != 0:
+ git_file_status, _ = st.communicate()
+ if st.returncode != 0:
sys.exit(f'error running {cmd}')
- for line in st.stdout:
+ for line in git_file_status.splitlines():
line = line.decode().rstrip()
status_text, filename = line.split(maxsplit=1)
status = set(status_text)
@@ -169,12 +170,24 @@ def report_modified_files(file_paths):
return "\n".join(lines)
+#: Python files that have tabs by design:
+_PYTHON_FILES_WITH_TABS = frozenset({
+ 'Tools/c-analyzer/cpython/_parser.py',
+})
+
+
@status("Fixing Python file whitespace", info=report_modified_files)
def normalize_whitespace(file_paths):
"""Make sure that the whitespace for .py files have been normalized."""
reindent.makebackup = False # No need to create backups.
- fixed = [path for path in file_paths if path.endswith('.py') and
- reindent.check(os.path.join(SRCDIR, path))]
+ fixed = [
+ path for path in file_paths
+ if (
+ path.endswith('.py')
+ and path not in _PYTHON_FILES_WITH_TABS
+ and reindent.check(os.path.join(SRCDIR, path))
+ )
+ ]
return fixed
diff --git a/Tools/peg_generator/pegen/c_generator.py b/Tools/peg_generator/pegen/c_generator.py
index e72ce7afdc4796..f57b6275f671d3 100644
--- a/Tools/peg_generator/pegen/c_generator.py
+++ b/Tools/peg_generator/pegen/c_generator.py
@@ -68,6 +68,7 @@ class NodeTypes(Enum):
KEYWORD = 4
SOFT_KEYWORD = 5
CUT_OPERATOR = 6
+ F_STRING_CHUNK = 7
BASE_NODETYPES = {
diff --git a/Tools/wasm/wasm_assets.py b/Tools/wasm/wasm_assets.py
index 9dc8bda4017e2c..1fc97fd5e70a10 100755
--- a/Tools/wasm/wasm_assets.py
+++ b/Tools/wasm/wasm_assets.py
@@ -6,7 +6,8 @@
- a stripped down, pyc-only stdlib zip file, e.g. {PREFIX}/lib/python311.zip
- os.py as marker module {PREFIX}/lib/python3.11/os.py
-- empty lib-dynload directory, to make sure it is copied into the bundle {PREFIX}/lib/python3.11/lib-dynload/.empty
+- empty lib-dynload directory, to make sure it is copied into the bundle:
+ {PREFIX}/lib/python3.11/lib-dynload/.empty
"""
import argparse
diff --git a/Tools/wasm/wasm_build.py b/Tools/wasm/wasm_build.py
index 493682c5b138a3..241a5d4eed5ae8 100755
--- a/Tools/wasm/wasm_build.py
+++ b/Tools/wasm/wasm_build.py
@@ -73,7 +73,7 @@
run "make clean -C '{SRCDIR}'".
"""
-INSTALL_NATIVE = f"""
+INSTALL_NATIVE = """
Builds require a C compiler (gcc, clang), make, pkg-config, and development
headers for dependencies like zlib.
@@ -598,7 +598,7 @@ def run_browser(self, bind="127.0.0.1", port=8000):
end = time.monotonic() + 3.0
while time.monotonic() < end and srv.returncode is None:
try:
- with socket.create_connection((bind, port), timeout=0.1) as s:
+ with socket.create_connection((bind, port), timeout=0.1) as _:
pass
except OSError:
time.sleep(0.01)
diff --git a/configure b/configure
index 9e99352f589f21..8133d47f61355b 100755
--- a/configure
+++ b/configure
@@ -892,6 +892,8 @@ PGO_PROF_USE_FLAG
PGO_PROF_GEN_FLAG
MERGE_FDATA
LLVM_BOLT
+ac_ct_READELF
+READELF
PREBOLT_RULE
LLVM_AR_FOUND
LLVM_AR
@@ -3104,7 +3106,6 @@ if test "$srcdir" != . -a "$srcdir" != "$(pwd)"; then
# resources get picked up before their $srcdir counterparts.
# Objects/ -> typeslots.inc
# Include/ -> Python.h
- # Python/ -> importlib.h
# (A side effect of this is that these resources will automatically be
# regenerated when building out-of-tree, regardless of whether or not
# the $srcdir counterpart is up-to-date. This is an acceptable trade
@@ -7917,6 +7918,112 @@ if test "$Py_BOLT" = 'true' ; then
DEF_MAKE_ALL_RULE="bolt-opt"
DEF_MAKE_RULE="build_all"
+
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in readelf
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_READELF+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$READELF"; then
+ ac_cv_prog_READELF="$READELF" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_READELF="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+READELF=$ac_cv_prog_READELF
+if test -n "$READELF"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $READELF" >&5
+$as_echo "$READELF" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$READELF" && break
+ done
+fi
+if test -z "$READELF"; then
+ ac_ct_READELF=$READELF
+ for ac_prog in readelf
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_READELF+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_READELF"; then
+ ac_cv_prog_ac_ct_READELF="$ac_ct_READELF" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_READELF="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_READELF=$ac_cv_prog_ac_ct_READELF
+if test -n "$ac_ct_READELF"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_READELF" >&5
+$as_echo "$ac_ct_READELF" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_READELF" && break
+done
+
+ if test "x$ac_ct_READELF" = x; then
+ READELF=""notfound""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ READELF=$ac_ct_READELF
+ fi
+fi
+
+ if test "$READELF" == "notfound"
+ then
+ as_fn_error $? "readelf is required for a --enable-bolt build but could not be found." "$LINENO" 5
+ fi
+
# -fno-reorder-blocks-and-partition is required for bolt to work.
# Possibly GCC only.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C compiler accepts -fno-reorder-blocks-and-partition" >&5
diff --git a/configure.ac b/configure.ac
index 31b7a2157a2bcc..3f20d8980d8abc 100644
--- a/configure.ac
+++ b/configure.ac
@@ -97,7 +97,6 @@ if test "$srcdir" != . -a "$srcdir" != "$(pwd)"; then
# resources get picked up before their $srcdir counterparts.
# Objects/ -> typeslots.inc
# Include/ -> Python.h
- # Python/ -> importlib.h
# (A side effect of this is that these resources will automatically be
# regenerated when building out-of-tree, regardless of whether or not
# the $srcdir counterpart is up-to-date. This is an acceptable trade
@@ -1939,6 +1938,13 @@ if test "$Py_BOLT" = 'true' ; then
DEF_MAKE_ALL_RULE="bolt-opt"
DEF_MAKE_RULE="build_all"
+ AC_SUBST(READELF)
+ AC_CHECK_TOOLS(READELF, [readelf], "notfound")
+ if test "$READELF" == "notfound"
+ then
+ AC_MSG_ERROR([readelf is required for a --enable-bolt build but could not be found.])
+ fi
+
# -fno-reorder-blocks-and-partition is required for bolt to work.
# Possibly GCC only.
AX_CHECK_COMPILE_FLAG([-fno-reorder-blocks-and-partition],[