Merge branch 'python:main' into pyrepl-module-completion-check-for-already-imported-modules

This commit is contained in:
Loïc Simon 2025-10-12 00:11:38 +02:00 committed by GitHub
commit e3f1ddb88b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
268 changed files with 6793 additions and 3830 deletions

4
.github/CODEOWNERS vendored
View file

@ -86,6 +86,10 @@ Modules/makesetup @erlend-aasland @AA-Turner @emmatyping
Modules/Setup* @erlend-aasland @AA-Turner @emmatyping Modules/Setup* @erlend-aasland @AA-Turner @emmatyping
Tools/build/regen-configure.sh @AA-Turner Tools/build/regen-configure.sh @AA-Turner
# generate-build-details
Tools/build/generate-build-details.py @FFY00
Lib/test/test_build_details.py @FFY00
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Documentation # Documentation

View file

@ -1,6 +1,7 @@
self-hosted-runner: self-hosted-runner:
# Pending https://github.com/rhysd/actionlint/issues/533 # Pending https://github.com/rhysd/actionlint/issues/533
labels: ["windows-11-arm"] # and https://github.com/rhysd/actionlint/issues/571
labels: ["windows-11-arm", "macos-15-intel"]
config-variables: null config-variables: null

View file

@ -202,24 +202,16 @@ jobs:
strategy: strategy:
fail-fast: false fail-fast: false
matrix: matrix:
# Cirrus and macos-14 are M1, macos-13 is default GHA Intel. # macos-14 is M1, macos-15-intel is Intel.
# macOS 13 only runs tests against the GIL-enabled CPython. # macos-15-intel only runs tests against the GIL-enabled CPython.
# Cirrus used for upstream, macos-14 for forks.
os: os:
- ghcr.io/cirruslabs/macos-runner:sonoma
- macos-14 - macos-14
- macos-13 - macos-15-intel
is-fork: # only used for the exclusion trick
- ${{ github.repository_owner != 'python' }}
free-threading: free-threading:
- false - false
- true - true
exclude: exclude:
- os: ghcr.io/cirruslabs/macos-runner:sonoma - os: macos-15-intel
is-fork: true
- os: macos-14
is-fork: false
- os: macos-13
free-threading: true free-threading: true
uses: ./.github/workflows/reusable-macos.yml uses: ./.github/workflows/reusable-macos.yml
with: with:
@ -273,7 +265,7 @@ jobs:
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise # Keep 1.1.1w in our list despite it being upstream EOL and otherwise
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs # unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
# supported by important vendors such as AWS-LC. # supported by important vendors such as AWS-LC.
openssl_ver: [1.1.1w, 3.0.17, 3.2.5, 3.3.4, 3.4.2, 3.5.2] openssl_ver: [1.1.1w, 3.0.18, 3.2.6, 3.3.5, 3.4.3, 3.5.4]
# See Tools/ssl/make_ssl_data.py for notes on adding a new version # See Tools/ssl/make_ssl_data.py for notes on adding a new version
env: env:
OPENSSL_VER: ${{ matrix.openssl_ver }} OPENSSL_VER: ${{ matrix.openssl_ver }}
@ -409,9 +401,8 @@ jobs:
fail-fast: false fail-fast: false
matrix: matrix:
include: include:
# Use the same runs-on configuration as build-macos and build-ubuntu.
- arch: aarch64 - arch: aarch64
runs-on: ${{ github.repository_owner == 'python' && 'ghcr.io/cirruslabs/macos-runner:sonoma' || 'macos-14' }} runs-on: macos-14
- arch: x86_64 - arch: x86_64
runs-on: ubuntu-24.04 runs-on: ubuntu-24.04
@ -421,7 +412,7 @@ jobs:
with: with:
persist-credentials: false persist-credentials: false
- name: Build and test - name: Build and test
run: ./Android/android.py ci ${{ matrix.arch }}-linux-android run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
build-wasi: build-wasi:
name: 'WASI' name: 'WASI'
@ -438,7 +429,7 @@ jobs:
needs: build-context needs: build-context
if: needs.build-context.outputs.run-tests == 'true' if: needs.build-context.outputs.run-tests == 'true'
env: env:
OPENSSL_VER: 3.0.16 OPENSSL_VER: 3.0.18
PYTHONSTRICTEXTENSIONBUILD: 1 PYTHONSTRICTEXTENSIONBUILD: 1
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@ -558,7 +549,7 @@ jobs:
matrix: matrix:
os: [ubuntu-24.04] os: [ubuntu-24.04]
env: env:
OPENSSL_VER: 3.0.16 OPENSSL_VER: 3.0.18
PYTHONSTRICTEXTENSIONBUILD: 1 PYTHONSTRICTEXTENSIONBUILD: 1
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0 ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
steps: steps:

View file

@ -81,7 +81,7 @@ jobs:
runner: windows-11-arm runner: windows-11-arm
- target: x86_64-apple-darwin/clang - target: x86_64-apple-darwin/clang
architecture: x86_64 architecture: x86_64
runner: macos-13 runner: macos-15-intel
- target: aarch64-apple-darwin/clang - target: aarch64-apple-darwin/clang
architecture: aarch64 architecture: aarch64
runner: macos-14 runner: macos-14
@ -106,15 +106,10 @@ jobs:
./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} ./PCbuild/build.bat --experimental-jit ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }}
./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3 ./PCbuild/rt.bat ${{ matrix.debug && '-d' || '' }} -p ${{ matrix.architecture }} -q --multiprocess 0 --timeout 4500 --verbose2 --verbose3
# The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966.
# This is a bug in the macOS runner image where the pre-installed Python is installed in the same
# directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes
# the symlink to the pre-installed Python so that the Homebrew Python is used instead.
- name: macOS - name: macOS
if: runner.os == 'macOS' if: runner.os == 'macOS'
run: | run: |
brew update brew update
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew install llvm@${{ matrix.llvm }} brew install llvm@${{ matrix.llvm }}
export SDKROOT="$(xcrun --show-sdk-path)" export SDKROOT="$(xcrun --show-sdk-path)"
# Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to # Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to

View file

@ -1,31 +0,0 @@
name: Update GH projects
on:
issues:
types:
- opened
- labeled
permissions:
contents: read
jobs:
add-to-project:
name: Add issues to projects
runs-on: ubuntu-latest
timeout-minutes: 10
strategy:
fail-fast: false
matrix:
include:
# if an issue has any of these labels, it will be added
# to the corresponding project
- { project: 2, label: "release-blocker, deferred-blocker" }
- { project: 32, label: sprint }
steps:
- uses: actions/add-to-project@v1.0.0
with:
project-url: https://github.com/orgs/python/projects/${{ matrix.project }}
github-token: ${{ secrets.ADD_TO_PROJECT_PAT }}
labeled: ${{ matrix.label }}

View file

@ -60,15 +60,15 @@ jobs:
--prefix=/opt/python-dev \ --prefix=/opt/python-dev \
--with-openssl="$(brew --prefix openssl@3.0)" --with-openssl="$(brew --prefix openssl@3.0)"
- name: Build CPython - name: Build CPython
if : ${{ inputs.free-threading || inputs.os != 'macos-13' }} if : ${{ inputs.free-threading || inputs.os != 'macos-15-intel' }}
run: gmake -j8 run: gmake -j8
- name: Build CPython for compiler warning check - name: Build CPython for compiler warning check
if : ${{ !inputs.free-threading && inputs.os == 'macos-13' }} if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }}
run: set -o pipefail; gmake -j8 --output-sync 2>&1 | tee compiler_output_macos.txt run: set -o pipefail; gmake -j8 --output-sync 2>&1 | tee compiler_output_macos.txt
- name: Display build info - name: Display build info
run: make pythoninfo run: make pythoninfo
- name: Check compiler warnings - name: Check compiler warnings
if : ${{ !inputs.free-threading && inputs.os == 'macos-13' }} if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }}
run: >- run: >-
python3 Tools/build/check_warnings.py python3 Tools/build/check_warnings.py
--compiler-output-file-path=compiler_output_macos.txt --compiler-output-file-path=compiler_output_macos.txt

View file

@ -30,7 +30,7 @@ jobs:
runs-on: ${{ inputs.os }} runs-on: ${{ inputs.os }}
timeout-minutes: 60 timeout-minutes: 60
env: env:
OPENSSL_VER: 3.0.15 OPENSSL_VER: 3.0.18
PYTHONSTRICTEXTENSIONBUILD: 1 PYTHONSTRICTEXTENSIONBUILD: 1
TERM: linux TERM: linux
steps: steps:

View file

@ -58,7 +58,7 @@ jobs:
# runner: windows-2022 # runner: windows-2022
- target: x86_64-apple-darwin/clang - target: x86_64-apple-darwin/clang
architecture: x86_64 architecture: x86_64
runner: macos-13 runner: macos-15-intel
- target: aarch64-apple-darwin/clang - target: aarch64-apple-darwin/clang
architecture: aarch64 architecture: aarch64
runner: macos-14 runner: macos-14
@ -101,17 +101,10 @@ jobs:
set LLVMInstallDir=C:\Program Files\LLVM set LLVMInstallDir=C:\Program Files\LLVM
./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }} ./PCbuild/build.bat --tail-call-interp -p ${{ matrix.architecture }}
# The `find` line is required as a result of https://github.com/actions/runner-images/issues/9966.
# This is a bug in the macOS runner image where the pre-installed Python is installed in the same
# directory as the Homebrew Python, which causes the build to fail for macos-13. This line removes
# the symlink to the pre-installed Python so that the Homebrew Python is used instead.
# Note: when a new LLVM is released, the homebrew installation directory changes, so the builds will fail.
# We either need to upgrade LLVM or change the directory being pointed to.
- name: Native macOS (release) - name: Native macOS (release)
if: runner.os == 'macOS' if: runner.os == 'macOS'
run: | run: |
brew update brew update
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
brew install llvm@${{ matrix.llvm }} brew install llvm@${{ matrix.llvm }}
export SDKROOT="$(xcrun --show-sdk-path)" export SDKROOT="$(xcrun --show-sdk-path)"
export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH" export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH"

View file

@ -26,6 +26,10 @@ repos:
name: Run Ruff (lint) on Tools/peg_generator/ name: Run Ruff (lint) on Tools/peg_generator/
args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml] args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml]
files: ^Tools/peg_generator/ files: ^Tools/peg_generator/
- id: ruff-check
name: Run Ruff (lint) on Tools/wasm/
args: [--exit-non-zero-on-fix, --config=Tools/wasm/.ruff.toml]
files: ^Tools/wasm/
- id: ruff-format - id: ruff-format
name: Run Ruff (format) on Doc/ name: Run Ruff (format) on Doc/
args: [--check] args: [--check]
@ -34,6 +38,10 @@ repos:
name: Run Ruff (format) on Tools/build/check_warnings.py name: Run Ruff (format) on Tools/build/check_warnings.py
args: [--check, --config=Tools/build/.ruff.toml] args: [--check, --config=Tools/build/.ruff.toml]
files: ^Tools/build/check_warnings.py files: ^Tools/build/check_warnings.py
- id: ruff-format
name: Run Ruff (format) on Tools/wasm/
args: [--check, --config=Tools/wasm/.ruff.toml]
files: ^Tools/wasm/
- repo: https://github.com/psf/black-pre-commit-mirror - repo: https://github.com/psf/black-pre-commit-mirror
rev: 25.9.0 rev: 25.9.0

View file

@ -2,6 +2,7 @@
import asyncio import asyncio
import argparse import argparse
import json
import os import os
import platform import platform
import re import re
@ -184,10 +185,16 @@ def make_build_python(context):
run(["make", "-j", str(os.cpu_count())]) run(["make", "-j", str(os.cpu_count())])
# To create new builds of these dependencies, usually all that's necessary is to
# push a tag to the cpython-android-source-deps repository, and GitHub Actions
# will do the rest.
#
# If you're a member of the Python core team, and you'd like to be able to push
# these tags yourself, please contact Malcolm Smith or Russell Keith-Magee.
def unpack_deps(host, prefix_dir): def unpack_deps(host, prefix_dir):
os.chdir(prefix_dir) os.chdir(prefix_dir)
deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download" deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"
for name_ver in ["bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.0.15-4", for name_ver in ["bzip2-1.0.8-3", "libffi-3.4.4-3", "openssl-3.0.18-0",
"sqlite-3.50.4-0", "xz-5.4.6-1", "zstd-1.5.7-1"]: "sqlite-3.50.4-0", "xz-5.4.6-1", "zstd-1.5.7-1"]:
filename = f"{name_ver}-{host}.tar.gz" filename = f"{name_ver}-{host}.tar.gz"
download(f"{deps_url}/{name_ver}/{filename}") download(f"{deps_url}/{name_ver}/{filename}")
@ -546,27 +553,33 @@ async def gradle_task(context):
task_prefix = "connected" task_prefix = "connected"
env["ANDROID_SERIAL"] = context.connected env["ANDROID_SERIAL"] = context.connected
if context.command: if context.ci_mode:
mode = "-c" context.args[0:0] = [
module = context.command # See _add_ci_python_opts in libregrtest/main.py.
else: "-W", "error", "-bb", "-E",
mode = "-m"
module = context.module or "test" # Randomization is disabled because order-dependent failures are
# much less likely to pass on a rerun in single-process mode.
"-m", "test",
f"--{context.ci_mode}-ci", "--single-process", "--no-randomize"
]
if not any(arg in context.args for arg in ["-c", "-m"]):
context.args[0:0] = ["-m", "test"]
args = [ args = [
gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest", gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest",
] + [ ] + [
# Build-time properties f"-P{name}={value}"
f"-Ppython.{name}={value}"
for name, value in [ for name, value in [
("sitePackages", context.site_packages), ("cwd", context.cwd) ("python.sitePackages", context.site_packages),
] if value ("python.cwd", context.cwd),
] + [ (
# Runtime properties "android.testInstrumentationRunnerArguments.pythonArgs",
f"-Pandroid.testInstrumentationRunnerArguments.python{name}={value}" json.dumps(context.args),
for name, value in [ ),
("Mode", mode), ("Module", module), ("Args", join_command(context.args)) ]
] if value if value
] ]
if context.verbose >= 2: if context.verbose >= 2:
args.append("--info") args.append("--info")
@ -734,15 +747,14 @@ def ci(context):
else: else:
with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir: with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
print("::group::Tests") print("::group::Tests")
# Prove the package is self-contained by using it to run the tests. # Prove the package is self-contained by using it to run the tests.
shutil.unpack_archive(package_path, temp_dir) shutil.unpack_archive(package_path, temp_dir)
launcher_args = [
# Randomization is disabled because order-dependent failures are "--managed", "maxVersion", "-v", f"--{context.ci_mode}-ci"
# much less likely to pass on a rerun in single-process mode. ]
launcher_args = ["--managed", "maxVersion", "-v"]
test_args = ["--fast-ci", "--single-process", "--no-randomize"]
run( run(
["./android.py", "test", *launcher_args, "--", *test_args], ["./android.py", "test", *launcher_args],
cwd=temp_dir cwd=temp_dir
) )
print("::endgroup::") print("::endgroup::")
@ -825,18 +837,11 @@ def add_parser(*args, **kwargs):
test.add_argument( test.add_argument(
"--cwd", metavar="DIR", type=abspath, "--cwd", metavar="DIR", type=abspath,
help="Directory to copy as the app's working directory.") help="Directory to copy as the app's working directory.")
mode_group = test.add_mutually_exclusive_group()
mode_group.add_argument(
"-c", dest="command", help="Execute the given Python code.")
mode_group.add_argument(
"-m", dest="module", help="Execute the module with the given name.")
test.epilog = (
"If neither -c nor -m are passed, the default is '-m test', which will "
"run Python's own test suite.")
test.add_argument( test.add_argument(
"args", nargs="*", help=f"Arguments to add to sys.argv. " "args", nargs="*", help=f"Python command-line arguments. "
f"Separate them from {SCRIPT_NAME}'s own arguments with `--`.") f"Separate them from {SCRIPT_NAME}'s own arguments with `--`. "
f"If neither -c nor -m are included, `-m test` will be prepended, "
f"which will run Python's own test suite.")
# Package arguments. # Package arguments.
for subcommand in [package, ci]: for subcommand in [package, ci]:
@ -844,6 +849,16 @@ def add_parser(*args, **kwargs):
"-g", action="store_true", default=False, dest="debug", "-g", action="store_true", default=False, dest="debug",
help="Include debug information in package") help="Include debug information in package")
# CI arguments
for subcommand in [test, ci]:
group = subcommand.add_mutually_exclusive_group(required=subcommand is ci)
group.add_argument(
"--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")
return parser.parse_args() return parser.parse_args()

View file

