[Python-checkins] gh-125243: Fix ZoneInfo data race in free threading build (#125281)

2024-10-13 Thread colesbury
https://github.com/python/cpython/commit/f1d33dbddd3496b062e1fbe024fb6d7b023a35f5
commit: f1d33dbddd3496b062e1fbe024fb6d7b023a35f5
branch: main
author: Sam Gross 
committer: colesbury 
date: 2024-10-13T16:17:51-04:00
summary:

gh-125243: Fix ZoneInfo data race in free threading build (#125281)

Lock `ZoneInfoType` to protect accesses to `ZONEINFO_STRONG_CACHE`.
Refactor the `tp_new` handler to use Argument Clinic so that we can just
use `@critical_section` annotations on the relevant functions.

Also use `PyDict_SetDefaultRef` instead of `PyDict_SetDefault` when
inserting into the `TIMEDELTA_CACHE`.

files:
A Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst
M Modules/_zoneinfo.c
M Modules/clinic/_zoneinfo.c.h

diff --git 
a/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst 
b/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst
new file mode 100644
index 00..49f84d9711819f
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-10-20-39-57.gh-issue-125243.eUbbtu.rst
@@ -0,0 +1,2 @@
+Fix data race when creating :class:`zoneinfo.ZoneInfo` objects in the free
+threading build.
diff --git a/Modules/_zoneinfo.c b/Modules/_zoneinfo.c
index 902ece795b575b..c5292575c22f23 100644
--- a/Modules/_zoneinfo.c
+++ b/Modules/_zoneinfo.c
@@ -3,6 +3,7 @@
 #endif
 
 #include "Python.h"
+#include "pycore_critical_section.h"  // 
_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED()
 #include "pycore_long.h"  // _PyLong_GetOne()
 #include "pycore_pyerrors.h"  // _PyErr_ChainExceptions1()
 
@@ -298,15 +299,20 @@ get_weak_cache(zoneinfo_state *state, PyTypeObject *type)
 }
 }
 
+/*[clinic input]
+@critical_section
+@classmethod
+zoneinfo.ZoneInfo.__new__
+
+key: object
+
+Create a new ZoneInfo instance.
+[clinic start generated code]*/
+
 static PyObject *
