[Python-checkins] [3.12] gh-61011: Fix inheritance of nested mutually exclusive groups in argparse (GH-125210) (GH-125309)

2024-10-11 Thread serhiy-storchaka
https://github.com/python/cpython/commit/23cefd9f4c9e49fbdef50b7deaf76499760e4c4b
commit: 23cefd9f4c9e49fbdef50b7deaf76499760e4c4b
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka 
date: 2024-10-11T09:07:03Z
summary:

[3.12] gh-61011: Fix inheritance of nested mutually exclusive groups in 
argparse (GH-125210) (GH-125309)

Previously, all nested mutually exclusive groups lost their connection
to the group containing them and were displayed as belonging directly
to the parser.

(cherry picked from commit 18c74497681e0107d7cde53e63ea42feb38f2176)

Co-authored-by: Serhiy Storchaka 
Co-authored-by: Danica J. Sutherland 

files:
A Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
M Lib/argparse.py
M Lib/test/test_argparse.py
M Misc/ACKS

diff --git a/Lib/argparse.py b/Lib/argparse.py
index bd5c757197fcf8..2a3253453dff84 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1564,7 +1564,11 @@ def _add_container_actions(self, container):
 # NOTE: if add_mutually_exclusive_group ever gains title= and
 # description= then this code will need to be expanded as above
 for group in container._mutually_exclusive_groups:
-mutex_group = self.add_mutually_exclusive_group(
+if group._container is container:
+cont = self
+else:
+cont = title_group_map[group._container.title]
+mutex_group = cont.add_mutually_exclusive_group(
 required=group.required)
 
 # map the actions to their new mutex group
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index 13d15fbf075861..84f8b09fb1d2a4 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -2880,6 +2880,35 @@ def test_groups_parents(self):
   -x X
 '''.format(progname, ' ' if progname else '' )))
 
+def test_mutex_groups_parents(self):
+parent = ErrorRaisingArgumentParser(add_help=False)
+g = parent.add_argument_group(title='g', description='gd')
+g.add_argument('-w')
+g.add_argument('-x')
+m = g.add_mutually_exclusive_group()
+m.add_argument('-y')
+m.add_argument('-z')
+parser = ErrorRaisingArgumentParser(prog='PROG', parents=[parent])
+
+self.assertRaises(ArgumentParserError, parser.parse_args,
+['-y', 'Y', '-z', 'Z'])
+
+parser_help = parser.format_help()
+self.assertEqual(parser_help, textwrap.dedent('''\
+usage: PROG [-h] [-w W] [-x X] [-y Y | -z Z]
+
+options:
+  -h, --help  show this help message and exit
+
+g:
+  gd
+
+  -w W
+  -x X
+  -y Y
+  -z Z
+'''))
+
 # ==
 # Mutually exclusive group tests
 # ==
diff --git a/Misc/ACKS b/Misc/ACKS
index b5dc32ee507689..837ffbda18aea1 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1792,6 +1792,7 @@ Reuben Sumner
 Eryk Sun
 Sanjay Sundaresan
 Marek Šuppa
+Danica J. Sutherland
 Hisao Suzuki
 Kalle Svensson
 Andrew Svetlov
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst 
b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
new file mode 100644
index 00..20f9c0b9c78b12
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
@@ -0,0 +1,4 @@
+Fix inheritance of nested mutually exclusive groups from parent parser in
+:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive
+groups lost their connection to the group containing them and were displayed
+as belonging directly to the 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] gh-125235: Keep `_tkinter` TCL paths pointing to base installation on Windows (#125250)

2024-10-11 Thread vstinner
https://github.com/python/cpython/commit/b3aa1b5fe260382788a2df416599325ad680a5ee
commit: b3aa1b5fe260382788a2df416599325ad680a5ee
branch: main
author: Y5 <[email protected]>
committer: vstinner 
date: 2024-10-11T11:08:03+02:00
summary:

gh-125235: Keep `_tkinter` TCL paths pointing to base installation on Windows 
(#125250)

Signed-off-by: y5c4l3 

files:
A Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
M Modules/_tkinter.c

diff --git 
a/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst 
b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
new file mode 100644
index 00..f64d15917da1fc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
@@ -0,0 +1,2 @@
+Keep :mod:`tkinter` TCL paths in venv pointing to base installation on
+Windows.
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index 4f05cab375ed6b..b0b70ccb8cc3d3 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -143,7 +143,7 @@ _get_tcl_lib_path(void)
 struct stat stat_buf;
 int stat_return_value;
 
-PyObject *prefix = PySys_GetObject("prefix");  // borrowed reference
+PyObject *prefix = PySys_GetObject("base_prefix");  // borrowed 
reference
 if (prefix == NULL) {
 return NULL;
 }

___
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-125221: Fix free-threading data race in `object.__reduce_ex__` (#125267)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/b12e99261e656585ffbaa395af7c5dbaee5ad1ad
commit: b12e99261e656585ffbaa395af7c5dbaee5ad1ad
branch: main
author: Sam Gross 
committer: kumaraditya303 
date: 2024-10-11T13:26:01+05:30
summary:

gh-125221: Fix free-threading data race in `object.__reduce_ex__` (#125267)

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
M Objects/object.c
M Objects/typeobject.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
new file mode 100644
index 00..c79650c3a64feb
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
@@ -0,0 +1,2 @@
+Fix possible race condition when calling :meth:`~object.__reduce_ex__` for the
+first time in the free threading build.
diff --git a/Objects/object.c b/Objects/object.c
index 27d06cc081259d..4a4c5bf7d7f08a 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2372,6 +2372,14 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
 }
 }
 
+// Cache __reduce__ from PyBaseObject_Type object
+PyObject *baseobj_dict = _PyType_GetDict(&PyBaseObject_Type);
+PyObject *baseobj_reduce = PyDict_GetItemWithError(baseobj_dict, 
&_Py_ID(__reduce__));
+if (baseobj_reduce == NULL && PyErr_Occurred()) {
+return _PyStatus_ERR("Can't get __reduce__ from base object");
+}
+_Py_INTERP_CACHED_OBJECT(interp, objreduce) = baseobj_reduce;
+
 // Must be after static types are initialized
 if (_Py_initialize_generic(interp) < 0) {
 return _PyStatus_ERR("Can't initialize generic types");
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index d90bb5825fd437..6ca4406ec0ea2d 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -7359,18 +7359,7 @@ static PyObject *
 object___reduce_ex___impl(PyObject *self, int protocol)
 /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/
 {
-#define objreduce \
-(_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_GET(), objreduce))
-PyObject *reduce, *res;
-
-if (objreduce == NULL) {
-PyObject *dict = lookup_tp_dict(&PyBaseObject_Type);
-objreduce = PyDict_GetItemWithError(dict, &_Py_ID(__reduce__));
-if (objreduce == NULL && PyErr_Occurred()) {
-return NULL;
-}
-}
-
+PyObject *reduce;
 if (PyObject_GetOptionalAttr(self, &_Py_ID(__reduce__), &reduce) < 0) {
 return NULL;
 }
@@ -7384,10 +7373,12 @@ object___reduce_ex___impl(PyObject *self, int protocol)
 Py_DECREF(reduce);
 return NULL;
 }
-override = (clsreduce != objreduce);
+
+PyInterpreterState *interp = _PyInterpreterState_GET();
+override = (clsreduce != _Py_INTERP_CACHED_OBJECT(interp, objreduce));
 Py_DECREF(clsreduce);
 if (override) {
-res = _PyObject_CallNoArgs(reduce);
+PyObject *res = _PyObject_CallNoArgs(reduce);
 Py_DECREF(reduce);
 return res;
 }
@@ -7396,7 +7387,6 @@ object___reduce_ex___impl(PyObject *self, int protocol)
 }
 
 return _common_reduce(self, protocol);
-#undef objreduce
 }
 
 static PyObject *

___
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-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` (GH-125141) (#125306)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/49f171d9ea26be64f2be20a6448bd5de441a677b
commit: 49f171d9ea26be64f2be20a6448bd5de441a677b
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 
date: 2024-10-11T08:20:46Z
summary:

[3.13] gh-125058: update `_thread` docs regarding interruptibility of 
`lock.acquire()` (GH-125141) (#125306)

gh-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` 
(GH-125141)
(cherry picked from commit 0135848059162ad81478a7776fec622d68a36524)

Co-authored-by: Jan Kaliszewski 

files:
M Doc/library/_thread.rst

diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
index 5fd604c05380ac..6a66fc4c64bc45 100644
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -219,9 +219,11 @@ In addition to these methods, lock objects can also be 
used via the
 * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
   equivalent to calling :func:`_thread.exit`.
 
-* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on
-  a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock
-  has been acquired.
+* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method
+  on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception
+  will happen immediately, rather than only after the lock has been acquired or
+  the operation has timed out). It can be interrupted on POSIX, but not on
+  Windows.
 
 * When the main thread exits, it is system defined whether the other threads
   survive.  On most systems, they are killed without executing

___
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-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` (GH-125141) (#125307)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/4c40381023df1319661b27f4ab65075569532c73
commit: 4c40381023df1319661b27f4ab65075569532c73
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 
date: 2024-10-11T08:22:34Z
summary:

[3.12] gh-125058: update `_thread` docs regarding interruptibility of 
`lock.acquire()` (GH-125141) (#125307)

gh-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` 
(GH-125141)
(cherry picked from commit 0135848059162ad81478a7776fec622d68a36524)

Co-authored-by: Jan Kaliszewski 

files:
M Doc/library/_thread.rst

diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
index d82f63834dd2d1..e5cbff0b1ef4bc 100644
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -216,9 +216,11 @@ In addition to these methods, lock objects can also be 
used via the
 * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
   equivalent to calling :func:`_thread.exit`.
 
-* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on
-  a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock
-  has been acquired.
+* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method
+  on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception
+  will happen immediately, rather than only after the lock has been acquired or
+  the operation has timed out). It can be interrupted on POSIX, but not on
+  Windows.
 
 * When the main thread exits, it is system defined whether the other threads
   survive.  On most systems, they are killed without executing

___
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-125221: Fix free-threading data race in `object.__reduce_ex__` (GH-125267) (#125305)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/b3badabcd9bc17e095780adbf52ee9bd015c2771
commit: b3badabcd9bc17e095780adbf52ee9bd015c2771
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 
date: 2024-10-11T08:26:23Z
summary:

[3.13] gh-125221: Fix free-threading data race in `object.__reduce_ex__` 
(GH-125267) (#125305)

gh-125221: Fix free-threading data race in `object.__reduce_ex__` (GH-125267)
(cherry picked from commit b12e99261e656585ffbaa395af7c5dbaee5ad1ad)

Co-authored-by: Sam Gross 

files:
A 
Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
M Objects/object.c
M Objects/typeobject.c

diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
new file mode 100644
index 00..c79650c3a64feb
--- /dev/null
+++ 
b/Misc/NEWS.d/next/Core_and_Builtins/2024-10-10-14-47-13.gh-issue-125221.nfSQzT.rst
@@ -0,0 +1,2 @@
+Fix possible race condition when calling :meth:`~object.__reduce_ex__` for the
+first time in the free threading build.
diff --git a/Objects/object.c b/Objects/object.c
index cbf576d5e5aee3..b191b480cf270f 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -2353,6 +2353,14 @@ _PyTypes_InitTypes(PyInterpreterState *interp)
 }
 }
 
+// Cache __reduce__ from PyBaseObject_Type object
+PyObject *baseobj_dict = _PyType_GetDict(&PyBaseObject_Type);
+PyObject *baseobj_reduce = PyDict_GetItemWithError(baseobj_dict, 
&_Py_ID(__reduce__));
+if (baseobj_reduce == NULL && PyErr_Occurred()) {
+return _PyStatus_ERR("Can't get __reduce__ from base object");
+}
+_Py_INTERP_CACHED_OBJECT(interp, objreduce) = baseobj_reduce;
+
 // Must be after static types are initialized
 if (_Py_initialize_generic(interp) < 0) {
 return _PyStatus_ERR("Can't initialize generic types");
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c911c3020039ab..12808642963640 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -7050,18 +7050,7 @@ static PyObject *
 object___reduce_ex___impl(PyObject *self, int protocol)
 /*[clinic end generated code: output=2e157766f6b50094 input=f326b43fb8a4c5ff]*/
 {
-#define objreduce \
-(_Py_INTERP_CACHED_OBJECT(_PyInterpreterState_GET(), objreduce))
-PyObject *reduce, *res;
-
-if (objreduce == NULL) {
-PyObject *dict = lookup_tp_dict(&PyBaseObject_Type);
-objreduce = PyDict_GetItemWithError(dict, &_Py_ID(__reduce__));
-if (objreduce == NULL && PyErr_Occurred()) {
-return NULL;
-}
-}
-
+PyObject *reduce;
 if (PyObject_GetOptionalAttr(self, &_Py_ID(__reduce__), &reduce) < 0) {
 return NULL;
 }
@@ -7075,10 +7064,12 @@ object___reduce_ex___impl(PyObject *self, int protocol)
 Py_DECREF(reduce);
 return NULL;
 }
-override = (clsreduce != objreduce);
+
+PyInterpreterState *interp = _PyInterpreterState_GET();
+override = (clsreduce != _Py_INTERP_CACHED_OBJECT(interp, objreduce));
 Py_DECREF(clsreduce);
 if (override) {
-res = _PyObject_CallNoArgs(reduce);
+PyObject *res = _PyObject_CallNoArgs(reduce);
 Py_DECREF(reduce);
 return res;
 }
@@ -7087,7 +7078,6 @@ object___reduce_ex___impl(PyObject *self, int protocol)
 }
 
 return _common_reduce(self, protocol);
-#undef objreduce
 }
 
 static PyObject *

___
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-61011: Fix inheritance of nested mutually exclusive groups in argparse (GH-125210)

2024-10-11 Thread serhiy-storchaka
https://github.com/python/cpython/commit/18c74497681e0107d7cde53e63ea42feb38f2176
commit: 18c74497681e0107d7cde53e63ea42feb38f2176
branch: main
author: Serhiy Storchaka 
committer: serhiy-storchaka 
date: 2024-10-11T11:43:29+03:00
summary:

gh-61011: Fix inheritance of nested mutually exclusive groups in argparse 
(GH-125210)

Previously, all nested mutually exclusive groups lost their connection
to the group containing them and were displayed as belonging directly
to the parser.

Co-authored-by: Danica J. Sutherland 

files:
A Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
M Lib/argparse.py
M Lib/test/test_argparse.py
M Misc/ACKS

diff --git a/Lib/argparse.py b/Lib/argparse.py
index d1f8fa2ace8611..2d8a7ef343a4ef 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1521,7 +1521,11 @@ def _add_container_actions(self, container):
 # NOTE: if add_mutually_exclusive_group ever gains title= and
 # description= then this code will need to be expanded as above
 for group in container._mutually_exclusive_groups:
-mutex_group = self.add_mutually_exclusive_group(
+if group._container is container:
+cont = self
+else:
+cont = title_group_map[group._container.title]
+mutex_group = cont.add_mutually_exclusive_group(
 required=group.required)
 
 # map the actions to their new mutex group
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index c9e79eb18a08fb..1ebbc21bc1755b 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -2942,6 +2942,35 @@ def test_groups_parents(self):
 def test_wrong_type_parents(self):
 self.assertRaises(TypeError, ErrorRaisingArgumentParser, parents=[1])
 
+def test_mutex_groups_parents(self):
+parent = ErrorRaisingArgumentParser(add_help=False)
+g = parent.add_argument_group(title='g', description='gd')
+g.add_argument('-w')
+g.add_argument('-x')
+m = g.add_mutually_exclusive_group()
+m.add_argument('-y')
+m.add_argument('-z')
+parser = ErrorRaisingArgumentParser(prog='PROG', parents=[parent])
+
+self.assertRaises(ArgumentParserError, parser.parse_args,
+['-y', 'Y', '-z', 'Z'])
+
+parser_help = parser.format_help()
+self.assertEqual(parser_help, textwrap.dedent('''\
+usage: PROG [-h] [-w W] [-x X] [-y Y | -z Z]
+
+options:
+  -h, --help  show this help message and exit
+
+g:
+  gd
+
+  -w W
+  -x X
+  -y Y
+  -z Z
+'''))
+
 # ==
 # Mutually exclusive group tests
 # ==
diff --git a/Misc/ACKS b/Misc/ACKS
index d94cbacf888468..a1769d9601a2ea 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1814,6 +1814,7 @@ Reuben Sumner
 Eryk Sun
 Sanjay Sundaresan
 Marek Šuppa
+Danica J. Sutherland
 Hisao Suzuki
 Kalle Svensson
 Andrew Svetlov
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst 
b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
new file mode 100644
index 00..20f9c0b9c78b12
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
@@ -0,0 +1,4 @@
+Fix inheritance of nested mutually exclusive groups from parent parser in
+:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive
+groups lost their connection to the group containing them and were displayed
+as belonging directly to the 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] gh-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` (#125141)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/0135848059162ad81478a7776fec622d68a36524
commit: 0135848059162ad81478a7776fec622d68a36524
branch: main
author: Jan Kaliszewski 
committer: kumaraditya303 
date: 2024-10-11T13:45:46+05:30
summary:

gh-125058: update `_thread` docs regarding interruptibility of `lock.acquire()` 
(#125141)

files:
M Doc/library/_thread.rst

diff --git a/Doc/library/_thread.rst b/Doc/library/_thread.rst
index 5fd604c05380ac..6a66fc4c64bc45 100644
--- a/Doc/library/_thread.rst
+++ b/Doc/library/_thread.rst
@@ -219,9 +219,11 @@ In addition to these methods, lock objects can also be 
used via the
 * Calling :func:`sys.exit` or raising the :exc:`SystemExit` exception is
   equivalent to calling :func:`_thread.exit`.
 
-* It is not possible to interrupt the :meth:`~threading.Lock.acquire` method on
-  a lock --- the :exc:`KeyboardInterrupt` exception will happen after the lock
-  has been acquired.
+* It is platform-dependent whether the :meth:`~threading.Lock.acquire` method
+  on a lock can be interrupted (so that the :exc:`KeyboardInterrupt` exception
+  will happen immediately, rather than only after the lock has been acquired or
+  the operation has timed out). It can be interrupted on POSIX, but not on
+  Windows.
 
 * When the main thread exits, it is system defined whether the other threads
   survive.  On most systems, they are killed without executing

___
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-61011: Fix inheritance of nested mutually exclusive groups in argparse (GH-125210) (GH-125308)

2024-10-11 Thread serhiy-storchaka
https://github.com/python/cpython/commit/079bf1c31ce90fdea7bc1cb385169d9ad1417303
commit: 079bf1c31ce90fdea7bc1cb385169d9ad1417303
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: serhiy-storchaka 
date: 2024-10-11T09:14:04Z
summary:

[3.13] gh-61011: Fix inheritance of nested mutually exclusive groups in 
argparse (GH-125210) (GH-125308)

Previously, all nested mutually exclusive groups lost their connection
to the group containing them and were displayed as belonging directly
to the parser.

(cherry picked from commit 18c74497681e0107d7cde53e63ea42feb38f2176)

Co-authored-by: Serhiy Storchaka 
Co-authored-by: Danica J. Sutherland 

files:
A Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
M Lib/argparse.py
M Lib/test/test_argparse.py
M Misc/ACKS

diff --git a/Lib/argparse.py b/Lib/argparse.py
index 71d0c8fc8703ea..c625a96aca330a 100644
--- a/Lib/argparse.py
+++ b/Lib/argparse.py
@@ -1549,7 +1549,11 @@ def _add_container_actions(self, container):
 # NOTE: if add_mutually_exclusive_group ever gains title= and
 # description= then this code will need to be expanded as above
 for group in container._mutually_exclusive_groups:
-mutex_group = self.add_mutually_exclusive_group(
+if group._container is container:
+cont = self
+else:
+cont = title_group_map[group._container.title]
+mutex_group = cont.add_mutually_exclusive_group(
 required=group.required)
 
 # map the actions to their new mutex group
diff --git a/Lib/test/test_argparse.py b/Lib/test/test_argparse.py
index a5940c5554e5a4..a1503427c335f5 100644
--- a/Lib/test/test_argparse.py
+++ b/Lib/test/test_argparse.py
@@ -2947,6 +2947,35 @@ def test_groups_parents(self):
 def test_wrong_type_parents(self):
 self.assertRaises(TypeError, ErrorRaisingArgumentParser, parents=[1])
 
+def test_mutex_groups_parents(self):
+parent = ErrorRaisingArgumentParser(add_help=False)
+g = parent.add_argument_group(title='g', description='gd')
+g.add_argument('-w')
+g.add_argument('-x')
+m = g.add_mutually_exclusive_group()
+m.add_argument('-y')
+m.add_argument('-z')
+parser = ErrorRaisingArgumentParser(prog='PROG', parents=[parent])
+
+self.assertRaises(ArgumentParserError, parser.parse_args,
+['-y', 'Y', '-z', 'Z'])
+
+parser_help = parser.format_help()
+self.assertEqual(parser_help, textwrap.dedent('''\
+usage: PROG [-h] [-w W] [-x X] [-y Y | -z Z]
+
+options:
+  -h, --help  show this help message and exit
+
+g:
+  gd
+
+  -w W
+  -x X
+  -y Y
+  -z Z
+'''))
+
 # ==
 # Mutually exclusive group tests
 # ==
diff --git a/Misc/ACKS b/Misc/ACKS
index b5d2f51a8bd61d..05cb6874759c31 100644
--- a/Misc/ACKS
+++ b/Misc/ACKS
@@ -1811,6 +1811,7 @@ Reuben Sumner
 Eryk Sun
 Sanjay Sundaresan
 Marek Šuppa
+Danica J. Sutherland
 Hisao Suzuki
 Kalle Svensson
 Andrew Svetlov
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst 
b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
new file mode 100644
index 00..20f9c0b9c78b12
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-09-21-42-43.gh-issue-61011.pQXZb1.rst
@@ -0,0 +1,4 @@
+Fix inheritance of nested mutually exclusive groups from parent parser in
+:class:`argparse.ArgumentParser`. Previously, all nested mutually exclusive
+groups lost their connection to the group containing them and were displayed
+as belonging directly to the 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-124917: Allow keyword args to os.path.exists/lexists on Windows (GH-124918) (#125334)

2024-10-11 Thread JelleZijlstra
https://github.com/python/cpython/commit/4ab19f912d9220d9762a1f2a0bda2add8af6ae94
commit: 4ab19f912d9220d9762a1f2a0bda2add8af6ae94
branch: 3.12
author: Jelle Zijlstra 
committer: JelleZijlstra 
date: 2024-10-11T15:18:46-07:00
summary:

[3.12] gh-124917: Allow keyword args to os.path.exists/lexists on Windows 
(GH-124918) (#125334)

(cherry picked from commit cc2938a18967c9d462ebb18bc09f73e4364aa7d2)

files:
A Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
M Lib/test/test_genericpath.py
M Modules/clinic/posixmodule.c.h
M Modules/posixmodule.c

diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index bdfc5bfe260799..3eefb722b81e55 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -158,6 +158,11 @@ def test_exists(self):
 self.assertIs(self.pathmodule.lexists(filename + '\x00'), False)
 self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False)
 
+# Keyword arguments are accepted
+self.assertIs(self.pathmodule.exists(path=filename), True)
+if self.pathmodule is not genericpath:
+self.assertIs(self.pathmodule.lexists(path=filename), True)
+
 @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
 @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat")
 def test_exists_fd(self):
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst 
b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
new file mode 100644
index 00..6218528d2079c3
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
@@ -0,0 +1,2 @@
+Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with
+keyword arguments on Windows. Fixes a regression in 3.12.4.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index f46aa65148da7d..a33461dc5600dd 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -1975,25 +1975,55 @@ os__path_splitroot(PyObject *module, PyObject *const 
*args, Py_ssize_t nargs, Py
 #if defined(MS_WINDOWS)
 
 PyDoc_STRVAR(os__path_exists__doc__,
-"_path_exists($module, path, /)\n"
+"_path_exists($module, /, path)\n"
 "--\n"
 "\n"
 "Test whether a path exists.  Returns False for broken symbolic links.");
 
 #define OS__PATH_EXISTS_METHODDEF\
-{"_path_exists", (PyCFunction)os__path_exists, METH_O, 
os__path_exists__doc__},
+{"_path_exists", _PyCFunction_CAST(os__path_exists), 
METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__},
 
 static int
 os__path_exists_impl(PyObject *module, path_t *path);
 
 static PyObject *
-os__path_exists(PyObject *module, PyObject *arg)
+os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, 
PyObject *kwnames)
 {
 PyObject *return_value = NULL;
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+#define NUM_KEYWORDS 1
+static struct {
+PyGC_Head _this_is_not_used;
+PyObject_VAR_HEAD
+PyObject *ob_item[NUM_KEYWORDS];
+} _kwtuple = {
+.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+.ob_item = { &_Py_ID(path), },
+};
+#undef NUM_KEYWORDS
+#define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+#else  // !Py_BUILD_CORE
+#  define KWTUPLE NULL
+#endif  // !Py_BUILD_CORE
+
+static const char * const _keywords[] = {"path", NULL};
+static _PyArg_Parser _parser = {
+.keywords = _keywords,
+.fname = "_path_exists",
+.kwtuple = KWTUPLE,
+};
+#undef KWTUPLE
+PyObject *argsbuf[1];
 path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1);
 int _return_value;
 
-if (!path_converter(arg, &path)) {
+args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 
0, argsbuf);
+if (!args) {
+goto exit;
+}
+if (!path_converter(args[0], &path)) {
 goto exit;
 }
 _return_value = os__path_exists_impl(module, &path);
@@ -12002,4 +12032,4 @@ os_waitstatus_to_exitcode(PyObject *module, PyObject 
*const *args, Py_ssize_t na
 #ifndef OS_WAITSTATUS_TO_EXITCODE_METHODDEF
 #define OS_WAITSTATUS_TO_EXITCODE_METHODDEF
 #endif /* !defined(OS_WAITSTATUS_TO_EXITCODE_METHODDEF) */
-/*[clinic end generated code: output=67c2e3d4537287c1 input=a9049054013a1b77]*/
+/*[clinic end generated code: output=6d34c4564aca7725 input=a9049054013a1b77]*/
diff --git a/Modules/posixmodule.c b/Modules/posixmodule.c
index 2277caee58f505..b8558cc2265a58 100644
--- a/Modules/posixmodule.c
+++ b/Modules/posixmodule.c
@@ -5209,7 +5209,6 @@ _testFileType(path_t *path, int testedType)
 os._path_exists -> bool
 
 path: path_t(allow_fd=True, suppress_value_error=True)
-/
 
 Test whether a path exists.  Returns False for broken symbolic links.
 
@@ -5217,7 +5216,7 @@ Test whether a path exists.  Returns False for broken 
symbolic links.
 
 static int
 os__path_exists

[Python-checkins] [3.13] gh-124917: Allow keyword args to os.path.exists/lexists on Windows (GH-124918) (#125332)

2024-10-11 Thread JelleZijlstra
https://github.com/python/cpython/commit/e646cc369eca7c13f57113199deb02530e103bd0
commit: e646cc369eca7c13f57113199deb02530e103bd0
branch: 3.13
author: Jelle Zijlstra 
committer: JelleZijlstra 
date: 2024-10-11T15:18:33-07:00
summary:

[3.13] gh-124917: Allow keyword args to os.path.exists/lexists on Windows 
(GH-124918) (#125332)

(cherry picked from commit cc2938a18967c9d462ebb18bc09f73e4364aa7d2)

files:
A Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
M Lib/test/test_genericpath.py
M Modules/clinic/posixmodule.c.h
M Modules/posixmodule.c

diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index bf04b3fecf7057..6d2593cb4cf228 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -156,6 +156,10 @@ def test_exists(self):
 self.assertIs(self.pathmodule.lexists(filename + '\x00'), False)
 self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False)
 
+# Keyword arguments are accepted
+self.assertIs(self.pathmodule.exists(path=filename), True)
+self.assertIs(self.pathmodule.lexists(path=filename), True)
+
 @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
 @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat")
 def test_exists_fd(self):
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst 
b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
new file mode 100644
index 00..f208793859bbf8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
@@ -0,0 +1,2 @@
+Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with
+keyword arguments on Windows. Fixes a regression in 3.13.0.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index d7af87dc946aeb..6a3aacf13e74ad 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -2015,25 +2015,55 @@ os__path_splitroot(PyObject *module, PyObject *const 
*args, Py_ssize_t nargs, Py
 #if defined(MS_WINDOWS)
 
 PyDoc_STRVAR(os__path_exists__doc__,
-"_path_exists($module, path, /)\n"
+"_path_exists($module, /, path)\n"
 "--\n"
 "\n"
 "Test whether a path exists.  Returns False for broken symbolic links.");
 
 #define OS__PATH_EXISTS_METHODDEF\
-{"_path_exists", (PyCFunction)os__path_exists, METH_O, 
os__path_exists__doc__},
+{"_path_exists", _PyCFunction_CAST(os__path_exists), 
METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__},
 
 static int
 os__path_exists_impl(PyObject *module, path_t *path);
 
 static PyObject *
-os__path_exists(PyObject *module, PyObject *arg)
+os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, 
PyObject *kwnames)
 {
 PyObject *return_value = NULL;
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+#define NUM_KEYWORDS 1
+static struct {
+PyGC_Head _this_is_not_used;
+PyObject_VAR_HEAD
+PyObject *ob_item[NUM_KEYWORDS];
+} _kwtuple = {
+.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+.ob_item = { &_Py_ID(path), },
+};
+#undef NUM_KEYWORDS
+#define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+#else  // !Py_BUILD_CORE
+#  define KWTUPLE NULL
+#endif  // !Py_BUILD_CORE
+
+static const char * const _keywords[] = {"path", NULL};
+static _PyArg_Parser _parser = {
+.keywords = _keywords,
+.fname = "_path_exists",
+.kwtuple = KWTUPLE,
+};
+#undef KWTUPLE
+PyObject *argsbuf[1];
 path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1);
 int _return_value;
 
-if (!path_converter(arg, &path)) {
+args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 
0, argsbuf);
+if (!args) {
+goto exit;
+}
+if (!path_converter(args[0], &path)) {
 goto exit;
 }
 _return_value = os__path_exists_impl(module, &path);
@@ -2054,25 +2084,55 @@ os__path_exists(PyObject *module, PyObject *arg)
 #if defined(MS_WINDOWS)
 
 PyDoc_STRVAR(os__path_lexists__doc__,
-"_path_lexists($module, path, /)\n"
+"_path_lexists($module, /, path)\n"
 "--\n"
 "\n"
 "Test whether a path exists.  Returns True for broken symbolic links.");
 
 #define OS__PATH_LEXISTS_METHODDEF\
-{"_path_lexists", (PyCFunction)os__path_lexists, METH_O, 
os__path_lexists__doc__},
+{"_path_lexists", _PyCFunction_CAST(os__path_lexists), 
METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__},
 
 static int
 os__path_lexists_impl(PyObject *module, path_t *path);
 
 static PyObject *
-os__path_lexists(PyObject *module, PyObject *arg)
+os__path_lexists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, 
PyObject *kwnames)
 {
 PyObject *return_value = NULL;
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+#define NUM_KEYWORDS 1
+static struct {
+PyGC_Head _this_is_not_used;
+PyObject

[Python-checkins] gh-116938: Clarify documentation of `dict` and `dict.update` regarding the positional argument they accept (#125213)

2024-10-11 Thread AlexWaygood
https://github.com/python/cpython/commit/21ac0a7f4cf6d11da728b33ed5e8cfa65a5a8ae7
commit: 21ac0a7f4cf6d11da728b33ed5e8cfa65a5a8ae7
branch: main
author: Victorien <[email protected]>
committer: AlexWaygood 
date: 2024-10-11T23:05:13Z
summary:

gh-116938: Clarify documentation of `dict` and `dict.update` regarding the 
positional argument they accept (#125213)

Co-authored-by: Alex Waygood 

files:
M Doc/library/stdtypes.rst
M Lib/_collections_abc.py

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 833c71c4ce4b9a..a6e2e3b8928ebe 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -4505,14 +4505,14 @@ can be used interchangeably to index the same 
dictionary entry.
  ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)``
 
If no positional argument is given, an empty dictionary is created.
-   If a positional argument is given and it is a mapping object, a dictionary
-   is created with the same key-value pairs as the mapping object.  Otherwise,
-   the positional argument must be an :term:`iterable` object.  Each item in
-   the iterable must itself be an iterable with exactly two objects.  The
-   first object of each item becomes a key in the new dictionary, and the
-   second object the corresponding value.  If a key occurs more than once, the
-   last value for that key becomes the corresponding value in the new
-   dictionary.
+   If a positional argument is given and it defines a ``keys()`` method, a
+   dictionary is created by calling :meth:`~object.__getitem__` on the 
argument with
+   each returned key from the method.  Otherwise, the positional argument must 
be an
+   :term:`iterable` object.  Each item in the iterable must itself be an 
iterable
+   with exactly two elements.  The first element of each item becomes a key in 
the
+   new dictionary, and the second element the corresponding value.  If a key 
occurs
+   more than once, the last value for that key becomes the corresponding value 
in
+   the new dictionary.
 
If keyword arguments are given, the keyword arguments and their values are
added to the dictionary created from the positional argument.  If a key
@@ -4669,10 +4669,11 @@ can be used interchangeably to index the same 
dictionary entry.
   Update the dictionary with the key/value pairs from *other*, overwriting
   existing keys.  Return ``None``.
 
-  :meth:`update` accepts either another dictionary object or an iterable of
-  key/value pairs (as tuples or other iterables of length two).  If keyword
-  arguments are specified, the dictionary is then updated with those
-  key/value pairs: ``d.update(red=1, blue=2)``.
+  :meth:`update` accepts either another object with a ``keys()`` method (in
+  which case :meth:`~object.__getitem__` is called with every key returned 
from
+  the method). or an iterable of key/value pairs (as tuples or other 
iterables
+  of length two). If keyword arguments are specified, the dictionary is 
then
+  updated with those key/value pairs: ``d.update(red=1, blue=2)``.
 
.. method:: values()
 
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index c2edf6c8856c21..06667b7434ccef 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -962,7 +962,7 @@ def clear(self):
 
 def update(self, other=(), /, **kwds):
 ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and 
F.
-If E present and has a .keys() method, does: for k in E: D[k] 
= E[k]
+If E present and has a .keys() method, does: for k in 
E.keys(): D[k] = E[k]
 If E present and lacks .keys() method, does: for (k, v) in E: 
D[k] = v
 In either case, this is followed by: for k, v in F.items(): D[k] = 
v
 '''

___
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] Doc: Fix a typo in "Function Examples" in the control-flow tutorial (#125338)

2024-10-11 Thread AA-Turner
https://github.com/python/cpython/commit/5a074aab845f82f4a150c27b905dae05c337d381
commit: 5a074aab845f82f4a150c27b905dae05c337d381
branch: main
author: Rafael Fontenelle 
committer: AA-Turner <[email protected]>
date: 2024-10-12T01:40:33+01:00
summary:

Doc: Fix a typo in "Function Examples" in the control-flow tutorial (#125338)

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index fd765e58ff2485..9b73ac475c78d5 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -832,7 +832,7 @@ parameters as there is a ``/`` in the function definition::
  File "", line 1, in 
TypeError: pos_only_arg() got some positional-only arguments passed as 
keyword arguments: 'arg'
 
-The third function ``kwd_only_args`` only allows keyword arguments as indicated
+The third function ``kwd_only_arg`` only allows keyword arguments as indicated
 by a ``*`` in the function definition::
 
>>> kwd_only_arg(3)

___
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] Doc: Fix a typo in "Function Examples" in the control-flow tutorial (GH-125338) (#125341)

2024-10-11 Thread AA-Turner
https://github.com/python/cpython/commit/a314026cfe05306e90b1df156e8a9441520b5d9f
commit: a314026cfe05306e90b1df156e8a9441520b5d9f
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: AA-Turner <[email protected]>
date: 2024-10-12T00:45:50Z
summary:

[3.13] Doc: Fix a typo in "Function Examples" in the control-flow tutorial 
(GH-125338) (#125341)

Doc: Fix a typo in "Function Examples" in the control-flow tutorial (GH-125338)
(cherry picked from commit 5a074aab845f82f4a150c27b905dae05c337d381)

Co-authored-by: Rafael Fontenelle 

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index fd765e58ff2485..9b73ac475c78d5 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -832,7 +832,7 @@ parameters as there is a ``/`` in the function definition::
  File "", line 1, in 
TypeError: pos_only_arg() got some positional-only arguments passed as 
keyword arguments: 'arg'
 
-The third function ``kwd_only_args`` only allows keyword arguments as indicated
+The third function ``kwd_only_arg`` only allows keyword arguments as indicated
 by a ``*`` in the function definition::
 
>>> kwd_only_arg(3)

___
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] Doc: Fix a typo in "Function Examples" in the control-flow tutorial (GH-125338) (#125342)

2024-10-11 Thread AA-Turner
https://github.com/python/cpython/commit/2264c097e09810a563aab379cc17e6b5d9d2bf74
commit: 2264c097e09810a563aab379cc17e6b5d9d2bf74
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: AA-Turner <[email protected]>
date: 2024-10-12T00:47:23Z
summary:

[3.12] Doc: Fix a typo in "Function Examples" in the control-flow tutorial 
(GH-125338) (#125342)

Doc: Fix a typo in "Function Examples" in the control-flow tutorial (GH-125338)
(cherry picked from commit 5a074aab845f82f4a150c27b905dae05c337d381)

Co-authored-by: Rafael Fontenelle 

files:
M Doc/tutorial/controlflow.rst

diff --git a/Doc/tutorial/controlflow.rst b/Doc/tutorial/controlflow.rst
index fd765e58ff2485..9b73ac475c78d5 100644
--- a/Doc/tutorial/controlflow.rst
+++ b/Doc/tutorial/controlflow.rst
@@ -832,7 +832,7 @@ parameters as there is a ``/`` in the function definition::
  File "", line 1, in 
TypeError: pos_only_arg() got some positional-only arguments passed as 
keyword arguments: 'arg'
 
-The third function ``kwd_only_args`` only allows keyword arguments as indicated
+The third function ``kwd_only_arg`` only allows keyword arguments as indicated
 by a ``*`` in the function definition::
 
>>> kwd_only_arg(3)

___
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-116938: Clarify documentation of `dict` and `dict.update` regarding the positional argument they accept (GH-125213) (#125337)

2024-10-11 Thread AlexWaygood
https://github.com/python/cpython/commit/3f38ea11c029b68472d6c23aec3cf711e3e62d3c
commit: 3f38ea11c029b68472d6c23aec3cf711e3e62d3c
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: AlexWaygood 
date: 2024-10-11T23:23:54Z
summary:

[3.12] gh-116938: Clarify documentation of `dict` and `dict.update` regarding 
the positional argument they accept (GH-125213) (#125337)

Co-authored-by: Victorien <[email protected]>
Co-authored-by: Alex Waygood 

files:
M Doc/library/stdtypes.rst
M Lib/_collections_abc.py

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index e72711dc9cb5b7..0c1f29d8b69d97 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -4460,14 +4460,14 @@ can be used interchangeably to index the same 
dictionary entry.
  ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)``
 
If no positional argument is given, an empty dictionary is created.
-   If a positional argument is given and it is a mapping object, a dictionary
-   is created with the same key-value pairs as the mapping object.  Otherwise,
-   the positional argument must be an :term:`iterable` object.  Each item in
-   the iterable must itself be an iterable with exactly two objects.  The
-   first object of each item becomes a key in the new dictionary, and the
-   second object the corresponding value.  If a key occurs more than once, the
-   last value for that key becomes the corresponding value in the new
-   dictionary.
+   If a positional argument is given and it defines a ``keys()`` method, a
+   dictionary is created by calling :meth:`~object.__getitem__` on the 
argument with
+   each returned key from the method.  Otherwise, the positional argument must 
be an
+   :term:`iterable` object.  Each item in the iterable must itself be an 
iterable
+   with exactly two elements.  The first element of each item becomes a key in 
the
+   new dictionary, and the second element the corresponding value.  If a key 
occurs
+   more than once, the last value for that key becomes the corresponding value 
in
+   the new dictionary.
 
If keyword arguments are given, the keyword arguments and their values are
added to the dictionary created from the positional argument.  If a key
@@ -4624,10 +4624,11 @@ can be used interchangeably to index the same 
dictionary entry.
   Update the dictionary with the key/value pairs from *other*, overwriting
   existing keys.  Return ``None``.
 
-  :meth:`update` accepts either another dictionary object or an iterable of
-  key/value pairs (as tuples or other iterables of length two).  If keyword
-  arguments are specified, the dictionary is then updated with those
-  key/value pairs: ``d.update(red=1, blue=2)``.
+  :meth:`update` accepts either another object with a ``keys()`` method (in
+  which case :meth:`~object.__getitem__` is called with every key returned 
from
+  the method). or an iterable of key/value pairs (as tuples or other 
iterables
+  of length two). If keyword arguments are specified, the dictionary is 
then
+  updated with those key/value pairs: ``d.update(red=1, blue=2)``.
 
.. method:: values()
 
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index 601107d2d86771..09745658de1925 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -973,7 +973,7 @@ def clear(self):
 
 def update(self, other=(), /, **kwds):
 ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and 
F.
-If E present and has a .keys() method, does: for k in E: D[k] 
= E[k]
+If E present and has a .keys() method, does: for k in 
E.keys(): D[k] = E[k]
 If E present and lacks .keys() method, does: for (k, v) in E: 
D[k] = v
 In either case, this is followed by: for k, v in F.items(): D[k] = 
v
 '''

___
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-116938: Clarify documentation of `dict` and `dict.update` regarding the positional argument they accept (GH-125213) (#125336)

2024-10-11 Thread AlexWaygood
https://github.com/python/cpython/commit/21764ec5ab2dd9a97fe1ff8613dcddb35ef4b11a
commit: 21764ec5ab2dd9a97fe1ff8613dcddb35ef4b11a
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: AlexWaygood 
date: 2024-10-11T23:29:01Z
summary:

[3.13] gh-116938: Clarify documentation of `dict` and `dict.update` regarding 
the positional argument they accept (GH-125213) (#125336)

Co-authored-by: Victorien <[email protected]>
Co-authored-by: Alex Waygood 

files:
M Doc/library/stdtypes.rst
M Lib/_collections_abc.py

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 8b9d29545e328b..c77399461edc38 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -4469,14 +4469,14 @@ can be used interchangeably to index the same 
dictionary entry.
  ``dict([('foo', 100), ('bar', 200)])``, ``dict(foo=100, bar=200)``
 
If no positional argument is given, an empty dictionary is created.
-   If a positional argument is given and it is a mapping object, a dictionary
-   is created with the same key-value pairs as the mapping object.  Otherwise,
-   the positional argument must be an :term:`iterable` object.  Each item in
-   the iterable must itself be an iterable with exactly two objects.  The
-   first object of each item becomes a key in the new dictionary, and the
-   second object the corresponding value.  If a key occurs more than once, the
-   last value for that key becomes the corresponding value in the new
-   dictionary.
+   If a positional argument is given and it defines a ``keys()`` method, a
+   dictionary is created by calling :meth:`~object.__getitem__` on the 
argument with
+   each returned key from the method.  Otherwise, the positional argument must 
be an
+   :term:`iterable` object.  Each item in the iterable must itself be an 
iterable
+   with exactly two elements.  The first element of each item becomes a key in 
the
+   new dictionary, and the second element the corresponding value.  If a key 
occurs
+   more than once, the last value for that key becomes the corresponding value 
in
+   the new dictionary.
 
If keyword arguments are given, the keyword arguments and their values are
added to the dictionary created from the positional argument.  If a key
@@ -4633,10 +4633,11 @@ can be used interchangeably to index the same 
dictionary entry.
   Update the dictionary with the key/value pairs from *other*, overwriting
   existing keys.  Return ``None``.
 
-  :meth:`update` accepts either another dictionary object or an iterable of
-  key/value pairs (as tuples or other iterables of length two).  If keyword
-  arguments are specified, the dictionary is then updated with those
-  key/value pairs: ``d.update(red=1, blue=2)``.
+  :meth:`update` accepts either another object with a ``keys()`` method (in
+  which case :meth:`~object.__getitem__` is called with every key returned 
from
+  the method). or an iterable of key/value pairs (as tuples or other 
iterables
+  of length two). If keyword arguments are specified, the dictionary is 
then
+  updated with those key/value pairs: ``d.update(red=1, blue=2)``.
 
.. method:: values()
 
diff --git a/Lib/_collections_abc.py b/Lib/_collections_abc.py
index 036254869d52c3..aebe9c8b64ac08 100644
--- a/Lib/_collections_abc.py
+++ b/Lib/_collections_abc.py
@@ -978,7 +978,7 @@ def clear(self):
 
 def update(self, other=(), /, **kwds):
 ''' D.update([E, ]**F) -> None.  Update D from mapping/iterable E and 
F.
-If E present and has a .keys() method, does: for k in E: D[k] 
= E[k]
+If E present and has a .keys() method, does: for k in 
E.keys(): D[k] = E[k]
 If E present and lacks .keys() method, does: for (k, v) in E: 
D[k] = v
 In either case, this is followed by: for k, v in F.items(): D[k] = 
v
 '''

___
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-124309: fix staggered race on eager tasks (#124847)

2024-10-11 Thread 1st1
https://github.com/python/cpython/commit/979c0df7c0adfb744159a5fc184043dc733d8534
commit: 979c0df7c0adfb744159a5fc184043dc733d8534
branch: main
author: Thomas Grainger 
committer: 1st1 
date: 2024-10-11T16:31:06-07:00
summary:

gh-124309: fix staggered race on eager tasks (#124847)

This patch is entirely by Thomas and Peter

Co-authored-by: Thomas Grainger 
Co-authored-by: Peter Bierma 

files:
A Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst
M Lib/asyncio/staggered.py
M Lib/test/test_asyncio/test_eager_task_factory.py
M Lib/test/test_asyncio/test_staggered.py

diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py
index 326c6f708944af..0f4df8855a80b9 100644
--- a/Lib/asyncio/staggered.py
+++ b/Lib/asyncio/staggered.py
@@ -69,7 +69,11 @@ async def staggered_race(coro_fns, delay, *, loop=None):
 exceptions = []
 running_tasks = []
 
-async def run_one_coro(previous_failed) -> None:
+async def run_one_coro(ok_to_start, previous_failed) -> None:
+# in eager tasks this waits for the calling task to append this task
+# to running_tasks, in regular tasks this wait is a no-op that does
+# not yield a future. See gh-124309.
+await ok_to_start.wait()
 # Wait for the previous task to finish, or for delay seconds
 if previous_failed is not None:
 with contextlib.suppress(exceptions_mod.TimeoutError):
@@ -85,8 +89,12 @@ async def run_one_coro(previous_failed) -> None:
 return
 # Start task that will run the next coroutine
 this_failed = locks.Event()
-next_task = loop.create_task(run_one_coro(this_failed))
+next_ok_to_start = locks.Event()
+next_task = loop.create_task(run_one_coro(next_ok_to_start, 
this_failed))
 running_tasks.append(next_task)
+# next_task has been appended to running_tasks so next_task is ok to
+# start.
+next_ok_to_start.set()
 assert len(running_tasks) == this_index + 2
 # Prepare place to put this coroutine's exceptions if not won
 exceptions.append(None)
@@ -116,8 +124,11 @@ async def run_one_coro(previous_failed) -> None:
 if i != this_index:
 t.cancel()
 
-first_task = loop.create_task(run_one_coro(None))
+ok_to_start = locks.Event()
+first_task = loop.create_task(run_one_coro(ok_to_start, None))
 running_tasks.append(first_task)
+# first_task has been appended to running_tasks so first_task is ok to 
start.
+ok_to_start.set()
 try:
 # Wait for a growing list of tasks to all finish: poor man's version of
 # curio's TaskGroup or trio's nursery
diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py 
b/Lib/test/test_asyncio/test_eager_task_factory.py
index 0777f39b572486..31d2a00dbb8c9c 100644
--- a/Lib/test/test_asyncio/test_eager_task_factory.py
+++ b/Lib/test/test_asyncio/test_eager_task_factory.py
@@ -213,6 +213,52 @@ async def run():
 
 self.run_coro(run())
 
+def test_staggered_race_with_eager_tasks(self):
+# See https://github.com/python/cpython/issues/124309
+
+async def fail():
+await asyncio.sleep(0)
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: asyncio.sleep(2, result="sleep2"),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: fail()
+],
+delay=0.25
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], asyncio.CancelledError)
+self.assertIsInstance(excs[2], ValueError)
+
+self.run_coro(run())
+
+def test_staggered_race_with_eager_tasks_no_delay(self):
+# See https://github.com/python/cpython/issues/124309
+async def fail():
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: fail(),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: asyncio.sleep(0, result="sleep0"),
+],
+delay=None
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], ValueError)
+self.assertEqual(len(excs), 2)
+
+self.run_coro(run())
+
 
 class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, 
test_utils.TestCase):
 Task = tasks._PyTask
diff --git a/Lib/test/test_asyncio/test_staggered.py 
b/Lib/test/test_asyncio/test_staggered.py
index e6e32f7dbbbcba..74941f704c4890 100644
--- a/Lib/test/test_asyncio/test_sta

[Python-checkins] [3.13] Add some doctest cleanups for `configparser` (GH-125288) (#125290)

2024-10-11 Thread AlexWaygood
https://github.com/python/cpython/commit/73c152b346a18ed8308e469bdd232698e6cd3a63
commit: 73c152b346a18ed8308e469bdd232698e6cd3a63
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: AlexWaygood 
date: 2024-10-11T09:48:32Z
summary:

[3.13] Add some doctest cleanups for `configparser` (GH-125288) (#125290)

Co-authored-by: Alex Waygood 
Co-authored-by: Adam Turner <[email protected]>

files:
M Doc/library/configparser.rst

diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst
index cf13de4116fe3d..8e52689211895a 100644
--- a/Doc/library/configparser.rst
+++ b/Doc/library/configparser.rst
@@ -54,6 +54,7 @@ can be customized by end users easily.
 
import os
os.remove("example.ini")
+   os.remove("override.ini")
 
 
 Quick Start

___
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-124787: Fix `TypeAliasType` and incorrect `type_params` (#124795)

2024-10-11 Thread sobolevn
https://github.com/python/cpython/commit/2115d76acc14effb3dbb9fedcf21048b2ad62c5e
commit: 2115d76acc14effb3dbb9fedcf21048b2ad62c5e
branch: main
author: sobolevn 
committer: sobolevn 
date: 2024-10-11T17:39:18+03:00
summary:

gh-124787: Fix `TypeAliasType` and incorrect `type_params` (#124795)

Co-authored-by: Jelle Zijlstra 

files:
A Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst
M Lib/test/test_type_aliases.py
M Objects/typevarobject.c

diff --git a/Lib/test/test_type_aliases.py b/Lib/test/test_type_aliases.py
index ebb65d8c6cf81b..230bbe646baf28 100644
--- a/Lib/test/test_type_aliases.py
+++ b/Lib/test/test_type_aliases.py
@@ -4,7 +4,9 @@
 from test.support import check_syntax_error, run_code
 from test.typinganndata import mod_generics_cache
 
-from typing import Callable, TypeAliasType, TypeVar, get_args
+from typing import (
+Callable, TypeAliasType, TypeVar, TypeVarTuple, ParamSpec, get_args,
+)
 
 
 class TypeParamsInvalidTest(unittest.TestCase):
@@ -225,6 +227,46 @@ def test_not_generic(self):
 ):
 TA[int]
 
+def test_type_params_order_with_defaults(self):
+HasNoDefaultT = TypeVar("HasNoDefaultT")
+WithDefaultT = TypeVar("WithDefaultT", default=int)
+
+HasNoDefaultP = ParamSpec("HasNoDefaultP")
+WithDefaultP = ParamSpec("WithDefaultP", default=HasNoDefaultP)
+
+HasNoDefaultTT = TypeVarTuple("HasNoDefaultTT")
+WithDefaultTT = TypeVarTuple("WithDefaultTT", default=HasNoDefaultTT)
+
+for type_params in [
+(HasNoDefaultT, WithDefaultT),
+(HasNoDefaultP, WithDefaultP),
+(HasNoDefaultTT, WithDefaultTT),
+]:
+with self.subTest(type_params=type_params):
+TypeAliasType("A", int, type_params=type_params)  # ok
+
+msg = "follows default type parameter"
+for type_params in [
+(WithDefaultT, HasNoDefaultT),
+(WithDefaultP, HasNoDefaultP),
+(WithDefaultTT, HasNoDefaultTT),
+(WithDefaultT, HasNoDefaultP),  # different types
+]:
+with self.subTest(type_params=type_params):
+with self.assertRaisesRegex(TypeError, msg):
+TypeAliasType("A", int, type_params=type_params)
+
+def test_expects_type_like(self):
+T = TypeVar("T")
+
+msg = "Expected a type param"
+with self.assertRaisesRegex(TypeError, msg):
+TypeAliasType("A", int, type_params=(1,))
+with self.assertRaisesRegex(TypeError, msg):
+TypeAliasType("A", int, type_params=(1, 2))
+with self.assertRaisesRegex(TypeError, msg):
+TypeAliasType("A", int, type_params=(T, 2))
+
 def test_keywords(self):
 TA = TypeAliasType(name="TA", value=int)
 self.assertEqual(TA.__name__, "TA")
diff --git 
a/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst 
b/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst
new file mode 100644
index 00..d9d1bbcf5a2fe4
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-09-30-20-46-32.gh-issue-124787.3FnJnP.rst
@@ -0,0 +1,4 @@
+Fix :class:`typing.TypeAliasType` with incorrect ``type_params`` argument.
+Now it raises a :exc:`TypeError` when a type parameter without a default
+follows one with a default, and when an entry in the ``type_params`` tuple
+is not a type parameter object.
diff --git a/Objects/typevarobject.c b/Objects/typevarobject.c
index 51d93ed8b5ba8c..91cc37c9a72636 100644
--- a/Objects/typevarobject.c
+++ b/Objects/typevarobject.c
@@ -1799,6 +1799,24 @@ _Py_make_typevartuple(PyThreadState *Py_UNUSED(ignored), 
PyObject *v)
 return (PyObject *)typevartuple_alloc(v, NULL, NULL);
 }
 
+static PyObject *
+get_type_param_default(PyThreadState *ts, PyObject *typeparam) {
+// Does not modify refcount of existing objects.
+if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.typevar_type)) {
+return typevar_default((typevarobject *)typeparam, NULL);
+}
+else if (Py_IS_TYPE(typeparam, ts->interp->cached_objects.paramspec_type)) 
{
+return paramspec_default((paramspecobject *)typeparam, NULL);
+}
+else if (Py_IS_TYPE(typeparam, 
ts->interp->cached_objects.typevartuple_type)) {
+return typevartuple_default((typevartupleobject *)typeparam, NULL);
+}
+else {
+PyErr_Format(PyExc_TypeError, "Expected a type param, got %R", 
typeparam);
+return NULL;
+}
+}
+
 static void
 typealias_dealloc(PyObject *self)
 {
@@ -1906,25 +1924,75 @@ static PyGetSetDef typealias_getset[] = {
 {0}
 };
 
-static typealiasobject *
-typealias_alloc(PyObject *name, PyObject *type_params, PyObject *compute_value,
-PyObject *value, PyObject *module)
-{
-typealiasobject *ta = PyObject_GC_New(typealiasobject, &_PyTypeAlias_Type);
-if (ta == NULL) {
+static PyObject *
+typealias_check_type_params(PyObject *type_params, int *er

[Python-checkins] gh-124917: Allow keyword args to os.path.exists/lexists on Windows (#124918)

2024-10-11 Thread JelleZijlstra
https://github.com/python/cpython/commit/cc2938a18967c9d462ebb18bc09f73e4364aa7d2
commit: cc2938a18967c9d462ebb18bc09f73e4364aa7d2
branch: main
author: Jelle Zijlstra 
committer: JelleZijlstra 
date: 2024-10-11T12:41:59-07:00
summary:

gh-124917: Allow keyword args to os.path.exists/lexists on Windows (#124918)

files:
A Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
M Lib/test/test_genericpath.py
M Modules/clinic/posixmodule.c.h
M Modules/posixmodule.c

diff --git a/Lib/test/test_genericpath.py b/Lib/test/test_genericpath.py
index bf04b3fecf7057..6d2593cb4cf228 100644
--- a/Lib/test/test_genericpath.py
+++ b/Lib/test/test_genericpath.py
@@ -156,6 +156,10 @@ def test_exists(self):
 self.assertIs(self.pathmodule.lexists(filename + '\x00'), False)
 self.assertIs(self.pathmodule.lexists(bfilename + b'\x00'), False)
 
+# Keyword arguments are accepted
+self.assertIs(self.pathmodule.exists(path=filename), True)
+self.assertIs(self.pathmodule.lexists(path=filename), True)
+
 @unittest.skipUnless(hasattr(os, "pipe"), "requires os.pipe()")
 @unittest.skipIf(is_emscripten, "Emscripten pipe fds have no stat")
 def test_exists_fd(self):
diff --git 
a/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst 
b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
new file mode 100644
index 00..f208793859bbf8
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-02-21-11-18.gh-issue-124917.Lnwh5b.rst
@@ -0,0 +1,2 @@
+Allow calling :func:`os.path.exists` and :func:`os.path.lexists` with
+keyword arguments on Windows. Fixes a regression in 3.13.0.
diff --git a/Modules/clinic/posixmodule.c.h b/Modules/clinic/posixmodule.c.h
index 749fe54598cc39..d9d919ea75d853 100644
--- a/Modules/clinic/posixmodule.c.h
+++ b/Modules/clinic/posixmodule.c.h
@@ -2015,25 +2015,55 @@ os__path_splitroot(PyObject *module, PyObject *const 
*args, Py_ssize_t nargs, Py
 #if defined(MS_WINDOWS)
 
 PyDoc_STRVAR(os__path_exists__doc__,
-"_path_exists($module, path, /)\n"
+"_path_exists($module, /, path)\n"
 "--\n"
 "\n"
 "Test whether a path exists.  Returns False for broken symbolic links.");
 
 #define OS__PATH_EXISTS_METHODDEF\
-{"_path_exists", (PyCFunction)os__path_exists, METH_O, 
os__path_exists__doc__},
+{"_path_exists", _PyCFunction_CAST(os__path_exists), 
METH_FASTCALL|METH_KEYWORDS, os__path_exists__doc__},
 
 static int
 os__path_exists_impl(PyObject *module, path_t *path);
 
 static PyObject *
-os__path_exists(PyObject *module, PyObject *arg)
+os__path_exists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, 
PyObject *kwnames)
 {
 PyObject *return_value = NULL;
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+#define NUM_KEYWORDS 1
+static struct {
+PyGC_Head _this_is_not_used;
+PyObject_VAR_HEAD
+PyObject *ob_item[NUM_KEYWORDS];
+} _kwtuple = {
+.ob_base = PyVarObject_HEAD_INIT(&PyTuple_Type, NUM_KEYWORDS)
+.ob_item = { &_Py_ID(path), },
+};
+#undef NUM_KEYWORDS
+#define KWTUPLE (&_kwtuple.ob_base.ob_base)
+
+#else  // !Py_BUILD_CORE
+#  define KWTUPLE NULL
+#endif  // !Py_BUILD_CORE
+
+static const char * const _keywords[] = {"path", NULL};
+static _PyArg_Parser _parser = {
+.keywords = _keywords,
+.fname = "_path_exists",
+.kwtuple = KWTUPLE,
+};
+#undef KWTUPLE
+PyObject *argsbuf[1];
 path_t path = PATH_T_INITIALIZE_P("_path_exists", "path", 0, 0, 1, 1);
 int _return_value;
 
-if (!path_converter(arg, &path)) {
+args = _PyArg_UnpackKeywords(args, nargs, NULL, kwnames, &_parser, 1, 1, 
0, argsbuf);
+if (!args) {
+goto exit;
+}
+if (!path_converter(args[0], &path)) {
 goto exit;
 }
 _return_value = os__path_exists_impl(module, &path);
@@ -2054,25 +2084,55 @@ os__path_exists(PyObject *module, PyObject *arg)
 #if defined(MS_WINDOWS)
 
 PyDoc_STRVAR(os__path_lexists__doc__,
-"_path_lexists($module, path, /)\n"
+"_path_lexists($module, /, path)\n"
 "--\n"
 "\n"
 "Test whether a path exists.  Returns True for broken symbolic links.");
 
 #define OS__PATH_LEXISTS_METHODDEF\
-{"_path_lexists", (PyCFunction)os__path_lexists, METH_O, 
os__path_lexists__doc__},
+{"_path_lexists", _PyCFunction_CAST(os__path_lexists), 
METH_FASTCALL|METH_KEYWORDS, os__path_lexists__doc__},
 
 static int
 os__path_lexists_impl(PyObject *module, path_t *path);
 
 static PyObject *
-os__path_lexists(PyObject *module, PyObject *arg)
+os__path_lexists(PyObject *module, PyObject *const *args, Py_ssize_t nargs, 
PyObject *kwnames)
 {
 PyObject *return_value = NULL;
+#if defined(Py_BUILD_CORE) && !defined(Py_BUILD_CORE_MODULE)
+
+#define NUM_KEYWORDS 1
+static struct {
+PyGC_Head _this_is_not_used;
+PyObject_VAR_HEAD
+PyObject *ob_item[NUM_KEYWORDS];
+} _kwtuple = {
+.ob_base 

[Python-checkins] [3.13] Fix typo in ``Doc/library/functions.rst`` (GH-125327) (#125333)

2024-10-11 Thread Eclips4
https://github.com/python/cpython/commit/488807a52ab16550a260f919963e6119556a2161
commit: 488807a52ab16550a260f919963e6119556a2161
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Eclips4 
date: 2024-10-11T20:06:19Z
summary:

[3.13] Fix typo in ``Doc/library/functions.rst`` (GH-125327) (#125333)

Fix typo in ``Doclibrary/functions.rst`` (GH-125327)
(cherry picked from commit 76b29d271b3132bf8e13bc724f10be8c630057ba)

Co-authored-by: Rafael Fontenelle 

files:
M Doc/library/functions.rst

diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 798d96e846293e..e388cbb5b6fce3 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -680,7 +680,7 @@ are always available.  They are listed here in alphabetical 
order.
The *closure* argument specifies a closure--a tuple of cellvars.
It's only valid when the *object* is a code object containing
:term:`free (closure) variables `.
-   The length of the tuple must exactly match the length of the code object'S
+   The length of the tuple must exactly match the length of the code object's
:attr:`~codeobject.co_freevars` attribute.
 
.. audit-event:: exec code_object exec

___
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-119786: Move garbage collection doc from devguide to InternalDocs (#125282)

2024-10-11 Thread iritkatriel
https://github.com/python/cpython/commit/89515be596a0ca05fd9ab4ddf76c8013dd093545
commit: 89515be596a0ca05fd9ab4ddf76c8013dd093545
branch: main
author: Irit Katriel <[email protected]>
committer: iritkatriel <[email protected]>
date: 2024-10-11T21:18:37+01:00
summary:

gh-119786: Move garbage collection doc from devguide to InternalDocs (#125282)

Co-Authored-By: Carol Willing [email protected]
Co-Authored-By: Ezio Melotti [email protected]
Co-Authored-By: Hugo van Kemenade [email protected]
Co-Authored-By: Itamar Ostricher [email protected]
Co-Authored-By: Jesús Cea [email protected]
Co-Authored-By: Joannah Nanjekye 
[email protected]
Co-Authored-By: Ned Batchelder [email protected]
Co-Authored-By: Pablo Galindo Salgado [email protected]
Co-Authored-By: Pamela Fox [email protected]
Co-Authored-By: Sam Gross [email protected]
Co-Authored-By: Stefan Pochmann [email protected]
Co-Authored-By: T. Wouters [email protected]
Co-Authored-By: q-ata [email protected]
Co-Authored-By: slateny [email protected]
Co-Authored-By: Борис Верховский [email protected]
Co-authored-by: Adam Turner <[email protected]>
Co-authored-by: Jacob Coffee 

files:
A InternalDocs/garbage_collector.md
A InternalDocs/images/python-cyclic-gc-1-new-page.png
A InternalDocs/images/python-cyclic-gc-2-new-page.png
A InternalDocs/images/python-cyclic-gc-3-new-page.png
A InternalDocs/images/python-cyclic-gc-4-new-page.png
A InternalDocs/images/python-cyclic-gc-5-new-page.png
M InternalDocs/README.md

diff --git a/InternalDocs/README.md b/InternalDocs/README.md
index 8956ecafed2039..805e2f97937e1e 100644
--- a/InternalDocs/README.md
+++ b/InternalDocs/README.md
@@ -22,4 +22,6 @@ it is not, please report that through the
 
 [The Source Code Locations Table](locations.md)
 
+[Garbage collector design](garbage_collector.md)
+
 [Exception Handling](exception_handling.md)
diff --git a/InternalDocs/garbage_collector.md 
b/InternalDocs/garbage_collector.md
new file mode 100644
index 00..fd0246fa1a60e2
--- /dev/null
+++ b/InternalDocs/garbage_collector.md
@@ -0,0 +1,596 @@
+
+Garbage collector design
+
+
+Abstract
+
+
+The main garbage collection algorithm used by CPython is reference counting. 
The basic idea is
+that CPython counts how many different places there are that have a reference 
to an
+object. Such a place could be another object, or a global (or static) C 
variable, or
+a local variable in some C function. When an object’s reference count becomes 
zero,
+the object is deallocated. If it contains references to other objects, their
+reference counts are decremented. Those other objects may be deallocated in 
turn, if
+this decrement makes their reference count become zero, and so on. The 
reference
+count field can be examined using the ``sys.getrefcount()`` function (notice 
that the
+value returned by this function is always 1 more as the function also has a 
reference
+to the object when called):
+
+```pycon
+>>> x = object()
+>>> sys.getrefcount(x)
+2
+>>> y = x
+>>> sys.getrefcount(x)
+3
+>>> del y
+>>> sys.getrefcount(x)
+2
+```
+
+The main problem with the reference counting scheme is that it does not handle 
reference
+cycles. For instance, consider this code:
+
+```pycon
+>>> container = []
+>>> container.append(container)
+>>> sys.getrefcount(container)
+3
+>>> del container
+```
+
+In this example, ``container`` holds a reference to itself, so even when we 
remove
+our reference to it (the variable "container") the reference count never falls 
to 0
+because it still has its own internal reference. Therefore it would never be
+cleaned just by simple reference counting. For this reason some additional 
machinery
+is needed to clean these reference cycles between objects once they become
+unreachable. This is the cyclic garbage collector, usually called just Garbage
+Collector (GC), even though reference counting is also a form of garbage 
collection.
+
+Starting in version 3.13, CPython contains two GC implementations:
+
+- The default build implementation relies on the
+  [global interpreter 
lock](https://docs.python.org/3/glossary.html#term-global-interpreter-lock)
+  for thread safety.
+- The free-threaded build implementation pauses other executing threads when
+  performing a collection for thread safety.
+
+Both implementations use the same basic algorithms, but operate on different
+data structures.  The the section on
+[Differences between GC 
implementations](#Differences-between-GC-implementations)
+for the details.
+
+
+Memory layout and object structure
+==
+
+The garbage collector requires additional fields in Python objects to support
+garbage collection.  These extra fi

[Python-checkins] Fix typo in ``Doclibrary/functions.rst`` (#125327)

2024-10-11 Thread Eclips4
https://github.com/python/cpython/commit/76b29d271b3132bf8e13bc724f10be8c630057ba
commit: 76b29d271b3132bf8e13bc724f10be8c630057ba
branch: main
author: Rafael Fontenelle 
committer: Eclips4 
date: 2024-10-11T23:00:31+03:00
summary:

Fix typo in ``Doclibrary/functions.rst`` (#125327)

files:
M Doc/library/functions.rst

diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst
index 7f8df704a33327..0638df04c6ff40 100644
--- a/Doc/library/functions.rst
+++ b/Doc/library/functions.rst
@@ -686,7 +686,7 @@ are always available.  They are listed here in alphabetical 
order.
The *closure* argument specifies a closure--a tuple of cellvars.
It's only valid when the *object* is a code object containing
:term:`free (closure) variables `.
-   The length of the tuple must exactly match the length of the code object'S
+   The length of the tuple must exactly match the length of the code object's
:attr:`~codeobject.co_freevars` attribute.
 
.. audit-event:: exec code_object exec

___
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] Add some doctest cleanups for `configparser` (GH-125288) (#125291)

2024-10-11 Thread AlexWaygood
https://github.com/python/cpython/commit/7c48c630213ada618c7c7b20aa6af88273d75650
commit: 7c48c630213ada618c7c7b20aa6af88273d75650
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: AlexWaygood 
date: 2024-10-11T09:52:15Z
summary:

[3.12] Add some doctest cleanups for `configparser` (GH-125288) (#125291)

Co-authored-by: Alex Waygood 
Co-authored-by: Adam Turner <[email protected]>

files:
M Doc/library/configparser.rst

diff --git a/Doc/library/configparser.rst b/Doc/library/configparser.rst
index 5f04cbc42bf374..4f3549d9a8c0a3 100644
--- a/Doc/library/configparser.rst
+++ b/Doc/library/configparser.rst
@@ -54,6 +54,7 @@ can be customized by end users easily.
 
import os
os.remove("example.ini")
+   os.remove("override.ini")
 
 
 Quick Start

___
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-125235: Keep `_tkinter` TCL paths pointing to base installation on Windows (GH-125250) (#125312)

2024-10-11 Thread vstinner
https://github.com/python/cpython/commit/66b8cb114251c3454857bf35355c9365302f4b69
commit: 66b8cb114251c3454857bf35355c9365302f4b69
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vstinner 
date: 2024-10-11T09:34:04Z
summary:

[3.13] gh-125235: Keep `_tkinter` TCL paths pointing to base installation on 
Windows (GH-125250) (#125312)

gh-125235: Keep `_tkinter` TCL paths pointing to base installation on Windows 
(GH-125250)
(cherry picked from commit b3aa1b5fe260382788a2df416599325ad680a5ee)

Signed-off-by: y5c4l3 
Co-authored-by: Y5 <[email protected]>

files:
A Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
M Modules/_tkinter.c

diff --git 
a/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst 
b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
new file mode 100644
index 00..f64d15917da1fc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2024-10-10-18-33-31.gh-issue-125235.0kOB5I.rst
@@ -0,0 +1,2 @@
+Keep :mod:`tkinter` TCL paths in venv pointing to base installation on
+Windows.
diff --git a/Modules/_tkinter.c b/Modules/_tkinter.c
index cd3722f54c24ce..a2f0cf2b01acc4 100644
--- a/Modules/_tkinter.c
+++ b/Modules/_tkinter.c
@@ -143,7 +143,7 @@ _get_tcl_lib_path(void)
 struct stat stat_buf;
 int stat_return_value;
 
-PyObject *prefix = PySys_GetObject("prefix");  // borrowed reference
+PyObject *prefix = PySys_GetObject("base_prefix");  // borrowed 
reference
 if (prefix == NULL) {
 return NULL;
 }

___
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-124612: Update autoconf container image (#125320)

2024-10-11 Thread corona10
https://github.com/python/cpython/commit/08f6bf717118963815d9a3e60578104470fdf3e1
commit: 08f6bf717118963815d9a3e60578104470fdf3e1
branch: main
author: Donghee Na 
committer: corona10 
date: 2024-10-12T00:27:26+09:00
summary:

gh-124612: Update autoconf container image (#125320)

files:
M Tools/build/regen-configure.sh

diff --git a/Tools/build/regen-configure.sh b/Tools/build/regen-configure.sh
index efc80c8527885c..1a24b07c3ff707 100755
--- a/Tools/build/regen-configure.sh
+++ b/Tools/build/regen-configure.sh
@@ -5,7 +5,7 @@ set -e -x
 # The check_generated_files job of .github/workflows/build.yml must kept in
 # sync with this script. Use the same container image than the job so the job
 # doesn't need to run autoreconf in a container.
-IMAGE="ghcr.io/python/autoconf:2024.10.06.11200919239"
+IMAGE="ghcr.io/python/autoconf:2024.10.11.11293396815"
 AUTORECONF="autoreconf -ivf -Werror"
 
 WORK_DIR="/src"

___
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-116738: Make `_csv` module thread-safe (#118344)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/a00221e5a70e54a281ba0e2cff8d85cd37ae305f
commit: a00221e5a70e54a281ba0e2cff8d85cd37ae305f
branch: main
author: AN Long 
committer: kumaraditya303 
date: 2024-10-11T23:25:36+05:30
summary:

gh-116738: Make `_csv` module thread-safe (#118344)

files:
M Modules/_csv.c

diff --git a/Modules/_csv.c b/Modules/_csv.c
index 913560ce4a0ee3..1a4dc3f1f55ace 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -14,6 +14,7 @@ module instead.
 #endif
 
 #include "Python.h"
+#include "pycore_pyatomic_ft_wrappers.h"
 
 #include// offsetof()
 #include 
@@ -34,7 +35,7 @@ typedef struct {
 PyTypeObject *dialect_type;
 PyTypeObject *reader_type;
 PyTypeObject *writer_type;
-long field_limit;   /* max parsed field size */
+Py_ssize_t field_limit;   /* max parsed field size */
 PyObject *str_write;
 } _csvstate;
 
@@ -706,10 +707,11 @@ parse_grow_buff(ReaderObj *self)
 static int
 parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c)
 {
-if (self->field_len >= module_state->field_limit) {
+Py_ssize_t field_limit = 
FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
+if (self->field_len >= field_limit) {
 PyErr_Format(module_state->error_obj,
- "field larger than field limit (%ld)",
- module_state->field_limit);
+ "field larger than field limit (%zd)",
+ field_limit);
 return -1;
 }
 if (self->field_len == self->field_size && !parse_grow_buff(self))
@@ -1659,20 +1661,20 @@ _csv_field_size_limit_impl(PyObject *module, PyObject 
*new_limit)
 /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/
 {
 _csvstate *module_state = get_csv_state(module);
-long old_limit = module_state->field_limit;
+Py_ssize_t old_limit = 
FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
 if (new_limit != NULL) {
 if (!PyLong_CheckExact(new_limit)) {
 PyErr_Format(PyExc_TypeError,
  "limit must be an integer");
 return NULL;
 }
-module_state->field_limit = PyLong_AsLong(new_limit);
-if (module_state->field_limit == -1 && PyErr_Occurred()) {
-module_state->field_limit = old_limit;
+Py_ssize_t new_limit_value = PyLong_AsSsize_t(new_limit);
+if (new_limit_value == -1 && PyErr_Occurred()) {
 return NULL;
 }
+FT_ATOMIC_STORE_SSIZE_RELAXED(module_state->field_limit, 
new_limit_value);
 }
-return PyLong_FromLong(old_limit);
+return PyLong_FromSsize_t(old_limit);
 }
 
 static PyType_Slot error_slots[] = {

___
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-116738: Make `_csv` module thread-safe (GH-118344) (#125328)

2024-10-11 Thread kumaraditya303
https://github.com/python/cpython/commit/f5895133349ff8e09d06ca75dc2f5719382af44e
commit: f5895133349ff8e09d06ca75dc2f5719382af44e
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: kumaraditya303 
date: 2024-10-11T18:22:56Z
summary:

[3.13] gh-116738: Make `_csv` module thread-safe (GH-118344) (#125328)

gh-116738: Make `_csv` module thread-safe (GH-118344)
(cherry picked from commit a00221e5a70e54a281ba0e2cff8d85cd37ae305f)

Co-authored-by: AN Long 

files:
M Modules/_csv.c

diff --git a/Modules/_csv.c b/Modules/_csv.c
index 8d35d3bcee3584..0d315088c7a55a 100644
--- a/Modules/_csv.c
+++ b/Modules/_csv.c
@@ -14,6 +14,7 @@ module instead.
 #endif
 
 #include "Python.h"
+#include "pycore_pyatomic_ft_wrappers.h"
 
 #include// offsetof()
 #include 
@@ -34,7 +35,7 @@ typedef struct {
 PyTypeObject *dialect_type;
 PyTypeObject *reader_type;
 PyTypeObject *writer_type;
-long field_limit;   /* max parsed field size */
+Py_ssize_t field_limit;   /* max parsed field size */
 PyObject *str_write;
 } _csvstate;
 
@@ -702,10 +703,11 @@ parse_grow_buff(ReaderObj *self)
 static int
 parse_add_char(ReaderObj *self, _csvstate *module_state, Py_UCS4 c)
 {
-if (self->field_len >= module_state->field_limit) {
+Py_ssize_t field_limit = 
FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
+if (self->field_len >= field_limit) {
 PyErr_Format(module_state->error_obj,
- "field larger than field limit (%ld)",
- module_state->field_limit);
+ "field larger than field limit (%zd)",
+ field_limit);
 return -1;
 }
 if (self->field_len == self->field_size && !parse_grow_buff(self))
@@ -1651,20 +1653,20 @@ _csv_field_size_limit_impl(PyObject *module, PyObject 
*new_limit)
 /*[clinic end generated code: output=f2799ecd908e250b input=cec70e9226406435]*/
 {
 _csvstate *module_state = get_csv_state(module);
-long old_limit = module_state->field_limit;
+Py_ssize_t old_limit = 
FT_ATOMIC_LOAD_SSIZE_RELAXED(module_state->field_limit);
 if (new_limit != NULL) {
 if (!PyLong_CheckExact(new_limit)) {
 PyErr_Format(PyExc_TypeError,
  "limit must be an integer");
 return NULL;
 }
-module_state->field_limit = PyLong_AsLong(new_limit);
-if (module_state->field_limit == -1 && PyErr_Occurred()) {
-module_state->field_limit = old_limit;
+Py_ssize_t new_limit_value = PyLong_AsSsize_t(new_limit);
+if (new_limit_value == -1 && PyErr_Occurred()) {
 return NULL;
 }
+FT_ATOMIC_STORE_SSIZE_RELAXED(module_state->field_limit, 
new_limit_value);
 }
-return PyLong_FromLong(old_limit);
+return PyLong_FromSsize_t(old_limit);
 }
 
 static PyType_Slot error_slots[] = {

___
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-124309: fix staggered race on eager tasks (GH-124847) (#125340)

2024-10-11 Thread 1st1
https://github.com/python/cpython/commit/ac7ddac68d01ab8d63872770a44e96c46c44
commit: ac7ddac68d01ab8d63872770a44e96c46c44
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: 1st1 
date: 2024-10-11T20:12:11-07:00
summary:

[3.12] gh-124309: fix staggered race on eager tasks (GH-124847) (#125340)

gh-124309: fix staggered race on eager tasks (GH-124847)

This patch is entirely by Thomas and Peter

(cherry picked from commit 979c0df7c0adfb744159a5fc184043dc733d8534)

Co-authored-by: Thomas Grainger 
Co-authored-by: Peter Bierma 

files:
A Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst
M Lib/asyncio/staggered.py
M Lib/test/test_asyncio/test_eager_task_factory.py
M Lib/test/test_asyncio/test_staggered.py

diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py
index c3a7441a7b091d..7aafcea4d885eb 100644
--- a/Lib/asyncio/staggered.py
+++ b/Lib/asyncio/staggered.py
@@ -69,7 +69,11 @@ async def staggered_race(coro_fns, delay, *, loop=None):
 exceptions = []
 running_tasks = []
 
-async def run_one_coro(previous_failed) -> None:
+async def run_one_coro(ok_to_start, previous_failed) -> None:
+# in eager tasks this waits for the calling task to append this task
+# to running_tasks, in regular tasks this wait is a no-op that does
+# not yield a future. See gh-124309.
+await ok_to_start.wait()
 # Wait for the previous task to finish, or for delay seconds
 if previous_failed is not None:
 with contextlib.suppress(exceptions_mod.TimeoutError):
@@ -85,8 +89,12 @@ async def run_one_coro(previous_failed) -> None:
 return
 # Start task that will run the next coroutine
 this_failed = locks.Event()
-next_task = loop.create_task(run_one_coro(this_failed))
+next_ok_to_start = locks.Event()
+next_task = loop.create_task(run_one_coro(next_ok_to_start, 
this_failed))
 running_tasks.append(next_task)
+# next_task has been appended to running_tasks so next_task is ok to
+# start.
+next_ok_to_start.set()
 assert len(running_tasks) == this_index + 2
 # Prepare place to put this coroutine's exceptions if not won
 exceptions.append(None)
@@ -116,8 +124,11 @@ async def run_one_coro(previous_failed) -> None:
 if i != this_index:
 t.cancel()
 
-first_task = loop.create_task(run_one_coro(None))
+ok_to_start = locks.Event()
+first_task = loop.create_task(run_one_coro(ok_to_start, None))
 running_tasks.append(first_task)
+# first_task has been appended to running_tasks so first_task is ok to 
start.
+ok_to_start.set()
 try:
 # Wait for a growing list of tasks to all finish: poor man's version of
 # curio's TaskGroup or trio's nursery
diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py 
b/Lib/test/test_asyncio/test_eager_task_factory.py
index 58c06287bc3c5d..b06832e02f00d6 100644
--- a/Lib/test/test_asyncio/test_eager_task_factory.py
+++ b/Lib/test/test_asyncio/test_eager_task_factory.py
@@ -218,6 +218,52 @@ async def run():
 
 self.run_coro(run())
 
+def test_staggered_race_with_eager_tasks(self):
+# See https://github.com/python/cpython/issues/124309
+
+async def fail():
+await asyncio.sleep(0)
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: asyncio.sleep(2, result="sleep2"),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: fail()
+],
+delay=0.25
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], asyncio.CancelledError)
+self.assertIsInstance(excs[2], ValueError)
+
+self.run_coro(run())
+
+def test_staggered_race_with_eager_tasks_no_delay(self):
+# See https://github.com/python/cpython/issues/124309
+async def fail():
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: fail(),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: asyncio.sleep(0, result="sleep0"),
+],
+delay=None
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], ValueError)
+self.assertEqual(len(excs), 2)
+
+self.run_coro(run())
+
 
 class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, 
test_utils.TestCase):

[Python-checkins] [3.13] gh-124309: fix staggered race on eager tasks (GH-124847) (#125339)

2024-10-11 Thread 1st1
https://github.com/python/cpython/commit/b4c504d76ff3aa42943854571fa7610db5407e80
commit: b4c504d76ff3aa42943854571fa7610db5407e80
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: 1st1 
date: 2024-10-11T20:11:53-07:00
summary:

[3.13] gh-124309: fix staggered race on eager tasks (GH-124847) (#125339)

Co-authored-by: Thomas Grainger 
Co-authored-by: Peter Bierma 

files:
A Misc/NEWS.d/next/Library/2024-10-01-13-46-58.gh-issue-124390.dK1Zcm.rst
M Lib/asyncio/staggered.py
M Lib/test/test_asyncio/test_eager_task_factory.py
M Lib/test/test_asyncio/test_staggered.py

diff --git a/Lib/asyncio/staggered.py b/Lib/asyncio/staggered.py
index c3a7441a7b091d..7aafcea4d885eb 100644
--- a/Lib/asyncio/staggered.py
+++ b/Lib/asyncio/staggered.py
@@ -69,7 +69,11 @@ async def staggered_race(coro_fns, delay, *, loop=None):
 exceptions = []
 running_tasks = []
 
-async def run_one_coro(previous_failed) -> None:
+async def run_one_coro(ok_to_start, previous_failed) -> None:
+# in eager tasks this waits for the calling task to append this task
+# to running_tasks, in regular tasks this wait is a no-op that does
+# not yield a future. See gh-124309.
+await ok_to_start.wait()
 # Wait for the previous task to finish, or for delay seconds
 if previous_failed is not None:
 with contextlib.suppress(exceptions_mod.TimeoutError):
@@ -85,8 +89,12 @@ async def run_one_coro(previous_failed) -> None:
 return
 # Start task that will run the next coroutine
 this_failed = locks.Event()
-next_task = loop.create_task(run_one_coro(this_failed))
+next_ok_to_start = locks.Event()
+next_task = loop.create_task(run_one_coro(next_ok_to_start, 
this_failed))
 running_tasks.append(next_task)
+# next_task has been appended to running_tasks so next_task is ok to
+# start.
+next_ok_to_start.set()
 assert len(running_tasks) == this_index + 2
 # Prepare place to put this coroutine's exceptions if not won
 exceptions.append(None)
@@ -116,8 +124,11 @@ async def run_one_coro(previous_failed) -> None:
 if i != this_index:
 t.cancel()
 
-first_task = loop.create_task(run_one_coro(None))
+ok_to_start = locks.Event()
+first_task = loop.create_task(run_one_coro(ok_to_start, None))
 running_tasks.append(first_task)
+# first_task has been appended to running_tasks so first_task is ok to 
start.
+ok_to_start.set()
 try:
 # Wait for a growing list of tasks to all finish: poor man's version of
 # curio's TaskGroup or trio's nursery
diff --git a/Lib/test/test_asyncio/test_eager_task_factory.py 
b/Lib/test/test_asyncio/test_eager_task_factory.py
index 0777f39b572486..31d2a00dbb8c9c 100644
--- a/Lib/test/test_asyncio/test_eager_task_factory.py
+++ b/Lib/test/test_asyncio/test_eager_task_factory.py
@@ -213,6 +213,52 @@ async def run():
 
 self.run_coro(run())
 
+def test_staggered_race_with_eager_tasks(self):
+# See https://github.com/python/cpython/issues/124309
+
+async def fail():
+await asyncio.sleep(0)
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: asyncio.sleep(2, result="sleep2"),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: fail()
+],
+delay=0.25
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], asyncio.CancelledError)
+self.assertIsInstance(excs[2], ValueError)
+
+self.run_coro(run())
+
+def test_staggered_race_with_eager_tasks_no_delay(self):
+# See https://github.com/python/cpython/issues/124309
+async def fail():
+raise ValueError("no good")
+
+async def run():
+winner, index, excs = await asyncio.staggered.staggered_race(
+[
+lambda: fail(),
+lambda: asyncio.sleep(1, result="sleep1"),
+lambda: asyncio.sleep(0, result="sleep0"),
+],
+delay=None
+)
+self.assertEqual(winner, 'sleep1')
+self.assertEqual(index, 1)
+self.assertIsNone(excs[index])
+self.assertIsInstance(excs[0], ValueError)
+self.assertEqual(len(excs), 2)
+
+self.run_coro(run())
+
 
 class PyEagerTaskFactoryLoopTests(EagerTaskFactoryLoopTests, 
test_utils.TestCase):
 Task = tasks._PyTask
diff --git a/Lib/test/test_asyncio/test_staggered.py 
b/Lib/test/test_asyncio/test_staggered.py
index e6e32f7dbbbcba..74941f704c4890 100644
--- a/

[Python-checkins] [3.12] gh-125301: Backport some test support helpers (is_apple_mobile, is_apple) (GH-125311)

2024-10-11 Thread serhiy-storchaka
https://github.com/python/cpython/commit/59036318bfeae049fe13e16b7169caa0e2c00fcd
commit: 59036318bfeae049fe13e16b7169caa0e2c00fcd
branch: 3.12
author: Serhiy Storchaka 
committer: serhiy-storchaka 
date: 2024-10-11T14:22:27+03:00
summary:

[3.12] gh-125301: Backport some test support helpers (is_apple_mobile, 
is_apple) (GH-125311)

(cherry picked from commit 391659b3da570bfa28fed5fbdb6f2d9c26ab3dd0)

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

diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 9c3dcbc1d2bc29..5432b1ec5c9d84 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -43,7 +43,7 @@
 "requires_limited_api", "requires_specialization",
 # sys
 "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi",
-"check_impl_detail", "unix_shell", "setswitchinterval",
+"is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval",
 # os
 "get_pagesize",
 # network
@@ -531,7 +531,7 @@ def requires_legacy_unicode_capi():
 
 is_android = hasattr(sys, 'getandroidapilevel')
 
-if sys.platform not in ('win32', 'vxworks'):
+if sys.platform not in {"win32", "vxworks", "ios", "tvos", "watchos"}:
 unix_shell = '/system/bin/sh' if is_android else '/bin/sh'
 else:
 unix_shell = None
@@ -541,19 +541,35 @@ def requires_legacy_unicode_capi():
 is_emscripten = sys.platform == "emscripten"
 is_wasi = sys.platform == "wasi"
 
-has_fork_support = hasattr(os, "fork") and not is_emscripten and not is_wasi
+# Apple mobile platforms (iOS/tvOS/watchOS) are POSIX-like but do not
+# have subprocess or fork support.
+is_apple_mobile = sys.platform in {"ios", "tvos", "watchos"}
+is_apple = is_apple_mobile or sys.platform == "darwin"
+
+has_fork_support = hasattr(os, "fork") and not (
+is_emscripten
+or is_wasi
+or is_apple_mobile
+)
 
 def requires_fork():
 return unittest.skipUnless(has_fork_support, "requires working os.fork()")
 
-has_subprocess_support = not is_emscripten and not is_wasi
+has_subprocess_support = not (
+is_emscripten
+or is_wasi
+or is_apple_mobile
+)
 
 def requires_subprocess():
 """Used for subprocess, os.spawn calls, fd inheritance"""
 return unittest.skipUnless(has_subprocess_support, "requires subprocess 
support")
 
 # Emscripten's socket emulation and WASI sockets have limitations.
-has_socket_support = not is_emscripten and not is_wasi
+has_socket_support = not (
+is_emscripten
+or is_wasi
+)
 
 def requires_working_socket(*, module=False):
 """Skip tests or modules that require working sockets

___
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]