@ -20,7 +20,7 @@ class PythonSuite {
val status = PythonTestRunner( val status = PythonTestRunner(
InstrumentationRegistry.getInstrumentation().targetContext InstrumentationRegistry.getInstrumentation().targetContext
).run( ).run(
InstrumentationRegistry.getArguments() InstrumentationRegistry.getArguments().getString("pythonArgs")!!,
) )
assertEquals(0, status) assertEquals(0, status)
} finally { } finally {

View file

@ -3,6 +3,7 @@
#include <jni.h> #include <jni.h>
#include <pthread.h> #include <pthread.h>
#include <Python.h> #include <Python.h>
#include <signal.h>
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
@ -15,6 +16,13 @@ static void throw_runtime_exception(JNIEnv *env, const char *message) {
message); message);
} }
static void throw_errno(JNIEnv *env, const char *error_prefix) {
char error_message[1024];
snprintf(error_message, sizeof(error_message),
"%s: %s", error_prefix, strerror(errno));
throw_runtime_exception(env, error_message);
}
// --- Stdio redirection ------------------------------------------------------ // --- Stdio redirection ------------------------------------------------------
@ -95,10 +103,7 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL
for (StreamInfo *si = STREAMS; si->file; si++) { for (StreamInfo *si = STREAMS; si->file; si++) {
char *error_prefix; char *error_prefix;
if ((error_prefix = redirect_stream(si))) { if ((error_prefix = redirect_stream(si))) {
char error_message[1024]; throw_errno(env, error_prefix);
snprintf(error_message, sizeof(error_message),
"%s: %s", error_prefix, strerror(errno));
throw_runtime_exception(env, error_message);
return; return;
} }
} }
@ -107,13 +112,38 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL
// --- Python initialization --------------------------------------------------- // --- Python initialization ---------------------------------------------------
static PyStatus set_config_string( static char *init_signals() {
JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value // Some tests use SIGUSR1, but that's blocked by default in an Android app in
) { // order to make it available to `sigwait` in the Signal Catcher thread.
const char *value_utf8 = (*env)->GetStringUTFChars(env, value, NULL); // (https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/signal_catcher.cc).
PyStatus status = PyConfig_SetBytesString(config, config_str, value_utf8); // That thread's functionality is only useful for debugging the JVM, so disabling
(*env)->ReleaseStringUTFChars(env, value, value_utf8); // it should not weaken the tests.
return status; //
// There's no safe way of stopping the thread completely (#123982), but simply
// unblocking SIGUSR1 is enough to fix most tests.
//
// However, in tests that generate multiple different signals in quick
// succession, it's possible for SIGUSR1 to arrive while the main thread is busy
// running the C-level handler for a different signal. In that case, the SIGUSR1
// may be sent to the Signal Catcher thread instead, which will generate a log
// message containing the text "reacting to signal".
//
// Such tests may need to be changed in one of the following ways:
// * Use a signal other than SIGUSR1 (e.g. test_stress_delivery_simultaneous in
// test_signal.py).
// * Send the signal to a specific thread rather than the whole process (e.g.
// test_signals in test_threadsignals.py.
sigset_t set;
if (sigemptyset(&set)) {
return "sigemptyset";
}
if (sigaddset(&set, SIGUSR1)) {
return "sigaddset";
}
if ((errno = pthread_sigmask(SIG_UNBLOCK, &set, NULL))) {
return "pthread_sigmask";
}
return NULL;
} }
static void throw_status(JNIEnv *env, PyStatus status) { static void throw_status(JNIEnv *env, PyStatus status) {
@ -121,27 +151,47 @@ static void throw_status(JNIEnv *env, PyStatus status) {
} }
JNIEXPORT int JNICALL Java_org_python_testbed_PythonTestRunner_runPython( JNIEXPORT int JNICALL Java_org_python_testbed_PythonTestRunner_runPython(
JNIEnv *env, jobject obj, jstring home, jstring runModule JNIEnv *env, jobject obj, jstring home, jarray args
) { ) {
const char *home_utf8 = (*env)->GetStringUTFChars(env, home, NULL);
char cwd[PATH_MAX];
snprintf(cwd, sizeof(cwd), "%s/%s", home_utf8, "cwd");
if (chdir(cwd)) {
throw_errno(env, "chdir");
return 1;
}
char *error_prefix;
if ((error_prefix = init_signals())) {
throw_errno(env, error_prefix);
return 1;
}
PyConfig config; PyConfig config;
PyStatus status; PyStatus status;
PyConfig_InitIsolatedConfig(&config); PyConfig_InitPythonConfig(&config);
status = set_config_string(env, &config, &config.home, home); jsize argc = (*env)->GetArrayLength(env, args);
if (PyStatus_Exception(status)) { const char *argv[argc + 1];
for (int i = 0; i < argc; i++) {
jobject arg = (*env)->GetObjectArrayElement(env, args, i);
argv[i] = (*env)->GetStringUTFChars(env, arg, NULL);
}
argv[argc] = NULL;
// PyConfig_SetBytesArgv "must be called before other methods, since the
// preinitialization configuration depends on command line arguments"
if (PyStatus_Exception(status = PyConfig_SetBytesArgv(&config, argc, (char**)argv))) {
throw_status(env, status); throw_status(env, status);
return 1; return 1;
} }
status = set_config_string(env, &config, &config.run_module, runModule); status = PyConfig_SetBytesString(&config, &config.home, home_utf8);
if (PyStatus_Exception(status)) { if (PyStatus_Exception(status)) {
throw_status(env, status); throw_status(env, status);
return 1; return 1;
} }
// Some tests generate SIGPIPE and SIGXFSZ, which should be ignored.
config.install_signal_handlers = 1;
status = Py_InitializeFromConfig(&config); status = Py_InitializeFromConfig(&config);
if (PyStatus_Exception(status)) { if (PyStatus_Exception(status)) {
throw_status(env, status); throw_status(env, status);

View file

@ -5,6 +5,7 @@ import android.os.*
import android.system.Os import android.system.Os
import android.widget.TextView import android.widget.TextView
import androidx.appcompat.app.* import androidx.appcompat.app.*
import org.json.JSONArray
import java.io.* import java.io.*
@ -15,30 +16,25 @@ class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main) setContentView(R.layout.activity_main)
val status = PythonTestRunner(this).run("-m", "test", "-W -uall") val status = PythonTestRunner(this).run("""["-m", "test", "-W", "-uall"]""")
findViewById<TextView>(R.id.tvHello).text = "Exit status $status" findViewById<TextView>(R.id.tvHello).text = "Exit status $status"
} }
} }
class PythonTestRunner(val context: Context) { class PythonTestRunner(val context: Context) {
fun run(instrumentationArgs: Bundle) = run(
instrumentationArgs.getString("pythonMode")!!,
instrumentationArgs.getString("pythonModule")!!,
instrumentationArgs.getString("pythonArgs") ?: "",
)
/** Run Python. /** Run Python.
* *
* @param mode Either "-c" or "-m". * @param args Python command-line, encoded as JSON.
* @param module Python statements for "-c" mode, or a module name for
* "-m" mode.
* @param args Arguments to add to sys.argv. Will be parsed by `shlex.split`.
* @return The Python exit status: zero on success, nonzero on failure. */ * @return The Python exit status: zero on success, nonzero on failure. */
fun run(mode: String, module: String, args: String) : Int { fun run(args: String) : Int {
Os.setenv("PYTHON_MODE", mode, true) // We leave argument 0 as an empty string, which is a placeholder for the
Os.setenv("PYTHON_MODULE", module, true) // executable name in embedded mode.
Os.setenv("PYTHON_ARGS", args, true) val argsJsonArray = JSONArray(args)
val argsStringArray = Array<String>(argsJsonArray.length() + 1) { it -> ""}
for (i in 0..<argsJsonArray.length()) {
argsStringArray[i + 1] = argsJsonArray.getString(i)
}
// Python needs this variable to help it find the temporary directory, // Python needs this variable to help it find the temporary directory,
// but Android only sets it on API level 33 and later. // but Android only sets it on API level 33 and later.
@ -47,10 +43,7 @@ class PythonTestRunner(val context: Context) {
val pythonHome = extractAssets() val pythonHome = extractAssets()
System.loadLibrary("main_activity") System.loadLibrary("main_activity")
redirectStdioToLogcat() redirectStdioToLogcat()
return runPython(pythonHome.toString(), argsStringArray)
// The main module is in src/main/python. We don't simply call it
// "main", as that could clash with third-party test code.
return runPython(pythonHome.toString(), "android_testbed_main")
} }
private fun extractAssets() : File { private fun extractAssets() : File {
@ -59,6 +52,13 @@ class PythonTestRunner(val context: Context) {
throw RuntimeException("Failed to delete $pythonHome") throw RuntimeException("Failed to delete $pythonHome")
} }
extractAssetDir("python", context.filesDir) extractAssetDir("python", context.filesDir)
// Empty directories are lost in the asset packing/unpacking process.
val cwd = File(pythonHome, "cwd")
if (!cwd.exists()) {
cwd.mkdir()
}
return pythonHome return pythonHome
} }
@ -88,5 +88,5 @@ class PythonTestRunner(val context: Context) {
} }
private external fun redirectStdioToLogcat() private external fun redirectStdioToLogcat()
private external fun runPython(home: String, runModule: String) : Int private external fun runPython(home: String, args: Array<String>) : Int
} }

View file

@ -1,48 +0,0 @@
import os
import runpy
import shlex
import signal
import sys
# Some tests use SIGUSR1, but that's blocked by default in an Android app in
# order to make it available to `sigwait` in the Signal Catcher thread.
# (https://cs.android.com/android/platform/superproject/+/android14-qpr3-release:art/runtime/signal_catcher.cc).
# That thread's functionality is only useful for debugging the JVM, so disabling
# it should not weaken the tests.
#
# There's no safe way of stopping the thread completely (#123982), but simply
# unblocking SIGUSR1 is enough to fix most tests.
#
# However, in tests that generate multiple different signals in quick
# succession, it's possible for SIGUSR1 to arrive while the main thread is busy
# running the C-level handler for a different signal. In that case, the SIGUSR1
# may be sent to the Signal Catcher thread instead, which will generate a log
# message containing the text "reacting to signal".
#
# Such tests may need to be changed in one of the following ways:
# * Use a signal other than SIGUSR1 (e.g. test_stress_delivery_simultaneous in
# test_signal.py).
# * Send the signal to a specific thread rather than the whole process (e.g.
# test_signals in test_threadsignals.py.
signal.pthread_sigmask(signal.SIG_UNBLOCK, [signal.SIGUSR1])
mode = os.environ["PYTHON_MODE"]
module = os.environ["PYTHON_MODULE"]
sys.argv[1:] = shlex.split(os.environ["PYTHON_ARGS"])
cwd = f"{sys.prefix}/cwd"
if not os.path.exists(cwd):
# Empty directories are lost in the asset packing/unpacking process.
os.mkdir(cwd)
os.chdir(cwd)
if mode == "-c":
# In -c mode, sys.path starts with an empty string, which means whatever the current
# working directory is at the moment of each import.
sys.path.insert(0, "")
exec(module, {})
elif mode == "-m":
sys.path.insert(0, os.getcwd())
runpy.run_module(module, run_name="__main__", alter_sys=True)
else:
raise ValueError(f"unknown mode: {mode}")

View file

