mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
Merge branch 'python:main' into pyrepl-module-completion-check-for-already-imported-modules
This commit is contained in:
commit
e3f1ddb88b
268 changed files with 6793 additions and 3830 deletions
4
.github/CODEOWNERS
vendored
4
.github/CODEOWNERS
vendored
|
|
@ -86,6 +86,10 @@ Modules/makesetup @erlend-aasland @AA-Turner @emmatyping
|
|||
Modules/Setup* @erlend-aasland @AA-Turner @emmatyping
|
||||
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
|
||||
|
|
|
|||
3
.github/actionlint.yaml
vendored
3
.github/actionlint.yaml
vendored
|
|
@ -1,6 +1,7 @@
|
|||
self-hosted-runner:
|
||||
# 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
|
||||
|
||||
|
|
|
|||
27
.github/workflows/build.yml
vendored
27
.github/workflows/build.yml
vendored
|
|
@ -202,24 +202,16 @@ jobs:
|
|||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
# Cirrus and macos-14 are M1, macos-13 is default GHA Intel.
|
||||
# macOS 13 only runs tests against the GIL-enabled CPython.
|
||||
# Cirrus used for upstream, macos-14 for forks.
|
||||
# macos-14 is M1, macos-15-intel is Intel.
|
||||
# macos-15-intel only runs tests against the GIL-enabled CPython.
|
||||
os:
|
||||
- ghcr.io/cirruslabs/macos-runner:sonoma
|
||||
- macos-14
|
||||
- macos-13
|
||||
is-fork: # only used for the exclusion trick
|
||||
- ${{ github.repository_owner != 'python' }}
|
||||
- macos-15-intel
|
||||
free-threading:
|
||||
- false
|
||||
- true
|
||||
exclude:
|
||||
- os: ghcr.io/cirruslabs/macos-runner:sonoma
|
||||
is-fork: true
|
||||
- os: macos-14
|
||||
is-fork: false
|
||||
- os: macos-13
|
||||
- os: macos-15-intel
|
||||
free-threading: true
|
||||
uses: ./.github/workflows/reusable-macos.yml
|
||||
with:
|
||||
|
|
@ -273,7 +265,7 @@ jobs:
|
|||
# Keep 1.1.1w in our list despite it being upstream EOL and otherwise
|
||||
# unsupported as it most resembles other 1.1.1-work-a-like ssl APIs
|
||||
# supported by important vendors such as AWS-LC.
|
||||
openssl_ver: [1.1.1w, 3.0.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
|
||||
env:
|
||||
OPENSSL_VER: ${{ matrix.openssl_ver }}
|
||||
|
|
@ -409,9 +401,8 @@ jobs:
|
|||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
# Use the same runs-on configuration as build-macos and build-ubuntu.
|
||||
- arch: aarch64
|
||||
runs-on: ${{ github.repository_owner == 'python' && 'ghcr.io/cirruslabs/macos-runner:sonoma' || 'macos-14' }}
|
||||
runs-on: macos-14
|
||||
- arch: x86_64
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
|
|
@ -421,7 +412,7 @@ jobs:
|
|||
with:
|
||||
persist-credentials: false
|
||||
- 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:
|
||||
name: 'WASI'
|
||||
|
|
@ -438,7 +429,7 @@ jobs:
|
|||
needs: build-context
|
||||
if: needs.build-context.outputs.run-tests == 'true'
|
||||
env:
|
||||
OPENSSL_VER: 3.0.16
|
||||
OPENSSL_VER: 3.0.18
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
|
@ -558,7 +549,7 @@ jobs:
|
|||
matrix:
|
||||
os: [ubuntu-24.04]
|
||||
env:
|
||||
OPENSSL_VER: 3.0.16
|
||||
OPENSSL_VER: 3.0.18
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
ASAN_OPTIONS: detect_leaks=0:allocator_may_return_null=1:handle_segv=0
|
||||
steps:
|
||||
|
|
|
|||
7
.github/workflows/jit.yml
vendored
7
.github/workflows/jit.yml
vendored
|
|
@ -81,7 +81,7 @@ jobs:
|
|||
runner: windows-11-arm
|
||||
- target: x86_64-apple-darwin/clang
|
||||
architecture: x86_64
|
||||
runner: macos-13
|
||||
runner: macos-15-intel
|
||||
- target: aarch64-apple-darwin/clang
|
||||
architecture: aarch64
|
||||
runner: macos-14
|
||||
|
|
@ -106,15 +106,10 @@ jobs:
|
|||
./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
|
||||
|
||||
# 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
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
||||
brew install llvm@${{ matrix.llvm }}
|
||||
export SDKROOT="$(xcrun --show-sdk-path)"
|
||||
# Set MACOSX_DEPLOYMENT_TARGET and -Werror=unguarded-availability to
|
||||
|
|
|
|||
31
.github/workflows/project-updater.yml
vendored
31
.github/workflows/project-updater.yml
vendored
|
|
@ -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 }}
|
||||
6
.github/workflows/reusable-macos.yml
vendored
6
.github/workflows/reusable-macos.yml
vendored
|
|
@ -60,15 +60,15 @@ jobs:
|
|||
--prefix=/opt/python-dev \
|
||||
--with-openssl="$(brew --prefix openssl@3.0)"
|
||||
- name: Build CPython
|
||||
if : ${{ inputs.free-threading || inputs.os != 'macos-13' }}
|
||||
if : ${{ inputs.free-threading || inputs.os != 'macos-15-intel' }}
|
||||
run: gmake -j8
|
||||
- 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
|
||||
- name: Display build info
|
||||
run: make pythoninfo
|
||||
- name: Check compiler warnings
|
||||
if : ${{ !inputs.free-threading && inputs.os == 'macos-13' }}
|
||||
if : ${{ !inputs.free-threading && inputs.os == 'macos-15-intel' }}
|
||||
run: >-
|
||||
python3 Tools/build/check_warnings.py
|
||||
--compiler-output-file-path=compiler_output_macos.txt
|
||||
|
|
|
|||
2
.github/workflows/reusable-ubuntu.yml
vendored
2
.github/workflows/reusable-ubuntu.yml
vendored
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
runs-on: ${{ inputs.os }}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
OPENSSL_VER: 3.0.15
|
||||
OPENSSL_VER: 3.0.18
|
||||
PYTHONSTRICTEXTENSIONBUILD: 1
|
||||
TERM: linux
|
||||
steps:
|
||||
|
|
|
|||
9
.github/workflows/tail-call.yml
vendored
9
.github/workflows/tail-call.yml
vendored
|
|
@ -58,7 +58,7 @@ jobs:
|
|||
# runner: windows-2022
|
||||
- target: x86_64-apple-darwin/clang
|
||||
architecture: x86_64
|
||||
runner: macos-13
|
||||
runner: macos-15-intel
|
||||
- target: aarch64-apple-darwin/clang
|
||||
architecture: aarch64
|
||||
runner: macos-14
|
||||
|
|
@ -101,17 +101,10 @@ jobs:
|
|||
set LLVMInstallDir=C:\Program Files\LLVM
|
||||
./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)
|
||||
if: runner.os == 'macOS'
|
||||
run: |
|
||||
brew update
|
||||
find /usr/local/bin -lname '*/Library/Frameworks/Python.framework/*' -delete
|
||||
brew install llvm@${{ matrix.llvm }}
|
||||
export SDKROOT="$(xcrun --show-sdk-path)"
|
||||
export PATH="/usr/local/opt/llvm@${{ matrix.llvm }}/bin:$PATH"
|
||||
|
|
|
|||
|
|
@ -26,6 +26,10 @@ repos:
|
|||
name: Run Ruff (lint) on Tools/peg_generator/
|
||||
args: [--exit-non-zero-on-fix, --config=Tools/peg_generator/.ruff.toml]
|
||||
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
|
||||
name: Run Ruff (format) on Doc/
|
||||
args: [--check]
|
||||
|
|
@ -34,6 +38,10 @@ repos:
|
|||
name: Run Ruff (format) on Tools/build/check_warnings.py
|
||||
args: [--check, --config=Tools/build/.ruff.toml]
|
||||
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
|
||||
rev: 25.9.0
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import asyncio
|
||||
import argparse
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
|
|
@ -184,10 +185,16 @@ def make_build_python(context):
|
|||
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):
|
||||
os.chdir(prefix_dir)
|
||||
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"]:
|
||||
filename = f"{name_ver}-{host}.tar.gz"
|
||||
download(f"{deps_url}/{name_ver}/{filename}")
|
||||
|
|
@ -546,27 +553,33 @@ async def gradle_task(context):
|
|||
task_prefix = "connected"
|
||||
env["ANDROID_SERIAL"] = context.connected
|
||||
|
||||
if context.command:
|
||||
mode = "-c"
|
||||
module = context.command
|
||||
else:
|
||||
mode = "-m"
|
||||
module = context.module or "test"
|
||||
if context.ci_mode:
|
||||
context.args[0:0] = [
|
||||
# See _add_ci_python_opts in libregrtest/main.py.
|
||||
"-W", "error", "-bb", "-E",
|
||||
|
||||
# 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 = [
|
||||
gradlew, "--console", "plain", f"{task_prefix}DebugAndroidTest",
|
||||
] + [
|
||||
# Build-time properties
|
||||
f"-Ppython.{name}={value}"
|
||||
f"-P{name}={value}"
|
||||
for name, value in [
|
||||
("sitePackages", context.site_packages), ("cwd", context.cwd)
|
||||
] if value
|
||||
] + [
|
||||
# Runtime properties
|
||||
f"-Pandroid.testInstrumentationRunnerArguments.python{name}={value}"
|
||||
for name, value in [
|
||||
("Mode", mode), ("Module", module), ("Args", join_command(context.args))
|
||||
] if value
|
||||
("python.sitePackages", context.site_packages),
|
||||
("python.cwd", context.cwd),
|
||||
(
|
||||
"android.testInstrumentationRunnerArguments.pythonArgs",
|
||||
json.dumps(context.args),
|
||||
),
|
||||
]
|
||||
if value
|
||||
]
|
||||
if context.verbose >= 2:
|
||||
args.append("--info")
|
||||
|
|
@ -734,15 +747,14 @@ def ci(context):
|
|||
else:
|
||||
with TemporaryDirectory(prefix=SCRIPT_NAME) as temp_dir:
|
||||
print("::group::Tests")
|
||||
|
||||
# Prove the package is self-contained by using it to run the tests.
|
||||
shutil.unpack_archive(package_path, temp_dir)
|
||||
|
||||
# Randomization is disabled because order-dependent failures are
|
||||
# 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"]
|
||||
launcher_args = [
|
||||
"--managed", "maxVersion", "-v", f"--{context.ci_mode}-ci"
|
||||
]
|
||||
run(
|
||||
["./android.py", "test", *launcher_args, "--", *test_args],
|
||||
["./android.py", "test", *launcher_args],
|
||||
cwd=temp_dir
|
||||
)
|
||||
print("::endgroup::")
|
||||
|
|
@ -825,18 +837,11 @@ def add_parser(*args, **kwargs):
|
|||
test.add_argument(
|
||||
"--cwd", metavar="DIR", type=abspath,
|
||||
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(
|
||||
"args", nargs="*", help=f"Arguments to add to sys.argv. "
|
||||
f"Separate them from {SCRIPT_NAME}'s own arguments with `--`.")
|
||||
"args", nargs="*", help=f"Python command-line arguments. "
|
||||
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.
|
||||
for subcommand in [package, ci]:
|
||||
|
|
@ -844,6 +849,16 @@ def add_parser(*args, **kwargs):
|
|||
"-g", action="store_true", default=False, dest="debug",
|
||||
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()
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@ class PythonSuite {
|
|||
val status = PythonTestRunner(
|
||||
InstrumentationRegistry.getInstrumentation().targetContext
|
||||
).run(
|
||||
InstrumentationRegistry.getArguments()
|
||||
InstrumentationRegistry.getArguments().getString("pythonArgs")!!,
|
||||
)
|
||||
assertEquals(0, status)
|
||||
} finally {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
#include <jni.h>
|
||||
#include <pthread.h>
|
||||
#include <Python.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
|
|
@ -15,6 +16,13 @@ static void throw_runtime_exception(JNIEnv *env, const char *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 ------------------------------------------------------
|
||||
|
||||
|
|
@ -95,10 +103,7 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL
|
|||
for (StreamInfo *si = STREAMS; si->file; si++) {
|
||||
char *error_prefix;
|
||||
if ((error_prefix = redirect_stream(si))) {
|
||||
char error_message[1024];
|
||||
snprintf(error_message, sizeof(error_message),
|
||||
"%s: %s", error_prefix, strerror(errno));
|
||||
throw_runtime_exception(env, error_message);
|
||||
throw_errno(env, error_prefix);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
@ -107,13 +112,38 @@ JNIEXPORT void JNICALL Java_org_python_testbed_PythonTestRunner_redirectStdioToL
|
|||
|
||||
// --- Python initialization ---------------------------------------------------
|
||||
|
||||
static PyStatus set_config_string(
|
||||
JNIEnv *env, PyConfig *config, wchar_t **config_str, jstring value
|
||||
) {
|
||||
const char *value_utf8 = (*env)->GetStringUTFChars(env, value, NULL);
|
||||
PyStatus status = PyConfig_SetBytesString(config, config_str, value_utf8);
|
||||
(*env)->ReleaseStringUTFChars(env, value, value_utf8);
|
||||
return status;
|
||||
static char *init_signals() {
|
||||
// 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.
|
||||
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) {
|
||||
|
|
@ -121,27 +151,47 @@ static void throw_status(JNIEnv *env, PyStatus status) {
|
|||
}
|
||||
|
||||
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;
|
||||
PyStatus status;
|
||||
PyConfig_InitIsolatedConfig(&config);
|
||||
PyConfig_InitPythonConfig(&config);
|
||||
|
||||
status = set_config_string(env, &config, &config.home, home);
|
||||
if (PyStatus_Exception(status)) {
|
||||
jsize argc = (*env)->GetArrayLength(env, args);
|
||||
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);
|
||||
return 1;
|
||||
}
|
||||
|
||||
status = set_config_string(env, &config, &config.run_module, runModule);
|
||||
status = PyConfig_SetBytesString(&config, &config.home, home_utf8);
|
||||
if (PyStatus_Exception(status)) {
|
||||
throw_status(env, status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Some tests generate SIGPIPE and SIGXFSZ, which should be ignored.
|
||||
config.install_signal_handlers = 1;
|
||||
|
||||
status = Py_InitializeFromConfig(&config);
|
||||
if (PyStatus_Exception(status)) {
|
||||
throw_status(env, status);
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import android.os.*
|
|||
import android.system.Os
|
||||
import android.widget.TextView
|
||||
import androidx.appcompat.app.*
|
||||
import org.json.JSONArray
|
||||
import java.io.*
|
||||
|
||||
|
||||
|
|
@ -15,30 +16,25 @@ class MainActivity : AppCompatActivity() {
|
|||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class PythonTestRunner(val context: Context) {
|
||||
fun run(instrumentationArgs: Bundle) = run(
|
||||
instrumentationArgs.getString("pythonMode")!!,
|
||||
instrumentationArgs.getString("pythonModule")!!,
|
||||
instrumentationArgs.getString("pythonArgs") ?: "",
|
||||
)
|
||||
|
||||
/** Run Python.
|
||||
*
|
||||
* @param mode Either "-c" or "-m".
|
||||
* @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`.
|
||||
* @param args Python command-line, encoded as JSON.
|
||||
* @return The Python exit status: zero on success, nonzero on failure. */
|
||||
fun run(mode: String, module: String, args: String) : Int {
|
||||
Os.setenv("PYTHON_MODE", mode, true)
|
||||
Os.setenv("PYTHON_MODULE", module, true)
|
||||
Os.setenv("PYTHON_ARGS", args, true)
|
||||
fun run(args: String) : Int {
|
||||
// We leave argument 0 as an empty string, which is a placeholder for the
|
||||
// executable name in embedded mode.
|
||||
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,
|
||||
// but Android only sets it on API level 33 and later.
|
||||
|
|
@ -47,10 +43,7 @@ class PythonTestRunner(val context: Context) {
|
|||
val pythonHome = extractAssets()
|
||||
System.loadLibrary("main_activity")
|
||||
redirectStdioToLogcat()
|
||||
|
||||
// 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")
|
||||
return runPython(pythonHome.toString(), argsStringArray)
|
||||
}
|
||||
|
||||
private fun extractAssets() : File {
|
||||
|
|
@ -59,6 +52,13 @@ class PythonTestRunner(val context: Context) {
|
|||
throw RuntimeException("Failed to delete $pythonHome")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -88,5 +88,5 @@ class PythonTestRunner(val context: Context) {
|
|||
}
|
||||
|
||||
private external fun redirectStdioToLogcat()
|
||||
private external fun runPython(home: String, runModule: String) : Int
|
||||
private external fun runPython(home: String, args: Array<String>) : Int
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}")
|
||||
|
|
@ -312,11 +312,18 @@ def unpack_deps(
|
|||
On iOS, as a safety mechanism, any dynamic libraries will be purged from
|
||||
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"
|
||||
for name_ver in [
|
||||
"BZip2-1.0.8-2",
|
||||
"libFFI-3.4.7-2",
|
||||
"OpenSSL-3.0.17-1",
|
||||
"OpenSSL-3.0.18-1",
|
||||
"XZ-5.6.4-2",
|
||||
"mpdecimal-4.0.0-2",
|
||||
"zstd-1.5.7-1",
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ venv:
|
|||
fi
|
||||
|
||||
.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
|
||||
dist:
|
||||
|
|
|
|||
|
|
@ -260,7 +260,7 @@ Create, Finish, Discard
|
|||
writer size to *size*. The caller is responsible to write *size*
|
||||
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.
|
||||
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ There are a few functions specific to Python functions.
|
|||
|
||||
.. versionadded:: 3.12
|
||||
|
||||
- ``PyFunction_PYFUNC_EVENT_MODIFY_QUALNAME``
|
||||
|
||||
.. versionadded:: 3.15
|
||||
|
||||
.. c:type:: int (*PyFunction_WatchCallback)(PyFunction_WatchEvent event, PyFunctionObject *func, PyObject *new_value)
|
||||
|
||||
|
|
|
|||
|
|
@ -1113,7 +1113,7 @@ code, or when embedding the Python interpreter:
|
|||
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.
|
||||
|
||||
.. seealso:
|
||||
.. seealso::
|
||||
:c:func:`PyEval_ReleaseThread`
|
||||
|
||||
.. note::
|
||||
|
|
@ -1124,6 +1124,19 @@ code, or when embedding the Python interpreter:
|
|||
The following functions use thread-local storage, and are not compatible
|
||||
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()
|
||||
|
||||
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.
|
||||
|
||||
.. note::
|
||||
This function does not account for :term:`thread states <thread state>` created
|
||||
by something other than :c:func:`PyGILState_Ensure` (such as :c:func:`PyThreadState_New`).
|
||||
This function may return non-``NULL`` even when the :term:`thread state`
|
||||
is detached.
|
||||
Prefer :c:func:`PyThreadState_Get` or :c:func:`PyThreadState_GetUnchecked`
|
||||
for most cases.
|
||||
|
||||
.. seealso: :c:func:`PyThreadState_Get``
|
||||
.. seealso:: :c:func:`PyThreadState_Get`
|
||||
|
||||
.. 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>`
|
||||
|
||||
.. 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`.
|
||||
|
||||
.. 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)
|
||||
|
|
|
|||
|
|
@ -37,6 +37,19 @@ Tuple Objects
|
|||
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, ...)
|
||||
|
||||
Return a new tuple object of size *n*,
|
||||
|
|
|
|||
|
|
@ -15,7 +15,6 @@ although there is currently no date scheduled for their removal.
|
|||
|
||||
* :mod:`builtins`:
|
||||
|
||||
* ``bool(NotImplemented)``.
|
||||
* Generators: ``throw(type, exc, tb)`` and ``athrow(type, exc, tb)``
|
||||
signature is deprecated: use ``throw(exc)`` and ``athrow(exc)`` instead,
|
||||
the single argument signature.
|
||||
|
|
|
|||
|
|
@ -316,13 +316,14 @@ StreamWriter
|
|||
If that fails, the data is queued in an internal write buffer until it can be
|
||||
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::
|
||||
|
||||
stream.write(data)
|
||||
await stream.drain()
|
||||
|
||||
.. note::
|
||||
The *data* buffer should be a C contiguous one-dimensional :term:`bytes-like object <bytes-like object>`.
|
||||
|
||||
.. method:: writelines(data)
|
||||
|
||||
|
|
|
|||
|
|
@ -336,7 +336,7 @@ Collections Abstract Base Classes -- Detailed Descriptions
|
|||
|
||||
.. note::
|
||||
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.
|
||||
Using ``isinstance(gencoro, Awaitable)`` for them will return ``False``.
|
||||
Use :func:`inspect.isawaitable` to detect them.
|
||||
|
|
@ -354,7 +354,7 @@ Collections Abstract Base Classes -- Detailed Descriptions
|
|||
|
||||
.. note::
|
||||
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.
|
||||
Using ``isinstance(gencoro, Coroutine)`` for them will return ``False``.
|
||||
Use :func:`inspect.isawaitable` to detect them.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
The :mod:`!compression` package
|
||||
===============================
|
||||
|
||||
.. module:: compression
|
||||
|
||||
.. versionadded:: 3.14
|
||||
|
||||
The :mod:`!compression` package contains the canonical compression modules
|
||||
|
|
|
|||
|
|
@ -327,10 +327,10 @@ Functions and classes provided:
|
|||
.. function:: redirect_stdout(new_target)
|
||||
|
||||
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
|
||||
is hardwired to stdout.
|
||||
is hardwired to :data:`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
|
||||
|
|
@ -366,8 +366,8 @@ Functions and classes provided:
|
|||
|
||||
.. function:: redirect_stderr(new_target)
|
||||
|
||||
Similar to :func:`~contextlib.redirect_stdout` but redirecting
|
||||
:data:`sys.stderr` to another file or file-like object.
|
||||
Similar to :func:`~contextlib.redirect_stdout` but redirecting the global
|
||||
:data:`sys.stderr` to another :term:`file object`.
|
||||
|
||||
This context manager is :ref:`reentrant <reentrant-cms>`.
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
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.
|
||||
|
||||
The last version of Python that provided the :mod:`!crypt` module was
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ Module contents
|
|||
:func:`!field`, then the class attribute for this field will be
|
||||
replaced by the specified *default* value. If *default* is not
|
||||
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
|
||||
as if the default value itself were specified. For example,
|
||||
after::
|
||||
|
|
@ -427,7 +427,7 @@ Module contents
|
|||
:data:`typing.Any` is used for ``type``. The values of *init*,
|
||||
*repr*, *eq*, *order*, *unsafe_hash*, *frozen*,
|
||||
*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
|
||||
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.
|
||||
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.
|
||||
|
||||
This function is not strictly required, because any Python
|
||||
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
|
||||
example::
|
||||
|
||||
|
|
@ -569,7 +569,7 @@ Post-init processing
|
|||
def __post_init__(self):
|
||||
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
|
||||
that has to be called, it is common to call this method in a
|
||||
:meth:`__post_init__` method::
|
||||
|
|
@ -599,7 +599,7 @@ parameters to :meth:`!__post_init__`. Also see the warning about how
|
|||
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
|
||||
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
|
||||
|
|
@ -612,7 +612,7 @@ module-level :func:`fields` function.
|
|||
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
|
||||
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
|
||||
|
|
@ -646,7 +646,7 @@ Frozen instances
|
|||
----------------
|
||||
|
||||
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
|
||||
:meth:`~object.__setattr__` and :meth:`~object.__delattr__` methods to the class. These
|
||||
methods will raise a :exc:`FrozenInstanceError` when invoked.
|
||||
|
|
@ -662,7 +662,7 @@ must use :meth:`!object.__setattr__`.
|
|||
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
|
||||
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.
|
||||
|
|
@ -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
|
||||
creation they also share this behavior. There is no general way
|
||||
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
|
||||
a value is unhashable, it is mutable. This is a partial solution,
|
||||
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
|
||||
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
|
||||
form: ``descriptor.__get__(obj=None, type=cls)``. If the
|
||||
descriptor returns a value in this case, it will be used as the
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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
|
||||
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
|
||||
analysis of which lines are so frequent as to constitute noise, and this
|
||||
usually works better than using this function.
|
||||
|
|
|
|||
|
|
@ -690,7 +690,7 @@ The :mod:`functools` module defines the following functions:
|
|||
return not arg
|
||||
|
||||
``@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*
|
||||
decorator. Here is the ``Negator`` class with the ``neg`` methods bound to
|
||||
the class, rather than an instance of the class::
|
||||
|
|
@ -712,8 +712,7 @@ The :mod:`functools` module defines the following functions:
|
|||
return not arg
|
||||
|
||||
The same pattern can be used for other similar decorators:
|
||||
:func:`@staticmethod<staticmethod>`,
|
||||
:func:`@abstractmethod<abc.abstractmethod>`, and others.
|
||||
:deco:`staticmethod`, :deco:`~abc.abstractmethod`, and others.
|
||||
|
||||
.. versionadded:: 3.8
|
||||
|
||||
|
|
|
|||
|
|
@ -72,13 +72,12 @@ for example, a package and its resources can be imported from a zip file using
|
|||
|
||||
.. versionadded:: 3.9
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
*package* parameter was renamed to *anchor*. *anchor* can now
|
||||
be a non-package module and if omitted will default to the caller's
|
||||
module. *package* is still accepted for compatibility but will raise
|
||||
a :exc:`DeprecationWarning`. Consider passing the anchor positionally or
|
||||
using ``importlib_resources >= 5.10`` for a compatible interface
|
||||
on older Pythons.
|
||||
.. deprecated-removed:: 3.12 3.15
|
||||
*package* parameter was renamed to *anchor*. *anchor* can now be a
|
||||
non-package module and if omitted will default to the caller's module.
|
||||
*package* is no longer accepted since Python 3.15. Consider passing the
|
||||
anchor positionally or using ``importlib_resources >= 5.10`` for a
|
||||
compatible interface on older Pythons.
|
||||
|
||||
.. function:: as_file(traversable)
|
||||
|
||||
|
|
|
|||
|
|
@ -216,8 +216,8 @@ process and user.
|
|||
|
||||
You can delete items in this mapping to unset environment variables.
|
||||
: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
|
||||
called.
|
||||
:data:`os.environ`, and when one of the :meth:`~dict.pop` or
|
||||
:meth:`~dict.clear` methods is called.
|
||||
|
||||
.. seealso::
|
||||
|
||||
|
|
@ -430,8 +430,8 @@ process and user.
|
|||
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
|
||||
calls to :func:`setgroups`, and its length is not limited to 16. The
|
||||
deployment target value, :const:`MACOSX_DEPLOYMENT_TARGET`, can be
|
||||
obtained with :func:`sysconfig.get_config_var`.
|
||||
deployment target value can be obtained with
|
||||
:func:`sysconfig.get_config_var('MACOSX_DEPLOYMENT_TARGET') <sysconfig.get_config_var>`.
|
||||
|
||||
|
||||
.. function:: getlogin()
|
||||
|
|
@ -2606,10 +2606,10 @@ features:
|
|||
|
||||
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
|
||||
to be created, being combined (bitwise OR) with one of ``stat.S_IFREG``,
|
||||
``stat.S_IFCHR``, ``stat.S_IFBLK``, and ``stat.S_IFIFO`` (those constants are
|
||||
available in :mod:`stat`). For ``stat.S_IFCHR`` and ``stat.S_IFBLK``,
|
||||
*device* defines the newly created device special file (probably using
|
||||
to be created, being combined (bitwise OR) with one of :const:`stat.S_IFREG`,
|
||||
:const:`stat.S_IFCHR`, :const:`stat.S_IFBLK`, and :const:`stat.S_IFIFO`.
|
||||
For :const:`stat.S_IFCHR` and :const:`stat.S_IFBLK`, *device* defines the
|
||||
newly created device special file (probably using
|
||||
:func:`os.makedev`), otherwise it is ignored.
|
||||
|
||||
This function can also support :ref:`paths relative to directory descriptors
|
||||
|
|
@ -2627,13 +2627,13 @@ features:
|
|||
.. function:: major(device, /)
|
||||
|
||||
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, /)
|
||||
|
||||
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, /)
|
||||
|
|
@ -3364,8 +3364,8 @@ features:
|
|||
|
||||
.. versionchanged:: 3.8
|
||||
On Windows, the :attr:`st_mode` member now identifies special
|
||||
files as :const:`S_IFCHR`, :const:`S_IFIFO` or :const:`S_IFBLK`
|
||||
as appropriate.
|
||||
files as :const:`~stat.S_IFCHR`, :const:`~stat.S_IFIFO` or
|
||||
:const:`~stat.S_IFBLK` as appropriate.
|
||||
|
||||
.. versionchanged:: 3.12
|
||||
On Windows, :attr:`st_ctime` is deprecated. Eventually, it will
|
||||
|
|
@ -4285,10 +4285,10 @@ to be ignored.
|
|||
|
||||
.. 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
|
||||
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`.
|
||||
|
||||
|
||||
|
|
@ -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
|
||||
: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
|
||||
|
||||
.. 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
|
||||
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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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
|
||||
higher-level system APIs, and that includes using :mod:`urllib.request`.
|
||||
|
||||
.. versionchanged:: next
|
||||
The returned file descriptor is now made non-inheritable.
|
||||
|
||||
|
||||
.. function:: openpty()
|
||||
|
||||
|
|
|
|||
|
|
@ -205,10 +205,26 @@ The variables defined in the :mod:`signal` module are:
|
|||
|
||||
.. availability:: Unix.
|
||||
|
||||
.. data:: SIGPROF
|
||||
|
||||
Profiling timer expired.
|
||||
|
||||
.. availability:: Unix.
|
||||
|
||||
.. data:: SIGQUIT
|
||||
|
||||
Terminal quit signal.
|
||||
|
||||
.. availability:: Unix.
|
||||
|
||||
.. data:: SIGSEGV
|
||||
|
||||
Segmentation fault: invalid memory reference.
|
||||
|
||||
.. data:: SIGSTOP
|
||||
|
||||
Stop executing (cannot be caught or ignored).
|
||||
|
||||
.. data:: SIGSTKFLT
|
||||
|
||||
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.
|
||||
|
||||
.. data:: SIGVTALRM
|
||||
|
||||
Virtual timer expired.
|
||||
|
||||
.. availability:: Unix.
|
||||
|
||||
.. data:: SIGWINCH
|
||||
|
||||
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
|
||||
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
|
||||
':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
|
||||
not all systems define the same set of signal names; only those names defined by
|
||||
the system are defined by this module.
|
||||
|
|
@ -644,9 +666,8 @@ The :mod:`signal` module defines the following functions:
|
|||
*sigset*.
|
||||
|
||||
The return value is an object representing the data contained in the
|
||||
:c:type:`siginfo_t` structure, namely: :attr:`si_signo`, :attr:`si_code`,
|
||||
:attr:`si_errno`, :attr:`si_pid`, :attr:`si_uid`, :attr:`si_status`,
|
||||
:attr:`si_band`.
|
||||
``siginfo_t`` structure, namely: ``si_signo``, ``si_code``,
|
||||
``si_errno``, ``si_pid``, ``si_uid``, ``si_status``, ``si_band``.
|
||||
|
||||
.. availability:: Unix.
|
||||
|
||||
|
|
|
|||
|
|
@ -354,9 +354,8 @@ Random generation
|
|||
.. function:: RAND_status()
|
||||
|
||||
Return ``True`` if the SSL pseudo-random number generator has been seeded
|
||||
with 'enough' randomness, and ``False`` otherwise. You can use
|
||||
:func:`ssl.RAND_egd` and :func:`ssl.RAND_add` to increase the randomness of
|
||||
the pseudo-random number generator.
|
||||
with 'enough' randomness, and ``False`` otherwise. Use :func:`ssl.RAND_add`
|
||||
to increase the randomness of the pseudo-random number generator.
|
||||
|
||||
.. function:: RAND_add(bytes, entropy, /)
|
||||
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ Template strings
|
|||
Template strings are a mechanism for custom string processing.
|
||||
They have the full flexibility of Python's :ref:`f-strings`,
|
||||
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.
|
||||
|
||||
To write a t-string, use a ``'t'`` prefix instead of an ``'f'``, like so:
|
||||
|
|
@ -258,13 +258,16 @@ Types
|
|||
.. attribute:: expression
|
||||
: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
|
||||
interpolation's Python expression, if the interpolation was created
|
||||
from a t-string literal. Developers creating interpolations manually
|
||||
should either set this to an empty string or choose a suitable valid
|
||||
Python expression.
|
||||
We recommend using valid Python expressions or the empty string for the
|
||||
``expression`` field of manually created :class:`!Interpolation`
|
||||
instances, although this is not enforced at runtime.
|
||||
|
||||
>>> t'{1 + 2}'.interpolations[0].expression
|
||||
'1 + 2'
|
||||
|
|
|
|||
|
|
@ -649,7 +649,7 @@ functions.
|
|||
|
||||
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
|
||||
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
|
||||
|
||||
|
|
@ -1473,7 +1473,7 @@ handling consistency are valid for these functions.
|
|||
|
||||
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)``.
|
||||
*encoding* and *errors* are used to decode output;
|
||||
see the notes on :ref:`frequently-used-arguments` for more details.
|
||||
|
|
|
|||
|
|
@ -382,6 +382,9 @@ Other functions
|
|||
|
||||
Examples of returned values:
|
||||
|
||||
- linux-x86_64
|
||||
- linux-aarch64
|
||||
- solaris-2.6-sun4u
|
||||
|
||||
Windows:
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
typechecking of ``T``, as type checkers will simply ignore the metadata ``x``.
|
||||
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
|
||||
completely disables typechecking for a function or class.
|
||||
|
||||
|
|
@ -2269,7 +2269,7 @@ without the dedicated syntax, as documented below.
|
|||
|
||||
.. 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
|
||||
>>> Alias.__module__
|
||||
|
|
@ -2449,7 +2449,7 @@ types.
|
|||
|
||||
.. 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__
|
||||
|
||||
|
|
@ -2815,7 +2815,7 @@ Protocols
|
|||
---------
|
||||
|
||||
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
|
||||
|
||||
|
|
@ -2996,7 +2996,7 @@ Functions and decorators
|
|||
The presence of ``@dataclass_transform()`` tells a static type checker that the
|
||||
decorated object performs runtime "magic" that
|
||||
transforms a class in a similar way to
|
||||
:func:`@dataclasses.dataclass <dataclasses.dataclass>`.
|
||||
:deco:`dataclasses.dataclass`.
|
||||
|
||||
Example usage with a decorator function:
|
||||
|
||||
|
|
@ -3034,14 +3034,14 @@ Functions and decorators
|
|||
|
||||
The ``CustomerModel`` classes defined above will
|
||||
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
|
||||
``__init__`` methods that accept ``id`` and ``name``.
|
||||
|
||||
The decorated class, metaclass, or function may accept the following bool
|
||||
arguments which type checkers will assume have the same effect as they
|
||||
would have on the
|
||||
:func:`@dataclasses.dataclass<dataclasses.dataclass>` decorator: ``init``,
|
||||
:deco:`dataclasses.dataclass` decorator: ``init``,
|
||||
``eq``, ``order``, ``unsafe_hash``, ``frozen``, ``match_args``,
|
||||
``kw_only``, and ``slots``. It must be possible for the value of these
|
||||
arguments (``True`` or ``False``) to be statically evaluated.
|
||||
|
|
@ -3169,12 +3169,12 @@ Functions and decorators
|
|||
|
||||
.. 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* is the function object for the implementation of the
|
||||
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
|
||||
for the three defined overloads. If called on a function with no overloads,
|
||||
``get_overloads()`` returns an empty sequence.
|
||||
|
|
@ -3331,7 +3331,7 @@ Introspection helpers
|
|||
If *globalns* or *localns* is not given, appropriate namespace
|
||||
dictionaries are inferred from *obj*.
|
||||
* ``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.
|
||||
* 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
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ Available Functions
|
|||
The deprecation message passed to the decorator is saved in the
|
||||
``__deprecated__`` attribute on the decorated object.
|
||||
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
|
||||
:func:`typing.get_overloads`.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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.
|
||||
|
||||
For reading and writing ``.gz`` files see the :mod:`gzip` module.
|
||||
|
|
@ -340,6 +340,136 @@ Decompression objects support the following methods and attributes:
|
|||
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
|
||||
the following constants:
|
||||
|
||||
|
|
@ -375,10 +505,10 @@ the following constants:
|
|||
Module :mod:`gzip`
|
||||
Reading and writing :program:`gzip`\ -format files.
|
||||
|
||||
http://www.zlib.net
|
||||
https://www.zlib.net
|
||||
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
|
||||
functions.
|
||||
|
||||
|
|
|
|||
|
|
@ -2558,7 +2558,7 @@ instance dictionary. In contrast, non-data descriptors can be overridden by
|
|||
instances.
|
||||
|
||||
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
|
||||
override methods. This allows individual instances to acquire behaviors that
|
||||
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
|
||||
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__*
|
||||
|
|
|
|||
|
|
@ -10,12 +10,76 @@ Lexical analysis
|
|||
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
|
||||
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
|
||||
can be given by an encoding declaration and defaults to UTF-8, see :pep:`3120`
|
||||
for details. If the source file cannot be decoded, a :exc:`SyntaxError` is
|
||||
raised.
|
||||
The lexical analyzer determines the program text's :ref:`encoding <encodings>`
|
||||
(UTF-8 by default), and decodes the text into
|
||||
:ref:`source characters <lexical-source-character>`.
|
||||
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:
|
||||
|
|
@ -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
|
||||
and identifiers.
|
||||
|
||||
.. _lexical-source-character:
|
||||
|
||||
All lexical analysis, including string literals, comments
|
||||
and identifiers, works on Unicode text decoded using the source encoding.
|
||||
Any Unicode code point, except the NUL control character, can appear in
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
Doc/c-api/descriptor.rst
|
||||
Doc/c-api/float.rst
|
||||
Doc/c-api/init.rst
|
||||
Doc/c-api/init_config.rst
|
||||
Doc/c-api/intro.rst
|
||||
Doc/c-api/module.rst
|
||||
|
|
@ -30,12 +29,10 @@ Doc/library/profile.rst
|
|||
Doc/library/pyexpat.rst
|
||||
Doc/library/resource.rst
|
||||
Doc/library/select.rst
|
||||
Doc/library/signal.rst
|
||||
Doc/library/smtplib.rst
|
||||
Doc/library/socket.rst
|
||||
Doc/library/ssl.rst
|
||||
Doc/library/stdtypes.rst
|
||||
Doc/library/subprocess.rst
|
||||
Doc/library/termios.rst
|
||||
Doc/library/test.rst
|
||||
Doc/library/tkinter.rst
|
||||
|
|
@ -53,7 +50,6 @@ Doc/library/xml.sax.reader.rst
|
|||
Doc/library/xml.sax.rst
|
||||
Doc/library/xmlrpc.client.rst
|
||||
Doc/library/xmlrpc.server.rst
|
||||
Doc/library/zlib.rst
|
||||
Doc/whatsnew/2.4.rst
|
||||
Doc/whatsnew/2.5.rst
|
||||
Doc/whatsnew/2.6.rst
|
||||
|
|
|
|||
|
|
@ -42,22 +42,22 @@ <h1>{% trans %}Download Python {{ dl_version }} documentation{% endtrans %}</h1>
|
|||
</tr>
|
||||
<tr>
|
||||
<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 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.zip">Download</a>{% endtrans %}</td>
|
||||
<td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-html.tar.bz2">Download</a>{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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 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.zip">Download</a>{% endtrans %}</td>
|
||||
<td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-text.tar.bz2">Download</a>{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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 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.zip">Download</a>{% endtrans %}</td>
|
||||
<td>{% trans %}<a href="{{ dl_base }}/python-{{ dl_version }}-docs-texinfo.tar.bz2">Download</a>{% endtrans %}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<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>
|
||||
</tr>
|
||||
</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.
|
||||
{% endtrans %}</p>
|
||||
|
||||
|
||||
<h2>{% trans %}Unpacking{% endtrans %}</h2>
|
||||
|
||||
<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>
|
||||
<p>{% trans %}
|
||||
See the <a href="https://docs.python.org/{{ version }}/archives/">directory listing</a>
|
||||
for file sizes.{% endtrans %}</p>
|
||||
|
||||
|
||||
<h2>{% trans %}Problems{% endtrans %}</h2>
|
||||
|
||||
<p>{% trans %}If you have comments or suggestions for the Python documentation, please send
|
||||
email to <a href="mailto:docs@python.org">docs@python.org</a>.{% endtrans %}</p>
|
||||
{% set bugs = pathto('bugs') %}
|
||||
<p>{% trans bugs = bugs %}<a href="{{ bugs }}">Open an issue</a>
|
||||
if you have comments or suggestions for the Python documentation.{% endtrans %}</p>
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
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
|
||||
value associated with that key is forgotten. It is an error to extract a value
|
||||
using a non-existent key.
|
||||
value associated with that key is forgotten.
|
||||
|
||||
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
|
||||
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}
|
||||
>>> tel['jack']
|
||||
4098
|
||||
>>> tel['irv']
|
||||
Traceback (most recent call last):
|
||||
File "<stdin>", line 1, in <module>
|
||||
KeyError: 'irv'
|
||||
>>> print(tel.get('irv'))
|
||||
None
|
||||
>>> del tel['sape']
|
||||
>>> tel['irv'] = 4127
|
||||
>>> tel
|
||||
|
|
|
|||
|
|
@ -22,16 +22,51 @@ Features and minimum versions required to build CPython:
|
|||
|
||||
* Support for threads.
|
||||
|
||||
* OpenSSL 1.1.1 is the minimum version and OpenSSL 3.0.16 is the recommended
|
||||
minimum version for the :mod:`ssl` and :mod:`hashlib` extension modules.
|
||||
To build optional 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
|
||||
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
|
||||
:file:`configure` script.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
or syntax. When it's not possible to do that, Python 2.6 tries to do
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
compatible with 3.0 can do ``from future_builtins import hex, map`` as
|
||||
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
|
||||
with this switch to see how much work will be necessary to port
|
||||
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`.
|
||||
|
||||
.. 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
|
||||
block is complete.
|
||||
|
||||
The :func:`localcontext` function in the :mod:`decimal` module makes it easy
|
||||
to save and restore the current decimal context, which encapsulates the desired
|
||||
precision and rounding characteristics for computations::
|
||||
The :func:`~decimal.localcontext` function in the :mod:`decimal` module makes
|
||||
it easy to save and restore the current decimal context, which encapsulates
|
||||
the desired precision and rounding characteristics for computations::
|
||||
|
||||
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:
|
||||
|
||||
* 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__`
|
||||
methods.
|
||||
manager". The context manager must have :meth:`~object.__enter__` and
|
||||
:meth:`~object.__exit__` methods.
|
||||
|
||||
* The context manager's :meth:`~object.__enter__` method is called. The value returned
|
||||
is assigned to *VAR*. If no ``as VAR`` clause is present, the value is simply
|
||||
discarded.
|
||||
* The context manager's :meth:`~object.__enter__` method is called. The value
|
||||
returned is assigned to *VAR*. If no ``as VAR`` clause is present, the
|
||||
value is simply discarded.
|
||||
|
||||
* 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
|
||||
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:
|
||||
# Database interface
|
||||
|
|
@ -431,14 +431,15 @@ The contextlib module
|
|||
The :mod:`contextlib` module provides some functions and a decorator that
|
||||
are useful when writing objects for use with the ':keyword:`with`' statement.
|
||||
|
||||
The decorator is called :func:`contextmanager`, and lets you write a single
|
||||
generator function instead of defining a new class. The generator should yield
|
||||
exactly one value. The code up to the :keyword:`yield` will be executed as the
|
||||
:meth:`~object.__enter__` method, and the value yielded will be the method's return
|
||||
value that will get bound to the variable in the ':keyword:`with`' statement's
|
||||
:keyword:`!as` clause, if any. The code after the :keyword:`!yield` will be
|
||||
executed in the :meth:`~object.__exit__` method. Any exception raised in the block will
|
||||
be raised by the :keyword:`!yield` statement.
|
||||
The decorator is called :func:`~contextlib.contextmanager`, and lets you write
|
||||
a single generator function instead of defining a new class. The generator
|
||||
should yield exactly one value. The code up to the :keyword:`yield` will be
|
||||
executed as the :meth:`~object.__enter__` method, and the value yielded will
|
||||
be the method's return value that will get bound to the variable in the
|
||||
':keyword:`with`' statement's :keyword:`!as` clause, if any. The code after
|
||||
the :keyword:`!yield` will be executed in the :meth:`~object.__exit__` method.
|
||||
Any exception raised in the block will be raised by the :keyword:`!yield`
|
||||
statement.
|
||||
|
||||
Using this decorator, our database example from the previous section
|
||||
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):
|
||||
...
|
||||
|
||||
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
|
||||
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
|
||||
directory used for all Python versions supporting this feature. On
|
||||
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.
|
||||
|
||||
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
|
||||
goal was discarded along the path to Python 2.6, but the general
|
||||
approach of the module is still similar. The fundamental class
|
||||
is the :class:`Process`, which is passed a callable object and
|
||||
a collection of arguments. The :meth:`start` method
|
||||
is the :class:`~multiprocessing.Process`, which is passed a callable object and
|
||||
a collection of arguments. The :meth:`~multiprocessing.Process.start` method
|
||||
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
|
||||
and the :meth:`join` method to wait for the process to exit.
|
||||
the :meth:`~multiprocessing.Process.is_alive` method to check whether the
|
||||
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
|
||||
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
|
||||
versa.)
|
||||
|
||||
Two other classes, :class:`Pool` and :class:`Manager`, provide
|
||||
higher-level interfaces. :class:`Pool` will create a fixed number of
|
||||
worker processes, and requests can then be distributed to the workers
|
||||
by calling :meth:`apply` or :meth:`apply_async` to add a single request,
|
||||
and :meth:`map` or :meth:`map_async` to add a number of
|
||||
requests. The following code uses a :class:`Pool` to spread requests
|
||||
across 5 worker processes and retrieve a list of results::
|
||||
Two other classes, :class:`~multiprocessing.pool.Pool` and
|
||||
:class:`~multiprocessing.Manager`, provide higher-level interfaces.
|
||||
:class:`~multiprocessing.pool.Pool` will create a fixed number of worker
|
||||
processes, and requests can then be distributed to the workers by calling
|
||||
:meth:`~multiprocessing.pool.Pool.apply` or
|
||||
:meth:`~multiprocessing.pool.Pool.apply_async` to add a single request, and
|
||||
: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
|
||||
|
||||
|
|
@ -646,15 +651,18 @@ This produces the following output::
|
|||
33452526613163807108170062053440751665152000000000
|
||||
...
|
||||
|
||||
The other high-level interface, the :class:`Manager` class, creates a
|
||||
separate server process that can hold master copies of Python data
|
||||
The other high-level interface, the :class:`~multiprocessing.Manager` class,
|
||||
creates a separate server process that can hold master copies of Python data
|
||||
structures. Other processes can then access and modify these data
|
||||
structures using proxy objects. The following example creates a
|
||||
shared dictionary by calling the :meth:`dict` method; the worker
|
||||
processes then insert values into the dictionary. (Locking is not
|
||||
done for you automatically, which doesn't matter in this example.
|
||||
:class:`Manager`'s methods also include :meth:`Lock`, :meth:`RLock`,
|
||||
and :meth:`Semaphore` to create shared locks.)
|
||||
:class:`~multiprocessing.Manager`'s methods also include
|
||||
: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.
|
||||
===== ========================================================================
|
||||
|
||||
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::
|
||||
|
||||
def __format__(self, format_spec):
|
||||
|
|
@ -834,7 +842,7 @@ formatted. It receives a single argument, the format specifier::
|
|||
return str(self)
|
||||
|
||||
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::
|
||||
|
||||
>>> 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
|
||||
file-like objects don't necessarily support all of them. Objects that
|
||||
imitate files usually support :meth:`read` and :meth:`write`, but they
|
||||
may not support :meth:`readline`, for example. Python 3.0 introduces
|
||||
a layered I/O library in the :mod:`io` module that separates buffering
|
||||
and text-handling features from the fundamental read and write
|
||||
operations.
|
||||
imitate files usually support :meth:`!read` and
|
||||
:meth:`!write`, but they may not support :meth:`!readline`,
|
||||
for example. Python 3.0 introduces a layered I/O library in the :mod:`io`
|
||||
module that separates buffering and text-handling features from the
|
||||
fundamental read and write operations.
|
||||
|
||||
There are three levels of abstract base classes provided by
|
||||
the :mod:`io` module:
|
||||
|
||||
* :class:`RawIOBase` defines raw I/O operations: :meth:`read`,
|
||||
:meth:`readinto`,
|
||||
:meth:`write`, :meth:`seek`, :meth:`tell`, :meth:`truncate`,
|
||||
and :meth:`close`.
|
||||
* :class:`~io.RawIOBase` defines raw I/O operations: :meth:`~io.RawIOBase.read`,
|
||||
:meth:`~io.RawIOBase.readinto`, :meth:`~io.RawIOBase.write`,
|
||||
:meth:`~io.IOBase.seek`, :meth:`~io.IOBase.tell`, :meth:`~io.IOBase.truncate`,
|
||||
and :meth:`~io.IOBase.close`.
|
||||
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`
|
||||
methods for determining what operations a given object will allow.
|
||||
There are also :meth:`~io.IOBase.readable`, :meth:`~io.IOBase.writable`,
|
||||
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
|
||||
sockets, but Python 2.6 hasn't restructured its file and socket objects
|
||||
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
|
||||
system calls used, making I/O processing more efficient.
|
||||
It supports all of the methods of :class:`RawIOBase`,
|
||||
and adds a :attr:`raw` attribute holding the underlying raw object.
|
||||
It supports all of the methods of :class:`~io.RawIOBase`,
|
||||
and adds a :attr:`~io.BufferedIOBase.raw` attribute holding the underlying
|
||||
raw object.
|
||||
|
||||
There are five concrete classes implementing this ABC.
|
||||
:class:`BufferedWriter` and :class:`BufferedReader` are for objects
|
||||
that support write-only or read-only usage that have a :meth:`seek`
|
||||
method for random access. :class:`BufferedRandom` objects support
|
||||
:class:`~io.BufferedWriter` and :class:`~io.BufferedReader` are for objects
|
||||
that support write-only or read-only usage that have a :meth:`~io.IOBase.seek`
|
||||
method for random access. :class:`~io.BufferedRandom` objects support
|
||||
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.
|
||||
The :class:`BytesIO` class supports reading, writing, and seeking
|
||||
The :class:`~io.BytesIO` class supports reading, writing, and seeking
|
||||
over an in-memory buffer.
|
||||
|
||||
.. index::
|
||||
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),
|
||||
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
|
||||
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
|
||||
text I/O and adding a :attr:`buffer` attribute for access
|
||||
to the underlying object. :class:`StringIO` simply buffers
|
||||
text I/O and adding a :attr:`~io.TextIOBase.buffer` attribute for access
|
||||
to the underlying object. :class:`~io.StringIO` simply buffers
|
||||
everything in memory without ever writing anything to disk.
|
||||
|
||||
(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
|
||||
access protocol. Abstract Base Classes (or ABCs) are an equivalent
|
||||
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`
|
||||
builtins, and a collection of basic ABCs that the Python developers
|
||||
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.
|
||||
It probably means that accessing items with ``obj[1]`` 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`
|
||||
methods? What about the iterative variants such as :meth:`iterkeys`? :meth:`copy`
|
||||
and :meth:`update`? Iterating over the object with :func:`iter`?
|
||||
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`and :meth:`!update`? Iterating over the object with :func:`!iter`?
|
||||
|
||||
The Python 2.6 :mod:`collections` module includes a number of
|
||||
different ABCs that represent these distinctions. :class:`Iterable`
|
||||
indicates that a class defines :meth:`__iter__`, and
|
||||
:class:`Container` means the class defines a :meth:`__contains__`
|
||||
indicates that a class defines :meth:`~object.__iter__`, and
|
||||
:class:`Container` means the class defines a :meth:`~object.__contains__`
|
||||
method and therefore supports ``x in y`` expressions. The basic
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
|
||||
|
|
@ -1206,10 +1216,10 @@ calling the ABC's :meth:`register` method::
|
|||
collections.MutableMapping.register(Storage)
|
||||
|
||||
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
|
||||
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::
|
||||
|
||||
# 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
|
||||
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
|
||||
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_doubled`, though they can do so. An implementation
|
||||
of :meth:`!draw` is necessary, though; the ABC can't provide
|
||||
a useful generic implementation.
|
||||
|
||||
You can apply the ``@abstractmethod`` decorator to methods such as
|
||||
:meth:`draw` that must be implemented; Python will then raise an
|
||||
You can apply the :deco:`~abc.abstractmethod` decorator to methods such as
|
||||
:meth:`!draw` that must be implemented; Python will then raise an
|
||||
exception for classes that don't define the method.
|
||||
Note that the exception is only raised when you actually
|
||||
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):
|
||||
return self._x
|
||||
|
||||
Subclasses must then define a :meth:`readonly` property.
|
||||
Subclasses must then define a ``readonly`` property.
|
||||
|
||||
.. 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
|
||||
functions, and most of the changes can't be introduced in the Python
|
||||
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
|
||||
3.0-compatible code.
|
||||
|
||||
|
|
|
|||
|
|
@ -858,8 +858,8 @@ Some smaller changes made to the core Python language are:
|
|||
|
||||
.. XXX bytearray doesn't seem to be documented
|
||||
|
||||
* When using :class:`@classmethod <classmethod>` and
|
||||
:class:`@staticmethod <staticmethod>` to wrap
|
||||
* When using :deco:`classmethod` and
|
||||
:deco:`staticmethod` to wrap
|
||||
methods as class or static methods, the wrapper object now
|
||||
exposes the wrapped function as their :attr:`~method.__func__`
|
||||
attribute.
|
||||
|
|
|
|||
|
|
@ -847,8 +847,8 @@ Other Language Changes
|
|||
respectively.
|
||||
(Contributed by Joshua Bronson, Daniel Pope, and Justin Wang in :issue:`31861`.)
|
||||
|
||||
* Static methods (:func:`@staticmethod <staticmethod>`) and class methods
|
||||
(:func:`@classmethod <classmethod>`) now inherit the method attributes
|
||||
* Static methods (:deco:`staticmethod`) and class methods
|
||||
(:deco:`classmethod`) now inherit the method attributes
|
||||
(``__module__``, ``__name__``, ``__qualname__``, ``__doc__``,
|
||||
``__annotations__``) and have a new ``__wrapped__`` attribute.
|
||||
Moreover, static methods are now callable as regular functions.
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ Summary -- Release Highlights
|
|||
.. This section singles out the most important changes in Python 3.13.
|
||||
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
|
||||
and the standard library.
|
||||
The biggest changes include a new `interactive interpreter
|
||||
|
|
@ -1569,8 +1569,6 @@ and are now removed:
|
|||
|
||||
* :pypi:`bcrypt`:
|
||||
Modern password hashing for your software and your servers.
|
||||
* :pypi:`passlib`:
|
||||
Comprehensive password hashing framework supporting over 30 schemes.
|
||||
* :pypi:`argon2-cffi`:
|
||||
The secure Argon2 password hashing algorithm.
|
||||
* :pypi:`legacycrypt`:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -852,6 +852,9 @@ New features
|
|||
|
||||
(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
|
||||
----------------------
|
||||
|
|
|
|||
|
|
@ -78,7 +78,7 @@ __pragma(warning(disable: 4201))
|
|||
#include "pybuffer.h"
|
||||
#include "pystats.h"
|
||||
#include "pyatomic.h"
|
||||
#include "pylock.h"
|
||||
#include "cpython/pylock.h"
|
||||
#include "critical_section.h"
|
||||
#include "object.h"
|
||||
#include "refcount.h"
|
||||
|
|
@ -105,7 +105,7 @@ __pragma(warning(disable: 4201))
|
|||
#include "setobject.h"
|
||||
#include "methodobject.h"
|
||||
#include "moduleobject.h"
|
||||
#include "monitoring.h"
|
||||
#include "cpython/monitoring.h"
|
||||
#include "cpython/funcobject.h"
|
||||
#include "cpython/classobject.h"
|
||||
#include "fileobject.h"
|
||||
|
|
|
|||
|
|
@ -282,15 +282,6 @@ typedef struct _line_offsets {
|
|||
*/
|
||||
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,
|
||||
PyObject *names, PyObject *lnotab);
|
||||
|
||||
|
|
|
|||
|
|
@ -134,7 +134,8 @@ PyAPI_FUNC(PyObject *) PyStaticMethod_New(PyObject *);
|
|||
V(DESTROY) \
|
||||
V(MODIFY_CODE) \
|
||||
V(MODIFY_DEFAULTS) \
|
||||
V(MODIFY_KWDEFAULTS)
|
||||
V(MODIFY_KWDEFAULTS) \
|
||||
V(MODIFY_QUALNAME)
|
||||
|
||||
typedef enum {
|
||||
#define PY_DEF_EVENT(EVENT) PyFunction_EVENT_##EVENT,
|
||||
|
|
|
|||
17
Include/cpython/marshal.h
Normal file
17
Include/cpython/marshal.h
Normal 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);
|
||||
|
|
@ -1,7 +1,13 @@
|
|||
#ifndef Py_CPYTHON_MONITORING_H
|
||||
# error "this header file must not be included directly"
|
||||
#ifndef Py_MONITORING_H
|
||||
#define Py_MONITORING_H
|
||||
#ifndef Py_LIMITED_API
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// There is currently no limited API for monitoring
|
||||
|
||||
|
||||
/* Local events.
|
||||
* These require bytecode instrumentation */
|
||||
|
||||
|
|
@ -267,3 +273,9 @@ PyMonitoring_FireStopIterationEvent(PyMonitoringState *state, PyObject *codelike
|
|||
}
|
||||
|
||||
#undef _PYMONITORING_IF_ACTIVE
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !Py_LIMITED_API
|
||||
#endif // !Py_MONITORING_H
|
||||
|
|
|
|||
|
|
@ -492,7 +492,3 @@ PyAPI_FUNC(int) PyUnstable_TryIncRef(PyObject *);
|
|||
PyAPI_FUNC(void) PyUnstable_EnableTryIncRef(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);
|
||||
|
|
|
|||
|
|
@ -1,7 +1,11 @@
|
|||
#ifndef Py_CPYTHON_LOCK_H
|
||||
# error "this header file must not be included directly"
|
||||
#ifndef Py_LOCK_H
|
||||
#define Py_LOCK_H
|
||||
#ifndef Py_LIMITED_API
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
#define _Py_UNLOCKED 0
|
||||
#define _Py_LOCKED 1
|
||||
|
||||
|
|
@ -72,3 +76,10 @@ _PyMutex_IsLocked(PyMutex *m)
|
|||
return (_Py_atomic_load_uint8(&m->_bits) & _Py_LOCKED) != 0;
|
||||
}
|
||||
#define PyMutex_IsLocked _PyMutex_IsLocked
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // !Py_LIMITED_API
|
||||
#endif // !Py_LOCK_H
|
||||
|
|
|
|||
20
Include/cpython/sliceobject.h
Normal file
20
Include/cpython/sliceobject.h
Normal 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);
|
||||
12
Include/cpython/structseq.h
Normal file
12
Include/cpython/structseq.h
Normal 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
|
||||
|
|
@ -38,3 +38,7 @@ PyTuple_SET_ITEM(PyObject *op, Py_ssize_t index, PyObject *value) {
|
|||
}
|
||||
#define PyTuple_SET_ITEM(op, index, value) \
|
||||
PyTuple_SET_ITEM(_PyObject_CAST(op), (index), _PyObject_CAST(value))
|
||||
|
||||
PyAPI_FUNC(PyObject*) PyTuple_FromArray(
|
||||
PyObject *const *array,
|
||||
Py_ssize_t size);
|
||||
|
|
|
|||
|
|
@ -663,6 +663,15 @@ PyAPI_FUNC(int) _PyCode_VerifyStateless(
|
|||
PyAPI_FUNC(int) _PyCode_CheckPureFunction(PyCodeObject *, const char **);
|
||||
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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1047,6 +1047,10 @@ static inline Py_ALWAYS_INLINE void _Py_INCREF_MORTAL(PyObject *op)
|
|||
}
|
||||
#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
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ extern PyStatus _PyTuple_InitGlobalObjects(PyInterpreterState *);
|
|||
|
||||
#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_FromArraySteal(PyObject *const *, Py_ssize_t);
|
||||
|
||||
|
|
|
|||
|
|
@ -11,6 +11,70 @@ extern "C" {
|
|||
#include "pycore_fileutils.h" // _Py_error_handler
|
||||
#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 ----------------------------------------------- */
|
||||
|
||||
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.
|
||||
Behaviour is expected to be an exact match of `textwrap.dedent`.
|
||||
Return a new reference on success, NULL with exception set on error.
|
||||
|
|
|
|||
|
|
@ -1,31 +1,18 @@
|
|||
|
||||
/* Interface for marshal.c */
|
||||
|
||||
#ifndef Py_MARSHAL_H
|
||||
#define Py_MARSHAL_H
|
||||
#ifndef Py_LIMITED_API
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#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);
|
||||
#ifndef Py_LIMITED_API
|
||||
# define _Py_CPYTHON_MARSHAL_H
|
||||
# include "cpython/marshal.h"
|
||||
# undef _Py_CPYTHON_MARSHAL_H
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* Py_LIMITED_API */
|
||||
#endif /* !Py_MARSHAL_H */
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
@ -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 */
|
||||
|
|
@ -16,19 +16,6 @@ PyAPI_DATA(PyObject) _Py_EllipsisObject; /* Don't use this directly */
|
|||
|
||||
/* 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) PyEllipsis_Type;
|
||||
|
||||
|
|
@ -36,12 +23,6 @@ PyAPI_DATA(PyTypeObject) PyEllipsis_Type;
|
|||
|
||||
PyAPI_FUNC(PyObject *) PySlice_New(PyObject* start, PyObject* stop,
|
||||
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,
|
||||
Py_ssize_t *start, Py_ssize_t *stop, Py_ssize_t *step);
|
||||
Py_DEPRECATED(3.7)
|
||||
|
|
@ -63,6 +44,12 @@ PyAPI_FUNC(Py_ssize_t) PySlice_AdjustIndices(Py_ssize_t length,
|
|||
Py_ssize_t step);
|
||||
#endif
|
||||
|
||||
#ifndef Py_LIMITED_API
|
||||
# define Py_CPYTHON_SLICEOBJECT_H
|
||||
# include "cpython/sliceobject.h"
|
||||
# undef Py_CPYTHON_SLICEOBJECT_H
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -21,12 +21,6 @@ typedef struct PyStructSequence_Desc {
|
|||
|
||||
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(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);
|
||||
|
||||
#ifndef Py_LIMITED_API
|
||||
typedef PyTupleObject PyStructSequence;
|
||||
#define PyStructSequence_SET_ITEM PyStructSequence_SetItem
|
||||
#define PyStructSequence_GET_ITEM PyStructSequence_GetItem
|
||||
# define Py_CPYTHON_STRUCTSEQ_H
|
||||
# include "cpython/structseq.h"
|
||||
# undef Py_CPYTHON_STRUCTSEQ_H
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
|
|
@ -420,14 +420,17 @@ class delete(EditCommand):
|
|||
def do(self) -> None:
|
||||
r = self.reader
|
||||
b = r.buffer
|
||||
if (
|
||||
r.pos == 0
|
||||
and len(b) == 0 # this is something of a hack
|
||||
and self.event[-1] == "\004"
|
||||
):
|
||||
r.update_screen()
|
||||
r.console.finish()
|
||||
raise EOFError
|
||||
if self.event[-1] == "\004":
|
||||
if b and b[-1].endswith("\n"):
|
||||
self.finish = True
|
||||
elif (
|
||||
r.pos == 0
|
||||
and len(b) == 0 # this is something of a hack
|
||||
):
|
||||
r.update_screen()
|
||||
r.console.finish()
|
||||
raise EOFError
|
||||
|
||||
for i in range(r.get_arg()):
|
||||
if r.pos != len(b):
|
||||
del b[r.pos]
|
||||
|
|
|
|||
|
|
@ -390,7 +390,12 @@ def restore(self):
|
|||
os.write(self.output_fd, b"\033[?7h")
|
||||
|
||||
if hasattr(self, "old_sigwinch"):
|
||||
signal.signal(signal.SIGWINCH, self.old_sigwinch)
|
||||
try:
|
||||
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
|
||||
|
||||
def push_char(self, char: int | bytes) -> None:
|
||||
|
|
|
|||
|
|
@ -280,7 +280,7 @@ def add_argument(self, action):
|
|||
if action.help is not SUPPRESS:
|
||||
|
||||
# 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]
|
||||
for subaction in self._iter_indented_subactions(action):
|
||||
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
|
||||
# optional arguments and with no "usage:" prefix
|
||||
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()
|
||||
groups = self._mutually_exclusive_groups
|
||||
formatter.add_usage(None, positionals, groups, '')
|
||||
|
|
|
|||
|
|
@ -74,7 +74,8 @@ def callback():
|
|||
return
|
||||
except BaseException:
|
||||
if keyboard_interrupted:
|
||||
self.write("\nKeyboardInterrupt\n")
|
||||
if not CAN_USE_PYREPL:
|
||||
self.write("\nKeyboardInterrupt\n")
|
||||
else:
|
||||
self.showtraceback()
|
||||
return self.STATEMENT_FAILED
|
||||
|
|
|
|||
|
|
@ -1050,8 +1050,8 @@ def _read_ready__on_eof(self):
|
|||
|
||||
def write(self, data):
|
||||
if not isinstance(data, (bytes, bytearray, memoryview)):
|
||||
raise TypeError(f'data argument must be a bytes-like object, '
|
||||
f'not {type(data).__name__!r}')
|
||||
raise TypeError(f'data argument must be a bytes, bytearray, or memoryview '
|
||||
f'object, not {type(data).__name__!r}')
|
||||
if self._eof:
|
||||
raise RuntimeError('Cannot call write() after write_eof()')
|
||||
if self._empty_waiter is not None:
|
||||
|
|
|
|||
|
|
@ -302,6 +302,7 @@ def parse_request(self):
|
|||
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.request_version = version = self.default_request_version
|
||||
self.close_connection = True
|
||||
|
|
@ -359,6 +360,7 @@ def parse_request(self):
|
|||
HTTPStatus.BAD_REQUEST,
|
||||
"Bad HTTP/0.9 request type (%r)" % command)
|
||||
return False
|
||||
is_http_0_9 = True
|
||||
self.command, self.path = command, path
|
||||
|
||||
# gh-87389: The purpose of replacing '//' with '/' is to protect
|
||||
|
|
@ -368,6 +370,11 @@ def parse_request(self):
|
|||
if self.path.startswith('//'):
|
||||
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.
|
||||
try:
|
||||
self.headers = http.client.parse_headers(self.rfile,
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ Major contributors since 2005:
|
|||
- 2014: Saimadhav Heblikar
|
||||
- 2015: Mark Roseman
|
||||
- 2017: Louie Lu, Cheryl Sabella, and Serhiy Storchaka
|
||||
- 2025: Stan Ulbrych
|
||||
|
||||
For additional details refer to NEWS.txt and Changelog.
|
||||
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ def make_pat():
|
|||
name not in keyword.kwlist]
|
||||
builtin = r"([^.'\"\\#]\b|^)" + any("BUILTIN", builtinlist) + r"\b"
|
||||
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]*)*'?"
|
||||
dqstring = stringprefix + r'"[^"\\\n]*(\\.[^"\\\n]*)*"?'
|
||||
sq3string = stringprefix + r"'''[^'\\]*((\\.|'(?!''))[^'\\]*)*(''')?"
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@
|
|||
|
||||
# The default tab setting for a Text widget, in average-width characters.
|
||||
TK_TABWIDTH_DEFAULT = 8
|
||||
_py_version = ' (%s)' % platform.python_version()
|
||||
darwin = sys.platform == 'darwin'
|
||||
|
||||
def _sphinx_version():
|
||||
|
|
@ -1008,12 +1007,16 @@ def open_recent_file(fn_closure=file_name):
|
|||
def saved_change_hook(self):
|
||||
short = self.short_title()
|
||||
long = self.long_title()
|
||||
_py_version = ' (%s)' % platform.python_version()
|
||||
if short and long and not macosx.isCocoaTk():
|
||||
# Don't use both values on macOS because
|
||||
# that doesn't match platform conventions.
|
||||
title = short + " - " + long + _py_version
|
||||
elif short:
|
||||
title = short
|
||||
if short == "IDLE Shell":
|
||||
title = short + " " + platform.python_version()
|
||||
else:
|
||||
title = short + _py_version
|
||||
elif long:
|
||||
title = long
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ async def f(): await g()
|
|||
# All valid prefixes for unicode and byte strings should be colored.
|
||||
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'
|
||||
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'
|
||||
# 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'
|
||||
|
|
@ -390,19 +391,19 @@ def test_recolorize_main(self, mock_notify):
|
|||
('6.0', ('KEYWORD',)), ('6.10', ('DEFINITION',)), ('6.11', ()),
|
||||
('8.0', ('STRING',)), ('8.4', ()), ('8.5', ('STRING',)),
|
||||
('8.12', ()), ('8.14', ('STRING',)),
|
||||
('19.0', ('KEYWORD',)),
|
||||
('20.4', ('KEYWORD',)), ('20.16', ('KEYWORD',)),# ('20.19', ('KEYWORD',)),
|
||||
#('22.4', ('KEYWORD',)), ('22.10', ('KEYWORD',)), ('22.14', ('KEYWORD',)), ('22.19', ('STRING',)),
|
||||
#('23.12', ('KEYWORD',)),
|
||||
('24.8', ('KEYWORD',)),
|
||||
('25.4', ('KEYWORD',)), ('25.9', ('KEYWORD',)),
|
||||
('25.11', ('KEYWORD',)), ('25.15', ('STRING',)),
|
||||
('25.19', ('KEYWORD',)), ('25.22', ()),
|
||||
('25.24', ('KEYWORD',)), ('25.29', ('BUILTIN',)), ('25.37', ('KEYWORD',)),
|
||||
('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)),# ('26.11', ('KEYWORD',)), ('26.14', (),),
|
||||
('27.25', ('STRING',)), ('27.38', ('STRING',)),
|
||||
('29.0', ('STRING',)),
|
||||
('30.1', ('STRING',)),
|
||||
('20.0', ('KEYWORD',)),
|
||||
('21.4', ('KEYWORD',)), ('21.16', ('KEYWORD',)),# ('21.19', ('KEYWORD',)),
|
||||
#('23.4', ('KEYWORD',)), ('23.10', ('KEYWORD',)), ('23.14', ('KEYWORD',)), ('23.19', ('STRING',)),
|
||||
#('24.12', ('KEYWORD',)),
|
||||
('25.8', ('KEYWORD',)),
|
||||
('26.4', ('KEYWORD',)), ('26.9', ('KEYWORD',)),
|
||||
('26.11', ('KEYWORD',)), ('26.15', ('STRING',)),
|
||||
('26.19', ('KEYWORD',)), ('26.22', ()),
|
||||
('26.24', ('KEYWORD',)), ('26.29', ('BUILTIN',)), ('26.37', ('KEYWORD',)),
|
||||
('27.4', ('KEYWORD',)), ('27.9', ('KEYWORD',)),# ('27.11', ('KEYWORD',)), ('27.14', (),),
|
||||
('28.25', ('STRING',)), ('28.38', ('STRING',)),
|
||||
('30.0', ('STRING',)),
|
||||
('31.1', ('STRING',)),
|
||||
# SYNC at the end of every line.
|
||||
('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.17'), ('8.19', '8.26'))
|
||||
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):
|
||||
"""Check highlighting of a given piece of code.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
"Test outwin, coverage 76%."
|
||||
|
||||
from idlelib import outwin
|
||||
import platform
|
||||
import sys
|
||||
import unittest
|
||||
from test.support import requires
|
||||
|
|
@ -41,7 +42,7 @@ def test_ispythonsource(self):
|
|||
self.assertFalse(w.ispythonsource(__file__))
|
||||
|
||||
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):
|
||||
w = self.window
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@
|
|||
import linecache
|
||||
import os
|
||||
import os.path
|
||||
from platform import python_version
|
||||
import re
|
||||
import socket
|
||||
import subprocess
|
||||
|
|
@ -841,7 +840,7 @@ def display_executing_dialog(self):
|
|||
class PyShell(OutputWindow):
|
||||
from idlelib.squeezer import Squeezer
|
||||
|
||||
shell_title = "IDLE Shell " + python_version()
|
||||
shell_title = "IDLE Shell"
|
||||
|
||||
# Override classes
|
||||
ColorDelegator = ModifiedColorDelegator
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
import types
|
||||
import importlib
|
||||
import inspect
|
||||
import warnings
|
||||
import itertools
|
||||
|
||||
from typing import Union, Optional, cast
|
||||
|
|
@ -16,39 +15,6 @@
|
|||
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:
|
||||
"""
|
||||
Get a Traversable resource for an anchor.
|
||||
|
|
|
|||
|
|
@ -1065,7 +1065,9 @@ def __init__(self):
|
|||
|
||||
def tokeneater(self, type, token, srowcol, erowcol, line):
|
||||
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
|
||||
# skip any decorators
|
||||
elif token == "@":
|
||||
|
|
|
|||
11
Lib/os.py
11
Lib/os.py
|
|
@ -58,6 +58,11 @@ def _get_exports_list(module):
|
|||
__all__.append('_exit')
|
||||
except ImportError:
|
||||
pass
|
||||
try:
|
||||
from posix import _clearenv
|
||||
__all__.append('_clearenv')
|
||||
except ImportError:
|
||||
pass
|
||||
import posixpath as path
|
||||
|
||||
try:
|
||||
|
|
@ -768,6 +773,12 @@ def __ror__(self, other):
|
|||
new.update(self)
|
||||
return new
|
||||
|
||||
if _exists("_clearenv"):
|
||||
def clear(self):
|
||||
_clearenv()
|
||||
self._data.clear()
|
||||
|
||||
|
||||
def _create_environ_mapping():
|
||||
if name == 'nt':
|
||||
# Where Env Var Names Must Be UPPERCASE
|
||||
|
|
|
|||
|
|
@ -336,13 +336,8 @@ def _raw_path(self):
|
|||
return paths[0]
|
||||
elif paths:
|
||||
# Join path segments from the initializer.
|
||||
path = self.parser.join(*paths)
|
||||
# Cache the joined path.
|
||||
paths.clear()
|
||||
paths.append(path)
|
||||
return path
|
||||
return self.parser.join(*paths)
|
||||
else:
|
||||
paths.append('')
|
||||
return ''
|
||||
|
||||
@property
|
||||
|
|
@ -490,16 +485,19 @@ def relative_to(self, other, *, walk_up=False):
|
|||
"""
|
||||
if not hasattr(other, 'with_segments'):
|
||||
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:
|
||||
break
|
||||
elif not walk_up:
|
||||
raise ValueError(f"{str(self)!r} is not in the subpath of {str(other)!r}")
|
||||
elif path.name == '..':
|
||||
raise ValueError(f"'..' segment in {str(other)!r} cannot be walked")
|
||||
else:
|
||||
parts.append('..')
|
||||
else:
|
||||
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)
|
||||
|
||||
def is_relative_to(self, other):
|
||||
|
|
|
|||
|
|
@ -234,6 +234,33 @@ def parents(self):
|
|||
parent = split(path)[0]
|
||||
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):
|
||||
"""
|
||||
Return True if this path matches the given glob-style pattern. The
|
||||
|
|
|
|||
|
|
@ -348,7 +348,7 @@ def read_stringnl(f, decode=True, stripquotes=True, *, encoding='latin-1'):
|
|||
for q in (b'"', b"'"):
|
||||
if data.startswith(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))
|
||||
data = data[1:-1]
|
||||
break
|
||||
|
|
|
|||
|
|
@ -333,7 +333,7 @@ def _get_path(userbase):
|
|||
if sys.platform == 'darwin' and sys._framework:
|
||||
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():
|
||||
|
|
|
|||
|
|
@ -110,11 +110,6 @@
|
|||
)
|
||||
from _ssl import txt2obj as _txt2obj, nid2obj as _nid2obj
|
||||
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
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -645,6 +645,9 @@ def get_platform():
|
|||
isn't particularly important.
|
||||
|
||||
Examples of returned values:
|
||||
linux-x86_64
|
||||
linux-aarch64
|
||||
solaris-2.6-sun4u
|
||||
|
||||
|
||||
Windows:
|
||||
|
|
|
|||
|
|
@ -21,8 +21,9 @@
|
|||
# Regexes needed for parsing Makefile (and similar syntaxes,
|
||||
# like old-style Setup files).
|
||||
_variable_rx = r"([a-zA-Z][a-zA-Z0-9_]+)\s*=\s*(.*)"
|
||||
_findvar1_rx = r"\$\(([A-Za-z][A-Za-z0-9_]*)\)"
|
||||
_findvar2_rx = r"\${([A-Za-z][A-Za-z0-9_]*)}"
|
||||
_findvar_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):
|
||||
|
|
@ -49,26 +50,7 @@ def _parse_makefile(filename, vars=None, keep_unresolved=True):
|
|||
m = re.match(_variable_rx, line)
|
||||
if m:
|
||||
n, v = m.group(1, 2)
|
||||
v = 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())
|
||||
notdone[n] = v.strip()
|
||||
|
||||
# Variables with a 'PY_' prefix in the makefile. These need to
|
||||
# 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.
|
||||
renamed_variables = ('CFLAGS', 'LDFLAGS', 'CPPFLAGS')
|
||||
|
||||
while len(variables) > 0:
|
||||
for name in tuple(variables):
|
||||
value = notdone[name]
|
||||
m1 = re.search(_findvar1_rx, value)
|
||||
m2 = re.search(_findvar2_rx, value)
|
||||
if m1 and m2:
|
||||
m = m1 if m1.start() < m2.start() else m2
|
||||
else:
|
||||
m = m1 if m1 else m2
|
||||
if m is not None:
|
||||
n = m.group(1)
|
||||
found = True
|
||||
if n in done:
|
||||
item = str(done[n])
|
||||
elif n in notdone:
|
||||
# get it on a subsequent round
|
||||
found = False
|
||||
elif n in os.environ:
|
||||
# do it like make: fall back to environment
|
||||
item = os.environ[n]
|
||||
|
||||
elif n in renamed_variables:
|
||||
if (name.startswith('PY_') and
|
||||
name[3:] in renamed_variables):
|
||||
item = ""
|
||||
|
||||
elif 'PY_' + n in notdone:
|
||||
found = False
|
||||
|
||||
else:
|
||||
item = str(done['PY_' + n])
|
||||
|
||||
else:
|
||||
done[n] = item = ""
|
||||
|
||||
if found:
|
||||
after = value[m.end():]
|
||||
value = value[:m.start()] + item + after
|
||||
if "$" in after:
|
||||
notdone[name] = value
|
||||
else:
|
||||
try:
|
||||
if name in _ALWAYS_STR:
|
||||
raise ValueError
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
done[name] = value.strip()
|
||||
else:
|
||||
done[name] = value
|
||||
variables.remove(name)
|
||||
|
||||
if name.startswith('PY_') \
|
||||
and name[3:] in renamed_variables:
|
||||
|
||||
name = name[3:]
|
||||
if name not in done:
|
||||
done[name] = value
|
||||
|
||||
else:
|
||||
# Adds unresolved variables to the done dict.
|
||||
# This is disabled when called from distutils.sysconfig
|
||||
def resolve_var(name):
|
||||
def repl(m):
|
||||
n = m[1]
|
||||
if n == '$':
|
||||
return '$'
|
||||
elif n == '':
|
||||
# bogus variable reference (e.g. "prefix=$/opt/python")
|
||||
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)
|
||||
return m[0]
|
||||
raise ValueError
|
||||
elif n[0] == '(' and n[-1] == ')':
|
||||
n = n[1:-1]
|
||||
elif n[0] == '{' and n[-1] == '}':
|
||||
n = n[1:-1]
|
||||
|
||||
if n in done:
|
||||
return str(done[n])
|
||||
elif n in notdone:
|
||||
return str(resolve_var(n))
|
||||
elif n in os.environ:
|
||||
# do it like make: fall back to environment
|
||||
return os.environ[n]
|
||||
elif n in renamed_variables:
|
||||
if name.startswith('PY_') and name[3:] in renamed_variables:
|
||||
return ""
|
||||
n = 'PY_' + n
|
||||
if n in notdone:
|
||||
return str(resolve_var(n))
|
||||
else:
|
||||
assert n not in done
|
||||
return ""
|
||||
else:
|
||||
done[n] = ""
|
||||
return ""
|
||||
|
||||
assert name not in done
|
||||
done[name] = ""
|
||||
try:
|
||||
value = re.sub(_findvar_rx, repl, notdone[name])
|
||||
except ValueError:
|
||||
del done[name]
|
||||
return ""
|
||||
value = value.strip()
|
||||
if name not in _ALWAYS_STR:
|
||||
try:
|
||||
value = int(value)
|
||||
except ValueError:
|
||||
pass
|
||||
done[name] = value
|
||||
if name.startswith('PY_') and name[3:] in renamed_variables:
|
||||
name = name[3:]
|
||||
if name not in done:
|
||||
done[name] = value
|
||||
return value
|
||||
|
||||
for n in notdone:
|
||||
if n not in done:
|
||||
resolve_var(n)
|
||||
|
||||
# strip spurious spaces
|
||||
for k, v in done.items():
|
||||
|
|
|
|||
|
|
@ -4341,7 +4341,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
|
|||
goto exit;
|
||||
}
|
||||
a = args[0];
|
||||
__clinic_args = _PyTuple_FromArray(args + 1, nargs - 1);
|
||||
__clinic_args = PyTuple_FromArray(args + 1, nargs - 1);
|
||||
if (__clinic_args == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -4356,7 +4356,7 @@ test_vararg_and_posonly(PyObject *module, PyObject *const *args, Py_ssize_t narg
|
|||
|
||||
static PyObject *
|
||||
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]
|
||||
test_vararg
|
||||
|
|
@ -4421,7 +4421,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
|
|||
}
|
||||
a = fastargs[0];
|
||||
__clinic_args = nargs > 1
|
||||
? _PyTuple_FromArray(args + 1, nargs - 1)
|
||||
? PyTuple_FromArray(args + 1, nargs - 1)
|
||||
: PyTuple_New(0);
|
||||
if (__clinic_args == NULL) {
|
||||
goto exit;
|
||||
|
|
@ -4437,7 +4437,7 @@ test_vararg(PyObject *module, PyObject *const *args, Py_ssize_t nargs, PyObject
|
|||
|
||||
static PyObject *
|
||||
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]
|
||||
test_vararg_with_default
|
||||
|
|
@ -4514,7 +4514,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
|
|||
}
|
||||
skip_optional_kwonly:
|
||||
__clinic_args = nargs > 1
|
||||
? _PyTuple_FromArray(args + 1, nargs - 1)
|
||||
? PyTuple_FromArray(args + 1, nargs - 1)
|
||||
: PyTuple_New(0);
|
||||
if (__clinic_args == NULL) {
|
||||
goto exit;
|
||||
|
|
@ -4531,7 +4531,7 @@ test_vararg_with_default(PyObject *module, PyObject *const *args, Py_ssize_t nar
|
|||
static PyObject *
|
||||
test_vararg_with_default_impl(PyObject *module, PyObject *a, PyObject *args,
|
||||
int b)
|
||||
/*[clinic end generated code: output=3f2b06ab08d5d0be input=3a0f9f557ce1f712]*/
|
||||
/*[clinic end generated code: output=d25e56802c197344 input=3a0f9f557ce1f712]*/
|
||||
|
||||
/*[clinic input]
|
||||
test_vararg_with_only_defaults
|
||||
|
|
@ -4612,7 +4612,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
|
|||
}
|
||||
c = fastargs[1];
|
||||
skip_optional_kwonly:
|
||||
__clinic_args = _PyTuple_FromArray(args, nargs);
|
||||
__clinic_args = PyTuple_FromArray(args, nargs);
|
||||
if (__clinic_args == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
|
|
@ -4628,7 +4628,7 @@ test_vararg_with_only_defaults(PyObject *module, PyObject *const *args, Py_ssize
|
|||
static PyObject *
|
||||
test_vararg_with_only_defaults_impl(PyObject *module, PyObject *args, int b,
|
||||
PyObject *c)
|
||||
/*[clinic end generated code: output=f46666f0b1bf86b9 input=6983e66817f82924]*/
|
||||
/*[clinic end generated code: output=7366943a7df42e05 input=6983e66817f82924]*/
|
||||
|
||||
/*[clinic input]
|
||||
test_paramname_module
|
||||
|
|
|
|||
|
|
@ -646,15 +646,23 @@ def _add_cross_compile_opts(self, regrtest_opts):
|
|||
return (environ, keep_environ)
|
||||
|
||||
def _add_ci_python_opts(self, python_opts, keep_environ):
|
||||
# --fast-ci and --slow-ci add options to Python:
|
||||
# "-u -W default -bb -E"
|
||||
# --fast-ci and --slow-ci add options to Python.
|
||||
#
|
||||
# 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
|
||||
if not sys.stdout.write_through:
|
||||
# Unbuffered stdout and stderr. This isn't helpful on Android, because
|
||||
# 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')
|
||||
|
||||
# Add warnings filter 'error'
|
||||
if 'default' not in sys.warnoptions:
|
||||
# Add warnings filter 'error', unless the user specified a different
|
||||
# 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'))
|
||||
|
||||
# Error on bytes/str comparison
|
||||
|
|
@ -673,8 +681,12 @@ def _execute_python(self, cmd, environ):
|
|||
|
||||
cmd_text = shlex.join(cmd)
|
||||
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:
|
||||
os.execv(cmd[0], cmd)
|
||||
# On success, execv() do no return.
|
||||
|
|
|
|||
|
|
@ -310,6 +310,16 @@ def requires(resource, msg=None):
|
|||
if resource == 'gui' and not _is_gui_available():
|
||||
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):
|
||||
"""Decorator raising SkipTest if the OS is `sysname` and the version is less
|
||||
than `min_version`.
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
captured_stderr,
|
||||
force_not_colorized,
|
||||
force_not_colorized_test_class,
|
||||
swap_attr,
|
||||
)
|
||||
from test.support import import_helper
|
||||
from test.support import os_helper
|
||||
|
|
@ -7128,7 +7129,8 @@ class TestColorized(TestCase):
|
|||
def setUp(self):
|
||||
super().setUp()
|
||||
# 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
|
||||
|
||||
def test_argparse_color(self):
|
||||
|
|
@ -7311,11 +7313,11 @@ def custom_formatter(prog):
|
|||
{heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f {label}FOO{reset}] {pos}spam{reset}
|
||||
|
||||
{heading}positional arguments:{reset}
|
||||
{pos_b}spam{reset} spam help
|
||||
{pos_b}spam{reset} spam help
|
||||
|
||||
{heading}options:{reset}
|
||||
{short_b}-h{reset}, {long_b}--help{reset} show this help message and exit
|
||||
{short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help
|
||||
{short_b}-h{reset}, {long_b}--help{reset} show this help message and exit
|
||||
{short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help
|
||||
'''))
|
||||
|
||||
def test_custom_formatter_class(self):
|
||||
|
|
@ -7348,13 +7350,24 @@ def __init__(self, prog):
|
|||
{heading}usage: {reset}{prog}PROG{reset} [{short}-h{reset}] [{short}+f {label}FOO{reset}] {pos}spam{reset}
|
||||
|
||||
{heading}positional arguments:{reset}
|
||||
{pos_b}spam{reset} spam help
|
||||
{pos_b}spam{reset} spam help
|
||||
|
||||
{heading}options:{reset}
|
||||
{short_b}-h{reset}, {long_b}--help{reset} show this help message and exit
|
||||
{short_b}+f{reset}, {long_b}++foo{reset} {label_b}FOO{reset} foo help
|
||||
{short_b}-h{reset}, {long_b}--help{reset} show this help message and exit
|
||||
{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):
|
||||
def test_deprecated__version__(self):
|
||||
|
|
|
|||
|
|
@ -1180,32 +1180,68 @@ async def runner():
|
|||
|
||||
|
||||
@support.requires_fork()
|
||||
class TestFork(unittest.IsolatedAsyncioTestCase):
|
||||
class TestFork(unittest.TestCase):
|
||||
|
||||
async def test_fork_not_share_event_loop(self):
|
||||
with warnings_helper.ignore_fork_in_thread_deprecation_warnings():
|
||||
# The forked process should not share the event loop with the parent
|
||||
loop = asyncio.get_running_loop()
|
||||
r, w = os.pipe()
|
||||
self.addCleanup(os.close, r)
|
||||
self.addCleanup(os.close, w)
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# child
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
os.write(w, b'LOOP:' + str(id(loop)).encode())
|
||||
except RuntimeError:
|
||||
os.write(w, b'NO LOOP')
|
||||
except BaseException as e:
|
||||
os.write(w, b'ERROR:' + ascii(e).encode())
|
||||
finally:
|
||||
os._exit(0)
|
||||
else:
|
||||
# parent
|
||||
result = os.read(r, 100)
|
||||
self.assertEqual(result, b'NO LOOP')
|
||||
wait_process(pid, exitcode=0)
|
||||
@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
|
||||
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()
|
||||
self.addCleanup(os.close, r)
|
||||
self.addCleanup(os.close, w)
|
||||
pid = os.fork()
|
||||
if pid == 0:
|
||||
# child
|
||||
try:
|
||||
loop = asyncio.get_event_loop()
|
||||
os.write(w, b'LOOP:' + str(id(loop)).encode())
|
||||
except RuntimeError:
|
||||
os.write(w, b'NO LOOP')
|
||||
except BaseException as e:
|
||||
os.write(w, b'ERROR:' + ascii(e).encode())
|
||||
finally:
|
||||
os._exit(0)
|
||||
else:
|
||||
# parent
|
||||
result = os.read(r, 100)
|
||||
self.assertEqual(result, b'NO LOOP')
|
||||
wait_process(pid, exitcode=0)
|
||||
|
||||
@warnings_helper.ignore_fork_in_thread_deprecation_warnings()
|
||||
@hashlib_helper.requires_hashdigest('md5')
|
||||
|
|
|
|||
|
|
@ -62,6 +62,28 @@ def test_tuple_new(self):
|
|||
self.assertRaises(SystemError, tuple_new, PY_SSIZE_T_MIN)
|
||||
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):
|
||||
# Test PyTuple_Pack()
|
||||
pack = _testlimitedcapi.tuple_pack
|
||||
|
|
|
|||
|
|
@ -514,6 +514,10 @@ def myfunc():
|
|||
_testcapi.set_func_kwdefaults_via_capi(myfunc, new_kwdefaults)
|
||||
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
|
||||
events = []
|
||||
del myfunc
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue