Merge branch 'main' into doc-fix-84116

This commit is contained in:
Krishna-web-hub 2026-02-03 15:06:53 +05:30 committed by GitHub
commit bc50109663
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
332 changed files with 15328 additions and 7380 deletions

3
.gitattributes vendored
View file

@ -94,6 +94,8 @@ Lib/test/test_stable_abi_ctypes.py generated
Lib/test/test_zoneinfo/data/*.json generated
Lib/token.py generated
Misc/sbom.spdx.json generated
Modules/_testinternalcapi/test_cases.c.h generated
Modules/_testinternalcapi/test_targets.h generated
Objects/typeslots.inc generated
PC/python3dll.c generated
Parser/parser.c generated
@ -104,6 +106,7 @@ Python/executor_cases.c.h generated
Python/generated_cases.c.h generated
Python/optimizer_cases.c.h generated
Python/opcode_targets.h generated
Python/record_functions.c.h generated
Python/stdlib_module_names.h generated
Tools/peg_generator/pegen/grammar_parser.py generated
aclocal.m4 generated

5
.github/CODEOWNERS vendored
View file

@ -63,8 +63,8 @@
.azure-pipelines/ @AA-Turner
# GitHub & related scripts
.github/ @ezio-melotti @hugovk @AA-Turner
Tools/build/compute-changes.py @AA-Turner
.github/ @ezio-melotti @hugovk @AA-Turner @webknjaz
Tools/build/compute-changes.py @AA-Turner @hugovk @webknjaz
Tools/build/verify_ensurepip_wheels.py @AA-Turner @pfmoore @pradyunsg
# Pre-commit
@ -176,6 +176,7 @@ Tools/wasm/config.site-wasm32-emscripten @freakboy3742 @emmatyping
Tools/wasm/emscripten @freakboy3742 @emmatyping
# WebAssembly (WASI)
Platforms/WASI @brettcannon @emmatyping @savannahostrowski
Tools/wasm/wasi-env @brettcannon @emmatyping @savannahostrowski
Tools/wasm/wasi.py @brettcannon @emmatyping @savannahostrowski
Tools/wasm/wasi @brettcannon @emmatyping @savannahostrowski

View file

@ -1,9 +0,0 @@
---
name: Documentation
about: Report a problem with the documentation
labels: "docs"
---
# Documentation
(A clear and concise description of the issue.)

View file

@ -0,0 +1,15 @@
name: Documentation
description: Report a problem with the documentation
labels: ["docs"]
body:
- type: markdown
attributes:
value: |
> [!NOTE]
> Trivial changes (for example typos) dont require an issue before opening a PR.
- type: textarea
attributes:
label: "Documentation"
description: "A clear and concise description of the issue."
validations:
required: true

View file

@ -261,7 +261,7 @@ jobs:
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
# supported by important vendors such as AWS-LC.
openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4]
openssl_ver: [1.1.1w, 3.0.18, 3.3.5, 3.4.3, 3.5.4, 3.6.0]
# See Tools/ssl/make_ssl_data.py for notes on adding a new version
env:
OPENSSL_VER: ${{ matrix.openssl_ver }}
@ -655,11 +655,14 @@ jobs:
matrix:
sanitizer:
- address
- undefined
- memory
oss-fuzz-project-name:
- cpython3
- python3-libraries
include:
- sanitizer: undefined
oss-fuzz-project-name: cpython3
- sanitizer: memory
oss-fuzz-project-name: cpython3
exclude:
# Note that the 'no-exclude' sentinel below is to prevent
# an empty string value from excluding all jobs and causing

View file

@ -47,14 +47,14 @@ jobs:
- name: "Runner image version"
run: echo "IMAGE_OS_VERSION=${ImageOS}-${ImageVersion}" >> "$GITHUB_ENV"
- name: "Configure build Python"
run: python3 Tools/wasm/wasi configure-build-python -- --config-cache --with-pydebug
run: python3 Platforms/WASI configure-build-python -- --config-cache --with-pydebug
- name: "Make build Python"
run: python3 Tools/wasm/wasi make-build-python
run: python3 Platforms/WASI make-build-python
- name: "Configure host"
# `--with-pydebug` inferred from configure-build-python
run: python3 Tools/wasm/wasi configure-host -- --config-cache
run: python3 Platforms/WASI configure-host -- --config-cache
- name: "Make host"
run: python3 Tools/wasm/wasi make-host
run: python3 Platforms/WASI make-host
- name: "Display build info"
run: make --directory "${CROSS_BUILD_WASI}" pythoninfo
- name: "Test"

View file

@ -15,6 +15,7 @@
from asyncio import wait_for
from contextlib import asynccontextmanager
from datetime import datetime, timezone
from enum import IntEnum, auto
from glob import glob
from os.path import abspath, basename, relpath
from pathlib import Path
@ -61,6 +62,19 @@
hidden_output = []
# Based on android/log.h in the NDK.
class LogPriority(IntEnum):
UNKNOWN = 0
DEFAULT = auto()
VERBOSE = auto()
DEBUG = auto()
INFO = auto()
WARN = auto()
ERROR = auto()
FATAL = auto()
SILENT = auto()
def log_verbose(context, line, stream=sys.stdout):
if context.verbose:
stream.write(line)
@ -505,21 +519,23 @@ async def logcat_task(context, initial_devices):
pid = await wait_for(find_pid(serial), startup_timeout)
# `--pid` requires API level 24 or higher.
args = [adb, "-s", serial, "logcat", "--pid", pid, "--format", "tag"]
#
# `--binary` mode is used in order to detect which messages end with a
# newline, which most of the other modes don't indicate (except `--format
# long`). For example, every time pytest runs a test, it prints a "." and
# flushes the stream. Each "." becomes a separate log message, but we should
# show them all on the same line.
args = [adb, "-s", serial, "logcat", "--pid", pid, "--binary"]
logcat_started = False
async with async_process(
*args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
*args, stdout=subprocess.PIPE, stderr=None
) as process:
while line := (await process.stdout.readline()).decode(*DECODE_ARGS):
if match := re.fullmatch(r"([A-Z])/(.*)", line, re.DOTALL):
while True:
try:
priority, tag, message = await read_logcat(process.stdout)
logcat_started = True
level, message = match.groups()
else:
# If the regex doesn't match, this is either a logcat startup
# error, or the second or subsequent line of a multi-line
# message. Python won't produce multi-line messages, but other
# components might.
level, message = None, line
except asyncio.IncompleteReadError:
break
# Exclude high-volume messages which are rarely useful.
if context.verbose < 2 and "from python test_syslog" in message:
@ -527,25 +543,23 @@ async def logcat_task(context, initial_devices):
# Put high-level messages on stderr so they're highlighted in the
# buildbot logs. This will include Python's own stderr.
stream = (
sys.stderr
if level in ["W", "E", "F"] # WARNING, ERROR, FATAL (aka ASSERT)
else sys.stdout
)
stream = sys.stderr if priority >= LogPriority.WARN else sys.stdout
# To simplify automated processing of the output, e.g. a buildbot
# posting a failure notice on a GitHub PR, we strip the level and
# tag indicators from Python's stdout and stderr.
for prefix in ["python.stdout: ", "python.stderr: "]:
if message.startswith(prefix):
global python_started
python_started = True
stream.write(message.removeprefix(prefix))
break
# The app's stdout and stderr should be passed through transparently
# to our own corresponding streams.
if tag in ["python.stdout", "python.stderr"]:
global python_started
python_started = True
stream.write(message)
stream.flush()
else:
# Non-Python messages add a lot of noise, but they may
# sometimes help explain a failure.
log_verbose(context, line, stream)
# sometimes help explain a failure. Format them in the same way
# as `logcat --format tag`.
formatted = f"{priority.name[0]}/{tag}: {message}"
if not formatted.endswith("\n"):
formatted += "\n"
log_verbose(context, formatted, stream)
# If the device disconnects while logcat is running, which always
# happens in --managed mode, some versions of adb return non-zero.
@ -556,6 +570,44 @@ async def logcat_task(context, initial_devices):
raise CalledProcessError(status, args)
# Read one binary log message from the given StreamReader. The message format is
# described at https://android.stackexchange.com/a/74660. All supported versions
# of Android use format version 2 or later.
async def read_logcat(stream):
async def read_bytes(size):
return await stream.readexactly(size)
async def read_int(size):
return int.from_bytes(await read_bytes(size), "little")
payload_len = await read_int(2)
if payload_len < 2:
# 1 byte for priority, 1 byte for null terminator of tag.
raise ValueError(f"payload length {payload_len} is too short")
header_len = await read_int(2)
if header_len < 4:
raise ValueError(f"header length {header_len} is too short")
await read_bytes(header_len - 4) # Ignore other header fields.
priority_int = await read_int(1)
try:
priority = LogPriority(priority_int)
except ValueError:
priority = LogPriority.UNKNOWN
payload_fields = (await read_bytes(payload_len - 1)).split(b"\0")
if len(payload_fields) < 2:
raise ValueError(
f"payload {payload!r} does not contain at least 2 "
f"null-separated fields"
)
tag, message, *_ = [
field.decode(*DECODE_ARGS) for field in payload_fields
]
return priority, tag, message
def stop_app(serial):
run([adb, "-s", serial, "shell", "am", "force-stop", APP_ID], log=False)

View file

@ -92,7 +92,15 @@ android {
}
throw GradleException("Failed to find API level in $androidEnvFile")
}
targetSdk = 35
// This controls the API level of the maxVersion managed emulator, which is used
// by CI and cibuildwheel.
// * 33 has excessive buffering in the logcat client
// (https://cs.android.com/android/_/android/platform/system/logging/+/d340721894f223327339010df59b0ac514308826).
// * 34 consumes too much disk space on GitHub Actions (#142289).
// * 35 has issues connecting to the internet (#142387).
// * 36 and later are not available as aosp_atd images yet.
targetSdk = 32
versionCode = 1
versionName = "1.0"
@ -125,9 +133,10 @@ android {
path("src/main/c/CMakeLists.txt")
}
// Set this property to something non-empty, otherwise it'll use the default
// list, which ignores asset directories beginning with an underscore.
aaptOptions.ignoreAssetsPattern = ".git"
// Set this property to something nonexistent but non-empty. Otherwise it'll use the
// default list, which ignores asset directories beginning with an underscore, and
// maybe also other files required by tests.
aaptOptions.ignoreAssetsPattern = "android-testbed-dont-ignore-anything"
compileOptions {
sourceCompatibility = JavaVersion.VERSION_1_8
@ -229,6 +238,12 @@ androidComponents.onVariants { variant ->
from(cwd)
}
}
// A filename ending with .gz will be automatically decompressed
// while building the APK. Avoid this by adding a dash to the end,
// and add an extra dash to any filenames that already end with one.
// This will be undone in MainActivity.kt.
rename(""".*(\.gz|-)""", "$0-")
}
}

View file

@ -80,7 +80,9 @@ class PythonTestRunner(val context: Context) {
continue
}
input.use {
File(targetSubdir, name).outputStream().use { output ->
// Undo the .gz workaround from build.gradle.kts.
val outputName = name.replace(Regex("""(.*)-"""), "$1")
File(targetSubdir, outputName).outputStream().use { output ->
input.copyTo(output)
}
}

View file

@ -130,6 +130,8 @@ The following functions provide locale-independent string to number conversions.
*flags* can be zero or more of the following values or-ed together:
.. c:namespace:: NULL
.. c:macro:: Py_DTSF_SIGN
Always precede the returned string with a sign
@ -151,9 +153,21 @@ The following functions provide locale-independent string to number conversions.
.. versionadded:: 3.11
If *ptype* is non-``NULL``, then the value it points to will be set to one of
``Py_DTST_FINITE``, ``Py_DTST_INFINITE``, or ``Py_DTST_NAN``, signifying that
*val* is a finite number, an infinite number, or not a number, respectively.
If *ptype* is non-``NULL``, then the value it points to will be set to one
of the following constants depending on the type of *val*:
.. list-table::
:header-rows: 1
:align: left
* - *\*ptype*
- type of *val*
* - .. c:macro:: Py_DTST_FINITE
- finite number
* - .. c:macro:: Py_DTST_INFINITE
- infinite number
* - .. c:macro:: Py_DTST_NAN
- not a number
The return value is a pointer to *buffer* with the converted string or
``NULL`` if the conversion failed. The caller is responsible for freeing the

View file

@ -256,6 +256,8 @@ To allocate and free memory, see :ref:`allocating-objects`.
collection (i.e., the :c:macro:`Py_TPFLAGS_HAVE_GC` flag is set); this may
change in the future.
.. versionadded:: 3.4
.. c:function:: int PyObject_CallFinalizerFromDealloc(PyObject *op)
@ -266,6 +268,8 @@ To allocate and free memory, see :ref:`allocating-objects`.
should happen. Otherwise, this function returns 0 and destruction can
continue normally.
.. versionadded:: 3.4
.. seealso::
:c:member:`~PyTypeObject.tp_dealloc` for example code.

View file

@ -687,7 +687,7 @@ Export API
.. versionadded:: 3.14
.. c:struct:: PyLongLayout
.. c:type:: PyLongLayout
Layout of an array of "digits" ("limbs" in the GMP terminology), used to
represent absolute value for arbitrary precision integers.
@ -727,7 +727,7 @@ Export API
Get the native layout of Python :class:`int` objects.
See the :c:struct:`PyLongLayout` structure.
See the :c:type:`PyLongLayout` structure.
The function must not be called before Python initialization nor after
Python finalization. The returned layout is valid until Python is
@ -735,7 +735,7 @@ Export API
in a process, and so it can be cached.
.. c:struct:: PyLongExport
.. c:type:: PyLongExport
Export of a Python :class:`int` object.
@ -769,7 +769,7 @@ Export API
Export a Python :class:`int` object.
*export_long* must point to a :c:struct:`PyLongExport` structure allocated
*export_long* must point to a :c:type:`PyLongExport` structure allocated
by the caller. It must not be ``NULL``.
On success, fill in *\*export_long* and return ``0``.
@ -799,7 +799,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer.
.. versionadded:: 3.14
.. c:struct:: PyLongWriter
.. c:type:: PyLongWriter
A Python :class:`int` writer instance.
@ -827,7 +827,7 @@ The :c:type:`PyLongWriter` API can be used to import an integer.
The layout of *digits* is described by :c:func:`PyLong_GetNativeLayout`.
Digits must be in the range [``0``; ``(1 << bits_per_digit) - 1``]
(where the :c:struct:`~PyLongLayout.bits_per_digit` is the number of bits
(where the :c:type:`~PyLongLayout.bits_per_digit` is the number of bits
per digit).
Any unused most significant digits must be set to ``0``.

View file

@ -677,7 +677,11 @@ The pymalloc allocator
Python has a *pymalloc* allocator optimized for small objects (smaller or equal
to 512 bytes) with a short lifetime. It uses memory mappings called "arenas"
with a fixed size of either 256 KiB on 32-bit platforms or 1 MiB on 64-bit
platforms. It falls back to :c:func:`PyMem_RawMalloc` and
platforms. When Python is configured with :option:`--with-pymalloc-hugepages`,
the arena size on 64-bit platforms is increased to 2 MiB to match the huge page
size, and arena allocation will attempt to use huge pages (``MAP_HUGETLB`` on
Linux, ``MEM_LARGE_PAGES`` on Windows) with automatic fallback to regular pages.
It falls back to :c:func:`PyMem_RawMalloc` and
:c:func:`PyMem_RawRealloc` for allocations larger than 512 bytes.
*pymalloc* is the :ref:`default allocator <default-memory-allocators>` of the

View file

@ -426,10 +426,10 @@ To retrieve the state from a given module, use the following functions:
module state.
.. c:function:: int PyModule_GetStateSize(PyObject *, Py_ssize_t *result)
.. c:function:: int PyModule_GetStateSize(PyObject *module, Py_ssize_t *result)
Set *\*result* to the size of the module's state, as specified using
:c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`),
Set *\*result* to the size of *module*'s state, as specified
using :c:macro:`Py_mod_state_size` (or :c:member:`PyModuleDef.m_size`),
and return 0.
On error, set *\*result* to -1, and return -1 with an exception set.
@ -597,7 +597,7 @@ A module's token -- and the *your_token* value to use in the above code -- is:
.. c:function:: int PyModule_GetToken(PyObject *module, void** result)
Set *\*result* to the module's token and return 0.
Set *\*result* to the module token for *module* and return 0.
On error, set *\*result* to NULL, and return -1 with an exception set.
@ -645,7 +645,7 @@ rather than from an extension's :ref:`export hook <extension-export-hook>`.
.. c:function:: int PyModule_Exec(PyObject *module)
Execute the :c:data:`Py_mod_exec` slot(s) of the given *module*.
Execute the :c:data:`Py_mod_exec` slot(s) of *module*.
On success, return 0.
On error, return -1 with an exception set.
@ -1021,6 +1021,9 @@ or code that creates modules dynamically.
``PyModuleDef`` (such as when using :ref:`multi-phase-initialization`,
``PyModule_Create``, or ``PyModule_FromDefAndSpec``).
Return ``0`` on success.
Return ``-1`` with an exception set on error.
.. versionadded:: 3.5
.. c:function:: int PyUnstable_Module_SetGIL(PyObject *module, void *gil)

View file

@ -711,10 +711,10 @@ Object Protocol
:c:func:`PyUnstable_EnableTryIncRef` must have been called
earlier on *obj* or this function may spuriously return ``0`` in the
:term:`free threading` build.
:term:`free-threaded build`.
This function is logically equivalent to the following C code, except that
it behaves atomically in the :term:`free threading` build::
it behaves atomically in the :term:`free-threaded build`::
if (Py_REFCNT(op) > 0) {
Py_INCREF(op);
@ -791,10 +791,10 @@ Object Protocol
On GIL-enabled builds, this function is equivalent to
:c:expr:`Py_REFCNT(op) == 1`.
On a :term:`free threaded <free threading>` build, this checks if *op*'s
On a :term:`free-threaded build`, this checks if *op*'s
:term:`reference count` is equal to one and additionally checks if *op*
is only used by this thread. :c:expr:`Py_REFCNT(op) == 1` is **not**
thread-safe on free threaded builds; prefer this function.
thread-safe on free-threaded builds; prefer this function.
The caller must hold an :term:`attached thread state`, despite the fact
that this function doesn't call into the Python interpreter. This function

View file

@ -25,7 +25,7 @@ of Python objects.
.. note::
On :term:`free threaded <free threading>` builds of Python, returning 1
On :term:`free-threaded builds <free-threaded build>` of Python, returning 1
isn't sufficient to determine if it's safe to treat *o* as having no
access by other threads. Use :c:func:`PyUnstable_Object_IsUniquelyReferenced`
for that instead.

View file

@ -389,8 +389,14 @@ func,PyList_SetSlice,3.2,,
func,PyList_Size,3.2,,
func,PyList_Sort,3.2,,
data,PyList_Type,3.2,,
type,PyLongExport,3.15,,full-abi
type,PyLongLayout,3.15,,full-abi
type,PyLongObject,3.2,,opaque
data,PyLongRangeIter_Type,3.2,,
type,PyLongWriter,3.15,,opaque
func,PyLongWriter_Create,3.15,,
func,PyLongWriter_Discard,3.15,,
func,PyLongWriter_Finish,3.15,,
func,PyLong_AsDouble,3.2,,
func,PyLong_AsInt,3.13,,
func,PyLong_AsInt32,3.14,,
@ -409,6 +415,8 @@ func,PyLong_AsUnsignedLongLong,3.2,,
func,PyLong_AsUnsignedLongLongMask,3.2,,
func,PyLong_AsUnsignedLongMask,3.2,,
func,PyLong_AsVoidPtr,3.2,,
func,PyLong_Export,3.15,,
func,PyLong_FreeExport,3.15,,
func,PyLong_FromDouble,3.2,,
func,PyLong_FromInt32,3.14,,
func,PyLong_FromInt64,3.14,,
@ -425,6 +433,7 @@ func,PyLong_FromUnsignedLongLong,3.2,,
func,PyLong_FromUnsignedNativeBytes,3.14,,
func,PyLong_FromVoidPtr,3.2,,
func,PyLong_GetInfo,3.2,,
func,PyLong_GetNativeLayout,3.15,,
data,PyLong_Type,3.2,,
macro,PyMODEXPORT_FUNC,3.15,,
data,PyMap_Type,3.2,,

View file

@ -171,7 +171,10 @@ Now, build install the *project in the current directory* (``.``) via ``pip``:
.. code-block:: sh
python -m pip install .
python -m pip -v install .
The ``-v`` (``--verbose``) option causes ``pip`` to show the output from
the compiler, which is often useful during development.
.. tip::
@ -460,7 +463,7 @@ So, we'll need to *encode* the data, and we'll use the UTF-8 encoding for it.
and the C API has special support for it.)
The function to encode a Python string into a UTF-8 buffer is named
:c:func:`PyUnicode_AsUTF8` [#why-pyunicodeasutf8]_.
:c:func:`PyUnicode_AsUTF8AndSize` [#why-pyunicodeasutf8]_.
Call it like this:
.. code-block:: c
@ -469,31 +472,31 @@ Call it like this:
static PyObject *
spam_system(PyObject *self, PyObject *arg)
{
const char *command = PyUnicode_AsUTF8(arg);
const char *command = PyUnicode_AsUTF8AndSize(arg, NULL);
int status = 3;
PyObject *result = PyLong_FromLong(status);
return result;
}
If :c:func:`PyUnicode_AsUTF8` is successful, *command* will point to the
resulting array of bytes.
If :c:func:`PyUnicode_AsUTF8AndSize` is successful, *command* will point to the
resulting C string -- a zero-terminated array of bytes [#embedded-nul]_.
This buffer is managed by the *arg* object, which means we don't need to free
it, but we must follow some rules:
* We should only use the buffer inside the ``spam_system`` function.
When ``spam_system`` returns, *arg* and the buffer it manages might be
After ``spam_system`` returns, *arg* and the buffer it manages might be
garbage-collected.
* We must not modify it. This is why we use ``const``.
If :c:func:`PyUnicode_AsUTF8` was *not* successful, it returns a ``NULL``
If :c:func:`PyUnicode_AsUTF8AndSize` was *not* successful, it returns a ``NULL``
pointer.
When calling *any* Python C API, we always need to handle such error cases.
The way to do this in general is left for later chapters of this documentation.
For now, be assured that we are already handling errors from
:c:func:`PyLong_FromLong` correctly.
For the :c:func:`PyUnicode_AsUTF8` call, the correct way to handle errors is
returning ``NULL`` from ``spam_system``.
For the :c:func:`PyUnicode_AsUTF8AndSize` call, the correct way to handle
errors is returning ``NULL`` from ``spam_system``.
Add an ``if`` block for this:
@ -503,7 +506,7 @@ Add an ``if`` block for this:
static PyObject *
spam_system(PyObject *self, PyObject *arg)
{
const char *command = PyUnicode_AsUTF8(arg);
const char *command = PyUnicode_AsUTF8AndSize(arg);
if (command == NULL) {
return NULL;
}
@ -512,7 +515,18 @@ Add an ``if`` block for this:
return result;
}
That's it for the setup.
To test that error handling works, compile again, restart Python so that
``import spam`` picks up the new version of your module, and try passing
a non-string value to your function:
.. code-block:: pycon
>>> import spam
>>> spam.system(3)
Traceback (most recent call last):
...
TypeError: bad argument type for built-in operation
Now, all that is left is calling the C library function :c:func:`system` with
the ``char *`` buffer, and using its result instead of the ``3``:
@ -522,7 +536,7 @@ the ``char *`` buffer, and using its result instead of the ``3``:
static PyObject *
spam_system(PyObject *self, PyObject *arg)
{
const char *command = PyUnicode_AsUTF8(arg);
const char *command = PyUnicode_AsUTF8AndSize(arg);
if (command == NULL) {
return NULL;
}
@ -543,7 +557,8 @@ system command:
>>> result
0
You might also want to test error cases:
You can also test with other commands, like ``ls``, ``dir``, or one
that doesn't exist:
.. code-block:: pycon
@ -553,11 +568,6 @@ You might also want to test error cases:
>>> result
32512
>>> spam.system(3)
Traceback (most recent call last):
...
TypeError: bad argument type for built-in operation
The result
==========
@ -665,3 +675,13 @@ on :py:attr:`sys.path`.
type.
.. [#why-pyunicodeasutf8] Here, ``PyUnicode`` refers to the original name of
the Python :py:class:`str` class: ``unicode``.
The ``AndSize`` part of the name refers to the fact that this function can
also retrieve the size of the buffer, using an output argument.
We don't need this, so we set the second argument to NULL.
.. [#embedded-nul] We're ignoring the fact that Python strings can also
contain NUL bytes, which terminate a C string.
In other words, our function will treat ``spam.system("foo\0bar")`` as
``spam.system("foo")``.
This possibility can lead to security issues, so the real ``os.system``
function size checks for this case and raises an error.

View file

@ -1226,13 +1226,13 @@ This converts the list into a set, thereby removing duplicates, and then back
into a list.
How do you remove multiple items from a list
--------------------------------------------
How do you remove multiple items from a list?
---------------------------------------------
As with removing duplicates, explicitly iterating in reverse with a
delete condition is one possibility. However, it is easier and faster
to use slice replacement with an implicit or explicit forward iteration.
Here are three variations.::
Here are three variations::
mylist[:] = filter(keep_function, mylist)
mylist[:] = (x for x in mylist if keep_condition)

View file

@ -160,9 +160,9 @@ Glossary
On most builds of Python, having an attached thread state implies that the
caller holds the :term:`GIL` for the current interpreter, so only
one OS thread can have an attached thread state at a given moment. In
:term:`free-threaded <free threading>` builds of Python, threads can concurrently
hold an attached thread state, allowing for true parallelism of the bytecode
interpreter.
:term:`free-threaded builds <free-threaded build>` of Python, threads can
concurrently hold an attached thread state, allowing for true parallelism of
the bytecode interpreter.
attribute
A value associated with an object which is usually referenced by name
@ -580,6 +580,13 @@ Glossary
the :term:`global interpreter lock` which allows only one thread to
execute Python bytecode at a time. See :pep:`703`.
free-threaded build
A build of :term:`CPython` that supports :term:`free threading`,
configured using the :option:`--disable-gil` option before compilation.
See :ref:`freethreading-python-howto`.
free variable
Formally, as defined in the :ref:`language execution model <bind_names>`, a free
variable is any variable used in a namespace which is not a local variable in that

View file

@ -8,6 +8,16 @@ execute Python code remotely.
Most platforms require elevated privileges to attach to another Python process.
Disabling remote debugging
--------------------------
To disable remote debugging support, use any of the following:
* Set the :envvar:`PYTHON_DISABLE_REMOTE_DEBUG` environment variable to ``1`` before
starting the interpreter.
* Use the :option:`-X disable_remote_debug` command-line option.
* Compile Python with the :option:`--without-remote-debug` build flag.
.. _permission-requirements:
Permission requirements
@ -614,4 +624,3 @@ To inject and execute a Python script in a remote process:
6. Set ``_PY_EVAL_PLEASE_STOP_BIT`` in the ``eval_breaker`` field.
7. Resume the process (if suspended). The script will execute at the next safe
evaluation point.

View file

@ -12,7 +12,7 @@
static PyObject *
spam_system(PyObject *self, PyObject *arg)
{
const char *command = PyUnicode_AsUTF8(arg);
const char *command = PyUnicode_AsUTF8AndSize(arg, NULL);
if (command == NULL) {
return NULL;
}

View file

@ -73,6 +73,7 @@ POST request.
.. function:: b64decode(s, altchars=None, validate=False)
b64decode(s, altchars=None, validate=True, *, ignorechars)
Decode the Base64 encoded :term:`bytes-like object` or ASCII string
*s* and return the decoded :class:`bytes`.
@ -84,15 +85,30 @@ POST request.
A :exc:`binascii.Error` exception is raised
if *s* is incorrectly padded.
If *validate* is ``False`` (the default), characters that are neither
in the normal base-64 alphabet nor the alternative alphabet are
discarded prior to the padding check. If *validate* is ``True``,
these non-alphabet characters in the input result in a
:exc:`binascii.Error`.
If *ignorechars* is specified, it should be a :term:`bytes-like object`
containing characters to ignore from the input when *validate* is true.
The default value of *validate* is ``True`` if *ignorechars* is specified,
``False`` otherwise.
If *validate* is false, characters that are neither
in the normal base-64 alphabet nor (if *ignorechars* is not specified)
the alternative alphabet are
discarded prior to the padding check, but the ``+`` and ``/`` characters
keep their meaning if they are not in *altchars* (they will be discarded
in future Python versions).
If *validate* is true, these non-alphabet characters in the input
result in a :exc:`binascii.Error`.
For more information about the strict base64 check, see :func:`binascii.a2b_base64`
May assert or raise a :exc:`ValueError` if the length of *altchars* is not 2.
.. versionchanged:: next
Added the *ignorechars* parameter.
.. deprecated:: next
Accepting the ``+`` and ``/`` characters with an alternative alphabet
is now deprecated.
.. function:: standard_b64encode(s)
@ -123,6 +139,9 @@ POST request.
``/`` in the standard Base64 alphabet, and return the decoded
:class:`bytes`.
.. deprecated:: next
Accepting the ``+`` and ``/`` characters is now deprecated.
.. function:: b32encode(s)
@ -246,8 +265,7 @@ Refer to the documentation of the individual functions for more information.
*adobe* controls whether the input sequence is in Adobe Ascii85 format
(i.e. is framed with <~ and ~>).
*ignorechars* should be a :term:`bytes-like object` or ASCII string
containing characters to ignore
*ignorechars* should be a byte string containing characters to ignore
from the input. This should only contain whitespace characters, and by
default contains all whitespace characters in ASCII.

View file

@ -49,10 +49,16 @@ The :mod:`binascii` module defines the following functions:
.. function:: a2b_base64(string, /, *, strict_mode=False)
a2b_base64(string, /, *, strict_mode=True, ignorechars)
Convert a block of base64 data back to binary and return the binary data. More
than one line may be passed at a time.
If *ignorechars* is specified, it should be a :term:`bytes-like object`
containing characters to ignore from the input when *strict_mode* is true.
The default value of *strict_mode* is ``True`` if *ignorechars* is specified,
``False`` otherwise.
If *strict_mode* is true, only valid base64 data will be converted. Invalid base64
data will raise :exc:`binascii.Error`.
@ -66,6 +72,9 @@ The :mod:`binascii` module defines the following functions:
.. versionchanged:: 3.11
Added the *strict_mode* parameter.
.. versionchanged:: next
Added the *ignorechars* parameter.
.. function:: b2a_base64(data, *, wrapcol=0, newline=True)

View file

@ -77,6 +77,32 @@ Context Variables
to restore the variable to its previous value via the
:meth:`ContextVar.reset` method.
For convenience, the token object can be used as a context manager
to avoid calling :meth:`ContextVar.reset` manually::
var = ContextVar('var', default='default value')
with var.set('new value'):
assert var.get() == 'new value'
assert var.get() == 'default value'
It is a shorthand for::
var = ContextVar('var', default='default value')
token = var.set('new value')
try:
assert var.get() == 'new value'
finally:
var.reset(token)
assert var.get() == 'default value'
.. versionadded:: 3.14
Added support for using tokens as context managers.
.. method:: reset(token)
Reset the context variable to the value it had before the
@ -93,24 +119,18 @@ Context Variables
# After the reset call the var has no value again, so
# var.get() would raise a LookupError.
The same *token* cannot be used twice.
.. class:: Token
*Token* objects are returned by the :meth:`ContextVar.set` method.
They can be passed to the :meth:`ContextVar.reset` method to revert
the value of the variable to what it was before the corresponding
*set*.
*set*. A single token cannot reset a context variable more than once.
The token supports :ref:`context manager protocol <context-managers>`
to restore the corresponding context variable value at the exit from
:keyword:`with` block::
var = ContextVar('var', default='default value')
with var.set('new value'):
assert var.get() == 'new value'
assert var.get() == 'default value'
Tokens support the :ref:`context manager protocol <context-managers>`
to automatically reset context variables. See :meth:`ContextVar.set`.
.. versionadded:: 3.14

View file

@ -896,7 +896,7 @@ invalid non-\ ``NULL`` pointers would crash Python)::
Thread safety without the GIL
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
From Python 3.13 onward, the :term:`GIL` can be disabled on :term:`free threaded <free threading>` builds.
From Python 3.13 onward, the :term:`GIL` can be disabled on the :term:`free-threaded build`.
In ctypes, reads and writes to a single object concurrently is safe, but not across multiple objects:
.. code-block:: pycon

View file

@ -1642,7 +1642,7 @@ iterations of the loop.
Pushes a ``NULL`` to the stack.
Used in the call sequence to match the ``NULL`` pushed by
:opcode:`!LOAD_METHOD` for non-method calls.
:opcode:`LOAD_ATTR` for non-method calls.
.. versionadded:: 3.11

View file

@ -294,9 +294,9 @@ The following example demonstrates how to use the :mod:`http.cookies` module.
Set-Cookie: chips=ahoy
Set-Cookie: vienna=finger
>>> C = cookies.SimpleCookie()
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
>>> print(C)
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
>>> C = cookies.SimpleCookie()
>>> C["oreo"] = "doublestuff"
>>> C["oreo"]["path"] = "/"

View file

@ -158,7 +158,7 @@ Go to Line
Show Completions
Open a scrollable list allowing selection of existing names. See
:ref:`Completions <completions>` in the Editing and navigation section below.
:ref:`Completions <completions>` in the Editing and Navigation section below.
Expand Word
Expand a prefix you have typed to match a full word in the same window;
@ -167,7 +167,7 @@ Expand Word
Show Call Tip
After an unclosed parenthesis for a function, open a small window with
function parameter hints. See :ref:`Calltips <calltips>` in the
Editing and navigation section below.
Editing and Navigation section below.
Show Surrounding Parens
Highlight the surrounding parenthesis.
@ -178,9 +178,9 @@ Format menu (Editor window only)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Format Paragraph
Reformat the current blank-line-delimited paragraph in comment block or
multiline string or selected line in a string. All lines in the
paragraph will be formatted to less than N columns, where N defaults to 72.
Rewrap the text block containing the text insert cursor.
Avoid code lines. See :ref:`Format block<format-block>` in the
Editing and Navigation section below.
Indent Region
Shift selected lines right by the indent width (default 4 spaces).
@ -566,6 +566,20 @@ In an editor, import statements have no effect until one runs the file.
One might want to run a file after writing import statements, after
adding function definitions, or after opening an existing file.
.. _format-block:
Format block
^^^^^^^^^^^^
Reformat Paragraph rewraps a block ('paragraph') of contiguous equally
indented non-blank comments, a similar block of text within a multiline
string, or a selected subset of either.
If needed, add a blank line to separate string from code.
Partial lines in a selection expand to complete lines.
The resulting lines have the same indent as before
but have maximum total length of N columns (characters).
Change the default N of 72 on the Window tab of IDLE Settings.
.. _code-context:
Code Context

View file

@ -596,172 +596,6 @@ ABC hierarchy::
itself does not end in ``__init__``.
.. class:: ResourceReader
*Superseded by TraversableResources*
An :term:`abstract base class` to provide the ability to read
*resources*.
From the perspective of this ABC, a *resource* is a binary
artifact that is shipped within a package. Typically this is
something like a data file that lives next to the ``__init__.py``
file of the package. The purpose of this class is to help abstract
out the accessing of such data files so that it does not matter if
the package and its data file(s) are stored e.g. in a zip file
versus on the file system.
For any of methods of this class, a *resource* argument is
expected to be a :term:`path-like object` which represents
conceptually just a file name. This means that no subdirectory
paths should be included in the *resource* argument. This is
because the location of the package the reader is for, acts as the
"directory". Hence the metaphor for directories and file
names is packages and resources, respectively. This is also why
instances of this class are expected to directly correlate to
a specific package (instead of potentially representing multiple
packages or a module).
Loaders that wish to support resource reading are expected to
provide a method called ``get_resource_reader(fullname)`` which
returns an object implementing this ABC's interface. If the module
specified by fullname is not a package, this method should return
:const:`None`. An object compatible with this ABC should only be
returned when the specified module is a package.
.. versionadded:: 3.7
.. deprecated-removed:: 3.12 3.14
Use :class:`importlib.resources.abc.TraversableResources` instead.
.. method:: open_resource(resource)
:abstractmethod:
Returns an opened, :term:`file-like object` for binary reading
of the *resource*.
If the resource cannot be found, :exc:`FileNotFoundError` is
raised.
.. method:: resource_path(resource)
:abstractmethod:
Returns the file system path to the *resource*.
If the resource does not concretely exist on the file system,
raise :exc:`FileNotFoundError`.
.. method:: is_resource(name)
:abstractmethod:
Returns ``True`` if the named *name* is considered a resource.
:exc:`FileNotFoundError` is raised if *name* does not exist.
.. method:: contents()
:abstractmethod:
Returns an :term:`iterable` of strings over the contents of
the package. Do note that it is not required that all names
returned by the iterator be actual resources, e.g. it is
acceptable to return names for which :meth:`is_resource` would
be false.
Allowing non-resource names to be returned is to allow for
situations where how a package and its resources are stored
are known a priori and the non-resource names would be useful.
For instance, returning subdirectory names is allowed so that
when it is known that the package and resources are stored on
the file system then those subdirectory names can be used
directly.
The abstract method returns an iterable of no items.
.. class:: Traversable
An object with a subset of :class:`pathlib.Path` methods suitable for
traversing directories and opening files.
For a representation of the object on the file-system, use
:meth:`importlib.resources.as_file`.
.. versionadded:: 3.9
.. deprecated-removed:: 3.12 3.14
Use :class:`importlib.resources.abc.Traversable` instead.
.. attribute:: name
Abstract. The base name of this object without any parent references.
.. method:: iterdir()
:abstractmethod:
Yield ``Traversable`` objects in ``self``.
.. method:: is_dir()
:abstractmethod:
Return ``True`` if ``self`` is a directory.
.. method:: is_file()
:abstractmethod:
Return ``True`` if ``self`` is a file.
.. method:: joinpath(child)
:abstractmethod:
Return Traversable child in ``self``.
.. method:: __truediv__(child)
:abstractmethod:
Return ``Traversable`` child in ``self``.
.. method:: open(mode='r', *args, **kwargs)
:abstractmethod:
*mode* may be 'r' or 'rb' to open as text or binary. Return a handle
suitable for reading (same as :attr:`pathlib.Path.open`).
When opening as text, accepts encoding parameters such as those
accepted by :class:`io.TextIOWrapper`.
.. method:: read_bytes()
Read contents of ``self`` as bytes.
.. method:: read_text(encoding=None)
Read contents of ``self`` as text.
.. class:: TraversableResources
An abstract base class for resource readers capable of serving
the :meth:`importlib.resources.files` interface. Subclasses
:class:`importlib.resources.abc.ResourceReader` and provides
concrete implementations of the :class:`importlib.resources.abc.ResourceReader`'s
abstract methods. Therefore, any loader supplying
:class:`importlib.abc.TraversableResources` also supplies ResourceReader.
Loaders that wish to support resource reading are expected to
implement this interface.
.. versionadded:: 3.9
.. deprecated-removed:: 3.12 3.14
Use :class:`importlib.resources.abc.TraversableResources` instead.
.. method:: files()
:abstractmethod:
Returns a :class:`importlib.resources.abc.Traversable` object for the loaded
package.
:mod:`importlib.machinery` -- Importers and path hooks
------------------------------------------------------

View file

@ -524,7 +524,7 @@ attributes (see :ref:`import-mod-attrs` for module attributes):
.. versionchanged:: 3.13
Functions wrapped in :func:`functools.partialmethod` now return ``True``
if the wrapped function is a :term:`coroutine function`.
if the wrapped function is a :term:`asynchronous generator` function.
.. function:: isasyncgen(object)

View file

@ -720,7 +720,7 @@ than raw I/O does.
contains initial data.
Methods may be used from multiple threads without external locking in
:term:`free threading` builds.
:term:`free-threaded builds <free-threaded build>`.
:class:`BytesIO` provides or overrides these methods in addition to those
from :class:`BufferedIOBase` and :class:`IOBase`:

View file

@ -7,6 +7,8 @@
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
**Source code:** :source:`PC/msvcrtmodule.c`
--------------
These functions provide access to some useful capabilities on Windows platforms.

View file

@ -1234,22 +1234,32 @@ Miscellaneous
.. versionchanged:: 3.11
Accepts a :term:`path-like object`.
.. function:: set_forkserver_preload(module_names)
.. function:: set_forkserver_preload(module_names, *, on_error='ignore')
Set a list of module names for the forkserver main process to attempt to
import so that their already imported state is inherited by forked
processes. Any :exc:`ImportError` when doing so is silently ignored.
This can be used as a performance enhancement to avoid repeated work
in every process.
processes. This can be used as a performance enhancement to avoid repeated
work in every process.
For this to work, it must be called before the forkserver process has been
launched (before creating a :class:`Pool` or starting a :class:`Process`).
The *on_error* parameter controls how :exc:`ImportError` exceptions during
module preloading are handled: ``"ignore"`` (default) silently ignores
failures, ``"warn"`` causes the forkserver subprocess to emit an
:exc:`ImportWarning` to stderr, and ``"fail"`` causes the forkserver
subprocess to exit with the exception traceback on stderr, making
subsequent process creation fail with :exc:`EOFError` or
:exc:`ConnectionError`.
Only meaningful when using the ``'forkserver'`` start method.
See :ref:`multiprocessing-start-methods`.
.. versionadded:: 3.4
.. versionchanged:: next
Added the *on_error* parameter.
.. function:: set_start_method(method, force=False)
Set the method which should be used to start child processes.

View file

@ -4262,7 +4262,7 @@ features:
import os
# semaphore with start value '1'
fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFC_CLOEXEC)
fd = os.eventfd(1, os.EFD_SEMAPHORE | os.EFD_CLOEXEC)
try:
# acquire semaphore
v = os.eventfd_read(fd)

View file

@ -56,19 +56,6 @@ files.
The :mod:`pickle` module differs from :mod:`marshal` in several significant ways:
* The :mod:`pickle` module keeps track of the objects it has already serialized,
so that later references to the same object won't be serialized again.
:mod:`marshal` doesn't do this.
This has implications both for recursive objects and object sharing. Recursive
objects are objects that contain references to themselves. These are not
handled by marshal, and in fact, attempting to marshal recursive objects will
crash your Python interpreter. Object sharing happens when there are multiple
references to the same object in different places in the object hierarchy being
serialized. :mod:`pickle` stores such objects only once, and ensures that all
other references point to the master copy. Shared objects remain shared, which
can be very important for mutable objects.
* :mod:`marshal` cannot be used to serialize user-defined classes and their
instances. :mod:`pickle` can save and restore class instances transparently,
however the class definition must be importable and live in the same module as

View file

@ -34,7 +34,7 @@ For the head part, it uses ``sys.prefix`` and ``sys.exec_prefix``; empty heads
are skipped. For the tail part, it uses the empty string and then
:file:`lib/site-packages` (on Windows) or
:file:`lib/python{X.Y[t]}/site-packages` (on Unix and macOS). (The
optional suffix "t" indicates the :term:`free threading` build, and is
optional suffix "t" indicates the :term:`free-threaded build`, and is
appended if ``"t"`` is present in the :data:`sys.abiflags` constant.)
For each
of the distinct head-tail combinations, it sees if it refers to an existing

View file

@ -2562,6 +2562,19 @@ expression support in the :mod:`re` module).
after the separator. If the separator is not found, return a 3-tuple containing
two empty strings, followed by the string itself.
For example:
.. doctest::
>>> 'Monty Python'.rpartition(' ')
('Monty', ' ', 'Python')
>>> "Monty Python's Flying Circus".rpartition(' ')
("Monty Python's Flying", ' ', 'Circus')
>>> 'Monty Python'.rpartition('-')
('', '', 'Monty Python')
See also :meth:`partition`.
.. method:: str.rsplit(sep=None, maxsplit=-1)

View file

@ -803,14 +803,29 @@ Instances of the :class:`Popen` class have the following methods:
.. note::
When the ``timeout`` parameter is not ``None``, then (on POSIX) the
function is implemented using a busy loop (non-blocking call and short
sleeps). Use the :mod:`asyncio` module for an asynchronous wait: see
When ``timeout`` is not ``None`` and the platform supports it, an
efficient event-driven mechanism is used to wait for process termination:
- Linux >= 5.3 uses :func:`os.pidfd_open` + :func:`select.poll`
- macOS and other BSD variants use :func:`select.kqueue` +
``KQ_FILTER_PROC`` + ``KQ_NOTE_EXIT``
- Windows uses ``WaitForSingleObject``
If none of these mechanisms are available, the function falls back to a
busy loop (non-blocking call and short sleeps).
.. note::
Use the :mod:`asyncio` module for an asynchronous wait: see
:class:`asyncio.create_subprocess_exec`.
.. versionchanged:: 3.3
*timeout* was added.
.. versionchanged:: 3.15
if *timeout* is not ``None``, use efficient event-driven implementation
on Linux >= 5.3 and macOS / BSD.
.. method:: Popen.communicate(input=None, timeout=None)
Interact with process: Send data to stdin. Read data from stdout and stderr,

View file

@ -180,6 +180,12 @@ Examining Symbol Tables
Return a tuple containing names of :term:`free (closure) variables <closure variable>`
in this function.
.. method:: get_cells()
Return a tuple containing names of :term:`cell variables <closure variable>` in this table.
.. versionadded:: next
.. class:: Class
@ -291,6 +297,12 @@ Examining Symbol Tables
Return ``True`` if the symbol is referenced in its block, but not assigned
to.
.. method:: is_cell()
Return ``True`` if the symbol is referenced but not assigned in a nested block.
.. versionadded:: next
.. method:: is_free_class()
Return *True* if a class-scoped symbol is free from

View file

@ -1997,6 +1997,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only
interpreter is pre-release (alpha, beta, or release candidate) then the
local and remote interpreters must be the same exact version.
See :ref:`remote-debugging` for more information about the remote debugging
mechanism.
.. audit-event:: sys.remote_exec pid script_path
When the code is executed in the remote process, an
@ -2015,6 +2018,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only
.. availability:: Unix, Windows.
.. versionadded:: 3.14
See :pep:`768` for more details.
.. function:: _enablelegacywindowsfsencoding()

View file

@ -177,12 +177,12 @@ the modern themed widget set and API::
.. attribute:: master
The widget object that contains this widget. For :class:`Tk`, the
*master* is :const:`None` because it is the main window. The terms
:attr:`!master` is :const:`None` because it is the main window. The terms
*master* and *parent* are similar and sometimes used interchangeably
as argument names; however, calling :meth:`winfo_parent` returns a
string of the widget name whereas :attr:`master` returns the object.
string of the widget name whereas :attr:`!master` returns the object.
*parent*/*child* reflects the tree-like relationship while
*master*/*slave* reflects the container structure.
*master* (or *container*)/*content* reflects the container structure.
.. attribute:: children
@ -638,15 +638,15 @@ The Packer
.. index:: single: packing (widgets)
The packer is one of Tk's geometry-management mechanisms. Geometry managers
are used to specify the relative positioning of widgets within their container -
their mutual *master*. In contrast to the more cumbersome *placer* (which is
are used to specify the relative positioning of widgets within their container.
In contrast to the more cumbersome *placer* (which is
used less commonly, and we do not cover here), the packer takes qualitative
relationship specification - *above*, *to the left of*, *filling*, etc - and
works everything out to determine the exact placement coordinates for you.
The size of any *master* widget is determined by the size of the "slave widgets"
inside. The packer is used to control where slave widgets appear inside the
master into which they are packed. You can pack widgets into frames, and frames
The size of any container widget is determined by the size of the "content widgets"
inside. The packer is used to control where content widgets appear inside the
container into which they are packed. You can pack widgets into frames, and frames
into other frames, in order to achieve the kind of layout you desire.
Additionally, the arrangement is dynamically adjusted to accommodate incremental
changes to the configuration, once it is packed.
@ -673,7 +673,7 @@ For more extensive information on the packer and the options that it can take,
see the man pages and page 183 of John Ousterhout's book.
anchor
Anchor type. Denotes where the packer is to place each slave in its parcel.
Anchor type. Denotes where the packer is to place each content in its parcel.
expand
Boolean, ``0`` or ``1``.
@ -682,10 +682,10 @@ fill
Legal values: ``'x'``, ``'y'``, ``'both'``, ``'none'``.
ipadx and ipady
A distance - designating internal padding on each side of the slave widget.
A distance - designating internal padding on each side of the content.
padx and pady
A distance - designating external padding on each side of the slave widget.
A distance - designating external padding on each side of the content.
side
Legal values are: ``'left'``, ``'right'``, ``'top'``, ``'bottom'``.
@ -758,8 +758,8 @@ subclassed from the :class:`Wm` class, and so can call the :class:`Wm` methods
directly.
To get at the toplevel window that contains a given widget, you can often just
refer to the widget's master. Of course if the widget has been packed inside of
a frame, the master won't represent a toplevel window. To get at the toplevel
refer to the widget's :attr:`master`. Of course if the widget has been packed inside of
a frame, the :attr:`!master` won't represent a toplevel window. To get at the toplevel
window that contains an arbitrary widget, you can call the :meth:`_root` method.
This method begins with an underscore to denote the fact that this function is
part of the implementation, and not an interface to Tk functionality.

View file

@ -50,12 +50,16 @@ URL Parsing
The URL parsing functions focus on splitting a URL string into its components,
or on combining URL components into a URL string.
.. function:: urlparse(urlstring, scheme='', allow_fragments=True)
.. function:: urlparse(urlstring, scheme=None, allow_fragments=True, *, missing_as_none=False)
Parse a URL into six components, returning a 6-item :term:`named tuple`. This
corresponds to the general structure of a URL:
``scheme://netloc/path;parameters?query#fragment``.
Each tuple item is a string, possibly empty. The components are not broken up
Each tuple item is a string, possibly empty, or ``None`` if
*missing_as_none* is true.
Not defined component are represented an empty string (by default) or
``None`` if *missing_as_none* is true.
The components are not broken up
into smaller parts (for example, the network location is a single string), and %
escapes are not expanded. The delimiters as shown above are not part of the
result, except for a leading slash in the *path* component, which is retained if
@ -84,6 +88,12 @@ or on combining URL components into a URL string.
80
>>> o._replace(fragment="").geturl()
'http://docs.python.org:80/3/library/urllib.parse.html?highlight=params'
>>> urlparse("http://docs.python.org?")
ParseResult(scheme='http', netloc='docs.python.org',
path='', params='', query='', fragment='')
>>> urlparse("http://docs.python.org?", missing_as_none=True)
ParseResult(scheme='http', netloc='docs.python.org',
path='', params=None, query='', fragment=None)
Following the syntax specifications in :rfc:`1808`, urlparse recognizes
a netloc only if it is properly introduced by '//'. Otherwise the
@ -101,47 +111,53 @@ or on combining URL components into a URL string.
ParseResult(scheme='', netloc='', path='www.cwi.nl/%7Eguido/Python.html',
params='', query='', fragment='')
>>> urlparse('help/Python.html')
ParseResult(scheme='', netloc='', path='help/Python.html', params='',
query='', fragment='')
ParseResult(scheme='', netloc='', path='help/Python.html',
params='', query='', fragment='')
>>> urlparse('help/Python.html', missing_as_none=True)
ParseResult(scheme=None, netloc=None, path='help/Python.html',
params=None, query=None, fragment=None)
The *scheme* argument gives the default addressing scheme, to be
used only if the URL does not specify one. It should be the same type
(text or bytes) as *urlstring*, except that the default value ``''`` is
(text or bytes) as *urlstring* or ``None``, except that the ``''`` is
always allowed, and is automatically converted to ``b''`` if appropriate.
If the *allow_fragments* argument is false, fragment identifiers are not
recognized. Instead, they are parsed as part of the path, parameters
or query component, and :attr:`fragment` is set to the empty string in
the return value.
or query component, and :attr:`fragment` is set to ``None`` or the empty
string (depending on the value of *missing_as_none*) in the return value.
The return value is a :term:`named tuple`, which means that its items can
be accessed by index or as named attributes, which are:
+------------------+-------+-------------------------+------------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+========================+
| :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter |
+------------------+-------+-------------------------+------------------------+
| :attr:`netloc` | 1 | Network location part | empty string |
+------------------+-------+-------------------------+------------------------+
| :attr:`path` | 2 | Hierarchical path | empty string |
+------------------+-------+-------------------------+------------------------+
| :attr:`params` | 3 | Parameters for last | empty string |
| | | path element | |
+------------------+-------+-------------------------+------------------------+
| :attr:`query` | 4 | Query component | empty string |
+------------------+-------+-------------------------+------------------------+
| :attr:`fragment` | 5 | Fragment identifier | empty string |
+------------------+-------+-------------------------+------------------------+
| :attr:`username` | | User name | :const:`None` |
+------------------+-------+-------------------------+------------------------+
| :attr:`password` | | Password | :const:`None` |
+------------------+-------+-------------------------+------------------------+
| :attr:`hostname` | | Host name (lower case) | :const:`None` |
+------------------+-------+-------------------------+------------------------+
| :attr:`port` | | Port number as integer, | :const:`None` |
| | | if present | |
+------------------+-------+-------------------------+------------------------+
+------------------+-------+-------------------------+-------------------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+===============================+
| :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter or |
| | | | empty string [1]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`netloc` | 1 | Network location part | ``None`` or empty string [1]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`path` | 2 | Hierarchical path | empty string |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`params` | 3 | Parameters for last | ``None`` or empty string [1]_ |
| | | path element | |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`query` | 4 | Query component | ``None`` or empty string [1]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`fragment` | 5 | Fragment identifier | ``None`` or empty string [1]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`username` | | User name | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`password` | | Password | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`hostname` | | Host name (lower case) | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`port` | | Port number as integer, | ``None`` |
| | | if present | |
+------------------+-------+-------------------------+-------------------------------+
.. [1] Depending on the value of the *missing_as_none* argument.
Reading the :attr:`port` attribute will raise a :exc:`ValueError` if
an invalid port is specified in the URL. See section
@ -187,12 +203,15 @@ or on combining URL components into a URL string.
.. versionchanged:: 3.6
Out-of-range port numbers now raise :exc:`ValueError`, instead of
returning :const:`None`.
returning ``None``.
.. versionchanged:: 3.8
Characters that affect netloc parsing under NFKC normalization will
now raise :exc:`ValueError`.
.. versionchanged:: next
Added the *missing_as_none* parameter.
.. function:: parse_qs(qs, keep_blank_values=False, strict_parsing=False, encoding='utf-8', errors='replace', max_num_fields=None, separator='&')
@ -288,15 +307,27 @@ or on combining URL components into a URL string.
.. function:: urlunparse(parts)
urlunparse(parts, *, keep_empty)
Construct a URL from a tuple as returned by ``urlparse()``. The *parts*
argument can be any six-item iterable. This may result in a slightly
different, but equivalent URL, if the URL that was parsed originally had
unnecessary delimiters (for example, a ``?`` with an empty query; the RFC
states that these are equivalent).
argument can be any six-item iterable.
This may result in a slightly different, but equivalent URL, if the
URL that was parsed originally had unnecessary delimiters (for example,
a ``?`` with an empty query; the RFC states that these are equivalent).
If *keep_empty* is true, empty strings are kept in the result (for example,
a ``?`` for an empty query), only ``None`` components are omitted.
This allows rebuilding a URL that was parsed with option
``missing_as_none=True``.
By default, *keep_empty* is true if *parts* is the result of the
:func:`urlparse` call with ``missing_as_none=True``.
.. versionchanged:: next
Added the *keep_empty* parameter.
.. function:: urlsplit(urlstring, scheme='', allow_fragments=True)
.. function:: urlsplit(urlstring, scheme=None, allow_fragments=True, *, missing_as_none=False)
This is similar to :func:`urlparse`, but does not split the params from the URL.
This should generally be used instead of :func:`urlparse` if the more recent URL
@ -310,28 +341,31 @@ or on combining URL components into a URL string.
The return value is a :term:`named tuple`, its items can be accessed by index
or as named attributes:
+------------------+-------+-------------------------+----------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+======================+
| :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter |
+------------------+-------+-------------------------+----------------------+
| :attr:`netloc` | 1 | Network location part | empty string |
+------------------+-------+-------------------------+----------------------+
| :attr:`path` | 2 | Hierarchical path | empty string |
+------------------+-------+-------------------------+----------------------+
| :attr:`query` | 3 | Query component | empty string |
+------------------+-------+-------------------------+----------------------+
| :attr:`fragment` | 4 | Fragment identifier | empty string |
+------------------+-------+-------------------------+----------------------+
| :attr:`username` | | User name | :const:`None` |
+------------------+-------+-------------------------+----------------------+
| :attr:`password` | | Password | :const:`None` |
+------------------+-------+-------------------------+----------------------+
| :attr:`hostname` | | Host name (lower case) | :const:`None` |
+------------------+-------+-------------------------+----------------------+
| :attr:`port` | | Port number as integer, | :const:`None` |
| | | if present | |
+------------------+-------+-------------------------+----------------------+
+------------------+-------+-------------------------+-------------------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+===============================+
| :attr:`scheme` | 0 | URL scheme specifier | *scheme* parameter or |
| | | | empty string [1]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`netloc` | 1 | Network location part | ``None`` or empty string [2]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`path` | 2 | Hierarchical path | empty string |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`query` | 3 | Query component | ``None`` or empty string [2]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`fragment` | 4 | Fragment identifier | ``None`` or empty string [2]_ |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`username` | | User name | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`password` | | Password | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`hostname` | | Host name (lower case) | ``None`` |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`port` | | Port number as integer, | ``None`` |
| | | if present | |
+------------------+-------+-------------------------+-------------------------------+
.. [2] Depending on the value of the *missing_as_none* argument.
Reading the :attr:`port` attribute will raise a :exc:`ValueError` if
an invalid port is specified in the URL. See section
@ -356,7 +390,7 @@ or on combining URL components into a URL string.
.. versionchanged:: 3.6
Out-of-range port numbers now raise :exc:`ValueError`, instead of
returning :const:`None`.
returning ``None``.
.. versionchanged:: 3.8
Characters that affect netloc parsing under NFKC normalization will
@ -368,15 +402,31 @@ or on combining URL components into a URL string.
.. versionchanged:: 3.12
Leading WHATWG C0 control and space characters are stripped from the URL.
.. versionchanged:: next
Added the *missing_as_none* parameter.
.. _WHATWG spec: https://url.spec.whatwg.org/#concept-basic-url-parser
.. function:: urlunsplit(parts)
urlunsplit(parts, *, keep_empty)
Combine the elements of a tuple as returned by :func:`urlsplit` into a
complete URL as a string. The *parts* argument can be any five-item
iterable. This may result in a slightly different, but equivalent URL, if the
URL that was parsed originally had unnecessary delimiters (for example, a ?
with an empty query; the RFC states that these are equivalent).
iterable.
This may result in a slightly different, but equivalent URL, if the
URL that was parsed originally had unnecessary delimiters (for example,
a ``?`` with an empty query; the RFC states that these are equivalent).
If *keep_empty* is true, empty strings are kept in the result (for example,
a ``?`` for an empty query), only ``None`` components are omitted.
This allows rebuilding a URL that was parsed with option
``missing_as_none=True``.
By default, *keep_empty* is true if *parts* is the result of the
:func:`urlsplit` call with ``missing_as_none=True``.
.. versionchanged:: next
Added the *keep_empty* parameter.
.. function:: urljoin(base, url, allow_fragments=True)
@ -422,23 +472,25 @@ or on combining URL components into a URL string.
Behavior updated to match the semantics defined in :rfc:`3986`.
.. function:: urldefrag(url)
.. function:: urldefrag(url, *, missing_as_none=False)
If *url* contains a fragment identifier, return a modified version of *url*
with no fragment identifier, and the fragment identifier as a separate
string. If there is no fragment identifier in *url*, return *url* unmodified
and an empty string.
and an empty string (by default) or ``None`` if *missing_as_none* is true.
The return value is a :term:`named tuple`, its items can be accessed by index
or as named attributes:
+------------------+-------+-------------------------+----------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+======================+
| :attr:`url` | 0 | URL with no fragment | empty string |
+------------------+-------+-------------------------+----------------------+
| :attr:`fragment` | 1 | Fragment identifier | empty string |
+------------------+-------+-------------------------+----------------------+
+------------------+-------+-------------------------+-------------------------------+
| Attribute | Index | Value | Value if not present |
+==================+=======+=========================+===============================+
| :attr:`url` | 0 | URL with no fragment | empty string |
+------------------+-------+-------------------------+-------------------------------+
| :attr:`fragment` | 1 | Fragment identifier | ``None`` or empty string [3]_ |
+------------------+-------+-------------------------+-------------------------------+
.. [3] Depending on the value of the *missing_as_none* argument.
See section :ref:`urlparse-result-object` for more information on the result
object.
@ -446,6 +498,9 @@ or on combining URL components into a URL string.
.. versionchanged:: 3.2
Result is a structured object rather than a simple 2-tuple.
.. versionchanged:: next
Added the *missing_as_none* parameter.
.. function:: unwrap(url)
Extract the url from a wrapped URL (that is, a string formatted as
@ -465,8 +520,9 @@ URLs elsewhere. Their purpose is for practical functionality rather than
purity.
Instead of raising an exception on unusual input, they may instead return some
component parts as empty strings. Or components may contain more than perhaps
they should.
component parts as empty strings or ``None`` (depending on the value of the
*missing_as_none* argument).
Or components may contain more than perhaps they should.
We recommend that users of these APIs where the values may be used anywhere
with security implications code defensively. Do some verification within your
@ -542,7 +598,8 @@ previous section, as well as an additional method:
Return the re-combined version of the original URL as a string. This may
differ from the original URL in that the scheme may be normalized to lower
case and empty components may be dropped. Specifically, empty parameters,
queries, and fragment identifiers will be removed.
queries, and fragment identifiers will be removed unless the URL was parsed
with ``missing_as_none=True``.
For :func:`urldefrag` results, only empty fragment identifiers will be removed.
For :func:`urlsplit` and :func:`urlparse` results, all noted changes will be
@ -559,6 +616,9 @@ previous section, as well as an additional method:
>>> r2 = urlsplit(r1.geturl())
>>> r2.geturl()
'http://www.Python.org/doc/'
>>> r3 = urlsplit(url, missing_as_none=True)
>>> r3.geturl()
'http://www.Python.org/doc/#'
The following classes provide the implementations of the structured parse

View file

@ -7,6 +7,8 @@
.. sectionauthor:: Mark Hammond <MarkH@ActiveState.com>
**Source code:** :source:`PC/winreg.c`
--------------
These functions expose the Windows registry API to Python. Instead of using an
@ -25,7 +27,7 @@ to explicitly close them.
.. _functions:
Functions
------------------
---------
This module offers the following functions:
@ -554,7 +556,7 @@ This module offers the following functions:
.. _constants:
Constants
------------------
---------
The following constants are defined for use in many :mod:`winreg` functions.

View file

@ -8,6 +8,8 @@
.. moduleauthor:: Toby Dickenson <htrd90@zepler.org>
.. sectionauthor:: Fred L. Drake, Jr. <fdrake@acm.org>
**Source code:** :source:`PC/winsound.c`
--------------
The :mod:`winsound` module provides access to the basic sound-playing machinery
@ -16,6 +18,9 @@ provided by Windows platforms. It includes functions and several constants.
.. availability:: Windows.
Functions
---------
.. function:: Beep(frequency, duration)
Beep the PC's speaker. The *frequency* parameter specifies frequency, in hertz,
@ -46,6 +51,9 @@ provided by Windows platforms. It includes functions and several constants.
error, :exc:`RuntimeError` is raised.
Constants
---------
.. data:: SND_FILENAME
The *sound* parameter is the name of a WAV file. Do not use with

View file

@ -546,6 +546,7 @@ Special read-only attributes
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.. index::
single: __builtins__ (function attribute)
single: __closure__ (function attribute)
single: __globals__ (function attribute)
pair: global; namespace
@ -556,6 +557,12 @@ Special read-only attributes
* - Attribute
- Meaning
* - .. attribute:: function.__builtins__
- A reference to the :class:`dictionary <dict>` that holds the function's
builtins namespace.
.. versionadded:: 3.10
* - .. attribute:: function.__globals__
- A reference to the :class:`dictionary <dict>` that holds the function's
:ref:`global variables <naming>` -- the global namespace of the module

View file

@ -266,17 +266,19 @@ called "displays", each of them in two flavors:
Common syntax elements for comprehensions are:
.. productionlist:: python-grammar
comprehension: `assignment_expression` `comp_for`
comprehension: `flexible_expression` `comp_for`
comp_for: ["async"] "for" `target_list` "in" `or_test` [`comp_iter`]
comp_iter: `comp_for` | `comp_if`
comp_if: "if" `or_test` [`comp_iter`]
The comprehension consists of a single expression followed by at least one
:keyword:`!for` clause and zero or more :keyword:`!for` or :keyword:`!if` clauses.
In this case, the elements of the new container are those that would be produced
by considering each of the :keyword:`!for` or :keyword:`!if` clauses a block,
nesting from left to right, and evaluating the expression to produce an element
each time the innermost block is reached.
:keyword:`!for` clause and zero or more :keyword:`!for` or :keyword:`!if`
clauses. In this case, the elements of the new container are those that would
be produced by considering each of the :keyword:`!for` or :keyword:`!if`
clauses a block, nesting from left to right, and evaluating the expression to
produce an element each time the innermost block is reached. If the expression
is starred, the result will instead be unpacked to produce zero or more
elements.
However, aside from the iterable expression in the leftmost :keyword:`!for` clause,
the comprehension is executed in a separate implicitly nested scope. This ensures
@ -321,6 +323,9 @@ See also :pep:`530`.
asynchronous functions. Outer comprehensions implicitly become
asynchronous.
.. versionchanged:: next
Unpacking with the ``*`` operator is now allowed in the expression.
.. _lists:
@ -396,8 +401,8 @@ enclosed in curly braces:
.. productionlist:: python-grammar
dict_display: "{" [`dict_item_list` | `dict_comprehension`] "}"
dict_item_list: `dict_item` ("," `dict_item`)* [","]
dict_comprehension: `dict_item` `comp_for`
dict_item: `expression` ":" `expression` | "**" `or_expr`
dict_comprehension: `expression` ":" `expression` `comp_for`
A dictionary display yields a new dictionary object.
@ -419,10 +424,21 @@ earlier dict items and earlier dictionary unpackings.
.. versionadded:: 3.5
Unpacking into dictionary displays, originally proposed by :pep:`448`.
A dict comprehension, in contrast to list and set comprehensions, needs two
expressions separated with a colon followed by the usual "for" and "if" clauses.
When the comprehension is run, the resulting key and value elements are inserted
in the new dictionary in the order they are produced.
A dict comprehension may take one of two forms:
- The first form uses two expressions separated with a colon followed by the
usual "for" and "if" clauses. When the comprehension is run, the resulting
key and value elements are inserted in the new dictionary in the order they
are produced.
- The second form uses a single expression prefixed by the ``**`` dictionary
unpacking operator followed by the usual "for" and "if" clauses. When the
comprehension is evaluated, the expression is evaluated and then unpacked,
inserting zero or more key/value pairs into the new dictionary.
Both forms of dictionary comprehension retain the property that if the same key
is specified multiple times, the associated value in the resulting dictionary
will be the last one specified.
.. index:: pair: immutable; object
hashable
@ -439,6 +455,8 @@ prevails.
the key. Starting with 3.8, the key is evaluated before the value, as
proposed by :pep:`572`.
.. versionchanged:: next
Unpacking with the ``**`` operator is now allowed in dictionary comprehensions.
.. _genexpr:
@ -453,7 +471,7 @@ Generator expressions
A generator expression is a compact generator notation in parentheses:
.. productionlist:: python-grammar
generator_expression: "(" `expression` `comp_for` ")"
generator_expression: "(" `flexible_expression` `comp_for` ")"
A generator expression yields a new generator object. Its syntax is the same as
for comprehensions, except that it is enclosed in parentheses instead of

View file

@ -929,6 +929,25 @@ Examples::
>>> list(data[i] for i in range(len(data)-1, -1, -1))
['f', 'l', 'o', 'g']
>>> x = [[1,2,3], [], [4, 5]]
>>> g = (*i for i in x)
>>> list(g)
[1, 2, 3, 4, 5]
In most cases, generator expressions must be wrapped in parentheses. As a
special case, however, when provided as the sole argument to a function (as in
the examples involving ``sum``, ``set``, ``max``, and ``list`` above), the
generator expression does not need to be wrapped in an additional set of
parentheses. That is to say, the following two pieces of code are semantically
equivalent::
>>> f(x for x in y)
>>> f((x for x in y))
as are the following::
>>> f(*x for x in y)
>>> f((*x for x in y))
.. rubric:: Footnotes

View file

@ -333,6 +333,47 @@ The :func:`zip` function would do a great job for this use case::
See :ref:`tut-unpacking-arguments` for details on the asterisk in this line.
Unpacking in Lists and List Comprehensions
------------------------------------------
The section on :ref:`tut-unpacking-arguments` describes the use of ``*`` to
"unpack" the elements of an iterable object, providing each one seperately as
an argument to a function. Unpacking can also be used in other contexts, for
example, when creating lists. When specifying elements of a list, prefixing an
expression by a ``*`` will unpack the result of that expression, adding each of
its elements to the list we're creating::
>>> x = [1, 2, 3]
>>> [0, *x, 4, 5, 6]
[0, 1, 2, 3, 4, 5, 6]
This only works if the expression following the ``*`` evaluates to an iterable
object; trying to unpack a non-iterable object will raise an exception::
>>> x = 1
>>> [0, *x, 2, 3, 4]
Traceback (most recent call last):
File "<python-input-1>", line 1, in <module>
[0, *x, 2, 3, 4]
TypeError: Value after * must be an iterable, not int
Unpacking can also be used in list comprehensions, as a way to build a new list
representing the concatenation of an arbitrary number of iterables::
>>> x = [[1, 2, 3], [4, 5, 6], [], [7], [8, 9]]
>>> [*element for element in x]
[1, 2, 3, 4, 5, 6, 7, 8, 9]
Note that the effect is that each element from ``x`` is unpacked. This works
for arbitrary iterable objects, not just lists::
>>> x = [[1, 2, 3], 'cat', {'spam': 'eggs'}]
>>> [*element for element in x]
[1, 2, 3, 'c', 'a', 't', 'spam']
But if the objects in ``x`` are not iterable, this expression would again raise
an exception.
.. _tut-del:
The :keyword:`!del` statement
@ -394,7 +435,10 @@ A tuple consists of a number of values separated by commas, for instance::
>>> v = ([1, 2, 3], [3, 2, 1])
>>> v
([1, 2, 3], [3, 2, 1])
>>> # they support unpacking just like lists:
>>> x = [1, 2, 3]
>>> 0, *x, 4
(0, 1, 2, 3, 4)
As you see, on output tuples are always enclosed in parentheses, so that nested
tuples are interpreted correctly; they may be input with or without surrounding
@ -480,12 +524,16 @@ Here is a brief demonstration::
{'r', 'd', 'b', 'm', 'z', 'l'}
Similarly to :ref:`list comprehensions <tut-listcomps>`, set comprehensions
are also supported::
are also supported, including comprehensions with unpacking::
>>> a = {x for x in 'abracadabra' if x not in 'abc'}
>>> a
{'r', 'd'}
>>> fruits = [{'apple', 'avocado', 'apricot'}, {'banana', 'blueberry'}]
>>> {*fruit for fruit in fruits}
{'blueberry', 'banana', 'avocado', 'apple', 'apricot'}
.. _tut-dictionaries:
@ -563,6 +611,18 @@ arbitrary key and value expressions::
>>> {x: x**2 for x in (2, 4, 6)}
{2: 4, 4: 16, 6: 36}
And dictionary unpacking (via ``**``) can be used to merge multiple
dictionaries::
>>> odds = {i: i**2 for i in (1, 3, 5)}
>>> evens = {i: i**2 for i in (2, 4, 6)}
>>> {**odds, **evens}
{1: 1, 3: 9, 5: 25, 2: 4, 4: 16, 6: 36}
>>> all_values = [odds, evens, {0: 0}]
>>> {**i for i in all_values}
{1: 1, 3: 9, 5: 25, 2: 4, 4: 16, 6: 36, 0: 0}
When the keys are simple strings, it is sometimes easier to specify pairs using
keyword arguments::

View file

@ -1087,6 +1087,27 @@ conflict.
It now has no effect if set to an empty string.
.. envvar:: PYTHON_PYMALLOC_HUGEPAGES
If set to a non-zero integer, enable huge page support for
:ref:`pymalloc <pymalloc>` arenas. Set to ``0`` or unset to disable.
Python must be compiled with :option:`--with-pymalloc-hugepages` for this
variable to have any effect.
When enabled, arena allocation uses ``MAP_HUGETLB`` (Linux) or
``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages if
huge pages are not available.
.. warning::
On Linux, if the huge-page pool is exhausted, page faults — including
copy-on-write faults triggered by :func:`os.fork` — deliver ``SIGBUS``
and kill the process. Only enable this in environments where the
huge-page pool is properly sized and fork-safety is not a concern.
.. versionadded:: next
.. envvar:: PYTHONLEGACYWINDOWSFSENCODING
If set to a non-empty string, the default :term:`filesystem encoding and

View file

@ -421,7 +421,7 @@ General Options
:no-typesetting:
Enables support for running Python without the :term:`global interpreter
lock` (GIL): free threading build.
lock` (GIL): :term:`free-threaded build`.
Defines the ``Py_GIL_DISABLED`` macro and adds ``"t"`` to
:data:`sys.abiflags`.
@ -783,6 +783,27 @@ also be used to improve performance.
See also :envvar:`PYTHONMALLOC` environment variable.
.. option:: --with-pymalloc-hugepages
Enable huge page support for :ref:`pymalloc <pymalloc>` arenas (disabled by
default). When enabled, the arena size on 64-bit platforms is increased to
2 MiB and arena allocation uses ``MAP_HUGETLB`` (Linux) or
``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages.
Even when compiled with this option, huge pages are **not** used at runtime
unless the :envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable is set
to ``1``. This opt-in is required because huge pages carry risks on Linux:
if the huge-page pool is exhausted, page faults (including copy-on-write
faults after :func:`os.fork`) deliver ``SIGBUS`` and kill the process.
The configure script checks that the platform supports ``MAP_HUGETLB``
and emits a warning if it is not available.
On Windows, use the ``--pymalloc-hugepages`` flag with ``build.bat`` or
set the ``UsePymallocHugepages`` MSBuild property.
.. versionadded:: 3.15
.. option:: --without-doc-strings
Disable static documentation strings to reduce the memory footprint (enabled

View file

@ -126,9 +126,8 @@ is also an unambiguous ``pymanager`` command. Scripted installs that are
intending to use Python install manager should consider using ``pymanager``, due
to the lower chance of encountering a conflict with existing installs. The only
difference between the two commands is when running without any arguments:
``py`` will install and launch your default interpreter, while ``pymanager``
will display help (``pymanager exec ...`` provides equivalent behaviour to
``py ...``).
``py`` will launch your default interpreter, while ``pymanager`` will display
help (``pymanager exec ...`` provides equivalent behaviour to ``py ...``).
Each of these commands also has a windowed version that avoids creating a
console window. These are ``pyw``, ``pythonw`` and ``pymanagerw``. A ``python3``
@ -187,12 +186,11 @@ that virtual environment. In this scenario, the ``python`` command was likely
already overridden and none of these checks occurred. However, this behaviour
ensures that the ``py`` command can be used interchangeably.
When you launch either ``python`` or ``py`` but do not have any runtimes
installed, and the requested version is the default, it will be installed
automatically and then launched. Otherwise, the requested version will be
installed if automatic installation is configured (most likely by setting
``PYTHON_MANAGER_AUTOMATIC_INSTALL`` to ``true``), or if the ``py exec`` or
``pymanager exec`` forms of the command were used.
When no runtimes are installed, any launch command will try to install the
requested version and launch it. However, after any version is installed, only
the ``py exec ...`` and ``pymanager exec ...`` commands will install if the
requested version is absent. Other forms of commands will display an error and
direct you to use ``py install`` first.
Command help
@ -301,6 +299,14 @@ To launch the runtime, directly execute the main executable (typically
$> py install ... [-t=|--target=<PATH>] <TAG>
The ``py exec`` command will install the requested runtime if it is not already
present. This is controlled by the ``automatic_install`` configuration
(:envvar:`PYTHON_MANAGER_AUTOMATIC_INSTALL`), and is enabled by default.
If no runtimes are available at all, all launch commands will do an automatic
install if the configuration setting allows. This is to ensure a good experience
for new users, but should not generally be relied on rather than using the
``py exec`` command or explicit install commands.
.. _pymanager-offline:
@ -426,9 +432,11 @@ customization.
By default, :file:`%TEMP%`.
* - ``automatic_install``
- ``PYTHON_MANAGER_AUTOMATIC_INSTALL``
- True to allow automatic installs when using ``py exec`` to launch.
Other commands will not automatically install.
- .. envvar:: PYTHON_MANAGER_AUTOMATIC_INSTALL
- True to allow automatic installs when using ``py exec`` to launch (or
``py`` when no runtimes are installed yet).
Other commands will not automatically install, regardless of this
setting.
By default, true.
* - ``include_unmanaged``
@ -777,7 +785,7 @@ Troubleshooting
If your Python install manager does not seem to be working correctly, please
work through these tests and fixes to see if it helps. If not, please report an
issue at `our bug tracker <https://github.com/python/cpython/issues>`_,
issue at `our bug tracker <https://github.com/python/pymanager/issues>`_,
including any relevant log files (written to your :file:`%TEMP%` directory by
default).

View file

@ -69,6 +69,8 @@ Summary -- Release highlights
profiling tools <whatsnew315-profiling-package>`
* :pep:`799`: :ref:`Tachyon: High frequency statistical sampling profiler
profiling tools <whatsnew315-sampling-profiler>`
* :pep:`798`: :ref:`Unpacking in Comprehensions
<whatsnew315-unpacking-in-comprehensions>`
* :pep:`686`: :ref:`Python now uses UTF-8 as the default encoding
<whatsnew315-utf8-default>`
* :pep:`782`: :ref:`A new PyBytesWriter C API to create a Python bytes object
@ -187,6 +189,45 @@ available output formats, profiling modes, and configuration options.
(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953` and :gh:`138122`.)
.. _whatsnew315-unpacking-in-comprehensions:
:pep:`798`: Unpacking in Comprehensions
---------------------------------------
List, set, and dictionary comprehensions, as well as generator expressions, now
support unpacking with ``*`` and ``**``. This extends the unpacking syntax
from :pep:`448` to comprehensions, providing a new syntax for combining an
arbitrary number of iterables or dictionaries into a single flat structure.
This new syntax is a direct alternative to nested comprehensions,
:func:`itertools.chain`, and :meth:`itertools.chain.from_iterable`. For
example::
>>> lists = [[1, 2], [3, 4], [5]]
>>> [*L for L in lists] # equivalent to [x for L in lists for x in L]
[1, 2, 3, 4, 5]
>>> sets = [{1, 2}, {2, 3}, {3, 4}]
>>> {*s for s in sets} # equivalent to {x for s in sets for x in s}
{1, 2, 3, 4}
>>> dicts = [{'a': 1}, {'b': 2}, {'a': 3}]
>>> {**d for d in dicts} # equivalent to {k: v for d in dicts for k,v in d.items()}
{'a': 3, 'b': 2}
Generator expressions can similarly use unpacking to yield values from multiple
iterables::
>>> gen = (*L for L in lists) # equivalent to (x for L in lists for x in L)
>>> list(gen)
[1, 2, 3, 4, 5]
This change also extends to asynchronous generator expressions, such that, for
example, ``(*a async for a in agen())`` is equivalent to ``(x async for a in
agen() for x in a)``.
.. seealso:: :pep:`798` for further details.
(Contributed by Adam Hartz in :gh:`143055`.)
.. _whatsnew315-improved-error-messages:
@ -444,6 +485,8 @@ base64
* Added the *wrapcol* parameter in :func:`~base64.b64encode`.
(Contributed by Serhiy Storchaka in :gh:`143214`.)
* Added the *ignorechars* parameter in :func:`~base64.b64decode`.
(Contributed by Serhiy Storchaka in :gh:`144001`.)
binascii
--------
@ -451,6 +494,9 @@ binascii
* Added the *wrapcol* parameter in :func:`~binascii.b2a_base64`.
(Contributed by Serhiy Storchaka in :gh:`143214`.)
* Added the *ignorechars* parameter in :func:`~binascii.a2b_base64`.
(Contributed by Serhiy Storchaka in :gh:`144001`.)
calendar
--------
@ -603,8 +649,10 @@ math
mimetypes
---------
* Add ``application/dicom`` MIME type for ``.dcm`` extension. (Contributed by Benedikt Johannes in :gh:`144217`.)
* Add ``application/node`` MIME type for ``.cjs`` extension. (Contributed by John Franey in :gh:`140937`.)
* Add ``application/toml``. (Contributed by Gil Forcada in :gh:`139959`.)
* Add ``image/jxl``. (Contributed by Foolbar in :gh:`144213`.)
* Rename ``application/x-texinfo`` to ``application/texinfo``.
(Contributed by Charlie Lin in :gh:`140165`.)
* Changed the MIME type for ``.ai`` files to ``application/pdf``.
@ -736,6 +784,27 @@ ssl
(Contributed by Ron Frederick in :gh:`138252`.)
subprocess
----------
* :meth:`subprocess.Popen.wait`: when ``timeout`` is not ``None`` and the
platform supports it, an efficient event-driven mechanism is used to wait for
process termination:
- Linux >= 5.3 uses :func:`os.pidfd_open` + :func:`select.poll`.
- macOS and other BSD variants use :func:`select.kqueue` + ``KQ_FILTER_PROC`` + ``KQ_NOTE_EXIT``.
- Windows keeps using ``WaitForSingleObject`` (unchanged).
If none of these mechanisms are available, the function falls back to the
traditional busy loop (non-blocking call and short sleeps).
(Contributed by Giampaolo Rodola in :gh:`83069`).
symtable
--------
* Add :meth:`symtable.Function.get_cells` and :meth:`symtable.Symbol.is_cell` methods.
(Contributed by Yashp002 in :gh:`143504`.)
sys
---
@ -792,6 +861,12 @@ tkinter
using Tcl's ``-all`` and ``-overlap`` options.
(Contributed by Rihaan Meher in :gh:`130848`)
* Added new methods :meth:`!pack_content`, :meth:`!place_content` and
:meth:`!grid_content` which use Tk commands with new names (introduced
in Tk 8.6) instead of :meth:`!*_slaves` methods which use Tk commands
with outdated names.
(Contributed by Serhiy Storchaka in :gh:`143754`)
types
------
@ -830,6 +905,18 @@ unittest
(Contributed by Garry Cairns in :gh:`134567`.)
urllib.parse
------------
* Add the *missing_as_none* parameter to :func:`~urllib.parse.urlparse`,
:func:`~urllib.parse.urlsplit` and :func:`~urllib.parse.urldefrag` functions.
Add the *keep_empty* parameter to :func:`~urllib.parse.urlunparse` and
:func:`~urllib.parse.urlunsplit` functions.
This allows to distinguish between empty and not defined URI components
and preserve empty components.
(Contributed by Serhiy Storchaka in :gh:`67041`.)
venv
----
@ -1143,6 +1230,15 @@ Deprecated
New deprecations
----------------
* :mod:`base64`:
* Accepting the ``+`` and ``/`` characters with an alternative alphabet in
:func:`~base64.b64decode` and :func:`~base64.urlsafe_b64decode` is now
deprecated.
In future Python versions they will be errors in the strict mode and
discarded in the non-strict mode.
(Contributed by Serhiy Storchaka in :gh:`125346`.)
* CLI:
* Deprecate :option:`-b` and :option:`!-bb` command-line options
@ -1422,6 +1518,14 @@ Build changes
modules that are missing or packaged separately.
(Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.)
* The new configure option :option:`--with-pymalloc-hugepages` enables huge
page support for :ref:`pymalloc <pymalloc>` arenas. When enabled, arena size
increases to 2 MiB and allocation uses ``MAP_HUGETLB`` (Linux) or
``MEM_LARGE_PAGES`` (Windows) with automatic fallback to regular pages.
On Windows, use ``build.bat --pymalloc-hugepages``.
At runtime, huge pages must be explicitly enabled by setting the
:envvar:`PYTHON_PYMALLOC_HUGEPAGES` environment variable to ``1``.
* Annotating anonymous mmap usage is now supported if Linux kernel supports
:manpage:`PR_SET_VMA_ANON_NAME <PR_SET_VMA(2const)>` (Linux 5.17 or newer).
Annotations are visible in ``/proc/<pid>/maps`` if the kernel supports the feature

View file

@ -604,7 +604,7 @@ new ABC for access to, opening, and reading *resources* inside packages.
Resources are roughly similar to files inside packages, but they needn't
be actual files on the physical file system. Module loaders can provide a
:meth:`!get_resource_reader` function which returns
a :class:`importlib.abc.ResourceReader` instance to support this
a :class:`!importlib.abc.ResourceReader` instance to support this
new API. Built-in file path loaders and zip file loaders both support this.
Contributed by Barry Warsaw and Brett Cannon in :issue:`32248`.
@ -1043,7 +1043,7 @@ window are shown and hidden in the Options menu.
importlib
---------
The :class:`importlib.abc.ResourceReader` ABC was introduced to
The :class:`!importlib.abc.ResourceReader` ABC was introduced to
support the loading of resources from packages. See also
:ref:`whatsnew37_importlib_resources`.
(Contributed by Barry Warsaw, Brett Cannon in :issue:`32248`.)
@ -2032,7 +2032,7 @@ both deprecated in Python 3.4 now emit :exc:`DeprecationWarning`.
(Contributed by Matthias Bussonnier in :issue:`29576`.)
The :class:`importlib.abc.ResourceLoader` ABC has been deprecated in
favour of :class:`importlib.abc.ResourceReader`.
favour of :class:`!importlib.abc.ResourceReader`.
locale

View file

@ -709,12 +709,16 @@ expressions[expr_ty]:
| expression
expression[expr_ty] (memo):
| invalid_if_expression
| invalid_expression
| invalid_legacy_expression
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
| if_expression
| disjunction
| lambdef
if_expression[expr_ty]:
| a=disjunction 'if' b=disjunction 'else' c=expression { _PyAST_IfExp(b, a, c, EXTRA) }
yield_expr[expr_ty]:
| 'yield' 'from' a=expression { _PyAST_YieldFrom(a, EXTRA) }
| 'yield' a=[star_expressions] { _PyAST_Yield(a, EXTRA) }
@ -731,10 +735,16 @@ star_expression[expr_ty] (memo):
star_named_expressions[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression+ [','] { a }
star_named_expressions_sequence[asdl_expr_seq*]: a[asdl_expr_seq*]=','.star_named_expression_sequence+ [','] { a }
star_named_expression[expr_ty]:
| '*' a=bitwise_or { _PyAST_Starred(a, Load, EXTRA) }
| named_expression
star_named_expression_sequence[expr_ty]:
| invalid_starred_expression_unpacking_sequence
| star_named_expression
assignment_expression[expr_ty]:
| a=NAME ':=' ~ b=expression {
CHECK_VERSION(expr_ty, 8, "Assignment expressions are",
@ -882,9 +892,9 @@ atom[expr_ty]:
| 'None' { _PyAST_Constant(Py_None, NULL, EXTRA) }
| &(STRING|FSTRING_START|TSTRING_START) strings
| NUMBER
| &'(' (tuple | group | genexp)
| &'[' (list | listcomp)
| &'{' (dict | set | dictcomp | setcomp)
| &'(' (genexp | tuple | group)
| &'[' (listcomp | list)
| &'{' (dictcomp | setcomp | dict | set)
| '...' { _PyAST_Constant(Py_Ellipsis, NULL, EXTRA) }
group[expr_ty]:
@ -998,13 +1008,13 @@ strings[expr_ty] (memo):
| a[asdl_expr_seq*]=tstring+ { _PyPegen_concatenate_tstrings(p, a, EXTRA) }
list[expr_ty]:
| '[' a=[star_named_expressions] ']' { _PyAST_List(a, Load, EXTRA) }
| '[' a=[star_named_expressions_sequence] ']' { _PyAST_List(a, Load, EXTRA) }
tuple[expr_ty]:
| '(' a=[y=star_named_expression ',' z=[star_named_expressions] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
| '(' a=[y=star_named_expression_sequence ',' z=[star_named_expressions_sequence] { _PyPegen_seq_insert_in_front(p, y, z) } ] ')' {
_PyAST_Tuple(a, Load, EXTRA) }
set[expr_ty]: '{' a=star_named_expressions '}' { _PyAST_Set(a, EXTRA) }
set[expr_ty]: '{' a=star_named_expressions_sequence '}' { _PyAST_Set(a, EXTRA) }
# Dicts
# -----
@ -1040,20 +1050,20 @@ for_if_clause[comprehension_ty]:
| invalid_for_target
listcomp[expr_ty]:
| '[' a=named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) }
| '[' a=star_named_expression b=for_if_clauses ']' { _PyAST_ListComp(a, b, EXTRA) }
| invalid_comprehension
setcomp[expr_ty]:
| '{' a=named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
| '{' a=star_named_expression b=for_if_clauses '}' { _PyAST_SetComp(a, b, EXTRA) }
| invalid_comprehension
genexp[expr_ty]:
| '(' a=( assignment_expression | expression !':=') b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
| '(' a=( assignment_expression | expression !':=' | starred_expression ) b=for_if_clauses ')' { _PyAST_GeneratorExp(a, b, EXTRA) }
| invalid_comprehension
dictcomp[expr_ty]:
| '{' a=kvpair b=for_if_clauses '}' { _PyAST_DictComp(a->key, a->value, b, EXTRA) }
| invalid_dict_comprehension
| '{' '**' a=expression b=for_if_clauses '}' { _PyAST_DictComp(a, NULL, b, EXTRA) }
# FUNCTION CALL ARGUMENTS
# =======================
@ -1262,6 +1272,12 @@ invalid_expression:
| a='lambda' [lambda_params] b=':' &TSTRING_MIDDLE {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "t-string: lambda expressions are not allowed without parentheses") }
invalid_if_expression:
| disjunction 'if' b=disjunction 'else' a='*' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot unpack only part of a conditional expression") }
| disjunction 'if' b=disjunction 'else' a='**' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use dict unpacking on only part of a conditional expression") }
invalid_named_expression(memo):
| a=expression ':=' expression {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(
@ -1326,16 +1342,15 @@ invalid_assert_stmt:
invalid_block:
| NEWLINE !INDENT { RAISE_INDENTATION_ERROR("expected an indented block") }
invalid_comprehension:
| ('[' | '(' | '{') a=starred_expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "iterable unpacking cannot be used in comprehension") }
| '[' a='**' b=expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in list comprehension") }
| '(' a='**' b=expression for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in generator expression") }
| ('[' | '{') a=star_named_expression ',' b=star_named_expressions for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, PyPegen_last_item(b, expr_ty),
"did you forget parentheses around the comprehension target?") }
| ('[' | '{') a=star_named_expression b=',' for_if_clauses {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "did you forget parentheses around the comprehension target?") }
invalid_dict_comprehension:
| '{' a='**' bitwise_or for_if_clauses '}' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "dict unpacking cannot be used in dict comprehension") }
invalid_parameters:
| a="/" ',' {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "at least one parameter must precede /") }
@ -1530,19 +1545,32 @@ invalid_class_def_raw:
RAISE_INDENTATION_ERROR("expected an indented block after class definition on line %d", a->lineno) }
invalid_double_starred_kvpairs:
| ','.double_starred_kvpair+ ',' invalid_kvpair
| expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") }
| invalid_kvpair_unpacking [',']
| ','.double_starred_kvpair+ ',' (invalid_kvpair | invalid_kvpair_unpacking)
| expression a=':' &('}'|',') { RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_kvpair_unpacking:
| a='**' b=if_expression {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid double starred expression. Did you forget to wrap the conditional expression in parentheses?") }
| a='*' b=bitwise_or ':' expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use a starred expression in a dictionary key") }
| a='**' b=bitwise_or ':' expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in a dictionary key") }
| expression ':' a='*' b=bitwise_or { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use a starred expression in a dictionary value") }
| expression ':' a='**' b=bitwise_or { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot use dict unpacking in a dictionary value") }
invalid_kvpair:
| a=expression !(':') {
RAISE_ERROR_KNOWN_LOCATION(p, PyExc_SyntaxError, a->lineno, a->end_col_offset - 1, a->end_lineno, -1, "':' expected after dictionary key") }
| expression ':' a='*' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use a starred expression in a dictionary value") }
| expression ':' a='**' bitwise_or { RAISE_SYNTAX_ERROR_STARTING_FROM(a, "cannot use dict unpacking in a dictionary value") }
| expression a=':' &('}'|',') {RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "expression expected after dictionary key and ':'") }
invalid_starred_expression_unpacking:
| a='*' b=if_expression {
RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "invalid starred expression. Did you forget to wrap the conditional expression in parentheses?") }
| a='*' expression '=' b=expression { RAISE_SYNTAX_ERROR_KNOWN_RANGE(a, b, "cannot assign to iterable argument unpacking") }
invalid_starred_expression_unpacking_sequence:
| a='**' bitwise_or {
RAISE_SYNTAX_ERROR_KNOWN_LOCATION(a, "cannot use dict unpacking here") }
| invalid_starred_expression_unpacking
invalid_starred_expression:
| '*' { RAISE_SYNTAX_ERROR("Invalid star expression") }
invalid_fstring_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 '!'") }

View file

@ -149,6 +149,7 @@ typedef struct PyConfig {
int dump_refs;
wchar_t *dump_refs_file;
int malloc_stats;
int pymalloc_hugepages;
wchar_t *filesystem_encoding;
wchar_t *filesystem_errors;
wchar_t *pycache_prefix;

View file

@ -138,45 +138,6 @@ _PyLong_CompactValue(const PyLongObject *op)
#define PyUnstable_Long_CompactValue _PyLong_CompactValue
/* --- Import/Export API -------------------------------------------------- */
typedef struct PyLongLayout {
uint8_t bits_per_digit;
uint8_t digit_size;
int8_t digits_order;
int8_t digit_endianness;
} PyLongLayout;
PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void);
typedef struct PyLongExport {
int64_t value;
uint8_t negative;
Py_ssize_t ndigits;
const void *digits;
// Member used internally, must not be used for other purpose.
Py_uintptr_t _reserved;
} PyLongExport;
PyAPI_FUNC(int) PyLong_Export(
PyObject *obj,
PyLongExport *export_long);
PyAPI_FUNC(void) PyLong_FreeExport(
PyLongExport *export_long);
/* --- PyLongWriter API --------------------------------------------------- */
typedef struct PyLongWriter PyLongWriter;
PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create(
int negative,
Py_ssize_t ndigits,
void **digits);
PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer);
PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer);
#ifdef __cplusplus
}
#endif