@ -312,11 +312,18 @@ def unpack_deps(
On iOS, as a safety mechanism, any dynamic libraries will be purged from On iOS, as a safety mechanism, any dynamic libraries will be purged from
the unpacked dependencies. the unpacked dependencies.
""" """
# To create new builds of these dependencies, usually all that's necessary
# is to push a tag to the cpython-apple-source-deps repository, and GitHub
# Actions will do the rest.
#
# If you're a member of the Python core team, and you'd like to be able to
# push these tags yourself, please contact Malcolm Smith or Russell
# Keith-Magee.
deps_url = "https://github.com/beeware/cpython-apple-source-deps/releases/download" deps_url = "https://github.com/beeware/cpython-apple-source-deps/releases/download"
for name_ver in [ for name_ver in [
"BZip2-1.0.8-2", "BZip2-1.0.8-2",
"libFFI-3.4.7-2", "libFFI-3.4.7-2",
"OpenSSL-3.0.17-1", "OpenSSL-3.0.18-1",
"XZ-5.6.4-2", "XZ-5.6.4-2",
"mpdecimal-4.0.0-2", "mpdecimal-4.0.0-2",
"zstd-1.5.7-1", "zstd-1.5.7-1",

View file

@ -184,7 +184,7 @@ venv:
fi fi
.PHONY: dist-no-html .PHONY: dist-no-html
dist-no-html: dist-text dist-pdf dist-epub dist-texinfo dist-no-html: dist-text dist-epub dist-texinfo
.PHONY: dist .PHONY: dist
dist: dist:

View file

@ -260,7 +260,7 @@ Create, Finish, Discard
writer size to *size*. The caller is responsible to write *size* writer size to *size*. The caller is responsible to write *size*
bytes using :c:func:`PyBytesWriter_GetData`. bytes using :c:func:`PyBytesWriter_GetData`.
On error, set an exception and return NULL. On error, set an exception and return ``NULL``.
*size* must be positive or zero. *size* must be positive or zero.

View file

@ -175,6 +175,9 @@ There are a few functions specific to Python functions.
.. versionadded:: 3.12 .. versionadded:: 3.12
- ``PyFunction_PYFUNC_EVENT_MODIFY_QUALNAME``
.. versionadded:: 3.15
.. c:type:: int (*PyFunction_WatchCallback)(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value) .. c:type:: int (*PyFunction_WatchCallback)(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value)

View file

@ -1113,7 +1113,7 @@ code, or when embedding the Python interpreter:
This function is safe to call without an :term:`attached thread state`; it This function is safe to call without an :term:`attached thread state`; it
will simply return ``NULL`` indicating that there was no prior thread state. will simply return ``NULL`` indicating that there was no prior thread state.
.. seealso: .. seealso::
:c:func:`PyEval_ReleaseThread` :c:func:`PyEval_ReleaseThread`
.. note:: .. note::
@ -1124,6 +1124,19 @@ code, or when embedding the Python interpreter:
The following functions use thread-local storage, and are not compatible The following functions use thread-local storage, and are not compatible
with sub-interpreters: with sub-interpreters:
.. c:type:: PyGILState_STATE
The type of the value returned by :c:func:`PyGILState_Ensure` and passed to
:c:func:`PyGILState_Release`.
.. c:enumerator:: PyGILState_LOCKED
The GIL was already held when :c:func:`PyGILState_Ensure` was called.
.. c:enumerator:: PyGILState_UNLOCKED
The GIL was not held when :c:func:`PyGILState_Ensure` was called.
.. c:function:: PyGILState_STATE PyGILState_Ensure() .. c:function:: PyGILState_STATE PyGILState_Ensure()
Ensure that the current thread is ready to call the Python C API regardless Ensure that the current thread is ready to call the Python C API regardless
@ -1174,12 +1187,12 @@ with sub-interpreters:
made on the main thread. This is mainly a helper/diagnostic function. made on the main thread. This is mainly a helper/diagnostic function.
.. note:: .. note::
This function does not account for :term:`thread states <thread state>` created This function may return non-``NULL`` even when the :term:`thread state`
by something other than :c:func:`PyGILState_Ensure` (such as :c:func:`PyThreadState_New`). is detached.
Prefer :c:func:`PyThreadState_Get` or :c:func:`PyThreadState_GetUnchecked` Prefer :c:func:`PyThreadState_Get` or :c:func:`PyThreadState_GetUnchecked`
for most cases. for most cases.
.. seealso: :c:func:`PyThreadState_Get`` .. seealso:: :c:func:`PyThreadState_Get`
.. c:function:: int PyGILState_Check() .. c:function:: int PyGILState_Check()
@ -1278,11 +1291,11 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
must be :term:`attached <attached thread state>` must be :term:`attached <attached thread state>`
.. versionchanged:: 3.9 .. versionchanged:: 3.9
This function now calls the :c:member:`PyThreadState.on_delete` callback. This function now calls the :c:member:`!PyThreadState.on_delete` callback.
Previously, that happened in :c:func:`PyThreadState_Delete`. Previously, that happened in :c:func:`PyThreadState_Delete`.
.. versionchanged:: 3.13 .. versionchanged:: 3.13
The :c:member:`PyThreadState.on_delete` callback was removed. The :c:member:`!PyThreadState.on_delete` callback was removed.
.. c:function:: void PyThreadState_Delete(PyThreadState *tstate) .. c:function:: void PyThreadState_Delete(PyThreadState *tstate)

View file

@ -37,6 +37,19 @@ Tuple Objects
or ``NULL`` with an exception set on failure. or ``NULL`` with an exception set on failure.
.. c:function:: PyObject* PyTuple_FromArray(PyObject *const *array, Py_ssize_t size)
Create a tuple of *size* items and copy references from *array* to the new
tuple.
*array* can be NULL if *size* is ``0``.
On success, return a new reference.
On error, set an exception and return ``NULL``.
.. versionadded:: next
.. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...) .. c:function:: PyObject* PyTuple_Pack(Py_ssize_t n, ...)
Return a new tuple object of size *n*, Return a new tuple object of size *n*,

View file

@ -15,7 +15,6 @@ although there is currently no date scheduled for their removal.
* :mod:`builtins`: * :mod:`builtins`:
* ``bool(NotImplemented)``.
* Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)`` * Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)``
signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead, signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead,
the single argument signature. the single argument signature.

View file

@ -316,13 +316,14 @@ StreamWriter
If that fails, the data is queued in an internal write buffer until it can be If that fails, the data is queued in an internal write buffer until it can be
sent. sent.
The *data* buffer should be a bytes, bytearray, or C-contiguous one-dimensional
memoryview object.
The method should be used along with the ``drain()`` method:: The method should be used along with the ``drain()`` method::
stream.write(data) stream.write(data)
await stream.drain() await stream.drain()
.. note::
The *data* buffer should be a C contiguous one-dimensional :term:`bytes-like object <bytes-like object>`.
.. method:: writelines(data) .. method:: writelines(data)

View file

@ -336,7 +336,7 @@ Collections Abstract Base Classes -- Detailed Descriptions
.. note:: .. note::
In CPython, generator-based coroutines (:term:`generators <generator>` In CPython, generator-based coroutines (:term:`generators <generator>`
decorated with :func:`@types.coroutine <types.coroutine>`) are decorated with :deco:`types.coroutine`) are
*awaitables*, even though they do not have an :meth:`~object.__await__` method. *awaitables*, even though they do not have an :meth:`~object.__await__` method.
Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``. Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``.
Use :func:`inspect.isawaitable` to detect them. Use :func:`inspect.isawaitable` to detect them.
@ -354,7 +354,7 @@ Collections Abstract Base Classes -- Detailed Descriptions
.. note:: .. note::
In CPython, generator-based coroutines (:term:`generators <generator>` In CPython, generator-based coroutines (:term:`generators <generator>`
decorated with :func:`@types.coroutine <types.coroutine>`) are decorated with :deco:`types.coroutine`) are
*awaitables*, even though they do not have an :meth:`~object.__await__` method. *awaitables*, even though they do not have an :meth:`~object.__await__` method.
Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``. Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``.
Use :func:`inspect.isawaitable` to detect them. Use :func:`inspect.isawaitable` to detect them.

View file

@ -1,6 +1,8 @@
The :mod:`!compression` package The :mod:`!compression` package
=============================== ===============================
.. module:: compression
.. versionadded:: 3.14 .. versionadded:: 3.14
The :mod:`!compression` package contains the canonical compression modules The :mod:`!compression` package contains the canonical compression modules

View file

@ -327,10 +327,10 @@ Functions and classes provided:
.. function:: redirect_stdout(new_target) .. function:: redirect_stdout(new_target)
Context manager for temporarily redirecting :data:`sys.stdout` to Context manager for temporarily redirecting :data:`sys.stdout` to
another file or file-like object. another :term:`file object`.
This tool adds flexibility to existing functions or classes whose output This tool adds flexibility to existing functions or classes whose output
is hardwired to stdout. is hardwired to :data:`sys.stdout`.
For example, the output of :func:`help` normally is sent to *sys.stdout*. For example, the output of :func:`help` normally is sent to *sys.stdout*.
You can capture that output in a string by redirecting the output to an You can capture that output in a string by redirecting the output to an
@ -366,8 +366,8 @@ Functions and classes provided:
.. function:: redirect_stderr(new_target) .. function:: redirect_stderr(new_target)
Similar to :func:`~contextlib.redirect_stdout` but redirecting Similar to :func:`~contextlib.redirect_stdout` but redirecting the global
:data:`sys.stderr` to another file or file-like object. :data:`sys.stderr` to another :term:`file object`.
This context manager is :ref:`reentrant <reentrant-cms>`. This context manager is :ref:`reentrant <reentrant-cms>`.

View file

@ -13,7 +13,7 @@ being deprecated in Python 3.11. The removal was decided in :pep:`594`.
Applications can use the :mod:`hashlib` module from the standard library. Applications can use the :mod:`hashlib` module from the standard library.
Other possible replacements are third-party libraries from PyPI: Other possible replacements are third-party libraries from PyPI:
:pypi:`legacycrypt`, :pypi:`bcrypt`, :pypi:`argon2-cffi`, or :pypi:`passlib`. :pypi:`legacycrypt`, :pypi:`bcrypt`, or :pypi:`argon2-cffi`.
These are not supported or maintained by the Python core team. These are not supported or maintained by the Python core team.
The last version of Python that provided the :mod:`!crypt` module was The last version of Python that provided the :mod:`!crypt` module was

View file

@ -317,7 +317,7 @@ Module contents
:func:`!field`, then the class attribute for this field will be :func:`!field`, then the class attribute for this field will be
replaced by the specified *default* value. If *default* is not replaced by the specified *default* value. If *default* is not
provided, then the class attribute will be deleted. The intent is provided, then the class attribute will be deleted. The intent is
that after the :func:`@dataclass <dataclass>` decorator runs, the class that after the :deco:`dataclass` decorator runs, the class
attributes will all contain the default values for the fields, just attributes will all contain the default values for the fields, just
as if the default value itself were specified. For example, as if the default value itself were specified. For example,
after:: after::
@ -427,7 +427,7 @@ Module contents
:data:`typing.Any` is used for ``type``. The values of *init*, :data:`typing.Any` is used for ``type``. The values of *init*,
*repr*, *eq*, *order*, *unsafe_hash*, *frozen*, *repr*, *eq*, *order*, *unsafe_hash*, *frozen*,
*match_args*, *kw_only*, *slots*, and *weakref_slot* have *match_args*, *kw_only*, *slots*, and *weakref_slot* have
the same meaning as they do in :func:`@dataclass <dataclass>`. the same meaning as they do in :deco:`dataclass`.
If *module* is defined, the :attr:`!__module__` attribute If *module* is defined, the :attr:`!__module__` attribute
of the dataclass is set to that value. of the dataclass is set to that value.
@ -435,12 +435,12 @@ Module contents
The *decorator* parameter is a callable that will be used to create the dataclass. The *decorator* parameter is a callable that will be used to create the dataclass.
It should take the class object as a first argument and the same keyword arguments It should take the class object as a first argument and the same keyword arguments
as :func:`@dataclass <dataclass>`. By default, the :func:`@dataclass <dataclass>` as :deco:`dataclass`. By default, the :deco:`dataclass`
function is used. function is used.
This function is not strictly required, because any Python This function is not strictly required, because any Python
mechanism for creating a new class with :attr:`~object.__annotations__` can mechanism for creating a new class with :attr:`~object.__annotations__` can
then apply the :func:`@dataclass <dataclass>` function to convert that class to then apply the :deco:`dataclass` function to convert that class to
a dataclass. This function is provided as a convenience. For a dataclass. This function is provided as a convenience. For
example:: example::
@ -569,7 +569,7 @@ Post-init processing
def __post_init__(self): def __post_init__(self):
self.c = self.a + self.b self.c = self.a + self.b
The :meth:`~object.__init__` method generated by :func:`@dataclass <dataclass>` does not call base The :meth:`~object.__init__` method generated by :deco:`dataclass` does not call base
class :meth:`!__init__` methods. If the base class has an :meth:`!__init__` method class :meth:`!__init__` methods. If the base class has an :meth:`!__init__` method
that has to be called, it is common to call this method in a that has to be called, it is common to call this method in a
:meth:`__post_init__` method:: :meth:`__post_init__` method::
@ -599,7 +599,7 @@ parameters to :meth:`!__post_init__`. Also see the warning about how
Class variables Class variables
--------------- ---------------
One of the few places where :func:`@dataclass <dataclass>` actually inspects the type One of the few places where :deco:`dataclass` actually inspects the type
of a field is to determine if a field is a class variable as defined of a field is to determine if a field is a class variable as defined
in :pep:`526`. It does this by checking if the type of the field is in :pep:`526`. It does this by checking if the type of the field is
:data:`typing.ClassVar`. If a field is a ``ClassVar``, it is excluded :data:`typing.ClassVar`. If a field is a ``ClassVar``, it is excluded
@ -612,7 +612,7 @@ module-level :func:`fields` function.
Init-only variables Init-only variables
------------------- -------------------
Another place where :func:`@dataclass <dataclass>` inspects a type annotation is to Another place where :deco:`dataclass` inspects a type annotation is to
determine if a field is an init-only variable. It does this by seeing determine if a field is an init-only variable. It does this by seeing
if the type of a field is of type :class:`InitVar`. If a field if the type of a field is of type :class:`InitVar`. If a field
is an :class:`InitVar`, it is considered a pseudo-field called an init-only is an :class:`InitVar`, it is considered a pseudo-field called an init-only
@ -646,7 +646,7 @@ Frozen instances
---------------- ----------------
It is not possible to create truly immutable Python objects. However, It is not possible to create truly immutable Python objects. However,
by passing ``frozen=True`` to the :func:`@dataclass <dataclass>` decorator you can by passing ``frozen=True`` to the :deco:`dataclass` decorator you can
emulate immutability. In that case, dataclasses will add emulate immutability. In that case, dataclasses will add
:meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These :meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These
methods will raise a :exc:`FrozenInstanceError` when invoked. methods will raise a :exc:`FrozenInstanceError` when invoked.
@ -662,7 +662,7 @@ must use :meth:`!object.__setattr__`.
Inheritance Inheritance
----------- -----------
When the dataclass is being created by the :func:`@dataclass <dataclass>` decorator, When the dataclass is being created by the :deco:`dataclass` decorator,
it looks through all of the class's base classes in reverse MRO (that it looks through all of the class's base classes in reverse MRO (that
is, starting at :class:`object`) and, for each dataclass that it finds, is, starting at :class:`object`) and, for each dataclass that it finds,
adds the fields from that base class to an ordered mapping of fields. adds the fields from that base class to an ordered mapping of fields.
@ -786,7 +786,7 @@ for :attr:`!x` when creating a class instance will share the same copy
of :attr:`!x`. Because dataclasses just use normal Python class of :attr:`!x`. Because dataclasses just use normal Python class
creation they also share this behavior. There is no general way creation they also share this behavior. There is no general way
for Data Classes to detect this condition. Instead, the for Data Classes to detect this condition. Instead, the
:func:`@dataclass <dataclass>` decorator will raise a :exc:`ValueError` if it :deco:`dataclass` decorator will raise a :exc:`ValueError` if it
detects an unhashable default parameter. The assumption is that if detects an unhashable default parameter. The assumption is that if
a value is unhashable, it is mutable. This is a partial solution, a value is unhashable, it is mutable. This is a partial solution,
but it does protect against many common errors. but it does protect against many common errors.
@ -820,7 +820,7 @@ default value have the following special behaviors:
:meth:`~object.__get__` or :meth:`!__set__` method is called rather than returning or :meth:`~object.__get__` or :meth:`!__set__` method is called rather than returning or
overwriting the descriptor object. overwriting the descriptor object.
* To determine whether a field contains a default value, :func:`@dataclass <dataclass>` * To determine whether a field contains a default value, :deco:`dataclass`
will call the descriptor's :meth:`!__get__` method using its class access will call the descriptor's :meth:`!__get__` method using its class access
form: ``descriptor.__get__(obj=None, type=cls)``. If the form: ``descriptor.__get__(obj=None, type=cls)``. If the
descriptor returns a value in this case, it will be used as the descriptor returns a value in this case, it will be used as the

View file

@ -231,7 +231,7 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
*linejunk*: A function that accepts a single string argument, and returns *linejunk*: A function that accepts a single string argument, and returns
true if the string is junk, or false if not. The default is ``None``. There true if the string is junk, or false if not. The default is ``None``. There
is also a module-level function :func:`IS_LINE_JUNK`, which filters out lines is also a module-level function :func:`IS_LINE_JUNK`, which filters out lines
without visible characters, except for at most one pound character (``'#'``) without visible characters, except for at most one hash character (``'#'``)
-- however the underlying :class:`SequenceMatcher` class does a dynamic -- however the underlying :class:`SequenceMatcher` class does a dynamic
analysis of which lines are so frequent as to constitute noise, and this analysis of which lines are so frequent as to constitute noise, and this
usually works better than using this function. usually works better than using this function.

View file

@ -690,7 +690,7 @@ The :mod:`functools` module defines the following functions:
return not arg return not arg
``@singledispatchmethod`` supports nesting with other decorators such as ``@singledispatchmethod`` supports nesting with other decorators such as
:func:`@classmethod<classmethod>`. Note that to allow for :deco:`classmethod`. Note that to allow for
``dispatcher.register``, ``singledispatchmethod`` must be the *outer most* ``dispatcher.register``, ``singledispatchmethod`` must be the *outer most*
decorator. Here is the ``Negator`` class with the ``neg`` methods bound to decorator. Here is the ``Negator`` class with the ``neg`` methods bound to
the class, rather than an instance of the class:: the class, rather than an instance of the class::
@ -712,8 +712,7 @@ The :mod:`functools` module defines the following functions:
return not arg return not arg
The same pattern can be used for other similar decorators: The same pattern can be used for other similar decorators:
:func:`@staticmethod<staticmethod>`, :deco:`staticmethod`, :deco:`~abc.abstractmethod`, and others.
:func:`@abstractmethod<abc.abstractmethod>`, and others.
.. versionadded:: 3.8 .. versionadded:: 3.8

View file

@ -72,13 +72,12 @@ for example, a package and its resources can be imported from a zip file using
.. versionadded:: 3.9 .. versionadded:: 3.9
.. versionchanged:: 3.12 .. deprecated-removed:: 3.12 3.15
*package* parameter was renamed to *anchor*. *anchor* can now *package* parameter was renamed to *anchor*. *anchor* can now be a
be a non-package module and if omitted will default to the caller's non-package module and if omitted will default to the caller's module.
module. *package* is still accepted for compatibility but will raise *package* is no longer accepted since Python 3.15. Consider passing the
a :exc:`DeprecationWarning`. Consider passing the anchor positionally or anchor positionally or using ``importlib_resources >= 5.10`` for a
using ``importlib_resources >= 5.10`` for a compatible interface compatible interface on older Pythons.
on older Pythons.
.. function:: as_file(traversable) .. function:: as_file(traversable)

View file

@ -216,8 +216,8 @@ process and user.
You can delete items in this mapping to unset environment variables. You can delete items in this mapping to unset environment variables.
:func:`unsetenv` will be called automatically when an item is deleted from :func:`unsetenv` will be called automatically when an item is deleted from
:data:`os.environ`, and when one of the :meth:`pop` or :meth:`clear` methods is :data:`os.environ`, and when one of the :meth:`~dict.pop` or
called. :meth:`~dict.clear` methods is called.
.. seealso:: .. seealso::
@ -430,8 +430,8 @@ process and user.
associated with the effective user id of the process; the group access associated with the effective user id of the process; the group access
list may change over the lifetime of the process, it is not affected by list may change over the lifetime of the process, it is not affected by
calls to :func:`setgroups`, and its length is not limited to 16. The calls to :func:`setgroups`, and its length is not limited to 16. The
deployment target value, :const:`MACOSX_DEPLOYMENT_TARGET`, can be deployment target value can be obtained with
obtained with :func:`sysconfig.get_config_var`. :func:`sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') <sysconfig.get_config_var>`.
.. function:: getlogin() .. function:: getlogin()
@ -2606,10 +2606,10 @@ features:
Create a filesystem node (file, device special file or named pipe) named Create a filesystem node (file, device special file or named pipe) named
*path*. *mode* specifies both the permissions to use and the type of node *path*. *mode* specifies both the permissions to use and the type of node
to be created, being combined (bitwise OR) with one of ``stat.S_IFREG``, to be created, being combined (bitwise OR) with one of :const:`stat.S_IFREG`,
``stat.S_IFCHR``, ``stat.S_IFBLK``, and ``stat.S_IFIFO`` (those constants are :const:`stat.S_IFCHR`, :const:`stat.S_IFBLK`, and :const:`stat.S_IFIFO`.
available in :mod:`stat`). For ``stat.S_IFCHR`` and ``stat.S_IFBLK``, For :const:`stat.S_IFCHR` and :const:`stat.S_IFBLK`, *device* defines the
*device* defines the newly created device special file (probably using newly created device special file (probably using
:func:`os.makedev`), otherwise it is ignored. :func:`os.makedev`), otherwise it is ignored.
This function can also support :ref:`paths relative to directory descriptors This function can also support :ref:`paths relative to directory descriptors
@ -2627,13 +2627,13 @@ features:
.. function:: major(device, /) .. function:: major(device, /)
Extract the device major number from a raw device number (usually the Extract the device major number from a raw device number (usually the
:attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). :attr:`~stat_result.st_dev` or :attr:`~stat_result.st_rdev` field from :c:struct:`stat`).
.. function:: minor(device, /) .. function:: minor(device, /)
Extract the device minor number from a raw device number (usually the Extract the device minor number from a raw device number (usually the
:attr:`st_dev` or :attr:`st_rdev` field from :c:struct:`stat`). :attr:`~stat_result.st_dev` or :attr:`~stat_result.st_rdev` field from :c:struct:`stat`).
.. function:: makedev(major, minor, /) .. function:: makedev(major, minor, /)
@ -3364,8 +3364,8 @@ features:
.. versionchanged:: 3.8 .. versionchanged:: 3.8
On Windows, the :attr:`st_mode` member now identifies special On Windows, the :attr:`st_mode` member now identifies special
files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK` files as :const:`~stat.S_IFCHR`, :const:`~stat.S_IFIFO` or
as appropriate. :const:`~stat.S_IFBLK` as appropriate.
.. versionchanged:: 3.12 .. versionchanged:: 3.12
On Windows, :attr:`st_ctime` is deprecated. Eventually, it will On Windows, :attr:`st_ctime` is deprecated. Eventually, it will
@ -4285,10 +4285,10 @@ to be ignored.
.. function:: abort() .. function:: abort()
Generate a :const:`SIGABRT` signal to the current process. On Unix, the default Generate a :const:`~signal.SIGABRT` signal to the current process. On Unix, the default
behavior is to produce a core dump; on Windows, the process immediately returns behavior is to produce a core dump; on Windows, the process immediately returns
an exit code of ``3``. Be aware that calling this function will not call the an exit code of ``3``. Be aware that calling this function will not call the
Python signal handler registered for :const:`SIGABRT` with Python signal handler registered for :const:`~signal.SIGABRT` with
:func:`signal.signal`. :func:`signal.signal`.
@ -4592,6 +4592,8 @@ written in Python, such as a mail server's external command delivery program.
master end of the pseudo-terminal. For a more portable approach, use the master end of the pseudo-terminal. For a more portable approach, use the
:mod:`pty` module. If an error occurs :exc:`OSError` is raised. :mod:`pty` module. If an error occurs :exc:`OSError` is raised.
The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
.. audit-event:: os.forkpty "" os.forkpty .. audit-event:: os.forkpty "" os.forkpty
.. warning:: .. warning::
@ -4608,6 +4610,9 @@ written in Python, such as a mail server's external command delivery program.
threads, this now raises a :exc:`DeprecationWarning`. See the threads, this now raises a :exc:`DeprecationWarning`. See the
longer explanation on :func:`os.fork`. longer explanation on :func:`os.fork`.
.. versionchanged:: next
The returned file descriptor is now made non-inheritable.
.. availability:: Unix, not WASI, not Android, not iOS. .. availability:: Unix, not WASI, not Android, not iOS.

View file

@ -33,9 +33,14 @@ The :mod:`pty` module defines the following functions:
file descriptor connected to the child's controlling terminal (and also to the file descriptor connected to the child's controlling terminal (and also to the
child's standard input and output). child's standard input and output).
The returned file descriptor *fd* is :ref:`non-inheritable <fd_inheritance>`.
.. warning:: On macOS the use of this function is unsafe when mixed with using .. warning:: On macOS the use of this function is unsafe when mixed with using
higher-level system APIs, and that includes using :mod:`urllib.request`. higher-level system APIs, and that includes using :mod:`urllib.request`.
.. versionchanged:: next
The returned file descriptor is now made non-inheritable.
.. function:: openpty() .. function:: openpty()

View file

@ -205,10 +205,26 @@ The variables defined in the :mod:`signal` module are:
.. availability:: Unix. .. availability:: Unix.
.. data:: SIGPROF
Profiling timer expired.
.. availability:: Unix.
.. data:: SIGQUIT
Terminal quit signal.
.. availability:: Unix.
.. data:: SIGSEGV .. data:: SIGSEGV
Segmentation fault: invalid memory reference. Segmentation fault: invalid memory reference.
.. data:: SIGSTOP
Stop executing (cannot be caught or ignored).
.. data:: SIGSTKFLT .. data:: SIGSTKFLT
Stack fault on coprocessor. The Linux kernel does not raise this signal: it Stack fault on coprocessor. The Linux kernel does not raise this signal: it
@ -237,6 +253,12 @@ The variables defined in the :mod:`signal` module are:
.. availability:: Unix. .. availability:: Unix.
.. data:: SIGVTALRM
Virtual timer expired.
.. availability:: Unix.
.. data:: SIGWINCH .. data:: SIGWINCH
Window resize signal. Window resize signal.
@ -248,7 +270,7 @@ The variables defined in the :mod:`signal` module are:
All the signal numbers are defined symbolically. For example, the hangup signal All the signal numbers are defined symbolically. For example, the hangup signal
is defined as :const:`signal.SIGHUP`; the variable names are identical to the is defined as :const:`signal.SIGHUP`; the variable names are identical to the
names used in C programs, as found in ``<signal.h>``. The Unix man page for names used in C programs, as found in ``<signal.h>``. The Unix man page for
':c:func:`signal`' lists the existing signals (on some systems this is '``signal``' lists the existing signals (on some systems this is
:manpage:`signal(2)`, on others the list is in :manpage:`signal(7)`). Note that :manpage:`signal(2)`, on others the list is in :manpage:`signal(7)`). Note that
not all systems define the same set of signal names; only those names defined by not all systems define the same set of signal names; only those names defined by
the system are defined by this module. the system are defined by this module.
@ -644,9 +666,8 @@ The :mod:`signal` module defines the following functions:
*sigset*. *sigset*.
The return value is an object representing the data contained in the The return value is an object representing the data contained in the
:c:type:`siginfo_t` structure, namely: :attr:`si_signo`, :attr:`si_code`, ``siginfo_t`` structure, namely: ``si_signo``, ``si_code``,
:attr:`si_errno`, :attr:`si_pid`, :attr:`si_uid`, :attr:`si_status`, ``si_errno``, ``si_pid``, ``si_uid``, ``si_status``, ``si_band``.
:attr:`si_band`.
.. availability:: Unix. .. availability:: Unix.

View file

@ -354,9 +354,8 @@ Random generation
.. function:: RAND_status() .. function:: RAND_status()
Return ``True`` if the SSL pseudo-random number generator has been seeded Return ``True`` if the SSL pseudo-random number generator has been seeded
with 'enough' randomness, and ``False`` otherwise. You can use with 'enough' randomness, and ``False`` otherwise. Use :func:`ssl.RAND_add`
:func:`ssl.RAND_egd` and :func:`ssl.RAND_add` to increase the randomness of to increase the randomness of the pseudo-random number generator.
the pseudo-random number generator.
.. function:: RAND_add(bytes, entropy, /) .. function:: RAND_add(bytes, entropy, /)

View file

@ -24,7 +24,7 @@ Template strings
Template strings are a mechanism for custom string processing. Template strings are a mechanism for custom string processing.
They have the full flexibility of Python's :ref:`f-strings`, They have the full flexibility of Python's :ref:`f-strings`,
but return a :class:`Template` instance that gives access but return a :class:`Template` instance that gives access
to the static and interpolated (in curly braces) parts of a string to the static and interpolated (in curly brackets) parts of a string
*before* they are combined. *before* they are combined.
To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so: To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so:
@ -258,13 +258,16 @@ Types
.. attribute:: expression .. attribute:: expression
:type: str :type: str
The text of a valid Python expression, or an empty string. For interpolations created by t-string literals, :attr:`!expression`
is the expression text found inside the curly brackets (``{`` & ``}``),
including any whitespace, excluding the curly brackets themselves,
and ending before the first ``!``, ``:``, or ``=`` if any is present.
For manually created interpolations, :attr:`!expression` is the arbitrary
string provided when constructing the interpolation instance.
The :attr:`.expression` is the original text of the We recommend using valid Python expressions or the empty string for the
interpolation's Python expression, if the interpolation was created ``expression`` field of manually created :class:`!Interpolation`
from a t-string literal. Developers creating interpolations manually instances, although this is not enforced at runtime.
should either set this to an empty string or choose a suitable valid
Python expression.
>>> t'{1 + 2}'.interpolations[0].expression >>> t'{1 + 2}'.interpolations[0].expression
'1 + 2' '1 + 2'

View file

@ -649,7 +649,7 @@ functions.
If specified, *env* must provide any variables required for the program to If specified, *env* must provide any variables required for the program to
execute. On Windows, in order to run a `side-by-side assembly`_ the execute. On Windows, in order to run a `side-by-side assembly`_ the
specified *env* **must** include a valid :envvar:`SystemRoot`. specified *env* **must** include a valid ``%SystemRoot%``.
.. _side-by-side assembly: https://en.wikipedia.org/wiki/Side-by-Side_Assembly .. _side-by-side assembly: https://en.wikipedia.org/wiki/Side-by-Side_Assembly
@ -1473,7 +1473,7 @@ handling consistency are valid for these functions.
Return ``(exitcode, output)`` of executing *cmd* in a shell. Return ``(exitcode, output)`` of executing *cmd* in a shell.
Execute the string *cmd* in a shell with :meth:`Popen.check_output` and Execute the string *cmd* in a shell with :func:`check_output` and
return a 2-tuple ``(exitcode, output)``. return a 2-tuple ``(exitcode, output)``.
*encoding* and *errors* are used to decode output; *encoding* and *errors* are used to decode output;
see the notes on :ref:`frequently-used-arguments` for more details. see the notes on :ref:`frequently-used-arguments` for more details.

View file

@ -382,6 +382,9 @@ Other functions
Examples of returned values: Examples of returned values:
- linux-x86_64
- linux-aarch64
- solaris-2.6-sun4u
Windows: Windows:

View file

@ -1390,7 +1390,7 @@ These can be used as types in annotations. They all support subscription using
Using ``Annotated[T, x]`` as an annotation still allows for static Using ``Annotated[T, x]`` as an annotation still allows for static
typechecking of ``T``, as type checkers will simply ignore the metadata ``x``. typechecking of ``T``, as type checkers will simply ignore the metadata ``x``.
In this way, ``Annotated`` differs from the In this way, ``Annotated`` differs from the
:func:`@no_type_check <no_type_check>` decorator, which can also be used for :deco:`no_type_check` decorator, which can also be used for
adding annotations outside the scope of the typing system, but adding annotations outside the scope of the typing system, but
completely disables typechecking for a function or class. completely disables typechecking for a function or class.
@ -2269,7 +2269,7 @@ without the dedicated syntax, as documented below.
.. attribute:: __module__ .. attribute:: __module__
The module in which the type alias was defined:: The name of the module in which the type alias was defined::
>>> type Alias = int >>> type Alias = int
>>> Alias.__module__ >>> Alias.__module__
@ -2449,7 +2449,7 @@ types.
.. attribute:: __module__ .. attribute:: __module__
The module in which the new type is defined. The name of the module in which the new type is defined.
.. attribute:: __name__ .. attribute:: __name__
@ -2815,7 +2815,7 @@ Protocols
--------- ---------
The following protocols are provided by the :mod:`!typing` module. All are decorated The following protocols are provided by the :mod:`!typing` module. All are decorated
with :func:`@runtime_checkable <runtime_checkable>`. with :deco:`runtime_checkable`.
.. class:: SupportsAbs .. class:: SupportsAbs
@ -2996,7 +2996,7 @@ Functions and decorators
The presence of ``@dataclass_transform()`` tells a static type checker that the The presence of ``@dataclass_transform()`` tells a static type checker that the
decorated object performs runtime "magic" that decorated object performs runtime "magic" that
transforms a class in a similar way to transforms a class in a similar way to
:func:`@dataclasses.dataclass <dataclasses.dataclass>`. :deco:`dataclasses.dataclass`.
Example usage with a decorator function: Example usage with a decorator function:
@ -3034,14 +3034,14 @@ Functions and decorators
The ``CustomerModel`` classes defined above will The ``CustomerModel`` classes defined above will
be treated by type checkers similarly to classes created with be treated by type checkers similarly to classes created with
:func:`@dataclasses.dataclass <dataclasses.dataclass>`. :deco:`dataclasses.dataclass`.
For example, type checkers will assume these classes have For example, type checkers will assume these classes have
``__init__`` methods that accept ``id`` and ``name``. ``__init__`` methods that accept ``id`` and ``name``.
The decorated class, metaclass, or function may accept the following bool The decorated class, metaclass, or function may accept the following bool
arguments which type checkers will assume have the same effect as they arguments which type checkers will assume have the same effect as they
would have on the would have on the
:func:`@dataclasses.dataclass<dataclasses.dataclass>` decorator: ``init``, :deco:`dataclasses.dataclass` decorator: ``init``,
``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``, ``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``,
``kw_only``, and ``slots``. It must be possible for the value of these ``kw_only``, and ``slots``. It must be possible for the value of these
arguments (``True`` or ``False``) to be statically evaluated. arguments (``True`` or ``False``) to be statically evaluated.
@ -3169,12 +3169,12 @@ Functions and decorators
.. function:: get_overloads(func) .. function:: get_overloads(func)
Return a sequence of :func:`@overload <overload>`-decorated definitions for Return a sequence of :deco:`overload`-decorated definitions for
*func*. *func*.
*func* is the function object for the implementation of the *func* is the function object for the implementation of the
overloaded function. For example, given the definition of ``process`` in overloaded function. For example, given the definition of ``process`` in
the documentation for :func:`@overload <overload>`, the documentation for :deco:`overload`,
``get_overloads(process)`` will return a sequence of three function objects ``get_overloads(process)`` will return a sequence of three function objects
for the three defined overloads. If called on a function with no overloads, for the three defined overloads. If called on a function with no overloads,
``get_overloads()`` returns an empty sequence. ``get_overloads()`` returns an empty sequence.
@ -3331,7 +3331,7 @@ Introspection helpers
If *globalns* or *localns* is not given, appropriate namespace If *globalns* or *localns* is not given, appropriate namespace
dictionaries are inferred from *obj*. dictionaries are inferred from *obj*.
* ``None`` is replaced with :class:`types.NoneType`. * ``None`` is replaced with :class:`types.NoneType`.
* If :func:`@no_type_check <no_type_check>` has been applied to *obj*, an * If :deco:`no_type_check` has been applied to *obj*, an
empty dictionary is returned. empty dictionary is returned.
* If *obj* is a class ``C``, the function returns a dictionary that merges * If *obj* is a class ``C``, the function returns a dictionary that merges
annotations from ``C``'s base classes with those on ``C`` directly. This annotations from ``C``'s base classes with those on ``C`` directly. This

View file

@ -590,7 +590,7 @@ Available Functions
The deprecation message passed to the decorator is saved in the The deprecation message passed to the decorator is saved in the
``__deprecated__`` attribute on the decorated object. ``__deprecated__`` attribute on the decorated object.
If applied to an overload, the decorator If applied to an overload, the decorator
must be after the :func:`@overload <typing.overload>` decorator must be after the :deco:`~typing.overload` decorator
for the attribute to exist on the overload as returned by for the attribute to exist on the overload as returned by
:func:`typing.get_overloads`. :func:`typing.get_overloads`.

View file

@ -16,7 +16,7 @@ earlier than 1.1.3; 1.1.3 has a `security vulnerability <https://zlib.net/zlib_f
zlib's functions have many options and often need to be used in a particular zlib's functions have many options and often need to be used in a particular
order. This documentation doesn't attempt to cover all of the permutations; order. This documentation doesn't attempt to cover all of the permutations;
consult the zlib manual at http://www.zlib.net/manual.html for authoritative consult the `zlib manual <https://www.zlib.net/manual.html>`_ for authoritative
information. information.
For reading and writing ``.gz`` files see the :mod:`gzip` module. For reading and writing ``.gz`` files see the :mod:`gzip` module.
@ -340,6 +340,136 @@ Decompression objects support the following methods and attributes:
objects. objects.
The following constants are available to configure compression and decompression
behavior:
.. data:: DEFLATED
The deflate compression method.
.. data:: MAX_WBITS
The maximum window size, expressed as a power of 2.
For example, if :const:`!MAX_WBITS` is ``15`` it results in a window size
of ``32 KiB``.
.. data:: DEF_MEM_LEVEL
The default memory level for compression objects.
.. data:: DEF_BUF_SIZE
The default buffer size for decompression operations.
.. data:: Z_NO_COMPRESSION
Compression level ``0``.
.. versionadded:: 3.6
.. data:: Z_BEST_SPEED
Compression level ``1``.
.. data:: Z_BEST_COMPRESSION
Compression level ``9``.
.. data:: Z_DEFAULT_COMPRESSION
Default compression level (``-1``).
.. data:: Z_DEFAULT_STRATEGY
Default compression strategy, for normal data.
.. data:: Z_FILTERED
Compression strategy for data produced by a filter (or predictor).
.. data:: Z_HUFFMAN_ONLY
Compression strategy that forces Huffman coding only.
.. data:: Z_RLE
Compression strategy that limits match distances to one (run-length encoding).
This constant is only available if Python was compiled with zlib
1.2.0.1 or greater.
.. versionadded:: 3.6
.. data:: Z_FIXED
Compression strategy that prevents the use of dynamic Huffman codes.
This constant is only available if Python was compiled with zlib
1.2.2.2 or greater.
.. versionadded:: 3.6
.. data:: Z_NO_FLUSH
Flush mode ``0``. No special flushing behavior.
.. versionadded:: 3.6
.. data:: Z_PARTIAL_FLUSH
Flush mode ``1``. Flush as much output as possible.
.. data:: Z_SYNC_FLUSH
Flush mode ``2``. All output is flushed and the output is aligned to a byte boundary.
.. data:: Z_FULL_FLUSH
Flush mode ``3``. All output is flushed and the compression state is reset.
.. data:: Z_FINISH
Flush mode ``4``. All pending input is processed, no more input is expected.
.. data:: Z_BLOCK
Flush mode ``5``. A deflate block is completed and emitted.
This constant is only available if Python was compiled with zlib
1.2.2.2 or greater.
.. versionadded:: 3.6
.. data:: Z_TREES
Flush mode ``6``, for inflate operations. Instructs inflate to return when
it gets to the next deflate block boundary.
This constant is only available if Python was compiled with zlib
1.2.3.4 or greater.
.. versionadded:: 3.6
Information about the version of the zlib library in use is available through Information about the version of the zlib library in use is available through
the following constants: the following constants:
@ -375,10 +505,10 @@ the following constants:
Module :mod:`gzip` Module :mod:`gzip`
Reading and writing :program:`gzip`\ -format files. Reading and writing :program:`gzip`\ -format files.
http://www.zlib.net https://www.zlib.net
The zlib library home page. The zlib library home page.
http://www.zlib.net/manual.html https://www.zlib.net/manual.html
The zlib manual explains the semantics and usage of the library's many The zlib manual explains the semantics and usage of the library's many
functions. functions.

View file

@ -2558,7 +2558,7 @@ instance dictionary. In contrast, non-data descriptors can be overridden by
instances. instances.
Python methods (including those decorated with Python methods (including those decorated with
:func:`@staticmethod <staticmethod>` and :func:`@classmethod <classmethod>`) are :deco:`staticmethod` and :deco:`classmethod`) are
implemented as non-data descriptors. Accordingly, instances can redefine and implemented as non-data descriptors. Accordingly, instances can redefine and
override methods. This allows individual instances to acquire behaviors that override methods. This allows individual instances to acquire behaviors that
differ from other instances of the same class. differ from other instances of the same class.
@ -2993,7 +2993,7 @@ class method ``__class_getitem__()``.
When defined on a class, ``__class_getitem__()`` is automatically a class When defined on a class, ``__class_getitem__()`` is automatically a class
method. As such, there is no need for it to be decorated with method. As such, there is no need for it to be decorated with
:func:`@classmethod<classmethod>` when it is defined. :deco:`classmethod` when it is defined.
The purpose of *__class_getitem__* The purpose of *__class_getitem__*

View file

@ -10,12 +10,76 @@ Lexical analysis
A Python program is read by a *parser*. Input to the parser is a stream of A Python program is read by a *parser*. Input to the parser is a stream of
:term:`tokens <token>`, generated by the *lexical analyzer* (also known as :term:`tokens <token>`, generated by the *lexical analyzer* (also known as
the *tokenizer*). the *tokenizer*).
This chapter describes how the lexical analyzer breaks a file into tokens. This chapter describes how the lexical analyzer produces these tokens.
Python reads program text as Unicode code points; the encoding of a source file The lexical analyzer determines the program text's :ref:`encoding <encodings>`
can be given by an encoding declaration and defaults to UTF-8, see :pep:`3120` (UTF-8 by default), and decodes the text into
for details. If the source file cannot be decoded, a :exc:`SyntaxError` is :ref:`source characters <lexical-source-character>`.
raised. If the text cannot be decoded, a :exc:`SyntaxError` is raised.
Next, the lexical analyzer uses the source characters to generate a stream of tokens.
The type of a generated token generally depends on the next source character to
be processed. Similarly, other special behavior of the analyzer depends on
the first source character that hasn't yet been processed.
The following table gives a quick summary of these source characters,
with links to sections that contain more information.
.. list-table::
:header-rows: 1
* - Character
- Next token (or other relevant documentation)
* - * space
* tab
* formfeed
- * :ref:`Whitespace <whitespace>`
* - * CR, LF
- * :ref:`New line <line-structure>`
* :ref:`Indentation <indentation>`
* - * backslash (``\``)
- * :ref:`Explicit line joining <explicit-joining>`
* (Also significant in :ref:`string escape sequences <escape-sequences>`)
* - * hash (``#``)
- * :ref:`Comment <comments>`
* - * quote (``'``, ``"``)
- * :ref:`String literal <strings>`
* - * ASCII letter (``a``-``z``, ``A``-``Z``)
* non-ASCII character
- * :ref:`Name <identifiers>`
* Prefixed :ref:`string or bytes literal <strings>`
* - * underscore (``_``)
- * :ref:`Name <identifiers>`
* (Can also be part of :ref:`numeric literals <numbers>`)
* - * number (``0``-``9``)
- * :ref:`Numeric literal <numbers>`
* - * dot (``.``)
- * :ref:`Numeric literal <numbers>`
* :ref:`Operator <operators>`
* - * question mark (``?``)
* dollar (``$``)
*
.. (the following uses zero-width space characters to render
.. a literal backquote)
backquote (`````)
* control character
- * Error (outside string literals and comments)
* - * other printing character
- * :ref:`Operator or delimiter <operators>`
* - * end of file
- * :ref:`End marker <endmarker-token>`
.. _line-structure: .. _line-structure:
@ -120,6 +184,8 @@ If an encoding is declared, the encoding name must be recognized by Python
encoding is used for all lexical analysis, including string literals, comments encoding is used for all lexical analysis, including string literals, comments
and identifiers. and identifiers.
.. _lexical-source-character:
All lexical analysis, including string literals, comments All lexical analysis, including string literals, comments
and identifiers, works on Unicode text decoded using the source encoding. and identifiers, works on Unicode text decoded using the source encoding.
Any Unicode code point, except the NUL control character, can appear in Any Unicode code point, except the NUL control character, can appear in

View file

@ -4,7 +4,6 @@
Doc/c-api/descriptor.rst Doc/c-api/descriptor.rst
Doc/c-api/float.rst Doc/c-api/float.rst
Doc/c-api/init.rst
Doc/c-api/init_config.rst Doc/c-api/init_config.rst
Doc/c-api/intro.rst Doc/c-api/intro.rst
Doc/c-api/module.rst Doc/c-api/module.rst
@ -30,12 +29,10 @@ Doc/library/profile.rst
Doc/library/pyexpat.rst Doc/library/pyexpat.rst
Doc/library/resource.rst Doc/library/resource.rst
Doc/library/select.rst Doc/library/select.rst
Doc/library/signal.rst
Doc/library/smtplib.rst Doc/library/smtplib.rst
Doc/library/socket.rst Doc/library/socket.rst
Doc/library/ssl.rst Doc/library/ssl.rst
Doc/library/stdtypes.rst Doc/library/stdtypes.rst
Doc/library/subprocess.rst
Doc/library/termios.rst Doc/library/termios.rst
Doc/library/test.rst Doc/library/test.rst
Doc/library/tkinter.rst Doc/library/tkinter.rst
@ -53,7 +50,6 @@ Doc/library/xml.sax.reader.rst
Doc/library/xml.sax.rst Doc/library/xml.sax.rst
Doc/library/xmlrpc.client.rst Doc/library/xmlrpc.client.rst
Doc/library/xmlrpc.server.rst Doc/library/xmlrpc.server.rst
Doc/library/zlib.rst
Doc/whatsnew/2.4.rst Doc/whatsnew/2.4.rst
Doc/whatsnew/2.5.rst Doc/whatsnew/2.5.rst
Doc/whatsnew/2.6.rst Doc/whatsnew/2.6.rst

View file

@ -42,22 +42,22 @@ <h1>{% trans %}Download Python {{ dl_version }} documentation{% endtrans %}</h1>
</tr> </tr>
<tr> <tr>
<td>{% trans %}HTML{% endtrans %}</td> <td>{% trans %}HTML{% endtrans %}</td>
<td>{% trans download_size="13" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-html.zip">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-html.zip">Download</a>{% endtrans %}</td>
<td>{% trans download_size="8" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-html.tar.bz2">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-html.tar.bz2">Download</a>{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td>{% trans %}Plain text{% endtrans %}</td> <td>{% trans %}Plain text{% endtrans %}</td>
<td>{% trans download_size="4" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-text.zip">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-text.zip">Download</a>{% endtrans %}</td>
<td>{% trans download_size="3" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-text.tar.bz2">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-text.tar.bz2">Download</a>{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td>{% trans %}Texinfo{% endtrans %}</td> <td>{% trans %}Texinfo{% endtrans %}</td>
<td>{% trans download_size="9" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-texinfo.zip">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-texinfo.zip">Download</a>{% endtrans %}</td>
<td>{% trans download_size="7" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-texinfo.tar.bz2">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-texinfo.tar.bz2">Download</a>{% endtrans %}</td>
</tr> </tr>
<tr> <tr>
<td>{% trans %}EPUB{% endtrans %}</td> <td>{% trans %}EPUB{% endtrans %}</td>
<td>{% trans download_size="6" %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs.epub">Download</a> (ca. {{ download_size }} MiB){% endtrans %}</td> <td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs.epub">Download</a>{% endtrans %}</td>
<td></td> <td></td>
</tr> </tr>
</table> </table>
@ -71,21 +71,13 @@ <h1>{% trans %}Download Python {{ dl_version }} documentation{% endtrans %}</h1>
and run <code>make dist-pdf</code> in the <code>Doc/</code> directory of a copy of the CPython repository. and run <code>make dist-pdf</code> in the <code>Doc/</code> directory of a copy of the CPython repository.
{% endtrans %}</p> {% endtrans %}</p>
<p>{% trans %}
<h2>{% trans %}Unpacking{% endtrans %}</h2> See the <a href="https://docs.python.org/{{ version }}/archives/">directory listing</a>
for file sizes.{% endtrans %}</p>
<p>{% trans %}Unix users should download the .tar.bz2 archives; these are bzipped tar
archives and can be handled in the usual way using tar and the bzip2
program. The <a href="https://infozip.sourceforge.net">Info-ZIP</a> unzip program can be
used to handle the ZIP archives if desired. The .tar.bz2 archives provide the
best compression and fastest download times.{% endtrans %}</p>
<p>{% trans %}Windows users can use the ZIP archives since those are customary on that
platform. These are created on Unix using the Info-ZIP zip program.{% endtrans %}</p>
<h2>{% trans %}Problems{% endtrans %}</h2> <h2>{% trans %}Problems{% endtrans %}</h2>
{% set bugs = pathto('bugs') %}
<p>{% trans %}If you have comments or suggestions for the Python documentation, please send <p>{% trans bugs = bugs %}<a href="{{ bugs }}">Open an issue</a>
email to <a href="mailto:docs@python.org">docs@python.org</a>.{% endtrans %}</p> if you have comments or suggestions for the Python documentation.{% endtrans %}</p>
{% endblock %} {% endblock %}

View file

@ -512,8 +512,12 @@ dictionary; this is also the way dictionaries are written on output.
The main operations on a dictionary are storing a value with some key and The main operations on a dictionary are storing a value with some key and
extracting the value given the key. It is also possible to delete a key:value extracting the value given the key. It is also possible to delete a key:value
pair with ``del``. If you store using a key that is already in use, the old pair with ``del``. If you store using a key that is already in use, the old
value associated with that key is forgotten. It is an error to extract a value value associated with that key is forgotten.
using a non-existent key.
Extracting a value for a non-existent key by subscripting (``d[key]``) raises a
:exc:`KeyError`. To avoid getting this error when trying to access a possibly
non-existent key, use the :meth:`~dict.get` method instead, which returns
``None`` (or a specified default value) if the key is not in the dictionary.
Performing ``list(d)`` on a dictionary returns a list of all the keys Performing ``list(d)`` on a dictionary returns a list of all the keys
used in the dictionary, in insertion order (if you want it sorted, just use used in the dictionary, in insertion order (if you want it sorted, just use
@ -528,6 +532,12 @@ Here is a small example using a dictionary::
{'jack': 4098, 'sape': 4139, 'guido': 4127} {'jack': 4098, 'sape': 4139, 'guido': 4127}
>>> tel['jack'] >>> tel['jack']
4098 4098
>>> tel['irv']
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'irv'
>>> print(tel.get('irv'))
None
>>> del tel['sape'] >>> del tel['sape']
>>> tel['irv'] = 4127 >>> tel['irv'] = 4127
>>> tel >>> tel

View file

@ -22,16 +22,51 @@ Features and minimum versions required to build CPython:
* Support for threads. * Support for threads.
* OpenSSL 1.1.1 is the minimum version and OpenSSL 3.0.16 is the recommended To build optional modules:
minimum version for the :mod:`ssl` and :mod:`hashlib` extension modules.
* SQLite 3.15.2 for the :mod:`sqlite3` extension module. * `libbz2 <https://sourceware.org/bzip2/>`_ for the :mod:`bz2` module.
* Tcl/Tk 8.5.12 for the :mod:`tkinter` module. * `libb2 <https://github.com/BLAKE2/libb2>`_ (:ref:`BLAKE2 <hashlib-blake2>`),
used by :mod:`hashlib` module.
* `libffi <https://sourceware.org/libffi/>`_ 3.3.0 is the recommended
minimum version for the :mod:`ctypes` module.
* ``liblzma``, for the :mod:`lzma` module.
* `libmpdec <https://www.bytereef.org/mpdecimal/doc/libmpdec/>`_ 2.5.0 * `libmpdec <https://www.bytereef.org/mpdecimal/doc/libmpdec/>`_ 2.5.0
for the :mod:`decimal` module. for the :mod:`decimal` module.
* ``libncurses`` or ``libncursesw``,
for the :mod:`curses` module.
* ``libpanel`` or ``libpanelw``,
for the :mod:`curses.panel` module.
* `libreadline <https://tiswww.case.edu/php/chet/readline/rltop.html>`_ or
`libedit <https://www.thrysoee.dk/editline/>`_
for the :mod:`readline` module.
* `libuuid <https://linux.die.net/man/3/libuuid>`_, for the :mod:`uuid` module.
* `OpenSSL <https://www.openssl.org/>`_ 1.1.1 is the minimum version and
OpenSSL 3.0.18 is the recommended minimum version for the
:mod:`ssl` and :mod:`hashlib` extension modules.
* `SQLite <https://sqlite.org/>`_ 3.15.2 for the :mod:`sqlite3` extension module.
* `Tcl/Tk <https://www.tcl-lang.org/>`_ 8.5.12 for the :mod:`tkinter` module.
* `zlib <https://www.zlib.net>`_ 1.1.4 is the reccomended minimum version for the
:mod:`zlib` module.
* `zstd <https://facebook.github.io/zstd/>`_ 1.4.5 is the minimum version for
the :mod:`compression.zstd` module.
For a full list of dependencies required to build all modules and how to install
them, see the
`devguide <https://devguide.python.org/getting-started/setup-building/#install-dependencies>`_.
* Autoconf 2.72 and aclocal 1.16.5 are required to regenerate the * Autoconf 2.72 and aclocal 1.16.5 are required to regenerate the
:file:`configure` script. :file:`configure` script.

View file

@ -56,7 +56,7 @@ Python 2.6 incorporates new features and syntax from 3.0 while
remaining compatible with existing code by not removing older features remaining compatible with existing code by not removing older features
or syntax. When it's not possible to do that, Python 2.6 tries to do or syntax. When it's not possible to do that, Python 2.6 tries to do
what it can, adding compatibility functions in a what it can, adding compatibility functions in a
:mod:`future_builtins` module and a :option:`!-3` switch to warn about :mod:`!future_builtins` module and a :option:`!-3` switch to warn about
usages that will become unsupported in 3.0. usages that will become unsupported in 3.0.
Some significant new packages have been added to the standard library, Some significant new packages have been added to the standard library,
@ -109,7 +109,7 @@ are:
Python 3.0 adds several new built-in functions and changes the Python 3.0 adds several new built-in functions and changes the
semantics of some existing builtins. Functions that are new in 3.0 semantics of some existing builtins. Functions that are new in 3.0
such as :func:`bin` have simply been added to Python 2.6, but existing such as :func:`bin` have simply been added to Python 2.6, but existing
builtins haven't been changed; instead, the :mod:`future_builtins` builtins haven't been changed; instead, the :mod:`!future_builtins`
module has versions with the new 3.0 semantics. Code written to be module has versions with the new 3.0 semantics. Code written to be
compatible with 3.0 can do ``from future_builtins import hex, map`` as compatible with 3.0 can do ``from future_builtins import hex, map`` as
necessary. necessary.
@ -118,7 +118,7 @@ A new command-line switch, :option:`!-3`, enables warnings
about features that will be removed in Python 3.0. You can run code about features that will be removed in Python 3.0. You can run code
with this switch to see how much work will be necessary to port with this switch to see how much work will be necessary to port
code to 3.0. The value of this switch is available code to 3.0. The value of this switch is available
to Python code as the boolean variable :data:`sys.py3kwarning`, to Python code as the boolean variable :data:`!sys.py3kwarning`,
and to C extension code as :c:data:`!Py_Py3kWarningFlag`. and to C extension code as :c:data:`!Py_Py3kWarningFlag`.
.. seealso:: .. seealso::
@ -307,9 +307,9 @@ The :mod:`threading` module's locks and condition variables also support the
The lock is acquired before the block is executed and always released once the The lock is acquired before the block is executed and always released once the
block is complete. block is complete.
The :func:`localcontext` function in the :mod:`decimal` module makes it easy The :func:`~decimal.localcontext` function in the :mod:`decimal` module makes
to save and restore the current decimal context, which encapsulates the desired it easy to save and restore the current decimal context, which encapsulates
precision and rounding characteristics for computations:: the desired precision and rounding characteristics for computations::
from decimal import Decimal, Context, localcontext from decimal import Decimal, Context, localcontext
@ -337,12 +337,12 @@ underlying implementation and should keep reading.
A high-level explanation of the context management protocol is: A high-level explanation of the context management protocol is:
* The expression is evaluated and should result in an object called a "context * The expression is evaluated and should result in an object called a "context
manager". The context manager must have :meth:`~object.__enter__` and :meth:`~object.__exit__` manager". The context manager must have :meth:`~object.__enter__` and
methods. :meth:`~object.__exit__` methods.
* The context manager's :meth:`~object.__enter__` method is called. The value returned * The context manager's :meth:`~object.__enter__` method is called. The value
is assigned to *VAR*. If no ``as VAR`` clause is present, the value is simply returned is assigned to *VAR*. If no ``as VAR`` clause is present, the
discarded. value is simply discarded.
* The code in *BLOCK* is executed. * The code in *BLOCK* is executed.
@ -378,7 +378,7 @@ be to let the user write code like this::
The transaction should be committed if the code in the block runs flawlessly or The transaction should be committed if the code in the block runs flawlessly or
rolled back if there's an exception. Here's the basic interface for rolled back if there's an exception. Here's the basic interface for
:class:`DatabaseConnection` that I'll assume:: :class:`!DatabaseConnection` that I'll assume::
class DatabaseConnection: class DatabaseConnection:
# Database interface # Database interface
@ -431,14 +431,15 @@ The contextlib module
The :mod:`contextlib` module provides some functions and a decorator that The :mod:`contextlib` module provides some functions and a decorator that
are useful when writing objects for use with the ':keyword:`with`' statement. are useful when writing objects for use with the ':keyword:`with`' statement.
The decorator is called :func:`contextmanager`, and lets you write a single The decorator is called :func:`~contextlib.contextmanager`, and lets you write
generator function instead of defining a new class. The generator should yield a single generator function instead of defining a new class. The generator
exactly one value. The code up to the :keyword:`yield` will be executed as the should yield exactly one value. The code up to the :keyword:`yield` will be
:meth:`~object.__enter__` method, and the value yielded will be the method's return executed as the :meth:`~object.__enter__` method, and the value yielded will
value that will get bound to the variable in the ':keyword:`with`' statement's be the method's return value that will get bound to the variable in the
:keyword:`!as` clause, if any. The code after the :keyword:`!yield` will be ':keyword:`with`' statement's :keyword:`!as` clause, if any. The code after
executed in the :meth:`~object.__exit__` method. Any exception raised in the block will the :keyword:`!yield` will be executed in the :meth:`~object.__exit__` method.
be raised by the :keyword:`!yield` statement. Any exception raised in the block will be raised by the :keyword:`!yield`
statement.
Using this decorator, our database example from the previous section Using this decorator, our database example from the previous section
could be written as:: could be written as::
@ -469,7 +470,7 @@ statement both starts a database transaction and acquires a thread lock::
with nested (db_transaction(db), lock) as (cursor, locked): with nested (db_transaction(db), lock) as (cursor, locked):
... ...
Finally, the :func:`closing` function returns its argument so that it can be Finally, the :func:`~contextlib.closing` function returns its argument so that it can be
bound to a variable, and calls the argument's ``.close()`` method at the end bound to a variable, and calls the argument's ``.close()`` method at the end
of the block. :: of the block. ::
@ -538,7 +539,7 @@ If you don't like the default directory, it can be overridden by an
environment variable. :envvar:`PYTHONUSERBASE` sets the root environment variable. :envvar:`PYTHONUSERBASE` sets the root
directory used for all Python versions supporting this feature. On directory used for all Python versions supporting this feature. On
Windows, the directory for application-specific data can be changed by Windows, the directory for application-specific data can be changed by
setting the :envvar:`APPDATA` environment variable. You can also setting the :envvar:`!APPDATA` environment variable. You can also
modify the :file:`site.py` file for your Python installation. modify the :file:`site.py` file for your Python installation.
The feature can be disabled entirely by running Python with the The feature can be disabled entirely by running Python with the
@ -568,11 +569,12 @@ The :mod:`multiprocessing` module started out as an exact emulation of
the :mod:`threading` module using processes instead of threads. That the :mod:`threading` module using processes instead of threads. That
goal was discarded along the path to Python 2.6, but the general goal was discarded along the path to Python 2.6, but the general
approach of the module is still similar. The fundamental class approach of the module is still similar. The fundamental class
is the :class:`Process`, which is passed a callable object and is the :class:`~multiprocessing.Process`, which is passed a callable object and
a collection of arguments. The :meth:`start` method a collection of arguments. The :meth:`~multiprocessing.Process.start` method
sets the callable running in a subprocess, after which you can call sets the callable running in a subprocess, after which you can call
the :meth:`is_alive` method to check whether the subprocess is still running the :meth:`~multiprocessing.Process.is_alive` method to check whether the
and the :meth:`join` method to wait for the process to exit. subprocess is still running and the :meth:`~multiprocessing.Process.join`
method to wait for the process to exit.
Here's a simple example where the subprocess will calculate a Here's a simple example where the subprocess will calculate a
factorial. The function doing the calculation is written strangely so factorial. The function doing the calculation is written strangely so
@ -619,13 +621,16 @@ the object to communicate. (If the parent were to change the value of
the global variable, the child's value would be unaffected, and vice the global variable, the child's value would be unaffected, and vice
versa.) versa.)
Two other classes, :class:`Pool` and :class:`Manager`, provide Two other classes, :class:`~multiprocessing.pool.Pool` and
higher-level interfaces. :class:`Pool` will create a fixed number of :class:`~multiprocessing.Manager`, provide higher-level interfaces.
worker processes, and requests can then be distributed to the workers :class:`~multiprocessing.pool.Pool` will create a fixed number of worker
by calling :meth:`apply` or :meth:`apply_async` to add a single request, processes, and requests can then be distributed to the workers by calling
and :meth:`map` or :meth:`map_async` to add a number of :meth:`~multiprocessing.pool.Pool.apply` or
requests. The following code uses a :class:`Pool` to spread requests :meth:`~multiprocessing.pool.Pool.apply_async` to add a single request, and
across 5 worker processes and retrieve a list of results:: :meth:`~multiprocessing.pool.Pool.map` or
:meth:`~multiprocessing.pool.Pool.map_async` to add a number of
requests. The following code uses a :class:`~multiprocessing.pool.Pool` to
spread requests across 5 worker processes and retrieve a list of results::
from multiprocessing import Pool from multiprocessing import Pool
@ -646,15 +651,18 @@ This produces the following output::
33452526613163807108170062053440751665152000000000 33452526613163807108170062053440751665152000000000
... ...
The other high-level interface, the :class:`Manager` class, creates a The other high-level interface, the :class:`~multiprocessing.Manager` class,
separate server process that can hold master copies of Python data creates a separate server process that can hold master copies of Python data
structures. Other processes can then access and modify these data structures. Other processes can then access and modify these data
structures using proxy objects. The following example creates a structures using proxy objects. The following example creates a
shared dictionary by calling the :meth:`dict` method; the worker shared dictionary by calling the :meth:`dict` method; the worker
processes then insert values into the dictionary. (Locking is not processes then insert values into the dictionary. (Locking is not
done for you automatically, which doesn't matter in this example. done for you automatically, which doesn't matter in this example.
:class:`Manager`'s methods also include :meth:`Lock`, :meth:`RLock`, :class:`~multiprocessing.Manager`'s methods also include
and :meth:`Semaphore` to create shared locks.) :meth:`~multiprocessing.managers.SyncManager.Lock`,
:meth:`~multiprocessing.managers.SyncManager.RLock`,
and :meth:`~multiprocessing.managers.SyncManager.Semaphore` to create
shared locks.)
:: ::
@ -824,7 +832,7 @@ documentation for a :ref:`complete list <formatstrings>`; here's a sample:
format, followed by a percent sign. format, followed by a percent sign.
===== ======================================================================== ===== ========================================================================
Classes and types can define a :meth:`__format__` method to control how they're Classes and types can define a :meth:`~object.__format__` method to control how they're
formatted. It receives a single argument, the format specifier:: formatted. It receives a single argument, the format specifier::
def __format__(self, format_spec): def __format__(self, format_spec):
@ -834,7 +842,7 @@ formatted. It receives a single argument, the format specifier::
return str(self) return str(self)
There's also a :func:`format` builtin that will format a single There's also a :func:`format` builtin that will format a single
value. It calls the type's :meth:`__format__` method with the value. It calls the type's :meth:`~object.__format__` method with the
provided specifier:: provided specifier::
>>> format(75.6564, '.2f') >>> format(75.6564, '.2f')
@ -1029,56 +1037,58 @@ PEP 3116: New I/O Library
Python's built-in file objects support a number of methods, but Python's built-in file objects support a number of methods, but
file-like objects don't necessarily support all of them. Objects that file-like objects don't necessarily support all of them. Objects that
imitate files usually support :meth:`read` and :meth:`write`, but they imitate files usually support :meth:`!read` and
may not support :meth:`readline`, for example. Python 3.0 introduces :meth:`!write`, but they may not support :meth:`!readline`,
a layered I/O library in the :mod:`io` module that separates buffering for example. Python 3.0 introduces a layered I/O library in the :mod:`io`
and text-handling features from the fundamental read and write module that separates buffering and text-handling features from the
operations. fundamental read and write operations.
There are three levels of abstract base classes provided by There are three levels of abstract base classes provided by
the :mod:`io` module: the :mod:`io` module:
* :class:`RawIOBase` defines raw I/O operations: :meth:`read`, * :class:`~io.RawIOBase` defines raw I/O operations: :meth:`~io.RawIOBase.read`,
:meth:`readinto`, :meth:`~io.RawIOBase.readinto`, :meth:`~io.RawIOBase.write`,
:meth:`write`, :meth:`seek`, :meth:`tell`, :meth:`truncate`, :meth:`~io.IOBase.seek`, :meth:`~io.IOBase.tell`, :meth:`~io.IOBase.truncate`,
and :meth:`close`. and :meth:`~io.IOBase.close`.
Most of the methods of this class will often map to a single system call. Most of the methods of this class will often map to a single system call.
There are also :meth:`readable`, :meth:`writable`, and :meth:`seekable` There are also :meth:`~io.IOBase.readable`, :meth:`~io.IOBase.writable`,
methods for determining what operations a given object will allow. and :meth:`~io.IOBase.seekable` methods for determining what operations a
given object will allow.
Python 3.0 has concrete implementations of this class for files and Python 3.0 has concrete implementations of this class for files and
sockets, but Python 2.6 hasn't restructured its file and socket objects sockets, but Python 2.6 hasn't restructured its file and socket objects
in this way. in this way.
* :class:`BufferedIOBase` is an abstract base class that * :class:`~io.BufferedIOBase` is an abstract base class that
buffers data in memory to reduce the number of buffers data in memory to reduce the number of
system calls used, making I/O processing more efficient. system calls used, making I/O processing more efficient.
It supports all of the methods of :class:`RawIOBase`, It supports all of the methods of :class:`~io.RawIOBase`,
and adds a :attr:`raw` attribute holding the underlying raw object. and adds a :attr:`~io.BufferedIOBase.raw` attribute holding the underlying
raw object.
There are five concrete classes implementing this ABC. There are five concrete classes implementing this ABC.
:class:`BufferedWriter` and :class:`BufferedReader` are for objects :class:`~io.BufferedWriter` and :class:`~io.BufferedReader` are for objects
that support write-only or read-only usage that have a :meth:`seek` that support write-only or read-only usage that have a :meth:`~io.IOBase.seek`
method for random access. :class:`BufferedRandom` objects support method for random access. :class:`~io.BufferedRandom` objects support
read and write access upon the same underlying stream, and read and write access upon the same underlying stream, and
:class:`BufferedRWPair` is for objects such as TTYs that have both :class:`~io.BufferedRWPair` is for objects such as TTYs that have both
read and write operations acting upon unconnected streams of data. read and write operations acting upon unconnected streams of data.
The :class:`BytesIO` class supports reading, writing, and seeking The :class:`~io.BytesIO` class supports reading, writing, and seeking
over an in-memory buffer. over an in-memory buffer.
.. index:: .. index::
single: universal newlines; What's new single: universal newlines; What's new
* :class:`TextIOBase`: Provides functions for reading and writing * :class:`~io.TextIOBase`: Provides functions for reading and writing
strings (remember, strings will be Unicode in Python 3.0), strings (remember, strings will be Unicode in Python 3.0),
and supporting :term:`universal newlines`. :class:`TextIOBase` defines and supporting :term:`universal newlines`. :class:`~io.TextIOBase` defines
the :meth:`readline` method and supports iteration upon the :meth:`readline` method and supports iteration upon
objects. objects.
There are two concrete implementations. :class:`TextIOWrapper` There are two concrete implementations. :class:`~io.TextIOWrapper`
wraps a buffered I/O object, supporting all of the methods for wraps a buffered I/O object, supporting all of the methods for
text I/O and adding a :attr:`buffer` attribute for access text I/O and adding a :attr:`~io.TextIOBase.buffer` attribute for access
to the underlying object. :class:`StringIO` simply buffers to the underlying object. :class:`~io.StringIO` simply buffers
everything in memory without ever writing anything to disk. everything in memory without ever writing anything to disk.
(In Python 2.6, :class:`io.StringIO` is implemented in (In Python 2.6, :class:`io.StringIO` is implemented in
@ -1162,7 +1172,7 @@ Some object-oriented languages such as Java support interfaces,
declaring that a class has a given set of methods or supports a given declaring that a class has a given set of methods or supports a given
access protocol. Abstract Base Classes (or ABCs) are an equivalent access protocol. Abstract Base Classes (or ABCs) are an equivalent
feature for Python. The ABC support consists of an :mod:`abc` module feature for Python. The ABC support consists of an :mod:`abc` module
containing a metaclass called :class:`ABCMeta`, special handling of containing a metaclass called :class:`~abc.ABCMeta`, special handling of
this metaclass by the :func:`isinstance` and :func:`issubclass` this metaclass by the :func:`isinstance` and :func:`issubclass`
builtins, and a collection of basic ABCs that the Python developers builtins, and a collection of basic ABCs that the Python developers
think will be widely useful. Future versions of Python will probably think will be widely useful. Future versions of Python will probably
@ -1172,17 +1182,17 @@ Let's say you have a particular class and wish to know whether it supports
dictionary-style access. The phrase "dictionary-style" is vague, however. dictionary-style access. The phrase "dictionary-style" is vague, however.
It probably means that accessing items with ``obj[1]`` works. It probably means that accessing items with ``obj[1]`` works.
Does it imply that setting items with ``obj[2] = value`` works? Does it imply that setting items with ``obj[2] = value`` works?
Or that the object will have :meth:`keys`, :meth:`values`, and :meth:`items` Or that the object will have :meth:`!keys`, :meth:`!values`, and :meth:`!items`
methods? What about the iterative variants such as :meth:`iterkeys`? :meth:`copy` methods? What about the iterative variants such as :meth:`!iterkeys`?
and :meth:`update`? Iterating over the object with :func:`iter`? :meth:`!copy`and :meth:`!update`? Iterating over the object with :func:`!iter`?
The Python 2.6 :mod:`collections` module includes a number of The Python 2.6 :mod:`collections` module includes a number of
different ABCs that represent these distinctions. :class:`Iterable` different ABCs that represent these distinctions. :class:`Iterable`
indicates that a class defines :meth:`__iter__`, and indicates that a class defines :meth:`~object.__iter__`, and
:class:`Container` means the class defines a :meth:`__contains__` :class:`Container` means the class defines a :meth:`~object.__contains__`
method and therefore supports ``x in y`` expressions. The basic method and therefore supports ``x in y`` expressions. The basic
dictionary interface of getting items, setting items, and dictionary interface of getting items, setting items, and
:meth:`keys`, :meth:`values`, and :meth:`items`, is defined by the :meth:`!keys`, :meth:`!values`, and :meth:`!items`, is defined by the
:class:`MutableMapping` ABC. :class:`MutableMapping` ABC.
You can derive your own classes from a particular ABC You can derive your own classes from a particular ABC
@ -1196,7 +1206,7 @@ to indicate they support that ABC's interface::
Alternatively, you could write the class without deriving from Alternatively, you could write the class without deriving from
the desired ABC and instead register the class by the desired ABC and instead register the class by
calling the ABC's :meth:`register` method:: calling the ABC's :meth:`~abc.ABCMeta.register` method::
import collections import collections
@ -1206,10 +1216,10 @@ calling the ABC's :meth:`register` method::
collections.MutableMapping.register(Storage) collections.MutableMapping.register(Storage)
For classes that you write, deriving from the ABC is probably clearer. For classes that you write, deriving from the ABC is probably clearer.
The :meth:`register` method is useful when you've written a new The :meth:`~abc.ABCMeta.register` method is useful when you've written a new
ABC that can describe an existing type or class, or if you want ABC that can describe an existing type or class, or if you want
to declare that some third-party class implements an ABC. to declare that some third-party class implements an ABC.
For example, if you defined a :class:`PrintableType` ABC, For example, if you defined a :class:`!PrintableType` ABC,
it's legal to do:: it's legal to do::
# Register Python's types # Register Python's types
@ -1256,16 +1266,16 @@ metaclass in a class definition::
... ...
In the :class:`Drawable` ABC above, the :meth:`draw_doubled` method In the :class:`!Drawable` ABC above, the :meth:`!draw_doubled` method
renders the object at twice its size and can be implemented in terms renders the object at twice its size and can be implemented in terms
of other methods described in :class:`Drawable`. Classes implementing of other methods described in :class:`!Drawable`. Classes implementing
this ABC therefore don't need to provide their own implementation this ABC therefore don't need to provide their own implementation
of :meth:`draw_doubled`, though they can do so. An implementation of :meth:`!draw_doubled`, though they can do so. An implementation
of :meth:`draw` is necessary, though; the ABC can't provide of :meth:`!draw` is necessary, though; the ABC can't provide
a useful generic implementation. a useful generic implementation.
You can apply the ``@abstractmethod`` decorator to methods such as You can apply the :deco:`~abc.abstractmethod` decorator to methods such as
:meth:`draw` that must be implemented; Python will then raise an :meth:`!draw` that must be implemented; Python will then raise an
exception for classes that don't define the method. exception for classes that don't define the method.
Note that the exception is only raised when you actually Note that the exception is only raised when you actually
try to create an instance of a subclass lacking the method:: try to create an instance of a subclass lacking the method::
@ -1289,7 +1299,7 @@ Abstract data attributes can be declared using the
def readonly(self): def readonly(self):
return self._x return self._x
Subclasses must then define a :meth:`readonly` property. Subclasses must then define a ``readonly`` property.
.. seealso:: .. seealso::
@ -2739,13 +2749,13 @@ numbers.
.. ====================================================================== .. ======================================================================
The :mod:`future_builtins` module The :mod:`!future_builtins` module
-------------------------------------- --------------------------------------
Python 3.0 makes many changes to the repertoire of built-in Python 3.0 makes many changes to the repertoire of built-in
functions, and most of the changes can't be introduced in the Python functions, and most of the changes can't be introduced in the Python
2.x series because they would break compatibility. 2.x series because they would break compatibility.
The :mod:`future_builtins` module provides versions The :mod:`!future_builtins` module provides versions
of these built-in functions that can be imported when writing of these built-in functions that can be imported when writing
3.0-compatible code. 3.0-compatible code.

View file

@ -858,8 +858,8 @@ Some smaller changes made to the core Python language are:
.. XXX bytearray doesn't seem to be documented .. XXX bytearray doesn't seem to be documented
* When using :class:`@classmethod <classmethod>` and * When using :deco:`classmethod` and
:class:`@staticmethod <staticmethod>` to wrap :deco:`staticmethod` to wrap
methods as class or static methods, the wrapper object now methods as class or static methods, the wrapper object now
exposes the wrapped function as their :attr:`~method.__func__` exposes the wrapped function as their :attr:`~method.__func__`
attribute. attribute.

View file

@ -847,8 +847,8 @@ Other Language Changes
respectively. respectively.
(Contributed by Joshua Bronson, Daniel Pope, and Justin Wang in :issue:`31861`.) (Contributed by Joshua Bronson, Daniel Pope, and Justin Wang in :issue:`31861`.)
* Static methods (:func:`@staticmethod <staticmethod>`) and class methods * Static methods (:deco:`staticmethod`) and class methods
(:func:`@classmethod <classmethod>`) now inherit the method attributes (:deco:`classmethod`) now inherit the method attributes
(``__module__``, ``__name__``, ``__qualname__``, ``__doc__``, (``__module__``, ``__name__``, ``__qualname__``, ``__doc__``,
``__annotations__``) and have a new ``__wrapped__`` attribute. ``__annotations__``) and have a new ``__wrapped__`` attribute.
Moreover, static methods are now callable as regular functions. Moreover, static methods are now callable as regular functions.

View file

@ -60,7 +60,7 @@ Summary -- Release Highlights
.. This section singles out the most important changes in Python 3.13. .. This section singles out the most important changes in Python 3.13.
Brevity is key. Brevity is key.
Python 3.13 is the latest stable release of the Python programming Python 3.13 is a stable release of the Python programming
language, with a mix of changes to the language, the implementation language, with a mix of changes to the language, the implementation
and the standard library. and the standard library.
The biggest changes include a new `interactive interpreter The biggest changes include a new `interactive interpreter
@ -1569,8 +1569,6 @@ and are now removed:
* :pypi:`bcrypt`: * :pypi:`bcrypt`:
Modern password hashing for your software and your servers. Modern password hashing for your software and your servers.
* :pypi:`passlib`:
Comprehensive password hashing framework supporting over 30 schemes.
* :pypi:`argon2-cffi`: * :pypi:`argon2-cffi`:
The secure Argon2 password hashing algorithm. The secure Argon2 password hashing algorithm.
* :pypi:`legacycrypt`: * :pypi:`legacycrypt`:

File diff suppressed because it is too large Load diff

View file

@ -852,6 +852,9 @@ New features
(Contributed by Victor Stinner in :gh:`129813`.) (Contributed by Victor Stinner in :gh:`129813`.)
* Add :c:func:`PyTuple_FromArray` to create a :class:`tuple` from an array.
(Contributed by Victor Stinner in :gh:`111489`.)
Porting to Python 3.15 Porting to Python 3.15
---------------------- ----------------------

View file

@ -78,7 +78,7 @@ __pragma(warning(disable: 4201))
#include "pybuffer.h" #include "pybuffer.h"
#include "pystats.h" #include "pystats.h"
#include "pyatomic.h" #include "pyatomic.h"
#include "pylock.h" #include "cpython/pylock.h"
#include "critical_section.h" #include "critical_section.h"
#include "object.h" #include "object.h"
#include "refcount.h" #include "refcount.h"
@ -105,7 +105,7 @@ __pragma(warning(disable: 4201))
#include "setobject.h" #include "setobject.h"
#include "methodobject.h" #include "methodobject.h"
#include "moduleobject.h" #include "moduleobject.h"
#include "monitoring.h" #include "cpython/monitoring.h"
#include "cpython/funcobject.h" #include "cpython/funcobject.h"
#include "cpython/classobject.h" #include "cpython/classobject.h"
#include "fileobject.h" #include "fileobject.h"

View file

@ -282,15 +282,6 @@ typedef struct _line_offsets {
*/ */
PyAPI_FUNC(int) _PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds); PyAPI_FUNC(int) _PyCode_CheckLineNumber(int lasti, PyCodeAddressRange *bounds);
/* Create a comparable key used to compare constants taking in account the
* object type. It is used to make sure types are not coerced (e.g., float and
* complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms
*
* Return (type(obj), obj, ...): a tuple with variable size (at least 2 items)
* depending on the type and the value. The type is the first item to not
* compare bytes and str which can raise a BytesWarning exception. */
PyAPI_FUNC(PyObject*) _PyCode_ConstantKey(PyObject *obj);
PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts, PyAPI_FUNC(PyObject*) PyCode_Optimize(PyObject *code, PyObject* consts,
PyObject *names, PyObject *lnotab); PyObject *names, PyObject *lnotab);

View file

@ -134,7 +134,8 @@ PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *);
V(DESTROY) \ V(DESTROY) \
V(MODIFY_CODE) \ V(MODIFY_CODE) \
V(MODIFY_DEFAULTS) \ V(MODIFY_DEFAULTS) \
V(MODIFY_KWDEFAULTS) V(MODIFY_KWDEFAULTS) \
V(MODIFY_QUALNAME)
typedef enum { typedef enum {
#define PY_DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT, #define PY_DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT,

17
Include/cpython/marshal.h Normal file
View file

@ -0,0 +1,17 @@
#ifndef _Py_CPYTHON_MARSHAL_H
# error "this header file must not be included directly"
#endif
PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *,
Py_ssize_t);
PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int);
#define Py_MARSHAL_VERSION 5
PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *);
PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *);
PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *);
PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *);
PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int);
PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);

