[Python-checkins] [3.13] gh-125940: Android: support 16 KB pages (GH-125941) (#125948)
https://github.com/python/cpython/commit/904634b2580565de73905f96d6a1ac42058c1978 commit: 904634b2580565de73905f96d6a1ac42058c1978 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: freakboy3742 date: 2024-10-25T08:37:38+08:00 summary: [3.13] gh-125940: Android: support 16 KB pages (GH-125941) (#125948) gh-125940: Android: support 16 KB pages (GH-125941) Modify Android build tooling to use 16kB pages. (cherry picked from commit e68d4b08ff13a06a2c2877f63bf856e6bf3c2e77) Co-authored-by: Malcolm Smith files: A Misc/NEWS.d/next/Build/2024-10-24-22-14-35.gh-issue-125940.2wMtTA.rst M Android/android-env.sh M Android/android.py M Android/testbed/app/build.gradle.kts M Android/testbed/build.gradle.kts M Android/testbed/gradle/wrapper/gradle-wrapper.properties diff --git a/Android/android-env.sh b/Android/android-env.sh index 93372e3fe1c7ee..b93e7f21ed5b94 100644 --- a/Android/android-env.sh +++ b/Android/android-env.sh @@ -24,7 +24,7 @@ fail() { # * https://android.googlesource.com/platform/ndk/+/ndk-rXX-release/docs/BuildSystemMaintainers.md # where XX is the NDK version. Do a diff against the version you're upgrading from, e.g.: # https://android.googlesource.com/platform/ndk/+/ndk-r25-release..ndk-r26-release/docs/BuildSystemMaintainers.md -ndk_version=26.2.11394342 +ndk_version=27.1.12297006 ndk=$ANDROID_HOME/ndk/$ndk_version if ! [ -e $ndk ]; then @@ -58,8 +58,8 @@ for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB" "$READELF" "$STRIP"; fi done -export CFLAGS="" -export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment" +export CFLAGS="-D__BIONIC_NO_PAGE_SIZE_MACRO" +export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment -Wl,-z,max-page-size=16384" # Unlike Linux, Android does not implicitly use a dlopened library to resolve # relocations in subsequently-loaded libraries, even if RTLD_GLOBAL is used @@ -85,6 +85,10 @@ if [ -n "${PREFIX:-}" ]; then export PKG_CONFIG_LIBDIR="$abs_prefix/lib/pkgconfig" fi +# When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and some will +# use CXXFLAGS alone. +export CXXFLAGS=$CFLAGS + # Use the same variable name as conda-build if [ $(uname) = "Darwin" ]; then export CPU_COUNT=$(sysctl -n hw.ncpu) diff --git a/Android/android.py b/Android/android.py index 8696d9eaeca19c..ae630aa8f4427c 100755 --- a/Android/android.py +++ b/Android/android.py @@ -138,8 +138,8 @@ def make_build_python(context): def unpack_deps(host): deps_url = "https://github.com/beeware/cpython-android-source-deps/releases/download"; -for name_ver in ["bzip2-1.0.8-1", "libffi-3.4.4-2", "openssl-3.0.15-0", - "sqlite-3.45.1-0", "xz-5.4.6-0"]: +for name_ver in ["bzip2-1.0.8-2", "libffi-3.4.4-3", "openssl-3.0.15-4", + "sqlite-3.45.3-3", "xz-5.4.6-1"]: filename = f"{name_ver}-{host}.tar.gz" download(f"{deps_url}/{name_ver}/{filename}") run(["tar", "-xf", filename]) @@ -189,12 +189,13 @@ def configure_host_python(context): def make_host_python(context): # The CFLAGS and LDFLAGS set in android-env include the prefix dir, so -# delete any previously-installed Python libs and include files to prevent -# them being used during the build. +# delete any previous Python installation to prevent it being used during +# the build. host_dir = subdir(context.host) prefix_dir = host_dir / "prefix" delete_glob(f"{prefix_dir}/include/python*") delete_glob(f"{prefix_dir}/lib/libpython*") +delete_glob(f"{prefix_dir}/lib/python*") os.chdir(host_dir / "build") run(["make", "-j", str(os.cpu_count())], host=context.host) diff --git a/Android/testbed/app/build.gradle.kts b/Android/testbed/app/build.gradle.kts index 7e0bef58ed88eb..6c17406c8724dc 100644 --- a/Android/testbed/app/build.gradle.kts +++ b/Android/testbed/app/build.gradle.kts @@ -30,16 +30,6 @@ val PYTHON_VERSION = file("$PYTHON_DIR/Include/patchlevel.h").useLines { throw GradleException("Failed to find Python version") } -android.ndkVersion = file("../../android-env.sh").useLines { -for (line in it) { -val match = """ndk_version=(\S+)""".toRegex().find(line) -if (match != null) { -return@useLines match.groupValues[1] -} -} -throw GradleException("Failed to find NDK version") -} - android { namespace = "org.python.testbed" @@ -55,11 +45,22 @@ android { ndk.abiFilters.addAll(ABIS.keys) externalNativeBuild.cmake.arguments( "-DPYTHON_CROSS_DIR=$PYTHON_CROSS_DIR", -"-DPYTHON_VERSION=$PYTHON_VERSION") +"-DPYTHON_VERSION=$PYTHON_VERSION", +"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON", +) testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } +val androidEnvFile = file("../../android-env.sh").absoluteFile +ndkVersion = androidEnvFile
[Python-checkins] gh-125933: Add ARIA labels to select elements in the version switcher (#125934)
https://github.com/python/cpython/commit/1306f33c84b2745aa8af5e3e8f680aa80b836c0e commit: 1306f33c84b2745aa8af5e3e8f680aa80b836c0e branch: main author: Kerim Kabirov committer: hugovk <[email protected]> date: 2024-10-24T23:52:21+03:00 summary: gh-125933: Add ARIA labels to select elements in the version switcher (#125934) Co-authored-by: Hugo van Kemenade <[email protected]> files: M Doc/tools/static/rtd_switcher.js diff --git a/Doc/tools/static/rtd_switcher.js b/Doc/tools/static/rtd_switcher.js index f5dc7045a0dbc4..2bf01a002db90c 100644 --- a/Doc/tools/static/rtd_switcher.js +++ b/Doc/tools/static/rtd_switcher.js @@ -7,7 +7,7 @@ document.addEventListener("readthedocs-addons-data-ready", function(event) { const config = event.detail.data() const versionSelect = ` - + ${ config.versions.active.map( (version) => ` a.language.name.localeCompare(b.language.name)); const languageSelect = ` - + ${ languages.map( (translation) => ` https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] Increase minimum Android API level to 24 (#125946)
https://github.com/python/cpython/commit/371c537dff0b384e46ebe6b08009f6628b7acd58
commit: 371c537dff0b384e46ebe6b08009f6628b7acd58
branch: main
author: Malcolm Smith
committer: freakboy3742
date: 2024-10-25T08:41:07+08:00
summary:
Increase minimum Android API level to 24 (#125946)
Minimum Android API level has been increased to 24 (Android 7.0).
files:
A Misc/NEWS.d/next/Build/2024-10-25-00-29-15.gh-issue-125946.KPA3g0.rst
M Android/android-env.sh
M Android/testbed/app/build.gradle.kts
M Android/testbed/app/src/main/c/main_activity.c
M Lib/test/test_android.py
diff --git a/Android/android-env.sh b/Android/android-env.sh
index b93e7f21ed5b94..a0f23ef8c9fc52 100644
--- a/Android/android-env.sh
+++ b/Android/android-env.sh
@@ -3,7 +3,7 @@
: ${HOST:?} # GNU target triplet
# You may also override the following:
-: ${api_level:=21} # Minimum Android API level the build will run on
+: ${api_level:=24} # Minimum Android API level the build will run on
: ${PREFIX:-} # Path in which to find required libraries
diff --git a/Android/testbed/app/build.gradle.kts
b/Android/testbed/app/build.gradle.kts
index 6c17406c8724dc..211b5bbfadf64d 100644
--- a/Android/testbed/app/build.gradle.kts
+++ b/Android/testbed/app/build.gradle.kts
@@ -32,13 +32,24 @@ val PYTHON_VERSION =
file("$PYTHON_DIR/Include/patchlevel.h").useLines {
android {
+val androidEnvFile = file("../../android-env.sh").absoluteFile
+
namespace = "org.python.testbed"
compileSdk = 34
defaultConfig {
applicationId = "org.python.testbed"
-minSdk = 21
+
+minSdk = androidEnvFile.useLines {
+for (line in it) {
+"""api_level:=(\d+)""".toRegex().find(line)?.let {
+return@useLines it.groupValues[1].toInt()
+}
+}
+throw GradleException("Failed to find API level in
$androidEnvFile")
+}
targetSdk = 34
+
versionCode = 1
versionName = "1.0"
@@ -52,7 +63,6 @@ android {
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
-val androidEnvFile = file("../../android-env.sh").absoluteFile
ndkVersion = androidEnvFile.useLines {
for (line in it) {
"""ndk_version=(\S+)""".toRegex().find(line)?.let {
diff --git a/Android/testbed/app/src/main/c/main_activity.c
b/Android/testbed/app/src/main/c/main_activity.c
index 69251332d48890..ec7f93a3e5ee13 100644
--- a/Android/testbed/app/src/main/c/main_activity.c
+++ b/Android/testbed/app/src/main/c/main_activity.c
@@ -34,9 +34,12 @@ typedef struct {
int pipe[2];
} StreamInfo;
+// The FILE member can't be initialized here because stdout and stderr are not
+// compile-time constants. Instead, it's initialized immediately before the
+// redirection.
static StreamInfo STREAMS[] = {
-{stdout, STDOUT_FILENO, ANDROID_LOG_INFO, "native.stdout", {-1, -1}},
-{stderr, STDERR_FILENO, ANDROID_LOG_WARN, "native.stderr", {-1, -1}},
+{NULL, STDOUT_FILENO, ANDROID_LOG_INFO, "native.stdout", {-1, -1}},
+{NULL, STDERR_FILENO, ANDROID_LOG_WARN, "native.stderr", {-1, -1}},
{NULL, -1, ANDROID_LOG_UNKNOWN, NULL, {-1, -1}},
};
@@ -87,6 +90,8 @@ static char *redirect_stream(StreamInfo *si) {
JNIEXPORT void JNICALL
Java_org_python_testbed_PythonTestRunner_redirectStdioToLogcat(
JNIEnv *env, jobject obj
) {
+STREAMS[0].file = stdout;
+STREAMS[1].file = stderr;
for (StreamInfo *si = STREAMS; si->file; si++) {
char *error_prefix;
if ((error_prefix = redirect_stream(si))) {
diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py
index 076190f7572045..a9abd61b9a8d92 100644
--- a/Lib/test/test_android.py
+++ b/Lib/test/test_android.py
@@ -24,10 +24,6 @@
# Test redirection of stdout and stderr to the Android log.
[email protected](
-api_level < 23 and platform.machine() == "aarch64",
-"SELinux blocks reading logs on older ARM64 emulators"
-)
class TestAndroidOutput(unittest.TestCase):
maxDiff = None
diff --git
a/Misc/NEWS.d/next/Build/2024-10-25-00-29-15.gh-issue-125946.KPA3g0.rst
b/Misc/NEWS.d/next/Build/2024-10-25-00-29-15.gh-issue-125946.KPA3g0.rst
new file mode 100644
index 00..ecab57c8111d45
--- /dev/null
+++ b/Misc/NEWS.d/next/Build/2024-10-25-00-29-15.gh-issue-125946.KPA3g0.rst
@@ -0,0 +1 @@
+The minimum supported Android version is now 7.0 (API level 24).
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-125940: Android: support 16 KB pages (#125941)
https://github.com/python/cpython/commit/e68d4b08ff13a06a2c2877f63bf856e6bf3c2e77
commit: e68d4b08ff13a06a2c2877f63bf856e6bf3c2e77
branch: main
author: Malcolm Smith
committer: freakboy3742
date: 2024-10-25T07:51:16+08:00
summary:
gh-125940: Android: support 16 KB pages (#125941)
Modify Android build tooling to use 16kB pages.
files:
A Misc/NEWS.d/next/Build/2024-10-24-22-14-35.gh-issue-125940.2wMtTA.rst
M Android/android-env.sh
M Android/android.py
M Android/testbed/app/build.gradle.kts
M Android/testbed/build.gradle.kts
M Android/testbed/gradle/wrapper/gradle-wrapper.properties
diff --git a/Android/android-env.sh b/Android/android-env.sh
index 93372e3fe1c7ee..b93e7f21ed5b94 100644
--- a/Android/android-env.sh
+++ b/Android/android-env.sh
@@ -24,7 +24,7 @@ fail() {
# *
https://android.googlesource.com/platform/ndk/+/ndk-rXX-release/docs/BuildSystemMaintainers.md
# where XX is the NDK version. Do a diff against the version you're
upgrading from, e.g.:
#
https://android.googlesource.com/platform/ndk/+/ndk-r25-release..ndk-r26-release/docs/BuildSystemMaintainers.md
-ndk_version=26.2.11394342
+ndk_version=27.1.12297006
ndk=$ANDROID_HOME/ndk/$ndk_version
if ! [ -e $ndk ]; then
@@ -58,8 +58,8 @@ for path in "$AR" "$AS" "$CC" "$CXX" "$LD" "$NM" "$RANLIB"
"$READELF" "$STRIP";
fi
done
-export CFLAGS=""
-export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment"
+export CFLAGS="-D__BIONIC_NO_PAGE_SIZE_MACRO"
+export LDFLAGS="-Wl,--build-id=sha1 -Wl,--no-rosegment
-Wl,-z,max-page-size=16384"
# Unlike Linux, Android does not implicitly use a dlopened library to resolve
# relocations in subsequently-loaded libraries, even if RTLD_GLOBAL is used
@@ -85,6 +85,10 @@ if [ -n "${PREFIX:-}" ]; then
export PKG_CONFIG_LIBDIR="$abs_prefix/lib/pkgconfig"
fi
+# When compiling C++, some build systems will combine CFLAGS and CXXFLAGS, and
some will
+# use CXXFLAGS alone.
+export CXXFLAGS=$CFLAGS
+
# Use the same variable name as conda-build
if [ $(uname) = "Darwin" ]; then
export CPU_COUNT=$(sysctl -n hw.ncpu)
diff --git a/Android/android.py b/Android/android.py
index 8696d9eaeca19c..ae630aa8f4427c 100755
--- a/Android/android.py
+++ b/Android/android.py
@@ -138,8 +138,8 @@ def make_build_python(context):
def unpack_deps(host):
deps_url =
"https://github.com/beeware/cpython-android-source-deps/releases/download";
-for name_ver in ["bzip2-1.0.8-1", "libffi-3.4.4-2", "openssl-3.0.15-0",
- "sqlite-3.45.1-0", "xz-5.4.6-0"]:
+for name_ver in ["bzip2-1.0.8-2", "libffi-3.4.4-3", "openssl-3.0.15-4",
+ "sqlite-3.45.3-3", "xz-5.4.6-1"]:
filename = f"{name_ver}-{host}.tar.gz"
download(f"{deps_url}/{name_ver}/{filename}")
run(["tar", "-xf", filename])
@@ -189,12 +189,13 @@ def configure_host_python(context):
def make_host_python(context):
# The CFLAGS and LDFLAGS set in android-env include the prefix dir, so
-# delete any previously-installed Python libs and include files to prevent
-# them being used during the build.
+# delete any previous Python installation to prevent it being used during
+# the build.
host_dir = subdir(context.host)
prefix_dir = host_dir / "prefix"
delete_glob(f"{prefix_dir}/include/python*")
delete_glob(f"{prefix_dir}/lib/libpython*")
+delete_glob(f"{prefix_dir}/lib/python*")
os.chdir(host_dir / "build")
run(["make", "-j", str(os.cpu_count())], host=context.host)
diff --git a/Android/testbed/app/build.gradle.kts
b/Android/testbed/app/build.gradle.kts
index 7e0bef58ed88eb..6c17406c8724dc 100644
--- a/Android/testbed/app/build.gradle.kts
+++ b/Android/testbed/app/build.gradle.kts
@@ -30,16 +30,6 @@ val PYTHON_VERSION =
file("$PYTHON_DIR/Include/patchlevel.h").useLines {
throw GradleException("Failed to find Python version")
}
-android.ndkVersion = file("../../android-env.sh").useLines {
-for (line in it) {
-val match = """ndk_version=(\S+)""".toRegex().find(line)
-if (match != null) {
-return@useLines match.groupValues[1]
-}
-}
-throw GradleException("Failed to find NDK version")
-}
-
android {
namespace = "org.python.testbed"
@@ -55,11 +45,22 @@ android {
ndk.abiFilters.addAll(ABIS.keys)
externalNativeBuild.cmake.arguments(
"-DPYTHON_CROSS_DIR=$PYTHON_CROSS_DIR",
-"-DPYTHON_VERSION=$PYTHON_VERSION")
+"-DPYTHON_VERSION=$PYTHON_VERSION",
+"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON",
+)
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
+val androidEnvFile = file("../../android-env.sh").absoluteFile
+ndkVersion = androidEnvFile.useLines {
+for (line in it) {
+"""ndk_version=(\S+)""".toRegex().find(line)?.let {
+return@useLines it.groupValues[1]
+}
+}
+throw GradleException("Failed to find N
[Python-checkins] [3.13] gh-125859: Fix crash when `gc.get_objects` is called during GC (GH-125882) (GH-125921)
https://github.com/python/cpython/commit/5c2696bc261905b84c71ddbee3f439af568a8795 commit: 5c2696bc261905b84c71ddbee3f439af568a8795 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: colesbury date: 2024-10-24T14:08:15Z summary: [3.13] gh-125859: Fix crash when `gc.get_objects` is called during GC (GH-125882) (GH-125921) This fixes a crash when `gc.get_objects()` or `gc.get_referrers()` is called during a GC in the free threading build. Switch to `_PyObjectStack` to avoid corrupting the `struct worklist` linked list maintained by the GC. Also, don't return objects that are frozen (`gc.freeze()`) or in the process of being collected to more closely match the behavior of the default build. (cherry picked from commit e545ead66ce725aae6fb0ad5d733abe806c19750) Co-authored-by: Sam Gross files: A Lib/test/test_free_threading/test_gc.py A Misc/NEWS.d/next/Core_and_Builtins/2024-10-23-14-42-27.gh-issue-125859.m3EF9E.rst M Include/internal/pycore_object_stack.h M Lib/test/test_gc.py M Python/gc_free_threading.c diff --git a/Include/internal/pycore_object_stack.h b/Include/internal/pycore_object_stack.h index fc130b1e9920b4..639f3c0c0d0b76 100644 --- a/Include/internal/pycore_object_stack.h +++ b/Include/internal/pycore_object_stack.h @@ -73,6 +73,16 @@ _PyObjectStack_Pop(_PyObjectStack *stack) return obj; } +static inline Py_ssize_t +_PyObjectStack_Size(_PyObjectStack *stack) +{ +Py_ssize_t size = 0; +for (_PyObjectStackChunk *buf = stack->head; buf != NULL; buf = buf->prev) { +size += buf->n; +} +return size; +} + // Merge src into dst, leaving src empty extern void _PyObjectStack_Merge(_PyObjectStack *dst, _PyObjectStack *src); diff --git a/Lib/test/test_free_threading/test_gc.py b/Lib/test/test_free_threading/test_gc.py new file mode 100644 index 00..401067fe9c612c --- /dev/null +++ b/Lib/test/test_free_threading/test_gc.py @@ -0,0 +1,61 @@ +import unittest + +import threading +from threading import Thread +from unittest import TestCase +import gc + +from test.support import threading_helper + + +class MyObj: +pass + + +@threading_helper.requires_working_threading() +class TestGC(TestCase): +def test_get_objects(self): +event = threading.Event() + +def gc_thread(): +for i in range(100): +o = gc.get_objects() +event.set() + +def mutator_thread(): +while not event.is_set(): +o1 = MyObj() +o2 = MyObj() +o3 = MyObj() +o4 = MyObj() + +gcs = [Thread(target=gc_thread)] +mutators = [Thread(target=mutator_thread) for _ in range(4)] +with threading_helper.start_threads(gcs + mutators): +pass + +def test_get_referrers(self): +event = threading.Event() + +obj = MyObj() + +def gc_thread(): +for i in range(100): +o = gc.get_referrers(obj) +event.set() + +def mutator_thread(): +while not event.is_set(): +d1 = { "key": obj } +d2 = { "key": obj } +d3 = { "key": obj } +d4 = { "key": obj } + +gcs = [Thread(target=gc_thread) for _ in range(2)] +mutators = [Thread(target=mutator_thread) for _ in range(4)] +with threading_helper.start_threads(gcs + mutators): +pass + + +if __name__ == "__main__": +unittest.main() diff --git a/Lib/test/test_gc.py b/Lib/test/test_gc.py index c285fbddb1bf55..9ce9d938f8b3c1 100644 --- a/Lib/test/test_gc.py +++ b/Lib/test/test_gc.py @@ -1105,6 +1105,29 @@ def test_get_referents_on_capsule(self): self.assertEqual(len(gc.get_referents(untracked_capsule)), 0) gc.get_referents(tracked_capsule) +@cpython_only +def test_get_objects_during_gc(self): +# gh-125859: Calling gc.get_objects() or gc.get_referrers() during a +# collection should not crash. +test = self +collected = False + +class GetObjectsOnDel: +def __del__(self): +nonlocal collected +collected = True +objs = gc.get_objects() +# NB: can't use "in" here because some objects override __eq__ +for obj in objs: +test.assertTrue(obj is not self) +test.assertEqual(gc.get_referrers(self), []) + +obj = GetObjectsOnDel() +obj.cycle = obj +del obj + +gc.collect() +self.assertTrue(collected) class GCCallbackTests(unittest.TestCase): def setUp(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-23-14-42-27.gh-issue-125859.m3EF9E.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-23-14-42-27.gh-issue-125859.m3EF9E.rst new file mode 100644 index 00..d36aa8fbe7482f --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-
[Python-checkins] gh-125864: Propagate `pickle.loads()` failures in `InterpreterPoolExecutor` (gh-125898)
https://github.com/python/cpython/commit/41bd9d959ccdb1095b6662b903bb3cbd2a47087b
commit: 41bd9d959ccdb1095b6662b903bb3cbd2a47087b
branch: main
author: Peter Bierma
committer: ericsnowcurrently
date: 2024-10-24T10:51:45-06:00
summary:
gh-125864: Propagate `pickle.loads()` failures in `InterpreterPoolExecutor`
(gh-125898)
Authored-by: Peter Bierma
files:
M Lib/concurrent/futures/interpreter.py
M Lib/test/test_concurrent_futures/test_interpreter_pool.py
diff --git a/Lib/concurrent/futures/interpreter.py
b/Lib/concurrent/futures/interpreter.py
index fd7941adb766bb..d17688dc9d7346 100644
--- a/Lib/concurrent/futures/interpreter.py
+++ b/Lib/concurrent/futures/interpreter.py
@@ -107,7 +107,8 @@ def _call(cls, func, args, kwargs, resultsid):
@classmethod
def _call_pickled(cls, pickled, resultsid):
-fn, args, kwargs = pickle.loads(pickled)
+with cls._capture_exc(resultsid):
+fn, args, kwargs = pickle.loads(pickled)
cls._call(fn, args, kwargs, resultsid)
def __init__(self, initdata, shared=None):
diff --git a/Lib/test/test_concurrent_futures/test_interpreter_pool.py
b/Lib/test/test_concurrent_futures/test_interpreter_pool.py
index 5264b1bb6e9c75..ea1512fc830d0c 100644
--- a/Lib/test/test_concurrent_futures/test_interpreter_pool.py
+++ b/Lib/test/test_concurrent_futures/test_interpreter_pool.py
@@ -56,6 +56,16 @@ def pipe(self):
return r, w
+class PickleShenanigans:
+"""Succeeds with pickle.dumps(), but fails with pickle.loads()"""
+def __init__(self, value):
+if value == 1:
+raise RuntimeError("gotcha")
+
+def __reduce__(self):
+return (self.__class__, (1,))
+
+
class InterpreterPoolExecutorTest(
InterpretersMixin, ExecutorTest, BaseTestCase):
@@ -279,6 +289,14 @@ def test_idle_thread_reuse(self):
self.assertEqual(len(executor._threads), 1)
executor.shutdown(wait=True)
+def test_pickle_errors_propagate(self):
+# GH-125864: Pickle errors happen before the script tries to execute,
so the
+# queue used to wait infinitely.
+
+fut = self.executor.submit(PickleShenanigans(0))
+with self.assertRaisesRegex(RuntimeError, "gotcha"):
+fut.result()
+
class AsyncioTest(InterpretersMixin, testasyncio_utils.TestCase):
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-125942: Android: set stdout to `errors="backslashreplace"` (#125943)
https://github.com/python/cpython/commit/b08570c90eb9fa2e2ee4429909b14240b7a427d4
commit: b08570c90eb9fa2e2ee4429909b14240b7a427d4
branch: main
author: Malcolm Smith
committer: freakboy3742
date: 2024-10-25T08:35:41+08:00
summary:
gh-125942: Android: set stdout to `errors="backslashreplace"` (#125943)
Android stdout/err streams now use `backslashreplace` encoding to ensure
readability of the Android log.
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst
M Lib/_android_support.py
M Lib/test/test_android.py
diff --git a/Lib/_android_support.py b/Lib/_android_support.py
index 353b34fa36aca4..7572745c851847 100644
--- a/Lib/_android_support.py
+++ b/Lib/_android_support.py
@@ -31,16 +31,19 @@ def init_streams(android_log_write, stdout_prio,
stderr_prio):
logcat = Logcat(android_log_write)
sys.stdout = TextLogStream(
-stdout_prio, "python.stdout", sys.stdout.fileno(),
-errors=sys.stdout.errors)
+stdout_prio, "python.stdout", sys.stdout.fileno())
sys.stderr = TextLogStream(
-stderr_prio, "python.stderr", sys.stderr.fileno(),
-errors=sys.stderr.errors)
+stderr_prio, "python.stderr", sys.stderr.fileno())
class TextLogStream(io.TextIOWrapper):
def __init__(self, prio, tag, fileno=None, **kwargs):
+# The default is surrogateescape for stdout and backslashreplace for
+# stderr, but in the context of an Android log, readability is more
+# important than reversibility.
kwargs.setdefault("encoding", "UTF-8")
+kwargs.setdefault("errors", "backslashreplace")
+
super().__init__(BinaryLogStream(prio, tag, fileno), **kwargs)
self._lock = RLock()
self._pending_bytes = []
diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py
index 2ef9f10fdcc1cc..076190f7572045 100644
--- a/Lib/test/test_android.py
+++ b/Lib/test/test_android.py
@@ -123,13 +123,10 @@ def test_str(self):
self.assertIs(stream.readable(), False)
self.assertEqual(stream.fileno(), fileno)
self.assertEqual("UTF-8", stream.encoding)
+self.assertEqual("backslashreplace", stream.errors)
self.assertIs(stream.line_buffering, True)
self.assertIs(stream.write_through, False)
-# stderr is backslashreplace by default; stdout is configured
-# that way by libregrtest.main.
-self.assertEqual("backslashreplace", stream.errors)
-
def write(s, lines=None, *, write_len=None):
if write_len is None:
write_len = len(s)
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst
new file mode 100644
index 00..d1b1ecd2a724ab
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst
@@ -0,0 +1,2 @@
+On Android, the ``errors`` setting of :any:`sys.stdout` was changed from
+``surrogateescape`` to ``backslashreplace``.
___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]
[Python-checkins] gh-125900: Clean-up logic around immortalization in free-threading (#125901)
https://github.com/python/cpython/commit/332356b880576a1a00b5dc34f03d7d3995dd4512
commit: 332356b880576a1a00b5dc34f03d7d3995dd4512
branch: main
author: Sam Gross
committer: colesbury
date: 2024-10-24T18:09:59-04:00
summary:
gh-125900: Clean-up logic around immortalization in free-threading (#125901)
* Remove `@suppress_immortalization` decorator
* Make suppression flag per-thread instead of per-interpreter
* Suppress immortalization in `eval()` to avoid refleaks in three tests
(test_datetime.test_roundtrip, test_logging.test_config8_ok, and
test_random.test_after_fork).
* frozenset() is constant, but not a singleton. When run multiple times,
the test could fail due to constant interning.
files:
M Include/internal/pycore_gc.h
M Include/internal/pycore_tstate.h
M Lib/test/libregrtest/main.py
M Lib/test/libregrtest/single.py
M Lib/test/seq_tests.py
M Lib/test/support/__init__.py
M Lib/test/test_ast/test_ast.py
M Lib/test/test_capi/test_misc.py
M Lib/test/test_capi/test_watchers.py
M Lib/test/test_code.py
M Lib/test/test_descr.py
M Lib/test/test_functools.py
M Lib/test/test_gc.py
M Lib/test/test_inspect/test_inspect.py
M Lib/test/test_module/__init__.py
M Lib/test/test_ordered_dict.py
M Lib/test/test_struct.py
M Lib/test/test_trace.py
M Lib/test/test_weakref.py
M Lib/test/test_zoneinfo/test_zoneinfo.py
M Modules/_testinternalcapi.c
M Objects/codeobject.c
M Python/bltinmodule.c
diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h
index cf96f661e6cd7e..b85957df5a6b9f 100644
--- a/Include/internal/pycore_gc.h
+++ b/Include/internal/pycore_gc.h
@@ -342,14 +342,6 @@ struct _gc_runtime_state {
collections, and are awaiting to undergo a full collection for
the first time. */
Py_ssize_t long_lived_pending;
-
-/* gh-117783: Deferred reference counting is not fully implemented yet, so
- as a temporary measure we treat objects using deferred reference
- counting as immortal. The value may be zero, one, or a negative number:
-0: immortalize deferred RC objects once the first thread is created
-1: immortalize all deferred RC objects immediately
-<0: suppressed; don't immortalize objects */
-int immortalize;
#endif
};
diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h
index a72ef4493b77ca..e0e7d5ebf0912c 100644
--- a/Include/internal/pycore_tstate.h
+++ b/Include/internal/pycore_tstate.h
@@ -41,6 +41,9 @@ typedef struct _PyThreadStateImpl {
// If set, don't use per-thread refcounts
int is_finalized;
} refcounts;
+
+// When >1, code objects do not immortalize their non-string constants.
+int suppress_co_const_immortalization;
#endif
#if defined(Py_REF_DEBUG) && defined(Py_GIL_DISABLED)
diff --git a/Lib/test/libregrtest/main.py b/Lib/test/libregrtest/main.py
index 2ef4349552bf5f..11ebb09fbb4745 100644
--- a/Lib/test/libregrtest/main.py
+++ b/Lib/test/libregrtest/main.py
@@ -7,8 +7,7 @@
import time
import trace
-from test.support import (os_helper, MS_WINDOWS, flush_std_streams,
- suppress_immortalization)
+from test.support import os_helper, MS_WINDOWS, flush_std_streams
from .cmdline import _parse_args, Namespace
from .findtests import findtests, split_test_packages, list_cases
@@ -535,10 +534,7 @@ def _run_tests(self, selected: TestTuple, tests: TestList
| None) -> int:
if self.num_workers:
self._run_tests_mp(runtests, self.num_workers)
else:
-# gh-117783: don't immortalize deferred objects when tracking
-# refleaks. Only relevant for the free-threaded build.
-with suppress_immortalization(runtests.hunt_refleak):
-self.run_tests_sequentially(runtests)
+self.run_tests_sequentially(runtests)
coverage = self.results.get_coverage_results()
self.display_result(runtests)
diff --git a/Lib/test/libregrtest/single.py b/Lib/test/libregrtest/single.py
index 67cc9db54f7485..17323e7f9cf730 100644
--- a/Lib/test/libregrtest/single.py
+++ b/Lib/test/libregrtest/single.py
@@ -304,10 +304,7 @@ def run_single_test(test_name: TestName, runtests:
RunTests) -> TestResult:
result = TestResult(test_name)
pgo = runtests.pgo
try:
-# gh-117783: don't immortalize deferred objects when tracking
-# refleaks. Only relevant for the free-threaded build.
-with support.suppress_immortalization(runtests.hunt_refleak):
-_runtest(result, runtests)
+_runtest(result, runtests)
except:
if not pgo:
msg = traceback.format_exc()
diff --git a/Lib/test/seq_tests.py b/Lib/test/seq_tests.py
index 719c9434a16820..a41970d8f3f55a 100644
--- a/Lib/test/seq_tests.py
+++ b/Lib/test/seq_tests.py
@@ -426,7 +426,6 @@ def test_pickle(self):
self.assertEqual(lst2, lst)
self.assertNotEqual(id(lst2), id(lst))
-@suppo
[Python-checkins] [3.13] gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (#125938)
https://github.com/python/cpython/commit/92d301eb678427dbb40aef2e0c9c91f75f278413 commit: 92d301eb678427dbb40aef2e0c9c91f75f278413 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: hugovk <[email protected]> date: 2024-10-24T20:57:52Z summary: [3.13] gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (#125938) gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (cherry picked from commit 1306f33c84b2745aa8af5e3e8f680aa80b836c0e) Co-authored-by: Kerim Kabirov Co-authored-by: Hugo van Kemenade <[email protected]> files: M Doc/tools/static/rtd_switcher.js diff --git a/Doc/tools/static/rtd_switcher.js b/Doc/tools/static/rtd_switcher.js index f5dc7045a0dbc4..2bf01a002db90c 100644 --- a/Doc/tools/static/rtd_switcher.js +++ b/Doc/tools/static/rtd_switcher.js @@ -7,7 +7,7 @@ document.addEventListener("readthedocs-addons-data-ready", function(event) { const config = event.detail.data() const versionSelect = ` - + ${ config.versions.active.map( (version) => ` a.language.name.localeCompare(b.language.name)); const languageSelect = ` - + ${ languages.map( (translation) => ` https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-125842: Fix `sys.exit(0xffff_ffff)` on Windows (GH-125896) (GH-125925)
https://github.com/python/cpython/commit/52b57eee64c1fe98306fae9643f7c8b66548fab0 commit: 52b57eee64c1fe98306fae9643f7c8b66548fab0 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: colesbury date: 2024-10-24T16:27:30Z summary: [3.13] gh-125842: Fix `sys.exit(0x_)` on Windows (GH-125896) (GH-125925) On Windows, `long` is a signed 32-bit integer so it can't represent `0x_` without overflow. Windows exit codes are unsigned 32-bit integers, so if a child process exits with `-1`, it will be represented as `0x_`. Also fix a number of other possible cases where `_Py_HandleSystemExit` could return with an exception set, leading to a `SystemError` (or fatal error in debug builds) later on during shutdown. (cherry picked from commit ad6110a93ffa82cae71af6c78692de065d3871b5) Co-authored-by: Sam Gross files: A Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst M Lib/test/test_sys.py M Python/pythonrun.c diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 3d2bcf2358f413..400577d36cd44d 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -206,6 +206,20 @@ def test_exit(self): self.assertEqual(out, b'') self.assertEqual(err, b'') +# gh-125842: Windows uses 32-bit unsigned integers for exit codes +# so a -1 exit code is sometimes interpreted as 0x_. +rc, out, err = assert_python_failure('-c', 'import sys; sys.exit(0x_)') +self.assertIn(rc, (-1, 0xff, 0x_)) +self.assertEqual(out, b'') +self.assertEqual(err, b'') + +# Overflow results in a -1 exit code, which may be converted to 0xff +# or 0x_. +rc, out, err = assert_python_failure('-c', 'import sys; sys.exit(2**128)') +self.assertIn(rc, (-1, 0xff, 0x_)) +self.assertEqual(out, b'') +self.assertEqual(err, b'') + # call with integer argument with self.assertRaises(SystemExit) as cm: sys.exit(42) diff --git a/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst b/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst new file mode 100644 index 00..63644721d57f5b --- /dev/null +++ b/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst @@ -0,0 +1,2 @@ +Fix a :exc:`SystemError` when :func:`sys.exit` is called with ``0x`` +on Windows. diff --git a/Python/pythonrun.c b/Python/pythonrun.c index b67597113ead45..5891d50cd3f598 100644 --- a/Python/pythonrun.c +++ b/Python/pythonrun.c @@ -563,6 +563,30 @@ PyRun_SimpleStringFlags(const char *command, PyCompilerFlags *flags) return _PyRun_SimpleStringFlagsWithName(command, NULL, flags); } +static int +parse_exit_code(PyObject *code, int *exitcode_p) +{ +if (PyLong_Check(code)) { +// gh-125842: Use a long long to avoid an overflow error when `long` +// is 32-bit. We still truncate the result to an int. +int exitcode = (int)PyLong_AsLongLong(code); +if (exitcode == -1 && PyErr_Occurred()) { +// On overflow or other error, clear the exception and use -1 +// as the exit code to match historical Python behavior. +PyErr_Clear(); +*exitcode_p = -1; +return 1; +} +*exitcode_p = exitcode; +return 1; +} +else if (code == Py_None) { +*exitcode_p = 0; +return 1; +} +return 0; +} + int _Py_HandleSystemExit(int *exitcode_p) { @@ -579,50 +603,40 @@ _Py_HandleSystemExit(int *exitcode_p) fflush(stdout); -int exitcode = 0; - PyObject *exc = PyErr_GetRaisedException(); -if (exc == NULL) { -goto done; -} -assert(PyExceptionInstance_Check(exc)); +assert(exc != NULL && PyExceptionInstance_Check(exc)); -/* The error code should be in the `code' attribute. */ PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code)); -if (code) { +if (code == NULL) { +// If the exception has no 'code' attribute, print the exception below +PyErr_Clear(); +} +else if (parse_exit_code(code, exitcode_p)) { +Py_DECREF(code); +Py_CLEAR(exc); +return 1; +} +else { +// If code is not an int or None, print it below Py_SETREF(exc, code); -if (exc == Py_None) { -goto done; -} } -/* If we failed to dig out the 'code' attribute, - * just let the else clause below print the error. - */ -if (PyLong_Check(exc)) { -exitcode = (int)PyLong_AsLong(exc); +PyThreadState *tstate = _PyThreadState_GET(); +PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr)); +if (sys_stderr != NULL && sys_stderr != Py_None) { +if (PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW) < 0) { +PyErr_Clear(); +} } else { -PyT
[Python-checkins] gh-125909: Avoid a redirect when linking to the devguide (#125826)
https://github.com/python/cpython/commit/5003ad5c5ea508f0dde1b374cd8bc6a481ad5c5d commit: 5003ad5c5ea508f0dde1b374cd8bc6a481ad5c5d branch: main author: partev committer: AA-Turner <[email protected]> date: 2024-10-24T17:41:01+01:00 summary: gh-125909: Avoid a redirect when linking to the devguide (#125826) files: M Doc/tools/templates/indexcontent.html diff --git a/Doc/tools/templates/indexcontent.html b/Doc/tools/templates/indexcontent.html index f2e9fbb0106452..2686f48dad2a95 100644 --- a/Doc/tools/templates/indexcontent.html +++ b/Doc/tools/templates/indexcontent.html @@ -59,7 +59,7 @@ {{ docstitle|e }} {% trans %}Reporting issues{% endtrans %} - https://devguide.python.org/docquality/#helping-with-documentation";>{% trans %}Contributing to Docs{% endtrans %} + https://devguide.python.org/documentation/help-documenting/";>{% trans %}Contributing to Docs{% endtrans %} {% trans %}Download the documentation{% endtrans %} {% trans %}History and license of Python{% endtrans %} ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] gh-123930: Better error for "from imports" when script shadows module (#123929)
https://github.com/python/cpython/commit/500f5338a8fe13719478589333fcd296e8e8eb02 commit: 500f5338a8fe13719478589333fcd296e8e8eb02 branch: main author: Shantanu <[email protected]> committer: hauntsaninja <[email protected]> date: 2024-10-24T12:11:12-07:00 summary: gh-123930: Better error for "from imports" when script shadows module (#123929) files: A Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-01-32-07.gh-issue-123930.BkPfB6.rst M Doc/whatsnew/3.13.rst M Include/internal/pycore_moduleobject.h M Lib/test/test_import/__init__.py M Objects/moduleobject.c M Python/ceval.c diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index f9e74a9b8ff9c6..de4c7fd4c0486b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -274,7 +274,7 @@ Improved error messages File "/home/me/random.py", line 3, in print(random.randint(5)) ^^ - AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it has the same name as the standard library module named 'random' and the import system gives it precedence) + AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module) Similarly, if a script has the same name as a third-party module that it attempts to import and this results in errors, @@ -289,7 +289,7 @@ Improved error messages File "/home/me/numpy.py", line 3, in np.array([1, 2, 3]) - AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a third-party module you intended to import) + AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a library you intended to import) (Contributed by Shantanu Jain in :gh:`95754`.) diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index cc2dda48ed9f28..9bb282a13a9659 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -11,6 +11,8 @@ extern "C" { extern void _PyModule_Clear(PyObject *); extern void _PyModule_ClearDict(PyObject *); extern int _PyModuleSpec_IsInitializing(PyObject *); +extern int _PyModuleSpec_GetFileOrigin(PyObject *, PyObject **); +extern int _PyModule_IsPossiblyShadowing(PyObject *); extern int _PyModule_IsExtension(PyObject *obj); diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 5d0d02480b3929..5b7ba90b2cc7c6 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -804,104 +804,133 @@ def test_issue105979(self): str(cm.exception)) def test_script_shadowing_stdlib(self): -with os_helper.temp_dir() as tmp: -with open(os.path.join(tmp, "fractions.py"), "w", encoding='utf-8') as f: -f.write("import fractions\nfractions.Fraction") - -expected_error = ( -rb"AttributeError: module 'fractions' has no attribute 'Fraction' " -rb"\(consider renaming '.*fractions.py' since it has the " -rb"same name as the standard library module named 'fractions' " -rb"and the import system gives it precedence\)" +script_errors = [ +( +"import fractions\nfractions.Fraction", +rb"AttributeError: module 'fractions' has no attribute 'Fraction'" +), +( +"from fractions import Fraction", +rb"ImportError: cannot import name 'Fraction' from 'fractions'" ) +] +for script, error in script_errors: +with self.subTest(script=script), os_helper.temp_dir() as tmp: +with open(os.path.join(tmp, "fractions.py"), "w", encoding='utf-8') as f: +f.write(script) + +expected_error = error + ( +rb" \(consider renaming '.*fractions.py' since it has the " +rb"same name as the standard library module named 'fractions' " +rb"and prevents importing that standard library module\)" +) -popen = script_helper.spawn_python(os.path.join(tmp, "fractions.py"), cwd=tmp) -stdout, stderr = popen.communicate() -self.assertRegex(stdout, expected_error) +popen = script_helper.spawn_python(os.path.join(tmp, "fractions.py"), cwd=tmp) +stdout, stderr = popen.communicate() +self.assertRegex(stdout, expected_error) -popen = script_helper.spawn_python('-m', 'fractions', cwd=tmp) -stdout, stderr = popen.communicate
[Python-checkins] gh-125842: Fix `sys.exit(0xffff_ffff)` on Windows (#125896)
https://github.com/python/cpython/commit/ad6110a93ffa82cae71af6c78692de065d3871b5
commit: ad6110a93ffa82cae71af6c78692de065d3871b5
branch: main
author: Sam Gross
committer: colesbury
date: 2024-10-24T12:03:50-04:00
summary:
gh-125842: Fix `sys.exit(0x_)` on Windows (#125896)
On Windows, `long` is a signed 32-bit integer so it can't represent
`0x_` without overflow. Windows exit codes are unsigned 32-bit
integers, so if a child process exits with `-1`, it will be represented
as `0x_`.
Also fix a number of other possible cases where `_Py_HandleSystemExit`
could return with an exception set, leading to a `SystemError` (or
fatal error in debug builds) later on during shutdown.
files:
A Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst
M Lib/test/test_sys.py
M Python/pythonrun.c
diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py
index 9689ef8e96e072..c0862d7d15f39e 100644
--- a/Lib/test/test_sys.py
+++ b/Lib/test/test_sys.py
@@ -206,6 +206,20 @@ def test_exit(self):
self.assertEqual(out, b'')
self.assertEqual(err, b'')
+# gh-125842: Windows uses 32-bit unsigned integers for exit codes
+# so a -1 exit code is sometimes interpreted as 0x_.
+rc, out, err = assert_python_failure('-c', 'import sys;
sys.exit(0x_)')
+self.assertIn(rc, (-1, 0xff, 0x_))
+self.assertEqual(out, b'')
+self.assertEqual(err, b'')
+
+# Overflow results in a -1 exit code, which may be converted to 0xff
+# or 0x_.
+rc, out, err = assert_python_failure('-c', 'import sys;
sys.exit(2**128)')
+self.assertIn(rc, (-1, 0xff, 0x_))
+self.assertEqual(out, b'')
+self.assertEqual(err, b'')
+
# call with integer argument
with self.assertRaises(SystemExit) as cm:
sys.exit(42)
diff --git
a/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst
b/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst
new file mode 100644
index 00..63644721d57f5b
--- /dev/null
+++ b/Misc/NEWS.d/next/Windows/2024-10-23-17-24-23.gh-issue-125842.m3EF9E.rst
@@ -0,0 +1,2 @@
+Fix a :exc:`SystemError` when :func:`sys.exit` is called with ``0x``
+on Windows.
diff --git a/Python/pythonrun.c b/Python/pythonrun.c
index fc0f11bc4e8af4..8b57018321c070 100644
--- a/Python/pythonrun.c
+++ b/Python/pythonrun.c
@@ -564,6 +564,30 @@ PyRun_SimpleStringFlags(const char *command,
PyCompilerFlags *flags)
return _PyRun_SimpleStringFlagsWithName(command, NULL, flags);
}
+static int
+parse_exit_code(PyObject *code, int *exitcode_p)
+{
+if (PyLong_Check(code)) {
+// gh-125842: Use a long long to avoid an overflow error when `long`
+// is 32-bit. We still truncate the result to an int.
+int exitcode = (int)PyLong_AsLongLong(code);
+if (exitcode == -1 && PyErr_Occurred()) {
+// On overflow or other error, clear the exception and use -1
+// as the exit code to match historical Python behavior.
+PyErr_Clear();
+*exitcode_p = -1;
+return 1;
+}
+*exitcode_p = exitcode;
+return 1;
+}
+else if (code == Py_None) {
+*exitcode_p = 0;
+return 1;
+}
+return 0;
+}
+
int
_Py_HandleSystemExit(int *exitcode_p)
{
@@ -580,50 +604,40 @@ _Py_HandleSystemExit(int *exitcode_p)
fflush(stdout);
-int exitcode = 0;
-
PyObject *exc = PyErr_GetRaisedException();
-if (exc == NULL) {
-goto done;
-}
-assert(PyExceptionInstance_Check(exc));
+assert(exc != NULL && PyExceptionInstance_Check(exc));
-/* The error code should be in the `code' attribute. */
PyObject *code = PyObject_GetAttr(exc, &_Py_ID(code));
-if (code) {
+if (code == NULL) {
+// If the exception has no 'code' attribute, print the exception below
+PyErr_Clear();
+}
+else if (parse_exit_code(code, exitcode_p)) {
+Py_DECREF(code);
+Py_CLEAR(exc);
+return 1;
+}
+else {
+// If code is not an int or None, print it below
Py_SETREF(exc, code);
-if (exc == Py_None) {
-goto done;
-}
}
-/* If we failed to dig out the 'code' attribute,
- * just let the else clause below print the error.
- */
-if (PyLong_Check(exc)) {
-exitcode = (int)PyLong_AsLong(exc);
+PyThreadState *tstate = _PyThreadState_GET();
+PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
+if (sys_stderr != NULL && sys_stderr != Py_None) {
+if (PyFile_WriteObject(exc, sys_stderr, Py_PRINT_RAW) < 0) {
+PyErr_Clear();
+}
}
else {
-PyThreadState *tstate = _PyThreadState_GET();
-PyObject *sys_stderr = _PySys_GetAttr(tstate, &_Py_ID(stderr));
-/* We clear the exception here to avoid triggerin
[Python-checkins] [3.13] gh-123930: Better error for "from imports" when script shadows module (GH-123929) (#125937)
https://github.com/python/cpython/commit/3d8b6f0977fa28335da6071e26a9699e90f0a168 commit: 3d8b6f0977fa28335da6071e26a9699e90f0a168 branch: 3.13 author: Shantanu <[email protected]> committer: hauntsaninja <[email protected]> date: 2024-10-24T19:37:31Z summary: [3.13] gh-123930: Better error for "from imports" when script shadows module (GH-123929) (#125937) gh-123930: Better error for "from imports" when script shadows module (#123929) (cherry picked from commit 500f5338a8fe13719478589333fcd296e8e8eb02) files: A Misc/NEWS.d/next/Core_and_Builtins/2024-09-11-01-32-07.gh-issue-123930.BkPfB6.rst M Doc/whatsnew/3.13.rst M Include/internal/pycore_moduleobject.h M Lib/test/test_import/__init__.py M Objects/moduleobject.c M Python/ceval.c diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst index f9e74a9b8ff9c6..de4c7fd4c0486b 100644 --- a/Doc/whatsnew/3.13.rst +++ b/Doc/whatsnew/3.13.rst @@ -274,7 +274,7 @@ Improved error messages File "/home/me/random.py", line 3, in print(random.randint(5)) ^^ - AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it has the same name as the standard library module named 'random' and the import system gives it precedence) + AttributeError: module 'random' has no attribute 'randint' (consider renaming '/home/me/random.py' since it has the same name as the standard library module named 'random' and prevents importing that standard library module) Similarly, if a script has the same name as a third-party module that it attempts to import and this results in errors, @@ -289,7 +289,7 @@ Improved error messages File "/home/me/numpy.py", line 3, in np.array([1, 2, 3]) - AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a third-party module you intended to import) + AttributeError: module 'numpy' has no attribute 'array' (consider renaming '/home/me/numpy.py' if it has the same name as a library you intended to import) (Contributed by Shantanu Jain in :gh:`95754`.) diff --git a/Include/internal/pycore_moduleobject.h b/Include/internal/pycore_moduleobject.h index 049677b292e235..dacc00dba54495 100644 --- a/Include/internal/pycore_moduleobject.h +++ b/Include/internal/pycore_moduleobject.h @@ -11,6 +11,8 @@ extern "C" { extern void _PyModule_Clear(PyObject *); extern void _PyModule_ClearDict(PyObject *); extern int _PyModuleSpec_IsInitializing(PyObject *); +extern int _PyModuleSpec_GetFileOrigin(PyObject *, PyObject **); +extern int _PyModule_IsPossiblyShadowing(PyObject *); extern int _PyModule_IsExtension(PyObject *obj); diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 3048894350e896..fac5265f1758da 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -823,104 +823,133 @@ def test_issue105979(self): str(cm.exception)) def test_script_shadowing_stdlib(self): -with os_helper.temp_dir() as tmp: -with open(os.path.join(tmp, "fractions.py"), "w", encoding='utf-8') as f: -f.write("import fractions\nfractions.Fraction") - -expected_error = ( -rb"AttributeError: module 'fractions' has no attribute 'Fraction' " -rb"\(consider renaming '.*fractions.py' since it has the " -rb"same name as the standard library module named 'fractions' " -rb"and the import system gives it precedence\)" +script_errors = [ +( +"import fractions\nfractions.Fraction", +rb"AttributeError: module 'fractions' has no attribute 'Fraction'" +), +( +"from fractions import Fraction", +rb"ImportError: cannot import name 'Fraction' from 'fractions'" ) +] +for script, error in script_errors: +with self.subTest(script=script), os_helper.temp_dir() as tmp: +with open(os.path.join(tmp, "fractions.py"), "w", encoding='utf-8') as f: +f.write(script) + +expected_error = error + ( +rb" \(consider renaming '.*fractions.py' since it has the " +rb"same name as the standard library module named 'fractions' " +rb"and prevents importing that standard library module\)" +) -popen = script_helper.spawn_python(os.path.join(tmp, "fractions.py"), cwd=tmp) -stdout, stderr = popen.communicate() -self.assertRegex(stdout, expected_error) +popen = script_helper.spawn_python(os.path.join(tmp, "fractions.py"), cwd=tmp) +stdout, stderr = popen.communicate() +
[Python-checkins] gh-118950: Fix SSLProtocol.connection_lost not being called when OSError is thrown (#118960)
https://github.com/python/cpython/commit/3f24bde0b6689b8f05872a8118a97908b5a94659 commit: 3f24bde0b6689b8f05872a8118a97908b5a94659 branch: main author: Javad Shafique committer: kumaraditya303 date: 2024-10-24T17:41:16Z summary: gh-118950: Fix SSLProtocol.connection_lost not being called when OSError is thrown (#118960) Co-authored-by: Kumar Aditya files: A Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst M Lib/asyncio/sslproto.py M Lib/test/test_asyncio/test_sslproto.py diff --git a/Lib/asyncio/sslproto.py b/Lib/asyncio/sslproto.py index fa99d4533aa0a6..74c5f0d5ca0609 100644 --- a/Lib/asyncio/sslproto.py +++ b/Lib/asyncio/sslproto.py @@ -101,7 +101,7 @@ def get_protocol(self): return self._ssl_protocol._app_protocol def is_closing(self): -return self._closed +return self._closed or self._ssl_protocol._is_transport_closing() def close(self): """Close the transport. @@ -379,6 +379,9 @@ def _get_app_transport(self): self._app_transport_created = True return self._app_transport +def _is_transport_closing(self): +return self._transport is not None and self._transport.is_closing() + def connection_made(self, transport): """Called when the low-level connection is made. diff --git a/Lib/test/test_asyncio/test_sslproto.py b/Lib/test/test_asyncio/test_sslproto.py index f5f0afeab51c9e..761904c5146b6a 100644 --- a/Lib/test/test_asyncio/test_sslproto.py +++ b/Lib/test/test_asyncio/test_sslproto.py @@ -109,6 +109,54 @@ def test_connection_lost(self): test_utils.run_briefly(self.loop) self.assertIsInstance(waiter.exception(), ConnectionAbortedError) +def test_connection_lost_when_busy(self): +# gh-118950: SSLProtocol.connection_lost not being called when OSError +# is thrown on asyncio.write. +sock = mock.Mock() +sock.fileno = mock.Mock(return_value=12345) +sock.send = mock.Mock(side_effect=BrokenPipeError) + +# construct StreamWriter chain that contains loop dependant logic this emulates +# what _make_ssl_transport() does in BaseSelectorEventLoop +reader = asyncio.StreamReader(limit=2 ** 16, loop=self.loop) +protocol = asyncio.StreamReaderProtocol(reader, loop=self.loop) +ssl_proto = self.ssl_protocol(proto=protocol) + +# emulate reading decompressed data +sslobj = mock.Mock() +sslobj.read.side_effect = ssl.SSLWantReadError +sslobj.write.side_effect = ssl.SSLWantReadError +ssl_proto._sslobj = sslobj + +# emulate outgoing data +data = b'An interesting message' + +outgoing = mock.Mock() +outgoing.read = mock.Mock(return_value=data) +outgoing.pending = len(data) +ssl_proto._outgoing = outgoing + +# use correct socket transport to initialize the SSLProtocol +self.loop._make_socket_transport(sock, ssl_proto) + +transport = ssl_proto._app_transport +writer = asyncio.StreamWriter(transport, protocol, reader, self.loop) + +async def main(): +# writes data to transport +async def write(): +writer.write(data) +await writer.drain() + +# try to write for the first time +await write() +# try to write for the second time, this raises as the connection_lost +# callback should be done with error +with self.assertRaises(ConnectionResetError): +await write() + +self.loop.run_until_complete(main()) + def test_close_during_handshake(self): # bpo-29743 Closing transport during handshake process leaks socket waiter = self.loop.create_future() diff --git a/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst b/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst new file mode 100644 index 00..82be975f4d808d --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2024-05-12-03-10-36.gh-issue-118950.5Wc4vp.rst @@ -0,0 +1 @@ +Fix bug where SSLProtocol.connection_lost wasn't getting called when OSError was thrown on writing to socket. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.12] gh-125909: Avoid a redirect when linking to the devguide (GH-125826) (#125930)
https://github.com/python/cpython/commit/869119e36d1b1367eff7003b04dfbe2ce7129a20 commit: 869119e36d1b1367eff7003b04dfbe2ce7129a20 branch: 3.12 author: Miss Islington (bot) <[email protected]> committer: AA-Turner <[email protected]> date: 2024-10-24T16:50:16Z summary: [3.12] gh-125909: Avoid a redirect when linking to the devguide (GH-125826) (#125930) (cherry picked from commit 5003ad5c5ea508f0dde1b374cd8bc6a481ad5c5d) Co-authored-by: partev files: M Doc/tools/templates/indexcontent.html diff --git a/Doc/tools/templates/indexcontent.html b/Doc/tools/templates/indexcontent.html index f2e9fbb0106452..2686f48dad2a95 100644 --- a/Doc/tools/templates/indexcontent.html +++ b/Doc/tools/templates/indexcontent.html @@ -59,7 +59,7 @@ {{ docstitle|e }} {% trans %}Reporting issues{% endtrans %} - https://devguide.python.org/docquality/#helping-with-documentation";>{% trans %}Contributing to Docs{% endtrans %} + https://devguide.python.org/documentation/help-documenting/";>{% trans %}Contributing to Docs{% endtrans %} {% trans %}Download the documentation{% endtrans %} {% trans %}History and license of Python{% endtrans %} ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.12] gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (#125939)
https://github.com/python/cpython/commit/31ff9e5ac685dff58456f7fa93d1872e8cda604f commit: 31ff9e5ac685dff58456f7fa93d1872e8cda604f branch: 3.12 author: Miss Islington (bot) <[email protected]> committer: hugovk <[email protected]> date: 2024-10-24T21:00:45Z summary: [3.12] gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (#125939) gh-125933: Add ARIA labels to select elements in the version switcher (GH-125934) (cherry picked from commit 1306f33c84b2745aa8af5e3e8f680aa80b836c0e) Co-authored-by: Kerim Kabirov Co-authored-by: Hugo van Kemenade <[email protected]> files: M Doc/tools/static/rtd_switcher.js diff --git a/Doc/tools/static/rtd_switcher.js b/Doc/tools/static/rtd_switcher.js index f5dc7045a0dbc4..2bf01a002db90c 100644 --- a/Doc/tools/static/rtd_switcher.js +++ b/Doc/tools/static/rtd_switcher.js @@ -7,7 +7,7 @@ document.addEventListener("readthedocs-addons-data-ready", function(event) { const config = event.detail.data() const versionSelect = ` - + ${ config.versions.active.map( (version) => ` a.language.name.localeCompare(b.language.name)); const languageSelect = ` - + ${ languages.map( (translation) => ` https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-125259: Fix error notes removal in enum initialization (GH-125647) (GH-125858)
https://github.com/python/cpython/commit/32830cf7030f5db5ef86204abe17dc7c4fcec7ff commit: 32830cf7030f5db5ef86204abe17dc7c4fcec7ff branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: ethanfurman date: 2024-10-24T20:24:23-07:00 summary: [3.13] gh-125259: Fix error notes removal in enum initialization (GH-125647) (GH-125858) gh-125259: Fix error notes removal in enum initialization (GH-125647) (cherry picked from commit 34653bba644aa5481613f398153757d7357e39ea) Co-authored-by: Mario Šaško files: A Misc/NEWS.d/next/Library/2024-10-17-16-10-29.gh-issue-125259.oMew0c.rst M Lib/enum.py M Lib/test/test_enum.py diff --git a/Lib/enum.py b/Lib/enum.py index ac13e2c733061b..fc765643692db2 100644 --- a/Lib/enum.py +++ b/Lib/enum.py @@ -564,22 +564,16 @@ def __new__(metacls, cls, bases, classdict, *, boundary=None, _simple=False, **k classdict['_all_bits_'] = 0 classdict['_inverted_'] = None try: -exc = None classdict['_%s__in_progress' % cls] = True enum_class = super().__new__(metacls, cls, bases, classdict, **kwds) classdict['_%s__in_progress' % cls] = False delattr(enum_class, '_%s__in_progress' % cls) except Exception as e: -# since 3.12 the line "Error calling __set_name__ on '_proto_member' instance ..." -# is tacked on to the error instead of raising a RuntimeError -# recreate the exception to discard -exc = type(e)(str(e)) -exc.__cause__ = e.__cause__ -exc.__context__ = e.__context__ -tb = e.__traceback__ -if exc is not None: -raise exc.with_traceback(tb) -# +# since 3.12 the note "Error calling __set_name__ on '_proto_member' instance ..." +# is tacked on to the error instead of raising a RuntimeError, so discard it +if hasattr(e, '__notes__'): +del e.__notes__ +raise # update classdict with any changes made by __init_subclass__ classdict.update(enum_class.__dict__) # diff --git a/Lib/test/test_enum.py b/Lib/test/test_enum.py index a99347191f88a8..e9948de39ed599 100644 --- a/Lib/test/test_enum.py +++ b/Lib/test/test_enum.py @@ -1902,6 +1902,25 @@ def test_wrong_inheritance_order(self): class Wrong(Enum, str): NotHere = 'error before this point' +def test_raise_custom_error_on_creation(self): +class InvalidRgbColorError(ValueError): +def __init__(self, r, g, b): +self.r = r +self.g = g +self.b = b +super().__init__(f'({r}, {g}, {b}) is not a valid RGB color') + +with self.assertRaises(InvalidRgbColorError): +class RgbColor(Enum): +RED = (255, 0, 0) +GREEN = (0, 255, 0) +BLUE = (0, 0, 255) +INVALID = (256, 0, 0) + +def __init__(self, r, g, b): +if not all(0 <= val <= 255 for val in (r, g, b)): +raise InvalidRgbColorError(r, g, b) + def test_intenum_transitivity(self): class number(IntEnum): one = 1 diff --git a/Misc/NEWS.d/next/Library/2024-10-17-16-10-29.gh-issue-125259.oMew0c.rst b/Misc/NEWS.d/next/Library/2024-10-17-16-10-29.gh-issue-125259.oMew0c.rst new file mode 100644 index 00..4fa6330abea512 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-17-16-10-29.gh-issue-125259.oMew0c.rst @@ -0,0 +1 @@ +Fix the notes removal logic for errors thrown in enum initialization. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-125245: Fix race condition when importing `collections.abc` (GH-125415) (GH-125944)
https://github.com/python/cpython/commit/d46d291bd390027811937bbf5af2e2600b8398a9 commit: d46d291bd390027811937bbf5af2e2600b8398a9 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: colesbury date: 2024-10-24T22:38:45Z summary: [3.13] gh-125245: Fix race condition when importing `collections.abc` (GH-125415) (GH-125944) If multiple threads concurrently imported `collections.abc`, some of the threads might incorrectly see the "shim" `Lib/collections/abc.py` module instead of the correct `Lib/_collections_abc.py` module. This affected both the free threading build and the default GIL-enabled build. (cherry picked from commit fed501d7247053ce46a2ba512bf0e4bb4f483be6) Co-authored-by: Sam Gross files: A Misc/NEWS.d/next/Library/2024-10-11-00-40-13.gh-issue-125245.8vReM-.rst D Lib/collections/abc.py M Lib/collections/__init__.py diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py index d06d84cbdfcc36..d29afffebf8447 100644 --- a/Lib/collections/__init__.py +++ b/Lib/collections/__init__.py @@ -29,6 +29,9 @@ import _collections_abc import sys as _sys +_sys.modules['collections.abc'] = _collections_abc +abc = _collections_abc + from itertools import chain as _chain from itertools import repeat as _repeat from itertools import starmap as _starmap diff --git a/Lib/collections/abc.py b/Lib/collections/abc.py deleted file mode 100644 index 034ba377a0dbec..00 --- a/Lib/collections/abc.py +++ /dev/null @@ -1,3 +0,0 @@ -import _collections_abc -import sys -sys.modules[__name__] = _collections_abc diff --git a/Misc/NEWS.d/next/Library/2024-10-11-00-40-13.gh-issue-125245.8vReM-.rst b/Misc/NEWS.d/next/Library/2024-10-11-00-40-13.gh-issue-125245.8vReM-.rst new file mode 100644 index 00..c880efe73d06b4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-11-00-40-13.gh-issue-125245.8vReM-.rst @@ -0,0 +1,2 @@ +Fix race condition when importing :mod:`collections.abc`, which could +incorrectly return an empty module. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-125942: Android: set stdout to `errors="backslashreplace"` (GH-125943) (#125950)
https://github.com/python/cpython/commit/083c5814c85e1daff54d2e0e1e08c5028f5d8bc8 commit: 083c5814c85e1daff54d2e0e1e08c5028f5d8bc8 branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: freakboy3742 date: 2024-10-25T00:59:23Z summary: [3.13] gh-125942: Android: set stdout to `errors="backslashreplace"` (GH-125943) (#125950) gh-125942: Android: set stdout to `errors="backslashreplace"` (GH-125943) Android stdout/err streams now use `backslashreplace` encoding to ensure readability of the Android log. (cherry picked from commit b08570c90eb9fa2e2ee4429909b14240b7a427d4) Co-authored-by: Malcolm Smith files: A Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst M Lib/_android_support.py M Lib/test/test_android.py diff --git a/Lib/_android_support.py b/Lib/_android_support.py index 353b34fa36aca4..7572745c851847 100644 --- a/Lib/_android_support.py +++ b/Lib/_android_support.py @@ -31,16 +31,19 @@ def init_streams(android_log_write, stdout_prio, stderr_prio): logcat = Logcat(android_log_write) sys.stdout = TextLogStream( -stdout_prio, "python.stdout", sys.stdout.fileno(), -errors=sys.stdout.errors) +stdout_prio, "python.stdout", sys.stdout.fileno()) sys.stderr = TextLogStream( -stderr_prio, "python.stderr", sys.stderr.fileno(), -errors=sys.stderr.errors) +stderr_prio, "python.stderr", sys.stderr.fileno()) class TextLogStream(io.TextIOWrapper): def __init__(self, prio, tag, fileno=None, **kwargs): +# The default is surrogateescape for stdout and backslashreplace for +# stderr, but in the context of an Android log, readability is more +# important than reversibility. kwargs.setdefault("encoding", "UTF-8") +kwargs.setdefault("errors", "backslashreplace") + super().__init__(BinaryLogStream(prio, tag, fileno), **kwargs) self._lock = RLock() self._pending_bytes = [] diff --git a/Lib/test/test_android.py b/Lib/test/test_android.py index 2ef9f10fdcc1cc..076190f7572045 100644 --- a/Lib/test/test_android.py +++ b/Lib/test/test_android.py @@ -123,13 +123,10 @@ def test_str(self): self.assertIs(stream.readable(), False) self.assertEqual(stream.fileno(), fileno) self.assertEqual("UTF-8", stream.encoding) +self.assertEqual("backslashreplace", stream.errors) self.assertIs(stream.line_buffering, True) self.assertIs(stream.write_through, False) -# stderr is backslashreplace by default; stdout is configured -# that way by libregrtest.main. -self.assertEqual("backslashreplace", stream.errors) - def write(s, lines=None, *, write_len=None): if write_len is None: write_len = len(s) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst new file mode 100644 index 00..d1b1ecd2a724ab --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-24-22-43-03.gh-issue-125942.3UQht1.rst @@ -0,0 +1,2 @@ +On Android, the ``errors`` setting of :any:`sys.stdout` was changed from +``surrogateescape`` to ``backslashreplace``. ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
[Python-checkins] [3.13] gh-124858: fix happy eyeballs refcyles (GH-124859) (#124912)
https://github.com/python/cpython/commit/e5967403993f4d491950aac01525c9d9a9b8eb1a commit: e5967403993f4d491950aac01525c9d9a9b8eb1a branch: 3.13 author: Miss Islington (bot) <[email protected]> committer: willingc date: 2024-10-23T12:35:56-07:00 summary: [3.13] gh-124858: fix happy eyeballs refcyles (GH-124859) (#124912) gh-124858: fix happy eyeballs refcyles (GH-124859) (cherry picked from commit c066bf553577d1000e208eb078d9e758c3e41186) Co-authored-by: Thomas Grainger files: A Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst M Lib/asyncio/base_events.py M Lib/asyncio/staggered.py M Lib/test/test_asyncio/test_streams.py diff --git a/Lib/asyncio/base_events.py b/Lib/asyncio/base_events.py index e4a39f4d345c79..91434042685239 100644 --- a/Lib/asyncio/base_events.py +++ b/Lib/asyncio/base_events.py @@ -17,7 +17,6 @@ import collections.abc import concurrent.futures import errno -import functools import heapq import itertools import os @@ -1140,11 +1139,18 @@ async def create_connection( except OSError: continue else: # using happy eyeballs -sock, _, _ = await staggered.staggered_race( -(functools.partial(self._connect_sock, - exceptions, addrinfo, laddr_infos) - for addrinfo in infos), -happy_eyeballs_delay, loop=self) +sock = (await staggered.staggered_race( +( +# can't use functools.partial as it keeps a reference +# to exceptions +lambda addrinfo=addrinfo: self._connect_sock( +exceptions, addrinfo, laddr_infos +) +for addrinfo in infos +), +happy_eyeballs_delay, +loop=self, +))[0] # can't use sock, _, _ as it keeks a reference to exceptions if sock is None: exceptions = [exc for sub in exceptions for exc in sub] diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py index 7aafcea4d885eb..0f4df8855a80b9 100644 --- a/Lib/asyncio/staggered.py +++ b/Lib/asyncio/staggered.py @@ -144,6 +144,7 @@ async def run_one_coro(ok_to_start, previous_failed) -> None: raise d.exception() return winner_result, winner_index, exceptions finally: +del exceptions # Make sure no tasks are left running if we leave this function for t in running_tasks: t.cancel() diff --git a/Lib/test/test_asyncio/test_streams.py b/Lib/test/test_asyncio/test_streams.py index ae943f39869815..3040ca55fae0e9 100644 --- a/Lib/test/test_asyncio/test_streams.py +++ b/Lib/test/test_asyncio/test_streams.py @@ -1246,6 +1246,24 @@ async def handle_echo(reader, writer): messages = self._basetest_unhandled_exceptions(handle_echo) self.assertEqual(messages, []) +def test_open_connection_happy_eyeball_refcycles(self): +port = socket_helper.find_unused_port() +async def main(): +exc = None +try: +await asyncio.open_connection( +host="localhost", +port=port, +happy_eyeballs_delay=0.25, +) +except* OSError as excs: +# can't use assertRaises because that clears frames +exc = excs.exceptions[0] +self.assertIsNotNone(exc) +self.assertListEqual(gc.get_referrers(exc), []) + +asyncio.run(main()) + if __name__ == '__main__': unittest.main() diff --git a/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst b/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst new file mode 100644 index 00..c05d24a7c5aacb --- /dev/null +++ b/Misc/NEWS.d/next/Library/2024-10-01-17-12-20.gh-issue-124858.Zy0tvT.rst @@ -0,0 +1 @@ +Fix reference cycles left in tracebacks in :func:`asyncio.open_connection` when used with ``happy_eyeballs_delay`` ___ Python-checkins mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-checkins.python.org/ Member address: [email protected]