View file

@ -292,17 +292,7 @@ extern int _PyCode_SafeAddr2Line(PyCodeObject *co, int addr);
extern void _PyCode_Clear_Executors(PyCodeObject *code);
#ifdef Py_GIL_DISABLED
// gh-115999 tracks progress on addressing this.
#define ENABLE_SPECIALIZATION 0
// Use this to enable specialization families once they are thread-safe. All
// uses will be replaced with ENABLE_SPECIALIZATION once all families are
// thread-safe.
#define ENABLE_SPECIALIZATION_FT 1
#else
#define ENABLE_SPECIALIZATION 1
#define ENABLE_SPECIALIZATION_FT ENABLE_SPECIALIZATION
#endif
/* Specialization functions, these are exported only for other re-generated
* interpreters to call */

View file

@ -44,15 +44,16 @@ extern PyFrameObject* _PyFrame_New_NoTrack(PyCodeObject *code);
/* other API */
typedef enum _framestate {
FRAME_CREATED = -3,
FRAME_SUSPENDED = -2,
FRAME_SUSPENDED_YIELD_FROM = -1,
FRAME_CREATED = -4,
FRAME_SUSPENDED = -3,
FRAME_SUSPENDED_YIELD_FROM = -2,
FRAME_SUSPENDED_YIELD_FROM_LOCKED = -1,
FRAME_EXECUTING = 0,
FRAME_COMPLETED = 1,
FRAME_CLEARED = 4
} PyFrameState;
#define FRAME_STATE_SUSPENDED(S) ((S) == FRAME_SUSPENDED || (S) == FRAME_SUSPENDED_YIELD_FROM)
#define FRAME_STATE_SUSPENDED(S) ((S) >= FRAME_SUSPENDED && (S) <= FRAME_SUSPENDED_YIELD_FROM_LOCKED)
#define FRAME_STATE_FINISHED(S) ((S) >= FRAME_COMPLETED)
#ifdef __cplusplus