View file

@ -1,7 +1,13 @@
#ifndef Py_CPYTHON_MONITORING_H #ifndef Py_MONITORING_H
# error "this header file must not be included directly" #define Py_MONITORING_H
#ifndef Py_LIMITED_API
#ifdef __cplusplus
extern "C" {
#endif #endif
// There is currently no limited API for monitoring
/* Local events. /* Local events.
* These require bytecode instrumentation */ * These require bytecode instrumentation */
@ -267,3 +273,9 @@ PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike
} }
#undef _PYMONITORING_IF_ACTIVE #undef _PYMONITORING_IF_ACTIVE
#ifdef __cplusplus
}
#endif
#endif // !Py_LIMITED_API
#endif // !Py_MONITORING_H

View file

@ -492,7 +492,3 @@ PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *);
PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *); PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(PyObject *);
PyAPI_FUNC(int) PyUnstable_Object_IsUniquelyReferenced(PyObject *); PyAPI_FUNC(int) PyUnstable_Object_IsUniquelyReferenced(PyObject *);
/* Utility for the tp_traverse slot of mutable heap types that have no other
* references. */
PyAPI_FUNC(int) _PyObject_VisitType(PyObject *op, visitproc visit, void *arg);

View file

@ -1,7 +1,11 @@
#ifndef Py_CPYTHON_LOCK_H #ifndef Py_LOCK_H
# error "this header file must not be included directly" #define Py_LOCK_H
#ifndef Py_LIMITED_API
#ifdef __cplusplus
extern "C" {
#endif #endif
#define _Py_UNLOCKED 0 #define _Py_UNLOCKED 0
#define _Py_LOCKED 1 #define _Py_LOCKED 1
@ -72,3 +76,10 @@ _PyMutex_IsLocked(PyMutex *m)
return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0; return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0;
} }
#define PyMutex_IsLocked _PyMutex_IsLocked #define PyMutex_IsLocked _PyMutex_IsLocked
#ifdef __cplusplus
}
#endif
#endif // !Py_LIMITED_API
#endif // !Py_LOCK_H