-zoneinfo_new(PyTypeObject *type, PyObject *args, PyObject *kw)
+zoneinfo_ZoneInfo_impl(PyTypeObject *type, PyObject *key)
+/*[clinic end generated code: output=95e61dab86bb95c3 input=ef73d7a83bf8790e]*/
 {
-PyObject *key = NULL;
-static char *kwlist[] = {"key", NULL};
-if (PyArg_ParseTupleAndKeywords(args, kw, "O", kwlist, &key) == 0) {
-return NULL;
-}
-
 zoneinfo_state *state = zoneinfo_get_state_by_self(type);
 PyObject *instance = zone_from_strong_cache(state, type, key);
 if (instance != NULL || PyErr_Occurred()) {
@@ -467,6 +473,7 @@ zoneinfo_ZoneInfo_no_cache_impl(PyTypeObject *type, 
PyTypeObject *cls,
 }
 
 /*[clinic input]
+@critical_section
 @classmethod
 zoneinfo.ZoneInfo.clear_cache
 
@@ -481,7 +488,7 @@ Clear the ZoneInfo cache.
 static PyObject *
 zoneinfo_ZoneInfo_clear_cache_impl(PyTypeObject *type, PyTypeObject *cls,
PyObject *only_keys)
-/*[clinic end generated code: output=114d9b7c8a22e660 input=e32ca3bb396788ba]*/
+/*[clinic end generated code: output=114d9b7c8a22e660 input=35944715df26d24e]*/
 {
 zoneinfo_state *state = zoneinfo_get_state_by_cls(cls);
 PyObject *weak_cache = get_weak_cache(state, type);
@@ -816,14 +823,10 @@ zoneinfo_ZoneInfo__unpickle_impl(PyTypeObject *type, 
PyTypeObject *cls,
 /*[clinic end generated code: output=556712fc709deecb input=6ac8c73eed3de316]*/
 {
 if (from_cache) {
-PyObject *val_args = PyTuple_Pack(1, key);
-if (val_args == NULL) {
-return NULL;
-}
-
-PyObject *rv = zoneinfo_new(type, val_args, NULL);
-
-Py_DECREF(val_args);
+PyObject *rv;
+Py_BEGIN_CRITICAL_SECTION(type);
+rv = zoneinfo_ZoneInfo_impl(type, key);
+Py_END_CRITICAL_SECTION();
 return rv;
 }
 else {
@@ -858,8 +861,7 @@ load_timedelta(zoneinfo_state *state, long seconds)
 0, seconds, 0, 1, PyDateTimeAPI->DeltaType);
 
 if (tmp != NULL) {
-rv = PyDict_SetDefault(state->TIMEDELTA_CACHE, pyoffset, tmp);
-Py_XINCREF(rv);
+PyDict_SetDefaultRef(state->TIMEDELTA_CACHE, pyoffset, tmp, &rv);
 Py_DECREF(tmp);
 }
 }
@@ -2368,6 +2370,7 @@ strong_cache_free(StrongCacheNode *root)
 static void
 remove_from_strong_cache(zoneinfo_state *state, StrongCacheNode *node)
 {
+_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType);
 if (state->ZONEINFO_STRONG_CACHE == node) {
 state->ZONEINFO_STRONG_CACHE = node->next;
 }
@@ -2422,6 +2425,7 @@ eject_from_strong_cache(zoneinfo_state *state, const 
PyTypeObject *const type,
 return 0;
 }
 
+_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoType);
 StrongCacheNode *cache = state->ZONEINFO_STRONG_CACHE;
 StrongCacheNode *node = find_in_strong_cache(cache, key);
 if (node != NULL) {
@@ -2478,6 +2482,7 @@ zone_from_strong_cache(zoneinfo_state *state, const 
PyTypeObject *const type,
 return NULL;  // Strong cache currently only implemented for base class
 }
 
+_Py_CRITICAL_SECTION_ASSERT_OBJECT_LOCKED(state->ZoneInfoT

[Python-checkins] [3.12] Trivial change: Update comments in activate about what running hash -r does (GH-125385) (#125388)

2024-10-13 Thread vsajip
https://github.com/python/cpython/commit/77020dae341764ee440c99cf8ba13c7766730b46
commit: 77020dae341764ee440c99cf8ba13c7766730b46
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: vsajip 
date: 2024-10-13T08:55:37+01:00
summary:

[3.12] Trivial change: Update comments in activate about what running hash -r 
does (GH-125385) (#125388)

(cherry picked from commit 82bcaf15890cf85b76b4f62d2dd1710bb49c3ed1)

files:
M Lib/venv/scripts/common/activate

diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate
index d5914e0cbb40d5..44df44a7404b43 100644
--- a/Lib/venv/scripts/common/activate
+++ b/Lib/venv/scripts/common/activate
@@ -14,8 +14,9 @@ deactivate () {
 unset _OLD_VIRTUAL_PYTHONHOME
 fi
 
-# Call hash to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
+# Call hash to forget past locations. Without forgetting
+# past locations the $PATH changes we made may not be respected.
+# See "man bash" for more details. hash is usually a builtin of your shell
 hash -r 2> /dev/null
 
 if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then

___
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-86673: Loosen test_ttk.test_identify() requirements (GH-125335) (#125391)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/afddaeb7698d2c572364d61e02c4271439650f6d
commit: afddaeb7698d2c572364d61e02c4271439650f6d
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: erlend-aasland 
date: 2024-10-13T07:56:04Z
summary:

[3.12] gh-86673: Loosen test_ttk.test_identify() requirements (GH-125335) 
(#125391)

In aeca373b3 (PR gh-12011, issue gh-71500), test_identify() was changed to 
expect different results on Darwin. Ned's fix was later adjusted by e52f9bee8. 
This workaround is only needed for some variants of Tk/Tcl on macOS, so we now 
allow both the workaround and the generic results for these tests.
(cherry picked from commit 4197a796ecf3a751ad7245b8d4f980d6d444b614)

Co-authored-by: Erlend E. Aasland 

files:
M Lib/test/test_ttk/test_widgets.py

diff --git a/Lib/test/test_ttk/test_widgets.py 
b/Lib/test/test_ttk/test_widgets.py
index 3e541fbc5a4ded..ceba95c92a1fc1 100644
--- a/Lib/test/test_ttk/test_widgets.py
+++ b/Lib/test/test_ttk/test_widgets.py
@@ -336,7 +336,8 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
 'show', 'state', 'style', 'takefocus', 'textvariable',
 'validate', 'validatecommand', 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea'
+# bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'.
+IDENTIFY_AS = {'Entry.field', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -373,8 +374,7 @@ def test_identify(self):
 self.entry.pack()
 self.entry.update()
 
-# bpo-27313: macOS Cocoa widget differs from X, allow either
-self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS)
+self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS)
 self.assertEqual(self.entry.identify(-1, -1), "")
 
 self.assertRaises(tkinter.TclError, self.entry.identify, None, 5)
@@ -461,7 +461,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
 'validate', 'validatecommand', 'values',
 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Combobox.button', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -1204,7 +1204,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand',
 'values', 'width', 'wrap', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Spinbox.field', 'textarea'}
 
 def setUp(self):
 super().setUp()

___
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] Trivial change: Update comments in activate about what running hash -r does (GH-125385) (GH-125387)

2024-10-13 Thread vsajip
https://github.com/python/cpython/commit/801ef7de08d816b1976865496e834c5af941a8ad
commit: 801ef7de08d816b1976865496e834c5af941a8ad
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vsajip 
date: 2024-10-13T08:56:09+01:00
summary:

[3.13] Trivial change: Update comments in activate about what running hash -r 
does (GH-125385) (GH-125387)

(cherry picked from commit 82bcaf15890cf85b76b4f62d2dd1710bb49c3ed1)

files:
M Lib/venv/scripts/common/activate

diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate
index cbd4873f012246..4593799b7e9b0e 100644
--- a/Lib/venv/scripts/common/activate
+++ b/Lib/venv/scripts/common/activate
@@ -14,8 +14,9 @@ deactivate () {
 unset _OLD_VIRTUAL_PYTHONHOME
 fi
 
-# Call hash to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
+# Call hash to forget past locations. Without forgetting
+# past locations the $PATH changes we made may not be respected.
+# See "man bash" for more details. hash is usually a builtin of your shell
 hash -r 2> /dev/null
 
 if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then

___
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-61698: Use launchctl to detect macOS window manager in tests (GH-118390) (#125393)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/a144037ac3501720b5587ee53de590684943639a
commit: a144037ac3501720b5587ee53de590684943639a
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: erlend-aasland 
date: 2024-10-13T08:39:05Z
summary:

[3.12] gh-61698: Use launchctl to detect macOS window manager in tests 
(GH-118390) (#125393)

(cherry picked from commit ce740d46246b28bb675ba9d62214b59be9b8411e)

Co-authored-by: Erlend E. Aasland 

files:
M Lib/test/support/__init__.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 5432b1ec5c9d84..78f410e1455852 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -250,22 +250,16 @@ class USEROBJECTFLAGS(ctypes.Structure):
 # process not running under the same user id as the current console
 # user.  To avoid that, raise an exception if the window manager
 # connection is not available.
-from ctypes import cdll, c_int, pointer, Structure
-from ctypes.util import find_library
-
-app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
-
-if app_services.CGMainDisplayID() == 0:
-reason = "gui tests cannot run without OS X window manager"
+import subprocess
+try:
+rc = subprocess.run(["launchctl", "managername"],
+capture_output=True, check=True)
+managername = rc.stdout.decode("utf-8").strip()
+except subprocess.CalledProcessError:
+reason = "unable to detect macOS launchd job manager"
 else:
-class ProcessSerialNumber(Structure):
-_fields_ = [("highLongOfPSN", c_int),
-("lowLongOfPSN", c_int)]
-psn = ProcessSerialNumber()
-psn_p = pointer(psn)
-if (  (app_services.GetCurrentProcess(psn_p) < 0) or
-  (app_services.SetFrontProcess(psn_p) < 0) ):
-reason = "cannot run without OS X gui process"
+if managername != "Aqua":
+reason = f"{managername=} -- can only run in a macOS GUI 
session"
 
 # check on every platform whether tkinter can actually do anything
 if not reason:

___
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-61698: Use launchctl to detect macOS window manager in tests (GH-118390) (#125392)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/b7dff8563828b486b27e8373b9171b1136473308
commit: b7dff8563828b486b27e8373b9171b1136473308
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: erlend-aasland 
date: 2024-10-13T08:46:35Z
summary:

[3.13] gh-61698: Use launchctl to detect macOS window manager in tests 
(GH-118390) (#125392)

(cherry picked from commit ce740d46246b28bb675ba9d62214b59be9b8411e)

Co-authored-by: Erlend E. Aasland 

files:
M Lib/test/support/__init__.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 057b3bbd22944f..6413af50a7c0be 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -252,22 +252,16 @@ class USEROBJECTFLAGS(ctypes.Structure):
 # process not running under the same user id as the current console
 # user.  To avoid that, raise an exception if the window manager
 # connection is not available.
-from ctypes import cdll, c_int, pointer, Structure
-from ctypes.util import find_library
-
-app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
-
-if app_services.CGMainDisplayID() == 0:
-reason = "gui tests cannot run without OS X window manager"
+import subprocess
+try:
+rc = subprocess.run(["launchctl", "managername"],
+capture_output=True, check=True)
+managername = rc.stdout.decode("utf-8").strip()
+except subprocess.CalledProcessError:
+reason = "unable to detect macOS launchd job manager"
 else:
-class ProcessSerialNumber(Structure):
-_fields_ = [("highLongOfPSN", c_int),
-("lowLongOfPSN", c_int)]
-psn = ProcessSerialNumber()
-psn_p = pointer(psn)
-if (  (app_services.GetCurrentProcess(psn_p) < 0) or
-  (app_services.SetFrontProcess(psn_p) < 0) ):
-reason = "cannot run without OS X gui process"
+if managername != "Aqua":
+reason = f"{managername=} -- can only run in a macOS GUI 
session"
 
 # check on every platform whether tkinter can actually do anything
 if not reason:

___
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-86673: Loosen test_ttk.test_identify() requirements (#125335)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/4197a796ecf3a751ad7245b8d4f980d6d444b614
commit: 4197a796ecf3a751ad7245b8d4f980d6d444b614
branch: main
author: Erlend E. Aasland 
committer: erlend-aasland 
date: 2024-10-13T09:38:47+02:00
summary:

gh-86673: Loosen test_ttk.test_identify() requirements (#125335)

In aeca373b3 (PR gh-12011, issue gh-71500), test_identify() was changed to 
expect different results on Darwin. Ned's fix was later adjusted by e52f9bee8. 
This workaround is only needed for some variants of Tk/Tcl on macOS, so we now 
allow both the workaround and the generic results for these tests.

files:
M Lib/test/test_ttk/test_widgets.py

diff --git a/Lib/test/test_ttk/test_widgets.py 
b/Lib/test/test_ttk/test_widgets.py
index 88740b18864006..10bec33be617a1 100644
--- a/Lib/test/test_ttk/test_widgets.py
+++ b/Lib/test/test_ttk/test_widgets.py
@@ -336,7 +336,8 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
 'show', 'state', 'style', 'takefocus', 'textvariable',
 'validate', 'validatecommand', 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea'
+# bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'.
+IDENTIFY_AS = {'Entry.field', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -373,8 +374,7 @@ def test_identify(self):
 self.entry.pack()
 self.entry.update()
 
-# bpo-27313: macOS Cocoa widget differs from X, allow either
-self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS)
+self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS)
 self.assertEqual(self.entry.identify(-1, -1), "")
 
 self.assertRaises(tkinter.TclError, self.entry.identify, None, 5)
@@ -461,7 +461,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
 'validate', 'validatecommand', 'values',
 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Combobox.button', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -1204,7 +1204,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand',
 'values', 'width', 'wrap', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Spinbox.field', 'textarea'}
 
 def setUp(self):
 super().setUp()

___
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-61698: Use launchctl to detect macOS window manager in tests (#118390)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/ce740d46246b28bb675ba9d62214b59be9b8411e
commit: ce740d46246b28bb675ba9d62214b59be9b8411e
branch: main
author: Erlend E. Aasland 
committer: erlend-aasland 
date: 2024-10-13T10:22:31+02:00
summary:

gh-61698: Use launchctl to detect macOS window manager in tests (#118390)

files:
M Lib/test/support/__init__.py

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 72ce5dacd1be4c..d768bead7120c7 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -253,22 +253,16 @@ class USEROBJECTFLAGS(ctypes.Structure):
 # process not running under the same user id as the current console
 # user.  To avoid that, raise an exception if the window manager
 # connection is not available.
-from ctypes import cdll, c_int, pointer, Structure
-from ctypes.util import find_library
-
-app_services = cdll.LoadLibrary(find_library("ApplicationServices"))
-
-if app_services.CGMainDisplayID() == 0:
-reason = "gui tests cannot run without OS X window manager"
+import subprocess
+try:
+rc = subprocess.run(["launchctl", "managername"],
+capture_output=True, check=True)
+managername = rc.stdout.decode("utf-8").strip()
+except subprocess.CalledProcessError:
+reason = "unable to detect macOS launchd job manager"
 else:
-class ProcessSerialNumber(Structure):
-_fields_ = [("highLongOfPSN", c_int),
-("lowLongOfPSN", c_int)]
-psn = ProcessSerialNumber()
-psn_p = pointer(psn)
-if (  (app_services.GetCurrentProcess(psn_p) < 0) or
-  (app_services.SetFrontProcess(psn_p) < 0) ):
-reason = "cannot run without OS X gui process"
+if managername != "Aqua":
+reason = f"{managername=} -- can only run in a macOS GUI 
session"
 
 # check on every platform whether tkinter can actually do anything
 if not reason:

___
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-125383: Update `fib` function comment for accuracy (#125386)

2024-10-13 Thread Eclips4
https://github.com/python/cpython/commit/283ea5f3b2b6a18605b8598a979afe263b0f21ce
commit: 283ea5f3b2b6a18605b8598a979afe263b0f21ce
branch: main
author: Wulian 
committer: Eclips4 
date: 2024-10-13T14:10:59+03:00
summary:

gh-125383: Update `fib` function comment for accuracy (#125386)

`Doc/tutorial/controlflow.rst`: fix comment for `fib` function

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index 9b73ac475c78d5..b830ce94ba4f47 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -461,8 +461,8 @@ Defining Functions
 We can create a function that writes the Fibonacci series to an arbitrary
 boundary::
 
-   >>> def fib(n):# write Fibonacci series up to n
-   ... """Print a Fibonacci series up to n."""
+   >>> def fib(n):# write Fibonacci series less than n
+   ... """Print a Fibonacci series less than n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')

___
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-125383: Update `fib` function comment for accuracy (GH-125386) (#125395)

2024-10-13 Thread Eclips4
https://github.com/python/cpython/commit/c9ead96249b3f4b18f2a42071546c90100595a17
commit: c9ead96249b3f4b18f2a42071546c90100595a17
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Eclips4 
date: 2024-10-13T11:16:23Z
summary:

[3.13] gh-125383: Update `fib` function comment for accuracy (GH-125386) 
(#125395)

gh-125383: Update `fib` function comment for accuracy (GH-125386)

`Doc/tutorial/controlflow.rst`: fix comment for `fib` function
(cherry picked from commit 283ea5f3b2b6a18605b8598a979afe263b0f21ce)

Co-authored-by: Wulian 

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index 9b73ac475c78d5..b830ce94ba4f47 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -461,8 +461,8 @@ Defining Functions
 We can create a function that writes the Fibonacci series to an arbitrary
 boundary::
 
-   >>> def fib(n):# write Fibonacci series up to n
-   ... """Print a Fibonacci series up to n."""
+   >>> def fib(n):# write Fibonacci series less than n
+   ... """Print a Fibonacci series less than n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')

___
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-125383: Update `fib` function comment for accuracy (GH-125386) (#125396)

2024-10-13 Thread Eclips4
https://github.com/python/cpython/commit/00c596d8ad913ef393d5b75d561608fc9ac521fa
commit: 00c596d8ad913ef393d5b75d561608fc9ac521fa
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: Eclips4 
date: 2024-10-13T11:17:55Z
summary:

[3.12] gh-125383: Update `fib` function comment for accuracy (GH-125386) 
(#125396)

gh-125383: Update `fib` function comment for accuracy (GH-125386)

`Doc/tutorial/controlflow.rst`: fix comment for `fib` function
(cherry picked from commit 283ea5f3b2b6a18605b8598a979afe263b0f21ce)

Co-authored-by: Wulian 

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index 9b73ac475c78d5..b830ce94ba4f47 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -461,8 +461,8 @@ Defining Functions
 We can create a function that writes the Fibonacci series to an arbitrary
 boundary::
 
-   >>> def fib(n):# write Fibonacci series up to n
-   ... """Print a Fibonacci series up to n."""
+   >>> def fib(n):# write Fibonacci series less than n
+   ... """Print a Fibonacci series less than n."""
... a, b = 0, 1
... while a < n:
... print(a, end=' ')

___
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-125403: fix console formatting in Chapter 12 of the tutorial (#125404)

2024-10-13 Thread kumaraditya303
https://github.com/python/cpython/commit/6c386b703d19aaec9a34fd1e843a4d0a144ad14b
commit: 6c386b703d19aaec9a34fd1e843a4d0a144ad14b
branch: main
author: partev 
committer: kumaraditya303 
date: 2024-10-13T22:16:15+05:30
summary:

gh-125403: fix console formatting in Chapter 12 of the tutorial (#125404)

files:
M Doc/tutorial/venv.rst

diff --git a/Doc/tutorial/venv.rst b/Doc/tutorial/venv.rst
index 91e4ce18acef1d..f362e1943b666f 100644
--- a/Doc/tutorial/venv.rst
+++ b/Doc/tutorial/venv.rst
@@ -76,7 +76,7 @@ virtual environment you're using, and modify the environment 
so that running
 ``python`` will get you that particular version and installation of Python.
 For example:
 
-.. code-block:: bash
+.. code-block:: console
 
   $ source ~/envs/tutorial-env/bin/activate
   (tutorial-env) $ python
@@ -108,7 +108,7 @@ complete documentation for ``pip``.)
 
 You can install the latest version of a package by specifying a package's name:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip install novas
   Collecting novas
@@ -120,7 +120,7 @@ You can install the latest version of a package by 
specifying a package's name:
 You can also install a specific version of a package by giving the
 package name  followed by ``==`` and the version number:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip install requests==2.6.0
   Collecting requests==2.6.0
@@ -133,7 +133,7 @@ version is already installed and do nothing.  You can 
supply a
 different version number to get that version, or you can run ``python
 -m pip install --upgrade`` to upgrade the package to the latest version:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip install --upgrade requests
   Collecting requests
@@ -148,7 +148,7 @@ remove the packages from the virtual environment.
 
 ``python -m pip show`` will display information about a particular package:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip show requests
   ---
@@ -166,7 +166,7 @@ remove the packages from the virtual environment.
 ``python -m pip list`` will display all of the packages installed in
 the virtual environment:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip list
   novas (3.1.1.3)
@@ -179,7 +179,7 @@ the virtual environment:
 but the output uses the format that ``python -m pip install`` expects.
 A common convention is to put this list in a ``requirements.txt`` file:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip freeze > requirements.txt
   (tutorial-env) $ cat requirements.txt
@@ -191,7 +191,7 @@ The ``requirements.txt`` can then be committed to version 
control and
 shipped as part of an application.  Users can then install all the
 necessary packages with ``install -r``:
 
-.. code-block:: bash
+.. code-block:: console
 
   (tutorial-env) $ python -m pip install -r requirements.txt
   Collecting novas==3.1.1.3 (from -r requirements.txt (line 1))

___
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] add Kumar Aditya as codeowner for weakref (#125405)

2024-10-13 Thread kumaraditya303
https://github.com/python/cpython/commit/e79bbd147fd58e825572f1aa93c5398953289fb2
commit: e79bbd147fd58e825572f1aa93c5398953289fb2
branch: main
author: Kumar Aditya 
committer: kumaraditya303 
date: 2024-10-13T16:59:27Z
summary:

add Kumar Aditya as codeowner for weakref (#125405)

files:
M .github/CODEOWNERS

diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 7e9c3caf23f079..221008717b29b1 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -280,3 +280,5 @@ Lib/test/test_configparser.py @jaraco
 
 # Doc sections
 Doc/reference/@willingc
+
+**/*weakref*  @kumaraditya303
\ No newline at end of file

___
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] Trivial change: Update comments in activate about what running hash -r does (GH-125385)

2024-10-13 Thread vsajip
https://github.com/python/cpython/commit/82bcaf15890cf85b76b4f62d2dd1710bb49c3ed1
commit: 82bcaf15890cf85b76b4f62d2dd1710bb49c3ed1
branch: main
author: Andrew Athan <[email protected]>
committer: vsajip 
date: 2024-10-13T08:22:05+01:00
summary:

Trivial change: Update comments in activate about what running hash -r does 
(GH-125385)

Update comments about what running hash -r does

The old comment said "hash -r" forgets "past commands." However, the 
documentation for "hash" states that it forgets past locations. The old comment 
was, in my opinion, confusing. This is because it could be interpreted to mean 
it does something to the command history (HISTORY/HISTFILE etc) vs the cache of 
locations.

files:
M Lib/venv/scripts/common/activate

diff --git a/Lib/venv/scripts/common/activate b/Lib/venv/scripts/common/activate
index cbd4873f012246..4593799b7e9b0e 100644
--- a/Lib/venv/scripts/common/activate
+++ b/Lib/venv/scripts/common/activate
@@ -14,8 +14,9 @@ deactivate () {
 unset _OLD_VIRTUAL_PYTHONHOME
 fi
 
-# Call hash to forget past commands. Without forgetting
-# past commands the $PATH changes we made may not be respected
+# Call hash to forget past locations. Without forgetting
+# past locations the $PATH changes we made may not be respected.
+# See "man bash" for more details. hash is usually a builtin of your shell
 hash -r 2> /dev/null
 
 if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then

___
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-86673: Loosen test_ttk.test_identify() requirements (GH-125335) (#125390)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/bcadaf23218085c8fbeb8e9f8793e55ce5ed0166
commit: bcadaf23218085c8fbeb8e9f8793e55ce5ed0166
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: erlend-aasland 
date: 2024-10-13T08:04:22Z
summary:

[3.13] gh-86673: Loosen test_ttk.test_identify() requirements (GH-125335) 
(#125390)

In aeca373b3 (PR gh-12011, issue gh-71500), test_identify() was changed to 
expect different results on Darwin. Ned's fix was later adjusted by e52f9bee8. 
This workaround is only needed for some variants of Tk/Tcl on macOS, so we now 
allow both the workaround and the generic results for these tests.
(cherry picked from commit 4197a796ecf3a751ad7245b8d4f980d6d444b614)

Co-authored-by: Erlend E. Aasland 

files:
M Lib/test/test_ttk/test_widgets.py

diff --git a/Lib/test/test_ttk/test_widgets.py 
b/Lib/test/test_ttk/test_widgets.py
index 88740b18864006..10bec33be617a1 100644
--- a/Lib/test/test_ttk/test_widgets.py
+++ b/Lib/test/test_ttk/test_widgets.py
@@ -336,7 +336,8 @@ class EntryTest(AbstractWidgetTest, unittest.TestCase):
 'show', 'state', 'style', 'takefocus', 'textvariable',
 'validate', 'validatecommand', 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Entry.field' if sys.platform == 'darwin' else 'textarea'
+# bpo-27313: macOS Tk/Tcl may or may not report 'Entry.field'.
+IDENTIFY_AS = {'Entry.field', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -373,8 +374,7 @@ def test_identify(self):
 self.entry.pack()
 self.entry.update()
 
-# bpo-27313: macOS Cocoa widget differs from X, allow either
-self.assertEqual(self.entry.identify(5, 5), self.IDENTIFY_AS)
+self.assertIn(self.entry.identify(5, 5), self.IDENTIFY_AS)
 self.assertEqual(self.entry.identify(-1, -1), "")
 
 self.assertRaises(tkinter.TclError, self.entry.identify, None, 5)
@@ -461,7 +461,7 @@ class ComboboxTest(EntryTest, unittest.TestCase):
 'validate', 'validatecommand', 'values',
 'width', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Combobox.button' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Combobox.button', 'textarea'}
 
 def setUp(self):
 super().setUp()
@@ -1204,7 +1204,7 @@ class SpinboxTest(EntryTest, unittest.TestCase):
 'takefocus', 'textvariable', 'to', 'validate', 'validatecommand',
 'values', 'width', 'wrap', 'xscrollcommand',
 )
-IDENTIFY_AS = 'Spinbox.field' if sys.platform == 'darwin' else 'textarea'
+IDENTIFY_AS = {'Spinbox.field', 'textarea'}
 
 def setUp(self):
 super().setUp()

___
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-89967: make WeakKeyDictionary and WeakValueDictionary thread safe (#125325)

2024-10-13 Thread kumaraditya303
https://github.com/python/cpython/commit/cd0f9d111a040ad863c680e9f464419640c8c3fd
commit: cd0f9d111a040ad863c680e9f464419640c8c3fd
branch: main
author: Kumar Aditya 
committer: kumaraditya303 
date: 2024-10-13T21:05:05+05:30
summary:

gh-89967: make WeakKeyDictionary and WeakValueDictionary thread safe (#125325)

Make `WeakKeyDictionary` and `WeakValueDictionary` thread safe by copying the 
underlying the dict before iterating over it.

files:
A Misc/NEWS.d/next/Library/2024-10-11-16-19-46.gh-issue-89967.vhWUOR.rst
M Lib/_weakrefset.py
M Lib/weakref.py

diff --git a/Lib/_weakrefset.py b/Lib/_weakrefset.py
index 2071755d71dfc8..d1c7fcaeec9821 100644
--- a/Lib/_weakrefset.py
+++ b/Lib/_weakrefset.py
@@ -8,31 +8,6 @@
 __all__ = ['WeakSet']
 
 
-class _IterationGuard:
-# This context manager registers itself in the current iterators of the
-# weak container, such as to delay all removals until the context manager
-# exits.
-# This technique should be relatively thread-safe (since sets are).
-
-def __init__(self, weakcontainer):
-# Don't create cycles
-self.weakcontainer = ref(weakcontainer)
-
-def __enter__(self):
-w = self.weakcontainer()
-if w is not None:
-w._iterating.add(self)
-return self
-
-def __exit__(self, e, t, b):
-w = self.weakcontainer()
-if w is not None:
-s = w._iterating
-s.remove(self)
-if not s:
-w._commit_removals()
-
-
 class WeakSet:
 def __init__(self, data=None):
 self.data = set()
diff --git a/Lib/weakref.py b/Lib/weakref.py
index 25b70927e29c31..94e4278143c987 100644
--- a/Lib/weakref.py
+++ b/Lib/weakref.py
@@ -19,7 +19,7 @@
  ReferenceType,
  _remove_dead_weakref)
 
-from _weakrefset import WeakSet, _IterationGuard
+from _weakrefset import WeakSet
 
 import _collections_abc  # Import after _weakref to avoid circular import.
 import sys
@@ -105,34 +105,14 @@ def __init__(self, other=(), /, **kw):
 def remove(wr, selfref=ref(self), 
_atomic_removal=_remove_dead_weakref):
 self = selfref()
 if self is not None:
-if self._iterating:
-self._pending_removals.append(wr.key)
-else:
-# Atomic removal is necessary since this function
-# can be called asynchronously by the GC
-_atomic_removal(self.data, wr.key)
+# Atomic removal is necessary since this function
+# can be called asynchronously by the GC
+_atomic_removal(self.data, wr.key)
 self._remove = remove
-# A list of keys to be removed
-self._pending_removals = []
-self._iterating = set()
 self.data = {}
 self.update(other, **kw)
 
-def _commit_removals(self, _atomic_removal=_remove_dead_weakref):
-pop = self._pending_removals.pop
-d = self.data
-# We shouldn't encounter any KeyError, because this method should
-# always be called *before* mutating the dict.
-while True:
-try:
-key = pop()
-except IndexError:
-return
-_atomic_removal(d, key)
-
 def __getitem__(self, key):
-if self._pending_removals:
-self._commit_removals()
 o = self.data[key]()
 if o is None:
 raise KeyError(key)
@@ -140,18 +120,12 @@ def __getitem__(self, key):
 return o
 
 def __delitem__(self, key):
-if self._pending_removals:
-self._commit_removals()
 del self.data[key]
 
 def __len__(self):
-if self._pending_removals:
-self._commit_removals()
 return len(self.data)
 
 def __contains__(self, key):
-if self._pending_removals:
-self._commit_removals()
 try:
 o = self.data[key]()
 except KeyError:
@@ -162,38 +136,28 @@ def __repr__(self):
 return "<%s at %#x>" % (self.__class__.__name__, id(self))
 
 def __setitem__(self, key, value):
-if self._pending_removals:
-self._commit_removals()
 self.data[key] = KeyedRef(value, self._remove, key)
 
 def copy(self):
-if self._pending_removals:
-self._commit_removals()
 new = WeakValueDictionary()
-with _IterationGuard(self):
-for key, wr in self.data.items():
-o = wr()
-if o is not None:
-new[key] = o
+for key, wr in self.data.copy().items():
+o = wr()
+if o is not None:
+new[key] = o
 return new
 
 __copy__ = copy
 
 def __deepcopy__(self, memo):
 from copy import deepcopy
-if self._pending_removals:
-self._commit_removals()
 new = self.__class__()
-with _IterationGuard(self):
-for

[Python-checkins] gh-125161: return non zero value in pthread_self on wasi (#125303)

2024-10-13 Thread kumaraditya303
https://github.com/python/cpython/commit/08489325d1cd94eba97c5f5f8cac49521fd0b0d7
commit: 08489325d1cd94eba97c5f5f8cac49521fd0b0d7
branch: main
author: Kumar Aditya 
committer: kumaraditya303 
date: 2024-10-13T20:59:41+05:30
summary:

gh-125161: return non zero value in pthread_self on wasi (#125303)

files:
M Python/thread_pthread_stubs.h

diff --git a/Python/thread_pthread_stubs.h b/Python/thread_pthread_stubs.h
index 4741e594e52e65..458f8fc5951720 100644
--- a/Python/thread_pthread_stubs.h
+++ b/Python/thread_pthread_stubs.h
@@ -1,5 +1,9 @@
 #include "cpython/pthread_stubs.h"
 
+typedef struct py_stub_tls_entry py_tls_entry;
+
+#define py_tls_entries (_PyRuntime.threads.stubs.tls_entries)
+
 // mutex
 int
 pthread_mutex_init(pthread_mutex_t *restrict mutex,
@@ -105,7 +109,7 @@ pthread_join(pthread_t thread, void** value_ptr)
 
 PyAPI_FUNC(pthread_t) pthread_self(void)
 {
-return 0;
+return (pthread_t)(uintptr_t)&py_tls_entries;
 }
 
 int
@@ -134,10 +138,6 @@ pthread_attr_destroy(pthread_attr_t *attr)
 }
 
 
-typedef struct py_stub_tls_entry py_tls_entry;
-
-#define py_tls_entries (_PyRuntime.threads.stubs.tls_entries)
-
 int
 pthread_key_create(pthread_key_t *key, void (*destr_function)(void *))
 {

___
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] fix comment in _PyMutex_TryUnlock (#125319)

2024-10-13 Thread kumaraditya303
https://github.com/python/cpython/commit/022c50d190e14affb952a244c4eb6e4a644ad0c9
commit: 022c50d190e14affb952a244c4eb6e4a644ad0c9
branch: main
author: Kumar Aditya 
committer: kumaraditya303 
date: 2024-10-13T20:59:07+05:30
summary:

fix comment in _PyMutex_TryUnlock (#125319)

files:
M Include/internal/pycore_lock.h

diff --git a/Include/internal/pycore_lock.h b/Include/internal/pycore_lock.h
index e6da083b807ce5..cd7deda00c7bee 100644
--- a/Include/internal/pycore_lock.h
+++ b/Include/internal/pycore_lock.h
@@ -64,8 +64,8 @@ PyMutex_LockFlags(PyMutex *m, _PyLockFlags flags)
 }
 }
 
-// Unlock a mutex, returns 0 if the mutex is not locked (used for improved
-// error messages).
+// Unlock a mutex, returns -1 if the mutex is not locked (used for improved
+// error messages) otherwise returns 0.
 extern int _PyMutex_TryUnlock(PyMutex *m);
 
 

___
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-101291: Add versionadded directives for PyUnstable_Long_* (#125384)

2024-10-13 Thread vstinner
https://github.com/python/cpython/commit/c6d7b644c2425b397cfb641f336bea70eb8a329a
commit: c6d7b644c2425b397cfb641f336bea70eb8a329a
branch: main
author: Sergey B Kirpichev 
committer: vstinner 
date: 2024-10-13T19:38:42+02:00
summary:

gh-101291: Add versionadded directives for PyUnstable_Long_* (#125384)

files:
M Doc/c-api/long.rst

diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index e0ae0f77a01db9..02ef8aa7846468 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -608,6 +608,9 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
Exactly what values are considered compact is an implementation detail
and is subject to change.
 
+   .. versionadded:: 3.12
+
+
 .. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op)
 
If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`,
@@ -615,3 +618,5 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
 
Otherwise, the return value is undefined.
 
+   .. versionadded:: 3.12
+

___
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-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384) (#125407)

2024-10-13 Thread vstinner
https://github.com/python/cpython/commit/cff627a27dc5126ecb4113fc3fe7e444f410ba99
commit: cff627a27dc5126ecb4113fc3fe7e444f410ba99
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vstinner 
date: 2024-10-13T17:44:50Z
summary:

[3.13] gh-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384) 
(#125407)

gh-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384)
(cherry picked from commit c6d7b644c2425b397cfb641f336bea70eb8a329a)

Co-authored-by: Sergey B Kirpichev 

files:
M Doc/c-api/long.rst

diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index c9e277680aba43..638be61c5b8091 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -538,6 +538,9 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
Exactly what values are considered compact is an implementation detail
and is subject to change.
 
+   .. versionadded:: 3.12
+
+
 .. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op)
 
If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`,
@@ -545,3 +548,5 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
 
Otherwise, the return value is undefined.
 
+   .. versionadded:: 3.12
+

___
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-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` (GH-125156) (#125409)

2024-10-13 Thread barneygale
https://github.com/python/cpython/commit/094d95f62c12d2773c9bf116d449e31ede2681b1
commit: 094d95f62c12d2773c9bf116d449e31ede2681b1
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: barneygale 
date: 2024-10-13T18:12:57Z
summary:

[3.13] GH-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` 
(GH-125156) (#125409)

`PurePath.__init__()` incorrectly uses the `_raw_paths` of a given
`PurePath` object with a different flavour, even though the procedure to
join path segments can differ between flavours.

This change makes the `_raw_paths`-enabled deferred joining apply _only_
when the path flavours match.

(cherry picked from commit cb8e5995d89d9b90e83cf43310ec50e177484e70)

Co-authored-by: Barney Gale 
Co-authored-by: Bénédikt Tran <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
M Lib/pathlib/_local.py
M Lib/test/test_pathlib/test_pathlib.py

diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py
index fbc8db78b86e61..0188e7c7722b81 100644
--- a/Lib/pathlib/_local.py
+++ b/Lib/pathlib/_local.py
@@ -118,9 +118,9 @@ def __init__(self, *args):
 paths = []
 for arg in args:
 if isinstance(arg, PurePath):
-if arg.parser is ntpath and self.parser is posixpath:
+if arg.parser is not self.parser:
 # GH-103631: Convert separators for backwards 
compatibility.
-paths.extend(path.replace('\\', '/') for path in 
arg._raw_paths)
+paths.append(arg.as_posix())
 else:
 paths.extend(arg._raw_paths)
 else:
diff --git a/Lib/test/test_pathlib/test_pathlib.py 
b/Lib/test/test_pathlib/test_pathlib.py
index ff054e76efcd60..093746c0c150d6 100644
--- a/Lib/test/test_pathlib/test_pathlib.py
+++ b/Lib/test/test_pathlib/test_pathlib.py
@@ -107,6 +107,15 @@ def test_constructor_nested(self):
 self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c")))
 self.assertEqual(P(P('./a:b')), P('./a:b'))
 
+@needs_windows
+def test_constructor_nested_foreign_flavour(self):
+# See GH-125069.
+p1 = pathlib.PurePosixPath('b/c:\\d')
+p2 = pathlib.PurePosixPath('b/', 'c:\\d')
+self.assertEqual(p1, p2)
+self.assertEqual(self.cls(p1), self.cls('b/c:/d'))
+self.assertEqual(self.cls(p2), self.cls('b/c:/d'))
+
 def _check_parse_path(self, raw_path, *expected):
 sep = self.parser.sep
 actual = self.cls._parse_path(raw_path.replace('/', sep))
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst 
b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
new file mode 100644
index 00..9f1fd871e1d0b5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
@@ -0,0 +1,4 @@
+Fix an issue where providing a :class:`pathlib.PurePath` object as an
+initializer argument to a second :class:`~pathlib.PurePath` object with a
+different :attr:`~pathlib.PurePath.parser` resulted in arguments to the
+former object's initializer being joined by the latter object's parser.

___
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-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` (GH-125156) (#125410)

2024-10-13 Thread barneygale
https://github.com/python/cpython/commit/f49221af4609ea98e0e41bfae0d056f98bdccae4
commit: f49221af4609ea98e0e41bfae0d056f98bdccae4
branch: 3.12
author: Barney Gale 
committer: barneygale 
date: 2024-10-13T18:18:41Z
summary:

[3.12] GH-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` 
(GH-125156) (#125410)

`PurePath.__init__()` incorrectly uses the `_raw_paths` of a given
`PurePath` object with a different flavour, even though the procedure to
join path segments can differ between flavours.

This change makes the `_raw_paths`-enabled deferred joining apply _only_
when the path flavours match.

(cherry picked from commit cb8e5995d89d9b90e83cf43310ec50e177484e70)

Co-authored-by: Bénédikt Tran <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
M Lib/pathlib.py
M Lib/test/test_pathlib.py

diff --git a/Lib/pathlib.py b/Lib/pathlib.py
index 65ff0ee1977f80..02eb5c25981e31 100644
--- a/Lib/pathlib.py
+++ b/Lib/pathlib.py
@@ -359,9 +359,9 @@ def __init__(self, *args):
 paths = []
 for arg in args:
 if isinstance(arg, PurePath):
-if arg._flavour is ntpath and self._flavour is posixpath:
+if arg._flavour is not self._flavour:
 # GH-103631: Convert separators for backwards 
compatibility.
-paths.extend(path.replace('\\', '/') for path in 
arg._raw_paths)
+paths.append(arg.as_posix())
 else:
 paths.extend(arg._raw_paths)
 else:
diff --git a/Lib/test/test_pathlib.py b/Lib/test/test_pathlib.py
index ca604df70a9a4e..4437f878004c70 100644
--- a/Lib/test/test_pathlib.py
+++ b/Lib/test/test_pathlib.py
@@ -831,6 +831,14 @@ class PureWindowsPathTest(_BasePurePathTest, 
unittest.TestCase):
 ],
 })
 
+def test_constructor_nested_foreign_flavour(self):
+# See GH-125069.
+p1 = pathlib.PurePosixPath('b/c:\\d')
+p2 = pathlib.PurePosixPath('b/', 'c:\\d')
+self.assertEqual(p1, p2)
+self.assertEqual(self.cls(p1), self.cls('b/c:/d'))
+self.assertEqual(self.cls(p2), self.cls('b/c:/d'))
+
 def test_drive_root_parts(self):
 check = self._check_drive_root_parts
 # First part is anchored.
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst 
b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
new file mode 100644
index 00..73d5fa59303d4d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
@@ -0,0 +1,4 @@
+Fix an issue where providing a :class:`pathlib.PurePath` object as an
+initializer argument to a second :class:`~pathlib.PurePath` object with a
+different flavour resulted in arguments to the former object's initializer
+ being joined by the latter object's flavour.

___
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-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` (#125156)

2024-10-13 Thread barneygale
https://github.com/python/cpython/commit/cb8e5995d89d9b90e83cf43310ec50e177484e70
commit: cb8e5995d89d9b90e83cf43310ec50e177484e70
branch: main
author: Barney Gale 
committer: barneygale 
date: 2024-10-13T17:46:10Z
summary:

GH-125069: Fix inconsistent joining in `WindowsPath(PosixPath(...))` (#125156)

`PurePath.__init__()` incorrectly uses the `_raw_paths` of a given
`PurePath` object with a different flavour, even though the procedure to
join path segments can differ between flavours.

This change makes the `_raw_paths`-enabled deferred joining apply _only_
when the path flavours match.

Co-authored-by: Bénédikt Tran <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
M Lib/pathlib/_local.py
M Lib/test/test_pathlib/test_pathlib.py

diff --git a/Lib/pathlib/_local.py b/Lib/pathlib/_local.py
index 1c02e4168d3a9e..a78997179820b1 100644
--- a/Lib/pathlib/_local.py
+++ b/Lib/pathlib/_local.py
@@ -119,9 +119,9 @@ def __init__(self, *args):
 paths = []
 for arg in args:
 if isinstance(arg, PurePath):
-if arg.parser is ntpath and self.parser is posixpath:
+if arg.parser is not self.parser:
 # GH-103631: Convert separators for backwards 
compatibility.
-paths.extend(path.replace('\\', '/') for path in 
arg._raw_paths)
+paths.append(arg.as_posix())
 else:
 paths.extend(arg._raw_paths)
 else:
diff --git a/Lib/test/test_pathlib/test_pathlib.py 
b/Lib/test/test_pathlib/test_pathlib.py
index b47b4a194cfaa9..c7104bfda90f6c 100644
--- a/Lib/test/test_pathlib/test_pathlib.py
+++ b/Lib/test/test_pathlib/test_pathlib.py
@@ -131,6 +131,15 @@ def test_constructor_nested(self):
 self.assertEqual(P(P('a'), P('b'), P('c')), P(FakePath("a/b/c")))
 self.assertEqual(P(P('./a:b')), P('./a:b'))
 
+@needs_windows
+def test_constructor_nested_foreign_flavour(self):
+# See GH-125069.
+p1 = pathlib.PurePosixPath('b/c:\\d')
+p2 = pathlib.PurePosixPath('b/', 'c:\\d')
+self.assertEqual(p1, p2)
+self.assertEqual(self.cls(p1), self.cls('b/c:/d'))
+self.assertEqual(self.cls(p2), self.cls('b/c:/d'))
+
 def _check_parse_path(self, raw_path, *expected):
 sep = self.parser.sep
 actual = self.cls._parse_path(raw_path.replace('/', sep))
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst 
b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
new file mode 100644
index 00..9f1fd871e1d0b5
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-08-21-17-16.gh-issue-125069.0RP0Mx.rst
@@ -0,0 +1,4 @@
+Fix an issue where providing a :class:`pathlib.PurePath` object as an
+initializer argument to a second :class:`~pathlib.PurePath` object with a
+different :attr:`~pathlib.PurePath.parser` resulted in arguments to the
+former object's initializer being joined by the latter object's parser.

___
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-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384) (#125408)

2024-10-13 Thread vstinner
https://github.com/python/cpython/commit/243a8a9d68a87d103340b894366497101e6b0226
commit: 243a8a9d68a87d103340b894366497101e6b0226
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: vstinner 
date: 2024-10-13T17:45:59Z
summary:

[3.12] gh-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384) 
(#125408)

gh-101291: Add versionadded directives for PyUnstable_Long_* (GH-125384)
(cherry picked from commit c6d7b644c2425b397cfb641f336bea70eb8a329a)

Co-authored-by: Sergey B Kirpichev 

files:
M Doc/c-api/long.rst

diff --git a/Doc/c-api/long.rst b/Doc/c-api/long.rst
index af86810c6b166b..972d69a5194511 100644
--- a/Doc/c-api/long.rst
+++ b/Doc/c-api/long.rst
@@ -350,6 +350,9 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
Exactly what values are considered compact is an implementation detail
and is subject to change.
 
+   .. versionadded:: 3.12
+
+
 .. c:function:: Py_ssize_t PyUnstable_Long_CompactValue(const PyLongObject* op)
 
If *op* is compact, as determined by :c:func:`PyUnstable_Long_IsCompact`,
@@ -357,3 +360,5 @@ distinguished from a number.  Use :c:func:`PyErr_Occurred` 
to disambiguate.
 
Otherwise, the return value is undefined.
 
+   .. versionadded:: 3.12
+

___
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-123849: Fix test_sqlite3.test_table_dump when foreign keys are enabled by default (GH-123859) (#125163)

2024-10-13 Thread erlend-aasland
https://github.com/python/cpython/commit/98655cec0e5c11ee28c8c67e446747e53d72d301
commit: 98655cec0e5c11ee28c8c67e446747e53d72d301
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: erlend-aasland 
date: 2024-10-13T20:47:38+02:00
summary:

[3.13] gh-123849: Fix test_sqlite3.test_table_dump when foreign keys are 
enabled by default (GH-123859) (#125163)

(cherry picked from commit 14b44c58e195c4cdee6594a4aacf8bf95b19fcd7)

Co-authored-by: Mariusz Felisiak 

files:
M Lib/test/test_sqlite3/test_dump.py

diff --git a/Lib/test/test_sqlite3/test_dump.py 
b/Lib/test/test_sqlite3/test_dump.py
index d508f238f84fb5..550cea41976441 100644
--- a/Lib/test/test_sqlite3/test_dump.py
+++ b/Lib/test/test_sqlite3/test_dump.py
@@ -10,6 +10,7 @@ class DumpTests(MemoryDatabaseMixin, unittest.TestCase):
 
 def test_table_dump(self):
 expected_sqls = [
+"PRAGMA foreign_keys=OFF;",
 """CREATE TABLE "index"("index" blob);"""
 ,
 """INSERT INTO "index" VALUES(X'01');"""
@@ -48,7 +49,7 @@ def test_table_dump(self):
 expected_sqls = [
 "PRAGMA foreign_keys=OFF;",
 "BEGIN TRANSACTION;",
-*expected_sqls,
+*expected_sqls[1:],
 "COMMIT;",
 ]
 [self.assertEqual(expected_sqls[i], actual_sqls[i])

___
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-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426)

2024-10-13 Thread willingc
https://github.com/python/cpython/commit/cfc27bc50fe165330f2295f9ac0ad56ca5b0f31c
commit: cfc27bc50fe165330f2295f9ac0ad56ca5b0f31c
branch: main
author: Sergey B Kirpichev 
committer: willingc 
date: 2024-10-13T21:44:48-07:00
summary:

gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426)

Co-authored-by: Serhiy Storchaka 

files:
M Doc/library/string.rst

diff --git a/Doc/library/string.rst b/Doc/library/string.rst
index 57a1f920523035..49aeb28d57c8d1 100644
--- a/Doc/library/string.rst
+++ b/Doc/library/string.rst
@@ -509,9 +509,8 @@ The available presentation types for :class:`float` and
| | significant digits. With no precision given, uses a  |
| | precision of ``6`` digits after the decimal point for|
| | :class:`float`, and shows all coefficient digits |
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'E'`` | Scientific notation. Same as ``'e'`` except it uses  |
| | an upper case 'E' as the separator character.|
@@ -522,9 +521,8 @@ The available presentation types for :class:`float` and
| | precision given, uses a precision of ``6`` digits after  |
| | the decimal point for :class:`float`, and uses a |
| | precision large enough to show all coefficient digits|
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts  |
| | ``nan`` to  ``NAN`` and ``inf`` to ``INF``.  |

___
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-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426) (#125428)

2024-10-13 Thread willingc
https://github.com/python/cpython/commit/1279be610dd22fc116998a60c0f9a08fa18386ea
commit: 1279be610dd22fc116998a60c0f9a08fa18386ea
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: willingc 
date: 2024-10-14T04:50:06Z
summary:

[3.13] gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426) 
(#125428)

gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426)
(cherry picked from commit cfc27bc50fe165330f2295f9ac0ad56ca5b0f31c)

Co-authored-by: Sergey B Kirpichev 
Co-authored-by: Serhiy Storchaka 

files:
M Doc/library/string.rst

diff --git a/Doc/library/string.rst b/Doc/library/string.rst
index 57a1f920523035..49aeb28d57c8d1 100644
--- a/Doc/library/string.rst
+++ b/Doc/library/string.rst
@@ -509,9 +509,8 @@ The available presentation types for :class:`float` and
| | significant digits. With no precision given, uses a  |
| | precision of ``6`` digits after the decimal point for|
| | :class:`float`, and shows all coefficient digits |
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'E'`` | Scientific notation. Same as ``'e'`` except it uses  |
| | an upper case 'E' as the separator character.|
@@ -522,9 +521,8 @@ The available presentation types for :class:`float` and
| | precision given, uses a precision of ``6`` digits after  |
| | the decimal point for :class:`float`, and uses a |
| | precision large enough to show all coefficient digits|
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts  |
| | ``nan`` to  ``NAN`` and ``inf`` to ``INF``.  |

___
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-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426) (#125429)

2024-10-13 Thread willingc
https://github.com/python/cpython/commit/20323bf733810d7dc7e6bcd86dfbc16b7f3c4b30
commit: 20323bf733810d7dc7e6bcd86dfbc16b7f3c4b30
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: willingc 
date: 2024-10-14T04:51:59Z
summary:

[3.12] gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426) 
(#125429)

gh-123133: clarify p=0 case for "f" and "e" formatting types (GH-125426)
(cherry picked from commit cfc27bc50fe165330f2295f9ac0ad56ca5b0f31c)

Co-authored-by: Sergey B Kirpichev 
Co-authored-by: Serhiy Storchaka 

files:
M Doc/library/string.rst

diff --git a/Doc/library/string.rst b/Doc/library/string.rst
index 57a1f920523035..49aeb28d57c8d1 100644
--- a/Doc/library/string.rst
+++ b/Doc/library/string.rst
@@ -509,9 +509,8 @@ The available presentation types for :class:`float` and
| | significant digits. With no precision given, uses a  |
| | precision of ``6`` digits after the decimal point for|
| | :class:`float`, and shows all coefficient digits |
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'E'`` | Scientific notation. Same as ``'e'`` except it uses  |
| | an upper case 'E' as the separator character.|
@@ -522,9 +521,8 @@ The available presentation types for :class:`float` and
| | precision given, uses a precision of ``6`` digits after  |
| | the decimal point for :class:`float`, and uses a |
| | precision large enough to show all coefficient digits|
-   | | for :class:`~decimal.Decimal`. If no digits follow the   |
-   | | decimal point, the decimal point is also removed unless  |
-   | | the ``#`` option is used.|
+   | | for :class:`~decimal.Decimal`.  If ``p=0``, the decimal  |
+   | | point is omitted unless the ``#`` option is used.|
+-+--+
| ``'F'`` | Fixed-point notation. Same as ``'f'``, but converts  |
| | ``nan`` to  ``NAN`` and ``inf`` to ``INF``.  |

___
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-86357: argparse: use str() consistently and explicitly to print choices (GH-117766)

2024-10-13 Thread serhiy-storchaka
https://github.com/python/cpython/commit/66b3922b97388c328c9bd8df050eef11c0261fae
commit: 66b3922b97388c328c9bd8df050eef11c0261fae
branch: main
author: rindeal 
committer: serhiy-storchaka 
date: 2024-10-14T09:36:53+03:00
summary:

gh-86357: argparse: use str() consistently and explicitly to print choices 
(GH-117766)

Signed-off-by: Jan Chren ~rindeal 

files:
A Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst
M Lib/argparse.py
M Lib/test/test_argparse.py

diff --git a/Lib/argparse.py b/Lib/argparse.py
index 550415dc93478b..fa9f5211257e96 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -547,8 +547,7 @@ def _metavar_formatter(self, action, default_metavar):
 if action.metavar is not None:
 result = action.metavar
 elif action.choices is not None:
-choice_strs = [str(choice) for choice in action.choices]
-result = '{%s}' % ','.join(choice_strs)
+result = '{%s}' % ','.join(map(str, action.choices))
 else:
 result = default_metavar
 
@@ -599,8 +598,7 @@ def _expand_help(self, action):
 elif hasattr(value, '__name__'):
 params[name] = value.__name__
 if params.get('choices') is not None:
-choices_str = ', '.join([str(c) for c in params['choices']])
-params['choices'] = choices_str
+params['choices'] = ', '.join(map(str, params['choices']))
 return help_string % params
 
 def _iter_indented_subactions(self, action):
@@ -717,7 +715,7 @@ def _get_action_name(argument):
 elif argument.dest not in (None, SUPPRESS):
 return argument.dest
 elif argument.choices:
-return '{' + ','.join(argument.choices) + '}'
+return '{%s}' % ','.join(map(str, argument.choices))
 else:
 return None
 
@@ -2607,8 +2605,8 @@ def _check_value(self, action, value):
 if isinstance(choices, str):
 choices = iter(choices)
 if value not in choices:
-args = {'value': value,
-'choices': ', '.join(map(repr, action.choices))}
+args = {'value': str(value),
+'choices': ', '.join(map(str, action.choices))}
 msg = _('invalid choice: %(value)r (choose from %(choices)s)')
 raise ArgumentError(action, msg % args)
 
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index f52a4b6bdd8aca..78692fd3474782 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -16,6 +16,7 @@
 import argparse
 import warnings
 
+from enum import StrEnum
 from test.support import captured_stderr
 from test.support import import_helper
 from test.support import os_helper
@@ -985,6 +986,34 @@ class 
TestDisallowLongAbbreviationAllowsShortGroupingPrefix(ParserTestCase):
 ]
 
 
+class TestStrEnumChoices(TestCase):
+class Color(StrEnum):
+RED = "red"
+GREEN = "green"
+BLUE = "blue"
+
+def test_parse_enum_value(self):
+parser = argparse.ArgumentParser()
+parser.add_argument('--color', choices=self.Color)
+args = parser.parse_args(['--color', 'red'])
+self.assertEqual(args.color, self.Color.RED)
+
+def test_help_message_contains_enum_choices(self):
+parser = argparse.ArgumentParser()
+parser.add_argument('--color', choices=self.Color, help='Choose a 
color')
+self.assertIn('[--color {red,green,blue}]', parser.format_usage())
+self.assertIn('  --color {red,green,blue}', parser.format_help())
+
+def test_invalid_enum_value_raises_error(self):
+parser = argparse.ArgumentParser(exit_on_error=False)
+parser.add_argument('--color', choices=self.Color)
+self.assertRaisesRegex(
+argparse.ArgumentError,
+r"invalid choice: 'yellow' \(choose from red, green, blue\)",
+parser.parse_args,
+['--color', 'yellow'],
+)
+
 # 
 # Positional tests
 # 
@@ -2485,7 +2514,7 @@ def 
test_wrong_argument_subparsers_no_destination_error(self):
 parser.parse_args(('baz',))
 self.assertRegex(
 excinfo.exception.stderr,
-r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 
'foo', 'bar'\)\n$"
+r"error: argument {foo,bar}: invalid choice: 'baz' \(choose from 
foo, bar\)\n$"
 )
 
 def test_optional_subparsers(self):
diff --git 
a/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst 
b/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst
new file mode 100644
index 00..d090f931f0238d
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-04-19-05-58-50.gh-issue-117766.J3xepp.rst
@@ -0,0 +1 @@
+Always use :func:`str` to print ``choices`` in :mod:`argparse`.

___
Python-checkins mailing list -- [email protected]