View file

@ -1797,6 +1797,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ident));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(identity_hint));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignore));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(ignorechars));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(imag));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(implieslink));
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(importlib));

View file

@ -520,6 +520,7 @@ struct _Py_global_strings {
STRUCT_FOR_ID(ident)
STRUCT_FOR_ID(identity_hint)
STRUCT_FOR_ID(ignore)
STRUCT_FOR_ID(ignorechars)
STRUCT_FOR_ID(imag)
STRUCT_FOR_ID(implieslink)
STRUCT_FOR_ID(importlib)

View file

@ -411,6 +411,7 @@ typedef struct _PyOptimizationConfig {
// Optimization flags
bool specialization_enabled;
bool uops_optimize_enabled;
} _PyOptimizationConfig;
struct

View file

@ -26,6 +26,7 @@ typedef _Py_CODEUNIT *(*jit_func)(
int _PyJIT_Compile(_PyExecutorObject *executor, const _PyUOpInstruction *trace, size_t length);
void _PyJIT_Free(_PyExecutorObject *executor);
void _PyJIT_Fini(void);
PyAPI_FUNC(int) _PyJIT_AddressInJitCode(PyInterpreterState *interp, uintptr_t addr);
#endif // _Py_JIT

View file

@ -70,6 +70,9 @@ PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags)
// error messages) otherwise returns 0.
extern int _PyMutex_TryUnlock(PyMutex *m);
// Yield the processor to other threads (e.g., sched_yield).
extern void _Py_yield(void);
// PyEvent is a one-time event notification
typedef struct {

View file

@ -208,7 +208,11 @@ typedef unsigned int pymem_uint; /* assuming >= 16 bits */
* mappings to reduce heap fragmentation.
*/
#ifdef USE_LARGE_ARENAS
#define ARENA_BITS 20 /* 1 MiB */
# ifdef PYMALLOC_USE_HUGEPAGES
# define ARENA_BITS 21 /* 2 MiB */
# else
# define ARENA_BITS 20 /* 1 MiB */
# endif
#else
#define ARENA_BITS 18 /* 256 KiB */
#endif
@ -469,7 +473,7 @@ nfp free pools in usable_arenas.
*/
/* How many arena_objects do we initially allocate?
* 16 = can allocate 16 arenas = 16 * ARENA_SIZE = 4MB before growing the
* 16 = can allocate 16 arenas = 16 * ARENA_SIZE before growing the
* `arenas` vector.
*/
#define INITIAL_ARENA_OBJECTS 16
@ -512,7 +516,11 @@ struct _obmalloc_mgmt {
memory address bit allocation for keys
64-bit pointers, IGNORE_BITS=0 and 2^20 arena size:
ARENA_BITS is configurable: 20 (1 MiB) by default on 64-bit, or
21 (2 MiB) when PYMALLOC_USE_HUGEPAGES is enabled. All bit widths
below are derived from ARENA_BITS automatically.
64-bit pointers, IGNORE_BITS=0 and 2^20 arena size (default):
15 -> MAP_TOP_BITS
15 -> MAP_MID_BITS
14 -> MAP_BOT_BITS
@ -520,6 +528,14 @@ struct _obmalloc_mgmt {
----
64
64-bit pointers, IGNORE_BITS=0 and 2^21 arena size (hugepages):
15 -> MAP_TOP_BITS
15 -> MAP_MID_BITS
13 -> MAP_BOT_BITS
21 -> ideal aligned arena
----
64
64-bit pointers, IGNORE_BITS=16, and 2^20 arena size:
16 -> IGNORE_BITS
10 -> MAP_TOP_BITS

View file

@ -1050,6 +1050,7 @@ enum InstructionFormat {
#define HAS_PERIODIC_FLAG (32768)
#define HAS_UNPREDICTABLE_JUMP_FLAG (65536)
#define HAS_NEEDS_GUARD_IP_FLAG (131072)
#define HAS_RECORDS_VALUE_FLAG (262144)
#define OPCODE_HAS_ARG(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_ARG_FLAG))
#define OPCODE_HAS_CONST(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_CONST_FLAG))
#define OPCODE_HAS_NAME(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NAME_FLAG))
@ -1068,6 +1069,7 @@ enum InstructionFormat {
#define OPCODE_HAS_PERIODIC(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_PERIODIC_FLAG))
#define OPCODE_HAS_UNPREDICTABLE_JUMP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_UNPREDICTABLE_JUMP_FLAG))
#define OPCODE_HAS_NEEDS_GUARD_IP(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_NEEDS_GUARD_IP_FLAG))
#define OPCODE_HAS_RECORDS_VALUE(OP) (_PyOpcode_opcode_metadata[OP].flags & (HAS_RECORDS_VALUE_FLAG))
#define OPARG_SIMPLE 0
#define OPARG_CACHE_1 1
@ -1094,12 +1096,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[BINARY_OP_ADD_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_ADD_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
[BINARY_OP_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_EXTEND] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_INPLACE_ADD_UNICODE] = { true, INSTR_FMT_IXC0000, HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_MULTIPLY_FLOAT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[BINARY_OP_MULTIPLY_INT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG },
[BINARY_OP_SUBSCR_DICT] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[BINARY_OP_SUBSCR_GETITEM] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[BINARY_OP_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_LIST_SLICE] = { true, INSTR_FMT_IXC0000, HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[BINARY_OP_SUBSCR_STR_INT] = { true, INSTR_FMT_IXC0000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
@ -1118,15 +1120,15 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[BUILD_TUPLE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG },
[CACHE] = { true, INSTR_FMT_IX, 0 },
[CALL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_ALLOC_AND_ENTER_INIT] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BOUND_METHOD_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BOUND_METHOD_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BUILTIN_CLASS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BUILTIN_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_BUILTIN_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_EX_NON_PY_GENERAL] = { true, INSTR_FMT_IXC, HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_EX_PY] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_EX_PY] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_FUNCTION_EX] = { true, INSTR_FMT_IXC, HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_INTRINSIC_1] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_INTRINSIC_2] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1138,12 +1140,12 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[CALL_LEN] = { true, INSTR_FMT_IXC00, HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_LIST_APPEND] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_FAST] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_METHOD_DESCRIPTOR_O] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_NON_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_PY_EXACT_ARGS] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_PY_GENERAL] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[CALL_STR_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_TUPLE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[CALL_TYPE_1] = { true, INSTR_FMT_IBC00, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
@ -1177,7 +1179,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[FORMAT_SIMPLE] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[FORMAT_WITH_SPEC] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[FOR_ITER] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[FOR_ITER_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[FOR_ITER_LIST] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_RANGE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_ERROR_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
[FOR_ITER_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EXIT_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG },
@ -1221,18 +1223,18 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[LIST_EXTEND] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_CLASS] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG },
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG },
[LOAD_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_METHOD_LAZY_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_METHOD_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_METHOD_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_MODULE] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_PROPERTY] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_SLOT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC00000000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[LOAD_BUILD_CLASS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[LOAD_COMMON_CONSTANT] = { true, INSTR_FMT_IB, HAS_ARG_FLAG },
[LOAD_CONST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_CONST_FLAG },
@ -1278,8 +1280,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[RESERVED] = { true, INSTR_FMT_IX, 0 },
[RESUME] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG },
[RESUME_CHECK] = { true, INSTR_FMT_IX, HAS_DEOPT_FLAG },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[RETURN_GENERATOR] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[RETURN_VALUE] = { true, INSTR_FMT_IX, HAS_ESCAPES_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[SEND] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG | HAS_SYNC_SP_FLAG | HAS_UNPREDICTABLE_JUMP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SEND_GEN] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_SYNC_SP_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[SETUP_ANNOTATIONS] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1288,8 +1290,8 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[SET_UPDATE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[STORE_ATTR] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[STORE_ATTR_INSTANCE_VALUE] = { true, INSTR_FMT_IXC000, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[STORE_ATTR_SLOT] = { true, INSTR_FMT_IXC000, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[STORE_ATTR_WITH_HINT] = { true, INSTR_FMT_IBC000, HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[STORE_DEREF] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_FREE_FLAG | HAS_ESCAPES_FLAG },
[STORE_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG },
[STORE_FAST_LOAD_FAST] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_LOCAL_FLAG | HAS_ESCAPES_FLAG },
@ -1302,7 +1304,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[STORE_SUBSCR_LIST_INT] = { true, INSTR_FMT_IXC, HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[SWAP] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_PURE_FLAG },
[TO_BOOL] = { true, INSTR_FMT_IXC00, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[TO_BOOL_ALWAYS_TRUE] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG | HAS_RECORDS_VALUE_FLAG },
[TO_BOOL_BOOL] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
[TO_BOOL_INT] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG },
[TO_BOOL_LIST] = { true, INSTR_FMT_IXC00, HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
@ -1318,7 +1320,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
[UNPACK_SEQUENCE_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[UNPACK_SEQUENCE_TWO_TUPLE] = { true, INSTR_FMT_IBC, HAS_ARG_FLAG | HAS_DEOPT_FLAG | HAS_EXIT_FLAG | HAS_ESCAPES_FLAG },
[WITH_EXCEPT_START] = { true, INSTR_FMT_IX, HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG },
[YIELD_VALUE] = { true, INSTR_FMT_IB, HAS_ARG_FLAG | HAS_NEEDS_GUARD_IP_FLAG | HAS_RECORDS_VALUE_FLAG },
[ANNOTATIONS_PLACEHOLDER] = { true, -1, HAS_PURE_FLAG },
[JUMP] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_EVAL_BREAK_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
[JUMP_IF_FALSE] = { true, -1, HAS_ARG_FLAG | HAS_JUMP_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG },
@ -1333,7 +1335,7 @@ const struct opcode_metadata _PyOpcode_opcode_metadata[267] = {
};
#endif
#define MAX_UOP_PER_EXPANSION 10
#define MAX_UOP_PER_EXPANSION 11
struct opcode_macro_expansion {
int nuops;
struct { int16_t uop; int8_t size; int8_t offset; } uops[MAX_UOP_PER_EXPANSION];
@ -1343,16 +1345,16 @@ extern const struct opcode_macro_expansion _PyOpcode_macro_expansion[256];
#ifdef NEED_OPCODE_METADATA
const struct opcode_macro_expansion
_PyOpcode_macro_expansion[256] = {
[BINARY_OP] = { .nuops = 1, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 } } },
[BINARY_OP] = { .nuops = 3, .uops = { { _BINARY_OP, OPARG_SIMPLE, 4 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[BINARY_OP_ADD_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_ADD_UNICODE] = { .nuops = 5, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_ADD_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_EXTEND] = { .nuops = 2, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 } } },
[BINARY_OP_EXTEND] = { .nuops = 4, .uops = { { _GUARD_BINARY_OP_EXTEND, 4, 1 }, { _BINARY_OP_EXTEND, 4, 1 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
[BINARY_OP_INPLACE_ADD_UNICODE] = { .nuops = 3, .uops = { { _GUARD_TOS_UNICODE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_UNICODE, OPARG_SIMPLE, 0 }, { _BINARY_OP_INPLACE_ADD_UNICODE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_FLOAT] = { .nuops = 5, .uops = { { _GUARD_TOS_FLOAT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_FLOAT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 }, { _POP_TOP_FLOAT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_MULTIPLY_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_INT, OPARG_SIMPLE, 0 }, { _BINARY_OP_MULTIPLY_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_DICT] = { .nuops = 4, .uops = { { _GUARD_NOS_DICT, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_DICT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_GETITEM] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_GETITEM] = { .nuops = 5, .uops = { { _RECORD_TOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_CHECK_FUNC, OPARG_SIMPLE, 5 }, { _BINARY_OP_SUBSCR_INIT_CALL, OPARG_SIMPLE, 5 }, { _PUSH_FRAME, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_LIST_SLICE] = { .nuops = 3, .uops = { { _GUARD_TOS_SLICE, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_LIST_SLICE, OPARG_SIMPLE, 5 } } },
[BINARY_OP_SUBSCR_STR_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_COMPACT_ASCII, OPARG_SIMPLE, 0 }, { _BINARY_OP_SUBSCR_STR_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_INT, OPARG_SIMPLE, 5 }, { _POP_TOP_UNICODE, OPARG_SIMPLE, 5 } } },
@ -1369,15 +1371,15 @@ _PyOpcode_macro_expansion[256] = {
[BUILD_STRING] = { .nuops = 1, .uops = { { _BUILD_STRING, OPARG_SIMPLE, 0 } } },
[BUILD_TEMPLATE] = { .nuops = 1, .uops = { { _BUILD_TEMPLATE, OPARG_SIMPLE, 0 } } },
[BUILD_TUPLE] = { .nuops = 1, .uops = { { _BUILD_TUPLE, OPARG_SIMPLE, 0 } } },
[CALL_ALLOC_AND_ENTER_INIT] = { .nuops = 4, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_AND_ALLOCATE_OBJECT, 2, 1 }, { _CREATE_INIT_FRAME, OPARG_SIMPLE, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 10, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BOUND_METHOD_GENERAL] = { .nuops = 7, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BUILTIN_CLASS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_O] = { .nuops = 4, .uops = { { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_ALLOC_AND_ENTER_INIT] = { .nuops = 5, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_AND_ALLOCATE_OBJECT, 2, 1 }, { _CREATE_INIT_FRAME, OPARG_SIMPLE, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BOUND_METHOD_EXACT_ARGS] = { .nuops = 11, .uops = { { _RECORD_BOUND_METHOD, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _INIT_CALL_BOUND_METHOD_EXACT_ARGS, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BOUND_METHOD_GENERAL] = { .nuops = 8, .uops = { { _RECORD_BOUND_METHOD, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_METHOD_VERSION, 2, 1 }, { _EXPAND_METHOD, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_BUILTIN_CLASS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_CLASS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_FAST_WITH_KEYWORDS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_BUILTIN_O] = { .nuops = 5, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_BUILTIN_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_EX_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _CHECK_IS_NOT_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CALL_FUNCTION_EX_NON_PY_GENERAL, OPARG_SIMPLE, 1 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 1 } } },
[CALL_EX_PY] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CHECK_IS_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _PY_FRAME_EX, OPARG_SIMPLE, 1 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[CALL_EX_PY] = { .nuops = 7, .uops = { { _RECORD_4OS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _MAKE_CALLARGS_A_TUPLE, OPARG_SIMPLE, 1 }, { _CHECK_IS_PY_CALLABLE_EX, OPARG_SIMPLE, 1 }, { _PY_FRAME_EX, OPARG_SIMPLE, 1 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[CALL_INTRINSIC_1] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_1, OPARG_SIMPLE, 0 } } },
[CALL_INTRINSIC_2] = { .nuops = 1, .uops = { { _CALL_INTRINSIC_2, OPARG_SIMPLE, 0 } } },
[CALL_ISINSTANCE] = { .nuops = 3, .uops = { { _GUARD_THIRD_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_ISINSTANCE, OPARG_SIMPLE, 3 }, { _CALL_ISINSTANCE, OPARG_SIMPLE, 3 } } },
@ -1387,12 +1389,12 @@ _PyOpcode_macro_expansion[256] = {
[CALL_LEN] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_LEN, OPARG_SIMPLE, 3 }, { _CALL_LEN, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[CALL_LIST_APPEND] = { .nuops = 6, .uops = { { _GUARD_CALLABLE_LIST_APPEND, OPARG_SIMPLE, 3 }, { _GUARD_NOS_NOT_NULL, OPARG_SIMPLE, 3 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 3 }, { _CALL_LIST_APPEND, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 2, .uops = { { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_O] = { .nuops = 5, .uops = { { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_NON_PY_GENERAL] = { .nuops = 3, .uops = { { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_PY_EXACT_ARGS] = { .nuops = 8, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_PY_GENERAL] = { .nuops = 6, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_FAST_WITH_KEYWORDS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_NOARGS] = { .nuops = 3, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_NOARGS, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_METHOD_DESCRIPTOR_O] = { .nuops = 6, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CALL_METHOD_DESCRIPTOR_O, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_NON_PY_GENERAL] = { .nuops = 4, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_IS_NOT_PY_CALLABLE, OPARG_SIMPLE, 3 }, { _CALL_NON_PY_GENERAL, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_PY_EXACT_ARGS] = { .nuops = 9, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_FUNCTION_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _CHECK_STACK_SPACE, OPARG_SIMPLE, 3 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _INIT_CALL_PY_EXACT_ARGS, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_PY_GENERAL] = { .nuops = 7, .uops = { { _RECORD_CALLABLE, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _CHECK_FUNCTION_VERSION, 2, 1 }, { _CHECK_RECURSION_REMAINING, OPARG_SIMPLE, 3 }, { _PY_FRAME_GENERAL, OPARG_SIMPLE, 3 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 3 }, { _PUSH_FRAME, OPARG_SIMPLE, 3 } } },
[CALL_STR_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_STR_1, OPARG_SIMPLE, 3 }, { _CALL_STR_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_TUPLE_1] = { .nuops = 5, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TUPLE_1, OPARG_SIMPLE, 3 }, { _CALL_TUPLE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 }, { _CHECK_PERIODIC_AT_END, OPARG_REPLACED, 3 } } },
[CALL_TYPE_1] = { .nuops = 4, .uops = { { _GUARD_NOS_NULL, OPARG_SIMPLE, 3 }, { _GUARD_CALLABLE_TYPE_1, OPARG_SIMPLE, 3 }, { _CALL_TYPE_1, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
@ -1422,7 +1424,7 @@ _PyOpcode_macro_expansion[256] = {
[FORMAT_SIMPLE] = { .nuops = 1, .uops = { { _FORMAT_SIMPLE, OPARG_SIMPLE, 0 } } },
[FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { _FORMAT_WITH_SPEC, OPARG_SIMPLE, 0 } } },
[FOR_ITER] = { .nuops = 1, .uops = { { _FOR_ITER, OPARG_REPLACED, 0 } } },
[FOR_ITER_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[FOR_ITER_GEN] = { .nuops = 4, .uops = { { _RECORD_NOS, OPARG_SIMPLE, 0 }, { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _FOR_ITER_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[FOR_ITER_LIST] = { .nuops = 3, .uops = { { _ITER_CHECK_LIST, OPARG_SIMPLE, 1 }, { _ITER_JUMP_LIST, OPARG_REPLACED, 1 }, { _ITER_NEXT_LIST, OPARG_REPLACED, 1 } } },
[FOR_ITER_RANGE] = { .nuops = 3, .uops = { { _ITER_CHECK_RANGE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_RANGE, OPARG_REPLACED, 1 }, { _ITER_NEXT_RANGE, OPARG_SIMPLE, 1 } } },
[FOR_ITER_TUPLE] = { .nuops = 3, .uops = { { _ITER_CHECK_TUPLE, OPARG_SIMPLE, 1 }, { _ITER_JUMP_TUPLE, OPARG_REPLACED, 1 }, { _ITER_NEXT_TUPLE, OPARG_SIMPLE, 1 } } },
@ -1442,17 +1444,17 @@ _PyOpcode_macro_expansion[256] = {
[LIST_EXTEND] = { .nuops = 1, .uops = { { _LIST_EXTEND, OPARG_SIMPLE, 0 } } },
[LOAD_ATTR] = { .nuops = 1, .uops = { { _LOAD_ATTR, OPARG_SIMPLE, 8 } } },
[LOAD_ATTR_CLASS] = { .nuops = 3, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 4, .uops = { { _CHECK_ATTR_CLASS, 2, 1 }, { _GUARD_TYPE_VERSION, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 5, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_MODULE] = { .nuops = 3, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 2, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } },
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_PROPERTY] = { .nuops = 5, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_SLOT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_CLASS_WITH_METACLASS_CHECK] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_CLASS, 2, 3 }, { _LOAD_ATTR_CLASS, 4, 5 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_INSTANCE_VALUE] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_MANAGED_OBJECT_HAS_VALUES, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_METHOD_LAZY_DICT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_ATTR_METHOD_LAZY_DICT, 1, 3 }, { _LOAD_ATTR_METHOD_LAZY_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_METHOD_NO_DICT, 4, 5 } } },
[LOAD_ATTR_METHOD_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_METHOD_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_MODULE] = { .nuops = 4, .uops = { { _LOAD_ATTR_MODULE, 2, 1 }, { _LOAD_ATTR_MODULE, OPERAND1_1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = { .nuops = 3, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_NONDESCRIPTOR_NO_DICT, 4, 5 } } },
[LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _GUARD_DORV_VALUES_INST_ATTR_FROM_DICT, OPARG_SIMPLE, 3 }, { _GUARD_KEYS_VERSION, 2, 3 }, { _LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES, 4, 5 } } },
[LOAD_ATTR_PROPERTY] = { .nuops = 6, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _CHECK_PEP_523, OPARG_SIMPLE, 3 }, { _LOAD_ATTR_PROPERTY_FRAME, 4, 5 }, { _SAVE_RETURN_OFFSET, OPARG_SAVE_RETURN_OFFSET, 9 }, { _PUSH_FRAME, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_SLOT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_ATTR_WITH_HINT] = { .nuops = 5, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _LOAD_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 }, { _PUSH_NULL_CONDITIONAL, OPARG_SIMPLE, 9 } } },
[LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { _LOAD_BUILD_CLASS, OPARG_SIMPLE, 0 } } },
[LOAD_COMMON_CONSTANT] = { .nuops = 1, .uops = { { _LOAD_COMMON_CONSTANT, OPARG_SIMPLE, 0 } } },
[LOAD_CONST] = { .nuops = 1, .uops = { { _LOAD_CONST, OPARG_SIMPLE, 0 } } },
@ -1492,8 +1494,8 @@ _PyOpcode_macro_expansion[256] = {
[PUSH_EXC_INFO] = { .nuops = 1, .uops = { { _PUSH_EXC_INFO, OPARG_SIMPLE, 0 } } },
[PUSH_NULL] = { .nuops = 1, .uops = { { _PUSH_NULL, OPARG_SIMPLE, 0 } } },
[RESUME_CHECK] = { .nuops = 1, .uops = { { _RESUME_CHECK, OPARG_SIMPLE, 0 } } },
[RETURN_GENERATOR] = { .nuops = 1, .uops = { { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
[RETURN_VALUE] = { .nuops = 1, .uops = { { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
[RETURN_GENERATOR] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_GENERATOR, OPARG_SIMPLE, 0 } } },
[RETURN_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _RETURN_VALUE, OPARG_SIMPLE, 0 } } },
[SEND_GEN] = { .nuops = 3, .uops = { { _CHECK_PEP_523, OPARG_SIMPLE, 1 }, { _SEND_GEN_FRAME, OPARG_SIMPLE, 1 }, { _PUSH_FRAME, OPARG_SIMPLE, 1 } } },
[SETUP_ANNOTATIONS] = { .nuops = 1, .uops = { { _SETUP_ANNOTATIONS, OPARG_SIMPLE, 0 } } },
[SET_ADD] = { .nuops = 1, .uops = { { _SET_ADD, OPARG_SIMPLE, 0 } } },
@ -1501,8 +1503,8 @@ _PyOpcode_macro_expansion[256] = {
[SET_UPDATE] = { .nuops = 1, .uops = { { _SET_UPDATE, OPARG_SIMPLE, 0 } } },
[STORE_ATTR] = { .nuops = 1, .uops = { { _STORE_ATTR, OPARG_SIMPLE, 3 } } },
[STORE_ATTR_INSTANCE_VALUE] = { .nuops = 4, .uops = { { _GUARD_TYPE_VERSION_AND_LOCK, 2, 1 }, { _GUARD_DORV_NO_DICT, OPARG_SIMPLE, 3 }, { _STORE_ATTR_INSTANCE_VALUE, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_SLOT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_WITH_HINT] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_SLOT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_SLOT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_ATTR_WITH_HINT] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _STORE_ATTR_WITH_HINT, 1, 3 }, { _POP_TOP, OPARG_SIMPLE, 4 } } },
[STORE_DEREF] = { .nuops = 1, .uops = { { _STORE_DEREF, OPARG_SIMPLE, 0 } } },
[STORE_FAST] = { .nuops = 2, .uops = { { _SWAP_FAST, OPARG_SIMPLE, 0 }, { _POP_TOP, OPARG_SIMPLE, 0 } } },
[STORE_FAST_LOAD_FAST] = { .nuops = 3, .uops = { { _SWAP_FAST, OPARG_TOP, 0 }, { _POP_TOP, OPARG_TOP, 0 }, { _LOAD_FAST, OPARG_BOTTOM, 0 } } },
@ -1515,7 +1517,7 @@ _PyOpcode_macro_expansion[256] = {
[STORE_SUBSCR_LIST_INT] = { .nuops = 5, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _GUARD_NOS_LIST, OPARG_SIMPLE, 0 }, { _STORE_SUBSCR_LIST_INT, OPARG_SIMPLE, 1 }, { _POP_TOP_INT, OPARG_SIMPLE, 1 }, { _POP_TOP, OPARG_SIMPLE, 1 } } },
[SWAP] = { .nuops = 1, .uops = { { _SWAP, OPARG_SIMPLE, 0 } } },
[TO_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL, OPARG_SIMPLE, 2 } } },
[TO_BOOL_ALWAYS_TRUE] = { .nuops = 3, .uops = { { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[TO_BOOL_ALWAYS_TRUE] = { .nuops = 4, .uops = { { _RECORD_TOS_TYPE, OPARG_SIMPLE, 1 }, { _GUARD_TYPE_VERSION, 2, 1 }, { _REPLACE_WITH_TRUE, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
[TO_BOOL_BOOL] = { .nuops = 1, .uops = { { _TO_BOOL_BOOL, OPARG_SIMPLE, 3 } } },
[TO_BOOL_INT] = { .nuops = 3, .uops = { { _GUARD_TOS_INT, OPARG_SIMPLE, 0 }, { _TO_BOOL_INT, OPARG_SIMPLE, 3 }, { _POP_TOP_INT, OPARG_SIMPLE, 3 } } },
[TO_BOOL_LIST] = { .nuops = 3, .uops = { { _GUARD_TOS_LIST, OPARG_SIMPLE, 0 }, { _TO_BOOL_LIST, OPARG_SIMPLE, 3 }, { _POP_TOP, OPARG_SIMPLE, 3 } } },
@ -1530,7 +1532,7 @@ _PyOpcode_macro_expansion[256] = {
[UNPACK_SEQUENCE_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TUPLE, OPARG_SIMPLE, 1 } } },
[UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 2, .uops = { { _GUARD_TOS_TUPLE, OPARG_SIMPLE, 0 }, { _UNPACK_SEQUENCE_TWO_TUPLE, OPARG_SIMPLE, 1 } } },
[WITH_EXCEPT_START] = { .nuops = 1, .uops = { { _WITH_EXCEPT_START, OPARG_SIMPLE, 0 } } },
[YIELD_VALUE] = { .nuops = 1, .uops = { { _YIELD_VALUE, OPARG_SIMPLE, 0 } } },
[YIELD_VALUE] = { .nuops = 2, .uops = { { _RECORD_CALLER_CODE, OPARG_SIMPLE, 0 }, { _YIELD_VALUE, OPARG_SIMPLE, 0 } } },
};
#endif // NEED_OPCODE_METADATA

View file

@ -16,12 +16,103 @@ extern "C" {
#include <stdbool.h>
typedef struct _PyJitUopBuffer {
_PyUOpInstruction *start;
_PyUOpInstruction *next;
_PyUOpInstruction *end;
} _PyJitUopBuffer;
typedef struct _JitOptContext {
char done;
char out_of_space;
bool contradiction;
// Has the builtins dict been watched?
bool builtins_watched;
// The current "executing" frame.
_Py_UOpsAbstractFrame *frame;
_Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH];
int curr_frame_depth;
// Arena for the symbolic types.
ty_arena t_arena;
JitOptRef *n_consumed;
JitOptRef *limit;
JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
_PyJitUopBuffer out_buffer;
} JitOptContext;
static inline void
uop_buffer_init(_PyJitUopBuffer *trace, _PyUOpInstruction *start, uint32_t size)
{
trace->next = trace->start = start;
trace->end = start + size;
}
static inline _PyUOpInstruction *
uop_buffer_last(_PyJitUopBuffer *trace)
{
assert(trace->next > trace->start);
return trace->next-1;
}
static inline int
uop_buffer_length(_PyJitUopBuffer *trace)
{
return (int)(trace->next - trace->start);
}
static inline int
uop_buffer_remaining_space(_PyJitUopBuffer *trace)
{
return (int)(trace->end - trace->next);
}
typedef struct _PyJitTracerInitialState {
int stack_depth;
int chain_depth;
struct _PyExitData *exit;
PyCodeObject *code; // Strong
PyFunctionObject *func; // Strong
struct _PyExecutorObject *executor; // Strong
_Py_CODEUNIT *start_instr;
_Py_CODEUNIT *close_loop_instr;
_Py_CODEUNIT *jump_backward_instr;
} _PyJitTracerInitialState;
typedef struct _PyJitTracerPreviousState {
bool dependencies_still_valid;
int instr_oparg;
int instr_stacklevel;
_Py_CODEUNIT *instr;
PyCodeObject *instr_code; // Strong
struct _PyInterpreterFrame *instr_frame;
_PyBloomFilter dependencies;
PyObject *recorded_value; // Strong, may be NULL
} _PyJitTracerPreviousState;
typedef struct _PyJitTracerTranslatorState {
int jump_backward_seen;
} _PyJitTracerTranslatorState;
typedef struct _PyJitTracerState {
bool is_tracing;
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
_PyJitTracerTranslatorState translator_state;
JitOptContext opt_context;
_PyJitUopBuffer code_buffer;
_PyJitUopBuffer out_buffer;
_PyUOpInstruction uop_array[2 * UOP_MAX_TRACE_LENGTH];
} _PyJitTracerState;
typedef struct _PyExecutorLinkListNode {
struct _PyExecutorObject *next;
struct _PyExecutorObject *previous;
} _PyExecutorLinkListNode;
typedef struct {
uint8_t opcode;
uint8_t oparg;
@ -86,8 +177,8 @@ PyAPI_FUNC(void) _Py_Executors_InvalidateCold(PyInterpreterState *interp);
int _Py_uop_analyze_and_optimize(
_PyThreadStateImpl *tstate,
_PyUOpInstruction *trace, int trace_len, int curr_stackentries,
_PyBloomFilter *dependencies);
_PyUOpInstruction *input, int trace_len, int curr_stackentries,
_PyUOpInstruction *output, _PyBloomFilter *dependencies);
extern PyTypeObject _PyUOpExecutor_Type;
@ -205,6 +296,8 @@ extern JitOptRef _Py_uop_sym_new_truthiness(JitOptContext *ctx, JitOptRef value,
extern bool _Py_uop_sym_is_compact_int(JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_compact_int(JitOptContext *ctx);
extern void _Py_uop_sym_set_compact_int(JitOptContext *ctx, JitOptRef sym);
extern JitOptRef _Py_uop_sym_new_predicate(JitOptContext *ctx, JitOptRef lhs_ref, JitOptRef rhs_ref, JitOptPredicateKind kind);
extern void _Py_uop_sym_apply_predicate_narrowing(JitOptContext *ctx, JitOptRef sym, bool branch_is_true);
extern void _Py_uop_abstractcontext_init(JitOptContext *ctx);
extern void _Py_uop_abstractcontext_fini(JitOptContext *ctx);
@ -244,7 +337,7 @@ PyAPI_FUNC(int) _PyJit_translate_single_bytecode_to_trace(PyThreadState *tstate,
PyAPI_FUNC(int)
_PyJit_TryInitializeTracing(PyThreadState *tstate, _PyInterpreterFrame *frame,
_Py_CODEUNIT *curr_instr, _Py_CODEUNIT *start_instr,
_Py_CODEUNIT *close_loop_instr, int curr_stackdepth, int chain_depth, _PyExitData *exit,
_Py_CODEUNIT *close_loop_instr, _PyStackRef *stack_pointer, int chain_depth, _PyExitData *exit,
int oparg, _PyExecutorObject *current_executor);
PyAPI_FUNC(void) _PyJit_FinalizeTracing(PyThreadState *tstate, int err);
@ -252,6 +345,12 @@ void _PyJit_TracerFree(_PyThreadStateImpl *_tstate);
void _PyJit_Tracer_InvalidateDependency(PyThreadState *old_tstate, void *obj);
#ifdef _Py_TIER2
typedef void (*_Py_RecordFuncPtr)(_PyInterpreterFrame *frame, _PyStackRef *stackpointer, int oparg, PyObject **recorded_value);
PyAPI_DATA(const _Py_RecordFuncPtr) _PyOpcode_RecordFunctions[];
PyAPI_DATA(const uint8_t) _PyOpcode_RecordFunctionIndices[256];
#endif
#ifdef __cplusplus
}
#endif

View file

@ -40,6 +40,7 @@ typedef enum _JitSymType {
JIT_SYM_TUPLE_TAG = 8,
JIT_SYM_TRUTHINESS_TAG = 9,
JIT_SYM_COMPACT_INT = 10,
JIT_SYM_PREDICATE_TAG = 11,
} JitSymType;
typedef struct _jit_opt_known_class {
@ -72,6 +73,20 @@ typedef struct {
uint16_t value;
} JitOptTruthiness;
typedef enum {
JIT_PRED_IS,
JIT_PRED_IS_NOT,
JIT_PRED_EQ,
JIT_PRED_NE,
} JitOptPredicateKind;
typedef struct {
uint8_t tag;
uint8_t kind;
uint16_t lhs;
uint16_t rhs;
} JitOptPredicate;
typedef struct {
uint8_t tag;
} JitOptCompactInt;
@ -84,6 +99,7 @@ typedef union _jit_opt_symbol {
JitOptTuple tuple;
JitOptTruthiness truthiness;
JitOptCompactInt compact;
JitOptPredicate predicate;
} JitOptSymbol;
// This mimics the _PyStackRef API
@ -112,27 +128,6 @@ typedef struct ty_arena {
JitOptSymbol arena[TY_ARENA_SIZE];
} ty_arena;
typedef struct _JitOptContext {
char done;
char out_of_space;
bool contradiction;
// Has the builtins dict been watched?
bool builtins_watched;
// The current "executing" frame.
_Py_UOpsAbstractFrame *frame;
_Py_UOpsAbstractFrame frames[MAX_ABSTRACT_FRAME_DEPTH];
int curr_frame_depth;
// Arena for the symbolic types.
ty_arena t_arena;
JitOptRef *n_consumed;
JitOptRef *limit;
JitOptRef locals_and_stack[MAX_ABSTRACT_INTERP_SIZE];
_PyUOpInstruction *out_buffer;
int out_len;
} JitOptContext;
#ifdef __cplusplus
}

View file

@ -1795,6 +1795,7 @@ extern "C" {
INIT_ID(ident), \
INIT_ID(identity_hint), \
INIT_ID(ignore), \
INIT_ID(ignorechars), \
INIT_ID(imag), \
INIT_ID(implieslink), \
INIT_ID(importlib), \

View file

@ -31,6 +31,7 @@ struct _pymem_allocators {
debug_alloc_api_t obj;
} debug;
int is_debug_enabled;
int use_hugepages;
PyObjectArenaAllocator obj_arena;
};

View file

@ -12,7 +12,6 @@ extern "C" {
#include "pycore_freelist_state.h" // struct _Py_freelists
#include "pycore_interpframe_structs.h" // _PyInterpreterFrame
#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
#include "pycore_optimizer_types.h" // JitOptContext
#include "pycore_qsbr.h" // struct qsbr
#include "pycore_uop.h" // struct _PyUOpInstruction
#include "pycore_structs.h"
@ -24,46 +23,6 @@ struct _gc_thread_state {
};
#endif
#if _Py_TIER2
typedef struct _PyJitTracerInitialState {
int stack_depth;
int chain_depth;
struct _PyExitData *exit;
PyCodeObject *code; // Strong
PyFunctionObject *func; // Strong
struct _PyExecutorObject *executor; // Strong
_Py_CODEUNIT *start_instr;
_Py_CODEUNIT *close_loop_instr;
_Py_CODEUNIT *jump_backward_instr;
} _PyJitTracerInitialState;
typedef struct _PyJitTracerPreviousState {
bool dependencies_still_valid;
int code_max_size;
int code_curr_size;
int instr_oparg;
int instr_stacklevel;
_Py_CODEUNIT *instr;
PyCodeObject *instr_code; // Strong
struct _PyInterpreterFrame *instr_frame;
_PyBloomFilter dependencies;
} _PyJitTracerPreviousState;
typedef struct _PyJitTracerTranslatorState {
int jump_backward_seen;
} _PyJitTracerTranslatorState;
typedef struct _PyJitTracerState {
bool is_tracing;
_PyJitTracerInitialState initial_state;
_PyJitTracerPreviousState prev_state;
_PyJitTracerTranslatorState translator_state;
JitOptContext opt_context;
_PyUOpInstruction code_buffer[UOP_MAX_TRACE_LENGTH];
_PyUOpInstruction out_buffer[UOP_MAX_TRACE_LENGTH];
} _PyJitTracerState;
#endif
// Every PyThreadState is actually allocated as a _PyThreadStateImpl. The
// PyThreadState fields are exposed as part of the C API, although most fields
@ -141,7 +100,7 @@ typedef struct _PyThreadStateImpl {
Py_ssize_t reftotal; // this thread's total refcount operations
#endif
#if _Py_TIER2
_PyJitTracerState *jit_tracer_state;
struct _PyJitTracerState *jit_tracer_state;
#endif
} _PyThreadStateImpl;

View file

@ -1860,6 +1860,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(ignorechars);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));
assert(PyUnicode_GET_LENGTH(string) != 1);
string = &_Py_ID(imag);
_PyUnicode_InternStatic(interp, &string);
assert(_PyUnicode_CheckConsistency(string, 1));

View file

@ -38,11 +38,10 @@ typedef struct _PyUOpInstruction{
// This is the length of the trace we translate initially.
#ifdef Py_DEBUG
// With asserts, the stencils are a lot larger
#define UOP_MAX_TRACE_LENGTH 2000
#define UOP_MAX_TRACE_LENGTH 1000
#else
#define UOP_MAX_TRACE_LENGTH 5000
#define UOP_MAX_TRACE_LENGTH 2500
#endif
#define UOP_BUFFER_SIZE (UOP_MAX_TRACE_LENGTH * sizeof(_PyUOpInstruction))
/* Bloom filter with m = 256
* https://en.wikipedia.org/wiki/Bloom_filter */

File diff suppressed because it is too large Load diff

View file

@ -115,7 +115,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_BINARY_OP_ADD_UNICODE] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_PURE_FLAG,
[_BINARY_OP_INPLACE_ADD_UNICODE] = HAS_LOCAL_FLAG | HAS_DEOPT_FLAG | HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_GUARD_BINARY_OP_EXTEND] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_OP_EXTEND] = HAS_ESCAPES_FLAG,
[_BINARY_OP_EXTEND] = HAS_ERROR_FLAG | HAS_ERROR_NO_POP_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_STORE_SLICE] = HAS_ERROR_FLAG | HAS_ESCAPES_FLAG,
[_BINARY_OP_SUBSCR_LIST_INT] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
@ -193,7 +193,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GUARD_TYPE_VERSION_AND_LOCK] = HAS_EXIT_FLAG,
[_CHECK_MANAGED_OBJECT_HAS_VALUES] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_INSTANCE_VALUE] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG | HAS_ESCAPES_FLAG,
[_LOAD_ATTR_MODULE] = HAS_DEOPT_FLAG,
[_LOAD_ATTR_WITH_HINT] = HAS_ARG_FLAG | HAS_NAME_FLAG | HAS_DEOPT_FLAG,
[_LOAD_ATTR_SLOT] = HAS_DEOPT_FLAG,
[_CHECK_ATTR_CLASS] = HAS_EXIT_FLAG,
@ -323,6 +323,16 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_SWAP] = HAS_ARG_FLAG | HAS_PURE_FLAG,
[_GUARD_IS_TRUE_POP] = HAS_EXIT_FLAG,
[_GUARD_IS_FALSE_POP] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_SET_POP_4] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_SET_POP_5] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_SET_POP_6] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_SET_POP_7] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_SET_POP] = HAS_ARG_FLAG | HAS_EXIT_FLAG,
[_GUARD_BIT_IS_UNSET_POP_4] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_UNSET_POP_5] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_UNSET_POP_6] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_UNSET_POP_7] = HAS_EXIT_FLAG,
[_GUARD_BIT_IS_UNSET_POP] = HAS_ARG_FLAG | HAS_EXIT_FLAG,
[_GUARD_IS_NONE_POP] = HAS_EXIT_FLAG,
[_GUARD_IS_NOT_NONE_POP] = HAS_EXIT_FLAG | HAS_ESCAPES_FLAG,
[_JUMP_TO_TOP] = 0,
@ -342,6 +352,7 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_POP_TWO_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG,
[_POP_CALL_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG,
[_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW] = HAS_ESCAPES_FLAG,
[_INSERT_1_LOAD_CONST_INLINE] = 0,
[_INSERT_1_LOAD_CONST_INLINE_BORROW] = 0,
[_INSERT_2_LOAD_CONST_INLINE_BORROW] = 0,
[_SHUFFLE_2_LOAD_CONST_INLINE_BORROW] = 0,
@ -363,6 +374,13 @@ const uint32_t _PyUop_Flags[MAX_UOP_ID+1] = {
[_GUARD_IP_YIELD_VALUE] = HAS_EXIT_FLAG,
[_GUARD_IP_RETURN_VALUE] = HAS_EXIT_FLAG,
[_GUARD_IP_RETURN_GENERATOR] = HAS_EXIT_FLAG,
[_RECORD_TOS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_TOS_TYPE] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_NOS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_4OS] = HAS_RECORDS_VALUE_FLAG,
[_RECORD_CALLABLE] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
[_RECORD_BOUND_METHOD] = HAS_ARG_FLAG | HAS_RECORDS_VALUE_FLAG,
[_RECORD_CALLER_CODE] = HAS_RECORDS_VALUE_FLAG,
};
const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = {
@ -373,6 +391,8 @@ const ReplicationRange _PyUop_Replication[MAX_UOP_ID+1] = {
[_INIT_CALL_PY_EXACT_ARGS] = { 0, 5 },
[_COPY] = { 1, 4 },
[_SWAP] = { 2, 4 },
[_GUARD_BIT_IS_SET_POP] = { 4, 8 },
[_GUARD_BIT_IS_UNSET_POP] = { 4, 8 },
};
const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
@ -1101,7 +1121,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
.entries = {
{ -1, -1, -1 },
{ -1, -1, -1 },
{ 1, 2, _BINARY_OP_EXTEND_r21 },
{ 3, 2, _BINARY_OP_EXTEND_r23 },
{ -1, -1, -1 },
},
},
@ -1802,7 +1822,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
.best = { 1, 1, 1, 1 },
.entries = {
{ -1, -1, -1 },
{ 1, 1, _LOAD_ATTR_MODULE_r11 },
{ 2, 1, _LOAD_ATTR_MODULE_r12 },
{ -1, -1, -1 },
{ -1, -1, -1 },
},
@ -2919,7 +2939,7 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
.entries = {
{ -1, -1, -1 },
{ -1, -1, -1 },
{ 1, 2, _BINARY_OP_r21 },
{ 3, 2, _BINARY_OP_r23 },
{ -1, -1, -1 },
},
},
@ -2968,6 +2988,96 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ 2, 2, _GUARD_IS_FALSE_POP_r32 },
},
},
[_GUARD_BIT_IS_SET_POP_4] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_SET_POP_4_r00 },
{ 0, 0, _GUARD_BIT_IS_SET_POP_4_r10 },
{ 1, 1, _GUARD_BIT_IS_SET_POP_4_r21 },
{ 2, 2, _GUARD_BIT_IS_SET_POP_4_r32 },
},
},
[_GUARD_BIT_IS_SET_POP_5] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_SET_POP_5_r00 },
{ 0, 0, _GUARD_BIT_IS_SET_POP_5_r10 },
{ 1, 1, _GUARD_BIT_IS_SET_POP_5_r21 },
{ 2, 2, _GUARD_BIT_IS_SET_POP_5_r32 },
},
},
[_GUARD_BIT_IS_SET_POP_6] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_SET_POP_6_r00 },
{ 0, 0, _GUARD_BIT_IS_SET_POP_6_r10 },
{ 1, 1, _GUARD_BIT_IS_SET_POP_6_r21 },
{ 2, 2, _GUARD_BIT_IS_SET_POP_6_r32 },
},
},
[_GUARD_BIT_IS_SET_POP_7] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_SET_POP_7_r00 },
{ 0, 0, _GUARD_BIT_IS_SET_POP_7_r10 },
{ 1, 1, _GUARD_BIT_IS_SET_POP_7_r21 },
{ 2, 2, _GUARD_BIT_IS_SET_POP_7_r32 },
},
},
[_GUARD_BIT_IS_SET_POP] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_SET_POP_r00 },
{ 0, 0, _GUARD_BIT_IS_SET_POP_r10 },
{ 1, 1, _GUARD_BIT_IS_SET_POP_r21 },
{ 2, 2, _GUARD_BIT_IS_SET_POP_r32 },
},
},
[_GUARD_BIT_IS_UNSET_POP_4] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_4_r00 },
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_4_r10 },
{ 1, 1, _GUARD_BIT_IS_UNSET_POP_4_r21 },
{ 2, 2, _GUARD_BIT_IS_UNSET_POP_4_r32 },
},
},
[_GUARD_BIT_IS_UNSET_POP_5] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_5_r00 },
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_5_r10 },
{ 1, 1, _GUARD_BIT_IS_UNSET_POP_5_r21 },
{ 2, 2, _GUARD_BIT_IS_UNSET_POP_5_r32 },
},
},
[_GUARD_BIT_IS_UNSET_POP_6] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_6_r00 },
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_6_r10 },
{ 1, 1, _GUARD_BIT_IS_UNSET_POP_6_r21 },
{ 2, 2, _GUARD_BIT_IS_UNSET_POP_6_r32 },
},
},
[_GUARD_BIT_IS_UNSET_POP_7] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_7_r00 },
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_7_r10 },
{ 1, 1, _GUARD_BIT_IS_UNSET_POP_7_r21 },
{ 2, 2, _GUARD_BIT_IS_UNSET_POP_7_r32 },
},
},
[_GUARD_BIT_IS_UNSET_POP] = {
.best = { 0, 1, 2, 3 },
.entries = {
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_r00 },
{ 0, 0, _GUARD_BIT_IS_UNSET_POP_r10 },
{ 1, 1, _GUARD_BIT_IS_UNSET_POP_r21 },
{ 2, 2, _GUARD_BIT_IS_UNSET_POP_r32 },
},
},
[_GUARD_IS_NONE_POP] = {
.best = { 0, 1, 2, 3 },
.entries = {
@ -3139,6 +3249,15 @@ const _PyUopCachingInfo _PyUop_Caching[MAX_UOP_ID+1] = {
{ 1, 3, _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31 },
},
},
[_INSERT_1_LOAD_CONST_INLINE] = {
.best = { 0, 1, 2, 2 },
.entries = {
{ 2, 0, _INSERT_1_LOAD_CONST_INLINE_r02 },
{ 2, 1, _INSERT_1_LOAD_CONST_INLINE_r12 },
{ 3, 2, _INSERT_1_LOAD_CONST_INLINE_r23 },
{ -1, -1, -1 },
},
},
[_INSERT_1_LOAD_CONST_INLINE_BORROW] = {
.best = { 0, 1, 2, 2 },
.entries = {
@ -3568,7 +3687,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_BINARY_OP_ADD_UNICODE_r23] = _BINARY_OP_ADD_UNICODE,
[_BINARY_OP_INPLACE_ADD_UNICODE_r21] = _BINARY_OP_INPLACE_ADD_UNICODE,
[_GUARD_BINARY_OP_EXTEND_r22] = _GUARD_BINARY_OP_EXTEND,
[_BINARY_OP_EXTEND_r21] = _BINARY_OP_EXTEND,
[_BINARY_OP_EXTEND_r23] = _BINARY_OP_EXTEND,
[_BINARY_SLICE_r31] = _BINARY_SLICE,
[_STORE_SLICE_r30] = _STORE_SLICE,
[_BINARY_OP_SUBSCR_LIST_INT_r23] = _BINARY_OP_SUBSCR_LIST_INT,
@ -3687,7 +3806,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_LOAD_ATTR_INSTANCE_VALUE_r02] = _LOAD_ATTR_INSTANCE_VALUE,
[_LOAD_ATTR_INSTANCE_VALUE_r12] = _LOAD_ATTR_INSTANCE_VALUE,
[_LOAD_ATTR_INSTANCE_VALUE_r23] = _LOAD_ATTR_INSTANCE_VALUE,
[_LOAD_ATTR_MODULE_r11] = _LOAD_ATTR_MODULE,
[_LOAD_ATTR_MODULE_r12] = _LOAD_ATTR_MODULE,
[_LOAD_ATTR_WITH_HINT_r12] = _LOAD_ATTR_WITH_HINT,
[_LOAD_ATTR_SLOT_r02] = _LOAD_ATTR_SLOT,
[_LOAD_ATTR_SLOT_r12] = _LOAD_ATTR_SLOT,
@ -3929,7 +4048,7 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_COPY_3_r23] = _COPY_3,
[_COPY_3_r33] = _COPY_3,
[_COPY_r01] = _COPY,
[_BINARY_OP_r21] = _BINARY_OP,
[_BINARY_OP_r23] = _BINARY_OP,
[_SWAP_2_r02] = _SWAP_2,
[_SWAP_2_r12] = _SWAP_2,
[_SWAP_2_r22] = _SWAP_2,
@ -3947,6 +4066,46 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_GUARD_IS_FALSE_POP_r10] = _GUARD_IS_FALSE_POP,
[_GUARD_IS_FALSE_POP_r21] = _GUARD_IS_FALSE_POP,
[_GUARD_IS_FALSE_POP_r32] = _GUARD_IS_FALSE_POP,
[_GUARD_BIT_IS_SET_POP_4_r00] = _GUARD_BIT_IS_SET_POP_4,
[_GUARD_BIT_IS_SET_POP_4_r10] = _GUARD_BIT_IS_SET_POP_4,
[_GUARD_BIT_IS_SET_POP_4_r21] = _GUARD_BIT_IS_SET_POP_4,
[_GUARD_BIT_IS_SET_POP_4_r32] = _GUARD_BIT_IS_SET_POP_4,
[_GUARD_BIT_IS_SET_POP_5_r00] = _GUARD_BIT_IS_SET_POP_5,
[_GUARD_BIT_IS_SET_POP_5_r10] = _GUARD_BIT_IS_SET_POP_5,
[_GUARD_BIT_IS_SET_POP_5_r21] = _GUARD_BIT_IS_SET_POP_5,
[_GUARD_BIT_IS_SET_POP_5_r32] = _GUARD_BIT_IS_SET_POP_5,
[_GUARD_BIT_IS_SET_POP_6_r00] = _GUARD_BIT_IS_SET_POP_6,
[_GUARD_BIT_IS_SET_POP_6_r10] = _GUARD_BIT_IS_SET_POP_6,
[_GUARD_BIT_IS_SET_POP_6_r21] = _GUARD_BIT_IS_SET_POP_6,
[_GUARD_BIT_IS_SET_POP_6_r32] = _GUARD_BIT_IS_SET_POP_6,
[_GUARD_BIT_IS_SET_POP_7_r00] = _GUARD_BIT_IS_SET_POP_7,
[_GUARD_BIT_IS_SET_POP_7_r10] = _GUARD_BIT_IS_SET_POP_7,
[_GUARD_BIT_IS_SET_POP_7_r21] = _GUARD_BIT_IS_SET_POP_7,
[_GUARD_BIT_IS_SET_POP_7_r32] = _GUARD_BIT_IS_SET_POP_7,
[_GUARD_BIT_IS_SET_POP_r00] = _GUARD_BIT_IS_SET_POP,
[_GUARD_BIT_IS_SET_POP_r10] = _GUARD_BIT_IS_SET_POP,
[_GUARD_BIT_IS_SET_POP_r21] = _GUARD_BIT_IS_SET_POP,
[_GUARD_BIT_IS_SET_POP_r32] = _GUARD_BIT_IS_SET_POP,
[_GUARD_BIT_IS_UNSET_POP_4_r00] = _GUARD_BIT_IS_UNSET_POP_4,
[_GUARD_BIT_IS_UNSET_POP_4_r10] = _GUARD_BIT_IS_UNSET_POP_4,
[_GUARD_BIT_IS_UNSET_POP_4_r21] = _GUARD_BIT_IS_UNSET_POP_4,
[_GUARD_BIT_IS_UNSET_POP_4_r32] = _GUARD_BIT_IS_UNSET_POP_4,
[_GUARD_BIT_IS_UNSET_POP_5_r00] = _GUARD_BIT_IS_UNSET_POP_5,
[_GUARD_BIT_IS_UNSET_POP_5_r10] = _GUARD_BIT_IS_UNSET_POP_5,
[_GUARD_BIT_IS_UNSET_POP_5_r21] = _GUARD_BIT_IS_UNSET_POP_5,
[_GUARD_BIT_IS_UNSET_POP_5_r32] = _GUARD_BIT_IS_UNSET_POP_5,
[_GUARD_BIT_IS_UNSET_POP_6_r00] = _GUARD_BIT_IS_UNSET_POP_6,
[_GUARD_BIT_IS_UNSET_POP_6_r10] = _GUARD_BIT_IS_UNSET_POP_6,
[_GUARD_BIT_IS_UNSET_POP_6_r21] = _GUARD_BIT_IS_UNSET_POP_6,
[_GUARD_BIT_IS_UNSET_POP_6_r32] = _GUARD_BIT_IS_UNSET_POP_6,
[_GUARD_BIT_IS_UNSET_POP_7_r00] = _GUARD_BIT_IS_UNSET_POP_7,
[_GUARD_BIT_IS_UNSET_POP_7_r10] = _GUARD_BIT_IS_UNSET_POP_7,
[_GUARD_BIT_IS_UNSET_POP_7_r21] = _GUARD_BIT_IS_UNSET_POP_7,
[_GUARD_BIT_IS_UNSET_POP_7_r32] = _GUARD_BIT_IS_UNSET_POP_7,
[_GUARD_BIT_IS_UNSET_POP_r00] = _GUARD_BIT_IS_UNSET_POP,
[_GUARD_BIT_IS_UNSET_POP_r10] = _GUARD_BIT_IS_UNSET_POP,
[_GUARD_BIT_IS_UNSET_POP_r21] = _GUARD_BIT_IS_UNSET_POP,
[_GUARD_BIT_IS_UNSET_POP_r32] = _GUARD_BIT_IS_UNSET_POP,
[_GUARD_IS_NONE_POP_r00] = _GUARD_IS_NONE_POP,
[_GUARD_IS_NONE_POP_r10] = _GUARD_IS_NONE_POP,
[_GUARD_IS_NONE_POP_r21] = _GUARD_IS_NONE_POP,
@ -3991,6 +4150,9 @@ const uint16_t _PyUop_Uncached[MAX_UOP_REGS_ID+1] = {
[_POP_TWO_LOAD_CONST_INLINE_BORROW_r21] = _POP_TWO_LOAD_CONST_INLINE_BORROW,
[_POP_CALL_LOAD_CONST_INLINE_BORROW_r21] = _POP_CALL_LOAD_CONST_INLINE_BORROW,
[_POP_CALL_ONE_LOAD_CONST_INLINE_BORROW_r31] = _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW,
[_INSERT_1_LOAD_CONST_INLINE_r02] = _INSERT_1_LOAD_CONST_INLINE,
[_INSERT_1_LOAD_CONST_INLINE_r12] = _INSERT_1_LOAD_CONST_INLINE,
[_INSERT_1_LOAD_CONST_INLINE_r23] = _INSERT_1_LOAD_CONST_INLINE,
[_INSERT_1_LOAD_CONST_INLINE_BORROW_r02] = _INSERT_1_LOAD_CONST_INLINE_BORROW,
[_INSERT_1_LOAD_CONST_INLINE_BORROW_r12] = _INSERT_1_LOAD_CONST_INLINE_BORROW,
[_INSERT_1_LOAD_CONST_INLINE_BORROW_r23] = _INSERT_1_LOAD_CONST_INLINE_BORROW,
@ -4083,7 +4245,7 @@ const uint16_t _PyUop_SpillsAndReloads[4][4] = {
const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_BINARY_OP] = "_BINARY_OP",
[_BINARY_OP_r21] = "_BINARY_OP_r21",
[_BINARY_OP_r23] = "_BINARY_OP_r23",
[_BINARY_OP_ADD_FLOAT] = "_BINARY_OP_ADD_FLOAT",
[_BINARY_OP_ADD_FLOAT_r03] = "_BINARY_OP_ADD_FLOAT_r03",
[_BINARY_OP_ADD_FLOAT_r13] = "_BINARY_OP_ADD_FLOAT_r13",
@ -4097,7 +4259,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_BINARY_OP_ADD_UNICODE_r13] = "_BINARY_OP_ADD_UNICODE_r13",
[_BINARY_OP_ADD_UNICODE_r23] = "_BINARY_OP_ADD_UNICODE_r23",
[_BINARY_OP_EXTEND] = "_BINARY_OP_EXTEND",
[_BINARY_OP_EXTEND_r21] = "_BINARY_OP_EXTEND_r21",
[_BINARY_OP_EXTEND_r23] = "_BINARY_OP_EXTEND_r23",
[_BINARY_OP_INPLACE_ADD_UNICODE] = "_BINARY_OP_INPLACE_ADD_UNICODE",
[_BINARY_OP_INPLACE_ADD_UNICODE_r21] = "_BINARY_OP_INPLACE_ADD_UNICODE_r21",
[_BINARY_OP_MULTIPLY_FLOAT] = "_BINARY_OP_MULTIPLY_FLOAT",
@ -4398,6 +4560,56 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r12",
[_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r22",
[_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33] = "_GUARD_BINARY_OP_SUBSCR_TUPLE_INT_BOUNDS_r33",
[_GUARD_BIT_IS_SET_POP] = "_GUARD_BIT_IS_SET_POP",
[_GUARD_BIT_IS_SET_POP_r00] = "_GUARD_BIT_IS_SET_POP_r00",
[_GUARD_BIT_IS_SET_POP_r10] = "_GUARD_BIT_IS_SET_POP_r10",
[_GUARD_BIT_IS_SET_POP_r21] = "_GUARD_BIT_IS_SET_POP_r21",
[_GUARD_BIT_IS_SET_POP_r32] = "_GUARD_BIT_IS_SET_POP_r32",
[_GUARD_BIT_IS_SET_POP_4] = "_GUARD_BIT_IS_SET_POP_4",
[_GUARD_BIT_IS_SET_POP_4_r00] = "_GUARD_BIT_IS_SET_POP_4_r00",
[_GUARD_BIT_IS_SET_POP_4_r10] = "_GUARD_BIT_IS_SET_POP_4_r10",
[_GUARD_BIT_IS_SET_POP_4_r21] = "_GUARD_BIT_IS_SET_POP_4_r21",
[_GUARD_BIT_IS_SET_POP_4_r32] = "_GUARD_BIT_IS_SET_POP_4_r32",
[_GUARD_BIT_IS_SET_POP_5] = "_GUARD_BIT_IS_SET_POP_5",
[_GUARD_BIT_IS_SET_POP_5_r00] = "_GUARD_BIT_IS_SET_POP_5_r00",
[_GUARD_BIT_IS_SET_POP_5_r10] = "_GUARD_BIT_IS_SET_POP_5_r10",
[_GUARD_BIT_IS_SET_POP_5_r21] = "_GUARD_BIT_IS_SET_POP_5_r21",
[_GUARD_BIT_IS_SET_POP_5_r32] = "_GUARD_BIT_IS_SET_POP_5_r32",
[_GUARD_BIT_IS_SET_POP_6] = "_GUARD_BIT_IS_SET_POP_6",
[_GUARD_BIT_IS_SET_POP_6_r00] = "_GUARD_BIT_IS_SET_POP_6_r00",
[_GUARD_BIT_IS_SET_POP_6_r10] = "_GUARD_BIT_IS_SET_POP_6_r10",
[_GUARD_BIT_IS_SET_POP_6_r21] = "_GUARD_BIT_IS_SET_POP_6_r21",
[_GUARD_BIT_IS_SET_POP_6_r32] = "_GUARD_BIT_IS_SET_POP_6_r32",
[_GUARD_BIT_IS_SET_POP_7] = "_GUARD_BIT_IS_SET_POP_7",
[_GUARD_BIT_IS_SET_POP_7_r00] = "_GUARD_BIT_IS_SET_POP_7_r00",
[_GUARD_BIT_IS_SET_POP_7_r10] = "_GUARD_BIT_IS_SET_POP_7_r10",
[_GUARD_BIT_IS_SET_POP_7_r21] = "_GUARD_BIT_IS_SET_POP_7_r21",
[_GUARD_BIT_IS_SET_POP_7_r32] = "_GUARD_BIT_IS_SET_POP_7_r32",
[_GUARD_BIT_IS_UNSET_POP] = "_GUARD_BIT_IS_UNSET_POP",
[_GUARD_BIT_IS_UNSET_POP_r00] = "_GUARD_BIT_IS_UNSET_POP_r00",
[_GUARD_BIT_IS_UNSET_POP_r10] = "_GUARD_BIT_IS_UNSET_POP_r10",
[_GUARD_BIT_IS_UNSET_POP_r21] = "_GUARD_BIT_IS_UNSET_POP_r21",
[_GUARD_BIT_IS_UNSET_POP_r32] = "_GUARD_BIT_IS_UNSET_POP_r32",
[_GUARD_BIT_IS_UNSET_POP_4] = "_GUARD_BIT_IS_UNSET_POP_4",
[_GUARD_BIT_IS_UNSET_POP_4_r00] = "_GUARD_BIT_IS_UNSET_POP_4_r00",
[_GUARD_BIT_IS_UNSET_POP_4_r10] = "_GUARD_BIT_IS_UNSET_POP_4_r10",
[_GUARD_BIT_IS_UNSET_POP_4_r21] = "_GUARD_BIT_IS_UNSET_POP_4_r21",
[_GUARD_BIT_IS_UNSET_POP_4_r32] = "_GUARD_BIT_IS_UNSET_POP_4_r32",
[_GUARD_BIT_IS_UNSET_POP_5] = "_GUARD_BIT_IS_UNSET_POP_5",
[_GUARD_BIT_IS_UNSET_POP_5_r00] = "_GUARD_BIT_IS_UNSET_POP_5_r00",
[_GUARD_BIT_IS_UNSET_POP_5_r10] = "_GUARD_BIT_IS_UNSET_POP_5_r10",
[_GUARD_BIT_IS_UNSET_POP_5_r21] = "_GUARD_BIT_IS_UNSET_POP_5_r21",
[_GUARD_BIT_IS_UNSET_POP_5_r32] = "_GUARD_BIT_IS_UNSET_POP_5_r32",
[_GUARD_BIT_IS_UNSET_POP_6] = "_GUARD_BIT_IS_UNSET_POP_6",
[_GUARD_BIT_IS_UNSET_POP_6_r00] = "_GUARD_BIT_IS_UNSET_POP_6_r00",
[_GUARD_BIT_IS_UNSET_POP_6_r10] = "_GUARD_BIT_IS_UNSET_POP_6_r10",
[_GUARD_BIT_IS_UNSET_POP_6_r21] = "_GUARD_BIT_IS_UNSET_POP_6_r21",
[_GUARD_BIT_IS_UNSET_POP_6_r32] = "_GUARD_BIT_IS_UNSET_POP_6_r32",
[_GUARD_BIT_IS_UNSET_POP_7] = "_GUARD_BIT_IS_UNSET_POP_7",
[_GUARD_BIT_IS_UNSET_POP_7_r00] = "_GUARD_BIT_IS_UNSET_POP_7_r00",
[_GUARD_BIT_IS_UNSET_POP_7_r10] = "_GUARD_BIT_IS_UNSET_POP_7_r10",
[_GUARD_BIT_IS_UNSET_POP_7_r21] = "_GUARD_BIT_IS_UNSET_POP_7_r21",
[_GUARD_BIT_IS_UNSET_POP_7_r32] = "_GUARD_BIT_IS_UNSET_POP_7_r32",
[_GUARD_CALLABLE_ISINSTANCE] = "_GUARD_CALLABLE_ISINSTANCE",
[_GUARD_CALLABLE_ISINSTANCE_r03] = "_GUARD_CALLABLE_ISINSTANCE_r03",
[_GUARD_CALLABLE_ISINSTANCE_r13] = "_GUARD_CALLABLE_ISINSTANCE_r13",
@ -4633,6 +4845,10 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_INIT_CALL_PY_EXACT_ARGS_3_r01] = "_INIT_CALL_PY_EXACT_ARGS_3_r01",
[_INIT_CALL_PY_EXACT_ARGS_4] = "_INIT_CALL_PY_EXACT_ARGS_4",
[_INIT_CALL_PY_EXACT_ARGS_4_r01] = "_INIT_CALL_PY_EXACT_ARGS_4_r01",
[_INSERT_1_LOAD_CONST_INLINE] = "_INSERT_1_LOAD_CONST_INLINE",
[_INSERT_1_LOAD_CONST_INLINE_r02] = "_INSERT_1_LOAD_CONST_INLINE_r02",
[_INSERT_1_LOAD_CONST_INLINE_r12] = "_INSERT_1_LOAD_CONST_INLINE_r12",
[_INSERT_1_LOAD_CONST_INLINE_r23] = "_INSERT_1_LOAD_CONST_INLINE_r23",
[_INSERT_1_LOAD_CONST_INLINE_BORROW] = "_INSERT_1_LOAD_CONST_INLINE_BORROW",
[_INSERT_1_LOAD_CONST_INLINE_BORROW_r02] = "_INSERT_1_LOAD_CONST_INLINE_BORROW_r02",
[_INSERT_1_LOAD_CONST_INLINE_BORROW_r12] = "_INSERT_1_LOAD_CONST_INLINE_BORROW_r12",
@ -4701,7 +4917,7 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_LOAD_ATTR_METHOD_WITH_VALUES_r12] = "_LOAD_ATTR_METHOD_WITH_VALUES_r12",
[_LOAD_ATTR_METHOD_WITH_VALUES_r23] = "_LOAD_ATTR_METHOD_WITH_VALUES_r23",
[_LOAD_ATTR_MODULE] = "_LOAD_ATTR_MODULE",
[_LOAD_ATTR_MODULE_r11] = "_LOAD_ATTR_MODULE_r11",
[_LOAD_ATTR_MODULE_r12] = "_LOAD_ATTR_MODULE_r12",
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT",
[_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11] = "_LOAD_ATTR_NONDESCRIPTOR_NO_DICT_r11",
[_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES] = "_LOAD_ATTR_NONDESCRIPTOR_WITH_VALUES",
@ -4960,6 +5176,13 @@ const char *const _PyOpcode_uop_name[MAX_UOP_REGS_ID+1] = {
[_PY_FRAME_GENERAL_r01] = "_PY_FRAME_GENERAL_r01",
[_PY_FRAME_KW] = "_PY_FRAME_KW",
[_PY_FRAME_KW_r11] = "_PY_FRAME_KW_r11",
[_RECORD_4OS] = "_RECORD_4OS",
[_RECORD_BOUND_METHOD] = "_RECORD_BOUND_METHOD",
[_RECORD_CALLABLE] = "_RECORD_CALLABLE",
[_RECORD_CALLER_CODE] = "_RECORD_CALLER_CODE",
[_RECORD_NOS] = "_RECORD_NOS",
[_RECORD_TOS] = "_RECORD_TOS",
[_RECORD_TOS_TYPE] = "_RECORD_TOS_TYPE",
[_REPLACE_WITH_TRUE] = "_REPLACE_WITH_TRUE",
[_REPLACE_WITH_TRUE_r02] = "_REPLACE_WITH_TRUE_r02",
[_REPLACE_WITH_TRUE_r12] = "_REPLACE_WITH_TRUE_r12",
@ -5732,6 +5955,26 @@ int _PyUop_num_popped(int opcode, int oparg)
return 1;
case _GUARD_IS_FALSE_POP:
return 1;
case _GUARD_BIT_IS_SET_POP_4:
return 1;
case _GUARD_BIT_IS_SET_POP_5:
return 1;
case _GUARD_BIT_IS_SET_POP_6:
return 1;
case _GUARD_BIT_IS_SET_POP_7:
return 1;
case _GUARD_BIT_IS_SET_POP:
return 1;
case _GUARD_BIT_IS_UNSET_POP_4:
return 1;
case _GUARD_BIT_IS_UNSET_POP_5:
return 1;
case _GUARD_BIT_IS_UNSET_POP_6:
return 1;
case _GUARD_BIT_IS_UNSET_POP_7:
return 1;
case _GUARD_BIT_IS_UNSET_POP:
return 1;
case _GUARD_IS_NONE_POP:
return 1;
case _GUARD_IS_NOT_NONE_POP:
@ -5770,6 +6013,8 @@ int _PyUop_num_popped(int opcode, int oparg)
return 2;
case _POP_CALL_ONE_LOAD_CONST_INLINE_BORROW:
return 3;
case _INSERT_1_LOAD_CONST_INLINE:
return 1;
case _INSERT_1_LOAD_CONST_INLINE_BORROW:
return 1;
case _INSERT_2_LOAD_CONST_INLINE_BORROW:
@ -5812,6 +6057,20 @@ int _PyUop_num_popped(int opcode, int oparg)
return 0;
case _GUARD_IP_RETURN_GENERATOR:
return 0;
case _RECORD_TOS:
return 0;
case _RECORD_TOS_TYPE:
return 0;
case _RECORD_NOS:
return 0;
case _RECORD_4OS:
return 0;
case _RECORD_CALLABLE:
return 0;
case _RECORD_BOUND_METHOD:
return 0;
case _RECORD_CALLER_CODE:
return 0;
default:
return -1;
}