View file

@ -0,0 +1,20 @@
#ifndef Py_CPYTHON_SLICEOBJECT_H
# error "this header file must not be included directly"
#endif
/* Slice object interface */
/*
A slice object containing start, stop, and step data members (the
names are from range). After much talk with Guido, it was decided to
let these be any arbitrary python type. Py_None stands for omitted values.
*/
typedef struct {
PyObject_HEAD
PyObject *start, *stop, *step; /* not NULL */
} PySliceObject;
PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop);
PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
PyObject **start_ptr, PyObject **stop_ptr,
PyObject **step_ptr);

View file

@ -0,0 +1,12 @@
#ifndef Py_CPYTHON_STRUCTSEQ_H
# error "this header file must not be included directly"
#endif
PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
PyStructSequence_Desc *desc);
PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type,
PyStructSequence_Desc *desc);
typedef PyTupleObject PyStructSequence;
#define PyStructSequence_SET_ITEM PyStructSequence_SetItem
#define PyStructSequence_GET_ITEM PyStructSequence_GetItem

View file

@ -38,3 +38,7 @@ PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
} }
#define PyTuple_SET_ITEM(op, index, value) \ #define PyTuple_SET_ITEM(op, index, value) \
PyTuple_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value)) PyTuple_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value))
PyAPI_FUNC(PyObject*) PyTuple_FromArray(
PyObject *const *array,
Py_ssize_t size);

