mirror of
https://github.com/python/cpython.git
synced 2026-02-07 18:30:30 +00:00
Merge branch 'main' into doc-fix-84116
This commit is contained in:
commit
bc50109663
332 changed files with 15328 additions and 7380 deletions
3
.gitattributes
vendored
3
.gitattributes
vendored
|
|
@ -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
5
.github/CODEOWNERS
vendored
|
|
@ -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
|
||||
|
|
|
|||
9
.github/ISSUE_TEMPLATE/documentation.md
vendored
9
.github/ISSUE_TEMPLATE/documentation.md
vendored
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: Documentation
|
||||
about: Report a problem with the documentation
|
||||
labels: "docs"
|
||||
---
|
||||
|
||||
# Documentation
|
||||
|
||||
(A clear and concise description of the issue.)
|
||||
15
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal file
15
.github/ISSUE_TEMPLATE/documentation.yml
vendored
Normal 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) don’t require an issue before opening a PR.
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: "Documentation"
|
||||
description: "A clear and concise description of the issue."
|
||||
validations:
|
||||
required: true
|
||||
9
.github/workflows/build.yml
vendored
9
.github/workflows/build.yml
vendored
|
|
@ -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
|
||||
|
|
|
|||
8
.github/workflows/reusable-wasi.yml
vendored
8
.github/workflows/reusable-wasi.yml
vendored
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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-")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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``.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
9
Doc/data/stable_abi.dat
generated
9
Doc/data/stable_abi.dat
generated
|
|
@ -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,,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"] = "/"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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`:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 '!'") }
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -411,6 +411,7 @@ typedef struct _PyOptimizationConfig {
|
|||
|
||||
// Optimization flags
|
||||
bool specialization_enabled;
|
||||
bool uops_optimize_enabled;
|
||||
} _PyOptimizationConfig;
|
||||
|
||||
struct
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
140
Include/internal/pycore_opcode_metadata.h
generated
140
Include/internal/pycore_opcode_metadata.h
generated
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
1
Include/internal/pycore_runtime_init_generated.h
generated
1
Include/internal/pycore_runtime_init_generated.h
generated
|
|
@ -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), \
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ struct _pymem_allocators {
|
|||
debug_alloc_api_t obj;
|
||||
} debug;
|
||||
int is_debug_enabled;
|
||||
int use_hugepages;
|
||||
PyObjectArenaAllocator obj_arena;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
2061
Include/internal/pycore_uop_ids.h
generated
2061
Include/internal/pycore_uop_ids.h
generated
File diff suppressed because it is too large
Load diff
281
Include/internal/pycore_uop_metadata.h
generated
281
Include/internal/pycore_uop_metadata.h
generated
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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 += (
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
))
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
25
Lib/idlelib/help.html
generated
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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":
|
||||
|
|
|
|||
11
Lib/stat.py
11
Lib/stat.py
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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."""
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Add table
Add a link
Reference in a new issue