View file

@ -166,6 +166,44 @@ PyAPI_FUNC(PyObject *) PyLong_FromString(const char *, char **, int);
PyAPI_FUNC(unsigned long) PyOS_strtoul(const char *, char **, int);
PyAPI_FUNC(long) PyOS_strtol(const char *, char **, int);
/* --- Import/Export API -------------------------------------------------- */
typedef struct PyLongLayout {
uint8_t bits_per_digit;
uint8_t digit_size;
int8_t digits_order;
int8_t digit_endianness;
} PyLongLayout;
PyAPI_FUNC(const PyLongLayout*) PyLong_GetNativeLayout(void);
typedef struct PyLongExport {
int64_t value;
uint8_t negative;
Py_ssize_t ndigits;
const void *digits;
// Member used internally, must not be used for other purpose.
Py_uintptr_t _reserved;
} PyLongExport;
PyAPI_FUNC(int) PyLong_Export(
PyObject *obj,
PyLongExport *export_long);
PyAPI_FUNC(void) PyLong_FreeExport(
PyLongExport *export_long);
/* --- PyLongWriter API --------------------------------------------------- */
typedef struct PyLongWriter PyLongWriter;
PyAPI_FUNC(PyLongWriter*) PyLongWriter_Create(
int negative,
Py_ssize_t ndigits,
void **digits);
PyAPI_FUNC(PyObject*) PyLongWriter_Finish(PyLongWriter *writer);
PyAPI_FUNC(void) PyLongWriter_Discard(PyLongWriter *writer);
#ifndef Py_LIMITED_API
# define Py_CPYTHON_LONGOBJECT_H
# include "cpython/longobject.h"