View file

@ -663,6 +663,15 @@ PyAPI_FUNC(int) _PyCode_VerifyStateless(
PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **); PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **);
PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *); PyAPI_FUNC(int) _PyCode_ReturnsOnlyNone(PyCodeObject *);
/* Create a comparable key used to compare constants taking in account the
* object type. It is used to make sure types are not coerced (e.g., float and
* complex) _and_ to distinguish 0.0 from -0.0 e.g. on IEEE platforms
*
* Return (type(obj), obj, ...): a tuple with variable size (at least 2 items)
* depending on the type and the value. The type is the first item to not
* compare bytes and str which can raise a BytesWarning exception. */
extern PyObject* _PyCode_ConstantKey(PyObject *obj);
#ifdef __cplusplus #ifdef __cplusplus
} }

View file

@ -1047,6 +1047,10 @@ static inline Py_ALWAYS_INLINE void _Py_INCREF_MORTAL(PyObject *op)
} }
#endif #endif
/* Utility for the tp_traverse slot of mutable heap types that have no other
* references. */
PyAPI_FUNC(int) _PyObject_VisitType(PyObject *op, visitproc visit, void *arg);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -23,7 +23,6 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
#define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item) #define _PyTuple_ITEMS(op) _Py_RVALUE(_PyTuple_CAST(op)->ob_item)
PyAPI_FUNC(PyObject *)_PyTuple_FromArray(PyObject *const *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromStackRefStealOnSuccess(const union _PyStackRef *, Py_ssize_t);
PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t); PyAPI_FUNC(PyObject *)_PyTuple_FromArraySteal(PyObject *const *, Py_ssize_t);

View file

@ -11,6 +11,70 @@ extern "C" {
#include "pycore_fileutils.h" // _Py_error_handler #include "pycore_fileutils.h" // _Py_error_handler
#include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI #include "pycore_ucnhash.h" // _PyUnicode_Name_CAPI
// Maximum code point of Unicode 6.0: 0x10ffff (1,114,111).
#define _Py_MAX_UNICODE 0x10ffff
extern int _PyUnicode_IsModifiable(PyObject *unicode);
static inline void
_PyUnicode_Fill(int kind, void *data, Py_UCS4 value,
Py_ssize_t start, Py_ssize_t length)
{
assert(0 <= start);
switch (kind) {
case PyUnicode_1BYTE_KIND: {
assert(value <= 0xff);
Py_UCS1 ch = (unsigned char)value;
Py_UCS1 *to = (Py_UCS1 *)data + start;
memset(to, ch, length);
break;
}
case PyUnicode_2BYTE_KIND: {
assert(value <= 0xffff);
Py_UCS2 ch = (Py_UCS2)value;
Py_UCS2 *to = (Py_UCS2 *)data + start;
const Py_UCS2 *end = to + length;
for (; to < end; ++to) *to = ch;
break;
}
case PyUnicode_4BYTE_KIND: {
assert(value <= _Py_MAX_UNICODE);
Py_UCS4 ch = value;
Py_UCS4 * to = (Py_UCS4 *)data + start;
const Py_UCS4 *end = to + length;
for (; to < end; ++to) *to = ch;
break;
}
default: Py_UNREACHABLE();
}
}
static inline int
_PyUnicode_EnsureUnicode(PyObject *obj)
{
if (!PyUnicode_Check(obj)) {
PyErr_Format(PyExc_TypeError,
"must be str, not %T", obj);
return -1;
}
return 0;
}
static inline int
_PyUnicodeWriter_WriteCharInline(_PyUnicodeWriter *writer, Py_UCS4 ch)
{
assert(ch <= _Py_MAX_UNICODE);
if (_PyUnicodeWriter_Prepare(writer, 1, ch) < 0)
return -1;
PyUnicode_WRITE(writer->kind, writer->data, writer->pos, ch);
writer->pos++;
return 0;
}
/* --- Characters Type APIs ----------------------------------------------- */ /* --- Characters Type APIs ----------------------------------------------- */
extern int _PyUnicode_IsXidStart(Py_UCS4 ch); extern int _PyUnicode_IsXidStart(Py_UCS4 ch);
@ -240,21 +304,6 @@ extern PyObject* _PyUnicode_XStrip(
); );
/* Using explicit passed-in values, insert the thousands grouping
into the string pointed to by buffer. For the argument descriptions,
see Objects/stringlib/localeutil.h */
extern Py_ssize_t _PyUnicode_InsertThousandsGrouping(
_PyUnicodeWriter *writer,
Py_ssize_t n_buffer,
PyObject *digits,
Py_ssize_t d_pos,
Py_ssize_t n_digits,
Py_ssize_t min_width,
const char *grouping,
PyObject *thousands_sep,
Py_UCS4 *maxchar,
int forward);
/* Dedent a string. /* Dedent a string.
Behaviour is expected to be an exact match of `textwrap.dedent`. Behaviour is expected to be an exact match of `textwrap.dedent`.
Return a new reference on success, NULL with exception set on error. Return a new reference on success, NULL with exception set on error.

View file

@ -1,31 +1,18 @@
/* Interface for marshal.c */ /* Interface for marshal.c */
#ifndef Py_MARSHAL_H #ifndef Py_MARSHAL_H
#define Py_MARSHAL_H #define Py_MARSHAL_H
#ifndef Py_LIMITED_API
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromString(const char *, #ifndef Py_LIMITED_API
Py_ssize_t); # define _Py_CPYTHON_MARSHAL_H
PyAPI_FUNC(PyObject *) PyMarshal_WriteObjectToString(PyObject *, int); # include "cpython/marshal.h"
# undef _Py_CPYTHON_MARSHAL_H
#define Py_MARSHAL_VERSION 5 #endif
PyAPI_FUNC(long) PyMarshal_ReadLongFromFile(FILE *);
PyAPI_FUNC(int) PyMarshal_ReadShortFromFile(FILE *);
PyAPI_FUNC(PyObject *) PyMarshal_ReadObjectFromFile(FILE *);
PyAPI_FUNC(PyObject *) PyMarshal_ReadLastObjectFromFile(FILE *);
PyAPI_FUNC(void) PyMarshal_WriteLongToFile(long, FILE *, int);
PyAPI_FUNC(void) PyMarshal_WriteObjectToFile(PyObject *, FILE *, int);
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif
#endif /* Py_LIMITED_API */
#endif /* !Py_MARSHAL_H */ #endif /* !Py_MARSHAL_H */

