[Python-checkins] [3.13] gh-125940: Android: support 16 KB pages (GH-125941) (#125948)

2024-10-24 Thread freakboy3742
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)

2024-10-24 Thread hugovk
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)

2024-10-24 Thread freakboy3742
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)

2024-10-24 Thread freakboy3742
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)

2024-10-24 Thread colesbury
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)

2024-10-24 Thread ericsnowcurrently
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)

2024-10-24 Thread freakboy3742
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)

2024-10-24 Thread colesbury
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)

2024-10-24 Thread hugovk
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)

2024-10-24 Thread colesbury
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)

2024-10-24 Thread AA-Turner
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)

2024-10-24 Thread hauntsaninja
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)

2024-10-24 Thread colesbury
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)

2024-10-24 Thread hauntsaninja
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)

2024-10-24 Thread kumaraditya303
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)

2024-10-24 Thread AA-Turner
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)

2024-10-24 Thread hugovk
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)

2024-10-24 Thread ethanfurman
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)

2024-10-24 Thread colesbury
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)

2024-10-24 Thread freakboy3742
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)

2024-10-24 Thread willingc
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]