View file

@ -118,11 +118,11 @@ PyAPI_FUNC(int) PyUnstable_Module_SetGIL(PyObject *module, void *gil);
#endif
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= _Py_PACK_VERSION(3, 15)
PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *,
PyAPI_FUNC(PyObject *) PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots,
PyObject *spec);
PyAPI_FUNC(int) PyModule_Exec(PyObject *mod);
PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *mod, Py_ssize_t *result);
PyAPI_FUNC(int) PyModule_GetToken(PyObject *, void **result);
PyAPI_FUNC(int) PyModule_Exec(PyObject *module);
PyAPI_FUNC(int) PyModule_GetStateSize(PyObject *module, Py_ssize_t *result);
PyAPI_FUNC(int) PyModule_GetToken(PyObject *module, void **result);
#endif
#ifndef _Py_OPAQUE_PYOBJECT

View file

@ -168,6 +168,13 @@ def write(self, prio, tag, message):
# message.
message = message.replace(b"\x00", b"\xc0\x80")
# On API level 30 and higher, Logcat will strip any number of leading
# newlines. This is visible in all `logcat` modes, even --binary. Work
# around this by adding a leading space, which shouldn't make any
# difference to the log's usability.
if message.startswith(b"\n"):
message = b" " + message
with self._lock:
now = time()
self._bucket_level += (

View file

@ -279,7 +279,13 @@ def __eq__(self, other):
# because dictionaries are not hashable.
and self.__globals__ is other.__globals__
and self.__forward_is_class__ == other.__forward_is_class__
and self.__cell__ == other.__cell__
# Two separate cells are always considered unequal in forward refs.
and (
{name: id(cell) for name, cell in self.__cell__.items()}
== {name: id(cell) for name, cell in other.__cell__.items()}
if isinstance(self.__cell__, dict) and isinstance(other.__cell__, dict)
else self.__cell__ is other.__cell__
)
and self.__owner__ == other.__owner__
and (
(tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None) ==
@ -293,7 +299,10 @@ def __hash__(self):
self.__forward_module__,
id(self.__globals__), # dictionaries are not hashable, so hash by identity
self.__forward_is_class__,
tuple(sorted(self.__cell__.items())) if isinstance(self.__cell__, dict) else self.__cell__,
( # cells are not hashable as well
tuple(sorted([(name, id(cell)) for name, cell in self.__cell__.items()]))
if isinstance(self.__cell__, dict) else id(self.__cell__),
),
self.__owner__,
tuple(sorted(self.__extra_names__.items())) if self.__extra_names__ else None,
))