View file

@ -1,18 +0,0 @@
#ifndef Py_MONITORING_H
#define Py_MONITORING_H
#ifdef __cplusplus
extern "C" {
#endif
// There is currently no limited API for monitoring
#ifndef Py_LIMITED_API
# define Py_CPYTHON_MONITORING_H
# include "cpython/monitoring.h"
# undef Py_CPYTHON_MONITORING_H
#endif
#ifdef __cplusplus
}
#endif
#endif /* !Py_MONITORING_H */

View file

@ -1,16 +0,0 @@
#ifndef Py_LOCK_H
#define Py_LOCK_H
#ifdef __cplusplus
extern "C" {
#endif
#ifndef Py_LIMITED_API
# define Py_CPYTHON_LOCK_H
# include "cpython/pylock.h"
# undef Py_CPYTHON_LOCK_H
#endif
#ifdef __cplusplus
}
#endif
#endif /* !Py_LOCK_H */

View file

@ -16,19 +16,6 @@ PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
/* Slice object interface */ /* Slice object interface */
/*
A slice object containing start, stop, and step data members (the
names are from range). After much talk with Guido, it was decided to
let these be any arbitrary python type. Py_None stands for omitted values.
*/
#ifndef Py_LIMITED_API
typedef struct {
PyObject_HEAD
PyObject *start, *stop, *step; /* not NULL */
} PySliceObject;
#endif
PyAPI_DATA(PyTypeObject) PySlice_Type; PyAPI_DATA(PyTypeObject) PySlice_Type;
PyAPI_DATA(PyTypeObject) PyEllipsis_Type; PyAPI_DATA(PyTypeObject) PyEllipsis_Type;
@ -36,12 +23,6 @@ PyAPI_DATA(PyTypeObject) PyEllipsis_Type;
PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop, PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop,
PyObject* step); PyObject* step);
#ifndef Py_LIMITED_API
PyAPI_FUNC(PyObject *) _PySlice_FromIndices(Py_ssize_t start, Py_ssize_t stop);
PyAPI_FUNC(int) _PySlice_GetLongIndices(PySliceObject *self, PyObject *length,
PyObject **start_ptr, PyObject **stop_ptr,
PyObject **step_ptr);
#endif
PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length, PyAPI_FUNC(int) PySlice_GetIndices(PyObject *r, Py_ssize_t length,
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step); Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
Py_DEPRECATED(3.7) Py_DEPRECATED(3.7)
@ -63,6 +44,12 @@ PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length,
Py_ssize_t step); Py_ssize_t step);
#endif #endif
#ifndef Py_LIMITED_API
# define Py_CPYTHON_SLICEOBJECT_H
# include "cpython/sliceobject.h"
# undef Py_CPYTHON_SLICEOBJECT_H
#endif
#ifdef __cplusplus #ifdef __cplusplus
} }
#endif #endif

View file

@ -21,12 +21,6 @@ typedef struct PyStructSequence_Desc {
PyAPI_DATA(const char * const) PyStructSequence_UnnamedField; PyAPI_DATA(const char * const) PyStructSequence_UnnamedField;
#ifndef Py_LIMITED_API
PyAPI_FUNC(void) PyStructSequence_InitType(PyTypeObject *type,
PyStructSequence_Desc *desc);
PyAPI_FUNC(int) PyStructSequence_InitType2(PyTypeObject *type,
PyStructSequence_Desc *desc);
#endif
PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc); PyAPI_FUNC(PyTypeObject*) PyStructSequence_NewType(PyStructSequence_Desc *desc);
PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type); PyAPI_FUNC(PyObject *) PyStructSequence_New(PyTypeObject* type);
@ -35,9 +29,9 @@ PyAPI_FUNC(void) PyStructSequence_SetItem(PyObject*, Py_ssize_t, PyObject*);
PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t); PyAPI_FUNC(PyObject*) PyStructSequence_GetItem(PyObject*, Py_ssize_t);
#ifndef Py_LIMITED_API #ifndef Py_LIMITED_API
typedef PyTupleObject PyStructSequence; # define Py_CPYTHON_STRUCTSEQ_H
#define PyStructSequence_SET_ITEM PyStructSequence_SetItem # include "cpython/structseq.h"
#define PyStructSequence_GET_ITEM PyStructSequence_GetItem # undef Py_CPYTHON_STRUCTSEQ_H
#endif #endif
#ifdef __cplusplus #ifdef __cplusplus

View file

@ -420,14 +420,17 @@ class delete(EditCommand):
def do(self) -> None: def do(self) -> None:
r = self.reader r = self.reader
b = r.buffer b = r.buffer
if ( if self.event[-1] == "\004":
if b and b[-1].endswith("\n"):
self.finish = True
elif (
r.pos == 0 r.pos == 0
and len(b) == 0 # this is something of a hack and len(b) == 0 # this is something of a hack
and self.event[-1] == "\004"
): ):
r.update_screen() r.update_screen()
r.console.finish() r.console.finish()
raise EOFError raise EOFError
for i in range(r.get_arg()): for i in range(r.get_arg()):
if r.pos != len(b): if r.pos != len(b):
del b[r.pos] del b[r.pos]

View file

@ -390,7 +390,12 @@ def restore(self):
os.write(self.output_fd, b"\033[?7h") os.write(self.output_fd, b"\033[?7h")
if hasattr(self, "old_sigwinch"): if hasattr(self, "old_sigwinch"):
try:
signal.signal(signal.SIGWINCH, self.old_sigwinch) signal.signal(signal.SIGWINCH, self.old_sigwinch)
except ValueError as e:
import threading
if threading.current_thread() is threading.main_thread():
raise e
del self.old_sigwinch del self.old_sigwinch
def push_char(self, char: int | bytes) -> None: def push_char(self, char: int | bytes) -> None:

View file

@ -280,7 +280,7 @@ def add_argument(self, action):
if action.help is not SUPPRESS: if action.help is not SUPPRESS:
# find all invocations # find all invocations
get_invocation = self._format_action_invocation get_invocation = lambda x: self._decolor(self._format_action_invocation(x))
invocation_lengths = [len(get_invocation(action)) + self._current_indent] invocation_lengths = [len(get_invocation(action)) + self._current_indent]
for subaction in self._iter_indented_subactions(action): for subaction in self._iter_indented_subactions(action):
invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent) invocation_lengths.append(len(get_invocation(subaction)) + self._current_indent)
@ -1959,7 +1959,9 @@ def add_subparsers(self, **kwargs):
# prog defaults to the usage message of this parser, skipping # prog defaults to the usage message of this parser, skipping
# optional arguments and with no "usage:" prefix # optional arguments and with no "usage:" prefix
if kwargs.get('prog') is None: if kwargs.get('prog') is None:
formatter = self._get_formatter() # Create formatter without color to avoid storing ANSI codes in prog
formatter = self.formatter_class(prog=self.prog)
formatter._set_color(False)
positionals = self._get_positional_actions() positionals = self._get_positional_actions()
groups = self._mutually_exclusive_groups groups = self._mutually_exclusive_groups
formatter.add_usage(None, positionals, groups, '') formatter.add_usage(None, positionals, groups, '')

View file

@ -74,6 +74,7 @@ def callback():
return return
except BaseException: except BaseException:
if keyboard_interrupted: if keyboard_interrupted:
if not CAN_USE_PYREPL:
self.write("\nKeyboardInterrupt\n") self.write("\nKeyboardInterrupt\n")
else: else:
self.showtraceback() self.showtraceback()

View file

@ -1050,8 +1050,8 @@ def _read_ready__on_eof(self):
def write(self, data): def write(self, data):
if not isinstance(data, (bytes, bytearray, memoryview)): if not isinstance(data, (bytes, bytearray, memoryview)):
raise TypeError(f'data argument must be a bytes-like object, ' raise TypeError(f'data argument must be a bytes, bytearray, or memoryview '
f'not {type(data).__name__!r}') f'object, not {type(data).__name__!r}')
if self._eof: if self._eof:
raise RuntimeError('Cannot call write() after write_eof()') raise RuntimeError('Cannot call write() after write_eof()')
if self._empty_waiter is not None: if self._empty_waiter is not None:

View file

@ -302,6 +302,7 @@ def parse_request(self):
error response has already been sent back. error response has already been sent back.
""" """
is_http_0_9 = False
self.command = None # set in case of error on the first line self.command = None # set in case of error on the first line
self.request_version = version = self.default_request_version self.request_version = version = self.default_request_version
self.close_connection = True self.close_connection = True
@ -359,6 +360,7 @@ def parse_request(self):
HTTPStatus.BAD_REQUEST, HTTPStatus.BAD_REQUEST,
"Bad HTTP/0.9 request type (%r)" % command) "Bad HTTP/0.9 request type (%r)" % command)
return False return False
is_http_0_9 = True
self.command, self.path = command, path self.command, self.path = command, path
# gh-87389: The purpose of replacing '//' with '/' is to protect # gh-87389: The purpose of replacing '//' with '/' is to protect
@ -368,6 +370,11 @@ def parse_request(self):
if self.path.startswith('//'): if self.path.startswith('//'):
self.path = '/' + self.path.lstrip('/') # Reduce to a single / self.path = '/' + self.path.lstrip('/') # Reduce to a single /
# For HTTP/0.9, headers are not expected at all.
if is_http_0_9:
self.headers = {}
return True
# Examine the headers and look for a Connection directive. # Examine the headers and look for a Connection directive.
try: try:
self.headers = http.client.parse_headers(self.rfile, self.headers = http.client.parse_headers(self.rfile,

View file

@ -37,6 +37,7 @@ Major contributors since 2005:
- 2014: Saimadhav Heblikar - 2014: Saimadhav Heblikar
- 2015: Mark Roseman - 2015: Mark Roseman
- 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka - 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka
- 2025: Stan Ulbrych
For additional details refer to NEWS.txt and Changelog. For additional details refer to NEWS.txt and Changelog.

View file

@ -47,7 +47,7 @@ def make_pat():
name not in keyword.kwlist] name not in keyword.kwlist]
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b" builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
comment = any("COMMENT", [r"#[^\n]*"]) comment = any("COMMENT", [r"#[^\n]*"])
stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb)?" stringprefix = r"(?i:r|u|f|fr|rf|b|br|rb|t|rt|tr)?"
sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?" sqstring = stringprefix + r"'[^'\\\n]*(\\.[^'\\\n]*)*'?"
dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?' dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?" sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"

View file

@ -33,7 +33,6 @@
# The default tab setting for a Text widget, in average-width characters. # The default tab setting for a Text widget, in average-width characters.
TK_TABWIDTH_DEFAULT = 8 TK_TABWIDTH_DEFAULT = 8
_py_version = ' (%s)' % platform.python_version()
darwin = sys.platform == 'darwin' darwin = sys.platform == 'darwin'
def _sphinx_version(): def _sphinx_version():
@ -1008,12 +1007,16 @@ def open_recent_file(fn_closure=file_name):
def saved_change_hook(self): def saved_change_hook(self):
short = self.short_title() short = self.short_title()
long = self.long_title() long = self.long_title()
_py_version = ' (%s)' % platform.python_version()
if short and long and not macosx.isCocoaTk(): if short and long and not macosx.isCocoaTk():
# Don't use both values on macOS because # Don't use both values on macOS because
# that doesn't match platform conventions. # that doesn't match platform conventions.
title = short + " - " + long + _py_version title = short + " - " + long + _py_version
elif short: elif short:
title = short if short == "IDLE Shell":
title = short + " " + platform.python_version()
else:
title = short + _py_version
elif long: elif long:
title = long title = long
else: else:

View file

@ -36,6 +36,7 @@ async def f(): await g()
# All valid prefixes for unicode and byte strings should be colored. # All valid prefixes for unicode and byte strings should be colored.
r'x', u'x', R'x', U'x', f'x', F'x' r'x', u'x', R'x', U'x', f'x', F'x'
fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x' fr'x', Fr'x', fR'x', FR'x', rf'x', rF'x', Rf'x', RF'x'
tr'x', Tr'x', tR'x', TR'x', rt'x', rT'x', Rt'x', RT'x'
b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x', rB'x',Rb'x',RB'x' b'x',B'x', br'x',Br'x',bR'x',BR'x', rb'x', rB'x',Rb'x',RB'x'
# Invalid combinations of legal characters should be half colored. # Invalid combinations of legal characters should be half colored.
ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x' ur'x', ru'x', uf'x', fu'x', UR'x', ufr'x', rfu'x', xf'x', fx'x'
@ -390,19 +391,19 @@ def test_recolorize_main(self, mock_notify):
('6.0', ('KEYWORD',)), ('6.10', ('DEFINITION',)), ('6.11', ()), ('6.0', ('KEYWORD',)), ('6.10', ('DEFINITION',)), ('6.11', ()),
('8.0', ('STRING',)), ('8.4', ()), ('8.5', ('STRING',)), ('8.0', ('STRING',)), ('8.4', ()), ('8.5', ('STRING',)),
('8.12', ()), ('8.14', ('STRING',)), ('8.12', ()), ('8.14', ('STRING',)),
('19.0', ('KEYWORD',)), ('20.0', ('KEYWORD',)),
('20.4', ('KEYWORD',)), ('20.16', ('KEYWORD',)),# ('20.19', ('KEYWORD',)), ('21.4', ('KEYWORD',)), ('21.16', ('KEYWORD',)),# ('21.19', ('KEYWORD',)),
#('22.4', ('KEYWORD',)), ('22.10', ('KEYWORD',)), ('22.14', ('KEYWORD',)), ('22.19', ('STRING',)), #('23.4', ('KEYWORD',)), ('23.10', ('KEYWORD',)), ('23.14', ('KEYWORD',)), ('23.19', ('STRING',)),
#('23.12', ('KEYWORD',)), #('24.12', ('KEYWORD',)),
('24.8', ('KEYWORD',)), ('25.8', ('KEYWORD',)),
('25.4', ('KEYWORD',)), ('25.9', ('KEYWORD',)), ('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)),
('25.11', ('KEYWORD',)), ('25.15', ('STRING',)), ('26.11', ('KEYWORD',)), ('26.15', ('STRING',)),
('25.19', ('KEYWORD',)), ('25.22', ()), ('26.19', ('KEYWORD',)), ('26.22', ()),
('25.24', ('KEYWORD',)), ('25.29', ('BUILTIN',)), ('25.37', ('KEYWORD',)), ('26.24', ('KEYWORD',)), ('26.29', ('BUILTIN',)), ('26.37', ('KEYWORD',)),
('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)),# ('26.11', ('KEYWORD',)), ('26.14', (),), ('27.4', ('KEYWORD',)), ('27.9', ('KEYWORD',)),# ('27.11', ('KEYWORD',)), ('27.14', (),),
('27.25', ('STRING',)), ('27.38', ('STRING',)), ('28.25', ('STRING',)), ('28.38', ('STRING',)),
('29.0', ('STRING',)), ('30.0', ('STRING',)),
('30.1', ('STRING',)), ('31.1', ('STRING',)),
# SYNC at the end of every line. # SYNC at the end of every line.
('1.55', ('SYNC',)), ('2.50', ('SYNC',)), ('3.34', ('SYNC',)), ('1.55', ('SYNC',)), ('2.50', ('SYNC',)), ('3.34', ('SYNC',)),
) )
@ -433,7 +434,7 @@ def test_recolorize_main(self, mock_notify):
eq(text.tag_nextrange('STRING', '8.12'), ('8.14', '8.17')) eq(text.tag_nextrange('STRING', '8.12'), ('8.14', '8.17'))
eq(text.tag_nextrange('STRING', '8.17'), ('8.19', '8.26')) eq(text.tag_nextrange('STRING', '8.17'), ('8.19', '8.26'))
eq(text.tag_nextrange('SYNC', '8.0'), ('8.26', '9.0')) eq(text.tag_nextrange('SYNC', '8.0'), ('8.26', '9.0'))
eq(text.tag_nextrange('SYNC', '30.0'), ('30.10', '32.0')) eq(text.tag_nextrange('SYNC', '31.0'), ('31.10', '33.0'))
def _assert_highlighting(self, source, tag_ranges): def _assert_highlighting(self, source, tag_ranges):
"""Check highlighting of a given piece of code. """Check highlighting of a given piece of code.

View file

@ -1,6 +1,7 @@
"Test outwin, coverage 76%." "Test outwin, coverage 76%."
from idlelib import outwin from idlelib import outwin
import platform
import sys import sys
import unittest import unittest
from test.support import requires from test.support import requires
@ -41,7 +42,7 @@ def test_ispythonsource(self):
self.assertFalse(w.ispythonsource(__file__)) self.assertFalse(w.ispythonsource(__file__))
def test_window_title(self): def test_window_title(self):
self.assertEqual(self.window.top.title(), 'Output') self.assertEqual(self.window.top.title(), 'Output' + ' (%s)' % platform.python_version())
def test_maybesave(self): def test_maybesave(self):
w = self.window w = self.window

View file

@ -22,7 +22,6 @@
import linecache import linecache
import os import os
import os.path import os.path
from platform import python_version
import re import re
import socket import socket
import subprocess import subprocess
@ -841,7 +840,7 @@ def display_executing_dialog(self):
class PyShell(OutputWindow): class PyShell(OutputWindow):
from idlelib.squeezer import Squeezer from idlelib.squeezer import Squeezer
shell_title = "IDLE Shell " + python_version() shell_title = "IDLE Shell"
# Override classes # Override classes
ColorDelegator = ModifiedColorDelegator ColorDelegator = ModifiedColorDelegator

View file

@ -6,7 +6,6 @@
import types import types
import importlib import importlib
import inspect import inspect
import warnings
import itertools import itertools
from typing import Union, Optional, cast from typing import Union, Optional, cast
@ -16,39 +15,6 @@
Anchor = Package Anchor = Package
def package_to_anchor(func):
"""
Replace 'package' parameter as 'anchor' and warn about the change.
Other errors should fall through.
>>> files('a', 'b')
Traceback (most recent call last):
TypeError: files() takes from 0 to 1 positional arguments but 2 were given
Remove this compatibility in Python 3.14.
"""
undefined = object()
@functools.wraps(func)
def wrapper(anchor=undefined, package=undefined):
if package is not undefined:
if anchor is not undefined:
return func(anchor, package)
warnings.warn(
"First parameter to files is renamed to 'anchor'",
DeprecationWarning,
stacklevel=2,
)
return func(package)
elif anchor is undefined:
return func()
return func(anchor)
return wrapper
@package_to_anchor
def files(anchor: Optional[Anchor] = None) -> Traversable: def files(anchor: Optional[Anchor] = None) -> Traversable:
""" """
Get a Traversable resource for an anchor. Get a Traversable resource for an anchor.

View file

@ -1065,7 +1065,9 @@ def __init__(self):
def tokeneater(self, type, token, srowcol, erowcol, line): def tokeneater(self, type, token, srowcol, erowcol, line):
if not self.started and not self.indecorator: if not self.started and not self.indecorator:
if type == tokenize.INDENT or token == "async": if type in (tokenize.INDENT, tokenize.COMMENT, tokenize.NL):
pass
elif token == "async":
pass pass
# skip any decorators # skip any decorators
elif token == "@": elif token == "@":

View file

@ -58,6 +58,11 @@ def _get_exports_list(module):
__all__.append('_exit') __all__.append('_exit')
except ImportError: except ImportError:
pass pass
try:
from posix import _clearenv
__all__.append('_clearenv')
except ImportError:
pass
import posixpath as path import posixpath as path
try: try:
@ -768,6 +773,12 @@ def __ror__(self, other):
new.update(self) new.update(self)
return new return new
if _exists("_clearenv"):
def clear(self):
_clearenv()
self._data.clear()
def _create_environ_mapping(): def _create_environ_mapping():
if name == 'nt': if name == 'nt':
# Where Env Var Names Must Be UPPERCASE # Where Env Var Names Must Be UPPERCASE

View file

@ -336,13 +336,8 @@ def _raw_path(self):
return paths[0] return paths[0]
elif paths: elif paths:
# Join path segments from the initializer. # Join path segments from the initializer.
path = self.parser.join(*paths) return self.parser.join(*paths)
# Cache the joined path.
paths.clear()
paths.append(path)
return path
else: else:
paths.append('')
return '' return ''
@property @property
@ -490,16 +485,19 @@ def relative_to(self, other, *, walk_up=False):
""" """
if not hasattr(other, 'with_segments'): if not hasattr(other, 'with_segments'):
other = self.with_segments(other) other = self.with_segments(other)
for step, path in enumerate(chain([other], other.parents)): parts = []
for path in chain([other], other.parents):
if path == self or path in self.parents: if path == self or path in self.parents:
break break
elif not walk_up: elif not walk_up:
raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}") raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
elif path.name == '..': elif path.name == '..':
raise ValueError(f"'..' segment in {str(other)!r} cannot be walked") raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
else:
parts.append('..')
else: else:
raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors") raise ValueError(f"{str(self)!r} and {str(other)!r} have different anchors")
parts = ['..'] * step + self._tail[len(path._tail):] parts.extend(self._tail[len(path._tail):])
return self._from_parsed_parts('', '', parts) return self._from_parsed_parts('', '', parts)
def is_relative_to(self, other): def is_relative_to(self, other):

View file

@ -234,6 +234,33 @@ def parents(self):
parent = split(path)[0] parent = split(path)[0]
return tuple(parents) return tuple(parents)
def relative_to(self, other, *, walk_up=False):
"""Return the relative path to another path identified by the passed
arguments. If the operation is not possible (because this is not
related to the other path), raise ValueError.
The *walk_up* parameter controls whether `..` may be used to resolve
the path.
"""
parts = []
for path in (other,) + other.parents:
if self.is_relative_to(path):
break
elif not walk_up:
raise ValueError(f"{self!r} is not in the subpath of {other!r}")
elif path.name == '..':
raise ValueError(f"'..' segment in {other!r} cannot be walked")
else:
parts.append('..')
else:
raise ValueError(f"{self!r} and {other!r} have different anchors")
return self.with_segments(*parts, *self.parts[len(path.parts):])
def is_relative_to(self, other):
"""Return True if the path is relative to another path or False.
"""
return other == self or other in self.parents
def full_match(self, pattern): def full_match(self, pattern):
""" """
Return True if this path matches the given glob-style pattern. The Return True if this path matches the given glob-style pattern. The

View file

@ -348,7 +348,7 @@ def read_stringnl(f, decode=True, stripquotes=True, *, encoding='latin-1'):
for q in (b'"', b"'"): for q in (b'"', b"'"):
if data.startswith(q): if data.startswith(q):
if not data.endswith(q): if not data.endswith(q):
raise ValueError("strinq quote %r not found at both " raise ValueError("string quote %r not found at both "
"ends of %r" % (q, data)) "ends of %r" % (q, data))
data = data[1:-1] data = data[1:-1]
break break

View file

@ -333,7 +333,7 @@ def _get_path(userbase):
if sys.platform == 'darwin' and sys._framework: if sys.platform == 'darwin' and sys._framework:
return f'{userbase}/lib/{implementation_lower}/site-packages' return f'{userbase}/lib/{implementation_lower}/site-packages'
return f'{userbase}/lib/python{version[0]}.{version[1]}{abi_thread}/site-packages' return f'{userbase}/lib/{implementation_lower}{version[0]}.{version[1]}{abi_thread}/site-packages'
def getuserbase(): def getuserbase():

View file

@ -110,11 +110,6 @@
) )
from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj
from _ssl import RAND_status, RAND_add, RAND_bytes from _ssl import RAND_status, RAND_add, RAND_bytes
try:
from _ssl import RAND_egd
except ImportError:
# RAND_egd is not supported on some platforms
pass
from _ssl import get_sigalgs from _ssl import get_sigalgs

