mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
Compare commits
209 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3db7bf2d18 | ||
|
|
7099af8f5e | ||
|
|
3fa1425bfb | ||
|
|
ef51a7c8f3 | ||
|
|
ff2577f56e | ||
|
|
dc9f2385ed | ||
|
|
f193c8fe9e | ||
|
|
1db9f56bff | ||
|
|
d6d850df89 | ||
|
|
c5b37228af | ||
|
|
edff5aaa48 | ||
|
|
572c780aa8 | ||
|
|
332da6295f | ||
|
|
9d707d8a64 | ||
|
|
ed4f78a4b3 | ||
|
|
07eff899d8 | ||
|
|
100e316e53 | ||
|
|
c91c373ef6 | ||
|
|
14715e3a64 | ||
|
|
56a442d0d8 | ||
|
|
35142b18ae | ||
|
|
0ed56ed88f | ||
|
|
70c27ce94b | ||
|
|
5be3405e4e | ||
|
|
61823a5382 | ||
|
|
d119443936 | ||
|
|
eba449a198 | ||
|
|
d49e6f38a7 | ||
|
|
58e1c7a16f | ||
|
|
dcac498e50 | ||
|
|
59f247e43b | ||
|
|
4085ff7b32 | ||
|
|
4b14529730 | ||
|
|
100c726d98 | ||
|
|
706fdda8b3 | ||
|
|
1d8f3ed2eb | ||
|
|
cac4b04973 | ||
|
|
4238a975d7 | ||
|
|
53ec7c8fc0 | ||
|
|
128d31637e | ||
|
|
b3bf212898 | ||
|
|
2dac9e6016 | ||
|
|
8392095bf9 | ||
|
|
6825d5c11d | ||
|
|
fb404ab575 | ||
|
|
1a7824a927 | ||
|
|
c5252045d3 | ||
|
|
547d8daf78 | ||
|
|
618dc36714 | ||
|
|
c0c65141b3 | ||
|
|
62423c9c36 | ||
|
|
aea5531583 | ||
|
|
f6f456f950 | ||
|
|
7e5fcae09b | ||
|
|
4172644d78 | ||
|
|
88cd5d9850 | ||
|
|
08d8e18ad8 | ||
|
|
8801c6dec7 | ||
|
|
d3c888b4ec | ||
|
|
748c4b47b7 | ||
|
|
fddc24e4c8 | ||
|
|
2dc28eb8b0 | ||
|
|
5e58548ebe | ||
|
|
41728856a2 | ||
|
|
eb892868b3 | ||
|
|
e32c975640 | ||
|
|
f87eb4d7cd | ||
|
|
52f9b5f580 | ||
|
|
694922cf40 | ||
|
|
5a4c4a033a | ||
|
|
d4fa70706c | ||
|
|
b708485d1a | ||
|
|
3e2c557493 | ||
|
|
981ce0cf3a | ||
|
|
229ed3dd1f | ||
|
|
cd4d0ae75c | ||
|
|
056d6c5ed9 | ||
|
|
ea51e745c7 | ||
|
|
db098a475a | ||
|
|
f2ca1581ca | ||
|
|
77399436bf | ||
|
|
3c117380ab | ||
|
|
cfcd52490d | ||
|
|
890fe5aad5 | ||
|
|
440bcb9456 | ||
|
|
5e749d3743 | ||
|
|
5b1862bdd8 | ||
|
|
923056b2d4 | ||
|
|
cc6bc4c97f | ||
|
|
526d7a8bb4 | ||
|
|
d2d2e92110 | ||
|
|
fa9519f8b2 | ||
|
|
5a7c9c6861 | ||
|
|
3001464248 | ||
|
|
5ec03cf3b0 | ||
|
|
656a64b37f | ||
|
|
69f54ce452 | ||
|
|
e02801dc37 | ||
|
|
9c4ff8a615 | ||
|
|
d5d9e89dde | ||
|
|
83d8134c5b | ||
|
|
7fe1a18b77 | ||
|
|
bc9e63dd9d | ||
|
|
9ac14288d7 | ||
|
|
9dbf77beb6 | ||
|
|
2c1fdf3592 | ||
|
|
2ff8608b4d | ||
|
|
c359ea4c71 | ||
|
|
2ea67caf31 | ||
|
|
27f62eb711 | ||
|
|
d7f0214f13 | ||
|
|
8c33c6143e | ||
|
|
33efd7178e | ||
|
|
9f2a34af74 | ||
|
|
a89ee4b9c2 | ||
|
|
202fce0dbd | ||
|
|
f445c452ea | ||
|
|
226011ba12 | ||
|
|
e6174ee981 | ||
|
|
d07d3a3c57 | ||
|
|
da1d468bea | ||
|
|
dc62b62252 | ||
|
|
369ce2b139 | ||
|
|
fee7782650 | ||
|
|
e1f1df4082 | ||
|
|
5f35702bb6 | ||
|
|
71126ab19c | ||
|
|
c490ffb7ac | ||
|
|
b484c32d0a | ||
|
|
fb655527d8 | ||
|
|
0cde70bde0 | ||
|
|
9346e22dd0 | ||
|
|
04e3670f6b | ||
|
|
0387a8e0f7 | ||
|
|
a4f4225213 | ||
|
|
0afcb51d17 | ||
|
|
e0773eacb7 | ||
|
|
bf66bce4ee | ||
|
|
6462322840 | ||
|
|
3eec46d3c3 | ||
|
|
425f24e4fa | ||
|
|
23b67aa037 | ||
|
|
4fe6e81d84 | ||
|
|
ecb901dd87 | ||
|
|
e457d60daa | ||
|
|
614a28b3da | ||
|
|
2746c698e3 | ||
|
|
e73fbbacbb | ||
|
|
227b9d326e | ||
|
|
425fd85ca3 | ||
|
|
cde19e565c | ||
|
|
d4e3829a74 | ||
|
|
58badb1711 | ||
|
|
08477dbf30 | ||
|
|
c41fce08a5 | ||
|
|
5c25bc5763 | ||
|
|
f21ed37daf | ||
|
|
dc9d2eea58 | ||
|
|
92972aea0f | ||
|
|
2d50dd242e | ||
|
|
019c315a8e | ||
|
|
a3b78a3ade | ||
|
|
fb26d9c2ef | ||
|
|
f15f6d0ba3 | ||
|
|
49ff8b6cc0 | ||
|
|
cb4c87df75 | ||
|
|
a8733cbc73 | ||
|
|
20b69aac0d | ||
|
|
07410da204 | ||
|
|
77cb39e0c7 | ||
|
|
b3383085f9 | ||
|
|
e90061f5f1 | ||
|
|
722f4bb8c9 | ||
|
|
b1558b6d3e | ||
|
|
4273616ebf | ||
|
|
2da7ecc680 | ||
|
|
ce701032a3 | ||
|
|
41b9ad5b38 | ||
|
|
e265ce8a56 | ||
|
|
a35c683da5 | ||
|
|
bc9b9d47f9 | ||
|
|
e5adaafc52 | ||
|
|
ca1e86f9d9 | ||
|
|
b4344f7020 | ||
|
|
fbc31d14ff | ||
|
|
3149d64c93 | ||
|
|
01713b4342 | ||
|
|
9b69a55be3 | ||
|
|
4bcab461c2 | ||
|
|
598d4c64de | ||
|
|
b3b63e8d6d | ||
|
|
96f496a949 | ||
|
|
e2178743fe | ||
|
|
95296a9d40 | ||
|
|
afa0badcc5 | ||
|
|
52f70a6f60 | ||
|
|
c25a070759 | ||
|
|
5d1f8f2d03 | ||
|
|
dbbf4b2e21 | ||
|
|
92c5de73b8 | ||
|
|
7b0b708675 | ||
|
|
ce79154176 | ||
|
|
652c764a59 | ||
|
|
17636ba48c | ||
|
|
4cfa695c95 | ||
|
|
daafacf005 | ||
|
|
600f3feb23 | ||
|
|
4695ec109d | ||
|
|
a52c39e260 |
438 changed files with 36149 additions and 14887 deletions
3
.github/CODEOWNERS
vendored
3
.github/CODEOWNERS
vendored
|
|
@ -126,6 +126,9 @@ Doc/howto/clinic.rst @erlend-aasland @AA-Turner
|
|||
# C Analyser
|
||||
Tools/c-analyzer/ @ericsnowcurrently
|
||||
|
||||
# C API Documentation Checks
|
||||
Tools/check-c-api-docs/ @ZeroIntensity
|
||||
|
||||
# Fuzzing
|
||||
Modules/_xxtestfuzz/ @ammaraskar
|
||||
|
||||
|
|
|
|||
11
.github/CONTRIBUTING.rst
vendored
11
.github/CONTRIBUTING.rst
vendored
|
|
@ -28,13 +28,12 @@ Please be aware that our workflow does deviate slightly from the typical GitHub
|
|||
project. Details on how to properly submit a pull request are covered in
|
||||
`Lifecycle of a Pull Request <https://devguide.python.org/getting-started/pull-request-lifecycle.html>`_.
|
||||
We utilize various bots and status checks to help with this, so do follow the
|
||||
comments they leave and their "Details" links, respectively. The key points of
|
||||
our workflow that are not covered by a bot or status check are:
|
||||
comments they leave and their "Details" links, respectively.
|
||||
|
||||
- All discussions that are not directly related to the code in the pull request
|
||||
should happen on `GitHub Issues <https://github.com/python/cpython/issues>`_.
|
||||
- Upon your first non-trivial pull request (which includes documentation changes),
|
||||
feel free to add yourself to ``Misc/ACKS``.
|
||||
The final key part of our workflow is that all discussions that are not
|
||||
directly related to the code in the pull request should happen on
|
||||
`GitHub Issues <https://github.com/python/cpython/issues>`__, generally in the
|
||||
pull request's parent issue.
|
||||
|
||||
|
||||
Setting Expectations
|
||||
|
|
|
|||
3
.github/ISSUE_TEMPLATE/config.yml
vendored
3
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -5,3 +5,6 @@ contact_links:
|
|||
- name: "Proposing new features"
|
||||
about: "Submit major feature proposal (e.g. syntax changes) to an ideas forum first."
|
||||
url: "https://discuss.python.org/c/ideas/6"
|
||||
- name: "Python Install Manager issues"
|
||||
about: "Report issues with the Python Install Manager (for Windows)"
|
||||
url: "https://github.com/python/pymanager/issues"
|
||||
|
|
|
|||
7
.github/dependabot.yml
vendored
7
.github/dependabot.yml
vendored
|
|
@ -12,6 +12,11 @@ updates:
|
|||
update-types:
|
||||
- "version-update:semver-minor"
|
||||
- "version-update:semver-patch"
|
||||
cooldown:
|
||||
# https://blog.yossarian.net/2025/11/21/We-should-all-be-using-dependency-cooldowns
|
||||
# Cooldowns protect against supply chain attacks by avoiding the
|
||||
# highest-risk window immediately after new releases.
|
||||
default-days: 14
|
||||
- package-ecosystem: "pip"
|
||||
directory: "/Tools/"
|
||||
schedule:
|
||||
|
|
@ -19,3 +24,5 @@ updates:
|
|||
labels:
|
||||
- "skip issue"
|
||||
- "skip news"
|
||||
cooldown:
|
||||
default-days: 14
|
||||
|
|
|
|||
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
|
|
@ -142,6 +142,9 @@ jobs:
|
|||
- name: Check for unsupported C global variables
|
||||
if: github.event_name == 'pull_request' # $GITHUB_EVENT_NAME
|
||||
run: make check-c-globals
|
||||
- name: Check for undocumented C APIs
|
||||
run: make check-c-api-docs
|
||||
|
||||
|
||||
build-windows:
|
||||
name: >-
|
||||
|
|
|
|||
2
.github/workflows/reusable-wasi.yml
vendored
2
.github/workflows/reusable-wasi.yml
vendored
|
|
@ -13,7 +13,7 @@ jobs:
|
|||
timeout-minutes: 60
|
||||
env:
|
||||
WASMTIME_VERSION: 38.0.3
|
||||
WASI_SDK_VERSION: 25
|
||||
WASI_SDK_VERSION: 29
|
||||
WASI_SDK_PATH: /opt/wasi-sdk
|
||||
CROSS_BUILD_PYTHON: cross-build/build
|
||||
CROSS_BUILD_WASI: cross-build/wasm32-wasip1
|
||||
|
|
|
|||
|
|
@ -2,6 +2,10 @@ repos:
|
|||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||
rev: v0.13.2
|
||||
hooks:
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||
files: ^Apple/
|
||||
- id: ruff-check
|
||||
name: Run Ruff (lint) on Doc/
|
||||
args: [--exit-non-zero-on-fix]
|
||||
|
|
@ -30,6 +34,10 @@ repos:
|
|||
name: Run Ruff (lint) on Tools/wasm/
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
|
||||
files: ^Tools/wasm/
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Apple/
|
||||
args: [--exit-non-zero-on-fix, --config=Apple/.ruff.toml]
|
||||
files: ^Apple
|
||||
- id: ruff-format
|
||||
name: Run Ruff (format) on Doc/
|
||||
args: [--check]
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@
|
|||
ANDROID_DIR.name == "Android" and (PYTHON_DIR / "pyconfig.h.in").exists()
|
||||
)
|
||||
|
||||
ENV_SCRIPT = ANDROID_DIR / "android-env.sh"
|
||||
TESTBED_DIR = ANDROID_DIR / "testbed"
|
||||
CROSS_BUILD_DIR = PYTHON_DIR / "cross-build"
|
||||
|
||||
|
|
@ -129,12 +130,11 @@ def android_env(host):
|
|||
sysconfig_filename = next(sysconfig_files).name
|
||||
host = re.fullmatch(r"_sysconfigdata__android_(.+).py", sysconfig_filename)[1]
|
||||
|
||||
env_script = ANDROID_DIR / "android-env.sh"
|
||||
env_output = subprocess.run(
|
||||
f"set -eu; "
|
||||
f"HOST={host}; "
|
||||
f"PREFIX={prefix}; "
|
||||
f". {env_script}; "
|
||||
f". {ENV_SCRIPT}; "
|
||||
f"export",
|
||||
check=True, shell=True, capture_output=True, encoding='utf-8',
|
||||
).stdout
|
||||
|
|
@ -151,7 +151,7 @@ def android_env(host):
|
|||
env[key] = value
|
||||
|
||||
if not env:
|
||||
raise ValueError(f"Found no variables in {env_script.name} output:\n"
|
||||
raise ValueError(f"Found no variables in {ENV_SCRIPT.name} output:\n"
|
||||
+ env_output)
|
||||
return env
|
||||
|
||||
|
|
@ -281,15 +281,30 @@ def clean_all(context):
|
|||
|
||||
|
||||
def setup_ci():
|
||||
# https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/
|
||||
if "GITHUB_ACTIONS" in os.environ and platform.system() == "Linux":
|
||||
run(
|
||||
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
|
||||
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
|
||||
text=True,
|
||||
)
|
||||
run(["sudo", "udevadm", "control", "--reload-rules"])
|
||||
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
|
||||
if "GITHUB_ACTIONS" in os.environ:
|
||||
# Enable emulator hardware acceleration
|
||||
# (https://github.blog/changelog/2024-04-02-github-actions-hardware-accelerated-android-virtualization-now-available/).
|
||||
if platform.system() == "Linux":
|
||||
run(
|
||||
["sudo", "tee", "/etc/udev/rules.d/99-kvm4all.rules"],
|
||||
input='KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"\n',
|
||||
text=True,
|
||||
)
|
||||
run(["sudo", "udevadm", "control", "--reload-rules"])
|
||||
run(["sudo", "udevadm", "trigger", "--name-match=kvm"])
|
||||
|
||||
# Free up disk space by deleting unused versions of the NDK
|
||||
# (https://github.com/freakboy3742/pyspamsum/pull/108).
|
||||
for line in ENV_SCRIPT.read_text().splitlines():
|
||||
if match := re.fullmatch(r"ndk_version=(.+)", line):
|
||||
ndk_version = match[1]
|
||||
break
|
||||
else:
|
||||
raise ValueError(f"Failed to find NDK version in {ENV_SCRIPT.name}")
|
||||
|
||||
for item in (android_home / "ndk").iterdir():
|
||||
if item.name[0].isdigit() and item.name != ndk_version:
|
||||
delete_glob(item)
|
||||
|
||||
|
||||
def setup_sdk():
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ android {
|
|||
val androidEnvFile = file("../../android-env.sh").absoluteFile
|
||||
|
||||
namespace = "org.python.testbed"
|
||||
compileSdk = 34
|
||||
compileSdk = 35
|
||||
|
||||
defaultConfig {
|
||||
applicationId = "org.python.testbed"
|
||||
|
|
@ -92,7 +92,7 @@ android {
|
|||
}
|
||||
throw GradleException("Failed to find API level in $androidEnvFile")
|
||||
}
|
||||
targetSdk = 34
|
||||
targetSdk = 35
|
||||
|
||||
versionCode = 1
|
||||
versionName = "1.0"
|
||||
|
|
|
|||
22
Apple/.ruff.toml
Normal file
22
Apple/.ruff.toml
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
extend = "../.ruff.toml" # Inherit the project-wide settings
|
||||
|
||||
[format]
|
||||
preview = true
|
||||
docstring-code-format = true
|
||||
|
||||
[lint]
|
||||
select = [
|
||||
"C4", # flake8-comprehensions
|
||||
"E", # pycodestyle
|
||||
"F", # pyflakes
|
||||
"I", # isort
|
||||
"ISC", # flake8-implicit-str-concat
|
||||
"LOG", # flake8-logging
|
||||
"PGH", # pygrep-hooks
|
||||
"PT", # flake8-pytest-style
|
||||
"PYI", # flake8-pyi
|
||||
"RUF100", # Ban unused `# noqa` comments
|
||||
"UP", # pyupgrade
|
||||
"W", # pycodestyle
|
||||
"YTT", # flake8-2020
|
||||
]
|
||||
|
|
@ -46,13 +46,12 @@
|
|||
import sys
|
||||
import sysconfig
|
||||
import time
|
||||
from collections.abc import Sequence
|
||||
from collections.abc import Callable, Sequence
|
||||
from contextlib import contextmanager
|
||||
from datetime import datetime, timezone
|
||||
from os.path import basename, relpath
|
||||
from pathlib import Path
|
||||
from subprocess import CalledProcessError
|
||||
from typing import Callable
|
||||
|
||||
EnvironmentT = dict[str, str]
|
||||
ArgsT = Sequence[str | Path]
|
||||
|
|
@ -140,17 +139,15 @@ def print_env(env: EnvironmentT) -> None:
|
|||
def apple_env(host: str) -> EnvironmentT:
|
||||
"""Construct an Apple development environment for the given host."""
|
||||
env = {
|
||||
"PATH": ":".join(
|
||||
[
|
||||
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
||||
str(subdir(host) / "prefix"),
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
"/usr/sbin",
|
||||
"/sbin",
|
||||
"/Library/Apple/usr/bin",
|
||||
]
|
||||
),
|
||||
"PATH": ":".join([
|
||||
str(PYTHON_DIR / "Apple/iOS/Resources/bin"),
|
||||
str(subdir(host) / "prefix"),
|
||||
"/usr/bin",
|
||||
"/bin",
|
||||
"/usr/sbin",
|
||||
"/sbin",
|
||||
"/Library/Apple/usr/bin",
|
||||
]),
|
||||
}
|
||||
|
||||
return env
|
||||
|
|
@ -196,14 +193,10 @@ def clean(context: argparse.Namespace, target: str = "all") -> None:
|
|||
paths.append(target)
|
||||
|
||||
if target in {"all", "hosts", "test"}:
|
||||
paths.extend(
|
||||
[
|
||||
path.name
|
||||
for path in CROSS_BUILD_DIR.glob(
|
||||
f"{context.platform}-testbed.*"
|
||||
)
|
||||
]
|
||||
)
|
||||
paths.extend([
|
||||
path.name
|
||||
for path in CROSS_BUILD_DIR.glob(f"{context.platform}-testbed.*")
|
||||
])
|
||||
|
||||
for path in paths:
|
||||
delete_path(path)
|
||||
|
|
@ -352,18 +345,16 @@ def download(url: str, target_dir: Path) -> Path:
|
|||
|
||||
out_path = target_path / basename(url)
|
||||
if not Path(out_path).is_file():
|
||||
run(
|
||||
[
|
||||
"curl",
|
||||
"-Lf",
|
||||
"--retry",
|
||||
"5",
|
||||
"--retry-all-errors",
|
||||
"-o",
|
||||
out_path,
|
||||
url,
|
||||
]
|
||||
)
|
||||
run([
|
||||
"curl",
|
||||
"-Lf",
|
||||
"--retry",
|
||||
"5",
|
||||
"--retry-all-errors",
|
||||
"-o",
|
||||
out_path,
|
||||
url,
|
||||
])
|
||||
else:
|
||||
print(f"Using cached version of {basename(url)}")
|
||||
return out_path
|
||||
|
|
@ -468,8 +459,7 @@ def package_version(prefix_path: Path) -> str:
|
|||
|
||||
|
||||
def lib_platform_files(dirname, names):
|
||||
"""A file filter that ignores platform-specific files in the lib directory.
|
||||
"""
|
||||
"""A file filter that ignores platform-specific files in lib."""
|
||||
path = Path(dirname)
|
||||
if (
|
||||
path.parts[-3] == "lib"
|
||||
|
|
@ -478,7 +468,7 @@ def lib_platform_files(dirname, names):
|
|||
):
|
||||
return names
|
||||
elif path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||
ignored_names = set(
|
||||
ignored_names = {
|
||||
name
|
||||
for name in names
|
||||
if (
|
||||
|
|
@ -486,7 +476,13 @@ def lib_platform_files(dirname, names):
|
|||
or name.startswith("_sysconfig_vars_")
|
||||
or name == "build-details.json"
|
||||
)
|
||||
)
|
||||
}
|
||||
elif path.parts[-1] == "lib":
|
||||
ignored_names = {
|
||||
name
|
||||
for name in names
|
||||
if name.startswith("libpython") and name.endswith(".dylib")
|
||||
}
|
||||
else:
|
||||
ignored_names = set()
|
||||
|
||||
|
|
@ -499,7 +495,9 @@ def lib_non_platform_files(dirname, names):
|
|||
"""
|
||||
path = Path(dirname)
|
||||
if path.parts[-2] == "lib" and path.parts[-1].startswith("python"):
|
||||
return set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
||||
return (
|
||||
set(names) - lib_platform_files(dirname, names) - {"lib-dynload"}
|
||||
)
|
||||
else:
|
||||
return set()
|
||||
|
||||
|
|
@ -514,7 +512,8 @@ def create_xcframework(platform: str) -> str:
|
|||
package_path.mkdir()
|
||||
except FileExistsError:
|
||||
raise RuntimeError(
|
||||
f"{platform} XCframework already exists; do you need to run with --clean?"
|
||||
f"{platform} XCframework already exists; do you need to run "
|
||||
"with --clean?"
|
||||
) from None
|
||||
|
||||
frameworks = []
|
||||
|
|
@ -607,7 +606,7 @@ def create_xcframework(platform: str) -> str:
|
|||
print(f" - {slice_name} binaries")
|
||||
shutil.copytree(first_path / "bin", slice_path / "bin")
|
||||
|
||||
# Copy the include path (this will be a symlink to the framework headers)
|
||||
# Copy the include path (a symlink to the framework headers)
|
||||
print(f" - {slice_name} include files")
|
||||
shutil.copytree(
|
||||
first_path / "include",
|
||||
|
|
@ -621,6 +620,12 @@ def create_xcframework(platform: str) -> str:
|
|||
slice_framework / "Headers/pyconfig.h",
|
||||
)
|
||||
|
||||
print(f" - {slice_name} shared library")
|
||||
# Create a simlink for the fat library
|
||||
shared_lib = slice_path / f"lib/libpython{version_tag}.dylib"
|
||||
shared_lib.parent.mkdir()
|
||||
shared_lib.symlink_to("../Python.framework/Python")
|
||||
|
||||
print(f" - {slice_name} architecture-specific files")
|
||||
for host_triple, multiarch in slice_parts.items():
|
||||
print(f" - {multiarch} standard library")
|
||||
|
|
@ -632,6 +637,7 @@ def create_xcframework(platform: str) -> str:
|
|||
framework_path(host_triple, multiarch) / "lib",
|
||||
package_path / "Python.xcframework/lib",
|
||||
ignore=lib_platform_files,
|
||||
symlinks=True,
|
||||
)
|
||||
has_common_stdlib = True
|
||||
|
||||
|
|
@ -639,6 +645,7 @@ def create_xcframework(platform: str) -> str:
|
|||
framework_path(host_triple, multiarch) / "lib",
|
||||
slice_path / f"lib-{arch}",
|
||||
ignore=lib_non_platform_files,
|
||||
symlinks=True,
|
||||
)
|
||||
|
||||
# Copy the host's pyconfig.h to an architecture-specific name.
|
||||
|
|
@ -659,7 +666,8 @@ def create_xcframework(platform: str) -> str:
|
|||
# statically link those libraries into a Framework, you become
|
||||
# responsible for providing a privacy manifest for that framework.
|
||||
xcprivacy_file = {
|
||||
"OpenSSL": subdir(host_triple) / "prefix/share/OpenSSL.xcprivacy"
|
||||
"OpenSSL": subdir(host_triple)
|
||||
/ "prefix/share/OpenSSL.xcprivacy"
|
||||
}
|
||||
print(f" - {multiarch} xcprivacy files")
|
||||
for module, lib in [
|
||||
|
|
@ -669,7 +677,8 @@ def create_xcframework(platform: str) -> str:
|
|||
shutil.copy(
|
||||
xcprivacy_file[lib],
|
||||
slice_path
|
||||
/ f"lib-{arch}/python{version_tag}/lib-dynload/{module}.xcprivacy",
|
||||
/ f"lib-{arch}/python{version_tag}"
|
||||
/ f"lib-dynload/{module}.xcprivacy",
|
||||
)
|
||||
|
||||
print(" - build tools")
|
||||
|
|
@ -692,18 +701,16 @@ def package(context: argparse.Namespace) -> None:
|
|||
|
||||
# Clone testbed
|
||||
print()
|
||||
run(
|
||||
[
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
||||
CROSS_BUILD_DIR / context.platform / "testbed",
|
||||
]
|
||||
)
|
||||
run([
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
CROSS_BUILD_DIR / context.platform / "Python.xcframework",
|
||||
CROSS_BUILD_DIR / context.platform / "testbed",
|
||||
])
|
||||
|
||||
# Build the final archive
|
||||
archive_name = (
|
||||
|
|
@ -757,7 +764,7 @@ def build(context: argparse.Namespace, host: str | None = None) -> None:
|
|||
package(context)
|
||||
|
||||
|
||||
def test(context: argparse.Namespace, host: str | None = None) -> None:
|
||||
def test(context: argparse.Namespace, host: str | None = None) -> None: # noqa: PT028
|
||||
"""The implementation of the "test" command."""
|
||||
if host is None:
|
||||
host = context.host
|
||||
|
|
@ -795,18 +802,16 @@ def test(context: argparse.Namespace, host: str | None = None) -> None:
|
|||
/ f"Frameworks/{apple_multiarch(host)}"
|
||||
)
|
||||
|
||||
run(
|
||||
[
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
framework_path,
|
||||
testbed_dir,
|
||||
]
|
||||
)
|
||||
run([
|
||||
sys.executable,
|
||||
"Apple/testbed",
|
||||
"clone",
|
||||
"--platform",
|
||||
context.platform,
|
||||
"--framework",
|
||||
framework_path,
|
||||
testbed_dir,
|
||||
])
|
||||
|
||||
run(
|
||||
[
|
||||
|
|
@ -840,7 +845,7 @@ def apple_sim_host(platform_name: str) -> str:
|
|||
"""Determine the native simulator target for this platform."""
|
||||
for _, slice_parts in HOSTS[platform_name].items():
|
||||
for host_triple in slice_parts:
|
||||
parts = host_triple.split('-')
|
||||
parts = host_triple.split("-")
|
||||
if parts[0] == platform.machine() and parts[-1] == "simulator":
|
||||
return host_triple
|
||||
|
||||
|
|
@ -968,20 +973,29 @@ def parse_args() -> argparse.Namespace:
|
|||
cmd.add_argument(
|
||||
"--simulator",
|
||||
help=(
|
||||
"The name of the simulator to use (eg: 'iPhone 16e'). Defaults to "
|
||||
"the most recently released 'entry level' iPhone device. Device "
|
||||
"architecture and OS version can also be specified; e.g., "
|
||||
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would run on "
|
||||
"an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
||||
"The name of the simulator to use (eg: 'iPhone 16e'). "
|
||||
"Defaults to the most recently released 'entry level' "
|
||||
"iPhone device. Device architecture and OS version can also "
|
||||
"be specified; e.g., "
|
||||
"`--simulator 'iPhone 16 Pro,arch=arm64,OS=26.0'` would "
|
||||
"run on an ARM64 iPhone 16 Pro simulator running iOS 26.0."
|
||||
),
|
||||
)
|
||||
group = cmd.add_mutually_exclusive_group()
|
||||
group.add_argument(
|
||||
"--fast-ci", action="store_const", dest="ci_mode", const="fast",
|
||||
help="Add test arguments for GitHub Actions")
|
||||
"--fast-ci",
|
||||
action="store_const",
|
||||
dest="ci_mode",
|
||||
const="fast",
|
||||
help="Add test arguments for GitHub Actions",
|
||||
)
|
||||
group.add_argument(
|
||||
"--slow-ci", action="store_const", dest="ci_mode", const="slow",
|
||||
help="Add test arguments for buildbots")
|
||||
"--slow-ci",
|
||||
action="store_const",
|
||||
dest="ci_mode",
|
||||
const="slow",
|
||||
help="Add test arguments for buildbots",
|
||||
)
|
||||
|
||||
for subcommand in [configure_build, configure_host, build, ci]:
|
||||
subcommand.add_argument(
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ install_stdlib() {
|
|||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
rsync -au "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib-$ARCHS/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
else
|
||||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/"
|
||||
# A single-arch framework will have a libpython symlink; that can't be included at runtime
|
||||
rsync -au --delete "$PROJECT_DIR/$PYTHON_XCFRAMEWORK_PATH/$SLICE_FOLDER/lib/" "$CODESIGNING_FOLDER_PATH/python/lib/" --exclude 'libpython*.dylib'
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -32,15 +32,15 @@ def select_simulator_device(platform):
|
|||
json_data = json.loads(raw_json)
|
||||
|
||||
if platform == "iOS":
|
||||
# Any iOS device will do; we'll look for "SE" devices - but the name isn't
|
||||
# consistent over time. Older Xcode versions will use "iPhone SE (Nth
|
||||
# generation)"; As of 2025, they've started using "iPhone 16e".
|
||||
# Any iOS device will do; we'll look for "SE" devices - but the name
|
||||
# isn't consistent over time. Older Xcode versions will use "iPhone SE
|
||||
# (Nth generation)"; As of 2025, they've started using "iPhone 16e".
|
||||
#
|
||||
# When Xcode is updated after a new release, new devices will be available
|
||||
# and old ones will be dropped from the set available on the latest iOS
|
||||
# version. Select the one with the highest minimum runtime version - this
|
||||
# is an indicator of the "newest" released device, which should always be
|
||||
# supported on the "most recent" iOS version.
|
||||
# When Xcode is updated after a new release, new devices will be
|
||||
# available and old ones will be dropped from the set available on the
|
||||
# latest iOS version. Select the one with the highest minimum runtime
|
||||
# version - this is an indicator of the "newest" released device, which
|
||||
# should always be supported on the "most recent" iOS version.
|
||||
se_simulators = sorted(
|
||||
(devicetype["minRuntimeVersion"], devicetype["name"])
|
||||
for devicetype in json_data["devicetypes"]
|
||||
|
|
@ -295,7 +295,8 @@ def main():
|
|||
|
||||
parser = argparse.ArgumentParser(
|
||||
description=(
|
||||
"Manages the process of testing an Apple Python project through Xcode."
|
||||
"Manages the process of testing an Apple Python project "
|
||||
"through Xcode."
|
||||
),
|
||||
)
|
||||
|
||||
|
|
@ -336,7 +337,10 @@ def main():
|
|||
|
||||
run = subcommands.add_parser(
|
||||
"run",
|
||||
usage="%(prog)s [-h] [--simulator SIMULATOR] -- <test arg> [<test arg> ...]",
|
||||
usage=(
|
||||
"%(prog)s [-h] [--simulator SIMULATOR] -- "
|
||||
"<test arg> [<test arg> ...]"
|
||||
),
|
||||
description=(
|
||||
"Run a testbed project. The arguments provided after `--` will be "
|
||||
"passed to the running iOS process as if they were arguments to "
|
||||
|
|
@ -397,9 +401,9 @@ def main():
|
|||
/ "bin"
|
||||
).is_dir():
|
||||
print(
|
||||
f"Testbed does not contain a compiled Python framework. Use "
|
||||
f"`python {sys.argv[0]} clone ...` to create a runnable "
|
||||
f"clone of this testbed."
|
||||
"Testbed does not contain a compiled Python framework. "
|
||||
f"Use `python {sys.argv[0]} clone ...` to create a "
|
||||
"runnable clone of this testbed."
|
||||
)
|
||||
sys.exit(20)
|
||||
|
||||
|
|
@ -411,7 +415,8 @@ def main():
|
|||
)
|
||||
else:
|
||||
print(
|
||||
f"Must specify test arguments (e.g., {sys.argv[0]} run -- test)"
|
||||
"Must specify test arguments "
|
||||
f"(e.g., {sys.argv[0]} run -- test)"
|
||||
)
|
||||
print()
|
||||
parser.print_help(sys.stderr)
|
||||
|
|
|
|||
|
|
@ -32,8 +32,9 @@ Contributors to the Python documentation
|
|||
----------------------------------------
|
||||
|
||||
Many people have contributed to the Python language, the Python standard
|
||||
library, and the Python documentation. See :source:`Misc/ACKS` in the Python
|
||||
source distribution for a partial list of contributors.
|
||||
library, and the Python documentation. See the `CPython
|
||||
GitHub repository <https://github.com/python/cpython/graphs/contributors>`__
|
||||
for a partial list of contributors.
|
||||
|
||||
It is only with the input and contributions of the Python community
|
||||
that Python has such wonderful documentation -- Thank You!
|
||||
|
|
|
|||
|
|
@ -162,16 +162,33 @@ The following functions provide locale-independent string to number conversions.
|
|||
.. versionadded:: 3.1
|
||||
|
||||
|
||||
.. c:function:: int PyOS_stricmp(const char *s1, const char *s2)
|
||||
.. c:function:: int PyOS_mystricmp(const char *str1, const char *str2)
|
||||
int PyOS_mystrnicmp(const char *str1, const char *str2, Py_ssize_t size)
|
||||
|
||||
Case insensitive comparison of strings. The function works almost
|
||||
identically to :c:func:`!strcmp` except that it ignores the case.
|
||||
Case insensitive comparison of strings. These functions work almost
|
||||
identically to :c:func:`!strcmp` and :c:func:`!strncmp` (respectively),
|
||||
except that they ignore the case of ASCII characters.
|
||||
|
||||
Return ``0`` if the strings are equal, a negative value if *str1* sorts
|
||||
lexicographically before *str2*, or a positive value if it sorts after.
|
||||
|
||||
In the *str1* or *str2* arguments, a NUL byte marks the end of the string.
|
||||
For :c:func:`!PyOS_mystrnicmp`, the *size* argument gives the maximum size
|
||||
of the string, as if NUL was present at the index given by *size*.
|
||||
|
||||
These functions do not use the locale.
|
||||
|
||||
|
||||
.. c:function:: int PyOS_strnicmp(const char *s1, const char *s2, Py_ssize_t size)
|
||||
.. c:function:: int PyOS_stricmp(const char *str1, const char *str2)
|
||||
int PyOS_strnicmp(const char *str1, const char *str2, Py_ssize_t size)
|
||||
|
||||
Case insensitive comparison of strings. The function works almost
|
||||
identically to :c:func:`!strncmp` except that it ignores the case.
|
||||
Case insensitive comparison of strings.
|
||||
|
||||
On Windows, these are aliases of :c:func:`!stricmp` and :c:func:`!strnicmp`,
|
||||
respectively.
|
||||
|
||||
On other platforms, they are aliases of :c:func:`PyOS_mystricmp` and
|
||||
:c:func:`PyOS_mystrnicmp`, respectively.
|
||||
|
||||
|
||||
Character classification and conversion
|
||||
|
|
|
|||
|
|
@ -8,11 +8,42 @@ DateTime Objects
|
|||
Various date and time objects are supplied by the :mod:`datetime` module.
|
||||
Before using any of these functions, the header file :file:`datetime.h` must be
|
||||
included in your source (note that this is not included by :file:`Python.h`),
|
||||
and the macro :c:macro:`!PyDateTime_IMPORT` must be invoked, usually as part of
|
||||
and the macro :c:macro:`PyDateTime_IMPORT` must be invoked, usually as part of
|
||||
the module initialisation function. The macro puts a pointer to a C structure
|
||||
into a static variable, :c:data:`!PyDateTimeAPI`, that is used by the following
|
||||
into a static variable, :c:data:`PyDateTimeAPI`, that is used by the following
|
||||
macros.
|
||||
|
||||
.. c:macro:: PyDateTime_IMPORT()
|
||||
|
||||
Import the datetime C API.
|
||||
|
||||
On success, populate the :c:var:`PyDateTimeAPI` pointer.
|
||||
On failure, set :c:var:`PyDateTimeAPI` to ``NULL`` and set an exception.
|
||||
The caller must check if an error occurred via :c:func:`PyErr_Occurred`:
|
||||
|
||||
.. code-block::
|
||||
|
||||
PyDateTime_IMPORT;
|
||||
if (PyErr_Occurred()) { /* cleanup */ }
|
||||
|
||||
.. warning::
|
||||
|
||||
This is not compatible with subinterpreters.
|
||||
|
||||
.. c:type:: PyDateTime_CAPI
|
||||
|
||||
Structure containing the fields for the datetime C API.
|
||||
|
||||
The fields of this structure are private and subject to change.
|
||||
|
||||
Do not use this directly; prefer ``PyDateTime_*`` APIs instead.
|
||||
|
||||
.. c:var:: PyDateTime_CAPI *PyDateTimeAPI
|
||||
|
||||
Dynamically allocated object containing the datetime C API.
|
||||
|
||||
This variable is only available once :c:macro:`PyDateTime_IMPORT` succeeds.
|
||||
|
||||
.. c:type:: PyDateTime_Date
|
||||
|
||||
This subtype of :c:type:`PyObject` represents a Python date object.
|
||||
|
|
@ -325,3 +356,16 @@ Macros for the convenience of modules implementing the DB API:
|
|||
|
||||
Create and return a new :class:`datetime.date` object given an argument
|
||||
tuple suitable for passing to :meth:`datetime.date.fromtimestamp`.
|
||||
|
||||
|
||||
Internal data
|
||||
-------------
|
||||
|
||||
The following symbols are exposed by the C API but should be considered
|
||||
internal-only.
|
||||
|
||||
.. c:macro:: PyDateTime_CAPSULE_NAME
|
||||
|
||||
Name of the datetime capsule to pass to :c:func:`PyCapsule_Import`.
|
||||
|
||||
Internal usage only. Use :c:macro:`PyDateTime_IMPORT` instead.
|
||||
|
|
|
|||
|
|
@ -21,12 +21,46 @@ found in the dictionary of type objects.
|
|||
.. c:function:: PyObject* PyDescr_NewMember(PyTypeObject *type, struct PyMemberDef *meth)
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyMemberDescr_Type
|
||||
|
||||
The type object for member descriptor objects created from
|
||||
:c:type:`PyMemberDef` structures. These descriptors expose fields of a
|
||||
C struct as attributes on a type, and correspond
|
||||
to :class:`types.MemberDescriptorType` objects in Python.
|
||||
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyGetSetDescr_Type
|
||||
|
||||
The type object for get/set descriptor objects created from
|
||||
:c:type:`PyGetSetDef` structures. These descriptors implement attributes
|
||||
whose value is computed by C getter and setter functions, and are used
|
||||
for many built-in type attributes.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewMethod(PyTypeObject *type, struct PyMethodDef *meth)
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyMethodDescr_Type
|
||||
|
||||
The type object for method descriptor objects created from
|
||||
:c:type:`PyMethodDef` structures. These descriptors expose C functions as
|
||||
methods on a type, and correspond to :class:`types.MemberDescriptorType`
|
||||
objects in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewWrapper(PyTypeObject *type, struct wrapperbase *wrapper, void *wrapped)
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyWrapperDescr_Type
|
||||
|
||||
The type object for wrapper descriptor objects created by
|
||||
:c:func:`PyDescr_NewWrapper` and :c:func:`PyWrapper_New`. Wrapper
|
||||
descriptors are used internally to expose special methods implemented
|
||||
via wrapper structures, and appear in Python as
|
||||
:class:`types.WrapperDescriptorType` objects.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)
|
||||
|
||||
|
||||
|
|
@ -55,6 +89,14 @@ Built-in descriptors
|
|||
:class:`classmethod` in the Python layer.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyClassMethodDescr_Type
|
||||
|
||||
The type object for C-level class method descriptor objects.
|
||||
This is the type of the descriptors created for :func:`classmethod` defined in
|
||||
C extension types, and is the same object as :class:`classmethod`
|
||||
in Python.
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyClassMethod_New(PyObject *callable)
|
||||
|
||||
Create a new :class:`classmethod` object wrapping *callable*.
|
||||
|
|
|
|||
|
|
@ -43,6 +43,17 @@ Dictionary Objects
|
|||
prevent modification of the dictionary for non-dynamic class types.
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyDictProxy_Type
|
||||
|
||||
The type object for mapping proxy objects created by
|
||||
:c:func:`PyDictProxy_New` and for the read-only ``__dict__`` attribute
|
||||
of many built-in types. A :c:type:`PyDictProxy_Type` instance provides a
|
||||
dynamic, read-only view of an underlying dictionary: changes to the
|
||||
underlying dictionary are reflected in the proxy, but the proxy itself
|
||||
does not support mutation operations. This corresponds to
|
||||
:class:`types.MappingProxyType` in Python.
|
||||
|
||||
|
||||
.. c:function:: void PyDict_Clear(PyObject *p)
|
||||
|
||||
Empty an existing dictionary of all key-value pairs.
|
||||
|
|
|
|||
|
|
@ -8,7 +8,8 @@ Defining extension modules
|
|||
A C extension for CPython is a shared library (for example, a ``.so`` file
|
||||
on Linux, ``.pyd`` DLL on Windows), which is loadable into the Python process
|
||||
(for example, it is compiled with compatible compiler settings), and which
|
||||
exports an :ref:`initialization function <extension-export-hook>`.
|
||||
exports an :dfn:`export hook` function (or an
|
||||
old-style :ref:`initialization function <extension-pyinit>`).
|
||||
|
||||
To be importable by default (that is, by
|
||||
:py:class:`importlib.machinery.ExtensionFileLoader`),
|
||||
|
|
@ -23,25 +24,127 @@ and must be named after the module name plus an extension listed in
|
|||
One suitable tool is Setuptools, whose documentation can be found at
|
||||
https://setuptools.pypa.io/en/latest/setuptools.html.
|
||||
|
||||
Normally, the initialization function returns a module definition initialized
|
||||
using :c:func:`PyModuleDef_Init`.
|
||||
This allows splitting the creation process into several phases:
|
||||
.. _extension-export-hook:
|
||||
|
||||
Extension export hook
|
||||
.....................
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Support for the :samp:`PyModExport_{<name>}` export hook was added in Python
|
||||
3.15. The older way of defining modules is still available: consult either
|
||||
the :ref:`extension-pyinit` section or earlier versions of this
|
||||
documentation if you plan to support earlier Python versions.
|
||||
|
||||
The export hook must be an exported function with the following signature:
|
||||
|
||||
.. c:function:: PyModuleDef_Slot *PyModExport_modulename(void)
|
||||
|
||||
For modules with ASCII-only names, the :ref:`export hook <extension-export-hook>`
|
||||
must be named :samp:`PyModExport_{<name>}`,
|
||||
with ``<name>`` replaced by the module's name.
|
||||
|
||||
For non-ASCII module names, the export hook must instead be named
|
||||
:samp:`PyModExportU_{<name>}` (note the ``U``), with ``<name>`` encoded using
|
||||
Python's *punycode* encoding with hyphens replaced by underscores. In Python:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def hook_name(name):
|
||||
try:
|
||||
suffix = b'_' + name.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
||||
return b'PyModExport' + suffix
|
||||
|
||||
The export hook returns an array of :c:type:`PyModuleDef_Slot` entries,
|
||||
terminated by an entry with a slot ID of ``0``.
|
||||
These slots describe how the module should be created and initialized.
|
||||
|
||||
This array must remain valid and constant until interpreter shutdown.
|
||||
Typically, it should use ``static`` storage.
|
||||
Prefer using the :c:macro:`Py_mod_create` and :c:macro:`Py_mod_exec` slots
|
||||
for any dynamic behavior.
|
||||
|
||||
The export hook may return ``NULL`` with an exception set to signal failure.
|
||||
|
||||
It is recommended to define the export hook function using a helper macro:
|
||||
|
||||
.. c:macro:: PyMODEXPORT_FUNC
|
||||
|
||||
Declare an extension module export hook.
|
||||
This macro:
|
||||
|
||||
* specifies the :c:expr:`PyModuleDef_Slot*` return type,
|
||||
* adds any special linkage declarations required by the platform, and
|
||||
* for C++, declares the function as ``extern "C"``.
|
||||
|
||||
For example, a module called ``spam`` would be defined like this::
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
static PyModuleDef_Slot spam_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
{Py_mod_name, "spam"},
|
||||
{Py_mod_init, spam_init_function},
|
||||
...
|
||||
{0, NULL},
|
||||
};
|
||||
|
||||
PyMODEXPORT_FUNC
|
||||
PyModExport_spam(void)
|
||||
{
|
||||
return spam_slots;
|
||||
}
|
||||
|
||||
The export hook is typically the only non-\ ``static``
|
||||
item defined in the module's C source.
|
||||
|
||||
The hook should be kept short -- ideally, one line as above.
|
||||
If you do need to use Python C API in this function, it is recommended to call
|
||||
``PyABIInfo_Check(&abi_info, "modulename")`` first to raise an exception,
|
||||
rather than crash, in common cases of ABI mismatch.
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
It is possible to export multiple modules from a single shared library by
|
||||
defining multiple export hooks.
|
||||
However, importing them requires a custom importer or suitably named
|
||||
copies/links of the extension file, because Python's import machinery only
|
||||
finds the function corresponding to the filename.
|
||||
See the `Multiple modules in one library <https://peps.python.org/pep-0489/#multiple-modules-in-one-library>`__
|
||||
section in :pep:`489` for details.
|
||||
|
||||
|
||||
.. _multi-phase-initialization:
|
||||
|
||||
Multi-phase initialization
|
||||
..........................
|
||||
|
||||
The process of creating an extension module follows several phases:
|
||||
|
||||
- Python finds and calls the export hook to get information on how to
|
||||
create the module.
|
||||
- Before any substantial code is executed, Python can determine which
|
||||
capabilities the module supports, and it can adjust the environment or
|
||||
refuse loading an incompatible extension.
|
||||
- By default, Python itself creates the module object -- that is, it does
|
||||
the equivalent of :py:meth:`object.__new__` for classes.
|
||||
It also sets initial attributes like :attr:`~module.__package__` and
|
||||
:attr:`~module.__loader__`.
|
||||
- Afterwards, the module object is initialized using extension-specific
|
||||
code -- the equivalent of :py:meth:`~object.__init__` on classes.
|
||||
Slots like :c:data:`Py_mod_abi`, :c:data:`Py_mod_gil` and
|
||||
:c:data:`Py_mod_multiple_interpreters` influence this step.
|
||||
- By default, Python itself then creates the module object -- that is, it does
|
||||
the equivalent of calling :py:meth:`~object.__new__` when creating an object.
|
||||
This step can be overridden using the :c:data:`Py_mod_create` slot.
|
||||
- Python sets initial module attributes like :attr:`~module.__package__` and
|
||||
:attr:`~module.__loader__`, and inserts the module object into
|
||||
:py:attr:`sys.modules`.
|
||||
- Afterwards, the module object is initialized in an extension-specific way
|
||||
-- the equivalent of :py:meth:`~object.__init__` when creating an object,
|
||||
or of executing top-level code in a Python-language module.
|
||||
The behavior is specified using the :c:data:`Py_mod_exec` slot.
|
||||
|
||||
This is called *multi-phase initialization* to distinguish it from the legacy
|
||||
(but still supported) *single-phase initialization* scheme,
|
||||
where the initialization function returns a fully constructed module.
|
||||
See the :ref:`single-phase-initialization section below <single-phase-initialization>`
|
||||
for details.
|
||||
(but still supported) :ref:`single-phase initialization <single-phase-initialization>`,
|
||||
where an initialization function returns a fully constructed module.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
|
|
@ -53,7 +156,7 @@ Multiple module instances
|
|||
|
||||
By default, extension modules are not singletons.
|
||||
For example, if the :py:attr:`sys.modules` entry is removed and the module
|
||||
is re-imported, a new module object is created, and typically populated with
|
||||
is re-imported, a new module object is created and, typically, populated with
|
||||
fresh method and type objects.
|
||||
The old module is subject to normal garbage collection.
|
||||
This mirrors the behavior of pure-Python modules.
|
||||
|
|
@ -83,36 +186,34 @@ A module may also be limited to the main interpreter using
|
|||
the :c:data:`Py_mod_multiple_interpreters` slot.
|
||||
|
||||
|
||||
.. _extension-export-hook:
|
||||
.. _extension-pyinit:
|
||||
|
||||
Initialization function
|
||||
.......................
|
||||
``PyInit`` function
|
||||
...................
|
||||
|
||||
The initialization function defined by an extension module has the
|
||||
following signature:
|
||||
.. deprecated:: next
|
||||
|
||||
This functionality is :term:`soft deprecated`.
|
||||
It will not get new features, but there are no plans to remove it.
|
||||
|
||||
Instead of :c:func:`PyModExport_modulename`, an extension module can define
|
||||
an older-style :dfn:`initialization function` with the signature:
|
||||
|
||||
.. c:function:: PyObject* PyInit_modulename(void)
|
||||
|
||||
Its name should be :samp:`PyInit_{<name>}`, with ``<name>`` replaced by the
|
||||
name of the module.
|
||||
For non-ASCII module names, use :samp:`PyInitU_{<name>}` instead, with
|
||||
``<name>`` encoded in the same way as for the
|
||||
:ref:`export hook <extension-export-hook>` (that is, using Punycode
|
||||
with underscores).
|
||||
|
||||
For modules with ASCII-only names, the function must instead be named
|
||||
:samp:`PyInit_{<name>}`, with ``<name>`` replaced by the name of the module.
|
||||
When using :ref:`multi-phase-initialization`, non-ASCII module names
|
||||
are allowed. In this case, the initialization function name is
|
||||
:samp:`PyInitU_{<name>}`, with ``<name>`` encoded using Python's
|
||||
*punycode* encoding with hyphens replaced by underscores. In Python:
|
||||
If a module exports both :samp:`PyInit_{<name>}` and
|
||||
:samp:`PyModExport_{<name>}`, the :samp:`PyInit_{<name>}` function
|
||||
is ignored.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def initfunc_name(name):
|
||||
try:
|
||||
suffix = b'_' + name.encode('ascii')
|
||||
except UnicodeEncodeError:
|
||||
suffix = b'U_' + name.encode('punycode').replace(b'-', b'_')
|
||||
return b'PyInit' + suffix
|
||||
|
||||
It is recommended to define the initialization function using a helper macro:
|
||||
Like with :c:macro:`PyMODEXPORT_FUNC`, it is recommended to define the
|
||||
initialization function using a helper macro:
|
||||
|
||||
.. c:macro:: PyMODINIT_FUNC
|
||||
|
||||
|
|
@ -123,6 +224,34 @@ It is recommended to define the initialization function using a helper macro:
|
|||
* adds any special linkage declarations required by the platform, and
|
||||
* for C++, declares the function as ``extern "C"``.
|
||||
|
||||
|
||||
Normally, the initialization function (``PyInit_modulename``) returns
|
||||
a :c:type:`PyModuleDef` instance with non-``NULL``
|
||||
:c:member:`~PyModuleDef.m_slots`. This allows Python to use
|
||||
:ref:`multi-phase initialization <multi-phase-initialization>`.
|
||||
|
||||
Before it is returned, the ``PyModuleDef`` instance must be initialized
|
||||
using the following function:
|
||||
|
||||
.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def)
|
||||
|
||||
Ensure a module definition is a properly initialized Python object that
|
||||
correctly reports its type and a reference count.
|
||||
|
||||
Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred.
|
||||
|
||||
Calling this function is required before returning a :c:type:`PyModuleDef`
|
||||
from a module initialization function.
|
||||
It should not be used in other contexts.
|
||||
|
||||
Note that Python assumes that ``PyModuleDef`` structures are statically
|
||||
allocated.
|
||||
This function may return either a new reference or a borrowed one;
|
||||
this reference must not be released.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
||||
For example, a module called ``spam`` would be defined like this::
|
||||
|
||||
static struct PyModuleDef spam_module = {
|
||||
|
|
@ -137,59 +266,23 @@ For example, a module called ``spam`` would be defined like this::
|
|||
return PyModuleDef_Init(&spam_module);
|
||||
}
|
||||
|
||||
It is possible to export multiple modules from a single shared library by
|
||||
defining multiple initialization functions. However, importing them requires
|
||||
using symbolic links or a custom importer, because by default only the
|
||||
function corresponding to the filename is found.
|
||||
See the `Multiple modules in one library <https://peps.python.org/pep-0489/#multiple-modules-in-one-library>`__
|
||||
section in :pep:`489` for details.
|
||||
|
||||
The initialization function is typically the only non-\ ``static``
|
||||
item defined in the module's C source.
|
||||
|
||||
|
||||
.. _multi-phase-initialization:
|
||||
|
||||
Multi-phase initialization
|
||||
..........................
|
||||
|
||||
Normally, the :ref:`initialization function <extension-export-hook>`
|
||||
(``PyInit_modulename``) returns a :c:type:`PyModuleDef` instance with
|
||||
non-``NULL`` :c:member:`~PyModuleDef.m_slots`.
|
||||
Before it is returned, the ``PyModuleDef`` instance must be initialized
|
||||
using the following function:
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyModuleDef_Init(PyModuleDef *def)
|
||||
|
||||
Ensure a module definition is a properly initialized Python object that
|
||||
correctly reports its type and a reference count.
|
||||
|
||||
Return *def* cast to ``PyObject*``, or ``NULL`` if an error occurred.
|
||||
|
||||
Calling this function is required for :ref:`multi-phase-initialization`.
|
||||
It should not be used in other contexts.
|
||||
|
||||
Note that Python assumes that ``PyModuleDef`` structures are statically
|
||||
allocated.
|
||||
This function may return either a new reference or a borrowed one;
|
||||
this reference must not be released.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
|
||||
.. _single-phase-initialization:
|
||||
|
||||
Legacy single-phase initialization
|
||||
..................................
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. attention::
|
||||
Single-phase initialization is a legacy mechanism to initialize extension
|
||||
.. deprecated:: next
|
||||
|
||||
Single-phase initialization is :term:`soft deprecated`.
|
||||
It is a legacy mechanism to initialize extension
|
||||
modules, with known drawbacks and design flaws. Extension module authors
|
||||
are encouraged to use multi-phase initialization instead.
|
||||
|
||||
In single-phase initialization, the
|
||||
:ref:`initialization function <extension-export-hook>` (``PyInit_modulename``)
|
||||
However, there are no plans to remove support for it.
|
||||
|
||||
In single-phase initialization, the old-style
|
||||
:ref:`initializaton function <extension-pyinit>` (``PyInit_modulename``)
|
||||
should create, populate and return a module object.
|
||||
This is typically done using :c:func:`PyModule_Create` and functions like
|
||||
:c:func:`PyModule_AddObjectRef`.
|
||||
|
|
@ -242,6 +335,8 @@ in the following ways:
|
|||
* Single-phase modules support module lookup functions like
|
||||
:c:func:`PyState_FindModule`.
|
||||
|
||||
* The module's :c:member:`PyModuleDef.m_slots` must be NULL.
|
||||
|
||||
.. [#testsinglephase] ``_testsinglephase`` is an internal module used
|
||||
in CPython's self-test suite; your installation may or may not
|
||||
include it.
|
||||
|
|
|
|||
|
|
@ -44,3 +44,41 @@ than explicitly calling :c:func:`PyGen_New` or :c:func:`PyGen_NewWithQualName`.
|
|||
with ``__name__`` and ``__qualname__`` set to *name* and *qualname*.
|
||||
A reference to *frame* is stolen by this function. The *frame* argument
|
||||
must not be ``NULL``.
|
||||
|
||||
.. c:function:: PyCodeObject* PyGen_GetCode(PyGenObject *gen)
|
||||
|
||||
Return a new :term:`strong reference` to the code object wrapped by *gen*.
|
||||
This function always succeeds.
|
||||
|
||||
|
||||
Asynchronous Generator Objects
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
.. seealso::
|
||||
:pep:`525`
|
||||
|
||||
.. c:var:: PyTypeObject PyAsyncGen_Type
|
||||
|
||||
The type object corresponding to asynchronous generator objects. This is
|
||||
available as :class:`types.AsyncGeneratorType` in the Python layer.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. c:function:: PyObject *PyAsyncGen_New(PyFrameObject *frame, PyObject *name, PyObject *qualname)
|
||||
|
||||
Create a new asynchronous generator wrapping *frame*, with ``__name__`` and
|
||||
``__qualname__`` set to *name* and *qualname*. *frame* is stolen by this
|
||||
function and must not be ``NULL``.
|
||||
|
||||
On success, this function returns a :term:`strong reference` to the
|
||||
new asynchronous generator. On failure, this function returns ``NULL``
|
||||
with an exception set.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
||||
.. c:function:: int PyAsyncGen_CheckExact(PyObject *op)
|
||||
|
||||
Return true if *op* is an asynchronous generator object, false otherwise.
|
||||
This function always succeeds.
|
||||
|
||||
.. versionadded:: 3.6
|
||||
|
|
|
|||
|
|
@ -314,6 +314,13 @@ Importing Modules
|
|||
initialization.
|
||||
|
||||
|
||||
.. c:var:: struct _inittab *PyImport_Inittab
|
||||
|
||||
The table of built-in modules used by Python initialization. Do not use this directly;
|
||||
use :c:func:`PyImport_AppendInittab` and :c:func:`PyImport_ExtendInittab`
|
||||
instead.
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyImport_ImportModuleAttr(PyObject *mod_name, PyObject *attr_name)
|
||||
|
||||
Import the module *mod_name* and get its attribute *attr_name*.
|
||||
|
|
@ -346,7 +353,7 @@ Importing Modules
|
|||
the same as for :c:func:`PyImport_AppendInittab`.
|
||||
|
||||
On success, create and return a module object.
|
||||
This module will not be initialized; call :c:func:`!PyModule_Exec`
|
||||
This module will not be initialized; call :c:func:`PyModule_Exec`
|
||||
to initialize it.
|
||||
(Custom importers should do this in their
|
||||
:py:meth:`~importlib.abc.Loader.exec_module` method.)
|
||||
|
|
|
|||
|
|
@ -1717,7 +1717,8 @@ function. You can create and destroy them using the following functions:
|
|||
Only C-level static and global variables are shared between these
|
||||
module objects.
|
||||
|
||||
* For modules using single-phase initialization,
|
||||
* For modules using legacy
|
||||
:ref:`single-phase initialization <single-phase-initialization>`,
|
||||
e.g. :c:func:`PyModule_Create`, the first time a particular extension
|
||||
is imported, it is initialized normally, and a (shallow) copy of its
|
||||
module's dictionary is squirreled away.
|
||||
|
|
@ -1891,6 +1892,25 @@ pointer and a void pointer argument.
|
|||
This function now always schedules *func* to be run in the main
|
||||
interpreter.
|
||||
|
||||
|
||||
.. c:function:: int Py_MakePendingCalls(void)
|
||||
|
||||
Execute all pending calls. This is usually executed automatically by the
|
||||
interpreter.
|
||||
|
||||
This function returns ``0`` on success, and returns ``-1`` with an exception
|
||||
set on failure.
|
||||
|
||||
If this is not called in the main thread of the main
|
||||
interpreter, this function does nothing and returns ``0``.
|
||||
The caller must hold an :term:`attached thread state`.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
This function only runs pending calls in the main interpreter.
|
||||
|
||||
|
||||
.. _profiling:
|
||||
|
||||
Profiling and Tracing
|
||||
|
|
@ -2520,3 +2540,220 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
|
|||
In the default build, this macro expands to ``}``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
|
||||
Legacy Locking APIs
|
||||
-------------------
|
||||
|
||||
These APIs are obsolete since Python 3.13 with the introduction of
|
||||
:c:type:`PyMutex`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
These APIs are now a simple wrapper around ``PyMutex``.
|
||||
|
||||
|
||||
.. c:type:: PyThread_type_lock
|
||||
|
||||
A pointer to a mutual exclusion lock.
|
||||
|
||||
|
||||
.. c:type:: PyLockStatus
|
||||
|
||||
The result of acquiring a lock with a timeout.
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
.. c:enumerator:: PY_LOCK_FAILURE
|
||||
|
||||
Failed to acquire the lock.
|
||||
|
||||
.. c:enumerator:: PY_LOCK_ACQUIRED
|
||||
|
||||
The lock was successfully acquired.
|
||||
|
||||
.. c:enumerator:: PY_LOCK_INTR
|
||||
|
||||
The lock was interrupted by a signal.
|
||||
|
||||
|
||||
.. c:function:: PyThread_type_lock PyThread_allocate_lock(void)
|
||||
|
||||
Allocate a new lock.
|
||||
|
||||
On success, this function returns a lock; on failure, this
|
||||
function returns ``0`` without an exception set.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
.. versionchanged:: 3.15
|
||||
This function now always uses :c:type:`PyMutex`. In prior versions, this
|
||||
would use a lock provided by the operating system.
|
||||
|
||||
|
||||
.. c:function:: void PyThread_free_lock(PyThread_type_lock lock)
|
||||
|
||||
Destroy *lock*. The lock should not be held by any thread when calling
|
||||
this.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
|
||||
|
||||
Acquire *lock* with a timeout.
|
||||
|
||||
This will wait for *microseconds* microseconds to acquire the lock. If the
|
||||
timeout expires, this function returns :c:enumerator:`PY_LOCK_FAILURE`.
|
||||
If *microseconds* is ``-1``, this will wait indefinitely until the lock has
|
||||
been released.
|
||||
|
||||
If *intr_flag* is ``1``, acquiring the lock may be interrupted by a signal,
|
||||
in which case this function returns :c:enumerator:`PY_LOCK_INTR`. Upon
|
||||
interruption, it's generally expected that the caller makes a call to
|
||||
:c:func:`Py_MakePendingCalls` to propagate an exception to Python code.
|
||||
|
||||
If the lock is successfully acquired, this function returns
|
||||
:c:enumerator:`PY_LOCK_ACQUIRED`.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
|
||||
|
||||
Acquire *lock*.
|
||||
|
||||
If *waitflag* is ``1`` and another thread currently holds the lock, this
|
||||
function will wait until the lock can be acquired and will always return
|
||||
``1``.
|
||||
|
||||
If *waitflag* is ``0`` and another thread holds the lock, this function will
|
||||
not wait and instead return ``0``. If the lock is not held by any other
|
||||
thread, then this function will acquire it and return ``1``.
|
||||
|
||||
Unlike :c:func:`PyThread_acquire_lock_timed`, acquiring the lock cannot be
|
||||
interrupted by a signal.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_release_lock(PyThread_type_lock lock)
|
||||
|
||||
Release *lock*. If *lock* is not held, then this function issues a
|
||||
fatal error.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
Operating System Thread APIs
|
||||
============================
|
||||
|
||||
.. c:macro:: PYTHREAD_INVALID_THREAD_ID
|
||||
|
||||
Sentinel value for an invalid thread ID.
|
||||
|
||||
This is currently equivalent to ``(unsigned long)-1``.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg)
|
||||
|
||||
Start function *func* in a new thread with argument *arg*.
|
||||
The resulting thread is not intended to be joined.
|
||||
|
||||
*func* must not be ``NULL``, but *arg* may be ``NULL``.
|
||||
|
||||
On success, this function returns the identifier of the new thread; on failure,
|
||||
this returns :c:macro:`PYTHREAD_INVALID_THREAD_ID`.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_get_thread_ident(void)
|
||||
|
||||
Return the identifier of the current thread, which will never be zero.
|
||||
|
||||
This function cannot fail, and the caller does not need to hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`threading.get_ident`
|
||||
|
||||
|
||||
.. c:function:: PyObject *PyThread_GetInfo(void)
|
||||
|
||||
Get general information about the current thread in the form of a
|
||||
:ref:`struct sequence <struct-sequence-objects>` object. This information is
|
||||
accessible as :py:attr:`sys.thread_info` in Python.
|
||||
|
||||
On success, this returns a new :term:`strong reference` to the thread
|
||||
information; on failure, this returns ``NULL`` with an exception set.
|
||||
|
||||
The caller must hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:macro:: PY_HAVE_THREAD_NATIVE_ID
|
||||
|
||||
This macro is defined when the system supports native thread IDs.
|
||||
|
||||
|
||||
.. c:function:: unsigned long PyThread_get_thread_native_id(void)
|
||||
|
||||
Get the native identifier of the current thread as it was assigned by the operating
|
||||
system's kernel, which will never be less than zero.
|
||||
|
||||
This function is only available when :c:macro:`PY_HAVE_THREAD_NATIVE_ID` is
|
||||
defined.
|
||||
|
||||
This function cannot fail, and the caller does not need to hold an
|
||||
:term:`attached thread state`.
|
||||
|
||||
.. seealso::
|
||||
:py:func:`threading.get_native_id`
|
||||
|
||||
|
||||
.. c:function:: void PyThread_exit_thread(void)
|
||||
|
||||
Terminate the current thread. This function is generally considered unsafe
|
||||
and should be avoided. It is kept solely for backwards compatibility.
|
||||
|
||||
This function is only safe to call if all functions in the full call
|
||||
stack are written to safely allow it.
|
||||
|
||||
.. warning::
|
||||
|
||||
If the current system uses POSIX threads (also known as "pthreads"),
|
||||
this calls :manpage:`pthread_exit(3)`, which attempts to unwind the stack
|
||||
and call C++ destructors on some libc implementations. However, if a
|
||||
``noexcept`` function is reached, it may terminate the process.
|
||||
Other systems, such as macOS, do unwinding.
|
||||
|
||||
On Windows, this function calls ``_endthreadex()``, which kills the thread
|
||||
without calling C++ destructors.
|
||||
|
||||
In any case, there is a risk of corruption on the thread's stack.
|
||||
|
||||
.. deprecated:: 3.14
|
||||
|
||||
|
||||
.. c:function:: void PyThread_init_thread(void)
|
||||
|
||||
Initialize ``PyThread*`` APIs. Python executes this function automatically,
|
||||
so there's little need to call it from an extension module.
|
||||
|
||||
|
||||
.. c:function:: int PyThread_set_stacksize(size_t size)
|
||||
|
||||
Set the stack size of the current thread to *size* bytes.
|
||||
|
||||
This function returns ``0`` on success, ``-1`` if *size* is invalid, or
|
||||
``-2`` if the system does not support changing the stack size. This function
|
||||
does not set exceptions.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
||||
|
||||
.. c:function:: size_t PyThread_get_stacksize(void)
|
||||
|
||||
Return the stack size of the current thread in bytes, or ``0`` if the system's
|
||||
default stack size is in use.
|
||||
|
||||
The caller does not need to hold an :term:`attached thread state`.
|
||||
|
|
|
|||
|
|
@ -171,6 +171,17 @@ complete listing.
|
|||
Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the
|
||||
command line (see :c:member:`PyConfig.use_environment`).
|
||||
|
||||
.. c:macro:: Py_LOCAL(type)
|
||||
|
||||
Declare a function returning the specified *type* using a fast-calling
|
||||
qualifier for functions that are local to the current file.
|
||||
Semantically, this is equivalent to ``static type``.
|
||||
|
||||
.. c:macro:: Py_LOCAL_INLINE(type)
|
||||
|
||||
Equivalent to :c:macro:`Py_LOCAL` but additionally requests the function
|
||||
be inlined.
|
||||
|
||||
.. c:macro:: Py_MAX(x, y)
|
||||
|
||||
Return the maximum value between ``x`` and ``y``.
|
||||
|
|
@ -311,6 +322,19 @@ complete listing.
|
|||
PyDoc_VAR(python_doc) = PyDoc_STR("A genus of constricting snakes in the Pythonidae family native "
|
||||
"to the tropics and subtropics of the Eastern Hemisphere.");
|
||||
|
||||
.. c:macro:: Py_ARRAY_LENGTH(array)
|
||||
|
||||
Compute the length of a statically allocated C array at compile time.
|
||||
|
||||
The *array* argument must be a C array with a size known at compile time.
|
||||
Passing an array with an unknown size, such as a heap-allocated array,
|
||||
will result in a compilation error on some compilers, or otherwise produce
|
||||
incorrect results.
|
||||
|
||||
This is roughly equivalent to::
|
||||
|
||||
sizeof(array) / sizeof((array)[0])
|
||||
|
||||
|
||||
.. _api-objects:
|
||||
|
||||
|
|
|
|||
|
|
@ -3,11 +3,10 @@
|
|||
.. _moduleobjects:
|
||||
|
||||
Module Objects
|
||||
--------------
|
||||
==============
|
||||
|
||||
.. index:: pair: object; module
|
||||
|
||||
|
||||
.. c:var:: PyTypeObject PyModule_Type
|
||||
|
||||
.. index:: single: ModuleType (in module types)
|
||||
|
|
@ -97,13 +96,6 @@ Module Objects
|
|||
Note that Python code may rename a module by setting its :py:attr:`~module.__name__`
|
||||
attribute.
|
||||
|
||||
.. c:function:: void* PyModule_GetState(PyObject *module)
|
||||
|
||||
Return the "state" of the module, that is, a pointer to the block of memory
|
||||
allocated at module creation time, or ``NULL``. See
|
||||
:c:member:`PyModuleDef.m_size`.
|
||||
|
||||
|
||||
.. c:function:: PyModuleDef* PyModule_GetDef(PyObject *module)
|
||||
|
||||
Return a pointer to the :c:type:`PyModuleDef` struct from which the module was
|
||||
|
|
@ -141,210 +133,108 @@ Module Objects
|
|||
unencodable filenames, use :c:func:`PyModule_GetFilenameObject` instead.
|
||||
|
||||
|
||||
.. _pymoduledef:
|
||||
.. _pymoduledef_slot:
|
||||
|
||||
Module definitions
|
||||
------------------
|
||||
Module definition
|
||||
-----------------
|
||||
|
||||
The functions in the previous section work on any module object, including
|
||||
modules imported from Python code.
|
||||
Modules created using the C API are typically defined using an
|
||||
array of :dfn:`slots`.
|
||||
The slots provide a "description" of how a module should be created.
|
||||
|
||||
Modules defined using the C API typically use a *module definition*,
|
||||
:c:type:`PyModuleDef` -- a statically allocated, constant “description" of
|
||||
how a module should be created.
|
||||
.. versionchanged:: next
|
||||
|
||||
The definition is usually used to define an extension's “main” module object
|
||||
(see :ref:`extension-modules` for details).
|
||||
It is also used to
|
||||
:ref:`create extension modules dynamically <moduledef-dynamic>`.
|
||||
Previously, a :c:type:`PyModuleDef` struct was necessary to define modules.
|
||||
The older way of defining modules is still available: consult either the
|
||||
:ref:`pymoduledef` section or earlier versions of this documentation
|
||||
if you plan to support earlier Python versions.
|
||||
|
||||
Unlike :c:func:`PyModule_New`, the definition allows management of
|
||||
*module state* -- a piece of memory that is allocated and cleared together
|
||||
with the module object.
|
||||
Unlike the module's Python attributes, Python code cannot replace or delete
|
||||
data stored in module state.
|
||||
The slots array is usually used to define an extension module's “main”
|
||||
module object (see :ref:`extension-modules` for details).
|
||||
It can also be used to
|
||||
:ref:`create extension modules dynamically <module-from-slots>`.
|
||||
|
||||
.. c:type:: PyModuleDef
|
||||
Unless specified otherwise, the same slot ID may not be repeated
|
||||
in an array of slots.
|
||||
|
||||
The module definition struct, which holds all information needed to create
|
||||
a module object.
|
||||
This structure must be statically allocated (or be otherwise guaranteed
|
||||
to be valid while any modules created from it exist).
|
||||
Usually, there is only one variable of this type for each extension module.
|
||||
|
||||
.. c:member:: PyModuleDef_Base m_base
|
||||
|
||||
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`.
|
||||
|
||||
.. c:member:: const char *m_name
|
||||
|
||||
Name for the new module.
|
||||
|
||||
.. c:member:: const char *m_doc
|
||||
|
||||
Docstring for the module; usually a docstring variable created with
|
||||
:c:macro:`PyDoc_STRVAR` is used.
|
||||
|
||||
.. c:member:: Py_ssize_t m_size
|
||||
|
||||
Module state may be kept in a per-module memory area that can be
|
||||
retrieved with :c:func:`PyModule_GetState`, rather than in static globals.
|
||||
This makes modules safe for use in multiple sub-interpreters.
|
||||
|
||||
This memory area is allocated based on *m_size* on module creation,
|
||||
and freed when the module object is deallocated, after the
|
||||
:c:member:`~PyModuleDef.m_free` function has been called, if present.
|
||||
|
||||
Setting it to a non-negative value means that the module can be
|
||||
re-initialized and specifies the additional amount of memory it requires
|
||||
for its state.
|
||||
|
||||
Setting ``m_size`` to ``-1`` means that the module does not support
|
||||
sub-interpreters, because it has global state.
|
||||
Negative ``m_size`` is only allowed when using
|
||||
:ref:`legacy single-phase initialization <single-phase-initialization>`
|
||||
or when :ref:`creating modules dynamically <moduledef-dynamic>`.
|
||||
|
||||
See :PEP:`3121` for more details.
|
||||
|
||||
.. c:member:: PyMethodDef* m_methods
|
||||
|
||||
A pointer to a table of module-level functions, described by
|
||||
:c:type:`PyMethodDef` values. Can be ``NULL`` if no functions are present.
|
||||
|
||||
.. c:member:: PyModuleDef_Slot* m_slots
|
||||
|
||||
An array of slot definitions for multi-phase initialization, terminated by
|
||||
a ``{0, NULL}`` entry.
|
||||
When using legacy single-phase initialization, *m_slots* must be ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Prior to version 3.5, this member was always set to ``NULL``,
|
||||
and was defined as:
|
||||
|
||||
.. c:member:: inquiry m_reload
|
||||
|
||||
.. c:member:: traverseproc m_traverse
|
||||
|
||||
A traversal function to call during GC traversal of the module object, or
|
||||
``NULL`` if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
.. c:member:: inquiry m_clear
|
||||
|
||||
A clear function to call during GC clearing of the module object, or
|
||||
``NULL`` if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
Like :c:member:`PyTypeObject.tp_clear`, this function is not *always*
|
||||
called before a module is deallocated. For example, when reference
|
||||
counting is enough to determine that an object is no longer used,
|
||||
the cyclic garbage collector is not involved and
|
||||
:c:member:`~PyModuleDef.m_free` is called directly.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
.. c:member:: freefunc m_free
|
||||
|
||||
A function to call during deallocation of the module object, or ``NULL``
|
||||
if not needed.
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if :c:member:`~PyModuleDef.m_size` is greater
|
||||
than 0 and the module state (as returned by :c:func:`PyModule_GetState`)
|
||||
is ``NULL``.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
No longer called before the module state is allocated.
|
||||
|
||||
|
||||
Module slots
|
||||
............
|
||||
|
||||
.. c:type:: PyModuleDef_Slot
|
||||
|
||||
.. c:member:: int slot
|
||||
|
||||
A slot ID, chosen from the available values explained below.
|
||||
A slot ID, chosen from the available ``Py_mod_*`` values explained below.
|
||||
|
||||
An ID of 0 marks the end of a :c:type:`!PyModuleDef_Slot` array.
|
||||
|
||||
.. c:member:: void* value
|
||||
|
||||
Value of the slot, whose meaning depends on the slot ID.
|
||||
|
||||
The value may not be NULL.
|
||||
To leave a slot out, omit the :c:type:`PyModuleDef_Slot` entry entirely.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
The available slot types are:
|
||||
|
||||
.. c:macro:: Py_mod_create
|
||||
Metadata slots
|
||||
..............
|
||||
|
||||
Specifies a function that is called to create the module object itself.
|
||||
The *value* pointer of this slot must point to a function of the signature:
|
||||
.. c:macro:: Py_mod_name
|
||||
|
||||
.. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the name of the new module,
|
||||
as a NUL-terminated UTF8-encoded ``const char *``.
|
||||
|
||||
The function receives a :py:class:`~importlib.machinery.ModuleSpec`
|
||||
instance, as defined in :PEP:`451`, and the module definition.
|
||||
It should return a new module object, or set an error
|
||||
and return ``NULL``.
|
||||
Note that modules are typically created using a
|
||||
:py:class:`~importlib.machinery.ModuleSpec`, and when they are, the
|
||||
name from the spec will be used instead of :c:data:`!Py_mod_name`.
|
||||
However, it is still recommended to include this slot for introspection
|
||||
and debugging purposes.
|
||||
|
||||
This function should be kept minimal. In particular, it should not
|
||||
call arbitrary Python code, as trying to import the same module again may
|
||||
result in an infinite loop.
|
||||
.. versionadded:: next
|
||||
|
||||
Multiple ``Py_mod_create`` slots may not be specified in one module
|
||||
definition.
|
||||
Use :c:member:`PyModuleDef.m_name` instead to support previous versions.
|
||||
|
||||
If ``Py_mod_create`` is not specified, the import machinery will create
|
||||
a normal module object using :c:func:`PyModule_New`. The name is taken from
|
||||
*spec*, not the definition, to allow extension modules to dynamically adjust
|
||||
to their place in the module hierarchy and be imported under different
|
||||
names through symlinks, all while sharing a single module definition.
|
||||
.. c:macro:: Py_mod_doc
|
||||
|
||||
There is no requirement for the returned object to be an instance of
|
||||
:c:type:`PyModule_Type`. Any type can be used, as long as it supports
|
||||
setting and getting import-related attributes.
|
||||
However, only ``PyModule_Type`` instances may be returned if the
|
||||
``PyModuleDef`` has non-``NULL`` ``m_traverse``, ``m_clear``,
|
||||
``m_free``; non-zero ``m_size``; or slots other than ``Py_mod_create``.
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the docstring of the new
|
||||
module, as a NUL-terminated UTF8-encoded ``const char *``.
|
||||
|
||||
.. c:macro:: Py_mod_exec
|
||||
Usually it is set to a variable created with :c:macro:`PyDoc_STRVAR`.
|
||||
|
||||
Specifies a function that is called to *execute* the module.
|
||||
This is equivalent to executing the code of a Python module: typically,
|
||||
this function adds classes and constants to the module.
|
||||
The signature of the function is:
|
||||
.. versionadded:: next
|
||||
|
||||
.. c:function:: int exec_module(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
Use :c:member:`PyModuleDef.m_doc` instead to support previous versions.
|
||||
|
||||
If multiple ``Py_mod_exec`` slots are specified, they are processed in the
|
||||
order they appear in the *m_slots* array.
|
||||
|
||||
Feature slots
|
||||
.............
|
||||
|
||||
.. c:macro:: Py_mod_abi
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value points to
|
||||
a :c:struct:`PyABIInfo` structure describing the ABI that
|
||||
the extension is using.
|
||||
|
||||
A suitable :c:struct:`!PyABIInfo` variable can be defined using the
|
||||
:c:macro:`PyABIInfo_VAR` macro, as in:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
|
||||
static PyModuleDef_Slot mymodule_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
...
|
||||
};
|
||||
|
||||
When creating a module, Python checks the value of this slot
|
||||
using :c:func:`PyABIInfo_Check`.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:macro:: Py_mod_multiple_interpreters
|
||||
|
||||
Specifies one of the following values:
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value is one of:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
|
|
@ -367,9 +257,6 @@ The available slot types are:
|
|||
This slot determines whether or not importing this module
|
||||
in a subinterpreter will fail.
|
||||
|
||||
Multiple ``Py_mod_multiple_interpreters`` slots may not be specified
|
||||
in one module definition.
|
||||
|
||||
If ``Py_mod_multiple_interpreters`` is not specified, the import
|
||||
machinery defaults to ``Py_MOD_MULTIPLE_INTERPRETERS_SUPPORTED``.
|
||||
|
||||
|
|
@ -377,7 +264,7 @@ The available slot types are:
|
|||
|
||||
.. c:macro:: Py_mod_gil
|
||||
|
||||
Specifies one of the following values:
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` whose value is one of:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
|
|
@ -395,45 +282,482 @@ The available slot types are:
|
|||
this module will cause the GIL to be automatically enabled. See
|
||||
:ref:`whatsnew313-free-threaded-cpython` for more detail.
|
||||
|
||||
Multiple ``Py_mod_gil`` slots may not be specified in one module definition.
|
||||
|
||||
If ``Py_mod_gil`` is not specified, the import machinery defaults to
|
||||
``Py_MOD_GIL_USED``.
|
||||
|
||||
.. versionadded:: 3.13
|
||||
|
||||
.. c:macro:: Py_mod_abi
|
||||
|
||||
A pointer to a :c:struct:`PyABIInfo` structure that describes the ABI that
|
||||
the extension is using.
|
||||
Creation and initialization slots
|
||||
.................................
|
||||
|
||||
When the module is loaded, the :c:struct:`!PyABIInfo` in this slot is checked
|
||||
using :c:func:`PyABIInfo_Check`.
|
||||
.. c:macro:: Py_mod_create
|
||||
|
||||
A suitable :c:struct:`!PyABIInfo` variable can be defined using the
|
||||
:c:macro:`PyABIInfo_VAR` macro, as in:
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function that creates
|
||||
the module object itself.
|
||||
The function must have the signature:
|
||||
|
||||
.. code-block:: c
|
||||
.. c:function:: PyObject* create_module(PyObject *spec, PyModuleDef *def)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
PyABIInfo_VAR(abi_info);
|
||||
The function will be called with:
|
||||
|
||||
static PyModuleDef_Slot mymodule_slots[] = {
|
||||
{Py_mod_abi, &abi_info},
|
||||
...
|
||||
};
|
||||
- *spec*: a ``ModuleSpec``-like object, meaning that any attributes defined
|
||||
for :py:class:`importlib.machinery.ModuleSpec` have matching semantics.
|
||||
However, any of the attributes may be missing.
|
||||
- *def*: ``NULL``, or the module definition if the module is created from one.
|
||||
|
||||
.. versionadded:: 3.15
|
||||
The function should return a new module object, or set an error
|
||||
and return ``NULL``.
|
||||
|
||||
This function should be kept minimal. In particular, it should not
|
||||
call arbitrary Python code, as trying to import the same module again may
|
||||
result in an infinite loop.
|
||||
|
||||
If ``Py_mod_create`` is not specified, the import machinery will create
|
||||
a normal module object using :c:func:`PyModule_New`. The name is taken from
|
||||
*spec*, not the definition, to allow extension modules to dynamically adjust
|
||||
to their place in the module hierarchy and be imported under different
|
||||
names through symlinks, all while sharing a single module definition.
|
||||
|
||||
There is no requirement for the returned object to be an instance of
|
||||
:c:type:`PyModule_Type`.
|
||||
However, some slots may only be used with
|
||||
:c:type:`!PyModule_Type` instances; in particular:
|
||||
|
||||
- :c:macro:`Py_mod_exec`,
|
||||
- :ref:`module state slots <ext-module-state-slots>` (``Py_mod_state_*``),
|
||||
- :c:macro:`Py_mod_token`.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. versionchanged:: next
|
||||
|
||||
The *slots* argument may be a ``ModuleSpec``-like object, rather than
|
||||
a true :py:class:`~importlib.machinery.ModuleSpec` instance.
|
||||
Note that previous versions of CPython did not enforce this.
|
||||
|
||||
The *def* argument may now be ``NULL``, since modules are not necessarily
|
||||
made from definitions.
|
||||
|
||||
.. c:macro:: Py_mod_exec
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function that will
|
||||
:dfn:`execute`, or initialize, the module.
|
||||
This function does the equivalent to executing the code of a Python module:
|
||||
typically, it adds classes and constants to the module.
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int exec_module(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
See the :ref:`capi-module-support-functions` section for some useful
|
||||
functions to call.
|
||||
|
||||
For backwards compatibility, the :c:type:`PyModuleDef.m_slots` array may
|
||||
contain multiple :c:macro:`!Py_mod_exec` slots; these are processed in the
|
||||
order they appear in the array.
|
||||
Elsewhere (that is, in arguments to :c:func:`PyModule_FromSlotsAndSpec`
|
||||
and in return values of :samp:`PyModExport_{<name>}`), repeating the slot
|
||||
is not allowed.
|
||||
|
||||
.. versionadded:: 3.5
|
||||
|
||||
.. versionchanged:: next
|
||||
|
||||
Repeated ``Py_mod_exec`` slots are disallowed, except in
|
||||
:c:type:`PyModuleDef.m_slots`.
|
||||
|
||||
.. c:macro:: Py_mod_methods
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a table of module-level
|
||||
functions, as an array of :c:type:`PyMethodDef` values suitable as the
|
||||
*functions* argument to :c:func:`PyModule_AddFunctions`.
|
||||
|
||||
Like other slot IDs, a slots array may only contain one
|
||||
:c:macro:`!Py_mod_methods` entry.
|
||||
To add functions from multiple :c:type:`PyMethodDef` arrays, call
|
||||
:c:func:`PyModule_AddFunctions` in the :c:macro:`Py_mod_exec` function.
|
||||
|
||||
The table must be statically allocated (or otherwise guaranteed to outlive
|
||||
the module object).
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Use :c:member:`PyModuleDef.m_methods` instead to support previous versions.
|
||||
|
||||
.. _ext-module-state:
|
||||
|
||||
Module state
|
||||
------------
|
||||
|
||||
Extension modules can have *module state* -- a
|
||||
piece of memory that is allocated on module creation,
|
||||
and freed when the module object is deallocated.
|
||||
The module state is specified using :ref:`dedicated slots <ext-module-state-slots>`.
|
||||
|
||||
A typical use of module state is storing an exception type -- or indeed *any*
|
||||
type object defined by the module --
|
||||
|
||||
Unlike the module's Python attributes, Python code cannot replace or delete
|
||||
data stored in module state.
|
||||
|
||||
Keeping per-module information in attributes and module state, rather than in
|
||||
static globals, makes module objects *isolated* and safer for use in
|
||||
multiple sub-interpreters.
|
||||
It also helps Python do an orderly clean-up when it shuts down.
|
||||
|
||||
Extensions that keep references to Python objects as part of module state must
|
||||
implement :c:macro:`Py_mod_state_traverse` and :c:macro:`Py_mod_state_clear`
|
||||
functions to avoid reference leaks.
|
||||
|
||||
To retrieve the state from a given module, use the following functions:
|
||||
|
||||
.. c:function:: void* PyModule_GetState(PyObject *module)
|
||||
|
||||
Return the "state" of the module, that is, a pointer to the block of memory
|
||||
allocated at module creation time, or ``NULL``. See
|
||||
:c:macro:`Py_mod_state_size`.
|
||||
|
||||
On error, return ``NULL`` with an exception set.
|
||||
Use :c:func:`PyErr_Occurred` to tell this case apart from missing
|
||||
module state.
|
||||
|
||||
|
||||
.. _moduledef-dynamic:
|
||||
.. c:function:: int PyModule_GetStateSize(PyObject *, 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`),
|
||||
and return 0.
|
||||
|
||||
On error, set *\*result* to -1, and return -1 with an exception set.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
|
||||
|
||||
.. _ext-module-state-slots:
|
||||
|
||||
Slots for defining module state
|
||||
...............................
|
||||
|
||||
The following :c:member:`PyModuleDef_Slot.slot` IDs are available for
|
||||
defining the module state.
|
||||
|
||||
.. c:macro:: Py_mod_state_size
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the size of the module state,
|
||||
in bytes.
|
||||
|
||||
Setting the value to a non-negative value means that the module can be
|
||||
re-initialized and specifies the additional amount of memory it requires
|
||||
for its state.
|
||||
|
||||
See :PEP:`3121` for more details.
|
||||
|
||||
Use :c:func:`PyModule_GetStateSize` to retrieve the size of a given module.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_traverse
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a traversal function to call
|
||||
during GC traversal of the module object.
|
||||
|
||||
The signature of the function, and meanings of the arguments,
|
||||
is similar as for :c:member:`PyTypeObject.tp_traverse`:
|
||||
|
||||
.. c:function:: int traverse_module_state(PyObject *module, visitproc visit, void *arg)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Use :c:member:`PyModuleDef.m_size` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_clear
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a clear function to call
|
||||
during GC clearing of the module object.
|
||||
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int clear_module_state(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
Like :c:member:`PyTypeObject.tp_clear`, this function is not *always*
|
||||
called before a module is deallocated. For example, when reference
|
||||
counting is enough to determine that an object is no longer used,
|
||||
the cyclic garbage collector is not involved and
|
||||
the :c:macro:`Py_mod_state_free` function is called directly.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Use :c:member:`PyModuleDef.m_clear` instead to support previous versions.
|
||||
|
||||
.. c:macro:: Py_mod_state_free
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for a function to call during
|
||||
deallocation of the module object.
|
||||
|
||||
The signature of the function is:
|
||||
|
||||
.. c:function:: int free_module_state(PyObject* module)
|
||||
:no-index-entry:
|
||||
:no-contents-entry:
|
||||
|
||||
This function is not called if the module state was requested but is not
|
||||
allocated yet. This is the case immediately after the module is created
|
||||
and before the module is executed (:c:data:`Py_mod_exec` function). More
|
||||
precisely, this function is not called if the state size
|
||||
(:c:data:`Py_mod_state_size`) is greater than 0 and the module state
|
||||
(as returned by :c:func:`PyModule_GetState`) is ``NULL``.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
Use :c:member:`PyModuleDef.m_free` instead to support previous versions.
|
||||
|
||||
|
||||
.. _ext-module-token:
|
||||
|
||||
Module token
|
||||
............
|
||||
|
||||
Each module may have an associated *token*: a pointer-sized value intended to
|
||||
identify of the module state's memory layout.
|
||||
This means that if you have a module object, but you are not sure if it
|
||||
“belongs” to your extension, you can check using code like this:
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
PyObject *module = <the module in question>
|
||||
|
||||
void *module_token;
|
||||
if (PyModule_GetToken(module, &module_token) < 0) {
|
||||
return NULL;
|
||||
}
|
||||
if (module_token != your_token) {
|
||||
PyErr_SetString(PyExc_ValueError, "unexpected module")
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// This module's state has the expected memory layout; it's safe to cast
|
||||
struct my_state state = (struct my_state*)PyModule_GetState(module)
|
||||
|
||||
A module's token -- and the *your_token* value to use in the above code -- is:
|
||||
|
||||
- For modules created with :c:type:`PyModuleDef`: the address of that
|
||||
:c:type:`PyModuleDef`;
|
||||
- For modules defined with the :c:macro:`Py_mod_token` slot: the value
|
||||
of that slot;
|
||||
- For modules created from an ``PyModExport_*``
|
||||
:ref:`export hook <extension-export-hook>`: the slots array that the export
|
||||
hook returned (unless overriden with :c:macro:`Py_mod_token`).
|
||||
|
||||
.. c:macro:: Py_mod_token
|
||||
|
||||
:c:type:`Slot ID <PyModuleDef_Slot.slot>` for the module token.
|
||||
|
||||
If you use this slot to set the module token (rather than rely on the
|
||||
default), you must ensure that:
|
||||
|
||||
* The pointer outlives the class, so it's not reused for something else
|
||||
while the class exists.
|
||||
* It "belongs" to the extension module where the class lives, so it will not
|
||||
clash with other extensions.
|
||||
* If the token points to a :c:type:`PyModuleDef` struct, the module should
|
||||
behave as if it was created from that :c:type:`PyModuleDef`.
|
||||
In particular, the module state must have matching layout and semantics.
|
||||
|
||||
Modules created from :c:type:`PyModuleDef` allways use the address of
|
||||
the :c:type:`PyModuleDef` as the token.
|
||||
This means that :c:macro:`!Py_mod_token` cannot be used in
|
||||
:c:member:`PyModuleDef.m_slots`.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. c:function:: int PyModule_GetToken(PyObject *module, void** result)
|
||||
|
||||
Set *\*result* to the module's token and return 0.
|
||||
|
||||
On error, set *\*result* to NULL, and return -1 with an exception set.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
See also :c:func:`PyType_GetModuleByToken`.
|
||||
|
||||
|
||||
.. _module-from-slots:
|
||||
|
||||
Creating extension modules dynamically
|
||||
--------------------------------------
|
||||
|
||||
The following functions may be used to create a module outside of an
|
||||
extension's :ref:`initialization function <extension-export-hook>`.
|
||||
They are also used in
|
||||
:ref:`single-phase initialization <single-phase-initialization>`.
|
||||
The following functions may be used to create an extension module dynamically,
|
||||
rather than from an extension's :ref:`export hook <extension-export-hook>`.
|
||||
|
||||
.. c:function:: PyObject *PyModule_FromSlotsAndSpec(const PyModuleDef_Slot *slots, PyObject *spec)
|
||||
|
||||
Create a new module object, given an array of :ref:`slots <pymoduledef_slot>`
|
||||
and the :py:class:`~importlib.machinery.ModuleSpec` *spec*.
|
||||
|
||||
The *slots* argument must point to an array of :c:type:`PyModuleDef_Slot`
|
||||
structures, terminated by an entry slot with slot ID of 0
|
||||
(typically written as ``{0}`` or ``{0, NULL}`` in C).
|
||||
The *slots* argument may not be ``NULL``.
|
||||
|
||||
The *spec* argument may be any ``ModuleSpec``-like object, as described
|
||||
in :c:macro:`Py_mod_create` documentation.
|
||||
Currently, the *spec* must have a ``name`` attribute.
|
||||
|
||||
On success, return the new module.
|
||||
On error, return ``NULL`` with an exception set.
|
||||
|
||||
Note that this does not process the module's execution slot
|
||||
(:c:data:`Py_mod_exec`).
|
||||
Both :c:func:`!PyModule_FromSlotsAndSpec` and :c:func:`PyModule_Exec`
|
||||
must be called to fully initialize a module.
|
||||
(See also :ref:`multi-phase-initialization`.)
|
||||
|
||||
The *slots* array only needs to be valid for the duration of the
|
||||
:c:func:`!PyModule_FromSlotsAndSpec` call.
|
||||
In particular, it may be heap-allocated.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. c:function:: int PyModule_Exec(PyObject *module)
|
||||
|
||||
Execute the :c:data:`Py_mod_exec` slot(s) of the given *module*.
|
||||
|
||||
On success, return 0.
|
||||
On error, return -1 with an exception set.
|
||||
|
||||
For clarity: If *module* has no slots, for example if it uses
|
||||
:ref:`legacy single-phase initialization <single-phase-initialization>`,
|
||||
this function does nothing and returns 0.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
|
||||
|
||||
.. _pymoduledef:
|
||||
|
||||
Module definition struct
|
||||
------------------------
|
||||
|
||||
Traditionally, extension modules were defined using a *module definition*
|
||||
as the “description" of how a module should be created.
|
||||
Rather than using an array of :ref:`slots <pymoduledef_slot>` directly,
|
||||
the definition has dedicated members for most common functionality,
|
||||
and allows additional slots as an extension mechanism.
|
||||
|
||||
This way of defining modules is still available and there are no plans to
|
||||
remove it.
|
||||
|
||||
.. c:type:: PyModuleDef
|
||||
|
||||
The module definition struct, which holds information needed to create
|
||||
a module object.
|
||||
|
||||
This structure must be statically allocated (or be otherwise guaranteed
|
||||
to be valid while any modules created from it exist).
|
||||
Usually, there is only one variable of this type for each extension module
|
||||
defined this way.
|
||||
|
||||
.. c:member:: PyModuleDef_Base m_base
|
||||
|
||||
Always initialize this member to :c:macro:`PyModuleDef_HEAD_INIT`:
|
||||
|
||||
.. c:namespace:: NULL
|
||||
|
||||
.. c:type:: PyModuleDef_Base
|
||||
|
||||
The type of :c:member:`!PyModuleDef.m_base`.
|
||||
|
||||
.. c:macro:: PyModuleDef_HEAD_INIT
|
||||
|
||||
The required initial value for :c:member:`!PyModuleDef.m_base`.
|
||||
|
||||
.. c:member:: const char *m_name
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_name` slot.
|
||||
|
||||
.. c:member:: const char *m_doc
|
||||
|
||||
These members correspond to the :c:macro:`Py_mod_doc` slot.
|
||||
Setting this to NULL is equivalent to omitting the slot.
|
||||
|
||||
.. c:member:: Py_ssize_t m_size
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_state_size` slot.
|
||||
Setting this to zero is equivalent to omitting the slot.
|
||||
|
||||
When using :ref:`legacy single-phase initialization <single-phase-initialization>`
|
||||
or when creating modules dynamically using :c:func:`PyModule_Create`
|
||||
or :c:func:`PyModule_Create2`, :c:member:`!m_size` may be set to -1.
|
||||
This indicates that the module does not support sub-interpreters,
|
||||
because it has global state.
|
||||
|
||||
.. c:member:: PyMethodDef *m_methods
|
||||
|
||||
Corresponds to the :c:macro:`Py_mod_methods` slot.
|
||||
Setting this to NULL is equivalent to omitting the slot.
|
||||
|
||||
.. c:member:: PyModuleDef_Slot* m_slots
|
||||
|
||||
An array of additional slots, terminated by a ``{0, NULL}`` entry.
|
||||
|
||||
This array may not contain slots corresponding to :c:type:`PyModuleDef`
|
||||
members.
|
||||
For example, you cannot use :c:macro:`Py_mod_name` in :c:member:`!m_slots`;
|
||||
the module name must be given as :c:member:`PyModuleDef.m_name`.
|
||||
|
||||
.. versionchanged:: 3.5
|
||||
|
||||
Prior to version 3.5, this member was always set to ``NULL``,
|
||||
and was defined as:
|
||||
|
||||
.. c:member:: inquiry m_reload
|
||||
|
||||
.. c:member:: traverseproc m_traverse
|
||||
inquiry m_clear
|
||||
freefunc m_free
|
||||
|
||||
These members correspond to the :c:macro:`Py_mod_state_traverse`,
|
||||
:c:macro:`Py_mod_state_clear`, and :c:macro:`Py_mod_state_free` slots,
|
||||
respectively.
|
||||
|
||||
Setting these members to NULL is equivalent to omitting the
|
||||
corresponding slots.
|
||||
|
||||
.. versionchanged:: 3.9
|
||||
|
||||
:c:member:`m_traverse`, :c:member:`m_clear` and :c:member:`m_free`
|
||||
functions are longer called before the module state is allocated.
|
||||
|
||||
|
||||
.. _moduledef-dynamic:
|
||||
|
||||
The following API can be used to create modules from a :c:type:`!PyModuleDef`
|
||||
struct:
|
||||
|
||||
.. c:function:: PyObject* PyModule_Create(PyModuleDef *def)
|
||||
|
||||
|
|
@ -510,12 +834,13 @@ They are also used in
|
|||
useful for versioning. This may change in the future.
|
||||
|
||||
|
||||
.. _capi-module-support-functions:
|
||||
|
||||
Support functions
|
||||
-----------------
|
||||
|
||||
The following functions are provided to help initialize a module
|
||||
state.
|
||||
They are intended for a module's execution slots (:c:data:`Py_mod_exec`),
|
||||
The following functions are provided to help initialize a module object.
|
||||
They are intended for a module's execution slot (:c:data:`Py_mod_exec`),
|
||||
the initialization function for legacy :ref:`single-phase initialization <single-phase-initialization>`,
|
||||
or code that creates modules dynamically.
|
||||
|
||||
|
|
|
|||
|
|
@ -85,6 +85,35 @@ Object Protocol
|
|||
instead of the :func:`repr`.
|
||||
|
||||
|
||||
.. c:function:: void PyUnstable_Object_Dump(PyObject *op)
|
||||
|
||||
Dump an object *op* to ``stderr``. This should only be used for debugging.
|
||||
|
||||
The output is intended to try dumping objects even after memory corruption:
|
||||
|
||||
* Information is written starting with fields that are the least likely to
|
||||
crash when accessed.
|
||||
* This function can be called without an :term:`attached thread state`, but
|
||||
it's not recommended to do so: it can cause deadlocks.
|
||||
* An object that does not belong to the current interpreter may be dumped,
|
||||
but this may also cause crashes or unintended behavior.
|
||||
* Implement a heuristic to detect if the object memory has been freed. Don't
|
||||
display the object contents in this case, only its memory address.
|
||||
* The output format may change at any time.
|
||||
|
||||
Example of output:
|
||||
|
||||
.. code-block:: output
|
||||
|
||||
object address : 0x7f80124702c0
|
||||
object refcount : 2
|
||||
object type : 0x9902e0
|
||||
object type name: str
|
||||
object repr : 'abcdef'
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
|
||||
.. c:function:: int PyObject_HasAttrWithError(PyObject *o, PyObject *attr_name)
|
||||
|
||||
Returns ``1`` if *o* has the attribute *attr_name*, and ``0`` otherwise.
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ subtypes but not for instances of :class:`frozenset` or its subtypes.
|
|||
|
||||
Return ``1`` if found and removed, ``0`` if not found (no action taken), and ``-1`` if an
|
||||
error is encountered. Does not raise :exc:`KeyError` for missing keys. Raise a
|
||||
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~frozenset.discard`
|
||||
:exc:`TypeError` if the *key* is unhashable. Unlike the Python :meth:`~set.discard`
|
||||
method, this function does not automatically convert unhashable sets into
|
||||
temporary frozensets. Raise :exc:`SystemError` if *set* is not an
|
||||
instance of :class:`set` or its subtype.
|
||||
|
|
|
|||
|
|
@ -280,6 +280,8 @@ Implementing functions and methods
|
|||
|
||||
Name of the method.
|
||||
|
||||
A ``NULL`` *ml_name* marks the end of a :c:type:`!PyMethodDef` array.
|
||||
|
||||
.. c:member:: PyCFunction ml_meth
|
||||
|
||||
Pointer to the C implementation.
|
||||
|
|
@ -698,14 +700,12 @@ The following flags can be used with :c:member:`PyMemberDef.flags`:
|
|||
entry indicates an offset from the subclass-specific data, rather than
|
||||
from ``PyObject``.
|
||||
|
||||
Can only be used as part of :c:member:`Py_tp_members <PyTypeObject.tp_members>`
|
||||
Can only be used as part of the :c:data:`Py_tp_members`
|
||||
:c:type:`slot <PyType_Slot>` when creating a class using negative
|
||||
:c:member:`~PyType_Spec.basicsize`.
|
||||
It is mandatory in that case.
|
||||
|
||||
This flag is only used in :c:type:`PyType_Slot`.
|
||||
When setting :c:member:`~PyTypeObject.tp_members` during
|
||||
class creation, Python clears it and sets
|
||||
When setting :c:member:`~PyTypeObject.tp_members` from the slot during
|
||||
class creation, Python clears the flag and sets
|
||||
:c:member:`PyMemberDef.offset` to the offset from the ``PyObject`` struct.
|
||||
|
||||
.. index::
|
||||
|
|
|
|||
|
|
@ -283,8 +283,8 @@ Type Objects
|
|||
``Py_TYPE(self)`` may be a *subclass* of the intended class, and subclasses
|
||||
are not necessarily defined in the same module as their superclass.
|
||||
See :c:type:`PyCMethod` to get the class that defines the method.
|
||||
See :c:func:`PyType_GetModuleByDef` for cases when :c:type:`!PyCMethod` cannot
|
||||
be used.
|
||||
See :c:func:`PyType_GetModuleByToken` for cases when :c:type:`!PyCMethod`
|
||||
cannot be used.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
|
@ -304,10 +304,10 @@ Type Objects
|
|||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
|
||||
.. c:function:: PyObject* PyType_GetModuleByToken(PyTypeObject *type, const void *mod_token)
|
||||
|
||||
Find the first superclass whose module was created from
|
||||
the given :c:type:`PyModuleDef` *def*, and return that module.
|
||||
Find the first superclass whose module has the given
|
||||
:ref:`module token <ext-module-token>`, and return that module.
|
||||
|
||||
If no module is found, raises a :py:class:`TypeError` and returns ``NULL``.
|
||||
|
||||
|
|
@ -317,6 +317,23 @@ Type Objects
|
|||
and other places where a method's defining class cannot be passed using the
|
||||
:c:type:`PyCMethod` calling convention.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
|
||||
.. c:function:: PyObject* PyType_GetModuleByDef(PyTypeObject *type, struct PyModuleDef *def)
|
||||
|
||||
Find the first superclass whose module was created from the given
|
||||
:c:type:`PyModuleDef` *def*, or whose :ref:`module token <ext-module-token>`
|
||||
is equal to *def*, and return that module.
|
||||
|
||||
Note that modules created from a :c:type:`PyModuleDef` always have their
|
||||
token set to the :c:type:`PyModuleDef`'s address.
|
||||
In other words, this function is equivalent to
|
||||
:c:func:`PyType_GetModuleByToken`, except that it:
|
||||
|
||||
- returns a borrowed reference, and
|
||||
- has a non-``void*`` argument type (which is a cosmetic difference in C).
|
||||
|
||||
The returned reference is :term:`borrowed <borrowed reference>` from *type*,
|
||||
and will be valid as long as you hold a reference to *type*.
|
||||
Do not release it with :c:func:`Py_DECREF` or similar.
|
||||
|
|
@ -324,10 +341,10 @@ Type Objects
|
|||
.. versionadded:: 3.11
|
||||
|
||||
|
||||
.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *token, PyTypeObject **result)
|
||||
.. c:function:: int PyType_GetBaseByToken(PyTypeObject *type, void *tp_token, PyTypeObject **result)
|
||||
|
||||
Find the first superclass in *type*'s :term:`method resolution order` whose
|
||||
:c:macro:`Py_tp_token` token is equal to the given one.
|
||||
:c:macro:`Py_tp_token` token is equal to *tp_token*.
|
||||
|
||||
* If found, set *\*result* to a new :term:`strong reference`
|
||||
to it and return ``1``.
|
||||
|
|
@ -338,7 +355,7 @@ Type Objects
|
|||
The *result* argument may be ``NULL``, in which case *\*result* is not set.
|
||||
Use this if you need only the return value.
|
||||
|
||||
The *token* argument may not be ``NULL``.
|
||||
The *tp_token* argument may not be ``NULL``.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
|
|
@ -383,8 +400,8 @@ The following functions and structs are used to create
|
|||
|
||||
The *bases* argument can be used to specify base classes; it can either
|
||||
be only one class or a tuple of classes.
|
||||
If *bases* is ``NULL``, the *Py_tp_bases* slot is used instead.
|
||||
If that also is ``NULL``, the *Py_tp_base* slot is used instead.
|
||||
If *bases* is ``NULL``, the :c:data:`Py_tp_bases` slot is used instead.
|
||||
If that also is ``NULL``, the :c:data:`Py_tp_base` slot is used instead.
|
||||
If that also is ``NULL``, the new type derives from :class:`object`.
|
||||
|
||||
The *module* argument can be used to record the module in which the new
|
||||
|
|
@ -590,9 +607,9 @@ The following functions and structs are used to create
|
|||
:c:type:`PyAsyncMethods` with an added ``Py_`` prefix.
|
||||
For example, use:
|
||||
|
||||
* ``Py_tp_dealloc`` to set :c:member:`PyTypeObject.tp_dealloc`
|
||||
* ``Py_nb_add`` to set :c:member:`PyNumberMethods.nb_add`
|
||||
* ``Py_sq_length`` to set :c:member:`PySequenceMethods.sq_length`
|
||||
* :c:data:`Py_tp_dealloc` to set :c:member:`PyTypeObject.tp_dealloc`
|
||||
* :c:data:`Py_nb_add` to set :c:member:`PyNumberMethods.nb_add`
|
||||
* :c:data:`Py_sq_length` to set :c:member:`PySequenceMethods.sq_length`
|
||||
|
||||
An additional slot is supported that does not correspond to a
|
||||
:c:type:`!PyTypeObject` struct field:
|
||||
|
|
@ -611,7 +628,7 @@ The following functions and structs are used to create
|
|||
|
||||
If it is not possible to switch to a ``MANAGED`` flag (for example,
|
||||
for vectorcall or to support Python older than 3.12), specify the
|
||||
offset in :c:member:`Py_tp_members <PyTypeObject.tp_members>`.
|
||||
offset in :c:data:`Py_tp_members`.
|
||||
See :ref:`PyMemberDef documentation <pymemberdef-offsets>`
|
||||
for details.
|
||||
|
||||
|
|
@ -638,8 +655,8 @@ The following functions and structs are used to create
|
|||
under the :ref:`limited API <limited-c-api>`.
|
||||
|
||||
.. versionchanged:: 3.14
|
||||
The field :c:member:`~PyTypeObject.tp_vectorcall` can now set
|
||||
using ``Py_tp_vectorcall``. See the field's documentation
|
||||
The field :c:member:`~PyTypeObject.tp_vectorcall` can now be set
|
||||
using :c:data:`Py_tp_vectorcall`. See the field's documentation
|
||||
for details.
|
||||
|
||||
.. c:member:: void *pfunc
|
||||
|
|
@ -649,7 +666,7 @@ The following functions and structs are used to create
|
|||
|
||||
*pfunc* values may not be ``NULL``, except for the following slots:
|
||||
|
||||
* ``Py_tp_doc``
|
||||
* :c:data:`Py_tp_doc`
|
||||
* :c:data:`Py_tp_token` (for clarity, prefer :c:data:`Py_TP_USE_SPEC`
|
||||
rather than ``NULL``)
|
||||
|
||||
|
|
|
|||
|
|
@ -2273,7 +2273,7 @@ and :c:data:`PyType_Type` effectively act as defaults.)
|
|||
This field should be set to ``NULL`` and treated as read-only.
|
||||
Python will fill it in when the type is :c:func:`initialized <PyType_Ready>`.
|
||||
|
||||
For dynamically created classes, the ``Py_tp_bases``
|
||||
For dynamically created classes, the :c:data:`Py_tp_bases`
|
||||
:c:type:`slot <PyType_Slot>` can be used instead of the *bases* argument
|
||||
of :c:func:`PyType_FromSpecWithBases`.
|
||||
The argument form is preferred.
|
||||
|
|
|
|||
|
|
@ -396,3 +396,43 @@ Available start symbols
|
|||
* :pep:`484`
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
Stack Effects
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
.. seealso::
|
||||
:py:func:`dis.stack_effect`
|
||||
|
||||
|
||||
.. c:macro:: PY_INVALID_STACK_EFFECT
|
||||
|
||||
Sentinel value representing an invalid stack effect.
|
||||
|
||||
This is currently equivalent to ``INT_MAX``.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
||||
.. c:function:: int PyCompile_OpcodeStackEffect(int opcode, int oparg)
|
||||
|
||||
Compute the stack effect of *opcode* with argument *oparg*.
|
||||
|
||||
On success, this function returns the stack effect; on failure, this
|
||||
returns :c:macro:`PY_INVALID_STACK_EFFECT`.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
|
||||
.. c:function:: int PyCompile_OpcodeStackEffectWithJump(int opcode, int oparg, int jump)
|
||||
|
||||
Similar to :c:func:`PyCompile_OpcodeStackEffect`, but don't include the
|
||||
stack effect of jumping if *jump* is zero.
|
||||
|
||||
If *jump* is ``0``, this will not include the stack effect of jumping, but
|
||||
if *jump* is ``1`` or ``-1``, this will include it.
|
||||
|
||||
On success, this function returns the stack effect; on failure, this
|
||||
returns :c:macro:`PY_INVALID_STACK_EFFECT`.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
|
|
|||
|
|
@ -361,7 +361,7 @@
|
|||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title, author, document class [howto/manual]).
|
||||
_stdauthor = 'Guido van Rossum and the Python development team'
|
||||
_stdauthor = 'The Python development team'
|
||||
latex_documents = [
|
||||
('c-api/index', 'c-api.tex', 'The Python/C API', _stdauthor, 'manual'),
|
||||
(
|
||||
|
|
|
|||
|
|
@ -1472,6 +1472,9 @@ PyModule_Create2:PyObject*::+1:
|
|||
PyModule_Create2:PyModuleDef*:def::
|
||||
PyModule_Create2:int:module_api_version::
|
||||
|
||||
PyModule_Exec:int:::
|
||||
PyModule_ExecDef:PyObject*:module:0:
|
||||
|
||||
PyModule_ExecDef:int:::
|
||||
PyModule_ExecDef:PyObject*:module:0:
|
||||
PyModule_ExecDef:PyModuleDef*:def::
|
||||
|
|
@ -1485,6 +1488,10 @@ PyModule_FromDefAndSpec2:PyModuleDef*:def::
|
|||
PyModule_FromDefAndSpec2:PyObject*:spec:0:
|
||||
PyModule_FromDefAndSpec2:int:module_api_version::
|
||||
|
||||
PyModule_FromSlotsAndSpec:PyObject*::+1:
|
||||
PyModule_FromSlotsAndSpec:const PyModuleDef_Slot *:slots::
|
||||
PyModule_FromSlotsAndSpec:PyObject*:spec:0:
|
||||
|
||||
PyModule_GetDef:PyModuleDef*::0:
|
||||
PyModule_GetDef:PyObject*:module:0:
|
||||
|
||||
|
|
@ -1506,6 +1513,14 @@ PyModule_GetNameObject:PyObject*:module:0:
|
|||
PyModule_GetState:void*:::
|
||||
PyModule_GetState:PyObject*:module:0:
|
||||
|
||||
PyModule_GetStateSize:int:::
|
||||
PyModule_GetStateSize:PyObject*:module:0:
|
||||
PyModule_GetToken:Py_ssize_t**:result::
|
||||
|
||||
PyModule_GetToken:int:::
|
||||
PyModule_GetToken:PyObject*:module:0:
|
||||
PyModule_GetToken:void**:result::
|
||||
|
||||
PyModule_New:PyObject*::+1:
|
||||
PyModule_New:char*:name::
|
||||
|
||||
|
|
@ -2412,6 +2427,10 @@ PyType_GetFlags:PyTypeObject*:type:0:
|
|||
PyType_GetName:PyObject*::+1:
|
||||
PyType_GetName:PyTypeObject*:type:0:
|
||||
|
||||
PyType_GetModuleByToken:PyObject*::+1:
|
||||
PyType_GetModuleByToken:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByToken:PyModuleDef*:def::
|
||||
|
||||
PyType_GetModuleByDef:PyObject*::0:
|
||||
PyType_GetModuleByDef:PyTypeObject*:type:0:
|
||||
PyType_GetModuleByDef:PyModuleDef*:def::
|
||||
|
|
|
|||
9
Doc/data/stable_abi.dat
generated
9
Doc/data/stable_abi.dat
generated
|
|
@ -160,6 +160,7 @@ func,PyDict_Merge,3.2,,
|
|||
func,PyDict_MergeFromSeq2,3.2,,
|
||||
func,PyDict_New,3.2,,
|
||||
func,PyDict_Next,3.2,,
|
||||
func,PyDict_SetDefaultRef,3.15,,
|
||||
func,PyDict_SetItem,3.2,,
|
||||
func,PyDict_SetItemString,3.2,,
|
||||
func,PyDict_Size,3.2,,
|
||||
|
|
@ -463,6 +464,7 @@ data,PyMethodDescr_Type,3.2,,
|
|||
type,PyModuleDef,3.2,,full-abi
|
||||
type,PyModuleDef_Base,3.2,,full-abi
|
||||
func,PyModuleDef_Init,3.5,,
|
||||
type,PyModuleDef_Slot,3.5,,full-abi
|
||||
data,PyModuleDef_Type,3.5,,
|
||||
func,PyModule_Add,3.13,,
|
||||
func,PyModule_AddFunctions,3.7,,
|
||||
|
|
@ -914,6 +916,7 @@ func,Py_GetPlatform,3.2,,
|
|||
func,Py_GetRecursionLimit,3.2,,
|
||||
func,Py_GetVersion,3.2,,
|
||||
data,Py_HasFileSystemDefaultEncoding,3.2,,
|
||||
func,Py_IS_TYPE,3.15,,
|
||||
func,Py_IncRef,3.2,,
|
||||
func,Py_Initialize,3.2,,
|
||||
func,Py_InitializeEx,3.2,,
|
||||
|
|
@ -935,6 +938,8 @@ func,Py_REFCNT,3.14,,
|
|||
macro,Py_RELATIVE_OFFSET,3.12,,
|
||||
func,Py_ReprEnter,3.2,,
|
||||
func,Py_ReprLeave,3.2,,
|
||||
func,Py_SET_SIZE,3.15,,
|
||||
func,Py_SIZE,3.15,,
|
||||
func,Py_SetProgramName,3.2,,
|
||||
func,Py_SetPythonHome,3.2,,
|
||||
func,Py_SetRecursionLimit,3.2,,
|
||||
|
|
@ -979,8 +984,12 @@ macro,Py_bf_releasebuffer,3.11,,
|
|||
type,Py_buffer,3.11,,full-abi
|
||||
type,Py_intptr_t,3.2,,
|
||||
macro,Py_mod_abi,3.15,,
|
||||
macro,Py_mod_create,3.5,,
|
||||
macro,Py_mod_doc,3.15,,
|
||||
macro,Py_mod_exec,3.5,,
|
||||
macro,Py_mod_gil,3.13,,
|
||||
macro,Py_mod_methods,3.15,,
|
||||
macro,Py_mod_multiple_interpreters,3.12,,
|
||||
macro,Py_mod_name,3.15,,
|
||||
macro,Py_mod_state_clear,3.15,,
|
||||
macro,Py_mod_state_free,3.15,,
|
||||
|
|
|
|||
|
|
@ -426,7 +426,7 @@ A pointer to the module definition must be returned via :c:func:`PyModuleDef_Ini
|
|||
so that the import machinery can create the module and store it in ``sys.modules``.
|
||||
|
||||
When embedding Python, the :c:func:`!PyInit_spam` function is not called
|
||||
automatically unless there's an entry in the :c:data:`!PyImport_Inittab` table.
|
||||
automatically unless there's an entry in the :c:data:`PyImport_Inittab` table.
|
||||
To add the module to the initialization table, use :c:func:`PyImport_AppendInittab`,
|
||||
optionally followed by an import of the module::
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
.. _a-conceptual-overview-of-asyncio:
|
||||
|
||||
****************************************
|
||||
A Conceptual Overview of :mod:`!asyncio`
|
||||
A conceptual overview of :mod:`!asyncio`
|
||||
****************************************
|
||||
|
||||
This :ref:`HOWTO <how-tos>` article seeks to help you build a sturdy mental
|
||||
|
|
@ -37,15 +37,15 @@ In part 1, we'll cover the main, high-level building blocks of :mod:`!asyncio`:
|
|||
the event loop, coroutine functions, coroutine objects, tasks, and ``await``.
|
||||
|
||||
==========
|
||||
Event Loop
|
||||
Event loop
|
||||
==========
|
||||
|
||||
Everything in :mod:`!asyncio` happens relative to the event loop.
|
||||
It's the star of the show.
|
||||
It's the star of the show, but prefers to work behind the scenes, managing
|
||||
and coordinating resources.
|
||||
It's like an orchestra conductor.
|
||||
It's behind the scenes managing resources.
|
||||
Some power is explicitly granted to it, but a lot of its ability to get things
|
||||
done comes from the respect and cooperation of its worker bees.
|
||||
done comes from the respect and cooperation of its band members.
|
||||
|
||||
In more technical terms, the event loop contains a collection of jobs to be run.
|
||||
Some jobs are added directly by you, and some indirectly by :mod:`!asyncio`.
|
||||
|
|
@ -59,7 +59,7 @@ This process repeats indefinitely, with the event loop cycling endlessly
|
|||
onwards.
|
||||
If there are no more jobs pending execution, the event loop is smart enough to
|
||||
rest and avoid needlessly wasting CPU cycles, and will come back when there's
|
||||
more work to be done.
|
||||
more work to be done, such as when I/O operations complete or timers expire.
|
||||
|
||||
Effective execution relies on jobs sharing well and cooperating; a greedy job
|
||||
could hog control and leave the other jobs to starve, rendering the overall
|
||||
|
|
@ -170,14 +170,17 @@ Roughly speaking, :ref:`tasks <asyncio-task-obj>` are coroutines (not coroutine
|
|||
functions) tied to an event loop.
|
||||
A task also maintains a list of callback functions whose importance will become
|
||||
clear in a moment when we discuss :keyword:`await`.
|
||||
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
||||
|
||||
Creating a task automatically schedules it for execution (by adding a
|
||||
callback to run it in the event loop's to-do list, that is, collection of jobs).
|
||||
The recommended way to create tasks is via :func:`asyncio.create_task`.
|
||||
|
||||
Since there's only one event loop (in each thread), :mod:`!asyncio` takes care of
|
||||
associating the task with the event loop for you. As such, there's no need
|
||||
to specify the event loop.
|
||||
:mod:`!asyncio` automatically associates tasks with the event loop for you.
|
||||
This automatic association was purposely designed into :mod:`!asyncio` for
|
||||
the sake of simplicity.
|
||||
Without it, you'd have to keep track of the event loop object and pass it to
|
||||
any coroutine function that wants to create tasks, adding redundant clutter
|
||||
to your code.
|
||||
|
||||
::
|
||||
|
||||
|
|
@ -250,6 +253,10 @@ different ways::
|
|||
In a crucial way, the behavior of ``await`` depends on the type of object
|
||||
being awaited.
|
||||
|
||||
^^^^^^^^^^^^^^
|
||||
Awaiting tasks
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Awaiting a task will cede control from the current task or coroutine to
|
||||
the event loop.
|
||||
In the process of relinquishing control, a few important things happen.
|
||||
|
|
@ -281,6 +288,10 @@ This is a basic, yet reliable mental model.
|
|||
In practice, the control handoffs are slightly more complex, but not by much.
|
||||
In part 2, we'll walk through the details that make this possible.
|
||||
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
Awaiting coroutines
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
**Unlike tasks, awaiting a coroutine does not hand control back to the event
|
||||
loop!**
|
||||
Wrapping a coroutine in a task first, then awaiting that would cede
|
||||
|
|
@ -347,8 +358,10 @@ The design intentionally trades off some conceptual clarity around usage of
|
|||
``await`` for improved performance.
|
||||
Each time a task is awaited, control needs to be passed all the way up the
|
||||
call stack to the event loop.
|
||||
That might sound minor, but in a large program with many ``await`` statements and a deep
|
||||
call stack, that overhead can add up to a meaningful performance drag.
|
||||
Then, the event loop needs to manage its internal state and work through
|
||||
its processing logic to resume the next job.
|
||||
That might sound minor, but in a large program with many ``await``\ s, that
|
||||
overhead can add up to a non-negligible performance drag.
|
||||
|
||||
------------------------------------------------
|
||||
A conceptual overview part 2: the nuts and bolts
|
||||
|
|
@ -364,7 +377,8 @@ and how to make your own asynchronous operators.
|
|||
The inner workings of coroutines
|
||||
================================
|
||||
|
||||
:mod:`!asyncio` leverages four components to pass around control.
|
||||
:mod:`!asyncio` leverages four components of Python to pass
|
||||
around control.
|
||||
|
||||
:meth:`coroutine.send(arg) <generator.send>` is the method used to start or
|
||||
resume a coroutine.
|
||||
|
|
@ -448,9 +462,9 @@ That might sound odd to you. You might be thinking:
|
|||
That causes the error: ``SyntaxError: yield from not allowed in a coroutine.``
|
||||
This was intentionally designed for the sake of simplicity -- mandating only
|
||||
one way of using coroutines.
|
||||
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
||||
Initially ``yield`` was barred as well, but was re-accepted to allow for
|
||||
async generators.
|
||||
Despite that, ``yield from`` and ``await`` effectively do the same thing.
|
||||
|
||||
=======
|
||||
Futures
|
||||
|
|
|
|||
|
|
@ -45,9 +45,12 @@ single-phase initialization.
|
|||
Multi-Phase Initialization
|
||||
..........................
|
||||
|
||||
Extensions that use multi-phase initialization (i.e.,
|
||||
:c:func:`PyModuleDef_Init`) should add a :c:data:`Py_mod_gil` slot in the
|
||||
module definition. If your extension supports older versions of CPython,
|
||||
Extensions that use :ref:`multi-phase initialization <multi-phase-initialization>`
|
||||
(functions like :c:func:`PyModuleDef_Init`,
|
||||
:c:func:`PyModExport_* <PyModExport_modulename>` export hook,
|
||||
:c:func:`PyModule_FromSlotsAndSpec`) should add a
|
||||
:c:data:`Py_mod_gil` slot in the module definition.
|
||||
If your extension supports older versions of CPython,
|
||||
you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
|
||||
|
||||
::
|
||||
|
|
@ -60,18 +63,12 @@ you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
|
|||
{0, NULL}
|
||||
};
|
||||
|
||||
static struct PyModuleDef moduledef = {
|
||||
PyModuleDef_HEAD_INIT,
|
||||
.m_slots = module_slots,
|
||||
...
|
||||
};
|
||||
|
||||
|
||||
Single-Phase Initialization
|
||||
...........................
|
||||
|
||||
Extensions that use single-phase initialization (i.e.,
|
||||
:c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
|
||||
Extensions that use legacy :ref:`single-phase initialization <single-phase-initialization>`
|
||||
(that is, :c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
|
||||
indicate that they support running with the GIL disabled. The function is
|
||||
only defined in the free-threaded build, so you should guard the call with
|
||||
``#ifdef Py_GIL_DISABLED`` to avoid compilation errors in the regular build.
|
||||
|
|
|
|||
|
|
@ -11,9 +11,7 @@ available processing power by running threads in parallel on available CPU cores
|
|||
While not all software will benefit from this automatically, programs
|
||||
designed with threading in mind will run faster on multi-core hardware.
|
||||
|
||||
The free-threaded mode is working and continues to be improved, but
|
||||
there is some additional overhead in single-threaded workloads compared
|
||||
to the regular build. Additionally, third-party packages, in particular ones
|
||||
Some third-party packages, in particular ones
|
||||
with an :term:`extension module`, may not be ready for use in a
|
||||
free-threaded build, and will re-enable the :term:`GIL`.
|
||||
|
||||
|
|
@ -101,63 +99,42 @@ This section describes known limitations of the free-threaded CPython build.
|
|||
Immortalization
|
||||
---------------
|
||||
|
||||
The free-threaded build of the 3.13 release makes some objects :term:`immortal`.
|
||||
In the free-threaded build, some objects are :term:`immortal`.
|
||||
Immortal objects are not deallocated and have reference counts that are
|
||||
never modified. This is done to avoid reference count contention that would
|
||||
prevent efficient multi-threaded scaling.
|
||||
|
||||
An object will be made immortal when a new thread is started for the first time
|
||||
after the main thread is running. The following objects are immortalized:
|
||||
As of the 3.14 release, immortalization is limited to:
|
||||
|
||||
* :ref:`function <user-defined-funcs>` objects declared at the module level
|
||||
* :ref:`method <instance-methods>` descriptors
|
||||
* :ref:`code <code-objects>` objects
|
||||
* :term:`module` objects and their dictionaries
|
||||
* :ref:`classes <classes>` (type objects)
|
||||
|
||||
Because immortal objects are never deallocated, applications that create many
|
||||
objects of these types may see increased memory usage under Python 3.13. This
|
||||
has been addressed in the 3.14 release, where the aforementioned objects use
|
||||
deferred reference counting to avoid reference count contention.
|
||||
|
||||
Additionally, numeric and string literals in the code as well as strings
|
||||
returned by :func:`sys.intern` are also immortalized in the 3.13 release. This
|
||||
behavior is part of the 3.14 release as well and it is expected to remain in
|
||||
future free-threaded builds.
|
||||
* Code constants: numeric literals, string literals, and tuple literals
|
||||
composed of other constants.
|
||||
* Strings interned by :func:`sys.intern`.
|
||||
|
||||
|
||||
Frame objects
|
||||
-------------
|
||||
|
||||
It is not safe to access :ref:`frame <frame-objects>` objects from other
|
||||
threads and doing so may cause your program to crash . This means that
|
||||
:func:`sys._current_frames` is generally not safe to use in a free-threaded
|
||||
build. Functions like :func:`inspect.currentframe` and :func:`sys._getframe`
|
||||
are generally safe as long as the resulting frame object is not passed to
|
||||
another thread.
|
||||
It is not safe to access :attr:`frame.f_locals` from a :ref:`frame <frame-objects>`
|
||||
object if that frame is currently executing in another thread, and doing so may
|
||||
crash the interpreter.
|
||||
|
||||
|
||||
Iterators
|
||||
---------
|
||||
|
||||
Sharing the same iterator object between multiple threads is generally not
|
||||
safe and threads may see duplicate or missing elements when iterating or crash
|
||||
the interpreter.
|
||||
It is generally not thread-safe to access the same iterator object from
|
||||
multiple threads concurrently, and threads may see duplicate or missing
|
||||
elements.
|
||||
|
||||
|
||||
Single-threaded performance
|
||||
---------------------------
|
||||
|
||||
The free-threaded build has additional overhead when executing Python code
|
||||
compared to the default GIL-enabled build. In 3.13, this overhead is about
|
||||
40% on the `pyperformance <https://pyperformance.readthedocs.io/>`_ suite.
|
||||
Programs that spend most of their time in C extensions or I/O will see
|
||||
less of an impact. The largest impact is because the specializing adaptive
|
||||
interpreter (:pep:`659`) is disabled in the free-threaded build.
|
||||
|
||||
The specializing adaptive interpreter has been re-enabled in a thread-safe way
|
||||
in the 3.14 release. The performance penalty on single-threaded code in
|
||||
free-threaded mode is now roughly 5-10%, depending on the platform and C
|
||||
compiler used.
|
||||
compared to the default GIL-enabled build. The amount of overhead depends
|
||||
on the workload and hardware. On the pyperformance benchmark suite, the
|
||||
average overhead ranges from about 1% on macOS aarch64 to 8% on x86-64 Linux
|
||||
systems.
|
||||
|
||||
|
||||
Behavioral changes
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
Functional Programming HOWTO
|
||||
********************************
|
||||
|
||||
:Author: A. M. Kuchling
|
||||
:Author: \A. M. Kuchling
|
||||
:Release: 0.32
|
||||
|
||||
In this document, we'll take a tour of Python's features suitable for
|
||||
|
|
|
|||
|
|
@ -353,7 +353,7 @@ garbage collection protocol.
|
|||
That is, heap types should:
|
||||
|
||||
- Have the :c:macro:`Py_TPFLAGS_HAVE_GC` flag.
|
||||
- Define a traverse function using ``Py_tp_traverse``, which
|
||||
- Define a traverse function using :c:data:`Py_tp_traverse`, which
|
||||
visits the type (e.g. using ``Py_VISIT(Py_TYPE(self))``).
|
||||
|
||||
Please refer to the documentation of
|
||||
|
|
|
|||
|
|
@ -352,6 +352,8 @@ If you don't include such a comment, the default encoding used will be UTF-8 as
|
|||
already mentioned. See also :pep:`263` for more information.
|
||||
|
||||
|
||||
.. _unicode-properties:
|
||||
|
||||
Unicode Properties
|
||||
------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ Introduction
|
|||
You may also find useful the following article on fetching web resources
|
||||
with Python:
|
||||
|
||||
* `Basic Authentication <https://web.archive.org/web/20201215133350/http://www.voidspace.org.uk/python/articles/authentication.shtml>`_
|
||||
* `Basic Authentication <https://web.archive.org/web/20201215133350/http://www.voidspace.org.uk/python/articles/authentication.shtml>`__
|
||||
|
||||
A tutorial on *Basic Authentication*, with examples in Python.
|
||||
|
||||
|
|
|
|||
|
|
@ -767,9 +767,9 @@ how the command-line arguments should be handled. The supplied actions are:
|
|||
Namespace(foo=42)
|
||||
|
||||
* ``'store_true'`` and ``'store_false'`` - These are special cases of
|
||||
``'store_const'`` used for storing the values ``True`` and ``False``
|
||||
respectively. In addition, they create default values of ``False`` and
|
||||
``True`` respectively::
|
||||
``'store_const'`` that respectively store the values ``True`` and ``False``
|
||||
with default values of ``False`` and
|
||||
``True``::
|
||||
|
||||
>>> parser = argparse.ArgumentParser()
|
||||
>>> parser.add_argument('--foo', action='store_true')
|
||||
|
|
@ -789,8 +789,8 @@ how the command-line arguments should be handled. The supplied actions are:
|
|||
>>> parser.parse_args('--foo 1 --foo 2'.split())
|
||||
Namespace(foo=['0', '1', '2'])
|
||||
|
||||
* ``'append_const'`` - This stores a list, and appends the value specified by
|
||||
the const_ keyword argument to the list; note that the const_ keyword
|
||||
* ``'append_const'`` - This appends the value specified by
|
||||
the const_ keyword argument to a list; note that the const_ keyword
|
||||
argument defaults to ``None``. The ``'append_const'`` action is typically
|
||||
useful when multiple arguments need to store constants to the same list. For
|
||||
example::
|
||||
|
|
@ -801,8 +801,8 @@ how the command-line arguments should be handled. The supplied actions are:
|
|||
>>> parser.parse_args('--str --int'.split())
|
||||
Namespace(types=[<class 'str'>, <class 'int'>])
|
||||
|
||||
* ``'extend'`` - This stores a list and appends each item from the multi-value
|
||||
argument list to it.
|
||||
* ``'extend'`` - This appends each item from a multi-value
|
||||
argument to a list.
|
||||
The ``'extend'`` action is typically used with the nargs_ keyword argument
|
||||
value ``'+'`` or ``'*'``.
|
||||
Note that when nargs_ is ``None`` (the default) or ``'?'``, each
|
||||
|
|
@ -816,7 +816,7 @@ how the command-line arguments should be handled. The supplied actions are:
|
|||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
* ``'count'`` - This counts the number of times a keyword argument occurs. For
|
||||
* ``'count'`` - This counts the number of times an argument occurs. For
|
||||
example, this is useful for increasing verbosity levels::
|
||||
|
||||
>>> parser = argparse.ArgumentParser()
|
||||
|
|
@ -1322,8 +1322,12 @@ attribute is determined by the ``dest`` keyword argument of
|
|||
|
||||
For optional argument actions, the value of ``dest`` is normally inferred from
|
||||
the option strings. :class:`ArgumentParser` generates the value of ``dest`` by
|
||||
taking the first long option string and stripping away the initial ``--``
|
||||
string. If no long option strings were supplied, ``dest`` will be derived from
|
||||
taking the first double-dash long option string and stripping away the initial
|
||||
``-`` characters.
|
||||
If no double-dash long option strings were supplied, ``dest`` will be derived
|
||||
from the first single-dash long option string by stripping the initial ``-``
|
||||
character.
|
||||
If no long option strings were supplied, ``dest`` will be derived from
|
||||
the first short option string by stripping the initial ``-`` character. Any
|
||||
internal ``-`` characters will be converted to ``_`` characters to make sure
|
||||
the string is a valid attribute name. The examples below illustrate this
|
||||
|
|
@ -1331,11 +1335,12 @@ behavior::
|
|||
|
||||
>>> parser = argparse.ArgumentParser()
|
||||
>>> parser.add_argument('-f', '--foo-bar', '--foo')
|
||||
>>> parser.add_argument('-q', '-quz')
|
||||
>>> parser.add_argument('-x', '-y')
|
||||
>>> parser.parse_args('-f 1 -x 2'.split())
|
||||
Namespace(foo_bar='1', x='2')
|
||||
>>> parser.parse_args('--foo 1 -y 2'.split())
|
||||
Namespace(foo_bar='1', x='2')
|
||||
>>> parser.parse_args('-f 1 -q 2 -x 3'.split())
|
||||
Namespace(foo_bar='1', quz='2', x='3')
|
||||
>>> parser.parse_args('--foo 1 -quz 2 -y 3'.split())
|
||||
Namespace(foo_bar='1', quz='2', x='2')
|
||||
|
||||
``dest`` allows a custom attribute name to be provided::
|
||||
|
||||
|
|
@ -1344,6 +1349,9 @@ behavior::
|
|||
>>> parser.parse_args('--foo XXX'.split())
|
||||
Namespace(bar='XXX')
|
||||
|
||||
.. versionchanged:: next
|
||||
Single-dash long option now takes precedence over short options.
|
||||
|
||||
|
||||
.. _deprecated:
|
||||
|
||||
|
|
@ -1437,8 +1445,18 @@ this API may be passed as the ``action`` parameter to
|
|||
>>> parser.parse_args(['--no-foo'])
|
||||
Namespace(foo=False)
|
||||
|
||||
Single-dash long options are also supported.
|
||||
For example, negative option ``-nofoo`` is automatically added for
|
||||
positive option ``-foo``.
|
||||
But no additional options are added for short options such as ``-f``.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
.. versionchanged:: next
|
||||
Added support for single-dash options.
|
||||
|
||||
Added support for alternate prefix_chars_.
|
||||
|
||||
|
||||
The parse_args() method
|
||||
-----------------------
|
||||
|
|
|
|||
|
|
@ -236,7 +236,7 @@ The :mod:`bdb` module also defines two classes:
|
|||
Normally derived classes don't override the following methods, but they may
|
||||
if they want to redefine the definition of stopping and breakpoints.
|
||||
|
||||
.. method:: is_skipped_line(module_name)
|
||||
.. method:: is_skipped_module(module_name)
|
||||
|
||||
Return ``True`` if *module_name* matches any skip pattern.
|
||||
|
||||
|
|
|
|||
|
|
@ -1209,7 +1209,7 @@ If a new entry overwrites an existing entry, the
|
|||
original insertion position is changed and moved to the end::
|
||||
|
||||
class LastUpdatedOrderedDict(OrderedDict):
|
||||
'Store items in the order the keys were last added'
|
||||
'Store items in the order that the keys were last updated.'
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
super().__setitem__(key, value)
|
||||
|
|
|
|||
|
|
@ -2109,20 +2109,20 @@ to work with the :class:`Decimal` class::
|
|||
Decimal FAQ
|
||||
-----------
|
||||
|
||||
Q. It is cumbersome to type ``decimal.Decimal('1234.5')``. Is there a way to
|
||||
Q: It is cumbersome to type ``decimal.Decimal('1234.5')``. Is there a way to
|
||||
minimize typing when using the interactive interpreter?
|
||||
|
||||
A. Some users abbreviate the constructor to just a single letter:
|
||||
A: Some users abbreviate the constructor to just a single letter:
|
||||
|
||||
>>> D = decimal.Decimal
|
||||
>>> D('1.23') + D('3.45')
|
||||
Decimal('4.68')
|
||||
|
||||
Q. In a fixed-point application with two decimal places, some inputs have many
|
||||
Q: In a fixed-point application with two decimal places, some inputs have many
|
||||
places and need to be rounded. Others are not supposed to have excess digits
|
||||
and need to be validated. What methods should be used?
|
||||
|
||||
A. The :meth:`~Decimal.quantize` method rounds to a fixed number of decimal places. If
|
||||
A: The :meth:`~Decimal.quantize` method rounds to a fixed number of decimal places. If
|
||||
the :const:`Inexact` trap is set, it is also useful for validation:
|
||||
|
||||
>>> TWOPLACES = Decimal(10) ** -2 # same as Decimal('0.01')
|
||||
|
|
@ -2140,10 +2140,10 @@ the :const:`Inexact` trap is set, it is also useful for validation:
|
|||
...
|
||||
Inexact: None
|
||||
|
||||
Q. Once I have valid two place inputs, how do I maintain that invariant
|
||||
Q: Once I have valid two place inputs, how do I maintain that invariant
|
||||
throughout an application?
|
||||
|
||||
A. Some operations like addition, subtraction, and multiplication by an integer
|
||||
A: Some operations like addition, subtraction, and multiplication by an integer
|
||||
will automatically preserve fixed point. Others operations, like division and
|
||||
non-integer multiplication, will change the number of decimal places and need to
|
||||
be followed-up with a :meth:`~Decimal.quantize` step:
|
||||
|
|
@ -2175,21 +2175,21 @@ to handle the :meth:`~Decimal.quantize` step:
|
|||
>>> div(b, a)
|
||||
Decimal('0.03')
|
||||
|
||||
Q. There are many ways to express the same value. The numbers ``200``,
|
||||
Q: There are many ways to express the same value. The numbers ``200``,
|
||||
``200.000``, ``2E2``, and ``.02E+4`` all have the same value at
|
||||
various precisions. Is there a way to transform them to a single recognizable
|
||||
canonical value?
|
||||
|
||||
A. The :meth:`~Decimal.normalize` method maps all equivalent values to a single
|
||||
A: The :meth:`~Decimal.normalize` method maps all equivalent values to a single
|
||||
representative:
|
||||
|
||||
>>> values = map(Decimal, '200 200.000 2E2 .02E+4'.split())
|
||||
>>> [v.normalize() for v in values]
|
||||
[Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2'), Decimal('2E+2')]
|
||||
|
||||
Q. When does rounding occur in a computation?
|
||||
Q: When does rounding occur in a computation?
|
||||
|
||||
A. It occurs *after* the computation. The philosophy of the decimal
|
||||
A: It occurs *after* the computation. The philosophy of the decimal
|
||||
specification is that numbers are considered exact and are created
|
||||
independent of the current context. They can even have greater
|
||||
precision than current context. Computations process with those
|
||||
|
|
@ -2207,10 +2207,10 @@ applied to the *result* of the computation::
|
|||
>>> pi + 0 - Decimal('0.00005'). # Intermediate values are rounded
|
||||
Decimal('3.1416')
|
||||
|
||||
Q. Some decimal values always print with exponential notation. Is there a way
|
||||
Q: Some decimal values always print with exponential notation. Is there a way
|
||||
to get a non-exponential representation?
|
||||
|
||||
A. For some values, exponential notation is the only way to express the number
|
||||
A: For some values, exponential notation is the only way to express the number
|
||||
of significant places in the coefficient. For example, expressing
|
||||
``5.0E+3`` as ``5000`` keeps the value constant but cannot show the
|
||||
original's two-place significance.
|
||||
|
|
@ -2225,9 +2225,9 @@ value unchanged:
|
|||
>>> remove_exponent(Decimal('5E+3'))
|
||||
Decimal('5000')
|
||||
|
||||
Q. Is there a way to convert a regular float to a :class:`Decimal`?
|
||||
Q: Is there a way to convert a regular float to a :class:`Decimal`?
|
||||
|
||||
A. Yes, any binary floating-point number can be exactly expressed as a
|
||||
A: Yes, any binary floating-point number can be exactly expressed as a
|
||||
Decimal though an exact conversion may take more precision than intuition would
|
||||
suggest:
|
||||
|
||||
|
|
@ -2236,19 +2236,19 @@ suggest:
|
|||
>>> Decimal(math.pi)
|
||||
Decimal('3.141592653589793115997963468544185161590576171875')
|
||||
|
||||
Q. Within a complex calculation, how can I make sure that I haven't gotten a
|
||||
Q: Within a complex calculation, how can I make sure that I haven't gotten a
|
||||
spurious result because of insufficient precision or rounding anomalies.
|
||||
|
||||
A. The decimal module makes it easy to test results. A best practice is to
|
||||
A: The decimal module makes it easy to test results. A best practice is to
|
||||
re-run calculations using greater precision and with various rounding modes.
|
||||
Widely differing results indicate insufficient precision, rounding mode issues,
|
||||
ill-conditioned inputs, or a numerically unstable algorithm.
|
||||
|
||||
Q. I noticed that context precision is applied to the results of operations but
|
||||
Q: I noticed that context precision is applied to the results of operations but
|
||||
not to the inputs. Is there anything to watch out for when mixing values of
|
||||
different precisions?
|
||||
|
||||
A. Yes. The principle is that all values are considered to be exact and so is
|
||||
A: Yes. The principle is that all values are considered to be exact and so is
|
||||
the arithmetic on those values. Only the results are rounded. The advantage
|
||||
for inputs is that "what you type is what you get". A disadvantage is that the
|
||||
results can look odd if you forget that the inputs haven't been rounded:
|
||||
|
|
@ -2276,9 +2276,9 @@ Alternatively, inputs can be rounded upon creation using the
|
|||
>>> Context(prec=5, rounding=ROUND_DOWN).create_decimal('1.2345678')
|
||||
Decimal('1.2345')
|
||||
|
||||
Q. Is the CPython implementation fast for large numbers?
|
||||
Q: Is the CPython implementation fast for large numbers?
|
||||
|
||||
A. Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of
|
||||
A: Yes. In the CPython and PyPy3 implementations, the C/CFFI versions of
|
||||
the decimal module integrate the high speed `libmpdec
|
||||
<https://www.bytereef.org/mpdecimal/doc/libmpdec/index.html>`_ library for
|
||||
arbitrary precision correctly rounded decimal floating-point arithmetic [#]_.
|
||||
|
|
|
|||
|
|
@ -978,6 +978,12 @@ their subgroups based on the types of the contained exceptions.
|
|||
raises a :exc:`TypeError` if any contained exception is not an
|
||||
:exc:`Exception` subclass.
|
||||
|
||||
.. impl-detail::
|
||||
|
||||
The ``excs`` parameter may be any sequence, but lists and tuples are
|
||||
specifically processed more efficiently here. For optimal performance,
|
||||
pass a tuple as ``excs``.
|
||||
|
||||
.. attribute:: message
|
||||
|
||||
The ``msg`` argument to the constructor. This is a read-only attribute.
|
||||
|
|
|
|||
|
|
@ -57,6 +57,10 @@ The :mod:`functools` module defines the following functions:
|
|||
another thread makes an additional call before the initial call has been
|
||||
completed and cached.
|
||||
|
||||
Call-once behavior is not guaranteed because locks are not held during the
|
||||
function call. Potentially another call with the same arguments could
|
||||
occur while the first call is still running.
|
||||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -108,10 +108,19 @@ The :mod:`gc` module provides the following functions:
|
|||
|
||||
* ``uncollectable`` is the total number of objects which were found
|
||||
to be uncollectable (and were therefore moved to the :data:`garbage`
|
||||
list) inside this generation.
|
||||
list) inside this generation;
|
||||
|
||||
* ``candidates`` is the total number of objects in this generation which were
|
||||
considered for collection and traversed;
|
||||
|
||||
* ``duration`` is the total time in seconds spent in collections for this
|
||||
generation.
|
||||
|
||||
.. versionadded:: 3.4
|
||||
|
||||
.. versionchanged:: next
|
||||
Add ``duration`` and ``candidates``.
|
||||
|
||||
|
||||
.. function:: set_threshold(threshold0, [threshold1, [threshold2]])
|
||||
|
||||
|
|
@ -313,6 +322,12 @@ values but should not rebind them):
|
|||
"uncollectable": When *phase* is "stop", the number of objects
|
||||
that could not be collected and were put in :data:`garbage`.
|
||||
|
||||
"candidates": When *phase* is "stop", the total number of objects in this
|
||||
generation which were considered for collection and traversed.
|
||||
|
||||
"duration": When *phase* is "stop", the time in seconds spent in the
|
||||
collection.
|
||||
|
||||
Applications can add their own callbacks to this list. The primary
|
||||
use cases are:
|
||||
|
||||
|
|
@ -325,6 +340,9 @@ values but should not rebind them):
|
|||
|
||||
.. versionadded:: 3.3
|
||||
|
||||
.. versionchanged:: next
|
||||
Add "duration" and "candidates".
|
||||
|
||||
|
||||
The following constants are provided for use with :func:`set_debug`:
|
||||
|
||||
|
|
|
|||
|
|
@ -506,7 +506,7 @@ Summation and product functions
|
|||
|
||||
Roughly equivalent to::
|
||||
|
||||
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q)))
|
||||
sqrt(sum((px - qx) ** 2.0 for px, qx in zip(p, q, strict=True)))
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
|
|
|||
|
|
@ -832,8 +832,8 @@ raising an exception.
|
|||
|
||||
One difference from other Python queue implementations, is that :mod:`multiprocessing`
|
||||
queues serializes all objects that are put into them using :mod:`pickle`.
|
||||
The object return by the get method is a re-created object that does not share memory
|
||||
with the original object.
|
||||
The object returned by the get method is a re-created object that does not share
|
||||
memory with the original object.
|
||||
|
||||
Note that one can also create a shared queue by using a manager object -- see
|
||||
:ref:`multiprocessing-managers`.
|
||||
|
|
@ -890,7 +890,7 @@ For an example of the usage of queues for interprocess communication see
|
|||
:ref:`multiprocessing-examples`.
|
||||
|
||||
|
||||
.. function:: Pipe([duplex])
|
||||
.. function:: Pipe(duplex=True)
|
||||
|
||||
Returns a pair ``(conn1, conn2)`` of
|
||||
:class:`~multiprocessing.connection.Connection` objects representing the
|
||||
|
|
@ -1577,12 +1577,22 @@ object -- see :ref:`multiprocessing-managers`.
|
|||
A solitary difference from its close analog exists: its ``acquire`` method's
|
||||
first argument is named *block*, as is consistent with :meth:`Lock.acquire`.
|
||||
|
||||
|
||||
.. method:: get_value()
|
||||
|
||||
Return the current value of semaphore.
|
||||
|
||||
Note that this may raise :exc:`NotImplementedError` on platforms like
|
||||
macOS where ``sem_getvalue()`` is not implemented.
|
||||
|
||||
|
||||
.. method:: locked()
|
||||
|
||||
Return a boolean indicating whether this object is locked right now.
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
|
||||
.. note::
|
||||
|
||||
On macOS, ``sem_timedwait`` is unsupported, so calling ``acquire()`` with
|
||||
|
|
|
|||
|
|
@ -347,81 +347,6 @@ The statistical profiler produces output similar to deterministic profilers but
|
|||
|
||||
.. _profile-cli:
|
||||
|
||||
:mod:`!profiling.sampling` Module Reference
|
||||
=======================================================
|
||||
|
||||
.. module:: profiling.sampling
|
||||
:synopsis: Python statistical profiler.
|
||||
|
||||
This section documents the programmatic interface for the :mod:`!profiling.sampling` module.
|
||||
For command-line usage, see :ref:`sampling-profiler-cli`. For conceptual information
|
||||
about statistical profiling, see :ref:`statistical-profiling`
|
||||
|
||||
.. function:: sample(pid, *, sort=2, sample_interval_usec=100, duration_sec=10, filename=None, all_threads=False, limit=None, show_summary=True, output_format="pstats", realtime_stats=False, native=False, gc=True)
|
||||
|
||||
Sample a Python process and generate profiling data.
|
||||
|
||||
This is the main entry point for statistical profiling. It creates a
|
||||
:class:`SampleProfiler`, collects stack traces from the target process, and
|
||||
outputs the results in the specified format.
|
||||
|
||||
:param int pid: Process ID of the target Python process
|
||||
:param int sort: Sort order for pstats output (default: 2 for cumulative time)
|
||||
:param int sample_interval_usec: Sampling interval in microseconds (default: 100)
|
||||
:param int duration_sec: Duration to sample in seconds (default: 10)
|
||||
:param str filename: Output filename (None for stdout/default naming)
|
||||
:param bool all_threads: Whether to sample all threads (default: False)
|
||||
:param int limit: Maximum number of functions to display (default: None)
|
||||
:param bool show_summary: Whether to show summary statistics (default: True)
|
||||
:param str output_format: Output format - 'pstats' or 'collapsed' (default: 'pstats')
|
||||
:param bool realtime_stats: Whether to display real-time statistics (default: False)
|
||||
:param bool native: Whether to include ``<native>`` frames (default: False)
|
||||
:param bool gc: Whether to include ``<GC>`` frames (default: True)
|
||||
|
||||
:raises ValueError: If output_format is not 'pstats' or 'collapsed'
|
||||
|
||||
Examples::
|
||||
|
||||
# Basic usage - profile process 1234 for 10 seconds
|
||||
import profiling.sampling
|
||||
profiling.sampling.sample(1234)
|
||||
|
||||
# Profile with custom settings
|
||||
profiling.sampling.sample(1234, duration_sec=30, sample_interval_usec=50, all_threads=True)
|
||||
|
||||
# Generate collapsed stack traces for flamegraph.pl
|
||||
profiling.sampling.sample(1234, output_format='collapsed', filename='profile.collapsed')
|
||||
|
||||
.. class:: SampleProfiler(pid, sample_interval_usec, all_threads)
|
||||
|
||||
Low-level API for the statistical profiler.
|
||||
|
||||
This profiler uses periodic stack sampling to collect performance data
|
||||
from running Python processes with minimal overhead. It can attach to
|
||||
any Python process by PID and collect stack traces at regular intervals.
|
||||
|
||||
:param int pid: Process ID of the target Python process
|
||||
:param int sample_interval_usec: Sampling interval in microseconds
|
||||
:param bool all_threads: Whether to sample all threads or just the main thread
|
||||
|
||||
.. method:: sample(collector, duration_sec=10)
|
||||
|
||||
Sample the target process for the specified duration.
|
||||
|
||||
Collects stack traces from the target process at regular intervals
|
||||
and passes them to the provided collector for processing.
|
||||
|
||||
:param collector: Object that implements ``collect()`` method to process stack traces
|
||||
:param int duration_sec: Duration to sample in seconds (default: 10)
|
||||
|
||||
The method tracks sampling statistics and can display real-time
|
||||
information if realtime_stats is enabled.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`sampling-profiler-cli`
|
||||
Command-line interface documentation for the statistical profiler.
|
||||
|
||||
Deterministic Profiler Command Line Interface
|
||||
=============================================
|
||||
|
||||
|
|
|
|||
|
|
@ -246,6 +246,15 @@ Startup hooks
|
|||
if Python was compiled for a version of the library that supports it.
|
||||
|
||||
|
||||
.. function:: get_pre_input_hook()
|
||||
|
||||
Get the current pre-input hook function, or ``None`` if no pre-input hook
|
||||
function has been set. This function only exists if Python was compiled
|
||||
for a version of the library that supports it.
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
|
||||
.. _readline-completion:
|
||||
|
||||
Completion
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ The module defines the following:
|
|||
:ref:`kevent-objects` below for the methods supported by kevent objects.
|
||||
|
||||
|
||||
.. function:: select(rlist, wlist, xlist[, timeout])
|
||||
.. function:: select(rlist, wlist, xlist, timeout=None)
|
||||
|
||||
This is a straightforward interface to the Unix :c:func:`!select` system call.
|
||||
The first three arguments are iterables of 'waitable objects': either
|
||||
|
|
@ -131,7 +131,7 @@ The module defines the following:
|
|||
platform-dependent. (It is known to work on Unix but not on Windows.) The
|
||||
optional *timeout* argument specifies a time-out in seconds; it may be
|
||||
a non-integer to specify fractions of seconds.
|
||||
When the *timeout* argument is omitted the function blocks until
|
||||
When the *timeout* argument is omitted or ``None``, the function blocks until
|
||||
at least one file descriptor is ready. A time-out value of zero specifies a
|
||||
poll and never blocks.
|
||||
|
||||
|
|
|
|||
|
|
@ -482,6 +482,9 @@ The AF_* and SOCK_* constants are now :class:`AddressFamily` and
|
|||
.. versionchanged:: 3.14
|
||||
Added support for ``TCP_QUICKACK`` on Windows platforms when available.
|
||||
|
||||
.. versionchanged:: next
|
||||
``IPV6_HDRINCL`` was added.
|
||||
|
||||
|
||||
.. data:: AF_CAN
|
||||
PF_CAN
|
||||
|
|
@ -2092,11 +2095,8 @@ to sockets.
|
|||
Accepts any real number, not only integer or float.
|
||||
|
||||
|
||||
.. method:: socket.setsockopt(level, optname, value: int)
|
||||
.. method:: socket.setsockopt(level, optname, value: buffer)
|
||||
:noindex:
|
||||
.. method:: socket.setsockopt(level, optname, None, optlen: int)
|
||||
:noindex:
|
||||
.. method:: socket.setsockopt(level, optname, value: int | Buffer)
|
||||
socket.setsockopt(level, optname, None, optlen: int)
|
||||
|
||||
.. index:: pair: module; struct
|
||||
|
||||
|
|
|
|||
|
|
@ -2959,16 +2959,16 @@ of TLS/SSL. Some new TLS 1.3 features are not yet available.
|
|||
Steve Kent
|
||||
|
||||
:rfc:`RFC 4086: Randomness Requirements for Security <4086>`
|
||||
Donald E., Jeffrey I. Schiller
|
||||
Donald E. Eastlake, Jeffrey I. Schiller, Steve Crocker
|
||||
|
||||
:rfc:`RFC 5280: Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile <5280>`
|
||||
D. Cooper
|
||||
David Cooper et al.
|
||||
|
||||
:rfc:`RFC 5246: The Transport Layer Security (TLS) Protocol Version 1.2 <5246>`
|
||||
T. Dierks et. al.
|
||||
Tim Dierks and Eric Rescorla.
|
||||
|
||||
:rfc:`RFC 6066: Transport Layer Security (TLS) Extensions <6066>`
|
||||
D. Eastlake
|
||||
Donald E. Eastlake
|
||||
|
||||
`IANA TLS: Transport Layer Security (TLS) Parameters <https://www.iana.org/assignments/tls-parameters/tls-parameters.xml>`_
|
||||
IANA
|
||||
|
|
|
|||
|
|
@ -1994,10 +1994,16 @@ expression support in the :mod:`re` module).
|
|||
``{}``. Each replacement field contains either the numeric index of a
|
||||
positional argument, or the name of a keyword argument. Returns a copy of
|
||||
the string where each replacement field is replaced with the string value of
|
||||
the corresponding argument.
|
||||
the corresponding argument. For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> "The sum of 1 + 2 is {0}".format(1+2)
|
||||
'The sum of 1 + 2 is 3'
|
||||
>>> "The sum of {a} + {b} is {answer}".format(answer=1+2, a=1, b=2)
|
||||
'The sum of 1 + 2 is 3'
|
||||
>>> "{1} expects the {0} Inquisition!".format("Spanish", "Nobody")
|
||||
'Nobody expects the Spanish Inquisition!'
|
||||
|
||||
See :ref:`formatstrings` for a description of the various formatting options
|
||||
that can be specified in format strings.
|
||||
|
|
@ -2057,13 +2063,32 @@ expression support in the :mod:`re` module).
|
|||
from the `Alphabetic property defined in the section 4.10 'Letters, Alphabetic, and
|
||||
Ideographic' of the Unicode Standard
|
||||
<https://www.unicode.org/versions/Unicode17.0.0/core-spec/chapter-4/#G91002>`__.
|
||||
For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> 'Letters and spaces'.isalpha()
|
||||
False
|
||||
>>> 'LettersOnly'.isalpha()
|
||||
True
|
||||
>>> 'µ'.isalpha() # non-ASCII characters can be considered alphabetical too
|
||||
True
|
||||
|
||||
See :ref:`unicode-properties`.
|
||||
|
||||
|
||||
.. method:: str.isascii()
|
||||
|
||||
Return ``True`` if the string is empty or all characters in the string are ASCII,
|
||||
``False`` otherwise.
|
||||
ASCII characters have code points in the range U+0000-U+007F.
|
||||
ASCII characters have code points in the range U+0000-U+007F. For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> 'ASCII characters'.isascii()
|
||||
True
|
||||
>>> 'µ'.isascii()
|
||||
False
|
||||
|
||||
.. versionadded:: 3.7
|
||||
|
||||
|
|
@ -2073,9 +2098,18 @@ expression support in the :mod:`re` module).
|
|||
Return ``True`` if all characters in the string are decimal
|
||||
characters and there is at least one character, ``False``
|
||||
otherwise. Decimal characters are those that can be used to form
|
||||
numbers in base 10, e.g. U+0660, ARABIC-INDIC DIGIT
|
||||
numbers in base 10, such as U+0660, ARABIC-INDIC DIGIT
|
||||
ZERO. Formally a decimal character is a character in the Unicode
|
||||
General Category "Nd".
|
||||
General Category "Nd". For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> '0123456789'.isdecimal()
|
||||
True
|
||||
>>> '٠١٢٣٤٥٦٧٨٩'.isdecimal() # Arabic-Indic digits zero to nine
|
||||
True
|
||||
>>> 'alphabetic'.isdecimal()
|
||||
False
|
||||
|
||||
|
||||
.. method:: str.isdigit()
|
||||
|
|
@ -2194,7 +2228,16 @@ expression support in the :mod:`re` module).
|
|||
Return a string which is the concatenation of the strings in *iterable*.
|
||||
A :exc:`TypeError` will be raised if there are any non-string values in
|
||||
*iterable*, including :class:`bytes` objects. The separator between
|
||||
elements is the string providing this method.
|
||||
elements is the string providing this method. For example:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> ', '.join(['spam', 'spam', 'spam'])
|
||||
'spam, spam, spam'
|
||||
>>> '-'.join('Python')
|
||||
'P-y-t-h-o-n'
|
||||
|
||||
See also :meth:`split`.
|
||||
|
||||
|
||||
.. method:: str.ljust(width, fillchar=' ', /)
|
||||
|
|
@ -2408,6 +2451,8 @@ expression support in the :mod:`re` module).
|
|||
>>> " foo ".split(maxsplit=0)
|
||||
['foo ']
|
||||
|
||||
See also :meth:`join`.
|
||||
|
||||
|
||||
.. index::
|
||||
single: universal newlines; str.splitlines method
|
||||
|
|
@ -2611,6 +2656,8 @@ expression support in the :mod:`re` module).
|
|||
single: : (colon); in formatted string literal
|
||||
single: = (equals); for help in debugging using string literals
|
||||
|
||||
.. _stdtypes-fstrings:
|
||||
|
||||
Formatted String Literals (f-strings)
|
||||
-------------------------------------
|
||||
|
||||
|
|
@ -2619,123 +2666,147 @@ Formatted String Literals (f-strings)
|
|||
The :keyword:`await` and :keyword:`async for` can be used in expressions
|
||||
within f-strings.
|
||||
.. versionchanged:: 3.8
|
||||
Added the debugging operator (``=``)
|
||||
Added the debug specifier (``=``)
|
||||
.. versionchanged:: 3.12
|
||||
Many restrictions on expressions within f-strings have been removed.
|
||||
Notably, nested strings, comments, and backslashes are now permitted.
|
||||
|
||||
An :dfn:`f-string` (formally a :dfn:`formatted string literal`) is
|
||||
a string literal that is prefixed with ``f`` or ``F``.
|
||||
This type of string literal allows embedding arbitrary Python expressions
|
||||
within *replacement fields*, which are delimited by curly brackets (``{}``).
|
||||
These expressions are evaluated at runtime, similarly to :meth:`str.format`,
|
||||
and are converted into regular :class:`str` objects.
|
||||
For example:
|
||||
This type of string literal allows embedding the results of arbitrary Python
|
||||
expressions within *replacement fields*, which are delimited by curly
|
||||
brackets (``{}``).
|
||||
Each replacement field must contain an expression, optionally followed by:
|
||||
|
||||
.. doctest::
|
||||
* a *debug specifier* -- an equal sign (``=``);
|
||||
* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or
|
||||
* a *format specifier* prefixed with a colon (``:``).
|
||||
|
||||
>>> who = 'nobody'
|
||||
>>> nationality = 'Spanish'
|
||||
>>> f'{who.title()} expects the {nationality} Inquisition!'
|
||||
'Nobody expects the Spanish Inquisition!'
|
||||
See the :ref:`Lexical Analysis section on f-strings <f-strings>` for details
|
||||
on the syntax of these fields.
|
||||
|
||||
It is also possible to use a multi line f-string:
|
||||
Debug specifier
|
||||
^^^^^^^^^^^^^^^
|
||||
|
||||
.. doctest::
|
||||
.. versionadded:: 3.8
|
||||
|
||||
>>> f'''This is a string
|
||||
... on two lines'''
|
||||
'This is a string\non two lines'
|
||||
If a debug specifier -- an equal sign (``=``) -- appears after the replacement
|
||||
field expression, the resulting f-string will contain the expression's source,
|
||||
the equal sign, and the value of the expression.
|
||||
This is often useful for debugging::
|
||||
|
||||
A single opening curly bracket, ``'{'``, marks a *replacement field* that
|
||||
can contain any Python expression:
|
||||
>>> number = 14.3
|
||||
>>> f'{number=}'
|
||||
'number=14.3'
|
||||
|
||||
.. doctest::
|
||||
Whitespace before, inside and after the expression, as well as whitespace
|
||||
after the equal sign, is significant --- it is retained in the result::
|
||||
|
||||
>>> nationality = 'Spanish'
|
||||
>>> f'The {nationality} Inquisition!'
|
||||
'The Spanish Inquisition!'
|
||||
>>> f'{ number - 4 = }'
|
||||
' number - 4 = 10.3'
|
||||
|
||||
To include a literal ``{`` or ``}``, use a double bracket:
|
||||
|
||||
.. doctest::
|
||||
Conversion specifier
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
>>> x = 42
|
||||
>>> f'{{x}} is {x}'
|
||||
'{x} is 42'
|
||||
|
||||
Functions can also be used, and :ref:`format specifiers <formatstrings>`:
|
||||
|
||||
.. doctest::
|
||||
|
||||
>>> from math import sqrt
|
||||
>>> f'√2 \N{ALMOST EQUAL TO} {sqrt(2):.5f}'
|
||||
'√2 ≈ 1.41421'
|
||||
|
||||
Any non-string expression is converted using :func:`str`, by default:
|
||||
|
||||
.. doctest::
|
||||
By default, the value of a replacement field expression is converted to
|
||||
a string using :func:`str`::
|
||||
|
||||
>>> from fractions import Fraction
|
||||
>>> f'{Fraction(1, 3)}'
|
||||
>>> one_third = Fraction(1, 3)
|
||||
>>> f'{one_third}'
|
||||
'1/3'
|
||||
|
||||
To use an explicit conversion, use the ``!`` (exclamation mark) operator,
|
||||
followed by any of the valid formats, which are:
|
||||
When a debug specifier but no format specifier is used, the default conversion
|
||||
instead uses :func:`repr`::
|
||||
|
||||
========== ==============
|
||||
Conversion Meaning
|
||||
========== ==============
|
||||
``!a`` :func:`ascii`
|
||||
``!r`` :func:`repr`
|
||||
``!s`` :func:`str`
|
||||
========== ==============
|
||||
>>> f'{one_third = }'
|
||||
'one_third = Fraction(1, 3)'
|
||||
|
||||
For example:
|
||||
The conversion can be specified explicitly using one of these specifiers:
|
||||
|
||||
.. doctest::
|
||||
* ``!s`` for :func:`str`
|
||||
* ``!r`` for :func:`repr`
|
||||
* ``!a`` for :func:`ascii`
|
||||
|
||||
>>> from fractions import Fraction
|
||||
>>> f'{Fraction(1, 3)!s}'
|
||||
For example::
|
||||
|
||||
>>> str(one_third)
|
||||
'1/3'
|
||||
>>> f'{Fraction(1, 3)!r}'
|
||||
>>> repr(one_third)
|
||||
'Fraction(1, 3)'
|
||||
>>> question = '¿Dónde está el Presidente?'
|
||||
>>> print(f'{question!a}')
|
||||
'\xbfD\xf3nde est\xe1 el Presidente?'
|
||||
|
||||
While debugging it may be helpful to see both the expression and its value,
|
||||
by using the equals sign (``=``) after the expression.
|
||||
This preserves spaces within the brackets, and can be used with a converter.
|
||||
By default, the debugging operator uses the :func:`repr` (``!r``) conversion.
|
||||
For example:
|
||||
>>> f'{one_third!s} is {one_third!r}'
|
||||
'1/3 is Fraction(1, 3)'
|
||||
|
||||
.. doctest::
|
||||
>>> string = "¡kočka 😸!"
|
||||
>>> ascii(string)
|
||||
"'\\xa1ko\\u010dka \\U0001f638!'"
|
||||
|
||||
>>> f'{string = !a}'
|
||||
"string = '\\xa1ko\\u010dka \\U0001f638!'"
|
||||
|
||||
|
||||
Format specifier
|
||||
^^^^^^^^^^^^^^^^
|
||||
|
||||
After the expression has been evaluated, and possibly converted using an
|
||||
explicit conversion specifier, it is formatted using the :func:`format` function.
|
||||
If the replacement field includes a *format specifier* introduced by a colon
|
||||
(``:``), the specifier is passed to :func:`!format` as the second argument.
|
||||
The result of :func:`!format` is then used as the final value for the
|
||||
replacement field. For example::
|
||||
|
||||
>>> from fractions import Fraction
|
||||
>>> calculation = Fraction(1, 3)
|
||||
>>> f'{calculation=}'
|
||||
'calculation=Fraction(1, 3)'
|
||||
>>> f'{calculation = }'
|
||||
'calculation = Fraction(1, 3)'
|
||||
>>> f'{calculation = !s}'
|
||||
'calculation = 1/3'
|
||||
>>> one_third = Fraction(1, 3)
|
||||
>>> f'{one_third:.6f}'
|
||||
'0.333333'
|
||||
>>> f'{one_third:_^+10}'
|
||||
'___+1/3___'
|
||||
>>> >>> f'{one_third!r:_^20}'
|
||||
'___Fraction(1, 3)___'
|
||||
>>> f'{one_third = :~>10}~'
|
||||
'one_third = ~~~~~~~1/3~'
|
||||
|
||||
Once the output has been evaluated, it can be formatted using a
|
||||
:ref:`format specifier <formatstrings>` following a colon (``':'``).
|
||||
After the expression has been evaluated, and possibly converted to a string,
|
||||
the :meth:`!__format__` method of the result is called with the format specifier,
|
||||
or the empty string if no format specifier is given.
|
||||
The formatted result is then used as the final value for the replacement field.
|
||||
For example:
|
||||
.. _stdtypes-tstrings:
|
||||
|
||||
.. doctest::
|
||||
Template String Literals (t-strings)
|
||||
------------------------------------
|
||||
|
||||
>>> from fractions import Fraction
|
||||
>>> f'{Fraction(1, 7):.6f}'
|
||||
'0.142857'
|
||||
>>> f'{Fraction(1, 7):_^+10}'
|
||||
'___+1/7___'
|
||||
An :dfn:`t-string` (formally a :dfn:`template string literal`) is
|
||||
a string literal that is prefixed with ``t`` or ``T``.
|
||||
|
||||
These strings follow the same syntax and evaluation rules as
|
||||
:ref:`formatted string literals <stdtypes-fstrings>`,
|
||||
with for the following differences:
|
||||
|
||||
* Rather than evaluating to a ``str`` object, template string literals evaluate
|
||||
to a :class:`string.templatelib.Template` object.
|
||||
|
||||
* The :func:`format` protocol is not used.
|
||||
Instead, the format specifier and conversions (if any) are passed to
|
||||
a new :class:`~string.templatelib.Interpolation` object that is created
|
||||
for each evaluated expression.
|
||||
It is up to code that processes the resulting :class:`~string.templatelib.Template`
|
||||
object to decide how to handle format specifiers and conversions.
|
||||
|
||||
* Format specifiers containing nested replacement fields are evaluated eagerly,
|
||||
prior to being passed to the :class:`~string.templatelib.Interpolation` object.
|
||||
For instance, an interpolation of the form ``{amount:.{precision}f}`` will
|
||||
evaluate the inner expression ``{precision}`` to determine the value of the
|
||||
``format_spec`` attribute.
|
||||
If ``precision`` were to be ``2``, the resulting format specifier
|
||||
would be ``'.2f'``.
|
||||
|
||||
* When the equals sign ``'='`` is provided in an interpolation expression,
|
||||
the text of the expression is appended to the literal string that precedes
|
||||
the relevant interpolation.
|
||||
This includes the equals sign and any surrounding whitespace.
|
||||
The :class:`!Interpolation` instance for the expression will be created as
|
||||
normal, except that :attr:`~string.templatelib.Interpolation.conversion` will
|
||||
be set to '``r``' (:func:`repr`) by default.
|
||||
If an explicit conversion or format specifier are provided,
|
||||
this will override the default behaviour.
|
||||
|
||||
|
||||
.. _old-string-formatting:
|
||||
|
|
@ -3195,7 +3266,7 @@ objects.
|
|||
|
||||
See the :ref:`What's New <whatsnew315-bytearray-take-bytes>` entry for
|
||||
common code patterns which can be optimized with
|
||||
:func:`bytearray.take_bytes`.
|
||||
:meth:`bytearray.take_bytes`.
|
||||
|
||||
Since bytearray objects are sequences of integers (akin to a list), for a
|
||||
bytearray object *b*, ``b[0]`` will be an integer, while ``b[0:1]`` will be
|
||||
|
|
@ -4604,7 +4675,7 @@ copying.
|
|||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
.. method:: index(value, start=0, stop=sys.maxsize, /)
|
||||
.. method:: index(value, start=0, stop=sys.maxsize, /)
|
||||
|
||||
Return the index of the first occurrence of *value* (at or after
|
||||
index *start* and before index *stop*).
|
||||
|
|
@ -4755,11 +4826,12 @@ other sequence-like behavior.
|
|||
|
||||
There are currently two built-in set types, :class:`set` and :class:`frozenset`.
|
||||
The :class:`set` type is mutable --- the contents can be changed using methods
|
||||
like :meth:`~set.add` and :meth:`~set.remove`. Since it is mutable, it has no
|
||||
hash value and cannot be used as either a dictionary key or as an element of
|
||||
another set. The :class:`frozenset` type is immutable and :term:`hashable` ---
|
||||
its contents cannot be altered after it is created; it can therefore be used as
|
||||
a dictionary key or as an element of another set.
|
||||
like :meth:`~set.add` and :meth:`~set.remove`.
|
||||
Since it is mutable, it has no hash value and cannot be used as
|
||||
either a dictionary key or as an element of another set.
|
||||
The :class:`frozenset` type is immutable and :term:`hashable` ---
|
||||
its contents cannot be altered after it is created;
|
||||
it can therefore be used as a dictionary key or as an element of another set.
|
||||
|
||||
Non-empty sets (not frozensets) can be created by placing a comma-separated list
|
||||
of elements within braces, for example: ``{'jack', 'sjoerd'}``, in addition to the
|
||||
|
|
@ -4776,164 +4848,172 @@ The constructors for both classes work the same:
|
|||
objects. If *iterable* is not specified, a new empty set is
|
||||
returned.
|
||||
|
||||
Sets can be created by several means:
|
||||
Sets can be created by several means:
|
||||
|
||||
* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
|
||||
* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
|
||||
* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``
|
||||
* Use a comma-separated list of elements within braces: ``{'jack', 'sjoerd'}``
|
||||
* Use a set comprehension: ``{c for c in 'abracadabra' if c not in 'abc'}``
|
||||
* Use the type constructor: ``set()``, ``set('foobar')``, ``set(['a', 'b', 'foo'])``
|
||||
|
||||
Instances of :class:`set` and :class:`frozenset` provide the following
|
||||
operations:
|
||||
Instances of :class:`set` and :class:`frozenset` provide the following
|
||||
operations:
|
||||
|
||||
.. describe:: len(s)
|
||||
.. describe:: len(s)
|
||||
|
||||
Return the number of elements in set *s* (cardinality of *s*).
|
||||
Return the number of elements in set *s* (cardinality of *s*).
|
||||
|
||||
.. describe:: x in s
|
||||
.. describe:: x in s
|
||||
|
||||
Test *x* for membership in *s*.
|
||||
Test *x* for membership in *s*.
|
||||
|
||||
.. describe:: x not in s
|
||||
.. describe:: x not in s
|
||||
|
||||
Test *x* for non-membership in *s*.
|
||||
Test *x* for non-membership in *s*.
|
||||
|
||||
.. method:: isdisjoint(other, /)
|
||||
.. method:: frozenset.isdisjoint(other, /)
|
||||
set.isdisjoint(other, /)
|
||||
|
||||
Return ``True`` if the set has no elements in common with *other*. Sets are
|
||||
disjoint if and only if their intersection is the empty set.
|
||||
Return ``True`` if the set has no elements in common with *other*. Sets are
|
||||
disjoint if and only if their intersection is the empty set.
|
||||
|
||||
.. method:: issubset(other, /)
|
||||
set <= other
|
||||
.. method:: frozenset.issubset(other, /)
|
||||
set.issubset(other, /)
|
||||
.. describe:: set <= other
|
||||
|
||||
Test whether every element in the set is in *other*.
|
||||
Test whether every element in the set is in *other*.
|
||||
|
||||
.. method:: set < other
|
||||
.. describe:: set < other
|
||||
|
||||
Test whether the set is a proper subset of *other*, that is,
|
||||
``set <= other and set != other``.
|
||||
Test whether the set is a proper subset of *other*, that is,
|
||||
``set <= other and set != other``.
|
||||
|
||||
.. method:: issuperset(other, /)
|
||||
set >= other
|
||||
.. method:: frozenset.issuperset(other, /)
|
||||
set.issuperset(other, /)
|
||||
.. describe:: set >= other
|
||||
|
||||
Test whether every element in *other* is in the set.
|
||||
Test whether every element in *other* is in the set.
|
||||
|
||||
.. method:: set > other
|
||||
.. describe:: set > other
|
||||
|
||||
Test whether the set is a proper superset of *other*, that is, ``set >=
|
||||
other and set != other``.
|
||||
Test whether the set is a proper superset of *other*, that is, ``set >=
|
||||
other and set != other``.
|
||||
|
||||
.. method:: union(*others)
|
||||
set | other | ...
|
||||
.. method:: frozenset.union(*others)
|
||||
set.union(*others)
|
||||
.. describe:: set | other | ...
|
||||
|
||||
Return a new set with elements from the set and all others.
|
||||
Return a new set with elements from the set and all others.
|
||||
|
||||
.. method:: intersection(*others)
|
||||
set & other & ...
|
||||
.. method:: frozenset.intersection(*others)
|
||||
set.intersection(*others)
|
||||
.. describe:: set & other & ...
|
||||
|
||||
Return a new set with elements common to the set and all others.
|
||||
Return a new set with elements common to the set and all others.
|
||||
|
||||
.. method:: difference(*others)
|
||||
set - other - ...
|
||||
.. method:: frozenset.difference(*others)
|
||||
set.difference(*others)
|
||||
.. describe:: set - other - ...
|
||||
|
||||
Return a new set with elements in the set that are not in the others.
|
||||
Return a new set with elements in the set that are not in the others.
|
||||
|
||||
.. method:: symmetric_difference(other, /)
|
||||
set ^ other
|
||||
.. method:: frozenset.symmetric_difference(other, /)
|
||||
set.symmetric_difference(other, /)
|
||||
.. describe:: set ^ other
|
||||
|
||||
Return a new set with elements in either the set or *other* but not both.
|
||||
Return a new set with elements in either the set or *other* but not both.
|
||||
|
||||
.. method:: copy()
|
||||
.. method:: frozenset.copy()
|
||||
set.copy()
|
||||
|
||||
Return a shallow copy of the set.
|
||||
Return a shallow copy of the set.
|
||||
|
||||
|
||||
Note, the non-operator versions of :meth:`union`, :meth:`intersection`,
|
||||
:meth:`difference`, :meth:`symmetric_difference`, :meth:`issubset`, and
|
||||
:meth:`issuperset` methods will accept any iterable as an argument. In
|
||||
contrast, their operator based counterparts require their arguments to be
|
||||
sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
|
||||
in favor of the more readable ``set('abc').intersection('cbs')``.
|
||||
Note, the non-operator versions of :meth:`~frozenset.union`,
|
||||
:meth:`~frozenset.intersection`, :meth:`~frozenset.difference`, :meth:`~frozenset.symmetric_difference`, :meth:`~frozenset.issubset`, and
|
||||
:meth:`~frozenset.issuperset` methods will accept any iterable as an argument. In
|
||||
contrast, their operator based counterparts require their arguments to be
|
||||
sets. This precludes error-prone constructions like ``set('abc') & 'cbs'``
|
||||
in favor of the more readable ``set('abc').intersection('cbs')``.
|
||||
|
||||
Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
|
||||
sets are equal if and only if every element of each set is contained in the
|
||||
other (each is a subset of the other). A set is less than another set if and
|
||||
only if the first set is a proper subset of the second set (is a subset, but
|
||||
is not equal). A set is greater than another set if and only if the first set
|
||||
is a proper superset of the second set (is a superset, but is not equal).
|
||||
Both :class:`set` and :class:`frozenset` support set to set comparisons. Two
|
||||
sets are equal if and only if every element of each set is contained in the
|
||||
other (each is a subset of the other). A set is less than another set if and
|
||||
only if the first set is a proper subset of the second set (is a subset, but
|
||||
is not equal). A set is greater than another set if and only if the first set
|
||||
is a proper superset of the second set (is a superset, but is not equal).
|
||||
|
||||
Instances of :class:`set` are compared to instances of :class:`frozenset`
|
||||
based on their members. For example, ``set('abc') == frozenset('abc')``
|
||||
returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.
|
||||
Instances of :class:`set` are compared to instances of :class:`frozenset`
|
||||
based on their members. For example, ``set('abc') == frozenset('abc')``
|
||||
returns ``True`` and so does ``set('abc') in set([frozenset('abc')])``.
|
||||
|
||||
The subset and equality comparisons do not generalize to a total ordering
|
||||
function. For example, any two nonempty disjoint sets are not equal and are not
|
||||
subsets of each other, so *all* of the following return ``False``: ``a<b``,
|
||||
``a==b``, or ``a>b``.
|
||||
The subset and equality comparisons do not generalize to a total ordering
|
||||
function. For example, any two nonempty disjoint sets are not equal and are not
|
||||
subsets of each other, so *all* of the following return ``False``: ``a<b``,
|
||||
``a==b``, or ``a>b``.
|
||||
|
||||
Since sets only define partial ordering (subset relationships), the output of
|
||||
the :meth:`list.sort` method is undefined for lists of sets.
|
||||
Since sets only define partial ordering (subset relationships), the output of
|
||||
the :meth:`list.sort` method is undefined for lists of sets.
|
||||
|
||||
Set elements, like dictionary keys, must be :term:`hashable`.
|
||||
Set elements, like dictionary keys, must be :term:`hashable`.
|
||||
|
||||
Binary operations that mix :class:`set` instances with :class:`frozenset`
|
||||
return the type of the first operand. For example: ``frozenset('ab') |
|
||||
set('bc')`` returns an instance of :class:`frozenset`.
|
||||
Binary operations that mix :class:`set` instances with :class:`frozenset`
|
||||
return the type of the first operand. For example: ``frozenset('ab') |
|
||||
set('bc')`` returns an instance of :class:`frozenset`.
|
||||
|
||||
The following table lists operations available for :class:`set` that do not
|
||||
apply to immutable instances of :class:`frozenset`:
|
||||
The following table lists operations available for :class:`set` that do not
|
||||
apply to immutable instances of :class:`frozenset`:
|
||||
|
||||
.. method:: update(*others)
|
||||
set |= other | ...
|
||||
.. method:: set.update(*others)
|
||||
.. describe:: set |= other | ...
|
||||
|
||||
Update the set, adding elements from all others.
|
||||
Update the set, adding elements from all others.
|
||||
|
||||
.. method:: intersection_update(*others)
|
||||
set &= other & ...
|
||||
.. method:: set.intersection_update(*others)
|
||||
.. describe:: set &= other & ...
|
||||
|
||||
Update the set, keeping only elements found in it and all others.
|
||||
Update the set, keeping only elements found in it and all others.
|
||||
|
||||
.. method:: difference_update(*others)
|
||||
set -= other | ...
|
||||
.. method:: set.difference_update(*others)
|
||||
.. describe:: set -= other | ...
|
||||
|
||||
Update the set, removing elements found in others.
|
||||
Update the set, removing elements found in others.
|
||||
|
||||
.. method:: symmetric_difference_update(other, /)
|
||||
set ^= other
|
||||
.. method:: set.symmetric_difference_update(other, /)
|
||||
.. describe:: set ^= other
|
||||
|
||||
Update the set, keeping only elements found in either set, but not in both.
|
||||
Update the set, keeping only elements found in either set, but not in both.
|
||||
|
||||
.. method:: add(elem, /)
|
||||
.. method:: set.add(elem, /)
|
||||
|
||||
Add element *elem* to the set.
|
||||
Add element *elem* to the set.
|
||||
|
||||
.. method:: remove(elem, /)
|
||||
.. method:: set.remove(elem, /)
|
||||
|
||||
Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
|
||||
not contained in the set.
|
||||
Remove element *elem* from the set. Raises :exc:`KeyError` if *elem* is
|
||||
not contained in the set.
|
||||
|
||||
.. method:: discard(elem, /)
|
||||
.. method:: set.discard(elem, /)
|
||||
|
||||
Remove element *elem* from the set if it is present.
|
||||
Remove element *elem* from the set if it is present.
|
||||
|
||||
.. method:: pop()
|
||||
.. method:: set.pop()
|
||||
|
||||
Remove and return an arbitrary element from the set. Raises
|
||||
:exc:`KeyError` if the set is empty.
|
||||
Remove and return an arbitrary element from the set. Raises
|
||||
:exc:`KeyError` if the set is empty.
|
||||
|
||||
.. method:: clear()
|
||||
.. method:: set.clear()
|
||||
|
||||
Remove all elements from the set.
|
||||
Remove all elements from the set.
|
||||
|
||||
|
||||
Note, the non-operator versions of the :meth:`update`,
|
||||
:meth:`intersection_update`, :meth:`difference_update`, and
|
||||
:meth:`symmetric_difference_update` methods will accept any iterable as an
|
||||
argument.
|
||||
Note, the non-operator versions of the :meth:`~set.update`,
|
||||
:meth:`~set.intersection_update`, :meth:`~set.difference_update`, and
|
||||
:meth:`~set.symmetric_difference_update` methods will accept any iterable as an
|
||||
argument.
|
||||
|
||||
Note, the *elem* argument to the :meth:`~object.__contains__`,
|
||||
:meth:`remove`, and
|
||||
:meth:`discard` methods may be a set. To support searching for an equivalent
|
||||
frozenset, a temporary one is created from *elem*.
|
||||
Note, the *elem* argument to the :meth:`~object.__contains__`,
|
||||
:meth:`~set.remove`, and
|
||||
:meth:`~set.discard` methods may be a set. To support searching for an equivalent
|
||||
frozenset, a temporary one is created from *elem*.
|
||||
|
||||
|
||||
.. _typesmapping:
|
||||
|
|
|
|||
|
|
@ -831,7 +831,9 @@ Instances of the :class:`Popen` class have the following methods:
|
|||
|
||||
If the process does not terminate after *timeout* seconds, a
|
||||
:exc:`TimeoutExpired` exception will be raised. Catching this exception and
|
||||
retrying communication will not lose any output.
|
||||
retrying communication will not lose any output. Supplying *input* to a
|
||||
subsequent post-timeout :meth:`communicate` call is in undefined behavior
|
||||
and may become an error in the future.
|
||||
|
||||
The child process is not killed if the timeout expires, so in order to
|
||||
cleanup properly a well-behaved application should kill the child process and
|
||||
|
|
@ -844,6 +846,11 @@ Instances of the :class:`Popen` class have the following methods:
|
|||
proc.kill()
|
||||
outs, errs = proc.communicate()
|
||||
|
||||
After a call to :meth:`~Popen.communicate` raises :exc:`TimeoutExpired`, do
|
||||
not call :meth:`~Popen.wait`. Use an additional :meth:`~Popen.communicate`
|
||||
call to finish handling pipes and populate the :attr:`~Popen.returncode`
|
||||
attribute.
|
||||
|
||||
.. note::
|
||||
|
||||
The data read is buffered in memory, so do not use this method if the data
|
||||
|
|
|
|||
|
|
@ -438,7 +438,7 @@ run whether the test method succeeded or not.
|
|||
Such a working environment for the testing code is called a
|
||||
:dfn:`test fixture`. A new TestCase instance is created as a unique
|
||||
test fixture used to execute each individual test method. Thus
|
||||
:meth:`~TestCase.setUp`, :meth:`~TestCase.tearDown`, and :meth:`~TestCase.__init__`
|
||||
:meth:`~TestCase.setUp`, :meth:`~TestCase.tearDown`, and :meth:`!TestCase.__init__`
|
||||
will be called once per test.
|
||||
|
||||
It is recommended that you use TestCase implementations to group tests together
|
||||
|
|
@ -518,7 +518,7 @@ set-up and tear-down methods::
|
|||
subclasses will make future test refactorings infinitely easier.
|
||||
|
||||
In some cases, the existing tests may have been written using the :mod:`doctest`
|
||||
module. If so, :mod:`doctest` provides a :class:`DocTestSuite` class that can
|
||||
module. If so, :mod:`doctest` provides a :class:`~doctest.DocTestSuite` class that can
|
||||
automatically build :class:`unittest.TestSuite` instances from the existing
|
||||
:mod:`doctest`\ -based tests.
|
||||
|
||||
|
|
@ -1023,7 +1023,7 @@ Test cases
|
|||
additional keyword argument *msg*.
|
||||
|
||||
The context manager will store the caught exception object in its
|
||||
:attr:`exception` attribute. This can be useful if the intention
|
||||
:attr:`!exception` attribute. This can be useful if the intention
|
||||
is to perform additional checks on the exception raised::
|
||||
|
||||
with self.assertRaises(SomeException) as cm:
|
||||
|
|
@ -1036,7 +1036,7 @@ Test cases
|
|||
Added the ability to use :meth:`assertRaises` as a context manager.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
Added the :attr:`exception` attribute.
|
||||
Added the :attr:`!exception` attribute.
|
||||
|
||||
.. versionchanged:: 3.3
|
||||
Added the *msg* keyword argument when used as a context manager.
|
||||
|
|
@ -1089,8 +1089,8 @@ Test cases
|
|||
additional keyword argument *msg*.
|
||||
|
||||
The context manager will store the caught warning object in its
|
||||
:attr:`warning` attribute, and the source line which triggered the
|
||||
warnings in the :attr:`filename` and :attr:`lineno` attributes.
|
||||
:attr:`!warning` attribute, and the source line which triggered the
|
||||
warnings in the :attr:`!filename` and :attr:`!lineno` attributes.
|
||||
This can be useful if the intention is to perform additional checks
|
||||
on the warning caught::
|
||||
|
||||
|
|
@ -1437,7 +1437,7 @@ Test cases
|
|||
that lists the differences between the sets. This method is used by
|
||||
default when comparing sets or frozensets with :meth:`assertEqual`.
|
||||
|
||||
Fails if either of *first* or *second* does not have a :meth:`set.difference`
|
||||
Fails if either of *first* or *second* does not have a :meth:`~frozenset.difference`
|
||||
method.
|
||||
|
||||
.. versionadded:: 3.1
|
||||
|
|
@ -1645,7 +1645,7 @@ Test cases
|
|||
.. method:: asyncSetUp()
|
||||
:async:
|
||||
|
||||
Method called to prepare the test fixture. This is called after :meth:`setUp`.
|
||||
Method called to prepare the test fixture. This is called after :meth:`TestCase.setUp`.
|
||||
This is called immediately before calling the test method; other than
|
||||
:exc:`AssertionError` or :exc:`SkipTest`, any exception raised by this method
|
||||
will be considered an error rather than a test failure. The default implementation
|
||||
|
|
@ -1655,7 +1655,7 @@ Test cases
|
|||
:async:
|
||||
|
||||
Method called immediately after the test method has been called and the
|
||||
result recorded. This is called before :meth:`tearDown`. This is called even if
|
||||
result recorded. This is called before :meth:`~TestCase.tearDown`. This is called even if
|
||||
the test method raised an exception, so the implementation in subclasses may need
|
||||
to be particularly careful about checking internal state. Any exception, other than
|
||||
:exc:`AssertionError` or :exc:`SkipTest`, raised by this method will be
|
||||
|
|
@ -1684,7 +1684,7 @@ Test cases
|
|||
Sets up a new event loop to run the test, collecting the result into
|
||||
the :class:`TestResult` object passed as *result*. If *result* is
|
||||
omitted or ``None``, a temporary result object is created (by calling
|
||||
the :meth:`defaultTestResult` method) and used. The result object is
|
||||
the :meth:`~TestCase.defaultTestResult` method) and used. The result object is
|
||||
returned to :meth:`run`'s caller. At the end of the test all the tasks
|
||||
in the event loop are cancelled.
|
||||
|
||||
|
|
@ -1805,7 +1805,7 @@ Grouping tests
|
|||
returned by repeated iterations before :meth:`TestSuite.run` must be the
|
||||
same for each call iteration. After :meth:`TestSuite.run`, callers should
|
||||
not rely on the tests returned by this method unless the caller uses a
|
||||
subclass that overrides :meth:`TestSuite._removeTestAtIndex` to preserve
|
||||
subclass that overrides :meth:`!TestSuite._removeTestAtIndex` to preserve
|
||||
test references.
|
||||
|
||||
.. versionchanged:: 3.2
|
||||
|
|
@ -1816,10 +1816,10 @@ Grouping tests
|
|||
.. versionchanged:: 3.4
|
||||
In earlier versions the :class:`TestSuite` held references to each
|
||||
:class:`TestCase` after :meth:`TestSuite.run`. Subclasses can restore
|
||||
that behavior by overriding :meth:`TestSuite._removeTestAtIndex`.
|
||||
that behavior by overriding :meth:`!TestSuite._removeTestAtIndex`.
|
||||
|
||||
In the typical usage of a :class:`TestSuite` object, the :meth:`run` method
|
||||
is invoked by a :class:`TestRunner` rather than by the end-user test harness.
|
||||
is invoked by a :class:`!TestRunner` rather than by the end-user test harness.
|
||||
|
||||
|
||||
Loading and running tests
|
||||
|
|
@ -1853,12 +1853,12 @@ Loading and running tests
|
|||
.. method:: loadTestsFromTestCase(testCaseClass)
|
||||
|
||||
Return a suite of all test cases contained in the :class:`TestCase`\ -derived
|
||||
:class:`testCaseClass`.
|
||||
:class:`!testCaseClass`.
|
||||
|
||||
A test case instance is created for each method named by
|
||||
:meth:`getTestCaseNames`. By default these are the method names
|
||||
beginning with ``test``. If :meth:`getTestCaseNames` returns no
|
||||
methods, but the :meth:`runTest` method is implemented, a single test
|
||||
methods, but the :meth:`!runTest` method is implemented, a single test
|
||||
case is created for that method instead.
|
||||
|
||||
|
||||
|
|
@ -1905,13 +1905,13 @@ Loading and running tests
|
|||
case class will be picked up as "a test method within a test case class",
|
||||
rather than "a callable object".
|
||||
|
||||
For example, if you have a module :mod:`SampleTests` containing a
|
||||
:class:`TestCase`\ -derived class :class:`SampleTestCase` with three test
|
||||
methods (:meth:`test_one`, :meth:`test_two`, and :meth:`test_three`), the
|
||||
For example, if you have a module :mod:`!SampleTests` containing a
|
||||
:class:`TestCase`\ -derived class :class:`!SampleTestCase` with three test
|
||||
methods (:meth:`!test_one`, :meth:`!test_two`, and :meth:`!test_three`), the
|
||||
specifier ``'SampleTests.SampleTestCase'`` would cause this method to
|
||||
return a suite which will run all three test methods. Using the specifier
|
||||
``'SampleTests.SampleTestCase.test_two'`` would cause it to return a test
|
||||
suite which will run only the :meth:`test_two` test method. The specifier
|
||||
suite which will run only the :meth:`!test_two` test method. The specifier
|
||||
can refer to modules and packages which have not been imported; they will
|
||||
be imported as a side-effect.
|
||||
|
||||
|
|
@ -2058,7 +2058,7 @@ Loading and running tests
|
|||
Testing frameworks built on top of :mod:`unittest` may want access to the
|
||||
:class:`TestResult` object generated by running a set of tests for reporting
|
||||
purposes; a :class:`TestResult` instance is returned by the
|
||||
:meth:`TestRunner.run` method for this purpose.
|
||||
:meth:`!TestRunner.run` method for this purpose.
|
||||
|
||||
:class:`TestResult` instances have the following attributes that will be of
|
||||
interest when inspecting the results of running a set of tests:
|
||||
|
|
@ -2144,12 +2144,12 @@ Loading and running tests
|
|||
|
||||
This method can be called to signal that the set of tests being run should
|
||||
be aborted by setting the :attr:`shouldStop` attribute to ``True``.
|
||||
:class:`TestRunner` objects should respect this flag and return without
|
||||
:class:`!TestRunner` objects should respect this flag and return without
|
||||
running any additional tests.
|
||||
|
||||
For example, this feature is used by the :class:`TextTestRunner` class to
|
||||
stop the test framework when the user signals an interrupt from the
|
||||
keyboard. Interactive tools which provide :class:`TestRunner`
|
||||
keyboard. Interactive tools which provide :class:`!TestRunner`
|
||||
implementations can use this in a similar manner.
|
||||
|
||||
The following methods of the :class:`TestResult` class are used to maintain
|
||||
|
|
@ -2469,9 +2469,9 @@ Class and Module Fixtures
|
|||
-------------------------
|
||||
|
||||
Class and module level fixtures are implemented in :class:`TestSuite`. When
|
||||
the test suite encounters a test from a new class then :meth:`tearDownClass`
|
||||
from the previous class (if there is one) is called, followed by
|
||||
:meth:`setUpClass` from the new class.
|
||||
the test suite encounters a test from a new class then
|
||||
:meth:`~TestCase.tearDownClass` from the previous class (if there is one)
|
||||
is called, followed by :meth:`~TestCase.setUpClass` from the new class.
|
||||
|
||||
Similarly if a test is from a different module from the previous test then
|
||||
``tearDownModule`` from the previous module is run, followed by
|
||||
|
|
|
|||
|
|
@ -74,7 +74,7 @@ given point) or to make use of the :func:`DOMEventStream.expandNode` method
|
|||
and switch to DOM-related processing.
|
||||
|
||||
|
||||
.. class:: PullDom(documentFactory=None)
|
||||
.. class:: PullDOM(documentFactory=None)
|
||||
|
||||
Subclass of :class:`xml.sax.handler.ContentHandler`.
|
||||
|
||||
|
|
|
|||
|
|
@ -96,6 +96,14 @@ for the feature and property names.
|
|||
|
||||
.. data:: feature_external_ges
|
||||
|
||||
.. warning::
|
||||
|
||||
Enabling opens a vulnerability to
|
||||
`external entity attacks <https://en.wikipedia.org/wiki/XML_external_entity_attack>`_
|
||||
if the parser is used with user-provided XML content.
|
||||
Please reflect on your `threat model <https://en.wikipedia.org/wiki/Threat_model>`_
|
||||
before enabling this feature.
|
||||
|
||||
| value: ``"http://xml.org/sax/features/external-general-entities"``
|
||||
| true: Include all external general (text) entities.
|
||||
| false: Do not include external general entities.
|
||||
|
|
|
|||
|
|
@ -472,7 +472,7 @@ remote server into a single request [#]_.
|
|||
|
||||
Create an object used to boxcar method calls. *server* is the eventual target of
|
||||
the call. Calls can be made to the result object, but they will immediately
|
||||
return ``None``, and only store the call name and parameters in the
|
||||
return ``None``, and only store the call name and arguments in the
|
||||
:class:`MultiCall` object. Calling the object itself causes all stored calls to
|
||||
be transmitted as a single ``system.multicall`` request. The result of this call
|
||||
is a :term:`generator`; iterating over this generator yields the individual
|
||||
|
|
|
|||
|
|
@ -16,10 +16,10 @@ provides tools to create, read, write, append, and list a ZIP file. Any
|
|||
advanced use of this module will require an understanding of the format, as
|
||||
defined in `PKZIP Application Note`_.
|
||||
|
||||
This module does not currently handle multi-disk ZIP files.
|
||||
This module does not handle multipart ZIP files.
|
||||
It can handle ZIP files that use the ZIP64 extensions
|
||||
(that is ZIP files that are more than 4 GiB in size). It supports
|
||||
decryption of encrypted files in ZIP archives, but it currently cannot
|
||||
decryption of encrypted files in ZIP archives, but it cannot
|
||||
create an encrypted file. Decryption is extremely slow as it is
|
||||
implemented in native Python rather than C.
|
||||
|
||||
|
|
@ -175,7 +175,7 @@ The module defines the following items:
|
|||
|
||||
.. _zipfile-objects:
|
||||
|
||||
ZipFile Objects
|
||||
ZipFile objects
|
||||
---------------
|
||||
|
||||
|
||||
|
|
@ -248,7 +248,7 @@ ZipFile Objects
|
|||
.. note::
|
||||
|
||||
*metadata_encoding* is an instance-wide setting for the ZipFile.
|
||||
It is not currently possible to set this on a per-member basis.
|
||||
It is not possible to set this on a per-member basis.
|
||||
|
||||
This attribute is a workaround for legacy implementations which produce
|
||||
archives with names in the current locale encoding or code page (mostly
|
||||
|
|
@ -571,7 +571,7 @@ The following data attributes are also available:
|
|||
|
||||
.. _path-objects:
|
||||
|
||||
Path Objects
|
||||
Path objects
|
||||
------------
|
||||
|
||||
.. class:: Path(root, at='')
|
||||
|
|
@ -707,7 +707,7 @@ changes.
|
|||
|
||||
.. _pyzipfile-objects:
|
||||
|
||||
PyZipFile Objects
|
||||
PyZipFile objects
|
||||
-----------------
|
||||
|
||||
The :class:`PyZipFile` constructor takes the same parameters as the
|
||||
|
|
@ -784,7 +784,7 @@ The :class:`PyZipFile` constructor takes the same parameters as the
|
|||
|
||||
.. _zipinfo-objects:
|
||||
|
||||
ZipInfo Objects
|
||||
ZipInfo objects
|
||||
---------------
|
||||
|
||||
Instances of the :class:`ZipInfo` class are returned by the :meth:`.getinfo` and
|
||||
|
|
@ -954,7 +954,7 @@ Instances have the following methods and attributes:
|
|||
.. _zipfile-commandline:
|
||||
.. program:: zipfile
|
||||
|
||||
Command-Line Interface
|
||||
Command-line interface
|
||||
----------------------
|
||||
|
||||
The :mod:`zipfile` module provides a simple command-line interface to interact
|
||||
|
|
@ -1029,7 +1029,7 @@ From file itself
|
|||
Decompression may fail due to incorrect password / CRC checksum / ZIP format or
|
||||
unsupported compression method / decryption.
|
||||
|
||||
File System limitations
|
||||
File system limitations
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Exceeding limitations on different file systems can cause decompression failed.
|
||||
|
|
|
|||
|
|
@ -449,7 +449,7 @@ Sets
|
|||
|
||||
These represent a mutable set. They are created by the built-in :func:`set`
|
||||
constructor and can be modified afterwards by several methods, such as
|
||||
:meth:`add <frozenset.add>`.
|
||||
:meth:`~set.add`.
|
||||
|
||||
|
||||
Frozen sets
|
||||
|
|
@ -2630,8 +2630,8 @@ Notes on using *__slots__*:
|
|||
descriptor directly from the base class). This renders the meaning of the
|
||||
program undefined. In the future, a check may be added to prevent this.
|
||||
|
||||
* :exc:`TypeError` will be raised if nonempty *__slots__* are defined for a
|
||||
class derived from a
|
||||
* :exc:`TypeError` will be raised if *__slots__* other than *__dict__* and
|
||||
*__weakref__* are defined for a class derived from a
|
||||
:c:member:`"variable-length" built-in type <PyTypeObject.tp_itemsize>` such as
|
||||
:class:`int`, :class:`bytes`, and :class:`tuple`.
|
||||
|
||||
|
|
@ -2656,6 +2656,10 @@ Notes on using *__slots__*:
|
|||
of the iterator's values. However, the *__slots__* attribute will be an empty
|
||||
iterator.
|
||||
|
||||
.. versionchanged:: next
|
||||
Allowed defining the *__dict__* and *__weakref__* *__slots__* for any class.
|
||||
|
||||
|
||||
.. _class-customization:
|
||||
|
||||
Customizing class creation
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ Formally:
|
|||
.. grammar-snippet::
|
||||
:group: python-grammar
|
||||
|
||||
strings: ( `STRING` | fstring)+ | tstring+
|
||||
strings: ( `STRING` | `fstring`)+ | `tstring`+
|
||||
|
||||
This feature is defined at the syntactical level, so it only works with literals.
|
||||
To concatenate string expressions at run time, the '+' operator may be used::
|
||||
|
|
|
|||
|
|
@ -345,7 +345,15 @@ Whitespace between tokens
|
|||
|
||||
Except at the beginning of a logical line or in string literals, the whitespace
|
||||
characters space, tab and formfeed can be used interchangeably to separate
|
||||
tokens. Whitespace is needed between two tokens only if their concatenation
|
||||
tokens:
|
||||
|
||||
.. grammar-snippet::
|
||||
:group: python-grammar
|
||||
|
||||
whitespace: ' ' | tab | formfeed
|
||||
|
||||
|
||||
Whitespace is needed between two tokens only if their concatenation
|
||||
could otherwise be interpreted as a different token. For example, ``ab`` is one
|
||||
token, but ``a b`` is two tokens. However, ``+a`` and ``+ a`` both produce
|
||||
two tokens, ``+`` and ``a``, as ``+a`` is not a valid token.
|
||||
|
|
@ -386,73 +394,29 @@ Names (identifiers and keywords)
|
|||
:data:`~token.NAME` tokens represent *identifiers*, *keywords*, and
|
||||
*soft keywords*.
|
||||
|
||||
Within the ASCII range (U+0001..U+007F), the valid characters for names
|
||||
include the uppercase and lowercase letters (``A-Z`` and ``a-z``),
|
||||
the underscore ``_`` and, except for the first character, the digits
|
||||
``0`` through ``9``.
|
||||
Names are composed of the following characters:
|
||||
|
||||
* uppercase and lowercase letters (``A-Z`` and ``a-z``),
|
||||
* the underscore (``_``),
|
||||
* digits (``0`` through ``9``), which cannot appear as the first character, and
|
||||
* non-ASCII characters. Valid names may only contain "letter-like" and
|
||||
"digit-like" characters; see :ref:`lexical-names-nonascii` for details.
|
||||
|
||||
Names must contain at least one character, but have no upper length limit.
|
||||
Case is significant.
|
||||
|
||||
Besides ``A-Z``, ``a-z``, ``_`` and ``0-9``, names can also use "letter-like"
|
||||
and "number-like" characters from outside the ASCII range, as detailed below.
|
||||
|
||||
All identifiers are converted into the `normalization form`_ NFKC while
|
||||
parsing; comparison of identifiers is based on NFKC.
|
||||
|
||||
Formally, the first character of a normalized identifier must belong to the
|
||||
set ``id_start``, which is the union of:
|
||||
|
||||
* Unicode category ``<Lu>`` - uppercase letters (includes ``A`` to ``Z``)
|
||||
* Unicode category ``<Ll>`` - lowercase letters (includes ``a`` to ``z``)
|
||||
* Unicode category ``<Lt>`` - titlecase letters
|
||||
* Unicode category ``<Lm>`` - modifier letters
|
||||
* Unicode category ``<Lo>`` - other letters
|
||||
* Unicode category ``<Nl>`` - letter numbers
|
||||
* {``"_"``} - the underscore
|
||||
* ``<Other_ID_Start>`` - an explicit set of characters in `PropList.txt`_
|
||||
to support backwards compatibility
|
||||
|
||||
The remaining characters must belong to the set ``id_continue``, which is the
|
||||
union of:
|
||||
|
||||
* all characters in ``id_start``
|
||||
* Unicode category ``<Nd>`` - decimal numbers (includes ``0`` to ``9``)
|
||||
* Unicode category ``<Pc>`` - connector punctuations
|
||||
* Unicode category ``<Mn>`` - nonspacing marks
|
||||
* Unicode category ``<Mc>`` - spacing combining marks
|
||||
* ``<Other_ID_Continue>`` - another explicit set of characters in
|
||||
`PropList.txt`_ to support backwards compatibility
|
||||
|
||||
Unicode categories use the version of the Unicode Character Database as
|
||||
included in the :mod:`unicodedata` module.
|
||||
|
||||
These sets are based on the Unicode standard annex `UAX-31`_.
|
||||
See also :pep:`3131` for further details.
|
||||
|
||||
Even more formally, names are described by the following lexical definitions:
|
||||
Formally, names are described by the following lexical definitions:
|
||||
|
||||
.. grammar-snippet::
|
||||
:group: python-grammar
|
||||
|
||||
NAME: `xid_start` `xid_continue`*
|
||||
id_start: <Lu> | <Ll> | <Lt> | <Lm> | <Lo> | <Nl> | "_" | <Other_ID_Start>
|
||||
id_continue: `id_start` | <Nd> | <Pc> | <Mn> | <Mc> | <Other_ID_Continue>
|
||||
xid_start: <all characters in `id_start` whose NFKC normalization is
|
||||
in (`id_start` `xid_continue`*)">
|
||||
xid_continue: <all characters in `id_continue` whose NFKC normalization is
|
||||
in (`id_continue`*)">
|
||||
identifier: <`NAME`, except keywords>
|
||||
NAME: `name_start` `name_continue`*
|
||||
name_start: "a"..."z" | "A"..."Z" | "_" | <non-ASCII character>
|
||||
name_continue: name_start | "0"..."9"
|
||||
identifier: <`NAME`, except keywords>
|
||||
|
||||
A non-normative listing of all valid identifier characters as defined by
|
||||
Unicode is available in the `DerivedCoreProperties.txt`_ file in the Unicode
|
||||
Character Database.
|
||||
|
||||
|
||||
.. _UAX-31: https://www.unicode.org/reports/tr31/
|
||||
.. _PropList.txt: https://www.unicode.org/Public/17.0.0/ucd/PropList.txt
|
||||
.. _DerivedCoreProperties.txt: https://www.unicode.org/Public/17.0.0/ucd/DerivedCoreProperties.txt
|
||||
.. _normalization form: https://www.unicode.org/reports/tr15/#Norm_Forms
|
||||
Note that not all names matched by this grammar are valid; see
|
||||
:ref:`lexical-names-nonascii` for details.
|
||||
|
||||
|
||||
.. _keywords:
|
||||
|
|
@ -555,6 +519,95 @@ characters:
|
|||
:ref:`atom-identifiers`.
|
||||
|
||||
|
||||
.. _lexical-names-nonascii:
|
||||
|
||||
Non-ASCII characters in names
|
||||
-----------------------------
|
||||
|
||||
Names that contain non-ASCII characters need additional normalization
|
||||
and validation beyond the rules and grammar explained
|
||||
:ref:`above <identifiers>`.
|
||||
For example, ``ř_1``, ``蛇``, or ``साँप`` are valid names, but ``r〰2``,
|
||||
``€``, or ``🐍`` are not.
|
||||
|
||||
This section explains the exact rules.
|
||||
|
||||
All names are converted into the `normalization form`_ NFKC while parsing.
|
||||
This means that, for example, some typographic variants of characters are
|
||||
converted to their "basic" form. For example, ``fiⁿₐˡᵢᶻₐᵗᵢᵒₙ`` normalizes to
|
||||
``finalization``, so Python treats them as the same name::
|
||||
|
||||
>>> fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = 3
|
||||
>>> finalization
|
||||
3
|
||||
|
||||
.. note::
|
||||
|
||||
Normalization is done at the lexical level only.
|
||||
Run-time functions that take names as *strings* generally do not normalize
|
||||
their arguments.
|
||||
For example, the variable defined above is accessible at run time in the
|
||||
:func:`globals` dictionary as ``globals()["finalization"]`` but not
|
||||
``globals()["fiⁿₐˡᵢᶻₐᵗᵢᵒₙ"]``.
|
||||
|
||||
Similarly to how ASCII-only names must contain only letters, digits and
|
||||
the underscore, and cannot start with a digit, a valid name must
|
||||
start with a character in the "letter-like" set ``xid_start``,
|
||||
and the remaining characters must be in the "letter- and digit-like" set
|
||||
``xid_continue``.
|
||||
|
||||
These sets based on the *XID_Start* and *XID_Continue* sets as defined by the
|
||||
Unicode standard annex `UAX-31`_.
|
||||
Python's ``xid_start`` additionally includes the underscore (``_``).
|
||||
Note that Python does not necessarily conform to `UAX-31`_.
|
||||
|
||||
A non-normative listing of characters in the *XID_Start* and *XID_Continue*
|
||||
sets as defined by Unicode is available in the `DerivedCoreProperties.txt`_
|
||||
file in the Unicode Character Database.
|
||||
For reference, the construction rules for the ``xid_*`` sets are given below.
|
||||
|
||||
The set ``id_start`` is defined as the union of:
|
||||
|
||||
* Unicode category ``<Lu>`` - uppercase letters (includes ``A`` to ``Z``)
|
||||
* Unicode category ``<Ll>`` - lowercase letters (includes ``a`` to ``z``)
|
||||
* Unicode category ``<Lt>`` - titlecase letters
|
||||
* Unicode category ``<Lm>`` - modifier letters
|
||||
* Unicode category ``<Lo>`` - other letters
|
||||
* Unicode category ``<Nl>`` - letter numbers
|
||||
* {``"_"``} - the underscore
|
||||
* ``<Other_ID_Start>`` - an explicit set of characters in `PropList.txt`_
|
||||
to support backwards compatibility
|
||||
|
||||
The set ``xid_start`` then closes this set under NFKC normalization, by
|
||||
removing all characters whose normalization is not of the form
|
||||
``id_start id_continue*``.
|
||||
|
||||
The set ``id_continue`` is defined as the union of:
|
||||
|
||||
* ``id_start`` (see above)
|
||||
* Unicode category ``<Nd>`` - decimal numbers (includes ``0`` to ``9``)
|
||||
* Unicode category ``<Pc>`` - connector punctuations
|
||||
* Unicode category ``<Mn>`` - nonspacing marks
|
||||
* Unicode category ``<Mc>`` - spacing combining marks
|
||||
* ``<Other_ID_Continue>`` - another explicit set of characters in
|
||||
`PropList.txt`_ to support backwards compatibility
|
||||
|
||||
Again, ``xid_continue`` closes this set under NFKC normalization.
|
||||
|
||||
Unicode categories use the version of the Unicode Character Database as
|
||||
included in the :mod:`unicodedata` module.
|
||||
|
||||
.. _UAX-31: https://www.unicode.org/reports/tr31/
|
||||
.. _PropList.txt: https://www.unicode.org/Public/17.0.0/ucd/PropList.txt
|
||||
.. _DerivedCoreProperties.txt: https://www.unicode.org/Public/17.0.0/ucd/DerivedCoreProperties.txt
|
||||
.. _normalization form: https://www.unicode.org/reports/tr15/#Norm_Forms
|
||||
|
||||
.. seealso::
|
||||
|
||||
* :pep:`3131` -- Supporting Non-ASCII Identifiers
|
||||
* :pep:`672` -- Unicode-related Security Considerations for Python
|
||||
|
||||
|
||||
.. _literals:
|
||||
|
||||
Literals
|
||||
|
|
@ -987,124 +1040,59 @@ f-strings
|
|||
---------
|
||||
|
||||
.. versionadded:: 3.6
|
||||
.. versionchanged:: 3.7
|
||||
The :keyword:`await` and :keyword:`async for` can be used in expressions
|
||||
within f-strings.
|
||||
.. versionchanged:: 3.8
|
||||
Added the debug specifier (``=``)
|
||||
.. versionchanged:: 3.12
|
||||
Many restrictions on expressions within f-strings have been removed.
|
||||
Notably, nested strings, comments, and backslashes are now permitted.
|
||||
|
||||
A :dfn:`formatted string literal` or :dfn:`f-string` is a string literal
|
||||
that is prefixed with '``f``' or '``F``'. These strings may contain
|
||||
replacement fields, which are expressions delimited by curly braces ``{}``.
|
||||
While other string literals always have a constant value, formatted strings
|
||||
are really expressions evaluated at run time.
|
||||
that is prefixed with '``f``' or '``F``'.
|
||||
Unlike other string literals, f-strings do not have a constant value.
|
||||
They may contain *replacement fields* delimited by curly braces ``{}``.
|
||||
Replacement fields contain expressions which are evaluated at run time.
|
||||
For example::
|
||||
|
||||
Escape sequences are decoded like in ordinary string literals (except when
|
||||
a literal is also marked as a raw string). After decoding, the grammar
|
||||
for the contents of the string is:
|
||||
>>> who = 'nobody'
|
||||
>>> nationality = 'Spanish'
|
||||
>>> f'{who.title()} expects the {nationality} Inquisition!'
|
||||
'Nobody expects the Spanish Inquisition!'
|
||||
|
||||
.. productionlist:: python-grammar
|
||||
f_string: (`literal_char` | "{{" | "}}" | `replacement_field`)*
|
||||
replacement_field: "{" `f_expression` ["="] ["!" `conversion`] [":" `format_spec`] "}"
|
||||
f_expression: (`conditional_expression` | "*" `or_expr`)
|
||||
: ("," `conditional_expression` | "," "*" `or_expr`)* [","]
|
||||
: | `yield_expression`
|
||||
conversion: "s" | "r" | "a"
|
||||
format_spec: (`literal_char` | `replacement_field`)*
|
||||
literal_char: <any code point except "{", "}" or NULL>
|
||||
Any doubled curly braces (``{{`` or ``}}``) outside replacement fields
|
||||
are replaced with the corresponding single curly brace::
|
||||
|
||||
The parts of the string outside curly braces are treated literally,
|
||||
except that any doubled curly braces ``'{{'`` or ``'}}'`` are replaced
|
||||
with the corresponding single curly brace. A single opening curly
|
||||
bracket ``'{'`` marks a replacement field, which starts with a
|
||||
Python expression. To display both the expression text and its value after
|
||||
evaluation, (useful in debugging), an equal sign ``'='`` may be added after the
|
||||
expression. A conversion field, introduced by an exclamation point ``'!'`` may
|
||||
follow. A format specifier may also be appended, introduced by a colon ``':'``.
|
||||
A replacement field ends with a closing curly bracket ``'}'``.
|
||||
>>> print(f'{{...}}')
|
||||
{...}
|
||||
|
||||
Other characters outside replacement fields are treated like in ordinary
|
||||
string literals.
|
||||
This means that escape sequences are decoded (except when a literal is
|
||||
also marked as a raw string), and newlines are possible in triple-quoted
|
||||
f-strings::
|
||||
|
||||
>>> name = 'Galahad'
|
||||
>>> favorite_color = 'blue'
|
||||
>>> print(f'{name}:\t{favorite_color}')
|
||||
Galahad: blue
|
||||
>>> print(rf"C:\Users\{name}")
|
||||
C:\Users\Galahad
|
||||
>>> print(f'''Three shall be the number of the counting
|
||||
... and the number of the counting shall be three.''')
|
||||
Three shall be the number of the counting
|
||||
and the number of the counting shall be three.
|
||||
|
||||
Expressions in formatted string literals are treated like regular
|
||||
Python expressions surrounded by parentheses, with a few exceptions.
|
||||
An empty expression is not allowed, and both :keyword:`lambda` and
|
||||
assignment expressions ``:=`` must be surrounded by explicit parentheses.
|
||||
Python expressions.
|
||||
Each expression is evaluated in the context where the formatted string literal
|
||||
appears, in order from left to right. Replacement expressions can contain
|
||||
newlines in both single-quoted and triple-quoted f-strings and they can contain
|
||||
comments. Everything that comes after a ``#`` inside a replacement field
|
||||
is a comment (even closing braces and quotes). In that case, replacement fields
|
||||
must be closed in a different line.
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
>>> f"abc{a # This is a comment }"
|
||||
... + 3}"
|
||||
'abc5'
|
||||
|
||||
.. versionchanged:: 3.7
|
||||
Prior to Python 3.7, an :keyword:`await` expression and comprehensions
|
||||
containing an :keyword:`async for` clause were illegal in the expressions
|
||||
in formatted string literals due to a problem with the implementation.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
Prior to Python 3.12, comments were not allowed inside f-string replacement
|
||||
fields.
|
||||
|
||||
When the equal sign ``'='`` is provided, the output will have the expression
|
||||
text, the ``'='`` and the evaluated value. Spaces after the opening brace
|
||||
``'{'``, within the expression and after the ``'='`` are all retained in the
|
||||
output. By default, the ``'='`` causes the :func:`repr` of the expression to be
|
||||
provided, unless there is a format specified. When a format is specified it
|
||||
defaults to the :func:`str` of the expression unless a conversion ``'!r'`` is
|
||||
declared.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
The equal sign ``'='``.
|
||||
|
||||
If a conversion is specified, the result of evaluating the expression
|
||||
is converted before formatting. Conversion ``'!s'`` calls :func:`str` on
|
||||
the result, ``'!r'`` calls :func:`repr`, and ``'!a'`` calls :func:`ascii`.
|
||||
|
||||
The result is then formatted using the :func:`format` protocol. The
|
||||
format specifier is passed to the :meth:`~object.__format__` method of the
|
||||
expression or conversion result. An empty string is passed when the
|
||||
format specifier is omitted. The formatted result is then included in
|
||||
the final value of the whole string.
|
||||
|
||||
Top-level format specifiers may include nested replacement fields. These nested
|
||||
fields may include their own conversion fields and :ref:`format specifiers
|
||||
<formatspec>`, but may not include more deeply nested replacement fields. The
|
||||
:ref:`format specifier mini-language <formatspec>` is the same as that used by
|
||||
the :meth:`str.format` method.
|
||||
|
||||
Formatted string literals may be concatenated, but replacement fields
|
||||
cannot be split across literals.
|
||||
|
||||
Some examples of formatted string literals::
|
||||
|
||||
>>> name = "Fred"
|
||||
>>> f"He said his name is {name!r}."
|
||||
"He said his name is 'Fred'."
|
||||
>>> f"He said his name is {repr(name)}." # repr() is equivalent to !r
|
||||
"He said his name is 'Fred'."
|
||||
>>> width = 10
|
||||
>>> precision = 4
|
||||
>>> value = decimal.Decimal("12.34567")
|
||||
>>> f"result: {value:{width}.{precision}}" # nested fields
|
||||
'result: 12.35'
|
||||
>>> today = datetime(year=2017, month=1, day=27)
|
||||
>>> f"{today:%B %d, %Y}" # using date format specifier
|
||||
'January 27, 2017'
|
||||
>>> f"{today=:%B %d, %Y}" # using date format specifier and debugging
|
||||
'today=January 27, 2017'
|
||||
>>> number = 1024
|
||||
>>> f"{number:#0x}" # using integer format specifier
|
||||
'0x400'
|
||||
>>> foo = "bar"
|
||||
>>> f"{ foo = }" # preserves whitespace
|
||||
" foo = 'bar'"
|
||||
>>> line = "The mill's closed"
|
||||
>>> f"{line = }"
|
||||
'line = "The mill\'s closed"'
|
||||
>>> f"{line = :20}"
|
||||
"line = The mill's closed "
|
||||
>>> f"{line = !r:20}"
|
||||
'line = "The mill\'s closed" '
|
||||
appears, in order from left to right.
|
||||
An empty expression is not allowed, and both :keyword:`lambda` and
|
||||
assignment expressions ``:=`` must be surrounded by explicit parentheses::
|
||||
|
||||
>>> f'{(half := 1/2)}, {half * 42}'
|
||||
'0.5, 21.0'
|
||||
|
||||
Reusing the outer f-string quoting type inside a replacement field is
|
||||
permitted::
|
||||
|
|
@ -1113,10 +1101,6 @@ permitted::
|
|||
>>> f"abc {a["x"]} def"
|
||||
'abc 2 def'
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
Prior to Python 3.12, reuse of the same quoting type of the outer f-string
|
||||
inside a replacement field was not possible.
|
||||
|
||||
Backslashes are also allowed in replacement fields and are evaluated the same
|
||||
way as in any other context::
|
||||
|
||||
|
|
@ -1127,23 +1111,84 @@ way as in any other context::
|
|||
b
|
||||
c
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
Prior to Python 3.12, backslashes were not permitted inside an f-string
|
||||
replacement field.
|
||||
It is possible to nest f-strings::
|
||||
|
||||
Formatted string literals cannot be used as docstrings, even if they do not
|
||||
include expressions.
|
||||
>>> name = 'world'
|
||||
>>> f'Repeated:{f' hello {name}' * 3}'
|
||||
'Repeated: hello world hello world hello world'
|
||||
|
||||
::
|
||||
Portable Python programs should not use more than 5 levels of nesting.
|
||||
|
||||
.. impl-detail::
|
||||
|
||||
CPython does not limit nesting of f-strings.
|
||||
|
||||
Replacement expressions can contain newlines in both single-quoted and
|
||||
triple-quoted f-strings and they can contain comments.
|
||||
Everything that comes after a ``#`` inside a replacement field
|
||||
is a comment (even closing braces and quotes).
|
||||
This means that replacement fields with comments must be closed in a
|
||||
different line:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
>>> a = 2
|
||||
>>> f"abc{a # This comment }" continues until the end of the line
|
||||
... + 3}"
|
||||
'abc5'
|
||||
|
||||
After the expression, replacement fields may optionally contain:
|
||||
|
||||
* a *debug specifier* -- an equal sign (``=``), optionally surrounded by
|
||||
whitespace on one or both sides;
|
||||
* a *conversion specifier* -- ``!s``, ``!r`` or ``!a``; and/or
|
||||
* a *format specifier* prefixed with a colon (``:``).
|
||||
|
||||
See the :ref:`Standard Library section on f-strings <stdtypes-fstrings>`
|
||||
for details on how these fields are evaluated.
|
||||
|
||||
As that section explains, *format specifiers* are passed as the second argument
|
||||
to the :func:`format` function to format a replacement field value.
|
||||
For example, they can be used to specify a field width and padding characters
|
||||
using the :ref:`Format Specification Mini-Language <formatspec>`::
|
||||
|
||||
>>> number = 14.3
|
||||
>>> f'{number:20.7f}'
|
||||
' 14.3000000'
|
||||
|
||||
Top-level format specifiers may include nested replacement fields::
|
||||
|
||||
>>> field_size = 20
|
||||
>>> precision = 7
|
||||
>>> f'{number:{field_size}.{precision}f}'
|
||||
' 14.3000000'
|
||||
|
||||
These nested fields may include their own conversion fields and
|
||||
:ref:`format specifiers <formatspec>`::
|
||||
|
||||
>>> number = 3
|
||||
>>> f'{number:{field_size}}'
|
||||
' 3'
|
||||
>>> f'{number:{field_size:05}}'
|
||||
'00000000000000000003'
|
||||
|
||||
However, these nested fields may not include more deeply nested replacement
|
||||
fields.
|
||||
|
||||
Formatted string literals cannot be used as :term:`docstrings <docstring>`,
|
||||
even if they do not include expressions::
|
||||
|
||||
>>> def foo():
|
||||
... f"Not a docstring"
|
||||
...
|
||||
>>> foo.__doc__ is None
|
||||
True
|
||||
>>> print(foo.__doc__)
|
||||
None
|
||||
|
||||
See also :pep:`498` for the proposal that added formatted string literals,
|
||||
and :meth:`str.format`, which uses a related format string mechanism.
|
||||
.. seealso::
|
||||
|
||||
* :pep:`498` -- Literal String Interpolation
|
||||
* :pep:`701` -- Syntactic formalization of f-strings
|
||||
* :meth:`str.format`, which uses a related format string mechanism.
|
||||
|
||||
|
||||
.. _t-strings:
|
||||
|
|
@ -1156,36 +1201,99 @@ t-strings
|
|||
|
||||
A :dfn:`template string literal` or :dfn:`t-string` is a string literal
|
||||
that is prefixed with '``t``' or '``T``'.
|
||||
These strings follow the same syntax and evaluation rules as
|
||||
:ref:`formatted string literals <f-strings>`, with the following differences:
|
||||
These strings follow the same syntax rules as
|
||||
:ref:`formatted string literals <f-strings>`.
|
||||
For differences in evaluation rules, see the
|
||||
:ref:`Standard Library section on t-strings <stdtypes-tstrings>`
|
||||
|
||||
* Rather than evaluating to a ``str`` object, template string literals evaluate
|
||||
to a :class:`string.templatelib.Template` object.
|
||||
|
||||
* The :func:`format` protocol is not used.
|
||||
Instead, the format specifier and conversions (if any) are passed to
|
||||
a new :class:`~string.templatelib.Interpolation` object that is created
|
||||
for each evaluated expression.
|
||||
It is up to code that processes the resulting :class:`~string.templatelib.Template`
|
||||
object to decide how to handle format specifiers and conversions.
|
||||
Formal grammar for f-strings
|
||||
----------------------------
|
||||
|
||||
* Format specifiers containing nested replacement fields are evaluated eagerly,
|
||||
prior to being passed to the :class:`~string.templatelib.Interpolation` object.
|
||||
For instance, an interpolation of the form ``{amount:.{precision}f}`` will
|
||||
evaluate the inner expression ``{precision}`` to determine the value of the
|
||||
``format_spec`` attribute.
|
||||
If ``precision`` were to be ``2``, the resulting format specifier
|
||||
would be ``'.2f'``.
|
||||
F-strings are handled partly by the :term:`lexical analyzer`, which produces the
|
||||
tokens :py:data:`~token.FSTRING_START`, :py:data:`~token.FSTRING_MIDDLE`
|
||||
and :py:data:`~token.FSTRING_END`, and partly by the parser, which handles
|
||||
expressions in the replacement field.
|
||||
The exact way the work is split is a CPython implementation detail.
|
||||
|
||||
* When the equals sign ``'='`` is provided in an interpolation expression,
|
||||
the text of the expression is appended to the literal string that precedes
|
||||
the relevant interpolation.
|
||||
This includes the equals sign and any surrounding whitespace.
|
||||
The :class:`!Interpolation` instance for the expression will be created as
|
||||
normal, except that :attr:`~string.templatelib.Interpolation.conversion` will
|
||||
be set to '``r``' (:func:`repr`) by default.
|
||||
If an explicit conversion or format specifier are provided,
|
||||
this will override the default behaviour.
|
||||
Correspondingly, the f-string grammar is a mix of
|
||||
:ref:`lexical and syntactic definitions <notation-lexical-vs-syntactic>`.
|
||||
|
||||
Whitespace is significant in these situations:
|
||||
|
||||
* There may be no whitespace in :py:data:`~token.FSTRING_START` (between
|
||||
the prefix and quote).
|
||||
* Whitespace in :py:data:`~token.FSTRING_MIDDLE` is part of the literal
|
||||
string contents.
|
||||
* In ``fstring_replacement_field``, if ``f_debug_specifier`` is present,
|
||||
all whitespace after the opening brace until the ``f_debug_specifier``,
|
||||
as well as whitespace immediatelly following ``f_debug_specifier``,
|
||||
is retained as part of the expression.
|
||||
|
||||
.. impl-detail::
|
||||
|
||||
The expression is not handled in the tokenization phase; it is
|
||||
retrieved from the source code using locations of the ``{`` token
|
||||
and the token after ``=``.
|
||||
|
||||
|
||||
The ``FSTRING_MIDDLE`` definition uses
|
||||
:ref:`negative lookaheads <lexical-lookaheads>` (``!``)
|
||||
to indicate special characters (backslash, newline, ``{``, ``}``) and
|
||||
sequences (``f_quote``).
|
||||
|
||||
.. grammar-snippet::
|
||||
:group: python-grammar
|
||||
|
||||
fstring: `FSTRING_START` `fstring_middle`* `FSTRING_END`
|
||||
|
||||
FSTRING_START: `fstringprefix` ("'" | '"' | "'''" | '"""')
|
||||
FSTRING_END: `f_quote`
|
||||
fstringprefix: <("f" | "fr" | "rf"), case-insensitive>
|
||||
f_debug_specifier: '='
|
||||
f_quote: <the quote character(s) used in FSTRING_START>
|
||||
|
||||
fstring_middle:
|
||||
| `fstring_replacement_field`
|
||||
| `FSTRING_MIDDLE`
|
||||
FSTRING_MIDDLE:
|
||||
| (!"\" !`newline` !'{' !'}' !`f_quote`) `source_character`
|
||||
| `stringescapeseq`
|
||||
| "{{"
|
||||
| "}}"
|
||||
| <newline, in triple-quoted f-strings only>
|
||||
fstring_replacement_field:
|
||||
| '{' `f_expression` [`f_debug_specifier`] [`fstring_conversion`]
|
||||
[`fstring_full_format_spec`] '}'
|
||||
fstring_conversion:
|
||||
| "!" ("s" | "r" | "a")
|
||||
fstring_full_format_spec:
|
||||
| ':' `fstring_format_spec`*
|
||||
fstring_format_spec:
|
||||
| `FSTRING_MIDDLE`
|
||||
| `fstring_replacement_field`
|
||||
f_expression:
|
||||
| ','.(`conditional_expression` | "*" `or_expr`)+ [","]
|
||||
| `yield_expression`
|
||||
|
||||
.. note::
|
||||
|
||||
In the above grammar snippet, the ``f_quote`` and ``FSTRING_MIDDLE`` rules
|
||||
are context-sensitive -- they depend on the contents of ``FSTRING_START``
|
||||
of the nearest enclosing ``fstring``.
|
||||
|
||||
Constructing a more traditional formal grammar from this template is left
|
||||
as an exercise for the reader.
|
||||
|
||||
The grammar for t-strings is identical to the one for f-strings, with *t*
|
||||
instead of *f* at the beginning of rule and token names and in the prefix.
|
||||
|
||||
.. grammar-snippet::
|
||||
:group: python-grammar
|
||||
|
||||
tstring: TSTRING_START tstring_middle* TSTRING_END
|
||||
|
||||
<rest of the t-string grammar is omitted; see above>
|
||||
|
||||
|
||||
.. _numbers:
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
# won't suddenly cause build failures. Updating the version is fine as long
|
||||
# as no warnings are raised by doing so.
|
||||
# Keep this version in sync with ``Doc/conf.py``.
|
||||
sphinx~=8.2.0
|
||||
sphinx~=9.0.0
|
||||
|
||||
blurb
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ Doc/c-api/descriptor.rst
|
|||
Doc/c-api/float.rst
|
||||
Doc/c-api/init_config.rst
|
||||
Doc/c-api/intro.rst
|
||||
Doc/c-api/module.rst
|
||||
Doc/c-api/stable.rst
|
||||
Doc/c-api/typeobj.rst
|
||||
Doc/library/ast.rst
|
||||
|
|
@ -29,14 +28,12 @@ Doc/library/pyexpat.rst
|
|||
Doc/library/select.rst
|
||||
Doc/library/socket.rst
|
||||
Doc/library/ssl.rst
|
||||
Doc/library/stdtypes.rst
|
||||
Doc/library/termios.rst
|
||||
Doc/library/test.rst
|
||||
Doc/library/tkinter.rst
|
||||
Doc/library/tkinter.scrolledtext.rst
|
||||
Doc/library/tkinter.ttk.rst
|
||||
Doc/library/unittest.mock.rst
|
||||
Doc/library/unittest.rst
|
||||
Doc/library/urllib.parse.rst
|
||||
Doc/library/urllib.request.rst
|
||||
Doc/library/wsgiref.rst
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@ def process_glossary_nodes(
|
|||
rendered = app.builder.render_partial(definition)
|
||||
terms[term.lower()] = {
|
||||
'title': term,
|
||||
'body': rendered['html_body'],
|
||||
'body': rendered['fragment'],
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -24,14 +24,6 @@
|
|||
# Used in conf.py and updated here by python/release-tools/run_release.py
|
||||
SOURCE_URI = 'https://github.com/python/cpython/tree/main/%s'
|
||||
|
||||
# monkey-patch reST parser to disable alphabetic and roman enumerated lists
|
||||
from docutils.parsers.rst.states import Body
|
||||
Body.enum.converters['loweralpha'] = \
|
||||
Body.enum.converters['upperalpha'] = \
|
||||
Body.enum.converters['lowerroman'] = \
|
||||
Body.enum.converters['upperroman'] = lambda x: None
|
||||
|
||||
|
||||
class PyAwaitableMixin(object):
|
||||
def handle_signature(self, sig, signode):
|
||||
ret = super(PyAwaitableMixin, self).handle_signature(sig, signode)
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@
|
|||
|
||||
In extensions/changes.py:
|
||||
|
||||
{% trans %}Deprecated since version {deprecated}, will be removed in version {removed}{% endtrans %}
|
||||
{% trans %}Deprecated since version {deprecated}, removed in version {removed}{% endtrans %}
|
||||
{% trans %}Deprecated since version %s, will be removed in version %s{% endtrans %}
|
||||
{% trans %}Deprecated since version %s, removed in version %s{% endtrans %}
|
||||
|
||||
In docsbuild-scripts, when rewriting indexsidebar.html with actual versions:
|
||||
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ primary prompt, ``>>>``. (It shouldn't take long.)
|
|||
Numbers
|
||||
-------
|
||||
|
||||
The interpreter acts as a simple calculator: you can type an expression at it
|
||||
The interpreter acts as a simple calculator: you can type an expression into it
|
||||
and it will write the value. Expression syntax is straightforward: the
|
||||
operators ``+``, ``-``, ``*`` and ``/`` can be used to perform
|
||||
arithmetic; parentheses (``()``) can be used for grouping.
|
||||
|
|
|
|||
|
|
@ -322,6 +322,30 @@ General Options
|
|||
|
||||
.. versionadded:: 3.11
|
||||
|
||||
.. option:: --with-missing-stdlib-config=FILE
|
||||
|
||||
Path to a `JSON <https://www.json.org/json-en.html>`_ configuration file
|
||||
containing custom error messages for missing :term:`standard library` modules.
|
||||
|
||||
This option is intended for Python distributors who wish to provide
|
||||
distribution-specific guidance when users encounter standard library
|
||||
modules that are missing or packaged separately.
|
||||
|
||||
The JSON file should map missing module names to custom error message strings.
|
||||
For example, if your distribution packages :mod:`tkinter` and
|
||||
:mod:`_tkinter` separately and excludes :mod:`!_gdbm` for legal reasons,
|
||||
the configuration could contain:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"_gdbm": "The '_gdbm' module is not available in this distribution",
|
||||
"tkinter": "Install the python-tk package to use tkinter",
|
||||
"_tkinter": "Install the python-tk package to use tkinter",
|
||||
}
|
||||
|
||||
.. versionadded:: next
|
||||
|
||||
.. option:: --enable-pystats
|
||||
|
||||
Turn on internal Python performance statistics gathering.
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ Here's a simple example::
|
|||
The union and intersection of sets can be computed with the :meth:`~frozenset.union` and
|
||||
:meth:`~frozenset.intersection` methods; an alternative notation uses the bitwise operators
|
||||
``&`` and ``|``. Mutable sets also have in-place versions of these methods,
|
||||
:meth:`!union_update` and :meth:`~frozenset.intersection_update`. ::
|
||||
:meth:`!union_update` and :meth:`~set.intersection_update`. ::
|
||||
|
||||
>>> S1 = sets.Set([1,2,3])
|
||||
>>> S2 = sets.Set([4,5,6])
|
||||
|
|
@ -87,7 +87,7 @@ It's also possible to take the symmetric difference of two sets. This is the
|
|||
set of all elements in the union that aren't in the intersection. Another way
|
||||
of putting it is that the symmetric difference contains all elements that are in
|
||||
exactly one set. Again, there's an alternative notation (``^``), and an
|
||||
in-place version with the ungainly name :meth:`~frozenset.symmetric_difference_update`. ::
|
||||
in-place version with the ungainly name :meth:`~set.symmetric_difference_update`. ::
|
||||
|
||||
>>> S1 = sets.Set([1,2,3,4])
|
||||
>>> S2 = sets.Set([3,4,5,6])
|
||||
|
|
|
|||
|
|
@ -2169,9 +2169,9 @@ Changes to Python's build process and to the C API include:
|
|||
|
||||
* Two new macros can be used to indicate C functions that are local to the
|
||||
current file so that a faster calling convention can be used.
|
||||
``Py_LOCAL(type)`` declares the function as returning a value of the
|
||||
:c:macro:`Py_LOCAL` declares the function as returning a value of the
|
||||
specified *type* and uses a fast-calling qualifier.
|
||||
``Py_LOCAL_INLINE(type)`` does the same thing and also requests the
|
||||
:c:macro:`Py_LOCAL_INLINE` does the same thing and also requests the
|
||||
function be inlined. If macro :c:macro:`!PY_LOCAL_AGGRESSIVE` is defined before
|
||||
:file:`python.h` is included, a set of more aggressive optimizations are enabled
|
||||
for the module; you should benchmark the results to find out if these
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ Summary -- Release highlights
|
|||
.. PEP-sized items next.
|
||||
|
||||
* :pep:`799`: :ref:`A dedicated profiling package for organizing Python
|
||||
profiling tools <whatsnew315-sampling-profiler>`
|
||||
profiling tools <whatsnew315-profiling-package>`
|
||||
* :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
|
||||
|
|
@ -77,12 +77,32 @@ Summary -- Release highlights
|
|||
New features
|
||||
============
|
||||
|
||||
.. _whatsnew315-profiling-package:
|
||||
|
||||
:pep:`799`: A dedicated profiling package
|
||||
-----------------------------------------
|
||||
|
||||
A new :mod:`!profiling` module has been added to organize Python's built-in
|
||||
profiling tools under a single, coherent namespace. This module contains:
|
||||
|
||||
* :mod:`!profiling.tracing`: deterministic function-call tracing (relocated from
|
||||
:mod:`cProfile`).
|
||||
* :mod:`!profiling.sampling`: a new statistical sampling profiler (named Tachyon).
|
||||
|
||||
The :mod:`cProfile` module remains as an alias for backwards compatibility.
|
||||
The :mod:`profile` module is deprecated and will be removed in Python 3.17.
|
||||
|
||||
.. seealso:: :pep:`799` for further details.
|
||||
|
||||
(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`138122`.)
|
||||
|
||||
|
||||
.. _whatsnew315-sampling-profiler:
|
||||
|
||||
:pep:`799`: High frequency statistical sampling profiler
|
||||
--------------------------------------------------------
|
||||
Tachyon: High frequency statistical sampling profiler
|
||||
-----------------------------------------------------
|
||||
|
||||
A new statistical sampling profiler has been added to the new :mod:`!profiling` module as
|
||||
A new statistical sampling profiler (Tachyon) has been added as
|
||||
:mod:`!profiling.sampling`. This profiler enables low-overhead performance analysis of
|
||||
running Python processes without requiring code modification or process restart.
|
||||
|
||||
|
|
@ -91,101 +111,64 @@ every function call, the sampling profiler periodically captures stack traces fr
|
|||
running processes. This approach provides virtually zero overhead while achieving
|
||||
sampling rates of **up to 1,000,000 Hz**, making it the fastest sampling profiler
|
||||
available for Python (at the time of its contribution) and ideal for debugging
|
||||
performance issues in production environments.
|
||||
performance issues in production environments. This capability is particularly
|
||||
valuable for debugging performance issues in production systems where traditional
|
||||
profiling approaches would be too intrusive.
|
||||
|
||||
Key features include:
|
||||
|
||||
* **Zero-overhead profiling**: Attach to any running Python process without
|
||||
affecting its performance
|
||||
* **No code modification required**: Profile existing applications without restart
|
||||
* **Real-time statistics**: Monitor sampling quality during data collection
|
||||
* **Multiple output formats**: Generate both detailed statistics and flamegraph data
|
||||
* **Thread-aware profiling**: Option to profile all threads or just the main thread
|
||||
affecting its performance. Ideal for production debugging where you can't afford
|
||||
to restart or slow down your application.
|
||||
|
||||
Profile process 1234 for 10 seconds with default settings:
|
||||
* **No code modification required**: Profile existing applications without restart.
|
||||
Simply point the profiler at a running process by PID and start collecting data.
|
||||
|
||||
.. code-block:: shell
|
||||
* **Flexible target modes**:
|
||||
|
||||
python -m profiling.sampling 1234
|
||||
* Profile running processes by PID (``attach``) - attach to already-running applications
|
||||
* Run and profile scripts directly (``run``) - profile from the very start of execution
|
||||
* Execute and profile modules (``run -m``) - profile packages run as ``python -m module``
|
||||
|
||||
Profile with custom interval and duration, save to file:
|
||||
* **Multiple profiling modes**: Choose what to measure based on your performance investigation:
|
||||
|
||||
.. code-block:: shell
|
||||
* **Wall-clock time** (``--mode wall``, default): Measures real elapsed time including I/O,
|
||||
network waits, and blocking operations. Use this to understand where your program spends
|
||||
calendar time, including when waiting for external resources.
|
||||
* **CPU time** (``--mode cpu``): Measures only active CPU execution time, excluding I/O waits
|
||||
and blocking. Use this to identify CPU-bound bottlenecks and optimize computational work.
|
||||
* **GIL-holding time** (``--mode gil``): Measures time spent holding Python's Global Interpreter
|
||||
Lock. Use this to identify which threads dominate GIL usage in multi-threaded applications.
|
||||
|
||||
python -m profiling.sampling -i 50 -d 30 -o profile.stats 1234
|
||||
* **Thread-aware profiling**: Option to profile all threads (``-a``) or just the main thread,
|
||||
essential for understanding multi-threaded application behavior.
|
||||
|
||||
Generate collapsed stacks for flamegraph:
|
||||
* **Multiple output formats**: Choose the visualization that best fits your workflow:
|
||||
|
||||
.. code-block:: shell
|
||||
* ``--pstats``: Detailed tabular statistics compatible with :mod:`pstats`. Shows function-level
|
||||
timing with direct and cumulative samples. Best for detailed analysis and integration with
|
||||
existing Python profiling tools.
|
||||
* ``--collapsed``: Generates collapsed stack traces (one line per stack). This format is
|
||||
specifically designed for creating flamegraphs with external tools like Brendan Gregg's
|
||||
FlameGraph scripts or speedscope.
|
||||
* ``--flamegraph``: Generates a self-contained interactive HTML flamegraph using D3.js.
|
||||
Opens directly in your browser for immediate visual analysis. Flamegraphs show the call
|
||||
hierarchy where width represents time spent, making it easy to spot bottlenecks at a glance.
|
||||
* ``--gecko``: Generates Gecko Profiler format compatible with Firefox Profiler
|
||||
(https://profiler.firefox.com). Upload the output to Firefox Profiler for advanced
|
||||
timeline-based analysis with features like stack charts, markers, and network activity.
|
||||
* ``--heatmap``: Generates an interactive HTML heatmap visualization with line-level sample
|
||||
counts. Creates a directory with per-file heatmaps showing exactly where time is spent
|
||||
at the source code level.
|
||||
|
||||
python -m profiling.sampling --collapsed 1234
|
||||
* **Live interactive mode**: Real-time TUI profiler with a top-like interface (``--live``).
|
||||
Monitor performance as your application runs with interactive sorting and filtering.
|
||||
|
||||
Profile all threads and sort by total time:
|
||||
* **Async-aware profiling**: Profile async/await code with task-based stack reconstruction
|
||||
(``--async-aware``). See which coroutines are consuming time, with options to show only
|
||||
running tasks or all tasks including those waiting.
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
python -m profiling.sampling -a --sort-tottime 1234
|
||||
|
||||
The profiler generates statistical estimates of where time is spent:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
Real-time sampling stats: Mean: 100261.5Hz (9.97µs) Min: 86333.4Hz (11.58µs) Max: 118807.2Hz (8.42µs) Samples: 400001
|
||||
Captured 498841 samples in 5.00 seconds
|
||||
Sample rate: 99768.04 samples/sec
|
||||
Error rate: 0.72%
|
||||
Profile Stats:
|
||||
nsamples sample% tottime (s) cumul% cumtime (s) filename:lineno(function)
|
||||
43/418858 0.0 0.000 87.9 4.189 case.py:667(TestCase.run)
|
||||
3293/418812 0.7 0.033 87.9 4.188 case.py:613(TestCase._callTestMethod)
|
||||
158562/158562 33.3 1.586 33.3 1.586 test_compile.py:725(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)
|
||||
129553/129553 27.2 1.296 27.2 1.296 ast.py:46(parse)
|
||||
0/128129 0.0 0.000 26.9 1.281 test_ast.py:884(AST_Tests.test_ast_recursion_limit.<locals>.check_limit)
|
||||
7/67446 0.0 0.000 14.2 0.674 test_compile.py:729(TestSpecifics.test_compiler_recursion_limit)
|
||||
6/60380 0.0 0.000 12.7 0.604 test_ast.py:888(AST_Tests.test_ast_recursion_limit)
|
||||
3/50020 0.0 0.000 10.5 0.500 test_compile.py:727(TestSpecifics.test_compiler_recursion_limit)
|
||||
1/38011 0.0 0.000 8.0 0.380 test_ast.py:886(AST_Tests.test_ast_recursion_limit)
|
||||
1/25076 0.0 0.000 5.3 0.251 test_compile.py:728(TestSpecifics.test_compiler_recursion_limit)
|
||||
22361/22362 4.7 0.224 4.7 0.224 test_compile.py:1368(TestSpecifics.test_big_dict_literal)
|
||||
4/18008 0.0 0.000 3.8 0.180 test_ast.py:889(AST_Tests.test_ast_recursion_limit)
|
||||
11/17696 0.0 0.000 3.7 0.177 subprocess.py:1038(Popen.__init__)
|
||||
16968/16968 3.6 0.170 3.6 0.170 subprocess.py:1900(Popen._execute_child)
|
||||
2/16941 0.0 0.000 3.6 0.169 test_compile.py:730(TestSpecifics.test_compiler_recursion_limit)
|
||||
|
||||
Legend:
|
||||
nsamples: Direct/Cumulative samples (direct executing / on call stack)
|
||||
sample%: Percentage of total samples this function was directly executing
|
||||
tottime: Estimated total time spent directly in this function
|
||||
cumul%: Percentage of total samples when this function was on the call stack
|
||||
cumtime: Estimated cumulative time (including time in called functions)
|
||||
filename:lineno(function): Function location and name
|
||||
|
||||
Summary of Interesting Functions:
|
||||
|
||||
Functions with Highest Direct/Cumulative Ratio (Hot Spots):
|
||||
1.000 direct/cumulative ratio, 33.3% direct samples: test_compile.py:(TestSpecifics.test_compiler_recursion_limit.<locals>.check_limit)
|
||||
1.000 direct/cumulative ratio, 27.2% direct samples: ast.py:(parse)
|
||||
1.000 direct/cumulative ratio, 3.6% direct samples: subprocess.py:(Popen._execute_child)
|
||||
|
||||
Functions with Highest Call Frequency (Indirect Calls):
|
||||
418815 indirect calls, 87.9% total stack presence: case.py:(TestCase.run)
|
||||
415519 indirect calls, 87.9% total stack presence: case.py:(TestCase._callTestMethod)
|
||||
159470 indirect calls, 33.5% total stack presence: test_compile.py:(TestSpecifics.test_compiler_recursion_limit)
|
||||
|
||||
Functions with Highest Call Magnification (Cumulative/Direct):
|
||||
12267.9x call magnification, 159470 indirect calls from 13 direct: test_compile.py:(TestSpecifics.test_compiler_recursion_limit)
|
||||
10581.7x call magnification, 116388 indirect calls from 11 direct: test_ast.py:(AST_Tests.test_ast_recursion_limit)
|
||||
9740.9x call magnification, 418815 indirect calls from 43 direct: case.py:(TestCase.run)
|
||||
|
||||
The profiler automatically identifies performance bottlenecks through statistical
|
||||
analysis, highlighting functions with high CPU usage and call frequency patterns.
|
||||
|
||||
This capability is particularly valuable for debugging performance issues in
|
||||
production systems where traditional profiling approaches would be too intrusive.
|
||||
|
||||
.. seealso:: :pep:`799` for further details.
|
||||
|
||||
(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953`.)
|
||||
(Contributed by Pablo Galindo and László Kiss Kollár in :gh:`135953` and :gh:`138122`.)
|
||||
|
||||
|
||||
.. _whatsnew315-improved-error-messages:
|
||||
|
|
@ -394,6 +377,10 @@ Other language changes
|
|||
syntax warnings by module name.
|
||||
(Contributed by Serhiy Storchaka in :gh:`135801`.)
|
||||
|
||||
* Allowed defining the *__dict__* and *__weakref__* :ref:`__slots__ <slots>`
|
||||
for any class.
|
||||
(Contributed by Serhiy Storchaka in :gh:`41779`.)
|
||||
|
||||
|
||||
New modules
|
||||
===========
|
||||
|
|
@ -412,6 +399,10 @@ Improved modules
|
|||
argparse
|
||||
--------
|
||||
|
||||
* The :class:`~argparse.BooleanOptionalAction` action supports now single-dash
|
||||
long options and alternate prefix characters.
|
||||
(Contributed by Serhiy Storchaka in :gh:`138525`.)
|
||||
|
||||
* Changed the *suggest_on_error* parameter of :class:`argparse.ArgumentParser` to
|
||||
default to ``True``. This enables suggestions for mistyped arguments by default.
|
||||
(Contributed by Jakob Schluse in :gh:`140450`.)
|
||||
|
|
@ -1084,19 +1075,23 @@ New features
|
|||
|
||||
(Contributed by Victor Stinner in :gh:`129813`.)
|
||||
|
||||
* Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating
|
||||
a module from a *spec* and *initfunc*.
|
||||
(Contributed by Itamar Oren in :gh:`116146`.)
|
||||
|
||||
* Add :c:func:`PyTuple_FromArray` to create a :class:`tuple` from an array.
|
||||
(Contributed by Victor Stinner in :gh:`111489`.)
|
||||
|
||||
* Add :c:func:`PyUnstable_Object_Dump` to dump an object to ``stderr``.
|
||||
It should only be used for debugging.
|
||||
(Contributed by Victor Stinner in :gh:`141070`.)
|
||||
|
||||
* Add :c:func:`PyUnstable_ThreadState_SetStackProtection` and
|
||||
:c:func:`PyUnstable_ThreadState_ResetStackProtection` functions to set
|
||||
the stack protection base address and stack protection size of a Python
|
||||
thread state.
|
||||
(Contributed by Victor Stinner in :gh:`139653`.)
|
||||
|
||||
* Add a new :c:func:`PyImport_CreateModuleFromInitfunc` C-API for creating
|
||||
a module from a *spec* and *initfunc*.
|
||||
(Contributed by Itamar Oren in :gh:`116146`.)
|
||||
|
||||
|
||||
Changed C APIs
|
||||
--------------
|
||||
|
|
@ -1235,6 +1230,12 @@ Build changes
|
|||
set to ``no`` or with :option:`!--without-system-libmpdec`.
|
||||
(Contributed by Sergey B Kirpichev in :gh:`115119`.)
|
||||
|
||||
* The new configure option :option:`--with-missing-stdlib-config=FILE` allows
|
||||
distributors to pass a `JSON <https://www.json.org/json-en.html>`_
|
||||
configuration file containing custom error messages for :term:`standard library`
|
||||
modules that are missing or packaged separately.
|
||||
(Contributed by Stan Ulbrych and Petr Viktorin in :gh:`139707`.)
|
||||
|
||||
|
||||
Porting to Python 3.15
|
||||
======================
|
||||
|
|
@ -1267,3 +1268,10 @@ that may require changes to your code.
|
|||
Use its :meth:`!close` method or the :func:`contextlib.closing` context
|
||||
manager to close it.
|
||||
(Contributed by Osama Abdelkader and Serhiy Storchaka in :gh:`140601`.)
|
||||
|
||||
* If a short option and a single-dash long option are passed to
|
||||
:meth:`argparse.ArgumentParser.add_argument`, *dest* is now inferred from
|
||||
the single-dash long option. For example, in ``add_argument('-f', '-foo')``,
|
||||
*dest* is now ``'foo'`` instead of ``'f'``.
|
||||
Pass an explicit *dest* argument to preserve the old behavior.
|
||||
(Contributed by Serhiy Storchaka in :gh:`138697`.)
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
What's New In Python 3.4
|
||||
****************************
|
||||
|
||||
:Author: R. David Murray <rdmurray@bitdance.com> (Editor)
|
||||
:Author: \R. David Murray <rdmurray@bitdance.com> (Editor)
|
||||
|
||||
.. Rules for maintenance:
|
||||
|
||||
|
|
|
|||
|
|
@ -39,16 +39,6 @@ Py_DEPRECATED(3.14) PyAPI_FUNC(PyObject *) _PyDict_GetItemStringWithError(PyObje
|
|||
PyAPI_FUNC(PyObject *) PyDict_SetDefault(
|
||||
PyObject *mp, PyObject *key, PyObject *defaultobj);
|
||||
|
||||
// Inserts `key` with a value `default_value`, if `key` is not already present
|
||||
// in the dictionary. If `result` is not NULL, then the value associated
|
||||
// with `key` is returned in `*result` (either the existing value, or the now
|
||||
// inserted `default_value`).
|
||||
// Returns:
|
||||
// -1 on error
|
||||
// 0 if `key` was not present and `default_value` was inserted
|
||||
// 1 if `key` was present and `default_value` was not inserted
|
||||
PyAPI_FUNC(int) PyDict_SetDefaultRef(PyObject *mp, PyObject *key, PyObject *default_value, PyObject **result);
|
||||
|
||||
/* Get the number of items of a dictionary. */
|
||||
static inline Py_ssize_t PyDict_GET_SIZE(PyObject *op) {
|
||||
PyDictObject *mp;
|
||||
|
|
|
|||
|
|
@ -295,7 +295,10 @@ PyAPI_FUNC(PyObject *) PyType_GetDict(PyTypeObject *);
|
|||
|
||||
PyAPI_FUNC(int) PyObject_Print(PyObject *, FILE *, int);
|
||||
PyAPI_FUNC(void) _Py_BreakPoint(void);
|
||||
PyAPI_FUNC(void) _PyObject_Dump(PyObject *);
|
||||
PyAPI_FUNC(void) PyUnstable_Object_Dump(PyObject *);
|
||||
|
||||
// Alias for backward compatibility
|
||||
#define _PyObject_Dump PyUnstable_Object_Dump
|
||||
|
||||
PyAPI_FUNC(PyObject*) _PyObject_GetAttrId(PyObject *, _Py_Identifier *);
|
||||
|
||||
|
|
@ -387,10 +390,11 @@ PyAPI_FUNC(PyObject *) _PyObject_FunctionStr(PyObject *);
|
|||
process with a message on stderr if the given condition fails to hold,
|
||||
but compile away to nothing if NDEBUG is defined.
|
||||
|
||||
However, before aborting, Python will also try to call _PyObject_Dump() on
|
||||
the given object. This may be of use when investigating bugs in which a
|
||||
particular object is corrupt (e.g. buggy a tp_visit method in an extension
|
||||
module breaking the garbage collector), to help locate the broken objects.
|
||||
However, before aborting, Python will also try to call
|
||||
PyUnstable_Object_Dump() on the given object. This may be of use when
|
||||
investigating bugs in which a particular object is corrupt (e.g. buggy a
|
||||
tp_visit method in an extension module breaking the garbage collector), to
|
||||
help locate the broken objects.
|
||||
|
||||
The WITH_MSG variant allows you to supply an additional message that Python
|
||||
will attempt to print to stderr, after the object dump. */
|
||||
|
|
@ -432,8 +436,6 @@ PyAPI_FUNC(void) _Py_NO_RETURN _PyObject_AssertFailed(
|
|||
PyAPI_FUNC(void) _PyTrash_thread_deposit_object(PyThreadState *tstate, PyObject *op);
|
||||
PyAPI_FUNC(void) _PyTrash_thread_destroy_chain(PyThreadState *tstate);
|
||||
|
||||
PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(PyThreadState *tstate, int margin_count);
|
||||
|
||||
/* For backwards compatibility with the old trashcan mechanism */
|
||||
#define Py_TRASHCAN_BEGIN(op, dealloc)
|
||||
#define Py_TRASHCAN_END
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ typedef struct {
|
|||
PyException_HEAD
|
||||
PyObject *msg;
|
||||
PyObject *excs;
|
||||
PyObject *excs_str;
|
||||
} PyBaseExceptionGroupObject;
|
||||
|
||||
typedef struct {
|
||||
|
|
|
|||
|
|
@ -135,6 +135,15 @@ struct _ts {
|
|||
/* Pointer to currently executing frame. */
|
||||
struct _PyInterpreterFrame *current_frame;
|
||||
|
||||
/* Pointer to the base frame (bottommost sentinel frame).
|
||||
Used by profilers to validate complete stack unwinding.
|
||||
Points to the embedded base_frame in _PyThreadStateImpl.
|
||||
The frame is embedded there rather than here because _PyInterpreterFrame
|
||||
is defined in internal headers that cannot be exposed in the public API. */
|
||||
struct _PyInterpreterFrame *base_frame;
|
||||
|
||||
struct _PyInterpreterFrame *last_profiled_frame;
|
||||
|
||||
Py_tracefunc c_profilefunc;
|
||||
Py_tracefunc c_tracefunc;
|
||||
PyObject *c_profileobj;
|
||||
|
|
|
|||
|
|
@ -68,6 +68,18 @@ PyAPI_FUNC(int) PyDict_GetItemRef(PyObject *mp, PyObject *key, PyObject **result
|
|||
PyAPI_FUNC(int) PyDict_GetItemStringRef(PyObject *mp, const char *key, PyObject **result);
|
||||
#endif
|
||||
|
||||
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030F0000
|
||||
// Inserts `key` with a value `default_value`, if `key` is not already present
|
||||
// in the dictionary. If `result` is not NULL, then the value associated
|
||||
// with `key` is returned in `*result` (either the existing value, or the now
|
||||
// inserted `default_value`).
|
||||
// Returns:
|
||||
// -1 on error
|
||||
// 0 if `key` was not present and `default_value` was inserted
|
||||
// 1 if `key` was present and `default_value` was not inserted
|
||||
PyAPI_FUNC(int) PyDict_SetDefaultRef(PyObject *mp, PyObject *key, PyObject *default_value, PyObject **result);
|
||||
#endif
|
||||
|
||||
#if !defined(Py_LIMITED_API) || Py_LIMITED_API+0 >= 0x030A0000
|
||||
PyAPI_FUNC(PyObject *) PyObject_GenericGetDict(PyObject *, void *);
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -22,33 +22,48 @@ extern "C" {
|
|||
Another use is for the Tier 2 optimizer to decide when to create
|
||||
a new Tier 2 trace (executor). Again, exponential backoff is used.
|
||||
|
||||
The 16-bit counter is structured as a 12-bit unsigned 'value'
|
||||
and a 4-bit 'backoff' field. When resetting the counter, the
|
||||
The 16-bit counter is structured as a 13-bit unsigned 'value'
|
||||
and a 3-bit 'backoff' field. When resetting the counter, the
|
||||
backoff field is incremented (until it reaches a limit) and the
|
||||
value is set to a bit mask representing the value 2**backoff - 1.
|
||||
The maximum backoff is 12 (the number of bits in the value).
|
||||
value is set to a bit mask representing some prime value - 1.
|
||||
New values and backoffs for each backoff are calculated once
|
||||
at compile time and saved to value_and_backoff_next table.
|
||||
The maximum backoff is 6, since 7 is an UNREACHABLE_BACKOFF.
|
||||
|
||||
There is an exceptional value which must not be updated, 0xFFFF.
|
||||
*/
|
||||
|
||||
#define BACKOFF_BITS 4
|
||||
#define MAX_BACKOFF 12
|
||||
#define UNREACHABLE_BACKOFF 15
|
||||
#define BACKOFF_BITS 3
|
||||
#define BACKOFF_MASK 7
|
||||
#define MAX_BACKOFF 6
|
||||
#define UNREACHABLE_BACKOFF 7
|
||||
#define MAX_VALUE 0x1FFF
|
||||
|
||||
static inline bool
|
||||
is_unreachable_backoff_counter(_Py_BackoffCounter counter)
|
||||
{
|
||||
return counter.value_and_backoff == UNREACHABLE_BACKOFF;
|
||||
}
|
||||
#define MAKE_VALUE_AND_BACKOFF(value, backoff) \
|
||||
((value << BACKOFF_BITS) | backoff)
|
||||
|
||||
// For previous backoff b we use value x such that
|
||||
// x + 1 is near to 2**(2*b+1) and x + 1 is prime.
|
||||
static const uint16_t value_and_backoff_next[] = {
|
||||
MAKE_VALUE_AND_BACKOFF(1, 1),
|
||||
MAKE_VALUE_AND_BACKOFF(6, 2),
|
||||
MAKE_VALUE_AND_BACKOFF(30, 3),
|
||||
MAKE_VALUE_AND_BACKOFF(126, 4),
|
||||
MAKE_VALUE_AND_BACKOFF(508, 5),
|
||||
MAKE_VALUE_AND_BACKOFF(2052, 6),
|
||||
// We use the same backoff counter for all backoffs >= MAX_BACKOFF.
|
||||
MAKE_VALUE_AND_BACKOFF(8190, 6),
|
||||
MAKE_VALUE_AND_BACKOFF(8190, 6),
|
||||
};
|
||||
|
||||
static inline _Py_BackoffCounter
|
||||
make_backoff_counter(uint16_t value, uint16_t backoff)
|
||||
{
|
||||
assert(backoff <= 15);
|
||||
assert(value <= 0xFFF);
|
||||
_Py_BackoffCounter result;
|
||||
result.value_and_backoff = (value << BACKOFF_BITS) | backoff;
|
||||
return result;
|
||||
assert(backoff <= UNREACHABLE_BACKOFF);
|
||||
assert(value <= MAX_VALUE);
|
||||
return ((_Py_BackoffCounter){
|
||||
.value_and_backoff = MAKE_VALUE_AND_BACKOFF(value, backoff)
|
||||
});
|
||||
}
|
||||
|
||||
static inline _Py_BackoffCounter
|
||||
|
|
@ -62,14 +77,11 @@ forge_backoff_counter(uint16_t counter)
|
|||
static inline _Py_BackoffCounter
|
||||
restart_backoff_counter(_Py_BackoffCounter counter)
|
||||
{
|
||||
assert(!is_unreachable_backoff_counter(counter));
|
||||
int backoff = counter.value_and_backoff & 15;
|
||||
if (backoff < MAX_BACKOFF) {
|
||||
return make_backoff_counter((1 << (backoff + 1)) - 1, backoff + 1);
|
||||
}
|
||||
else {
|
||||
return make_backoff_counter((1 << MAX_BACKOFF) - 1, MAX_BACKOFF);
|
||||
}
|
||||
uint16_t backoff = counter.value_and_backoff & BACKOFF_MASK;
|
||||
assert(backoff <= MAX_BACKOFF);
|
||||
return ((_Py_BackoffCounter){
|
||||
.value_and_backoff = value_and_backoff_next[backoff]
|
||||
});
|
||||
}
|
||||
|
||||
static inline _Py_BackoffCounter
|
||||
|
|
@ -113,7 +125,7 @@ trigger_backoff_counter(void)
|
|||
// as we always end up tracing the loop iteration's
|
||||
// exhaustion iteration. Which aborts our current tracer.
|
||||
#define JUMP_BACKWARD_INITIAL_VALUE 4000
|
||||
#define JUMP_BACKWARD_INITIAL_BACKOFF 12
|
||||
#define JUMP_BACKWARD_INITIAL_BACKOFF 6
|
||||
static inline _Py_BackoffCounter
|
||||
initial_jump_backoff_counter(void)
|
||||
{
|
||||
|
|
@ -126,7 +138,7 @@ initial_jump_backoff_counter(void)
|
|||
* otherwise when a side exit warms up we may construct
|
||||
* a new trace before the Tier 1 code has properly re-specialized. */
|
||||
#define SIDE_EXIT_INITIAL_VALUE 4000
|
||||
#define SIDE_EXIT_INITIAL_BACKOFF 12
|
||||
#define SIDE_EXIT_INITIAL_BACKOFF 6
|
||||
|
||||
static inline _Py_BackoffCounter
|
||||
initial_temperature_backoff_counter(void)
|
||||
|
|
|
|||
|
|
@ -64,39 +64,6 @@ PyAPI_FUNC(PyObject*) _PyObject_CallMethod(
|
|||
PyObject *name,
|
||||
const char *format, ...);
|
||||
|
||||
extern PyObject* _PyObject_CallMethodIdObjArgs(
|
||||
PyObject *obj,
|
||||
_Py_Identifier *name,
|
||||
...);
|
||||
|
||||
static inline PyObject *
|
||||
_PyObject_VectorcallMethodId(
|
||||
_Py_Identifier *name, PyObject *const *args,
|
||||
size_t nargsf, PyObject *kwnames)
|
||||
{
|
||||
PyObject *oname = _PyUnicode_FromId(name); /* borrowed */
|
||||
if (!oname) {
|
||||
return _Py_NULL;
|
||||
}
|
||||
return PyObject_VectorcallMethod(oname, args, nargsf, kwnames);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
_PyObject_CallMethodIdNoArgs(PyObject *self, _Py_Identifier *name)
|
||||
{
|
||||
size_t nargsf = 1 | PY_VECTORCALL_ARGUMENTS_OFFSET;
|
||||
return _PyObject_VectorcallMethodId(name, &self, nargsf, _Py_NULL);
|
||||
}
|
||||
|
||||
static inline PyObject *
|
||||
_PyObject_CallMethodIdOneArg(PyObject *self, _Py_Identifier *name, PyObject *arg)
|
||||
{
|
||||
PyObject *args[2] = {self, arg};
|
||||
size_t nargsf = 2 | PY_VECTORCALL_ARGUMENTS_OFFSET;
|
||||
assert(arg != NULL);
|
||||
return _PyObject_VectorcallMethodId(name, args, nargsf, _Py_NULL);
|
||||
}
|
||||
|
||||
|
||||
/* === Vectorcall protocol (PEP 590) ============================= */
|
||||
|
||||
|
|
|
|||
|
|
@ -33,8 +33,6 @@ extern int _PyEval_SetOpcodeTrace(PyFrameObject *f, bool enable);
|
|||
// Export for 'array' shared extension
|
||||
PyAPI_FUNC(PyObject*) _PyEval_GetBuiltin(PyObject *);
|
||||
|
||||
extern PyObject* _PyEval_GetBuiltinId(_Py_Identifier *);
|
||||
|
||||
extern void _PyEval_SetSwitchInterval(unsigned long microseconds);
|
||||
extern unsigned long _PyEval_GetSwitchInterval(void);
|
||||
|
||||
|
|
@ -217,10 +215,13 @@ extern void _PyEval_DeactivateOpCache(void);
|
|||
static inline int _Py_MakeRecCheck(PyThreadState *tstate) {
|
||||
uintptr_t here_addr = _Py_get_machine_stack_pointer();
|
||||
_PyThreadStateImpl *_tstate = (_PyThreadStateImpl *)tstate;
|
||||
// Overflow if stack pointer is between soft limit and the base of the hardware stack.
|
||||
// If it is below the hardware stack base, assume that we have the wrong stack limits, and do nothing.
|
||||
// We could have the wrong stack limits because of limited platform support, or user-space threads.
|
||||
#if _Py_STACK_GROWS_DOWN
|
||||
return here_addr < _tstate->c_stack_soft_limit;
|
||||
return here_addr < _tstate->c_stack_soft_limit && here_addr >= _tstate->c_stack_soft_limit - 2 * _PyOS_STACK_MARGIN_BYTES;
|
||||
#else
|
||||
return here_addr > _tstate->c_stack_soft_limit;
|
||||
return here_addr > _tstate->c_stack_soft_limit && here_addr <= _tstate->c_stack_soft_limit + 2 * _PyOS_STACK_MARGIN_BYTES;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
@ -260,6 +261,11 @@ static inline int _Py_ReachedRecursionLimit(PyThreadState *tstate) {
|
|||
#endif
|
||||
}
|
||||
|
||||
// Export for test_peg_generator
|
||||
PyAPI_FUNC(int) _Py_ReachedRecursionLimitWithMargin(
|
||||
PyThreadState *tstate,
|
||||
int margin_count);
|
||||
|
||||
static inline void _Py_LeaveRecursiveCall(void) {
|
||||
}
|
||||
|
||||
|
|
@ -402,6 +408,64 @@ _PyForIter_VirtualIteratorNext(PyThreadState* tstate, struct _PyInterpreterFrame
|
|||
|
||||
PyAPI_DATA(const _Py_CODEUNIT *) _Py_INTERPRETER_TRAMPOLINE_INSTRUCTIONS_PTR;
|
||||
|
||||
/* Helper functions for large uops */
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_VectorCall_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
_PyStackRef *arguments,
|
||||
int total_args,
|
||||
_PyStackRef kwnames);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_BuiltinCallFast_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_BuiltinCallFastWithKeywords_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_PyCallMethodDescriptorFast_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
PyMethodDef *meth,
|
||||
PyObject *self,
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_PyCallMethodDescriptorFastWithKeywords_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
PyMethodDef *meth,
|
||||
PyObject *self,
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_CallBuiltinClass_StackRefSteal(
|
||||
_PyStackRef callable,
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_BuildString_StackRefSteal(
|
||||
_PyStackRef *arguments,
|
||||
int total_args);
|
||||
|
||||
PyAPI_FUNC(PyObject *)
|
||||
_Py_BuildMap_StackRefSteal(
|
||||
_PyStackRef *arguments,
|
||||
int half_args);
|
||||
|
||||
PyAPI_FUNC(void)
|
||||
_Py_assert_within_stack_bounds(
|
||||
_PyInterpreterFrame *frame, _PyStackRef *stack_pointer,
|
||||
const char *filename, int lineno);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ extern "C" {
|
|||
const bool _should_lock_cs = PyList_CheckExact(_orig_seq); \
|
||||
PyCriticalSection _cs; \
|
||||
if (_should_lock_cs) { \
|
||||
_PyCriticalSection_Begin(&_cs, _orig_seq); \
|
||||
PyCriticalSection_Begin(&_cs, _orig_seq); \
|
||||
}
|
||||
|
||||
# define Py_END_CRITICAL_SECTION_SEQUENCE_FAST() \
|
||||
|
|
@ -77,10 +77,10 @@ _PyCriticalSection_Resume(PyThreadState *tstate);
|
|||
|
||||
// (private) slow path for locking the mutex
|
||||
PyAPI_FUNC(void)
|
||||
_PyCriticalSection_BeginSlow(PyCriticalSection *c, PyMutex *m);
|
||||
_PyCriticalSection_BeginSlow(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m);
|
||||
|
||||
PyAPI_FUNC(void)
|
||||
_PyCriticalSection2_BeginSlow(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2,
|
||||
_PyCriticalSection2_BeginSlow(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2,
|
||||
int is_m1_locked);
|
||||
|
||||
PyAPI_FUNC(void)
|
||||
|
|
@ -95,34 +95,30 @@ _PyCriticalSection_IsActive(uintptr_t tag)
|
|||
}
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_BeginMutex(PyCriticalSection *c, PyMutex *m)
|
||||
_PyCriticalSection_BeginMutex(PyThreadState *tstate, PyCriticalSection *c, PyMutex *m)
|
||||
{
|
||||
if (PyMutex_LockFast(m)) {
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
c->_cs_mutex = m;
|
||||
c->_cs_prev = tstate->critical_section;
|
||||
tstate->critical_section = (uintptr_t)c;
|
||||
}
|
||||
else {
|
||||
_PyCriticalSection_BeginSlow(c, m);
|
||||
_PyCriticalSection_BeginSlow(tstate, c, m);
|
||||
}
|
||||
}
|
||||
#define PyCriticalSection_BeginMutex _PyCriticalSection_BeginMutex
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_Begin(PyCriticalSection *c, PyObject *op)
|
||||
_PyCriticalSection_Begin(PyThreadState *tstate, PyCriticalSection *c, PyObject *op)
|
||||
{
|
||||
_PyCriticalSection_BeginMutex(c, &op->ob_mutex);
|
||||
_PyCriticalSection_BeginMutex(tstate, c, &op->ob_mutex);
|
||||
}
|
||||
#define PyCriticalSection_Begin _PyCriticalSection_Begin
|
||||
|
||||
// Removes the top-most critical section from the thread's stack of critical
|
||||
// sections. If the new top-most critical section is inactive, then it is
|
||||
// resumed.
|
||||
static inline void
|
||||
_PyCriticalSection_Pop(PyCriticalSection *c)
|
||||
_PyCriticalSection_Pop(PyThreadState *tstate, PyCriticalSection *c)
|
||||
{
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
uintptr_t prev = c->_cs_prev;
|
||||
tstate->critical_section = prev;
|
||||
|
||||
|
|
@ -132,7 +128,7 @@ _PyCriticalSection_Pop(PyCriticalSection *c)
|
|||
}
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_End(PyCriticalSection *c)
|
||||
_PyCriticalSection_End(PyThreadState *tstate, PyCriticalSection *c)
|
||||
{
|
||||
// If the mutex is NULL, we used the fast path in
|
||||
// _PyCriticalSection_BeginSlow for locks already held in the top-most
|
||||
|
|
@ -141,18 +137,17 @@ _PyCriticalSection_End(PyCriticalSection *c)
|
|||
return;
|
||||
}
|
||||
PyMutex_Unlock(c->_cs_mutex);
|
||||
_PyCriticalSection_Pop(c);
|
||||
_PyCriticalSection_Pop(tstate, c);
|
||||
}
|
||||
#define PyCriticalSection_End _PyCriticalSection_End
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
|
||||
_PyCriticalSection2_BeginMutex(PyThreadState *tstate, PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
|
||||
{
|
||||
if (m1 == m2) {
|
||||
// If the two mutex arguments are the same, treat this as a critical
|
||||
// section with a single mutex.
|
||||
c->_cs_mutex2 = NULL;
|
||||
_PyCriticalSection_BeginMutex(&c->_cs_base, m1);
|
||||
_PyCriticalSection_BeginMutex(tstate, &c->_cs_base, m1);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -167,7 +162,6 @@ _PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
|
|||
|
||||
if (PyMutex_LockFast(m1)) {
|
||||
if (PyMutex_LockFast(m2)) {
|
||||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
c->_cs_base._cs_mutex = m1;
|
||||
c->_cs_mutex2 = m2;
|
||||
c->_cs_base._cs_prev = tstate->critical_section;
|
||||
|
|
@ -176,24 +170,22 @@ _PyCriticalSection2_BeginMutex(PyCriticalSection2 *c, PyMutex *m1, PyMutex *m2)
|
|||
tstate->critical_section = p;
|
||||
}
|
||||
else {
|
||||
_PyCriticalSection2_BeginSlow(c, m1, m2, 1);
|
||||
_PyCriticalSection2_BeginSlow(tstate, c, m1, m2, 1);
|
||||
}
|
||||
}
|
||||
else {
|
||||
_PyCriticalSection2_BeginSlow(c, m1, m2, 0);
|
||||
_PyCriticalSection2_BeginSlow(tstate, c, m1, m2, 0);
|
||||
}
|
||||
}
|
||||
#define PyCriticalSection2_BeginMutex _PyCriticalSection2_BeginMutex
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection2_Begin(PyCriticalSection2 *c, PyObject *a, PyObject *b)
|
||||
_PyCriticalSection2_Begin(PyThreadState *tstate, PyCriticalSection2 *c, PyObject *a, PyObject *b)
|
||||
{
|
||||
_PyCriticalSection2_BeginMutex(c, &a->ob_mutex, &b->ob_mutex);
|
||||
_PyCriticalSection2_BeginMutex(tstate, c, &a->ob_mutex, &b->ob_mutex);
|
||||
}
|
||||
#define PyCriticalSection2_Begin _PyCriticalSection2_Begin
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection2_End(PyCriticalSection2 *c)
|
||||
_PyCriticalSection2_End(PyThreadState *tstate, PyCriticalSection2 *c)
|
||||
{
|
||||
// if mutex1 is NULL, we used the fast path in
|
||||
// _PyCriticalSection_BeginSlow for mutexes that are already held,
|
||||
|
|
@ -207,9 +199,8 @@ _PyCriticalSection2_End(PyCriticalSection2 *c)
|
|||
PyMutex_Unlock(c->_cs_mutex2);
|
||||
}
|
||||
PyMutex_Unlock(c->_cs_base._cs_mutex);
|
||||
_PyCriticalSection_Pop(&c->_cs_base);
|
||||
_PyCriticalSection_Pop(tstate, &c->_cs_base);
|
||||
}
|
||||
#define PyCriticalSection2_End _PyCriticalSection2_End
|
||||
|
||||
static inline void
|
||||
_PyCriticalSection_AssertHeld(PyMutex *mutex)
|
||||
|
|
@ -251,6 +242,45 @@ _PyCriticalSection_AssertHeldObj(PyObject *op)
|
|||
|
||||
#endif
|
||||
}
|
||||
|
||||
#undef Py_BEGIN_CRITICAL_SECTION
|
||||
# define Py_BEGIN_CRITICAL_SECTION(op) \
|
||||
{ \
|
||||
PyCriticalSection _py_cs; \
|
||||
PyThreadState *_cs_tstate = _PyThreadState_GET(); \
|
||||
_PyCriticalSection_Begin(_cs_tstate, &_py_cs, _PyObject_CAST(op))
|
||||
|
||||
#undef Py_BEGIN_CRITICAL_SECTION_MUTEX
|
||||
# define Py_BEGIN_CRITICAL_SECTION_MUTEX(mutex) \
|
||||
{ \
|
||||
PyCriticalSection _py_cs; \
|
||||
PyThreadState *_cs_tstate = _PyThreadState_GET(); \
|
||||
_PyCriticalSection_BeginMutex(_cs_tstate, &_py_cs, mutex)
|
||||
|
||||
#undef Py_END_CRITICAL_SECTION
|
||||
# define Py_END_CRITICAL_SECTION() \
|
||||
_PyCriticalSection_End(_cs_tstate, &_py_cs); \
|
||||
}
|
||||
|
||||
#undef Py_BEGIN_CRITICAL_SECTION2
|
||||
# define Py_BEGIN_CRITICAL_SECTION2(a, b) \
|
||||
{ \
|
||||
PyCriticalSection2 _py_cs2; \
|
||||
PyThreadState *_cs_tstate = _PyThreadState_GET(); \
|
||||
_PyCriticalSection2_Begin(_cs_tstate, &_py_cs2, _PyObject_CAST(a), _PyObject_CAST(b))
|
||||
|
||||
#undef Py_BEGIN_CRITICAL_SECTION2_MUTEX
|
||||
# define Py_BEGIN_CRITICAL_SECTION2_MUTEX(m1, m2) \
|
||||
{ \
|
||||
PyCriticalSection2 _py_cs2; \
|
||||
PyThreadState *_cs_tstate = _PyThreadState_GET(); \
|
||||
_PyCriticalSection2_BeginMutex(_cs_tstate, &_py_cs2, m1, m2)
|
||||
|
||||
#undef Py_END_CRITICAL_SECTION2
|
||||
# define Py_END_CRITICAL_SECTION2() \
|
||||
_PyCriticalSection2_End(_cs_tstate, &_py_cs2); \
|
||||
}
|
||||
|
||||
#endif /* Py_GIL_DISABLED */
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -102,6 +102,8 @@ typedef struct _Py_DebugOffsets {
|
|||
uint64_t next;
|
||||
uint64_t interp;
|
||||
uint64_t current_frame;
|
||||
uint64_t base_frame;
|
||||
uint64_t last_profiled_frame;
|
||||
uint64_t thread_id;
|
||||
uint64_t native_thread_id;
|
||||
uint64_t datastack_chunk;
|
||||
|
|
@ -272,6 +274,8 @@ typedef struct _Py_DebugOffsets {
|
|||
.next = offsetof(PyThreadState, next), \
|
||||
.interp = offsetof(PyThreadState, interp), \
|
||||
.current_frame = offsetof(PyThreadState, current_frame), \
|
||||
.base_frame = offsetof(PyThreadState, base_frame), \
|
||||
.last_profiled_frame = offsetof(PyThreadState, last_profiled_frame), \
|
||||
.thread_id = offsetof(PyThreadState, thread_id), \
|
||||
.native_thread_id = offsetof(PyThreadState, native_thread_id), \
|
||||
.datastack_chunk = offsetof(PyThreadState, datastack_chunk), \
|
||||
|
|
|
|||
|
|
@ -36,13 +36,6 @@ extern int _PyDict_DelItem_KnownHash_LockHeld(PyObject *mp, PyObject *key,
|
|||
|
||||
extern int _PyDict_Contains_KnownHash(PyObject *, PyObject *, Py_hash_t);
|
||||
|
||||
// "Id" variants
|
||||
extern PyObject* _PyDict_GetItemIdWithError(PyObject *dp,
|
||||
_Py_Identifier *key);
|
||||
extern int _PyDict_ContainsId(PyObject *, _Py_Identifier *);
|
||||
extern int _PyDict_SetItemId(PyObject *dp, _Py_Identifier *key, PyObject *item);
|
||||
extern int _PyDict_DelItemId(PyObject *mp, _Py_Identifier *key);
|
||||
|
||||
extern int _PyDict_Next(
|
||||
PyObject *mp, Py_ssize_t *pos, PyObject **key, PyObject **value, Py_hash_t *hash);
|
||||
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ static inline void
|
|||
_PyStaticObject_CheckRefcnt(PyObject *obj) {
|
||||
if (!_Py_IsImmortal(obj)) {
|
||||
fprintf(stderr, "Immortal Object has less refcnt than expected.\n");
|
||||
_PyObject_Dump(obj);
|
||||
PyUnstable_Object_Dump(obj);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1609,6 +1609,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
|||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_parameter_type));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_return));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(c_stack));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cache_frames));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_datetime_module));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cached_statements));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(cadata));
|
||||
|
|
@ -2053,6 +2054,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
|||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stacklevel));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(start));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(statement));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stats));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(status));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stderr));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(stdin));
|
||||
|
|
@ -2070,6 +2072,7 @@ _PyStaticObjects_CheckRefcnt(PyInterpreterState *interp) {
|
|||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(symmetric_difference_update));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tabsize));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(tag));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(take_bytes));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(target));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(target_is_directory));
|
||||
_PyStaticObject_CheckRefcnt((PyObject *)&_Py_ID(task));
|
||||
|
|
|
|||
|
|
@ -332,6 +332,7 @@ struct _Py_global_strings {
|
|||
STRUCT_FOR_ID(c_parameter_type)
|
||||
STRUCT_FOR_ID(c_return)
|
||||
STRUCT_FOR_ID(c_stack)
|
||||
STRUCT_FOR_ID(cache_frames)
|
||||
STRUCT_FOR_ID(cached_datetime_module)
|
||||
STRUCT_FOR_ID(cached_statements)
|
||||
STRUCT_FOR_ID(cadata)
|
||||
|
|
@ -776,6 +777,7 @@ struct _Py_global_strings {
|
|||
STRUCT_FOR_ID(stacklevel)
|
||||
STRUCT_FOR_ID(start)
|
||||
STRUCT_FOR_ID(statement)
|
||||
STRUCT_FOR_ID(stats)
|
||||
STRUCT_FOR_ID(status)
|
||||
STRUCT_FOR_ID(stderr)
|
||||
STRUCT_FOR_ID(stdin)
|
||||
|
|
@ -793,6 +795,7 @@ struct _Py_global_strings {
|
|||
STRUCT_FOR_ID(symmetric_difference_update)
|
||||
STRUCT_FOR_ID(tabsize)
|
||||
STRUCT_FOR_ID(tag)
|
||||
STRUCT_FOR_ID(take_bytes)
|
||||
STRUCT_FOR_ID(target)
|
||||
STRUCT_FOR_ID(target_is_directory)
|
||||
STRUCT_FOR_ID(task)
|
||||
|
|
|
|||
|
|
@ -128,11 +128,18 @@ PyAPI_FUNC(int) _PyImport_ClearExtension(PyObject *name, PyObject *filename);
|
|||
// state of the module argument:
|
||||
// - If module is NULL or a PyModuleObject with md_gil == Py_MOD_GIL_NOT_USED,
|
||||
// call _PyEval_DisableGIL().
|
||||
// - Otherwise, call _PyEval_EnableGILPermanent(). If the GIL was not already
|
||||
// enabled permanently, issue a warning referencing the module's name.
|
||||
// - Otherwise, call _PyImport_EnableGILAndWarn
|
||||
//
|
||||
// This function may raise an exception.
|
||||
extern int _PyImport_CheckGILForModule(PyObject *module, PyObject *module_name);
|
||||
// Assuming that the GIL is enabled from a call to
|
||||
// _PyEval_EnableGILTransient(), call _PyEval_EnableGILPermanent().
|
||||
// If the GIL was not already enabled permanently, issue a warning referencing
|
||||
// the module's name.
|
||||
// Leave a message in verbose mode.
|
||||
//
|
||||
// This function may raise an exception.
|
||||
extern int _PyImport_EnableGILAndWarn(PyThreadState *, PyObject *module_name);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -153,10 +153,8 @@ typedef enum {
|
|||
} _PyConfigInitEnum;
|
||||
|
||||
typedef enum {
|
||||
/* For now, this means the GIL is enabled.
|
||||
|
||||
gh-116329: This will eventually change to "the GIL is disabled but can
|
||||
be re-enabled by loading an incompatible extension module." */
|
||||
/* In free threaded builds, this means that the GIL is disabled at startup,
|
||||
but may be enabled by loading an incompatible extension module. */
|
||||
_PyConfig_GIL_DEFAULT = -1,
|
||||
|
||||
/* The GIL has been forced off or on, and will not be affected by module loading. */
|
||||
|
|
|
|||
|
|
@ -179,6 +179,10 @@ struct gc_collection_stats {
|
|||
Py_ssize_t collected;
|
||||
/* total number of uncollectable objects (put into gc.garbage) */
|
||||
Py_ssize_t uncollectable;
|
||||
// Total number of objects considered for collection and traversed:
|
||||
Py_ssize_t candidates;
|
||||
// Duration of the collection in seconds:
|
||||
double duration;
|
||||
};
|
||||
|
||||
/* Running stats per generation */
|
||||
|
|
@ -189,6 +193,10 @@ struct gc_generation_stats {
|
|||
Py_ssize_t collected;
|
||||
/* total number of uncollectable objects (put into gc.garbage) */
|
||||
Py_ssize_t uncollectable;
|
||||
// Total number of objects considered for collection and traversed:
|
||||
Py_ssize_t candidates;
|
||||
// Duration of the collection in seconds:
|
||||
double duration;
|
||||
};
|
||||
|
||||
enum _GCPhase {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,9 @@ extern "C" {
|
|||
# error "this header requires Py_BUILD_CORE define"
|
||||
#endif
|
||||
|
||||
/* To be able to reason about code layout and branches, keep code size below 1 MB */
|
||||
#define PY_MAX_JIT_CODE_SIZE ((1 << 20)-1)
|
||||
|
||||
#ifdef _Py_JIT
|
||||
|
||||
typedef _Py_CODEUNIT *(*jit_func)(_PyInterpreterFrame *frame, _PyStackRef *stack_pointer, PyThreadState *tstate);
|
||||
|
|
|
|||
|
|
@ -77,6 +77,10 @@ extern "C" {
|
|||
_Py_atomic_store_ushort_relaxed(&value, new_value)
|
||||
#define FT_ATOMIC_LOAD_USHORT_RELAXED(value) \
|
||||
_Py_atomic_load_ushort_relaxed(&value)
|
||||
#define FT_ATOMIC_LOAD_INT(value) \
|
||||
_Py_atomic_load_int(&value)
|
||||
#define FT_ATOMIC_STORE_INT(value, new_value) \
|
||||
_Py_atomic_store_int(&value, new_value)
|
||||
#define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) \
|
||||
_Py_atomic_store_int_relaxed(&value, new_value)
|
||||
#define FT_ATOMIC_LOAD_INT_RELAXED(value) \
|
||||
|
|
@ -144,6 +148,8 @@ extern "C" {
|
|||
#define FT_ATOMIC_STORE_SHORT_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_LOAD_USHORT_RELAXED(value) value
|
||||
#define FT_ATOMIC_STORE_USHORT_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_LOAD_INT(value) value
|
||||
#define FT_ATOMIC_STORE_INT(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_LOAD_INT_RELAXED(value) value
|
||||
#define FT_ATOMIC_STORE_INT_RELAXED(value, new_value) value = new_value
|
||||
#define FT_ATOMIC_LOAD_UINT_RELAXED(value) value
|
||||
|
|
|
|||
|
|
@ -70,6 +70,27 @@ static inline int _PyMem_IsPtrFreed(const void *ptr)
|
|||
#endif
|
||||
}
|
||||
|
||||
// Similar to _PyMem_IsPtrFreed() but expects an 'unsigned long' instead of a
|
||||
// pointer.
|
||||
static inline int _PyMem_IsULongFreed(unsigned long value)
|
||||
{
|
||||
#if SIZEOF_LONG == 8
|
||||
return (value == 0
|
||||
|| value == (unsigned long)0xCDCDCDCDCDCDCDCD
|
||||
|| value == (unsigned long)0xDDDDDDDDDDDDDDDD
|
||||
|| value == (unsigned long)0xFDFDFDFDFDFDFDFD
|
||||
|| value == (unsigned long)0xFFFFFFFFFFFFFFFF);
|
||||
#elif SIZEOF_LONG == 4
|
||||
return (value == 0
|
||||
|| value == (unsigned long)0xCDCDCDCD
|
||||
|| value == (unsigned long)0xDDDDDDDD
|
||||
|| value == (unsigned long)0xFDFDFDFD
|
||||
|| value == (unsigned long)0xFFFFFFFF);
|
||||
#else
|
||||
# error "unknown long size"
|
||||
#endif
|
||||
}
|
||||
|
||||
extern int _PyMem_GetAllocatorName(
|
||||
const char *name,
|
||||
PyMemAllocatorName *allocator);
|
||||
|
|
|
|||
3
Include/internal/pycore_runtime_init_generated.h
generated
3
Include/internal/pycore_runtime_init_generated.h
generated
|
|
@ -1607,6 +1607,7 @@ extern "C" {
|
|||
INIT_ID(c_parameter_type), \
|
||||
INIT_ID(c_return), \
|
||||
INIT_ID(c_stack), \
|
||||
INIT_ID(cache_frames), \
|
||||
INIT_ID(cached_datetime_module), \
|
||||
INIT_ID(cached_statements), \
|
||||
INIT_ID(cadata), \
|
||||
|
|
@ -2051,6 +2052,7 @@ extern "C" {
|
|||
INIT_ID(stacklevel), \
|
||||
INIT_ID(start), \
|
||||
INIT_ID(statement), \
|
||||
INIT_ID(stats), \
|
||||
INIT_ID(status), \
|
||||
INIT_ID(stderr), \
|
||||
INIT_ID(stdin), \
|
||||
|
|
@ -2068,6 +2070,7 @@ extern "C" {
|
|||
INIT_ID(symmetric_difference_update), \
|
||||
INIT_ID(tabsize), \
|
||||
INIT_ID(tag), \
|
||||
INIT_ID(take_bytes), \
|
||||
INIT_ID(target), \
|
||||
INIT_ID(target_is_directory), \
|
||||
INIT_ID(task), \
|
||||
|
|
|
|||
|
|
@ -30,8 +30,8 @@ struct _PyTraceMalloc_Config {
|
|||
};
|
||||
|
||||
|
||||
/* Pack the frame_t structure to reduce the memory footprint on 64-bit
|
||||
architectures: 12 bytes instead of 16. */
|
||||
/* Pack the tracemalloc_frame and tracemalloc_traceback structures to reduce
|
||||
the memory footprint on 64-bit architectures: 12 bytes instead of 16. */
|
||||
#if defined(_MSC_VER)
|
||||
#pragma pack(push, 4)
|
||||
#endif
|
||||
|
|
@ -46,18 +46,22 @@ tracemalloc_frame {
|
|||
PyObject *filename;
|
||||
unsigned int lineno;
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
struct tracemalloc_traceback {
|
||||
struct
|
||||
#ifdef __GNUC__
|
||||
__attribute__((packed))
|
||||
#endif
|
||||
tracemalloc_traceback {
|
||||
Py_uhash_t hash;
|
||||
/* Number of frames stored */
|
||||
uint16_t nframe;
|
||||
/* Total number of frames the traceback had */
|
||||
uint16_t total_nframe;
|
||||
struct tracemalloc_frame frames[1];
|
||||
struct tracemalloc_frame frames[];
|
||||
};
|
||||
#ifdef _MSC_VER
|
||||
#pragma pack(pop)
|
||||
#endif
|
||||
|
||||
|
||||
struct _tracemalloc_runtime_state {
|
||||
|
|
@ -95,7 +99,7 @@ struct _tracemalloc_runtime_state {
|
|||
Protected by TABLES_LOCK(). */
|
||||
_Py_hashtable_t *domains;
|
||||
|
||||
struct tracemalloc_traceback empty_traceback;
|
||||
struct tracemalloc_traceback *empty_traceback;
|
||||
|
||||
Py_tss_t reentrant_key;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ extern "C" {
|
|||
|
||||
#include "pycore_brc.h" // struct _brc_thread_state
|
||||
#include "pycore_freelist_state.h" // struct _Py_freelists
|
||||
#include "pycore_interpframe_structs.h" // _PyInterpreterFrame
|
||||
#include "pycore_mimalloc.h" // struct _mimalloc_thread_state
|
||||
#include "pycore_qsbr.h" // struct qsbr
|
||||
#include "pycore_uop.h" // struct _PyUOpInstruction
|
||||
|
|
@ -61,6 +62,10 @@ typedef struct _PyThreadStateImpl {
|
|||
// semi-public fields are in PyThreadState.
|
||||
PyThreadState base;
|
||||
|
||||
// Embedded base frame - sentinel at the bottom of the frame stack.
|
||||
// Used by profiling/sampling to detect incomplete stack traces.
|
||||
_PyInterpreterFrame base_frame;
|
||||
|
||||
// The reference count field is used to synchronize deallocation of the
|
||||
// thread state during runtime finalization.
|
||||
Py_ssize_t refcount;
|
||||
|
|
|
|||
|
|
@ -307,14 +307,6 @@ PyAPI_FUNC(PyObject*) _PyUnicode_JoinArray(
|
|||
Py_ssize_t seqlen
|
||||
);
|
||||
|
||||
/* Test whether a unicode is equal to ASCII identifier. Return 1 if true,
|
||||
0 otherwise. The right argument must be ASCII identifier.
|
||||
Any error occurs inside will be cleared before return. */
|
||||
extern int _PyUnicode_EqualToASCIIId(
|
||||
PyObject *left, /* Left string */
|
||||
_Py_Identifier *right /* Right identifier */
|
||||
);
|
||||
|
||||
// Test whether a unicode is equal to ASCII string. Return 1 if true,
|
||||
// 0 otherwise. The right argument must be ASCII-encoded string.
|
||||
// Any error occurs inside will be cleared before return.
|
||||
|
|
|
|||
12
Include/internal/pycore_unicodeobject_generated.h
generated
12
Include/internal/pycore_unicodeobject_generated.h
generated
|
|
@ -1108,6 +1108,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
|||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(cache_frames);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(cached_datetime_module);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
|
|
@ -2884,6 +2888,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
|||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(stats);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(status);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
|
|
@ -2952,6 +2960,10 @@ _PyUnicode_InitStaticStrings(PyInterpreterState *interp) {
|
|||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(take_bytes);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
assert(PyUnicode_GET_LENGTH(string) != 1);
|
||||
string = &_Py_ID(target);
|
||||
_PyUnicode_InternStatic(interp, &string);
|
||||
assert(_PyUnicode_CheckConsistency(string, 1));
|
||||
|
|
|
|||
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