View file

@ -26,6 +26,8 @@
]
_NOT_SPECIFIED = ['NOT SPECIFIED']
bytes_types = (bytes, bytearray) # Types acceptable as binary data
def _bytes_from_decode_data(s):
@ -62,7 +64,7 @@ def b64encode(s, altchars=None, *, wrapcol=0):
return encoded
def b64decode(s, altchars=None, validate=False):
def b64decode(s, altchars=None, validate=_NOT_SPECIFIED, *, ignorechars=_NOT_SPECIFIED):
"""Decode the Base64 encoded bytes-like object or ASCII string s.
Optional altchars must be a bytes-like object or ASCII string of length 2
@ -72,20 +74,53 @@ def b64decode(s, altchars=None, validate=False):
The result is returned as a bytes object. A binascii.Error is raised if
s is incorrectly padded.
If validate is False (the default), characters that are neither in the
normal base-64 alphabet nor the alternative alphabet are discarded prior
to the padding check. If validate is True, these non-alphabet characters
in the input result in a binascii.Error.
If ignorechars is specified, it should be a byte string containing
characters to ignore from the input. The default value of validate is
True if ignorechars is specified, False otherwise.
If validate is false, characters that are neither in the normal base-64
alphabet nor the alternative alphabet are discarded prior to the
padding check. If validate is true, these non-alphabet characters in
the input result in a binascii.Error if they are not in ignorechars.
For more information about the strict base64 check, see:
https://docs.python.org/3.11/library/binascii.html#binascii.a2b_base64
"""
s = _bytes_from_decode_data(s)
if validate is _NOT_SPECIFIED:
validate = ignorechars is not _NOT_SPECIFIED
badchar = None
if altchars is not None:
altchars = _bytes_from_decode_data(altchars)
assert len(altchars) == 2, repr(altchars)
s = s.translate(bytes.maketrans(altchars, b'+/'))
return binascii.a2b_base64(s, strict_mode=validate)
if len(altchars) != 2:
raise ValueError(f'invalid altchars: {altchars!r}')
if ignorechars is _NOT_SPECIFIED:
for b in b'+/':
if b not in altchars and b in s:
badchar = b
break
s = s.translate(bytes.maketrans(altchars, b'+/'))
else:
trans = bytes.maketrans(b'+/' + altchars, altchars + b'+/')
s = s.translate(trans)
ignorechars = ignorechars.translate(trans)
if ignorechars is _NOT_SPECIFIED:
ignorechars = b''
result = binascii.a2b_base64(s, strict_mode=validate,
ignorechars=ignorechars)
if badchar is not None:
import warnings
if validate:
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
f'with altchars={altchars!r} and validate=True '
f'will be an error in future Python versions',
DeprecationWarning, stacklevel=2)
else:
warnings.warn(f'invalid character {chr(badchar)!a} in Base64 data '
f'with altchars={altchars!r} and validate=False '
f'will be discarded in future Python versions',
FutureWarning, stacklevel=2)
return result
def standard_b64encode(s):
@ -130,8 +165,19 @@ def urlsafe_b64decode(s):
The alphabet uses '-' instead of '+' and '_' instead of '/'.
"""
s = _bytes_from_decode_data(s)
badchar = None
for b in b'+/':
if b in s:
badchar = b
break
s = s.translate(_urlsafe_decode_translation)
return b64decode(s)
result = binascii.a2b_base64(s, strict_mode=False)
if badchar is not None:
import warnings
warnings.warn(f'invalid character {chr(badchar)!a} in URL-safe Base64 data '
f'will be discarded in future Python versions',
FutureWarning, stacklevel=2)
return result

View file

@ -9,7 +9,7 @@
- seems to contain a bug when updating...
- reclaim free space (currently, space once occupied by deleted or expanded
items is not reused exept if .reorganize() is called)
items is not reused except if .reorganize() is called)
- support concurrent access (currently, if two processes take turns making
updates, they can mess up the index)

View file

@ -101,6 +101,12 @@ def make_quoted_pairs(value):
return str(value).replace('\\', '\\\\').replace('"', '\\"')
def make_parenthesis_pairs(value):
"""Escape parenthesis and backslash for use within a comment."""
return str(value).replace('\\', '\\\\') \
.replace('(', '\\(').replace(')', '\\)')
def quote_string(value):
escaped = make_quoted_pairs(value)
return f'"{escaped}"'
@ -943,7 +949,7 @@ def value(self):
return ' '
def startswith_fws(self):
return True
return self and self[0] in WSP
class ValueTerminal(Terminal):
@ -2963,6 +2969,13 @@ def _refold_parse_tree(parse_tree, *, policy):
[ValueTerminal(make_quoted_pairs(p), 'ptext')
for p in newparts] +
[ValueTerminal('"', 'ptext')])
if part.token_type == 'comment':
newparts = (
[ValueTerminal('(', 'ptext')] +
[ValueTerminal(make_parenthesis_pairs(p), 'ptext')
if p.token_type == 'ptext' else p
for p in newparts] +
[ValueTerminal(')', 'ptext')])
if not part.as_ew_allowed:
wrap_as_ew_blocked += 1
newparts.append(end_ew_not_allowed)

View file

@ -22,6 +22,7 @@
NLCRE = re.compile(r'\r\n|\r|\n')
fcre = re.compile(r'^From ', re.MULTILINE)
NEWLINE_WITHOUT_FWSP = re.compile(r'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]')
NEWLINE_WITHOUT_FWSP_BYTES = re.compile(br'\r\n[^ \t]|\r[^ \n\t]|\n[^ \t]')
class Generator:
@ -429,7 +430,16 @@ def _write_headers(self, msg):
# This is almost the same as the string version, except for handling
# strings with 8bit bytes.
for h, v in msg.raw_items():
self._fp.write(self.policy.fold_binary(h, v))
folded = self.policy.fold_binary(h, v)
if self.policy.verify_generated_headers:
linesep = self.policy.linesep.encode()
if not folded.endswith(linesep):
raise HeaderWriteError(
f'folded header does not end with {linesep!r}: {folded!r}')
if NEWLINE_WITHOUT_FWSP_BYTES.search(folded.removesuffix(linesep)):
raise HeaderWriteError(
f'folded header contains newline: {folded!r}')
self._fp.write(folded)
# A blank line always separates headers from body
self.write(self._NL)

View file

@ -602,6 +602,9 @@ def decorating_function(user_function):
return decorating_function
def _lru_cache_wrapper(user_function, maxsize, typed, _CacheInfo):
if not callable(user_function):
raise TypeError("the first argument must be callable")
# Constants shared by all lru cache instances:
sentinel = object() # unique object used to signal cache misses
make_key = _make_key # build a key from the function arguments

View file

@ -199,6 +199,7 @@ def done(self, *nodes):
self._ready_nodes.append(successor)
self._nfinished += 1
# See note "On Finding Cycles" at the bottom.
def _find_cycle(self):
n2i = self._node2info
stack = []
@ -212,8 +213,6 @@ def _find_cycle(self):
while True:
if node in seen:
# If we have seen already the node and is in the
# current stack we have found a cycle.
if node in node2stacki:
return stack[node2stacki[node] :] + [node]
# else go on to get next successor
@ -228,11 +227,15 @@ def _find_cycle(self):
while stack:
try:
node = itstack[-1]()
break
break # resume at top of "while True:"
except StopIteration:
# no more successors; pop the stack
# and continue looking up
del node2stacki[stack.pop()]
itstack.pop()
else:
# stack is empty; look for a fresh node to
# start over from (a node not yet in seen)
break
return None
@ -252,3 +255,55 @@ def static_order(self):
self.done(*node_group)
__class_getitem__ = classmethod(GenericAlias)
# On Finding Cycles
# -----------------
# There is a (at least one) total order if and only if the graph is
# acyclic.
#
# When it is cyclic, "there's a cycle - somewhere!" isn't very helpful.
# In theory, it would be most helpful to partition the graph into
# strongly connected components (SCCs) and display those with more than
# one node. Then all cycles could easily be identified "by eyeball".
#
# That's a lot of work, though, and we can get most of the benefit much
# more easily just by showing a single specific cycle.
#
# Approaches to that are based on breadth first or depth first search
# (BFS or DFS). BFS is most natural, which can easily be arranged to
# find a shortest-possible cycle. But memory burden can be high, because
# every path-in-progress has to keep its own idea of what "the path" is
# so far.
#
# DFS is much easier on RAM, only requiring keeping track of _the_ path
# from the starting node to the current node at the current recursion
# level. But there may be any number of nodes, and so there's no bound
# on recursion depth short of the total number of nodes.
#
# So we use an iterative version of DFS, keeping an exploit list
# (`stack`) of the path so far. A parallel stack (`itstack`) holds the
# `__next__` method of an iterator over the current level's node's
# successors, so when backtracking to a shallower level we can just call
# that to get the node's next successor. This is state that a recursive
# version would implicitly store in a `for` loop's internals.
#
# `seen()` is a set recording which nodes have already been, at some
# time, pushed on the stack. If a node has been pushed on the stack, DFS
# will find any cycle it's part of, so there's no need to ever look at
# it again.
#
# Finally, `node2stacki` maps a node to its index on the current stack,
# for and only for nodes currently _on_ the stack. If a successor to be
# pushed on the stack is in that dict, the node is already on the path,
# at that index. The cycle is then `stack[that_index :] + [node]`.
#
# As is often the case when removing recursion, the control flow looks a
# bit off. The "while True:" loop here rarely actually loops - it's only
# looking to go "up the stack" until finding a level that has another
# successor to consider, emulating a chain of returns in a recursive
# version.
#
# Worst cases: O(V+E) for time, and O(V) for memory, where V is the
# number of nodes and E the number of edges (which may be quadratic in
# V!). It requires care to ensure these bounds are met.

View file

@ -87,9 +87,9 @@
such trickeries do not confuse it.
>>> C = cookies.SimpleCookie()
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=\\012;";')
>>> C.load('keebler="E=everybody; L=\\"Loves\\"; fudge=;";')
>>> print(C)
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=\012;"
Set-Cookie: keebler="E=everybody; L=\"Loves\"; fudge=;"
Each element of the Cookie also supports all of the RFC 2109
Cookie attributes. Here's an example which sets the Path
@ -170,6 +170,15 @@ class CookieError(Exception):
})
_is_legal_key = re.compile('[%s]+' % re.escape(_LegalChars)).fullmatch
_control_character_re = re.compile(r'[\x00-\x1F\x7F]')
def _has_control_character(*val):
"""Detects control characters within a value.
Supports any type, as header values can be any type.
"""
return any(_control_character_re.search(str(v)) for v in val)
def _quote(str):
r"""Quote a string for use in a cookie header.
@ -294,12 +303,16 @@ def __setitem__(self, K, V):
K = K.lower()
if not K in self._reserved:
raise CookieError("Invalid attribute %r" % (K,))
if _has_control_character(K, V):
raise CookieError(f"Control characters are not allowed in cookies {K!r} {V!r}")
dict.__setitem__(self, K, V)
def setdefault(self, key, val=None):
key = key.lower()
if key not in self._reserved:
raise CookieError("Invalid attribute %r" % (key,))
if _has_control_character(key, val):
raise CookieError("Control characters are not allowed in cookies %r %r" % (key, val,))
return dict.setdefault(self, key, val)
def __eq__(self, morsel):
@ -335,6 +348,9 @@ def set(self, key, val, coded_val):
raise CookieError('Attempt to set a reserved key %r' % (key,))
if not _is_legal_key(key):
raise CookieError('Illegal key %r' % (key,))
if _has_control_character(key, val, coded_val):
raise CookieError(
"Control characters are not allowed in cookies %r %r %r" % (key, val, coded_val,))
# It's a good key, so save it.
self._key = key
@ -488,7 +504,10 @@ def output(self, attrs=None, header="Set-Cookie:", sep="\015\012"):
result = []
items = sorted(self.items())
for key, value in items:
result.append(value.output(attrs, header))
value_output = value.output(attrs, header)
if _has_control_character(value_output):
raise CookieError("Control characters are not allowed in cookies")
result.append(value_output)
return sep.join(result)
__str__ = output