View file

@ -645,6 +645,9 @@ def get_platform():
isn't particularly important. isn't particularly important.
Examples of returned values: Examples of returned values:
linux-x86_64
linux-aarch64
solaris-2.6-sun4u
Windows: Windows:

View file

@ -21,8 +21,9 @@
# Regexes needed for parsing Makefile (and similar syntaxes, # Regexes needed for parsing Makefile (and similar syntaxes,
# like old-style Setup files). # like old-style Setup files).
_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)" _variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)" _findvar_rx = (r"\$(\([A-Za-z][A-Za-z0-9_]*\)"
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}" r"|\{[A-Za-z][A-Za-z0-9_]*\}"
r"|\$?)")
def _parse_makefile(filename, vars=None, keep_unresolved=True): def _parse_makefile(filename, vars=None, keep_unresolved=True):
@ -49,26 +50,7 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True):
m = re.match(_variable_rx, line) m = re.match(_variable_rx, line)
if m: if m:
n, v = m.group(1, 2) n, v = m.group(1, 2)
v = v.strip() notdone[n] = v.strip()
# `$$' is a literal `$' in make
tmpv = v.replace('$$', '')
if "$" in tmpv:
notdone[n] = v
else:
try:
if n in _ALWAYS_STR:
raise ValueError
v = int(v)
except ValueError:
# insert literal `$'
done[n] = v.replace('$$', '$')
else:
done[n] = v
# do variable interpolation here
variables = list(notdone.keys())
# Variables with a 'PY_' prefix in the makefile. These need to # Variables with a 'PY_' prefix in the makefile. These need to
# be made available without that prefix through sysconfig. # be made available without that prefix through sysconfig.
@ -76,72 +58,64 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True):
# if the expansion uses the name without a prefix. # if the expansion uses the name without a prefix.
renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS') renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
while len(variables) > 0: def resolve_var(name):
for name in tuple(variables): def repl(m):
value = notdone[name] n = m[1]
m1 = re.search(_findvar1_rx, value) if n == '$':
m2 = re.search(_findvar2_rx, value) return '$'
if m1 and m2: elif n == '':
m = m1 if m1.start() < m2.start() else m2 # bogus variable reference (e.g. "prefix=$/opt/python")
else: if keep_unresolved:
m = m1 if m1 else m2 return m[0]
if m is not None: raise ValueError
n = m.group(1) elif n[0] == '(' and n[-1] == ')':
found = True n = n[1:-1]
elif n[0] == '{' and n[-1] == '}':
n = n[1:-1]
if n in done: if n in done:
item = str(done[n]) return str(done[n])
elif n in notdone: elif n in notdone:
# get it on a subsequent round return str(resolve_var(n))
found = False
elif n in os.environ: elif n in os.environ:
# do it like make: fall back to environment # do it like make: fall back to environment
item = os.environ[n] return os.environ[n]
elif n in renamed_variables: elif n in renamed_variables:
if (name.startswith('PY_') and if name.startswith('PY_') and name[3:] in renamed_variables:
name[3:] in renamed_variables): return ""
item = "" n = 'PY_' + n
if n in notdone:
elif 'PY_' + n in notdone: return str(resolve_var(n))
found = False
else: else:
item = str(done['PY_' + n]) assert n not in done
return ""
else: else:
done[n] = item = "" done[n] = ""
return ""
if found: assert name not in done
after = value[m.end():] done[name] = ""
value = value[:m.start()] + item + after try:
if "$" in after: value = re.sub(_findvar_rx, repl, notdone[name])
notdone[name] = value except ValueError:
else: del done[name]
return ""
value = value.strip()
if name not in _ALWAYS_STR:
try: try:
if name in _ALWAYS_STR:
raise ValueError
value = int(value) value = int(value)
except ValueError: except ValueError:
done[name] = value.strip() pass
else:
done[name] = value done[name] = value
variables.remove(name) if name.startswith('PY_') and name[3:] in renamed_variables:
if name.startswith('PY_') \
and name[3:] in renamed_variables:
name = name[3:] name = name[3:]
if name not in done: if name not in done:
done[name] = value done[name] = value
return value
else: for n in notdone:
# Adds unresolved variables to the done dict. if n not in done:
# This is disabled when called from distutils.sysconfig resolve_var(n)
if keep_unresolved:
done[name] = value
# bogus variable reference (e.g. "prefix=$/opt/python");
# just drop it since we can't deal
variables.remove(name)
# strip spurious spaces # strip spurious spaces
for k, v in done.items(): for k, v in done.items():

View file

@ -4341,7 +4341,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
goto exit; goto exit;
} }
a = args[0]; a = args[0];
__clinic_args = _PyTuple_FromArray(args + 1, nargs - 1); __clinic_args = PyTuple_FromArray(args + 1, nargs - 1);
if (__clinic_args == NULL) { if (__clinic_args == NULL) {
goto exit; goto exit;
} }
@ -4356,7 +4356,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
static PyObject * static PyObject *
test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args) test_vararg_and_posonly_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=0c11c475e240869e input=2c49a482f68545c0]*/ /*[clinic end generated code: output=83cbe9554d04add2 input=2c49a482f68545c0]*/
/*[clinic input] /*[clinic input]
test_vararg test_vararg
@ -4421,7 +4421,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
} }
a = fastargs[0]; a = fastargs[0];
__clinic_args = nargs > 1 __clinic_args = nargs > 1
? _PyTuple_FromArray(args + 1, nargs - 1) ? PyTuple_FromArray(args + 1, nargs - 1)
: PyTuple_New(0); : PyTuple_New(0);
if (__clinic_args == NULL) { if (__clinic_args == NULL) {
goto exit; goto exit;
@ -4437,7 +4437,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
static PyObject * static PyObject *
test_vararg_impl(PyObject *module, PyObject *a, PyObject *args) test_vararg_impl(PyObject *module, PyObject *a, PyObject *args)
/*[clinic end generated code: output=17ba625cdd0369c1 input=7448995636d9186a]*/ /*[clinic end generated code: output=d773f7b54e61f73a input=7448995636d9186a]*/
/*[clinic input] /*[clinic input]
test_vararg_with_default test_vararg_with_default
@ -4514,7 +4514,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
} }
skip_optional_kwonly: skip_optional_kwonly:
__clinic_args = nargs > 1 __clinic_args = nargs > 1
? _PyTuple_FromArray(args + 1, nargs - 1) ? PyTuple_FromArray(args + 1, nargs - 1)
: PyTuple_New(0); : PyTuple_New(0);
if (__clinic_args == NULL) { if (__clinic_args == NULL) {
goto exit; goto exit;
@ -4531,7 +4531,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
static PyObject * static PyObject *
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args, test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
int b) int b)
/*[clinic end generated code: output=3f2b06ab08d5d0be input=3a0f9f557ce1f712]*/ /*[clinic end generated code: output=d25e56802c197344 input=3a0f9f557ce1f712]*/
/*[clinic input] /*[clinic input]
test_vararg_with_only_defaults test_vararg_with_only_defaults
@ -4612,7 +4612,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
} }
c = fastargs[1]; c = fastargs[1];
skip_optional_kwonly: skip_optional_kwonly:
__clinic_args = _PyTuple_FromArray(args, nargs); __clinic_args = PyTuple_FromArray(args, nargs);
if (__clinic_args == NULL) { if (__clinic_args == NULL) {
goto exit; goto exit;
} }
@ -4628,7 +4628,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
static PyObject * static PyObject *
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b, test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
PyObject *c) PyObject *c)
/*[clinic end generated code: output=f46666f0b1bf86b9 input=6983e66817f82924]*/ /*[clinic end generated code: output=7366943a7df42e05 input=6983e66817f82924]*/
/*[clinic input] /*[clinic input]
test_paramname_module test_paramname_module

View file

@ -646,15 +646,23 @@ def _add_cross_compile_opts(self, regrtest_opts):
return (environ, keep_environ) return (environ, keep_environ)
def _add_ci_python_opts(self, python_opts, keep_environ): def _add_ci_python_opts(self, python_opts, keep_environ):
# --fast-ci and --slow-ci add options to Python: # --fast-ci and --slow-ci add options to Python.
# "-u -W default -bb -E" #
# Some platforms run tests in embedded mode and cannot change options
# after startup, so if this function changes, consider also updating:
# * gradle_task in Android/android.py
# Unbuffered stdout and stderr # Unbuffered stdout and stderr. This isn't helpful on Android, because
if not sys.stdout.write_through: # it would cause lines to be split into multiple log messages.
if not sys.stdout.write_through and sys.platform != "android":
python_opts.append('-u') python_opts.append('-u')
# Add warnings filter 'error' # Add warnings filter 'error', unless the user specified a different
if 'default' not in sys.warnoptions: # filter. Ignore BytesWarning since it's controlled by '-b' below.
if not [
opt for opt in sys.warnoptions
if not opt.endswith("::BytesWarning")
]:
python_opts.extend(('-W', 'error')) python_opts.extend(('-W', 'error'))
# Error on bytes/str comparison # Error on bytes/str comparison
@ -673,8 +681,12 @@ def _execute_python(self, cmd, environ):
cmd_text = shlex.join(cmd) cmd_text = shlex.join(cmd)
try: try:
print(f"+ {cmd_text}", flush=True) # Android and iOS run tests in embedded mode. To update their
# Python options, see the comment in _add_ci_python_opts.
if not cmd[0]:
raise ValueError("No Python executable is present")
print(f"+ {cmd_text}", flush=True)
if hasattr(os, 'execv') and not MS_WINDOWS: if hasattr(os, 'execv') and not MS_WINDOWS:
os.execv(cmd[0], cmd) os.execv(cmd[0], cmd)
# On success, execv() do no return. # On success, execv() do no return.

View file

@ -310,6 +310,16 @@ def requires(resource, msg=None):
if resource == 'gui' and not _is_gui_available(): if resource == 'gui' and not _is_gui_available():
raise ResourceDenied(_is_gui_available.reason) raise ResourceDenied(_is_gui_available.reason)
def _get_kernel_version(sysname="Linux"):
import platform
if platform.system() != sysname:
return None
version_txt = platform.release().split('-', 1)[0]
try:
return tuple(map(int, version_txt.split('.')))
except ValueError:
return None
def _requires_unix_version(sysname, min_version): def _requires_unix_version(sysname, min_version):
"""Decorator raising SkipTest if the OS is `sysname` and the version is less """Decorator raising SkipTest if the OS is `sysname` and the version is less
than `min_version`. than `min_version`.

View file

@ -22,6 +22,7 @@
captured_stderr, captured_stderr,
force_not_colorized, force_not_colorized,
force_not_colorized_test_class, force_not_colorized_test_class,
swap_attr,
) )
from test.support import import_helper from test.support import import_helper
from test.support import os_helper from test.support import os_helper
@ -7128,7 +7129,8 @@ class TestColorized(TestCase):
def setUp(self): def setUp(self):
super().setUp() super().setUp()
# Ensure color even if ran with NO_COLOR=1 # Ensure color even if ran with NO_COLOR=1
_colorize.can_colorize = lambda *args, **kwargs: True self.enterContext(swap_attr(_colorize, 'can_colorize',
lambda *args, **kwargs: True))
self.theme = _colorize.get_theme(force_color=True).argparse self.theme = _colorize.get_theme(force_color=True).argparse
def test_argparse_color(self): def test_argparse_color(self):
@ -7355,6 +7357,17 @@ def __init__(self, prog):
{short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help {short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help
''')) '''))
def test_subparser_prog_is_stored_without_color(self):
parser = argparse.ArgumentParser(prog='complex', color=True)
sub = parser.add_subparsers(dest='command')
demo_parser = sub.add_parser('demo')
self.assertNotIn('\x1b[', demo_parser.prog)
demo_parser.color = False
help_text = demo_parser.format_help()
self.assertNotIn('\x1b[', help_text)
class TestModule(unittest.TestCase): class TestModule(unittest.TestCase):
def test_deprecated__version__(self): def test_deprecated__version__(self):

View file

@ -1180,12 +1180,48 @@ async def runner():
@support.requires_fork() @support.requires_fork()
class TestFork(unittest.IsolatedAsyncioTestCase): class TestFork(unittest.TestCase):
async def test_fork_not_share_event_loop(self): @warnings_helper.ignore_fork_in_thread_deprecation_warnings()
with warnings_helper.ignore_fork_in_thread_deprecation_warnings(): def test_fork_not_share_current_task(self):
loop = object()
task = object()
asyncio._set_running_loop(loop)
self.addCleanup(asyncio._set_running_loop, None)
asyncio.tasks._enter_task(loop, task)
self.addCleanup(asyncio.tasks._leave_task, loop, task)
self.assertIs(asyncio.current_task(), task)
r, w = os.pipe()
self.addCleanup(os.close, r)
self.addCleanup(os.close, w)
pid = os.fork()
if pid == 0:
# child
try:
asyncio._set_running_loop(loop)
current_task = asyncio.current_task()
if current_task is None:
os.write(w, b'NO TASK')
else:
os.write(w, b'TASK:' + str(id(current_task)).encode())
except BaseException as e:
os.write(w, b'ERROR:' + ascii(e).encode())
finally:
asyncio._set_running_loop(None)
os._exit(0)
else:
# parent
result = os.read(r, 100)
self.assertEqual(result, b'NO TASK')
wait_process(pid, exitcode=0)
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
def test_fork_not_share_event_loop(self):
# The forked process should not share the event loop with the parent # The forked process should not share the event loop with the parent
loop = asyncio.get_running_loop() loop = object()
asyncio._set_running_loop(loop)
self.assertIs(asyncio.get_running_loop(), loop)
self.addCleanup(asyncio._set_running_loop, None)
r, w = os.pipe() r, w = os.pipe()
self.addCleanup(os.close, r) self.addCleanup(os.close, r)
self.addCleanup(os.close, w) self.addCleanup(os.close, w)

View file

@ -62,6 +62,28 @@ def test_tuple_new(self):
self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN) self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN)
self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX) self.assertRaises(MemoryError, tuple_new, PY_SSIZE_T_MAX)
def test_tuple_fromarray(self):
# Test PyTuple_FromArray()
tuple_fromarray = _testcapi.tuple_fromarray
tup = tuple([i] for i in range(5))
copy = tuple_fromarray(tup)
self.assertEqual(copy, tup)
tup = ()
copy = tuple_fromarray(tup)
self.assertIs(copy, tup)
copy = tuple_fromarray(NULL, 0)
self.assertIs(copy, ())
with self.assertRaises(SystemError):
tuple_fromarray(NULL, -1)
with self.assertRaises(SystemError):
tuple_fromarray(NULL, PY_SSIZE_T_MIN)
with self.assertRaises(MemoryError):
tuple_fromarray(NULL, PY_SSIZE_T_MAX)
def test_tuple_pack(self): def test_tuple_pack(self):
# Test PyTuple_Pack() # Test PyTuple_Pack()
pack = _testlimitedcapi.tuple_pack pack = _testlimitedcapi.tuple_pack

View file

@ -514,6 +514,10 @@ def myfunc():
_testcapi.set_func_kwdefaults_via_capi(myfunc, new_kwdefaults) _testcapi.set_func_kwdefaults_via_capi(myfunc, new_kwdefaults)
self.assertIn((_testcapi.PYFUNC_EVENT_MODIFY_KWDEFAULTS, myfunc, new_kwdefaults), events) self.assertIn((_testcapi.PYFUNC_EVENT_MODIFY_KWDEFAULTS, myfunc, new_kwdefaults), events)
new_qualname = "foo.bar"
myfunc.__qualname__ = new_qualname
self.assertIn((_testcapi.PYFUNC_EVENT_MODIFY_QUALNAME, myfunc, new_qualname), events)
# Clear events reference to func # Clear events reference to func
events = [] events = []
del myfunc del myfunc

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