View file

@ -1,9 +1,20 @@
What's New in IDLE 3.15.0
(since 3.14.0)
Released on 2026-10-01
=========================
gh-143774: Better explain the operation of Format / Format Paragraph.
Patch by Terry J. Reedy.
gh-139742: Colorize t-string prefixes for template strings in IDLE,
as done for f-string prefixes. Patch by Anuradha Agrawal.
What's New in IDLE 3.14.0
(since 3.13.0)
Released on 2025-10-07
=========================
gh-129873: Simplify displaying the IDLE doc by only copying the text
section of idle.html to idlelib/help.html. Patch by Stan Ulbrych.

25
Lib/idlelib/help.html generated
View file

@ -111,14 +111,14 @@ line visible. A request past the end of the file goes to the end.
Clear any selection and update the line and column status.</p>
</dd>
<dt>Show Completions</dt><dd><p>Open a scrollable list allowing selection of existing names. See
<a class="reference internal" href="#completions"><span class="std std-ref">Completions</span></a> in the Editing and navigation section below.</p>
<a class="reference internal" href="#completions"><span class="std std-ref">Completions</span></a> in the Editing and Navigation section below.</p>
</dd>
<dt>Expand Word</dt><dd><p>Expand a prefix you have typed to match a full word in the same window;
repeat to get a different expansion.</p>
</dd>
<dt>Show Call Tip</dt><dd><p>After an unclosed parenthesis for a function, open a small window with
function parameter hints. See <a class="reference internal" href="#calltips"><span class="std std-ref">Calltips</span></a> in the
Editing and navigation section below.</p>
Editing and Navigation section below.</p>
</dd>
<dt>Show Surrounding Parens</dt><dd><p>Highlight the surrounding parenthesis.</p>
</dd>
@ -127,9 +127,9 @@ Editing and navigation section below.</p>
<section id="format-menu-editor-window-only">
<span id="format-menu"></span><h3>Format menu (Editor window only)<a class="headerlink" href="#format-menu-editor-window-only" title="Link to this heading"></a></h3>
<dl class="simple">
<dt>Format Paragraph</dt><dd><p>Reformat the current blank-line-delimited paragraph in comment block or
multiline string or selected line in a string. All lines in the
paragraph will be formatted to less than N columns, where N defaults to 72.</p>
<dt>Format Paragraph</dt><dd><p>Rewrap the text block containing the text insert cursor.
Avoid code lines. See <a class="reference internal" href="#format-block"><span class="std std-ref">Format block</span></a> in the
Editing and Navigation section below.</p>
</dd>
<dt>Indent Region</dt><dd><p>Shift selected lines right by the indent width (default 4 spaces).</p>
</dd>
@ -443,8 +443,19 @@ will display a calltip.</p>
One might want to run a file after writing import statements, after
adding function definitions, or after opening an existing file.</p>
</section>
<section id="format-block">
<span id="id4"></span><h3>Format block<a class="headerlink" href="#format-block" title="Link to this heading"></a></h3>
<p>Reformat Paragraph rewraps a block (paragraph) of contiguous equally
indented non-blank comments, a similar block of text within a multiline
string, or a selected subset of either.
If needed, add a blank line to separate string from code.
Partial lines in a selection expand to complete lines.
The resulting lines have the same indent as before
but have maximum total length of N columns (characters).
Change the default N of 72 on the Window tab of IDLE Settings.</p>
</section>
<section id="code-context">
<span id="id4"></span><h3>Code Context<a class="headerlink" href="#code-context" title="Link to this heading"></a></h3>
<span id="id5"></span><h3>Code Context<a class="headerlink" href="#code-context" title="Link to this heading"></a></h3>
<p>Within an editor window containing Python code, code context can be toggled
in order to show or hide a pane at the top of the window. When shown, this
pane freezes the opening lines for block code, such as those beginning with
@ -791,7 +802,7 @@ with the default subprocess if at all possible.</p>
<section id="help-and-preferences">
<h2>Help and Preferences<a class="headerlink" href="#help-and-preferences" title="Link to this heading"></a></h2>
<section id="help-sources">
<span id="id5"></span><h3>Help sources<a class="headerlink" href="#help-sources" title="Link to this heading"></a></h3>
<span id="id6"></span><h3>Help sources<a class="headerlink" href="#help-sources" title="Link to this heading"></a></h3>
<p>Help menu entry “IDLE Help” displays a formatted html version of the
IDLE chapter of the Library Reference. The result, in a read-only
tkinter text window, is close to what one sees in a web browser.

View file

@ -129,7 +129,7 @@
# We compile these in _mode_xxx.
_Literal = br'.*{(?P<size>\d+)}$'
_Untagged_status = br'\* (?P<data>\d+) (?P<type>[A-Z-]+)( (?P<data2>.*))?'
_control_chars = re.compile(b'[\x00-\x1F\x7F]')
class IMAP4:
@ -1105,6 +1105,8 @@ def _command(self, name, *args):
if arg is None: continue
if isinstance(arg, str):
arg = bytes(arg, self._encoding)
if _control_chars.search(arg):
raise ValueError("Control characters not allowed in commands")
data = data + b' ' + arg
literal = self.literal

View file

@ -348,6 +348,7 @@ def isgenerator(object):
gi_frame frame object or possibly None once the generator has
been exhausted
gi_running set to 1 when generator is executing, 0 otherwise
gi_suspended set to 1 when the generator is suspended at a yield point, 0 otherwise
gi_yieldfrom object being iterated by yield from or None
__iter__() defined to support iteration over container

View file

@ -477,6 +477,7 @@ def _default_mime_types():
types_map = _types_map_default = {
'.js' : 'text/javascript',
'.mjs' : 'text/javascript',
'.dcm' : 'application/dicom',
'.epub' : 'application/epub+zip',
'.gz' : 'application/gzip',
'.json' : 'application/json',
@ -608,6 +609,7 @@ def _default_mime_types():
'.jpeg' : 'image/jpeg',
'.jpm' : 'image/jpm',
'.jpx' : 'image/jpx',
'.jxl' : 'image/jxl',
'.heic' : 'image/heic',
'.heif' : 'image/heif',
'.png' : 'image/png',

View file

@ -177,12 +177,15 @@ def set_executable(self, executable):
from .spawn import set_executable
set_executable(executable)
def set_forkserver_preload(self, module_names):
def set_forkserver_preload(self, module_names, *, on_error='ignore'):
'''Set list of module names to try to load in forkserver process.
This is really just a hint.
The on_error parameter controls how import failures are handled:
"ignore" (default) silently ignores failures, "warn" emits warnings,
and "fail" raises exceptions breaking the forkserver context.
'''
from .forkserver import set_forkserver_preload
set_forkserver_preload(module_names)
set_forkserver_preload(module_names, on_error=on_error)
def get_context(self, method=None):
if method is None:

View file

@ -42,6 +42,7 @@ def __init__(self):
self._inherited_fds = None
self._lock = threading.Lock()
self._preload_modules = ['__main__']
self._preload_on_error = 'ignore'
def _stop(self):
# Method used by unit tests to stop the server
@ -64,11 +65,22 @@ def _stop_unlocked(self):
self._forkserver_address = None
self._forkserver_authkey = None
def set_forkserver_preload(self, modules_names):
'''Set list of module names to try to load in forkserver process.'''
def set_forkserver_preload(self, modules_names, *, on_error='ignore'):
'''Set list of module names to try to load in forkserver process.
The on_error parameter controls how import failures are handled:
"ignore" (default) silently ignores failures, "warn" emits warnings,
and "fail" raises exceptions breaking the forkserver context.
'''
if not all(type(mod) is str for mod in modules_names):
raise TypeError('module_names must be a list of strings')
if on_error not in ('ignore', 'warn', 'fail'):
raise ValueError(
f"on_error must be 'ignore', 'warn', or 'fail', "
f"not {on_error!r}"
)
self._preload_modules = modules_names
self._preload_on_error = on_error
def get_inherited_fds(self):
'''Return list of fds inherited from parent process.
@ -107,6 +119,14 @@ def connect_to_new_process(self, fds):
wrapped_client, self._forkserver_authkey)
connection.deliver_challenge(
wrapped_client, self._forkserver_authkey)
except (EOFError, ConnectionError, BrokenPipeError) as exc:
if (self._preload_modules and
self._preload_on_error == 'fail'):
exc.add_note(
"Forkserver process may have crashed during module "
"preloading. Check stderr."
)
raise
finally:
wrapped_client._detach()
del wrapped_client
@ -154,6 +174,8 @@ def ensure_running(self):
main_kws['main_path'] = data['init_main_from_path']
if 'sys_argv' in data:
main_kws['sys_argv'] = data['sys_argv']
if self._preload_on_error != 'ignore':
main_kws['on_error'] = self._preload_on_error
with socket.socket(socket.AF_UNIX) as listener:
address = connection.arbitrary_address('AF_UNIX')
@ -198,8 +220,69 @@ def ensure_running(self):
#
#
def _handle_import_error(on_error, modinfo, exc, *, warn_stacklevel):
"""Handle an import error according to the on_error policy."""
match on_error:
case 'fail':
raise
case 'warn':
warnings.warn(
f"Failed to preload {modinfo}: {exc}",
ImportWarning,
stacklevel=warn_stacklevel + 1
)
case 'ignore':
pass
def _handle_preload(preload, main_path=None, sys_path=None, sys_argv=None,
on_error='ignore'):
"""Handle module preloading with configurable error handling.
Args:
preload: List of module names to preload.
main_path: Path to __main__ module if '__main__' is in preload.
sys_path: sys.path to use for imports (None means use current).
sys_argv: sys.argv to use (None means use current).
on_error: How to handle import errors ("ignore", "warn", or "fail").
"""
if not preload:
return
if sys_argv is not None:
sys.argv[:] = sys_argv
if sys_path is not None:
sys.path[:] = sys_path
if '__main__' in preload and main_path is not None:
process.current_process()._inheriting = True
try:
spawn.import_main_path(main_path)
except Exception as e:
# Catch broad Exception because import_main_path() uses
# runpy.run_path() which executes the script and can raise
# any exception, not just ImportError
_handle_import_error(
on_error, f"__main__ from {main_path!r}", e, warn_stacklevel=2
)
finally:
del process.current_process()._inheriting
for modname in preload:
try:
__import__(modname)
except ImportError as e:
_handle_import_error(
on_error, f"module {modname!r}", e, warn_stacklevel=2
)
# gh-135335: flush stdout/stderr in case any of the preloaded modules
# wrote to them, otherwise children might inherit buffered data
util._flush_std_streams()
def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
*, sys_argv=None, authkey_r=None):
*, sys_argv=None, authkey_r=None, on_error='ignore'):
"""Run forkserver."""
if authkey_r is not None:
try:
@ -210,26 +293,7 @@ def main(listener_fd, alive_r, preload, main_path=None, sys_path=None,
else:
authkey = b''
if preload:
if sys_argv is not None:
sys.argv[:] = sys_argv
if sys_path is not None:
sys.path[:] = sys_path
if '__main__' in preload and main_path is not None:
process.current_process()._inheriting = True
try:
spawn.import_main_path(main_path)
finally:
del process.current_process()._inheriting
for modname in preload:
try:
__import__(modname)
except ImportError:
pass
# gh-135335: flush stdout/stderr in case any of the preloaded modules
# wrote to them, otherwise children might inherit buffered data
util._flush_std_streams()
_handle_preload(preload, main_path, sys_path, sys_argv, on_error)
util._close_stdin()

View file

@ -888,7 +888,7 @@ def _exec_in_closure(self, source, globals, locals):
locals.update(pdb_eval["write_back"])
eval_result = pdb_eval["result"]
if eval_result is not None:
print(repr(eval_result))
self.message(repr(eval_result))
return True

View file

@ -122,6 +122,8 @@ def _putline(self, line):
def _putcmd(self, line):
if self._debugging: print('*cmd*', repr(line))
line = bytes(line, self.encoding)
if re.search(b'[\x00-\x1F\x7F]', line):
raise ValueError('Control characters not allowed in commands')
self._putline(line)

View file

@ -42,6 +42,7 @@ def _pause_threads(unwinder, blocking):
LiveStatsCollector = None
_FREE_THREADED_BUILD = sysconfig.get_config_var("Py_GIL_DISABLED") is not None
# Minimum number of samples required before showing the TUI
# If fewer samples are collected, we skip the TUI and just print a message
MIN_SAMPLES_FOR_TUI = 200
@ -64,19 +65,23 @@ def __init__(self, pid, sample_interval_usec, all_threads, *, mode=PROFILING_MOD
self.realtime_stats = False
def _new_unwinder(self, native, gc, opcodes, skip_non_matching_threads):
if _FREE_THREADED_BUILD:
unwinder = _remote_debugging.RemoteUnwinder(
self.pid, all_threads=self.all_threads, mode=self.mode, native=native, gc=gc,
opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads,
cache_frames=True, stats=self.collect_stats
)
kwargs = {}
if _FREE_THREADED_BUILD or self.all_threads:
kwargs['all_threads'] = self.all_threads
else:
unwinder = _remote_debugging.RemoteUnwinder(
self.pid, only_active_thread=bool(self.all_threads), mode=self.mode, native=native, gc=gc,
opcodes=opcodes, skip_non_matching_threads=skip_non_matching_threads,
cache_frames=True, stats=self.collect_stats
)
return unwinder
kwargs['only_active_thread'] = bool(self.all_threads)
return _remote_debugging.RemoteUnwinder(
self.pid,
mode=self.mode,
native=native,
gc=gc,
opcodes=opcodes,
skip_non_matching_threads=skip_non_matching_threads,
cache_frames=True,
stats=self.collect_stats,
**kwargs
)
def sample(self, collector, duration_sec=None, *, async_aware=False):
sample_interval_sec = self.sample_interval_usec / 1_000_000
@ -95,7 +100,11 @@ def sample(self, collector, duration_sec=None, *, async_aware=False):
break
current_time = time.perf_counter()
if next_time < current_time:
if next_time > current_time:
sleep_time = (next_time - current_time) * 0.9
if sleep_time > 0.0001:
time.sleep(sleep_time)
elif next_time < current_time:
try:
with _pause_threads(self.unwinder, self.blocking):
if async_aware == "all":

View file

@ -166,9 +166,14 @@ def filemode(mode):
perm = []
for index, table in enumerate(_filemode_table):
for bit, char in table:
if mode & bit == bit:
perm.append(char)
break
if index == 0:
if S_IFMT(mode) == bit:
perm.append(char)
break
else:
if mode & bit == bit:
perm.append(char)
break
else:
if index == 0:
# Unknown filetype

View file

@ -748,6 +748,60 @@ def _use_posix_spawn():
return False
def _can_use_pidfd_open():
# Availability: Linux >= 5.3
if not hasattr(os, "pidfd_open"):
return False
try:
pidfd = os.pidfd_open(os.getpid(), 0)
except OSError as err:
if err.errno in {errno.EMFILE, errno.ENFILE}:
# transitory 'too many open files'
return True
# likely blocked by security policy like SECCOMP (EPERM,
# EACCES, ENOSYS)
return False
else:
os.close(pidfd)
return True
def _can_use_kqueue():
# Availability: macOS, BSD
names = (
"kqueue",
"KQ_EV_ADD",
"KQ_EV_ONESHOT",
"KQ_FILTER_PROC",
"KQ_NOTE_EXIT",
)
if not all(hasattr(select, x) for x in names):
return False
kq = None
try:
kq = select.kqueue()
kev = select.kevent(
os.getpid(),
filter=select.KQ_FILTER_PROC,
flags=select.KQ_EV_ADD | select.KQ_EV_ONESHOT,
fflags=select.KQ_NOTE_EXIT,
)
kq.control([kev], 1, 0)
return True
except OSError as err:
if err.errno in {errno.EMFILE, errno.ENFILE}:
# transitory 'too many open files'
return True
return False
finally:
if kq is not None:
kq.close()
_CAN_USE_PIDFD_OPEN = not _mswindows and _can_use_pidfd_open()
_CAN_USE_KQUEUE = not _mswindows and _can_use_kqueue()
# These are primarily fail-safe knobs for negatives. A True value does not
# guarantee the given libc/syscall API will be used.
_USE_POSIX_SPAWN = _use_posix_spawn()
@ -2046,14 +2100,100 @@ def _try_wait(self, wait_flags):
sts = 0
return (pid, sts)
def _wait_pidfd(self, timeout):
"""Wait for PID to terminate using pidfd_open() + poll().
Linux >= 5.3 only.
"""
if not _CAN_USE_PIDFD_OPEN:
return False
try:
pidfd = os.pidfd_open(self.pid, 0)
except OSError:
# May be:
# - ESRCH: no such process
# - EMFILE, ENFILE: too many open files (usually 1024)
# - ENODEV: anonymous inode filesystem not supported
# - EPERM, EACCES, ENOSYS: undocumented; may happen if
# blocked by security policy like SECCOMP
return False
try:
poller = select.poll()
poller.register(pidfd, select.POLLIN)
events = poller.poll(timeout * 1000)
if not events:
raise TimeoutExpired(self.args, timeout)
return True
finally:
os.close(pidfd)
def _wait_kqueue(self, timeout):
"""Wait for PID to terminate using kqueue(). macOS and BSD only."""
if not _CAN_USE_KQUEUE:
return False
try:
kq = select.kqueue()
except OSError:
# likely EMFILE / ENFILE (too many open files)
return False
try:
kev = select.kevent(
self.pid,
filter=select.KQ_FILTER_PROC,
flags=select.KQ_EV_ADD | select.KQ_EV_ONESHOT,
fflags=select.KQ_NOTE_EXIT,
)
try:
events = kq.control([kev], 1, timeout) # wait
except OSError:
return False
else:
if not events:
raise TimeoutExpired(self.args, timeout)
return True
finally:
kq.close()
def _wait(self, timeout):
"""Internal implementation of wait() on POSIX."""
"""Internal implementation of wait() on POSIX.
Uses efficient pidfd_open() + poll() on Linux or kqueue()
on macOS/BSD when available. Falls back to polling
waitpid(WNOHANG) otherwise.
"""
if self.returncode is not None:
return self.returncode
if timeout is not None:
endtime = _time() + timeout
if timeout < 0:
raise TimeoutExpired(self.args, timeout)
started = _time()
endtime = started + timeout
# Try efficient wait first.
if self._wait_pidfd(timeout) or self._wait_kqueue(timeout):
# Process is gone. At this point os.waitpid(pid, 0)
# will return immediately, but in very rare races
# the PID may have been reused.
# os.waitpid(pid, WNOHANG) ensures we attempt a
# non-blocking reap without blocking indefinitely.
with self._waitpid_lock:
if self.returncode is not None:
return self.returncode # Another thread waited.
(pid, sts) = self._try_wait(os.WNOHANG)
assert pid == self.pid or pid == 0
if pid == self.pid:
self._handle_exitstatus(sts)
return self.returncode
# os.waitpid(pid, WNOHANG) returned 0 instead
# of our PID, meaning PID has not yet exited,
# even though poll() / kqueue() said so. Very
# rare and mostly theoretical. Fallback to busy
# polling.
elapsed = _time() - started
endtime -= elapsed
# Enter a busy loop if we have a timeout. This busy loop was
# cribbed from Lib/threading.py in Thread.wait() at r71065.
delay = 0.0005 # 500 us -> initial delay of 1 ms
@ -2085,6 +2225,7 @@ def _wait(self, timeout):
# http://bugs.python.org/issue14396.
if pid == self.pid:
self._handle_exitstatus(sts)
return self.returncode

View file

@ -184,6 +184,7 @@ class Function(SymbolTable):
__frees = None
__globals = None
__nonlocals = None
__cells = None
def __idents_matching(self, test_func):
return tuple(ident for ident in self.get_identifiers()
@ -229,6 +230,14 @@ def get_frees(self):
self.__frees = self.__idents_matching(is_free)
return self.__frees
def get_cells(self):
"""Return a tuple of cell variables in the function.
"""
if self.__cells is None:
is_cell = lambda x: _get_scope(x) == CELL
self.__cells = self.__idents_matching(is_cell)
return self.__cells
class Class(SymbolTable):
@ -342,6 +351,10 @@ def is_free(self):
"""
return bool(self.__scope == FREE)
def is_cell(self):
"""Return *True* if the symbol is a cell variable."""
return bool(self.__scope == CELL)
def is_free_class(self):
"""Return *True* if a class-scoped symbol is free from
the perspective of a method."""

View file

@ -26,7 +26,7 @@ def __getinitargs__(self):
E.__module__ = "__main__"
# Simple mutable object.
class Object:
class Object(object):
pass
# Hashable immutable key object containing unheshable mutable data.
@ -38,6 +38,43 @@ def __reduce__(self):
# Shouldn't support the recursion itself
return K, (self.value,)
class WithSlots(object):
__slots__ = ('a', 'b')
class WithSlotsSubclass(WithSlots):
__slots__ = ('c',)
class WithSlotsAndDict(object):
__slots__ = ('a', '__dict__')
class WithPrivateAttrs(object):
def __init__(self, a):
self.__private = a
def get(self):
return self.__private
class WithPrivateAttrsSubclass(WithPrivateAttrs):
def __init__(self, a, b):
super().__init__(a)
self.__private = b
def get2(self):
return self.__private
class WithPrivateSlots(object):
__slots__ = ('__private',)
def __init__(self, a):
self.__private = a
def get(self):
return self.__private
class WithPrivateSlotsSubclass(WithPrivateSlots):
__slots__ = ('__private',)
def __init__(self, a, b):
super().__init__(a)
self.__private = b
def get2(self):
return self.__private
# For test_misc
class myint(int):
def __init__(self, x):

Some files were not shown because too many files have changed in this diff Show more