[Python-checkins] gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (#121843)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/f6c7d8d79c4e17167af98f2e0cb4b1e55d7b5d3c
commit: f6c7d8d79c4e17167af98f2e0cb4b1e55d7b5d3c
branch: main
author: sobolevn 
committer: sobolevn 
date: 2024-07-17T10:00:07+03:00
summary:

gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (#121843)

files:
M Lib/test/test_capi/test_bytes.py

diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py
index f14d5545c829e5..d5f047bcf18277 100644
--- a/Lib/test/test_capi/test_bytes.py
+++ b/Lib/test/test_capi/test_bytes.py
@@ -53,6 +53,8 @@ def test_fromstringandsize(self):
 self.assertEqual(fromstringandsize(b'abc'), b'abc')
 self.assertEqual(fromstringandsize(b'abc', 2), b'ab')
 self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def')
+self.assertEqual(fromstringandsize(b'a'), b'a')
+self.assertEqual(fromstringandsize(b'a', 1), b'a')
 self.assertEqual(fromstringandsize(b'', 0), b'')
 self.assertEqual(fromstringandsize(NULL, 0), b'')
 self.assertEqual(len(fromstringandsize(NULL, 3)), 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] gh-121834: Improve `complex` C-API docs (#121835)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/72dccd60735b597e99c007a7b69210763a746877
commit: 72dccd60735b597e99c007a7b69210763a746877
branch: main
author: sobolevn 
committer: sobolevn 
date: 2024-07-17T10:01:28+03:00
summary:

gh-121834: Improve `complex` C-API docs (#121835)

Co-authored-by: Sergey B Kirpichev 
Co-authored-by: Petr Viktorin 

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

diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index 5a0474869071d9..67d0c5f144e075 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -25,12 +25,16 @@ pointers.  This is consistent throughout the API.
 
The C structure which corresponds to the value portion of a Python complex
number object.  Most of the functions for dealing with complex number 
objects
-   use structures of this type as input or output values, as appropriate.  It 
is
-   defined as::
+   use structures of this type as input or output values, as appropriate.
+
+   .. c:member:: double real
+ double imag
+
+   The structure is defined as::
 
   typedef struct {
- double real;
- double imag;
+  double real;
+  double imag;
   } Py_complex;
 
 
@@ -106,11 +110,13 @@ Complex Numbers as Python Objects
 .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
 
Create a new Python complex number object from a C :c:type:`Py_complex` 
value.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag)
 
Return a new :c:type:`PyComplexObject` object from *real* and *imag*.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: double PyComplex_RealAsDouble(PyObject *op)
@@ -121,7 +127,9 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object.  If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
-   returns its result.  Upon failure, this method returns ``-1.0``, so one
+   returns its result.
+
+   Upon failure, this method returns ``-1.0`` with an exception set, so one
should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.13
@@ -135,8 +143,10 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object.  If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
-   returns ``0.0`` on success.  Upon failure, this method returns ``-1.0``, so
-   one should call :c:func:`PyErr_Occurred` to check for errors.
+   returns ``0.0`` on success.
+
+   Upon failure, this method returns ``-1.0`` with an exception set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.13
   Use :meth:`~object.__complex__` if available.
@@ -149,8 +159,11 @@ Complex Numbers as Python Objects
method, this method will first be called to convert *op* to a Python complex
number object.  If :meth:`!__complex__` is not defined then it falls back to
:meth:`~object.__float__`.  If :meth:`!__float__` is not defined then it 
falls back
-   to :meth:`~object.__index__`.  Upon failure, this method returns ``-1.0`` 
as a real
-   value.
+   to :meth:`~object.__index__`.
+
+   Upon failure, this method returns :c:type:`Py_complex`
+   with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception 
set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.8
   Use :meth:`~object.__index__` if available.

___
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-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843) (#121894)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/6e0ba93dfa625fa329a9361062de8efc1a12c990
commit: 6e0ba93dfa625fa329a9361062de8efc1a12c990
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: sobolevn 
date: 2024-07-17T07:16:25Z
summary:

[3.12] gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843) 
(#121894)

gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843)
(cherry picked from commit f6c7d8d79c4e17167af98f2e0cb4b1e55d7b5d3c)

Co-authored-by: sobolevn 

files:
M Lib/test/test_capi/test_bytes.py

diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py
index bb5d724ff187d4..c692ee82d04283 100644
--- a/Lib/test/test_capi/test_bytes.py
+++ b/Lib/test/test_capi/test_bytes.py
@@ -52,6 +52,8 @@ def test_fromstringandsize(self):
 self.assertEqual(fromstringandsize(b'abc'), b'abc')
 self.assertEqual(fromstringandsize(b'abc', 2), b'ab')
 self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def')
+self.assertEqual(fromstringandsize(b'a'), b'a')
+self.assertEqual(fromstringandsize(b'a', 1), b'a')
 self.assertEqual(fromstringandsize(b'', 0), b'')
 self.assertEqual(fromstringandsize(NULL, 0), b'')
 self.assertEqual(len(fromstringandsize(NULL, 3)), 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] Fix Several Typos in Readme & Tests (#121559)

2024-07-17 Thread rhettinger
https://github.com/python/cpython/commit/dc9cc91f76fbbaa09a3bb40d0cbb6f9a2381e269
commit: dc9cc91f76fbbaa09a3bb40d0cbb6f9a2381e269
branch: main
author: Michael <[email protected]>
committer: rhettinger 
date: 2024-07-17T00:24:35-07:00
summary:

Fix Several Typos in Readme & Tests (#121559)

files:
M Lib/test/test_itertools.py
M Lib/test/test_shutil.py

diff --git a/Lib/test/test_itertools.py b/Lib/test/test_itertools.py
index 5fd6ecf37427f7..052dcace4efdc7 100644
--- a/Lib/test/test_itertools.py
+++ b/Lib/test/test_itertools.py
@@ -1278,7 +1278,7 @@ def test_tee(self):
 t3 = tnew(t1)
 self.assertTrue(list(t1) == list(t2) == list(t3) == list('abc'))
 
-# test that tee objects are weak referencable
+# test that tee objects are weak referenceable
 a, b = tee(range(10))
 p = weakref.proxy(a)
 self.assertEqual(getattr(p, '__class__'), type(b))
diff --git a/Lib/test/test_shutil.py b/Lib/test/test_shutil.py
index 02ef172613bf94..c458c5df32572b 100644
--- a/Lib/test/test_shutil.py
+++ b/Lib/test/test_shutil.py
@@ -905,10 +905,10 @@ def test_copytree_arg_types_of_ignore(self):
 os.mkdir(os.path.join(src_dir, 'test_dir', 'subdir'))
 write_file((src_dir, 'test_dir', 'subdir', 'test.txt'), '456')
 
-invokations = []
+invocations = []
 
 def _ignore(src, names):
-invokations.append(src)
+invocations.append(src)
 self.assertIsInstance(src, str)
 self.assertIsInstance(names, list)
 self.assertEqual(len(names), len(set(names)))
@@ -933,7 +933,7 @@ def _ignore(src, names):
 self.assertTrue(exists(join(dst_dir, 'test_dir', 'subdir',
 'test.txt')))
 
-self.assertEqual(len(invokations), 9)
+self.assertEqual(len(invocations), 9)
 
 def test_copytree_retains_permissions(self):
 tmp_dir = self.mkdtemp()

___
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-121834: Improve `complex` C-API docs (GH-121835) (#121895)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/bcf1c7004d6254e220dce431d0b49be04003587d
commit: bcf1c7004d6254e220dce431d0b49be04003587d
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: sobolevn 
date: 2024-07-17T07:25:07Z
summary:

[3.13] gh-121834: Improve `complex` C-API docs (GH-121835) (#121895)

gh-121834: Improve `complex` C-API docs (GH-121835)
(cherry picked from commit 72dccd60735b597e99c007a7b69210763a746877)

Co-authored-by: sobolevn 
Co-authored-by: Sergey B Kirpichev 
Co-authored-by: Petr Viktorin 

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

diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index 5a0474869071d9..67d0c5f144e075 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -25,12 +25,16 @@ pointers.  This is consistent throughout the API.
 
The C structure which corresponds to the value portion of a Python complex
number object.  Most of the functions for dealing with complex number 
objects
-   use structures of this type as input or output values, as appropriate.  It 
is
-   defined as::
+   use structures of this type as input or output values, as appropriate.
+
+   .. c:member:: double real
+ double imag
+
+   The structure is defined as::
 
   typedef struct {
- double real;
- double imag;
+  double real;
+  double imag;
   } Py_complex;
 
 
@@ -106,11 +110,13 @@ Complex Numbers as Python Objects
 .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
 
Create a new Python complex number object from a C :c:type:`Py_complex` 
value.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag)
 
Return a new :c:type:`PyComplexObject` object from *real* and *imag*.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: double PyComplex_RealAsDouble(PyObject *op)
@@ -121,7 +127,9 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object.  If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
-   returns its result.  Upon failure, this method returns ``-1.0``, so one
+   returns its result.
+
+   Upon failure, this method returns ``-1.0`` with an exception set, so one
should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.13
@@ -135,8 +143,10 @@ Complex Numbers as Python Objects
:meth:`~object.__complex__` method, this method will first be called to
convert *op* to a Python complex number object.  If :meth:`!__complex__` is
not defined then it falls back to call :c:func:`PyFloat_AsDouble` and
-   returns ``0.0`` on success.  Upon failure, this method returns ``-1.0``, so
-   one should call :c:func:`PyErr_Occurred` to check for errors.
+   returns ``0.0`` on success.
+
+   Upon failure, this method returns ``-1.0`` with an exception set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.13
   Use :meth:`~object.__complex__` if available.
@@ -149,8 +159,11 @@ Complex Numbers as Python Objects
method, this method will first be called to convert *op* to a Python complex
number object.  If :meth:`!__complex__` is not defined then it falls back to
:meth:`~object.__float__`.  If :meth:`!__float__` is not defined then it 
falls back
-   to :meth:`~object.__index__`.  Upon failure, this method returns ``-1.0`` 
as a real
-   value.
+   to :meth:`~object.__index__`.
+
+   Upon failure, this method returns :c:type:`Py_complex`
+   with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception 
set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.8
   Use :meth:`~object.__index__` if available.

___
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-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843) (#121893)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/96c524cef641d53f887321488b29d12c0ac21ac7
commit: 96c524cef641d53f887321488b29d12c0ac21ac7
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: sobolevn 
date: 2024-07-17T07:24:44Z
summary:

[3.13] gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843) 
(#121893)

gh-121842: Improve coverage of `PyBytes_FromStringAndSize` (GH-121843)
(cherry picked from commit f6c7d8d79c4e17167af98f2e0cb4b1e55d7b5d3c)

Co-authored-by: sobolevn 

files:
M Lib/test/test_capi/test_bytes.py

diff --git a/Lib/test/test_capi/test_bytes.py b/Lib/test/test_capi/test_bytes.py
index f14d5545c829e5..d5f047bcf18277 100644
--- a/Lib/test/test_capi/test_bytes.py
+++ b/Lib/test/test_capi/test_bytes.py
@@ -53,6 +53,8 @@ def test_fromstringandsize(self):
 self.assertEqual(fromstringandsize(b'abc'), b'abc')
 self.assertEqual(fromstringandsize(b'abc', 2), b'ab')
 self.assertEqual(fromstringandsize(b'abc\0def'), b'abc\0def')
+self.assertEqual(fromstringandsize(b'a'), b'a')
+self.assertEqual(fromstringandsize(b'a', 1), b'a')
 self.assertEqual(fromstringandsize(b'', 0), b'')
 self.assertEqual(fromstringandsize(NULL, 0), b'')
 self.assertEqual(len(fromstringandsize(NULL, 3)), 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-121834: Improve `complex` C-API docs (GH-121835) (#121897)

2024-07-17 Thread sobolevn
https://github.com/python/cpython/commit/6a19d22a190be2a2ccdde3a273bc319b6acdf1f2
commit: 6a19d22a190be2a2ccdde3a273bc319b6acdf1f2
branch: 3.12
author: sobolevn 
committer: sobolevn 
date: 2024-07-17T07:30:18Z
summary:

[3.12] gh-121834: Improve `complex` C-API docs (GH-121835) (#121897)

* [3.12] gh-121834: Improve `complex` C-API docs (GH-121835)
(cherry picked from commit 72dccd60735b597e99c007a7b69210763a746877)

Co-authored-by: sobolevn 
Co-authored-by: Sergey B Kirpichev 
Co-authored-by: Petr Viktorin 

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

diff --git a/Doc/c-api/complex.rst b/Doc/c-api/complex.rst
index e3fd001c599c80..77cb67d8de2b4c 100644
--- a/Doc/c-api/complex.rst
+++ b/Doc/c-api/complex.rst
@@ -25,12 +25,16 @@ pointers.  This is consistent throughout the API.
 
The C structure which corresponds to the value portion of a Python complex
number object.  Most of the functions for dealing with complex number 
objects
-   use structures of this type as input or output values, as appropriate.  It 
is
-   defined as::
+   use structures of this type as input or output values, as appropriate.
+
+   .. c:member:: double real
+ double imag
+
+   The structure is defined as::
 
   typedef struct {
- double real;
- double imag;
+  double real;
+  double imag;
   } Py_complex;
 
 
@@ -106,17 +110,22 @@ Complex Numbers as Python Objects
 .. c:function:: PyObject* PyComplex_FromCComplex(Py_complex v)
 
Create a new Python complex number object from a C :c:type:`Py_complex` 
value.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: PyObject* PyComplex_FromDoubles(double real, double imag)
 
Return a new :c:type:`PyComplexObject` object from *real* and *imag*.
+   Return ``NULL`` with an exception set on error.
 
 
 .. c:function:: double PyComplex_RealAsDouble(PyObject *op)
 
Return the real part of *op* as a C :c:expr:`double`.
 
+   Upon failure, this method returns ``-1.0`` with an exception set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
+
 
 .. c:function:: double PyComplex_ImagAsDouble(PyObject *op)
 
@@ -131,8 +140,11 @@ Complex Numbers as Python Objects
method, this method will first be called to convert *op* to a Python complex
number object.  If :meth:`!__complex__` is not defined then it falls back to
:meth:`~object.__float__`.  If :meth:`!__float__` is not defined then it 
falls back
-   to :meth:`~object.__index__`.  Upon failure, this method returns ``-1.0`` 
as a real
-   value.
+   to :meth:`~object.__index__`.
+
+   Upon failure, this method returns :c:type:`Py_complex`
+   with :c:member:`~Py_complex.real` set to ``-1.0`` and with an exception 
set, so one
+   should call :c:func:`PyErr_Occurred` to check for errors.
 
.. versionchanged:: 3.8
   Use :meth:`~object.__index__` if available.

___
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] Remove duplicate "it" in whatsnew 3.13 (#121580)

2024-07-17 Thread rhettinger
https://github.com/python/cpython/commit/5d98a4d266fef754455baf8e65a20dd140ebecd3
commit: 5d98a4d266fef754455baf8e65a20dd140ebecd3
branch: main
author: Rafael Fontenelle 
committer: rhettinger 
date: 2024-07-17T00:31:21-07:00
summary:

Remove duplicate "it" in whatsnew 3.13 (#121580)

files:
M Doc/whatsnew/3.13.rst

diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index ca0d91d6f65416..58bad9208116d2 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -1941,7 +1941,7 @@ although there is currently no date scheduled for their 
removal.
 
 * :mod:`xml.etree.ElementTree`: Testing the truth value of an
   :class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it
-  it will always return ``True``. Prefer explicit ``len(elem)`` or
+  will always return ``True``. Prefer explicit ``len(elem)`` or
   ``elem is not None`` tests instead.
 
 * :meth:`zipimport.zipimporter.load_module` is deprecated:

___
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] Remove duplicate "it" in whatsnew 3.13 (GH-121580) (gh-121899)

2024-07-17 Thread rhettinger
https://github.com/python/cpython/commit/d358f74a695b41b2b494b82df7ce3fd719dfac9c
commit: d358f74a695b41b2b494b82df7ce3fd719dfac9c
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: rhettinger 
date: 2024-07-17T07:52:22Z
summary:

[3.13] Remove duplicate "it" in whatsnew 3.13 (GH-121580) (gh-121899)

files:
M Doc/whatsnew/3.13.rst

diff --git a/Doc/whatsnew/3.13.rst b/Doc/whatsnew/3.13.rst
index e91a9348a1a4ee..9e46ddabf043a3 100644
--- a/Doc/whatsnew/3.13.rst
+++ b/Doc/whatsnew/3.13.rst
@@ -1929,7 +1929,7 @@ although there is currently no date scheduled for their 
removal.
 
 * :mod:`xml.etree.ElementTree`: Testing the truth value of an
   :class:`~xml.etree.ElementTree.Element` is deprecated. In a future release it
-  it will always return ``True``. Prefer explicit ``len(elem)`` or
+  will always return ``True``. Prefer explicit ``len(elem)`` or
   ``elem is not None`` tests instead.
 
 * :meth:`zipimport.zipimporter.load_module` is deprecated:

___
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-121153: Fix some errors with use of _PyLong_CompactValue() (GH-121154)

2024-07-17 Thread serhiy-storchaka
https://github.com/python/cpython/commit/874eed6cfe165df6469bf806cd3f1eb08e432286
commit: 874eed6cfe165df6469bf806cd3f1eb08e432286
branch: 3.12
author: Serhiy Storchaka 
committer: serhiy-storchaka 
date: 2024-07-17T07:58:25Z
summary:

[3.12] gh-121153: Fix some errors with use of _PyLong_CompactValue() (GH-121154)

* The result has type Py_ssize_t, not intptr_t.
* Type cast between unsigned and signed integer types should be explicit.
* Downcasting should be explicit.
* Fix integer overflow check in sum().
(cherry picked from commit 1801545)

files:
M Objects/longobject.c
M Python/bltinmodule.c

diff --git a/Objects/longobject.c b/Objects/longobject.c
index c72e1643c9f41d..83699e065fb74a 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -484,11 +484,18 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
 do_decref = 1;
 }
 if (_PyLong_IsCompact(v)) {
-#if SIZEOF_LONG < SIZEOF_VOID_P
-intptr_t tmp = _PyLong_CompactValue(v);
-res = (long)tmp;
-if (res != tmp) {
-*overflow = tmp < 0 ? -1 : 1;
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+Py_ssize_t tmp = _PyLong_CompactValue(v);
+if (tmp < LONG_MIN) {
+*overflow = -1;
+res = -1;
+}
+else if (tmp > LONG_MAX) {
+*overflow = 1;
+res = -1;
+}
+else {
+res = (long)tmp;
 }
 #else
 res = _PyLong_CompactValue(v);
@@ -633,14 +640,15 @@ PyLong_AsUnsignedLong(PyObject *vv)
 
 v = (PyLongObject *)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
-#if SIZEOF_LONG < SIZEOF_VOID_P
-intptr_t tmp = _PyLong_CompactValue(v);
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+size_t tmp = (size_t)_PyLong_CompactValue(v);
 unsigned long res = (unsigned long)tmp;
 if (res != tmp) {
 goto overflow;
 }
+return res;
 #else
-return _PyLong_CompactValue(v);
+return (unsigned long)(size_t)_PyLong_CompactValue(v);
 #endif
 }
 if (_PyLong_IsNegative(v)) {
@@ -686,7 +694,7 @@ PyLong_AsSize_t(PyObject *vv)
 
 v = (PyLongObject *)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
-return _PyLong_CompactValue(v);
+return (size_t)_PyLong_CompactValue(v);
 }
 if (_PyLong_IsNegative(v)) {
 PyErr_SetString(PyExc_OverflowError,
@@ -723,7 +731,11 @@ _PyLong_AsUnsignedLongMask(PyObject *vv)
 }
 v = (PyLongObject *)vv;
 if (_PyLong_IsCompact(v)) {
-return (unsigned long)_PyLong_CompactValue(v);
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+return (unsigned long)(size_t)_PyLong_CompactValue(v);
+#else
+return (unsigned long)(long)_PyLong_CompactValue(v);
+#endif
 }
 i = _PyLong_DigitCount(v);
 int sign = _PyLong_NonCompactSign(v);
@@ -1267,7 +1279,18 @@ PyLong_AsUnsignedLongLong(PyObject *vv)
 v = (PyLongObject*)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
 res = 0;
-bytes = _PyLong_CompactValue(v);
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+size_t tmp = (size_t)_PyLong_CompactValue(v);
+bytes = (unsigned long long)tmp;
+if (bytes != tmp) {
+PyErr_SetString(PyExc_OverflowError,
+"Python int too large to convert "
+"to C unsigned long long");
+res = -1;
+}
+#else
+bytes = (unsigned long long)(size_t)_PyLong_CompactValue(v);
+#endif
 }
 else {
 res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
@@ -1298,7 +1321,11 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv)
 }
 v = (PyLongObject *)vv;
 if (_PyLong_IsCompact(v)) {
-return (unsigned long long)(signed long long)_PyLong_CompactValue(v);
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+return (unsigned long long)(size_t)_PyLong_CompactValue(v);
+#else
+return (unsigned long long)(long long)_PyLong_CompactValue(v);
+#endif
 }
 i = _PyLong_DigitCount(v);
 sign = _PyLong_NonCompactSign(v);
@@ -1370,7 +1397,22 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
 do_decref = 1;
 }
 if (_PyLong_IsCompact(v)) {
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+Py_ssize_t tmp = _PyLong_CompactValue(v);
+if (tmp < LLONG_MIN) {
+*overflow = -1;
+res = -1;
+}
+else if (tmp > LLONG_MAX) {
+*overflow = 1;
+res = -1;
+}
+else {
+res = (long long)tmp;
+}
+#else
 res = _PyLong_CompactValue(v);
+#endif
 }
 else {
 i = _PyLong_DigitCount(v);
@@ -3308,7 +3350,7 @@ long_hash(PyLongObject *v)
 int sign;
 
 if (_PyLong_IsCompact(v)) {
-x = _PyLong_CompactValue(v);
+x = (Py_uhash_t)_PyLong_CompactValue(v);
 if (x == (Py_uhash_t)-1) {
 x = (Py_uhash_t)-2;
 }
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 84fbc33a48ca61..1a65ddd0154bd0 

[Python-checkins] [3.13] gh-121153: Fix some errors with use of _PyLong_CompactValue() (GH-121154) (GH-121900)

2024-07-17 Thread serhiy-storchaka
https://github.com/python/cpython/commit/09ff4ec14f4285aca1ddf907274e2bb3a1fbb6a1
commit: 09ff4ec14f4285aca1ddf907274e2bb3a1fbb6a1
branch: 3.13
author: Serhiy Storchaka 
committer: serhiy-storchaka 
date: 2024-07-17T08:04:45Z
summary:

[3.13] gh-121153: Fix some errors with use of _PyLong_CompactValue() 
(GH-121154) (GH-121900)

* The result has type Py_ssize_t, not intptr_t.
* Type cast between unsigned and signed integer types should be explicit.
* Downcasting should be explicit.
* Fix integer overflow check in sum().
(cherry picked from commit 1801545)

files:
M Objects/longobject.c
M Python/bltinmodule.c

diff --git a/Objects/longobject.c b/Objects/longobject.c
index d4c11e9c27e6f5..b2a3a38c565545 100644
--- a/Objects/longobject.c
+++ b/Objects/longobject.c
@@ -483,11 +483,18 @@ PyLong_AsLongAndOverflow(PyObject *vv, int *overflow)
 do_decref = 1;
 }
 if (_PyLong_IsCompact(v)) {
-#if SIZEOF_LONG < SIZEOF_VOID_P
-intptr_t tmp = _PyLong_CompactValue(v);
-res = (long)tmp;
-if (res != tmp) {
-*overflow = tmp < 0 ? -1 : 1;
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+Py_ssize_t tmp = _PyLong_CompactValue(v);
+if (tmp < LONG_MIN) {
+*overflow = -1;
+res = -1;
+}
+else if (tmp > LONG_MAX) {
+*overflow = 1;
+res = -1;
+}
+else {
+res = (long)tmp;
 }
 #else
 res = _PyLong_CompactValue(v);
@@ -632,14 +639,15 @@ PyLong_AsUnsignedLong(PyObject *vv)
 
 v = (PyLongObject *)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
-#if SIZEOF_LONG < SIZEOF_VOID_P
-intptr_t tmp = _PyLong_CompactValue(v);
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+size_t tmp = (size_t)_PyLong_CompactValue(v);
 unsigned long res = (unsigned long)tmp;
 if (res != tmp) {
 goto overflow;
 }
+return res;
 #else
-return _PyLong_CompactValue(v);
+return (unsigned long)(size_t)_PyLong_CompactValue(v);
 #endif
 }
 if (_PyLong_IsNegative(v)) {
@@ -685,7 +693,7 @@ PyLong_AsSize_t(PyObject *vv)
 
 v = (PyLongObject *)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
-return _PyLong_CompactValue(v);
+return (size_t)_PyLong_CompactValue(v);
 }
 if (_PyLong_IsNegative(v)) {
 PyErr_SetString(PyExc_OverflowError,
@@ -722,7 +730,11 @@ _PyLong_AsUnsignedLongMask(PyObject *vv)
 }
 v = (PyLongObject *)vv;
 if (_PyLong_IsCompact(v)) {
-return (unsigned long)_PyLong_CompactValue(v);
+#if SIZEOF_LONG < SIZEOF_SIZE_T
+return (unsigned long)(size_t)_PyLong_CompactValue(v);
+#else
+return (unsigned long)(long)_PyLong_CompactValue(v);
+#endif
 }
 i = _PyLong_DigitCount(v);
 int sign = _PyLong_NonCompactSign(v);
@@ -1528,7 +1540,18 @@ PyLong_AsUnsignedLongLong(PyObject *vv)
 v = (PyLongObject*)vv;
 if (_PyLong_IsNonNegativeCompact(v)) {
 res = 0;
-bytes = _PyLong_CompactValue(v);
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+size_t tmp = (size_t)_PyLong_CompactValue(v);
+bytes = (unsigned long long)tmp;
+if (bytes != tmp) {
+PyErr_SetString(PyExc_OverflowError,
+"Python int too large to convert "
+"to C unsigned long long");
+res = -1;
+}
+#else
+bytes = (unsigned long long)(size_t)_PyLong_CompactValue(v);
+#endif
 }
 else {
 res = _PyLong_AsByteArray((PyLongObject *)vv, (unsigned char *)&bytes,
@@ -1559,7 +1582,11 @@ _PyLong_AsUnsignedLongLongMask(PyObject *vv)
 }
 v = (PyLongObject *)vv;
 if (_PyLong_IsCompact(v)) {
-return (unsigned long long)(signed long long)_PyLong_CompactValue(v);
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+return (unsigned long long)(size_t)_PyLong_CompactValue(v);
+#else
+return (unsigned long long)(long long)_PyLong_CompactValue(v);
+#endif
 }
 i = _PyLong_DigitCount(v);
 sign = _PyLong_NonCompactSign(v);
@@ -1631,7 +1658,22 @@ PyLong_AsLongLongAndOverflow(PyObject *vv, int *overflow)
 do_decref = 1;
 }
 if (_PyLong_IsCompact(v)) {
+#if SIZEOF_LONG_LONG < SIZEOF_SIZE_T
+Py_ssize_t tmp = _PyLong_CompactValue(v);
+if (tmp < LLONG_MIN) {
+*overflow = -1;
+res = -1;
+}
+else if (tmp > LLONG_MAX) {
+*overflow = 1;
+res = -1;
+}
+else {
+res = (long long)tmp;
+}
+#else
 res = _PyLong_CompactValue(v);
+#endif
 }
 else {
 i = _PyLong_DigitCount(v);
@@ -3568,7 +3610,7 @@ long_hash(PyLongObject *v)
 int sign;
 
 if (_PyLong_IsCompact(v)) {
-x = _PyLong_CompactValue(v);
+x = (Py_uhash_t)_PyLong_CompactValue(v);
 if (x == (Py_uhash_t)-1) {
 x = (Py_uhash_t)-2;
 }
diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c
index 8f368578767497..5a

[Python-checkins] gh-121849: Fix PyUnicodeWriter_WriteSubstring() crash if len=0 (#121896)

2024-07-17 Thread vstinner
https://github.com/python/cpython/commit/bfdbeac355235f6831ace5b514264bd1908000e5
commit: bfdbeac355235f6831ace5b514264bd1908000e5
branch: main
author: Victor Stinner 
committer: vstinner 
date: 2024-07-17T10:26:05+02:00
summary:

gh-121849: Fix PyUnicodeWriter_WriteSubstring() crash if len=0 (#121896)

Do nothing if start=end.

files:
M Lib/test/test_capi/test_unicode.py
M Objects/unicodeobject.c

diff --git a/Lib/test/test_capi/test_unicode.py 
b/Lib/test/test_capi/test_unicode.py
index 9ef476a02de47d..e6f85427214958 100644
--- a/Lib/test/test_capi/test_unicode.py
+++ b/Lib/test/test_capi/test_unicode.py
@@ -1736,7 +1736,7 @@ def test_basic(self):
 writer.write_char('=')
 
 # test PyUnicodeWriter_WriteSubstring()
-writer.write_substring("[long]", 1, 5);
+writer.write_substring("[long]", 1, 5)
 
 # test PyUnicodeWriter_WriteStr()
 writer.write_str(" value ")
@@ -1862,6 +1862,10 @@ def test_ucs4(self):
 with self.assertRaises(ValueError):
 writer.write_ucs4("text", -1)
 
+def test_substring_empty(self):
+writer = self.create_writer(0)
+writer.write_substring("abc", 1, 1)
+self.assertEqual(writer.finish(), '')
 
 
 @unittest.skipIf(ctypes is None, 'need ctypes')
diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c
index 408d74fb3afef9..6196a8e766a15b 100644
--- a/Objects/unicodeobject.c
+++ b/Objects/unicodeobject.c
@@ -13637,27 +13637,28 @@ int
 _PyUnicodeWriter_WriteSubstring(_PyUnicodeWriter *writer, PyObject *str,
 Py_ssize_t start, Py_ssize_t end)
 {
-Py_UCS4 maxchar;
-Py_ssize_t len;
-
 assert(0 <= start);
 assert(end <= PyUnicode_GET_LENGTH(str));
 assert(start <= end);
 
-if (end == 0)
-return 0;
-
 if (start == 0 && end == PyUnicode_GET_LENGTH(str))
 return _PyUnicodeWriter_WriteStr(writer, str);
 
-if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar)
+Py_ssize_t len = end - start;
+if (len == 0) {
+return 0;
+}
+
+Py_UCS4 maxchar;
+if (PyUnicode_MAX_CHAR_VALUE(str) > writer->maxchar) {
 maxchar = _PyUnicode_FindMaxChar(str, start, end);
-else
+}
+else {
 maxchar = writer->maxchar;
-len = end - start;
-
-if (_PyUnicodeWriter_Prepare(writer, len, maxchar) < 0)
+}
+if (_PyUnicodeWriter_Prepare(writer, len, maxchar) < 0) {
 return -1;
+}
 
 _PyUnicode_FastCopyCharacters(writer->buffer, writer->pos,
   str, start, len);

___
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-121863: Immortalize names in code objects to avoid crash (GH-121903)

2024-07-17 Thread encukou
https://github.com/python/cpython/commit/cffad5c6ef9371b26e32556296cea2bfe8358b1a
commit: cffad5c6ef9371b26e32556296cea2bfe8358b1a
branch: main
author: Petr Viktorin 
committer: encukou 
date: 2024-07-17T11:31:28+02:00
summary:

gh-121863: Immortalize names in code objects to avoid crash (GH-121903)

files:
M Lib/test/test_scope.py
M Objects/codeobject.c

diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index 6e46dfa96a664f..24a366efc6ca05 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -810,6 +810,30 @@ def dig(self):
 gc_collect()  # For PyPy or other GCs.
 self.assertIsNone(ref())
 
+def test_multiple_nesting(self):
+# Regression test for https://github.com/python/cpython/issues/121863
+class MultiplyNested:
+def f1(self):
+__arg = 1
+class D:
+def g(self, __arg):
+return __arg
+return D().g(_MultiplyNested__arg=2)
+
+def f2(self):
+__arg = 1
+class D:
+def g(self, __arg):
+return __arg
+return D().g
+
+inst = MultiplyNested()
+with self.assertRaises(TypeError):
+inst.f1()
+
+closure = inst.f2()
+with self.assertRaises(TypeError):
+closure(_MultiplyNested__arg=2)
 
 if __name__ == '__main__':
 unittest.main()
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 7493280c898750..d45ba5ed4a9c06 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -147,7 +147,7 @@ intern_strings(PyObject *tuple)
 "non-string found in code slot");
 return -1;
 }
-_PyUnicode_InternMortal(interp, &_PyTuple_ITEMS(tuple)[i]);
+_PyUnicode_InternImmortal(interp, &_PyTuple_ITEMS(tuple)[i]);
 }
 return 0;
 }

___
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-121863: Immortalize names in code objects to avoid crash (GH-121903) (GH-121904)

2024-07-17 Thread encukou
https://github.com/python/cpython/commit/72cd53ea15c6b304b826fe2ec69fa5afb1d3664e
commit: 72cd53ea15c6b304b826fe2ec69fa5afb1d3664e
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: encukou 
date: 2024-07-17T09:55:22Z
summary:

[3.13] gh-121863: Immortalize names in code objects to avoid crash (GH-121903) 
(GH-121904)

(cherry picked from commit cffad5c6ef9371b26e32556296cea2bfe8358b1a)

Co-authored-by: Petr Viktorin 

files:
M Lib/test/test_scope.py
M Objects/codeobject.c

diff --git a/Lib/test/test_scope.py b/Lib/test/test_scope.py
index 6e46dfa96a664f..24a366efc6ca05 100644
--- a/Lib/test/test_scope.py
+++ b/Lib/test/test_scope.py
@@ -810,6 +810,30 @@ def dig(self):
 gc_collect()  # For PyPy or other GCs.
 self.assertIsNone(ref())
 
+def test_multiple_nesting(self):
+# Regression test for https://github.com/python/cpython/issues/121863
+class MultiplyNested:
+def f1(self):
+__arg = 1
+class D:
+def g(self, __arg):
+return __arg
+return D().g(_MultiplyNested__arg=2)
+
+def f2(self):
+__arg = 1
+class D:
+def g(self, __arg):
+return __arg
+return D().g
+
+inst = MultiplyNested()
+with self.assertRaises(TypeError):
+inst.f1()
+
+closure = inst.f2()
+with self.assertRaises(TypeError):
+closure(_MultiplyNested__arg=2)
 
 if __name__ == '__main__':
 unittest.main()
diff --git a/Objects/codeobject.c b/Objects/codeobject.c
index 7b1244a8d5fd21..fbc1439d30c27a 100644
--- a/Objects/codeobject.c
+++ b/Objects/codeobject.c
@@ -147,7 +147,7 @@ intern_strings(PyObject *tuple)
 "non-string found in code slot");
 return -1;
 }
-_PyUnicode_InternMortal(interp, &_PyTuple_ITEMS(tuple)[i]);
+_PyUnicode_InternImmortal(interp, &_PyTuple_ITEMS(tuple)[i]);
 }
 return 0;
 }

___
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-113993: Don't immortalize in PyUnicode_InternInPlace; keep immortalizing in other API (GH-121364) (GH-121854)

2024-07-17 Thread encukou
https://github.com/python/cpython/commit/4395d68c7017eacf0ad643befe1f1e0bc6149f26
commit: 4395d68c7017eacf0ad643befe1f1e0bc6149f26
branch: 3.13
author: Petr Viktorin 
committer: encukou 
date: 2024-07-17T14:51:42+02:00
summary:

[3.13] gh-113993: Don't immortalize in PyUnicode_InternInPlace; keep 
immortalizing in other API (GH-121364) (GH-121854)

* Switch PyUnicode_InternInPlace to _PyUnicode_InternMortal, clarify docs

* Document immortality in some functions that take `const char *`

This is PyUnicode_InternFromString;
PyDict_SetItemString, PyObject_SetAttrString;
PyObject_DelAttrString; PyUnicode_InternFromString;
and the PyModule_Add convenience functions.

Always point out a non-immortalizing alternative.

* Don't immortalize user-provided attr names in _ctypes
(cherry picked from commit b4aedb23ae7954fb58084dda16cd41786819a8cf)

files:
A Misc/NEWS.d/next/C API/2024-07-04-15-41-10.gh-issue-113993.cLSiWV.rst
M Doc/c-api/module.rst
M Doc/c-api/object.rst
M Doc/c-api/unicode.rst
M Modules/_ctypes/_ctypes.c
M Objects/unicodeobject.c

diff --git a/Doc/c-api/module.rst b/Doc/c-api/module.rst
index 3ea7aeb55d0d74..8a15a5ea83e3e8 100644
--- a/Doc/c-api/module.rst
+++ b/Doc/c-api/module.rst
@@ -549,6 +549,14 @@ state:
Note that ``Py_XDECREF()`` should be used instead of ``Py_DECREF()`` in
this case, since *obj* can be ``NULL``.
 
+   The number of different *name* strings passed to this function
+   should be kept small, usually by only using statically allocated strings
+   as *name*.
+   For names that aren't known at compile time, prefer calling
+   :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly.
+   For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+   used internally to create a key object.
+
.. versionadded:: 3.10
 
 
@@ -610,6 +618,9 @@ state:
used from the module's initialization function.
Return ``-1`` with an exception set on error, ``0`` on success.
 
+   This is a convenience function that calls :c:func:`PyLong_FromLong` and
+   :c:func:`PyModule_AddObjectRef`; see their documentation for details.
+
 
 .. c:function:: int PyModule_AddStringConstant(PyObject *module, const char 
*name, const char *value)
 
@@ -618,6 +629,10 @@ state:
``NULL``-terminated.
Return ``-1`` with an exception set on error, ``0`` on success.
 
+   This is a convenience function that calls
+   :c:func:`PyUnicode_InternFromString` and :c:func:`PyModule_AddObjectRef`;
+   see their documentation for details.
+
 
 .. c:macro:: PyModule_AddIntMacro(module, macro)
 
diff --git a/Doc/c-api/object.rst b/Doc/c-api/object.rst
index 2103a64d8ffbb7..1c28f30321bd7a 100644
--- a/Doc/c-api/object.rst
+++ b/Doc/c-api/object.rst
@@ -206,6 +206,13 @@ Object Protocol
If *v* is ``NULL``, the attribute is deleted, but this feature is
deprecated in favour of using :c:func:`PyObject_DelAttrString`.
 
+   The number of different attribute names passed to this function
+   should be kept small, usually by using a statically allocated string
+   as *attr_name*.
+   For attribute names that aren't known at compile time, prefer calling
+   :c:func:`PyUnicode_FromString` and :c:func:`PyObject_SetAttr` directly.
+   For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+   used internally to create a key object.
 
 .. c:function:: int PyObject_GenericSetAttr(PyObject *o, PyObject *name, 
PyObject *value)
 
@@ -231,6 +238,14 @@ Object Protocol
specified as a :c:expr:`const char*` UTF-8 encoded bytes string,
rather than a :c:expr:`PyObject*`.
 
+   The number of different attribute names passed to this function
+   should be kept small, usually by using a statically allocated string
+   as *attr_name*.
+   For attribute names that aren't known at compile time, prefer calling
+   :c:func:`PyUnicode_FromString` and :c:func:`PyObject_DelAttr` directly.
+   For more details, see :c:func:`PyUnicode_InternFromString`, which may be
+   used internally to create a key object for lookup.
+
 
 .. c:function:: PyObject* PyObject_GenericGetDict(PyObject *o, void *context)
 
diff --git a/Doc/c-api/unicode.rst b/Doc/c-api/unicode.rst
index 7320d035bab513..607ccc7b5df96f 100644
--- a/Doc/c-api/unicode.rst
+++ b/Doc/c-api/unicode.rst
@@ -1490,15 +1490,41 @@ They all return ``NULL`` or ``-1`` if an exception 
occurs.
existing interned string that is the same as :c:expr:`*p_unicode`, it sets 
:c:expr:`*p_unicode` to
it (releasing the reference to the old string object and creating a new
:term:`strong reference` to the interned string object), otherwise it leaves
-   :c:expr:`*p_unicode` alone and interns it (creating a new :term:`strong 
reference`).
+   :c:expr:`*p_unicode` alone and interns it.
+
(Clarification: even though there is a lot of talk about references, think
-   of this function as reference-neutral; you own the object after the call
-   if and only if you owned it before the call.)
+   of this function as reference-neutral. You must

[Python-checkins] gh-119698: fix a special case in `symtable.Class.get_methods` (#121802)

2024-07-17 Thread JelleZijlstra
https://github.com/python/cpython/commit/6682d916780c1cb305e679a057ee6992b114118e
commit: 6682d916780c1cb305e679a057ee6992b114118e
branch: main
author: Bénédikt Tran <[email protected]>
committer: JelleZijlstra 
date: 2024-07-17T06:27:35-07:00
summary:

gh-119698: fix a special case in `symtable.Class.get_methods` (#121802)

files:
M Lib/symtable.py
M Lib/test/test_symtable.py

diff --git a/Lib/symtable.py b/Lib/symtable.py
index 221aaf88d41670..8c796b7cc7edb8 100644
--- a/Lib/symtable.py
+++ b/Lib/symtable.py
@@ -249,6 +249,11 @@ def is_local_symbol(ident):
 if is_local_symbol(st.name):
 match st.type:
 case _symtable.TYPE_FUNCTION:
+# generators are of type TYPE_FUNCTION with a ".0"
+# parameter as a first parameter (which makes them
+# distinguishable from a function named 'genexpr')
+if st.name == 'genexpr' and '.0' in st.varnames:
+continue
 d[st.name] = 1
 case _symtable.TYPE_TYPE_PARAMETERS:
 # Get the function-def block in the annotation
@@ -256,7 +261,14 @@ def is_local_symbol(ident):
 scope_name = st.name
 for c in st.children:
 if c.name == scope_name and c.type == 
_symtable.TYPE_FUNCTION:
-d[st.name] = 1
+# A generic generator of type TYPE_FUNCTION
+# cannot be a direct child of 'st' (but it
+# can be a descendant), e.g.:
+#
+# class A:
+#   type genexpr[genexpr] = (x for x in [])
+assert scope_name != 'genexpr' or '.0' not 
in c.varnames
+d[scope_name] = 1
 break
 self.__methods = tuple(d)
 return self.__methods
diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py
index 0cc192655931ba..82f667d3687fee 100644
--- a/Lib/test/test_symtable.py
+++ b/Lib/test/test_symtable.py
@@ -1,6 +1,8 @@
 """
 Test the API of the symtable module.
 """
+
+import textwrap
 import symtable
 import unittest
 
@@ -356,7 +358,7 @@ def test_name(self):
 self.assertEqual(self.spam.lookup("x").get_name(), "x")
 self.assertEqual(self.Mine.get_name(), "Mine")
 
-def test_class_info(self):
+def test_class_get_methods(self):
 self.assertEqual(self.Mine.get_methods(), ('a_method',))
 
 top = symtable.symtable(TEST_COMPLEX_CLASS_CODE, "?", "exec")
@@ -377,6 +379,58 @@ def test_class_info(self):
 'glob_assigned_async_meth', 'glob_assigned_async_meth_pep_695',
 ))
 
+# Test generator expressions that are of type TYPE_FUNCTION
+# but will not be reported by get_methods() since they are
+# not functions per se.
+#
+# Other kind of comprehensions such as list, set or dict
+# expressions do not have the TYPE_FUNCTION type.
+
+def check_body(body, expected_methods):
+indented = textwrap.indent(body, ' ' * 4)
+top = symtable.symtable(f"class A:\n{indented}", "?", "exec")
+this = find_block(top, "A")
+self.assertEqual(this.get_methods(), expected_methods)
+
+# statements with 'genexpr' inside it
+GENEXPRS = (
+'x = (x for x in [])',
+'x = (x async for x in [])',
+'type x[genexpr = (x for x in [])] = (x for x in [])',
+'type x[genexpr = (x async for x in [])] = (x async for x in [])',
+'genexpr = (x for x in [])',
+'genexpr = (x async for x in [])',
+'type genexpr[genexpr = (x for x in [])] = (x for x in [])',
+'type genexpr[genexpr = (x async for x in [])] = (x async for x in 
[])',
+)
+
+for gen in GENEXPRS:
+# test generator expression
+with self.subTest(gen=gen):
+check_body(gen, ())
+
+# test generator expression + variable named 'genexpr'
+with self.subTest(gen=gen, isvar=True):
+check_body('\n'.join((gen, 'genexpr = 1')), ())
+check_body('\n'.join(('genexpr = 1', gen)), ())
+
+for paramlist in ('()', '(x)', '(x, y)', '(z: T)'):
+for func in (
+f'def genexpr{paramlist}:pass',
+f'async def genexpr{paramlist}:pass',
+f'def genexpr[T]{paramlist}:pass',
+f'async def genexpr[T]{paramlist}:pass',
+):
+with self.subTest(func=func):
+# test function nam

[Python-checkins] gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (#121876)

2024-07-17 Thread terryjreedy
https://github.com/python/cpython/commit/58753f33e47fe48906883dc010771f68c13b7e52
commit: 58753f33e47fe48906883dc010771f68c13b7e52
branch: main
author: Terry Jan Reedy 
committer: terryjreedy 
date: 2024-07-17T09:33:33-04:00
summary:

gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (#121876)

Problem occurred when attribute xyz could not be pickled.
Since this is not trivial to selectively fix, block all
attributes (other than 'width').  IDLE does not access them
and they are private implementation details.

files:
A Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
M Lib/idlelib/News3.txt
M Lib/idlelib/run.py

diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt
index b1b652dc562c8e..68702ac8fb9157 100644
--- a/Lib/idlelib/News3.txt
+++ b/Lib/idlelib/News3.txt
@@ -4,6 +4,9 @@ Released on 2024-10-xx
 =
 
 
+gh-78889: Stop Shell freezes by blocking user access to non-method
+sys.stdout.shell attributes, which are all private.
+
 gh-78955: Use user-selected color theme for Help => IDLE Doc.
 
 gh-96905: In idlelib code, stop redefining built-ins 'dict' and 'object'.
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 8974b52674fb8c..8f98e73258e778 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -443,6 +443,9 @@ class StdioFile(io.TextIOBase):
 
 def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
 self.shell = shell
+# GH-78889: accessing unpickleable attributes freezes Shell.
+# IDLE only needs methods; allow 'width' for possible use.
+self.shell._RPCProxy__attributes = {'width': 1}
 self.tags = tags
 self._encoding = encoding
 self._errors = errors
diff --git 
a/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst 
b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
new file mode 100644
index 00..604194ebb2e859
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
@@ -0,0 +1,2 @@
+Stop Shell freezes by blocking user access to non-method sys.stdout.shell 
attributes,
+which are all private.

___
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-119698: fix a special case in `symtable.Class.get_methods` (GH-121802) (#121909)

2024-07-17 Thread JelleZijlstra
https://github.com/python/cpython/commit/c6ef5aca614e3ee1cfe4125148d80e0e0bd77462
commit: c6ef5aca614e3ee1cfe4125148d80e0e0bd77462
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: JelleZijlstra 
date: 2024-07-17T13:54:40Z
summary:

[3.13] gh-119698: fix a special case in `symtable.Class.get_methods` 
(GH-121802) (#121909)

(cherry picked from commit 6682d916780c1cb305e679a057ee6992b114118e)

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

files:
M Lib/symtable.py
M Lib/test/test_symtable.py

diff --git a/Lib/symtable.py b/Lib/symtable.py
index 73e9fb318ad917..672ec0ce1ff8fe 100644
--- a/Lib/symtable.py
+++ b/Lib/symtable.py
@@ -238,6 +238,11 @@ def is_local_symbol(ident):
 if is_local_symbol(st.name):
 match st.type:
 case _symtable.TYPE_FUNCTION:
+# generators are of type TYPE_FUNCTION with a ".0"
+# parameter as a first parameter (which makes them
+# distinguishable from a function named 'genexpr')
+if st.name == 'genexpr' and '.0' in st.varnames:
+continue
 d[st.name] = 1
 case _symtable.TYPE_TYPE_PARAMETERS:
 # Get the function-def block in the annotation
@@ -245,7 +250,14 @@ def is_local_symbol(ident):
 scope_name = st.name
 for c in st.children:
 if c.name == scope_name and c.type == 
_symtable.TYPE_FUNCTION:
-d[st.name] = 1
+# A generic generator of type TYPE_FUNCTION
+# cannot be a direct child of 'st' (but it
+# can be a descendant), e.g.:
+#
+# class A:
+#   type genexpr[genexpr] = (x for x in [])
+assert scope_name != 'genexpr' or '.0' not 
in c.varnames
+d[scope_name] = 1
 break
 self.__methods = tuple(d)
 return self.__methods
diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py
index 2443898c981a00..c1b7030d2d250c 100644
--- a/Lib/test/test_symtable.py
+++ b/Lib/test/test_symtable.py
@@ -1,6 +1,8 @@
 """
 Test the API of the symtable module.
 """
+
+import textwrap
 import symtable
 import unittest
 
@@ -354,7 +356,7 @@ def test_name(self):
 self.assertEqual(self.spam.lookup("x").get_name(), "x")
 self.assertEqual(self.Mine.get_name(), "Mine")
 
-def test_class_info(self):
+def test_class_get_methods(self):
 self.assertEqual(self.Mine.get_methods(), ('a_method',))
 
 top = symtable.symtable(TEST_COMPLEX_CLASS_CODE, "?", "exec")
@@ -375,6 +377,58 @@ def test_class_info(self):
 'glob_assigned_async_meth', 'glob_assigned_async_meth_pep_695',
 ))
 
+# Test generator expressions that are of type TYPE_FUNCTION
+# but will not be reported by get_methods() since they are
+# not functions per se.
+#
+# Other kind of comprehensions such as list, set or dict
+# expressions do not have the TYPE_FUNCTION type.
+
+def check_body(body, expected_methods):
+indented = textwrap.indent(body, ' ' * 4)
+top = symtable.symtable(f"class A:\n{indented}", "?", "exec")
+this = find_block(top, "A")
+self.assertEqual(this.get_methods(), expected_methods)
+
+# statements with 'genexpr' inside it
+GENEXPRS = (
+'x = (x for x in [])',
+'x = (x async for x in [])',
+'type x[genexpr = (x for x in [])] = (x for x in [])',
+'type x[genexpr = (x async for x in [])] = (x async for x in [])',
+'genexpr = (x for x in [])',
+'genexpr = (x async for x in [])',
+'type genexpr[genexpr = (x for x in [])] = (x for x in [])',
+'type genexpr[genexpr = (x async for x in [])] = (x async for x in 
[])',
+)
+
+for gen in GENEXPRS:
+# test generator expression
+with self.subTest(gen=gen):
+check_body(gen, ())
+
+# test generator expression + variable named 'genexpr'
+with self.subTest(gen=gen, isvar=True):
+check_body('\n'.join((gen, 'genexpr = 1')), ())
+check_body('\n'.join(('genexpr = 1', gen)), ())
+
+for paramlist in ('()', '(x)', '(x, y)', '(z: T)'):
+for func in (
+f'def genexpr{paramlist}:pass',
+f'async def genexpr{paramlist}:pass',
+f'def genexpr[T]{param

[Python-checkins] [3.12] gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876) (#121912)

2024-07-17 Thread terryjreedy
https://github.com/python/cpython/commit/a6516de08b7062d224a6a5f88a7d4ad4dd1fd051
commit: a6516de08b7062d224a6a5f88a7d4ad4dd1fd051
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: terryjreedy 
date: 2024-07-17T14:03:54Z
summary:

[3.12] gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876) 
(#121912)

gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876)

Problem occurred when attribute xyz could not be pickled.
Since this is not trivial to selectively fix, block all
attributes (other than 'width').  IDLE does not access them
and they are private implementation details.
(cherry picked from commit 58753f33e47fe48906883dc010771f68c13b7e52)

Co-authored-by: Terry Jan Reedy 

files:
A Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
M Lib/idlelib/News3.txt
M Lib/idlelib/run.py

diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt
index c92196f1f4a642..39791d60c06829 100644
--- a/Lib/idlelib/News3.txt
+++ b/Lib/idlelib/News3.txt
@@ -4,6 +4,9 @@ Released after 2023-10-02
 =
 
 
+gh-78889: Stop Shell freezes by blocking user access to non-method
+sys.stdout.shell attributes, which are all private.
+
 gh-78955: Use user-selected color theme for Help => IDLE Doc.
 
 gh-96905: In idlelib code, stop redefining built-ins 'dict' and 'object'.
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 53e80a9b42801f..476a7b26c004b5 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -436,6 +436,9 @@ class StdioFile(io.TextIOBase):
 
 def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
 self.shell = shell
+# GH-78889: accessing unpickleable attributes freezes Shell.
+# IDLE only needs methods; allow 'width' for possible use.
+self.shell._RPCProxy__attributes = {'width': 1}
 self.tags = tags
 self._encoding = encoding
 self._errors = errors
diff --git 
a/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst 
b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
new file mode 100644
index 00..604194ebb2e859
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
@@ -0,0 +1,2 @@
+Stop Shell freezes by blocking user access to non-method sys.stdout.shell 
attributes,
+which are all private.

___
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-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876) (#121911)

2024-07-17 Thread terryjreedy
https://github.com/python/cpython/commit/5a8e1373fe5700ca52b55117880b32912fbece3a
commit: 5a8e1373fe5700ca52b55117880b32912fbece3a
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: terryjreedy 
date: 2024-07-17T14:10:13Z
summary:

[3.13] gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876) 
(#121911)

gh-78889: Stop IDLE Shell freezes from sys.stdout.shell.xyz (GH-121876)

Problem occurred when attribute xyz could not be pickled.
Since this is not trivial to selectively fix, block all
attributes (other than 'width').  IDLE does not access them
and they are private implementation details.
(cherry picked from commit 58753f33e47fe48906883dc010771f68c13b7e52)

Co-authored-by: Terry Jan Reedy 

files:
A Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
M Lib/idlelib/News3.txt
M Lib/idlelib/run.py

diff --git a/Lib/idlelib/News3.txt b/Lib/idlelib/News3.txt
index b1b652dc562c8e..68702ac8fb9157 100644
--- a/Lib/idlelib/News3.txt
+++ b/Lib/idlelib/News3.txt
@@ -4,6 +4,9 @@ Released on 2024-10-xx
 =
 
 
+gh-78889: Stop Shell freezes by blocking user access to non-method
+sys.stdout.shell attributes, which are all private.
+
 gh-78955: Use user-selected color theme for Help => IDLE Doc.
 
 gh-96905: In idlelib code, stop redefining built-ins 'dict' and 'object'.
diff --git a/Lib/idlelib/run.py b/Lib/idlelib/run.py
index 8974b52674fb8c..8f98e73258e778 100644
--- a/Lib/idlelib/run.py
+++ b/Lib/idlelib/run.py
@@ -443,6 +443,9 @@ class StdioFile(io.TextIOBase):
 
 def __init__(self, shell, tags, encoding='utf-8', errors='strict'):
 self.shell = shell
+# GH-78889: accessing unpickleable attributes freezes Shell.
+# IDLE only needs methods; allow 'width' for possible use.
+self.shell._RPCProxy__attributes = {'width': 1}
 self.tags = tags
 self._encoding = encoding
 self._errors = errors
diff --git 
a/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst 
b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
new file mode 100644
index 00..604194ebb2e859
--- /dev/null
+++ b/Misc/NEWS.d/next/IDLE/2024-07-16-16-57-03.gh-issue-78889.U7ghFD.rst
@@ -0,0 +1,2 @@
+Stop Shell freezes by blocking user access to non-method sys.stdout.shell 
attributes,
+which are all private.

___
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-120678: pyrepl: Include globals from modules passed with `-i` (GH-120904)

2024-07-17 Thread ambv
https://github.com/python/cpython/commit/ac07451116d52dd6a5545d27b6a2e3737ed27cf0
commit: ac07451116d52dd6a5545d27b6a2e3737ed27cf0
branch: main
author: Alex Waygood 
committer: ambv 
date: 2024-07-17T16:18:42+02:00
summary:

gh-120678: pyrepl: Include globals from modules passed with `-i` (GH-120904)

Co-authored-by: Łukasz Langa 

files:
A Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst
M Lib/_pyrepl/__main__.py
M Lib/test/support/__init__.py
M Lib/test/test_pyrepl/support.py
M Lib/test/test_pyrepl/test_pyrepl.py
M Modules/main.c

diff --git a/Lib/_pyrepl/__main__.py b/Lib/_pyrepl/__main__.py
index efb6d343cc9a7c..3fa992eee8eeff 100644
--- a/Lib/_pyrepl/__main__.py
+++ b/Lib/_pyrepl/__main__.py
@@ -1,3 +1,6 @@
+# Important: don't add things to this module, as they will end up in the REPL's
+# default globals.  Use _pyrepl.main instead.
+
 if __name__ == "__main__":
 from .main import interactive_console as __pyrepl_interactive_console
 __pyrepl_interactive_console()
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 7f6579319589b4..37e3305036f499 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2614,14 +2614,18 @@ def force_not_colorized(func):
 def wrapper(*args, **kwargs):
 import _colorize
 original_fn = _colorize.can_colorize
-variables = {"PYTHON_COLORS": None, "FORCE_COLOR": None}
+variables: dict[str, str | None] = {
+"PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None
+}
 try:
 for key in variables:
 variables[key] = os.environ.pop(key, None)
+os.environ["NO_COLOR"] = "1"
 _colorize.can_colorize = lambda: False
 return func(*args, **kwargs)
 finally:
 _colorize.can_colorize = original_fn
+del os.environ["NO_COLOR"]
 for key, value in variables.items():
 if value is not None:
 os.environ[key] = value
diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py
index 58b1a92d68b184..cb5cb4ab20aa54 100644
--- a/Lib/test/test_pyrepl/support.py
+++ b/Lib/test/test_pyrepl/support.py
@@ -1,3 +1,4 @@
+import os
 from code import InteractiveConsole
 from functools import partial
 from typing import Iterable
@@ -100,8 +101,18 @@ def handle_all_events(
 )
 
 
+def make_clean_env() -> dict[str, str]:
+clean_env = os.environ.copy()
+for k in clean_env.copy():
+if k.startswith("PYTHON"):
+clean_env.pop(k)
+clean_env.pop("FORCE_COLOR", None)
+clean_env.pop("NO_COLOR", None)
+return clean_env
+
+
 class FakeConsole(Console):
-def __init__(self, events, encoding="utf-8"):
+def __init__(self, events, encoding="utf-8") -> None:
 self.events = iter(events)
 self.encoding = encoding
 self.screen = []
diff --git a/Lib/test/test_pyrepl/test_pyrepl.py 
b/Lib/test/test_pyrepl/test_pyrepl.py
index 2b1f8c3cea42f9..6451d6104b5d1a 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -2,6 +2,7 @@
 import itertools
 import os
 import pathlib
+import re
 import rlcompleter
 import select
 import subprocess
@@ -21,7 +22,8 @@
 more_lines,
 multiline_input,
 code_to_events,
-clean_screen
+clean_screen,
+make_clean_env,
 )
 from _pyrepl.console import Event
 from _pyrepl.readline import ReadlineAlikeReader, ReadlineConfig
@@ -487,6 +489,18 @@ def prepare_reader(self, events):
 reader.can_colorize = False
 return reader
 
+def test_stdin_is_tty(self):
+# Used during test log analysis to figure out if a TTY was available.
+if os.isatty(sys.stdin.fileno()):
+return
+self.skipTest("stdin is not a tty")
+
+def test_stdout_is_tty(self):
+# Used during test log analysis to figure out if a TTY was available.
+if os.isatty(sys.stdout.fileno()):
+return
+self.skipTest("stdout is not a tty")
+
 def test_basic(self):
 reader = self.prepare_reader(code_to_events("1+1\n"))
 
@@ -888,12 +902,7 @@ def setUp(self):
 # Cleanup from PYTHON* variables to isolate from local
 # user settings, see #121359.  Such variables should be
 # added later in test methods to patched os.environ.
-clean_env = os.environ.copy()
-for k in clean_env.copy():
-if k.startswith("PYTHON"):
-clean_env.pop(k)
-
-patcher = patch('os.environ', new=clean_env)
+patcher = patch('os.environ', new=make_clean_env())
 self.addCleanup(patcher.stop)
 patcher.start()
 
@@ -920,6 +929,84 @@ def test_exposed_globals_in_repl(self):
 
 self.assertTrue(case1 or case2 or case3 or case4, output)
 
+def _assertMatchOK(
+self, var: str, expected: str | re.Pattern, actual: str
+) -> None:
+if isinstance(

[Python-checkins] [3.13] gh-120678: pyrepl: Include globals from modules passed with `-i` (GH-120904) (#121916)

2024-07-17 Thread ambv
https://github.com/python/cpython/commit/3d9692dbf8f38747ea07f6387724a5928df0eb1a
commit: 3d9692dbf8f38747ea07f6387724a5928df0eb1a
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: ambv 
date: 2024-07-17T16:52:46+02:00
summary:

[3.13] gh-120678: pyrepl: Include globals from modules passed with `-i` 
(GH-120904) (#121916)

(cherry picked from commit ac07451116d52dd6a5545d27b6a2e3737ed27cf0)

Co-authored-by: Alex Waygood 
Co-authored-by: Łukasz Langa 

files:
A Misc/NEWS.d/next/Library/2024-06-22-17-01-56.gh-issue-120678.Ik8dCg.rst
M Lib/_pyrepl/__main__.py
M Lib/test/support/__init__.py
M Lib/test/test_pyrepl/support.py
M Lib/test/test_pyrepl/test_pyrepl.py
M Modules/main.c

diff --git a/Lib/_pyrepl/__main__.py b/Lib/_pyrepl/__main__.py
index efb6d343cc9a7c..3fa992eee8eeff 100644
--- a/Lib/_pyrepl/__main__.py
+++ b/Lib/_pyrepl/__main__.py
@@ -1,3 +1,6 @@
+# Important: don't add things to this module, as they will end up in the REPL's
+# default globals.  Use _pyrepl.main instead.
+
 if __name__ == "__main__":
 from .main import interactive_console as __pyrepl_interactive_console
 __pyrepl_interactive_console()
diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py
index 38357cb792d7b2..03950bf63bf4b9 100644
--- a/Lib/test/support/__init__.py
+++ b/Lib/test/support/__init__.py
@@ -2595,14 +2595,18 @@ def force_not_colorized(func):
 def wrapper(*args, **kwargs):
 import _colorize
 original_fn = _colorize.can_colorize
-variables = {"PYTHON_COLORS": None, "FORCE_COLOR": None}
+variables: dict[str, str | None] = {
+"PYTHON_COLORS": None, "FORCE_COLOR": None, "NO_COLOR": None
+}
 try:
 for key in variables:
 variables[key] = os.environ.pop(key, None)
+os.environ["NO_COLOR"] = "1"
 _colorize.can_colorize = lambda: False
 return func(*args, **kwargs)
 finally:
 _colorize.can_colorize = original_fn
+del os.environ["NO_COLOR"]
 for key, value in variables.items():
 if value is not None:
 os.environ[key] = value
diff --git a/Lib/test/test_pyrepl/support.py b/Lib/test/test_pyrepl/support.py
index 58b1a92d68b184..cb5cb4ab20aa54 100644
--- a/Lib/test/test_pyrepl/support.py
+++ b/Lib/test/test_pyrepl/support.py
@@ -1,3 +1,4 @@
+import os
 from code import InteractiveConsole
 from functools import partial
 from typing import Iterable
@@ -100,8 +101,18 @@ def handle_all_events(
 )
 
 
+def make_clean_env() -> dict[str, str]:
+clean_env = os.environ.copy()
+for k in clean_env.copy():
+if k.startswith("PYTHON"):
+clean_env.pop(k)
+clean_env.pop("FORCE_COLOR", None)
+clean_env.pop("NO_COLOR", None)
+return clean_env
+
+
 class FakeConsole(Console):
-def __init__(self, events, encoding="utf-8"):
+def __init__(self, events, encoding="utf-8") -> None:
 self.events = iter(events)
 self.encoding = encoding
 self.screen = []
diff --git a/Lib/test/test_pyrepl/test_pyrepl.py 
b/Lib/test/test_pyrepl/test_pyrepl.py
index 2b1f8c3cea42f9..6451d6104b5d1a 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -2,6 +2,7 @@
 import itertools
 import os
 import pathlib
+import re
 import rlcompleter
 import select
 import subprocess
@@ -21,7 +22,8 @@
 more_lines,
 multiline_input,
 code_to_events,
-clean_screen
+clean_screen,
+make_clean_env,
 )
 from _pyrepl.console import Event
 from _pyrepl.readline import ReadlineAlikeReader, ReadlineConfig
@@ -487,6 +489,18 @@ def prepare_reader(self, events):
 reader.can_colorize = False
 return reader
 
+def test_stdin_is_tty(self):
+# Used during test log analysis to figure out if a TTY was available.
+if os.isatty(sys.stdin.fileno()):
+return
+self.skipTest("stdin is not a tty")
+
+def test_stdout_is_tty(self):
+# Used during test log analysis to figure out if a TTY was available.
+if os.isatty(sys.stdout.fileno()):
+return
+self.skipTest("stdout is not a tty")
+
 def test_basic(self):
 reader = self.prepare_reader(code_to_events("1+1\n"))
 
@@ -888,12 +902,7 @@ def setUp(self):
 # Cleanup from PYTHON* variables to isolate from local
 # user settings, see #121359.  Such variables should be
 # added later in test methods to patched os.environ.
-clean_env = os.environ.copy()
-for k in clean_env.copy():
-if k.startswith("PYTHON"):
-clean_env.pop(k)
-
-patcher = patch('os.environ', new=clean_env)
+patcher = patch('os.environ', new=make_clean_env())
 self.addCleanup(patcher.stop)
 patcher.start()
 
@@ -920,6 +929,84 @@ def test_exposed_globals_in_repl(self):
 
 self.assertTrue(c

[Python-checkins] [3.13] Move misplaced blurb entries (#121919)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/ea364204db7896b71dc6806ca15c48ec5c295bb1
commit: ea364204db7896b71dc6806ca15c48ec5c295bb1
branch: 3.13
author: T. Wouters 
committer: Yhg1s 
date: 2024-07-17T15:33:30Z
summary:

[3.13] Move misplaced blurb entries (#121919)

Move misplaced blurb entries from "C_API" to "C API", and from 
"Core_and_Builtins" to "Core and Builtins".

files:
A Misc/NEWS.d/next/C API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst
A Misc/NEWS.d/next/Core and 
Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
A Misc/NEWS.d/next/Core and 
Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst
D Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst
D 
Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
D 
Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst

diff --git 
a/Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst 
b/Misc/NEWS.d/next/C API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst
similarity index 100%
rename from Misc/NEWS.d/next/C_API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst
rename to Misc/NEWS.d/next/C API/2024-07-09-15-55-20.gh-issue-89364.yYYroI.rst
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
 b/Misc/NEWS.d/next/Core and 
Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
similarity index 100%
rename from 
Misc/NEWS.d/next/Core_and_Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
rename to Misc/NEWS.d/next/Core and 
Builtins/2024-07-13-09-51-44.gh-issue-121609.jWsE5t.rst
diff --git 
a/Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst
 b/Misc/NEWS.d/next/Core and 
Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst
similarity index 100%
rename from 
Misc/NEWS.d/next/Core_and_Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst
rename to Misc/NEWS.d/next/Core and 
Builtins/2024-07-15-20-03-29.gh-issue-121295.w53ucI.rst

___
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-120678: Guard against stdin.fileno() being unavailable (#121924)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/19cbf8fd636192059550d0c908c3e29797feed1f
commit: 19cbf8fd636192059550d0c908c3e29797feed1f
branch: main
author: Łukasz Langa 
committer: Yhg1s 
date: 2024-07-17T16:05:34Z
summary:

gh-120678: Guard against stdin.fileno() being unavailable (#121924)

files:
M Lib/test/test_pyrepl/test_pyrepl.py

diff --git a/Lib/test/test_pyrepl/test_pyrepl.py 
b/Lib/test/test_pyrepl/test_pyrepl.py
index 6451d6104b5d1a..e6fcb69571c324 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -491,15 +491,23 @@ def prepare_reader(self, events):
 
 def test_stdin_is_tty(self):
 # Used during test log analysis to figure out if a TTY was available.
-if os.isatty(sys.stdin.fileno()):
-return
-self.skipTest("stdin is not a tty")
+try:
+if os.isatty(sys.stdin.fileno()):
+return
+except OSError as ose:
+self.skipTest(f"stdin tty check failed: {ose}")
+else:
+self.skipTest("stdin is not a tty")
 
 def test_stdout_is_tty(self):
 # Used during test log analysis to figure out if a TTY was available.
-if os.isatty(sys.stdout.fileno()):
-return
-self.skipTest("stdout is not a tty")
+try:
+if os.isatty(sys.stdout.fileno()):
+return
+except OSError as ose:
+self.skipTest(f"stdout tty check failed: {ose}")
+else:
+self.skipTest("stdout is not a tty")
 
 def test_basic(self):
 reader = self.prepare_reader(code_to_events("1+1\n"))

___
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-121925: Fix uninitialized variables in `main.c` (#121926)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/f4bc84d261c828ed81f137f2a48fa2f0de7a0211
commit: f4bc84d261c828ed81f137f2a48fa2f0de7a0211
branch: main
author: sobolevn 
committer: Yhg1s 
date: 2024-07-17T16:13:37Z
summary:

gh-121925: Fix uninitialized variables in `main.c` (#121926)

files:
M Modules/main.c

diff --git a/Modules/main.c b/Modules/main.c
index bd77558ea6412f..3c202c85c76dcc 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -264,8 +264,12 @@ static int
 pymain_start_pyrepl_no_main(void)
 {
 int res = 0;
-PyObject *pyrepl, *console, *empty_tuple, *kwargs, *console_result;
-pyrepl = PyImport_ImportModule("_pyrepl.main");
+PyObject *console = NULL;
+PyObject *empty_tuple = NULL;
+PyObject *kwargs = NULL;
+PyObject *console_result = NULL;
+
+PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main");
 if (pyrepl == NULL) {
 fprintf(stderr, "Could not import _pyrepl.main\n");
 res = pymain_exit_err_print();

___
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-120678: Guard against stdin.fileno() being unavailable (GH-121924) (#121929)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/91e098f44dbb5b6533e5173ec9a819de4cae6660
commit: 91e098f44dbb5b6533e5173ec9a819de4cae6660
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Yhg1s 
date: 2024-07-17T16:33:28Z
summary:

[3.13] gh-120678: Guard against stdin.fileno() being unavailable (GH-121924) 
(#121929)

gh-120678: Guard against stdin.fileno() being unavailable (GH-121924)
(cherry picked from commit 19cbf8fd636192059550d0c908c3e29797feed1f)

Co-authored-by: Łukasz Langa 

files:
M Lib/test/test_pyrepl/test_pyrepl.py

diff --git a/Lib/test/test_pyrepl/test_pyrepl.py 
b/Lib/test/test_pyrepl/test_pyrepl.py
index 6451d6104b5d1a..e6fcb69571c324 100644
--- a/Lib/test/test_pyrepl/test_pyrepl.py
+++ b/Lib/test/test_pyrepl/test_pyrepl.py
@@ -491,15 +491,23 @@ def prepare_reader(self, events):
 
 def test_stdin_is_tty(self):
 # Used during test log analysis to figure out if a TTY was available.
-if os.isatty(sys.stdin.fileno()):
-return
-self.skipTest("stdin is not a tty")
+try:
+if os.isatty(sys.stdin.fileno()):
+return
+except OSError as ose:
+self.skipTest(f"stdin tty check failed: {ose}")
+else:
+self.skipTest("stdin is not a tty")
 
 def test_stdout_is_tty(self):
 # Used during test log analysis to figure out if a TTY was available.
-if os.isatty(sys.stdout.fileno()):
-return
-self.skipTest("stdout is not a tty")
+try:
+if os.isatty(sys.stdout.fileno()):
+return
+except OSError as ose:
+self.skipTest(f"stdout tty check failed: {ose}")
+else:
+self.skipTest("stdout is not a tty")
 
 def test_basic(self):
 reader = self.prepare_reader(code_to_events("1+1\n"))

___
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-121925: Fix uninitialized variables in `main.c` (GH-121926) (#121931)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/449529a8c2ebf5790072cb0d7a2b236eaf663e4a
commit: 449529a8c2ebf5790072cb0d7a2b236eaf663e4a
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: Yhg1s 
date: 2024-07-17T17:00:42Z
summary:

[3.13] gh-121925: Fix uninitialized variables in `main.c` (GH-121926) (#121931)

gh-121925: Fix uninitialized variables in `main.c` (GH-121926)
(cherry picked from commit f4bc84d261c828ed81f137f2a48fa2f0de7a0211)

Co-authored-by: sobolevn 

files:
M Modules/main.c

diff --git a/Modules/main.c b/Modules/main.c
index bd77558ea6412f..3c202c85c76dcc 100644
--- a/Modules/main.c
+++ b/Modules/main.c
@@ -264,8 +264,12 @@ static int
 pymain_start_pyrepl_no_main(void)
 {
 int res = 0;
-PyObject *pyrepl, *console, *empty_tuple, *kwargs, *console_result;
-pyrepl = PyImport_ImportModule("_pyrepl.main");
+PyObject *console = NULL;
+PyObject *empty_tuple = NULL;
+PyObject *kwargs = NULL;
+PyObject *console_result = NULL;
+
+PyObject *pyrepl = PyImport_ImportModule("_pyrepl.main");
 if (pyrepl == NULL) {
 fprintf(stderr, "Could not import _pyrepl.main\n");
 res = pymain_exit_err_print();

___
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-121528: Fix _PyObject_Init() assertion for stable ABI (#121725)

2024-07-17 Thread vstinner
https://github.com/python/cpython/commit/b826e459ca6b640f896c2a9551bb2c78d10f0e2b
commit: b826e459ca6b640f896c2a9551bb2c78d10f0e2b
branch: main
author: Victor Stinner 
committer: vstinner 
date: 2024-07-17T21:49:37+02:00
summary:

gh-121528: Fix _PyObject_Init() assertion for stable ABI (#121725)

Add _Py_IsImmortalLoose() function for assertions.

files:
M Include/internal/pycore_object.h

diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index d385b20b0e964d..155810d00bef5b 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -15,6 +15,30 @@ extern "C" {
 #include "pycore_pyatomic_ft_wrappers.h"  // FT_ATOMIC_STORE_PTR_RELAXED
 #include "pycore_pystate.h"   // _PyInterpreterState_GET()
 
+
+#define _Py_IMMORTAL_REFCNT_LOOSE ((_Py_IMMORTAL_REFCNT >> 1) + 1)
+
+// gh-121528, gh-118997: Similar to _Py_IsImmortal() but be more loose when
+// comparing the reference count to stay compatible with C extensions built
+// with the stable ABI 3.11 or older. Such extensions implement INCREF/DECREF
+// as refcnt++ and refcnt-- without taking in account immortal objects. For
+// example, the reference count of an immortal object can change from
+// _Py_IMMORTAL_REFCNT to _Py_IMMORTAL_REFCNT+1 (INCREF) or
+// _Py_IMMORTAL_REFCNT-1 (DECREF).
+//
+// This function should only be used in assertions. Otherwise, _Py_IsImmortal()
+// must be used instead.
+static inline int _Py_IsImmortalLoose(PyObject *op)
+{
+#if defined(Py_GIL_DISABLED)
+return _Py_IsImmortal(op);
+#else
+return (op->ob_refcnt >= _Py_IMMORTAL_REFCNT_LOOSE);
+#endif
+}
+#define _Py_IsImmortalLoose(op) _Py_IsImmortalLoose(_PyObject_CAST(op))
+
+
 /* Check if an object is consistent. For example, ensure that the reference
counter is greater than or equal to 1, and ensure that ob_type is not NULL.
 
@@ -134,7 +158,7 @@ PyAPI_FUNC(void) _Py_SetImmortalUntracked(PyObject *op);
 static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt)
 {
 if (op) {
-assert(_Py_IsImmortal(op));
+assert(_Py_IsImmortalLoose(op));
 #ifdef Py_GIL_DISABLED
 op->ob_tid = _Py_UNOWNED_TID;
 op->ob_ref_local = 0;
@@ -266,7 +290,7 @@ _PyObject_Init(PyObject *op, PyTypeObject *typeobj)
 {
 assert(op != NULL);
 Py_SET_TYPE(op, typeobj);
-assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || 
_Py_IsImmortal(typeobj));
+assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || 
_Py_IsImmortalLoose(typeobj));
 Py_INCREF(typeobj);
 _Py_NewReference(op);
 }

___
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-121266: Change dict check_lookup() return type to int (#121581)

2024-07-17 Thread vstinner
https://github.com/python/cpython/commit/51da3dfbf3782ad678624e720ec3fc8dfff27d16
commit: 51da3dfbf3782ad678624e720ec3fc8dfff27d16
branch: main
author: Victor Stinner 
committer: vstinner 
date: 2024-07-17T21:52:19+02:00
summary:

gh-121266: Change dict check_lookup() return type to int (#121581)

files:
M Objects/dictobject.c

diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index ad921fcb113d91..88f3025e5c51dc 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1050,7 +1050,7 @@ lookdict_index(PyDictKeysObject *k, Py_hash_t hash, 
Py_ssize_t index)
 
 static inline Py_ALWAYS_INLINE Py_ssize_t
 do_lookup(PyDictObject *mp, PyDictKeysObject *dk, PyObject *key, Py_hash_t 
hash,
-  Py_ssize_t (*check_lookup)(PyDictObject *, PyDictKeysObject *, void 
*, Py_ssize_t ix, PyObject *key, Py_hash_t))
+  int (*check_lookup)(PyDictObject *, PyDictKeysObject *, void *, 
Py_ssize_t ix, PyObject *key, Py_hash_t))
 {
 void *ep0 = _DK_ENTRIES(dk);
 size_t mask = DK_MASK(dk);
@@ -1060,7 +1060,7 @@ do_lookup(PyDictObject *mp, PyDictKeysObject *dk, 
PyObject *key, Py_hash_t hash,
 for (;;) {
 ix = dictkeys_get_index(dk, i);
 if (ix >= 0) {
-Py_ssize_t cmp = check_lookup(mp, dk, ep0, ix, key, hash);
+int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
 if (cmp < 0) {
 return cmp;
 } else if (cmp) {
@@ -1076,7 +1076,7 @@ do_lookup(PyDictObject *mp, PyDictKeysObject *dk, 
PyObject *key, Py_hash_t hash,
 // Manual loop unrolling
 ix = dictkeys_get_index(dk, i);
 if (ix >= 0) {
-Py_ssize_t cmp = check_lookup(mp, dk, ep0, ix, key, hash);
+int cmp = check_lookup(mp, dk, ep0, ix, key, hash);
 if (cmp < 0) {
 return cmp;
 } else if (cmp) {
@@ -1092,7 +1092,7 @@ do_lookup(PyDictObject *mp, PyDictKeysObject *dk, 
PyObject *key, Py_hash_t hash,
 Py_UNREACHABLE();
 }
 
-static inline Py_ALWAYS_INLINE Py_ssize_t
+static inline Py_ALWAYS_INLINE int
 compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t 
hash)
 {
@@ -1127,7 +1127,7 @@ unicodekeys_lookup_generic(PyDictObject *mp, 
PyDictKeysObject* dk, PyObject *key
 return do_lookup(mp, dk, key, hash, compare_unicode_generic);
 }
 
-static inline Py_ALWAYS_INLINE Py_ssize_t
+static inline Py_ALWAYS_INLINE int
 compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t 
hash)
 {
@@ -1148,7 +1148,7 @@ unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject 
*key, Py_hash_t hash)
 return do_lookup(NULL, dk, key, hash, compare_unicode_unicode);
 }
 
-static inline Py_ALWAYS_INLINE Py_ssize_t
+static inline Py_ALWAYS_INLINE int
 compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
 {
@@ -1343,8 +1343,8 @@ ensure_shared_on_resize(PyDictObject *mp)
 
 #ifdef Py_GIL_DISABLED
 
-static inline Py_ALWAYS_INLINE
-Py_ssize_t compare_unicode_generic_threadsafe(PyDictObject *mp, 
PyDictKeysObject *dk,
+static inline Py_ALWAYS_INLINE int
+compare_unicode_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, 
Py_hash_t hash)
 {
 PyDictUnicodeEntry *ep = &((PyDictUnicodeEntry *)ep0)[ix];
@@ -1386,7 +1386,7 @@ unicodekeys_lookup_generic_threadsafe(PyDictObject *mp, 
PyDictKeysObject* dk, Py
 return do_lookup(mp, dk, key, hash, compare_unicode_generic_threadsafe);
 }
 
-static inline Py_ALWAYS_INLINE Py_ssize_t
+static inline Py_ALWAYS_INLINE int
 compare_unicode_unicode_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, 
Py_hash_t hash)
 {
@@ -1420,8 +1420,8 @@ unicodekeys_lookup_unicode_threadsafe(PyDictKeysObject* 
dk, PyObject *key, Py_ha
 return do_lookup(NULL, dk, key, hash, compare_unicode_unicode_threadsafe);
 }
 
-static inline Py_ALWAYS_INLINE
-Py_ssize_t compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
+static inline Py_ALWAYS_INLINE int
+compare_generic_threadsafe(PyDictObject *mp, PyDictKeysObject *dk,
void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t 
hash)
 {
 PyDictKeyEntry *ep = &((PyDictKeyEntry *)ep0)[ix];

___
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-121528: Fix _PyObject_Init() assertion for stable ABI (GH-121725) (#121936)

2024-07-17 Thread vstinner
https://github.com/python/cpython/commit/f7b2b2a8fb167ee259990bd837db81d5f2b8d5a6
commit: f7b2b2a8fb167ee259990bd837db81d5f2b8d5a6
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: vstinner 
date: 2024-07-17T20:14:22Z
summary:

[3.13] gh-121528: Fix _PyObject_Init() assertion for stable ABI (GH-121725) 
(#121936)

gh-121528: Fix _PyObject_Init() assertion for stable ABI (GH-121725)

Add _Py_IsImmortalLoose() function for assertions.
(cherry picked from commit b826e459ca6b640f896c2a9551bb2c78d10f0e2b)

Co-authored-by: Victor Stinner 

files:
M Include/internal/pycore_object.h

diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 74c1916804aca4..62d63878082386 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -15,6 +15,30 @@ extern "C" {
 #include "pycore_pyatomic_ft_wrappers.h"  // FT_ATOMIC_STORE_PTR_RELAXED
 #include "pycore_pystate.h"   // _PyInterpreterState_GET()
 
+
+#define _Py_IMMORTAL_REFCNT_LOOSE ((_Py_IMMORTAL_REFCNT >> 1) + 1)
+
+// gh-121528, gh-118997: Similar to _Py_IsImmortal() but be more loose when
+// comparing the reference count to stay compatible with C extensions built
+// with the stable ABI 3.11 or older. Such extensions implement INCREF/DECREF
+// as refcnt++ and refcnt-- without taking in account immortal objects. For
+// example, the reference count of an immortal object can change from
+// _Py_IMMORTAL_REFCNT to _Py_IMMORTAL_REFCNT+1 (INCREF) or
+// _Py_IMMORTAL_REFCNT-1 (DECREF).
+//
+// This function should only be used in assertions. Otherwise, _Py_IsImmortal()
+// must be used instead.
+static inline int _Py_IsImmortalLoose(PyObject *op)
+{
+#if defined(Py_GIL_DISABLED)
+return _Py_IsImmortal(op);
+#else
+return (op->ob_refcnt >= _Py_IMMORTAL_REFCNT_LOOSE);
+#endif
+}
+#define _Py_IsImmortalLoose(op) _Py_IsImmortalLoose(_PyObject_CAST(op))
+
+
 /* Check if an object is consistent. For example, ensure that the reference
counter is greater than or equal to 1, and ensure that ob_type is not NULL.
 
@@ -134,7 +158,7 @@ extern void _Py_SetImmortalUntracked(PyObject *op);
 static inline void _Py_SetMortal(PyObject *op, Py_ssize_t refcnt)
 {
 if (op) {
-assert(_Py_IsImmortal(op));
+assert(_Py_IsImmortalLoose(op));
 #ifdef Py_GIL_DISABLED
 op->ob_tid = _Py_UNOWNED_TID;
 op->ob_ref_local = 0;
@@ -281,7 +305,7 @@ _PyObject_Init(PyObject *op, PyTypeObject *typeobj)
 {
 assert(op != NULL);
 Py_SET_TYPE(op, typeobj);
-assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || 
_Py_IsImmortal(typeobj));
+assert(_PyType_HasFeature(typeobj, Py_TPFLAGS_HEAPTYPE) || 
_Py_IsImmortalLoose(typeobj));
 Py_INCREF(typeobj);
 _Py_NewReference(op);
 }

___
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3/lists/python-checkins.python.org/
Member address: [email protected]


[Python-checkins] Add note about PYTHON_JIT environment variable to JIT README (GH-121635)

2024-07-17 Thread brandtbucher
https://github.com/python/cpython/commit/f113c1a2a9d4fb2860de1bd8c05677f00fd49bd9
commit: f113c1a2a9d4fb2860de1bd8c05677f00fd49bd9
branch: main
author: Savannah Ostrowski 
committer: brandtbucher 
date: 2024-07-17T15:17:47-07:00
summary:

Add note about PYTHON_JIT environment variable to JIT README (GH-121635)

files:
M Tools/jit/README.md

diff --git a/Tools/jit/README.md b/Tools/jit/README.md
index 73d2deebbbc216..bc6f793b296f12 100644
--- a/Tools/jit/README.md
+++ b/Tools/jit/README.md
@@ -1,7 +1,7 @@
 The JIT Compiler
 
 
-This version of CPython can be built with an experimental just-in-time 
compiler. While most everything you already know about building and using 
CPython is unchanged, you will probably need to install a compatible version of 
LLVM first.
+This version of CPython can be built with an experimental just-in-time 
compiler[^pep-744]. While most everything you already know about building and 
using CPython is unchanged, you will probably need to install a compatible 
version of LLVM first.
 
 ## Installing LLVM
 
@@ -57,6 +57,10 @@ For `PCbuild`-based builds, pass the new 
`--experimental-jit` option to `build.b
 
 For all other builds, pass the new `--enable-experimental-jit` option to 
`configure`.
 
-Otherwise, just configure and build as you normally would. Cross-compiling 
"just works", since the JIT is built for the host platform.
+Otherwise, just configure and build as you normally would. Cross-compiling 
"just works", since the JIT is built for the host platform. 
+
+The JIT can also be enabled or disabled using the `PYTHON_JIT` environment 
variable, even on builds where it is enabled or disabled by default. More 
details about configuring CPython with the JIT and optional values for 
`--enable-experimental-jit` can be found 
[here](https://docs.python.org/dev/whatsnew/3.13.html#experimental-jit-compiler).
+
+[^pep-744]: [PEP 744](https://peps.python.org/pep-0744/)
 
 [^why-llvm]: Clang is specifically needed because it's the only C compiler 
with support for guaranteed tail calls (`musttail`), which are required by 
CPython's continuation-passing-style approach to JIT compilation. Since LLVM 
also includes other functionalities we need (namely, object file parsing and 
disassembly), it's convenient to only support one toolchain at this time.

___
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] Add note about PYTHON_JIT environment variable to JIT README (GH-121942)

2024-07-17 Thread brandtbucher
https://github.com/python/cpython/commit/a12c10590828cd840679f44ed1a92f2d970eb940
commit: a12c10590828cd840679f44ed1a92f2d970eb940
branch: 3.13
author: Miss Islington (bot) <[email protected]>
committer: brandtbucher 
date: 2024-07-17T22:18:39Z
summary:

[3.13] Add note about PYTHON_JIT environment variable to JIT README (GH-121942)

(cherry picked from commit f113c1a2a9d4fb2860de1bd8c05677f00fd49bd9)
Co-authored-by: Savannah Ostrowski 

files:
M Tools/jit/README.md

diff --git a/Tools/jit/README.md b/Tools/jit/README.md
index 73d2deebbbc216..bc6f793b296f12 100644
--- a/Tools/jit/README.md
+++ b/Tools/jit/README.md
@@ -1,7 +1,7 @@
 The JIT Compiler
 
 
-This version of CPython can be built with an experimental just-in-time 
compiler. While most everything you already know about building and using 
CPython is unchanged, you will probably need to install a compatible version of 
LLVM first.
+This version of CPython can be built with an experimental just-in-time 
compiler[^pep-744]. While most everything you already know about building and 
using CPython is unchanged, you will probably need to install a compatible 
version of LLVM first.
 
 ## Installing LLVM
 
@@ -57,6 +57,10 @@ For `PCbuild`-based builds, pass the new 
`--experimental-jit` option to `build.b
 
 For all other builds, pass the new `--enable-experimental-jit` option to 
`configure`.
 
-Otherwise, just configure and build as you normally would. Cross-compiling 
"just works", since the JIT is built for the host platform.
+Otherwise, just configure and build as you normally would. Cross-compiling 
"just works", since the JIT is built for the host platform. 
+
+The JIT can also be enabled or disabled using the `PYTHON_JIT` environment 
variable, even on builds where it is enabled or disabled by default. More 
details about configuring CPython with the JIT and optional values for 
`--enable-experimental-jit` can be found 
[here](https://docs.python.org/dev/whatsnew/3.13.html#experimental-jit-compiler).
+
+[^pep-744]: [PEP 744](https://peps.python.org/pep-0744/)
 
 [^why-llvm]: Clang is specifically needed because it's the only C compiler 
with support for guaranteed tail calls (`musttail`), which are required by 
CPython's continuation-passing-style approach to JIT compilation. Since LLVM 
also includes other functionalities we need (namely, object file parsing and 
disassembly), it's convenient to only support one toolchain at this time.

___
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-121621: Move asyncio_running_loop to private struct (#121939)

2024-07-17 Thread Yhg1s
https://github.com/python/cpython/commit/81fd625b5c30cc6f417c93bad404923676ad8ca3
commit: 81fd625b5c30cc6f417c93bad404923676ad8ca3
branch: main
author: Sam Gross 
committer: Yhg1s 
date: 2024-07-17T15:21:24-07:00
summary:

gh-121621: Move asyncio_running_loop to private struct (#121939)

This avoids changing the ABI and keeps the field in the private struct.

files:
M Include/cpython/pystate.h
M Include/internal/pycore_tstate.h
M Modules/_asynciomodule.c
M Python/pystate.c

diff --git a/Include/cpython/pystate.h b/Include/cpython/pystate.h
index ce050424cccd49..bb2af78a376d75 100644
--- a/Include/cpython/pystate.h
+++ b/Include/cpython/pystate.h
@@ -68,8 +68,6 @@ struct _ts {
pycore_ceval.h. */
 uintptr_t eval_breaker;
 
-PyObject *asyncio_running_loop; // Strong reference
-
 struct {
 /* Has been initialized to a safe state.
 
diff --git a/Include/internal/pycore_tstate.h b/Include/internal/pycore_tstate.h
index befca950920bac..1ed5b1d826aaa4 100644
--- a/Include/internal/pycore_tstate.h
+++ b/Include/internal/pycore_tstate.h
@@ -21,6 +21,8 @@ typedef struct _PyThreadStateImpl {
 // semi-public fields are in PyThreadState.
 PyThreadState base;
 
+PyObject *asyncio_running_loop; // Strong reference
+
 struct _qsbr_thread_state *qsbr;  // only used by free-threaded build
 struct llist_node mem_free_queue; // delayed free queue
 
diff --git a/Modules/_asynciomodule.c b/Modules/_asynciomodule.c
index 31a45f8169be88..05ac09fe31c48d 100644
--- a/Modules/_asynciomodule.c
+++ b/Modules/_asynciomodule.c
@@ -324,7 +324,7 @@ get_event_loop(asyncio_state *state)
 PyObject *loop;
 PyObject *policy;
 
-PyThreadState *ts = _PyThreadState_GET();
+_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
 loop = Py_XNewRef(ts->asyncio_running_loop);
 
 if (loop != NULL) {
@@ -3278,7 +3278,7 @@ static PyObject *
 _asyncio__get_running_loop_impl(PyObject *module)
 /*[clinic end generated code: output=b4390af721411a0a input=0a21627e25a4bd43]*/
 {
-PyThreadState *ts = _PyThreadState_GET();
+_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
 PyObject *loop = Py_XNewRef(ts->asyncio_running_loop);
 if (loop == NULL) {
 /* There's no currently running event loop */
@@ -3302,7 +3302,7 @@ static PyObject *
 _asyncio__set_running_loop(PyObject *module, PyObject *loop)
 /*[clinic end generated code: output=ae56bf7a28ca189a input=4c9720233d606604]*/
 {
-PyThreadState *ts = _PyThreadState_GET();
+_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
 if (loop == Py_None) {
 loop = NULL;
 }
@@ -3344,7 +3344,7 @@ _asyncio_get_running_loop_impl(PyObject *module)
 /*[clinic end generated code: output=c247b5f9e529530e input=2a3bf02ba39f173d]*/
 {
 PyObject *loop;
-PyThreadState *ts = _PyThreadState_GET();
+_PyThreadStateImpl *ts = (_PyThreadStateImpl *)_PyThreadState_GET();
 loop = Py_XNewRef(ts->asyncio_running_loop);
 if (loop == NULL) {
 /* There's no currently running event loop */
diff --git a/Python/pystate.c b/Python/pystate.c
index f77a2cc54e867a..7a272de11ec761 100644
--- a/Python/pystate.c
+++ b/Python/pystate.c
@@ -1499,7 +1499,7 @@ init_threadstate(_PyThreadStateImpl *_tstate,
 tstate->previous_executor = NULL;
 tstate->dict_global_version = 0;
 
-tstate->asyncio_running_loop = NULL;
+_tstate->asyncio_running_loop = NULL;
 
 tstate->delete_later = NULL;
 
@@ -1702,7 +1702,7 @@ PyThreadState_Clear(PyThreadState *tstate)
 
 /* Don't clear tstate->pyframe: it is a borrowed reference */
 
-Py_CLEAR(tstate->asyncio_running_loop);
+Py_CLEAR(((_PyThreadStateImpl *)tstate)->asyncio_running_loop);
 
 Py_CLEAR(tstate->dict);
 Py_CLEAR(tstate->async_exc);

___
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-119698: fix a special case in `symtable.Class.get_methods` (GH-121802) (#121910)

2024-07-17 Thread JelleZijlstra
https://github.com/python/cpython/commit/3279a4fbfff509a80cc5401b6997e8310ffadd84
commit: 3279a4fbfff509a80cc5401b6997e8310ffadd84
branch: 3.12
author: Miss Islington (bot) <[email protected]>
committer: JelleZijlstra 
date: 2024-07-17T22:32:29Z
summary:

[3.12] gh-119698: fix a special case in `symtable.Class.get_methods` 
(GH-121802) (#121910)

(cherry picked from commit 6682d916780c1cb305e679a057ee6992b114118e)

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

files:
M Lib/symtable.py
M Lib/test/test_symtable.py

diff --git a/Lib/symtable.py b/Lib/symtable.py
index 6c8edff7b417d7..f95639bee3a820 100644
--- a/Lib/symtable.py
+++ b/Lib/symtable.py
@@ -227,6 +227,11 @@ def is_local_symbol(ident):
 if is_local_symbol(st.name):
 match st.type:
 case _symtable.TYPE_FUNCTION:
+# generators are of type TYPE_FUNCTION with a ".0"
+# parameter as a first parameter (which makes them
+# distinguishable from a function named 'genexpr')
+if st.name == 'genexpr' and '.0' in st.varnames:
+continue
 d[st.name] = 1
 case _symtable.TYPE_TYPE_PARAM:
 # Get the function-def block in the annotation
@@ -234,7 +239,14 @@ def is_local_symbol(ident):
 scope_name = st.name
 for c in st.children:
 if c.name == scope_name and c.type == 
_symtable.TYPE_FUNCTION:
-d[st.name] = 1
+# A generic generator of type TYPE_FUNCTION
+# cannot be a direct child of 'st' (but it
+# can be a descendant), e.g.:
+#
+# class A:
+#   type genexpr[genexpr] = (x for x in [])
+assert scope_name != 'genexpr' or '.0' not 
in c.varnames
+d[scope_name] = 1
 break
 self.__methods = tuple(d)
 return self.__methods
diff --git a/Lib/test/test_symtable.py b/Lib/test/test_symtable.py
index b42e8eec713938..fe023fa61ac7be 100644
--- a/Lib/test/test_symtable.py
+++ b/Lib/test/test_symtable.py
@@ -1,6 +1,8 @@
 """
 Test the API of the symtable module.
 """
+
+import textwrap
 import symtable
 import unittest
 
@@ -350,7 +352,7 @@ def test_name(self):
 self.assertEqual(self.spam.lookup("x").get_name(), "x")
 self.assertEqual(self.Mine.get_name(), "Mine")
 
-def test_class_info(self):
+def test_class_get_methods(self):
 self.assertEqual(self.Mine.get_methods(), ('a_method',))
 
 top = symtable.symtable(TEST_COMPLEX_CLASS_CODE, "?", "exec")
@@ -371,6 +373,54 @@ def test_class_info(self):
 'glob_assigned_async_meth', 'glob_assigned_async_meth_pep_695',
 ))
 
+# Test generator expressions that are of type TYPE_FUNCTION
+# but will not be reported by get_methods() since they are
+# not functions per se.
+#
+# Other kind of comprehensions such as list, set or dict
+# expressions do not have the TYPE_FUNCTION type.
+
+def check_body(body, expected_methods):
+indented = textwrap.indent(body, ' ' * 4)
+top = symtable.symtable(f"class A:\n{indented}", "?", "exec")
+this = find_block(top, "A")
+self.assertEqual(this.get_methods(), expected_methods)
+
+# statements with 'genexpr' inside it
+GENEXPRS = (
+'x = (x for x in [])',
+'x = (x async for x in [])',
+'genexpr = (x for x in [])',
+'genexpr = (x async for x in [])',
+)
+
+for gen in GENEXPRS:
+# test generator expression
+with self.subTest(gen=gen):
+check_body(gen, ())
+
+# test generator expression + variable named 'genexpr'
+with self.subTest(gen=gen, isvar=True):
+check_body('\n'.join((gen, 'genexpr = 1')), ())
+check_body('\n'.join(('genexpr = 1', gen)), ())
+
+for paramlist in ('()', '(x)', '(x, y)', '(z: T)'):
+for func in (
+f'def genexpr{paramlist}:pass',
+f'async def genexpr{paramlist}:pass',
+f'def genexpr[T]{paramlist}:pass',
+f'async def genexpr[T]{paramlist}:pass',
+):
+with self.subTest(func=func):
+# test function named 'genexpr'
+check_body(func, ('genexpr',))
+
+for gen in GENEXPRS:
+with self.subT

[Python-checkins] gh-121266: Remove Py_ALWAYS_INLINE in dictobject.c (#121493)

2024-07-17 Thread vstinner
https://github.com/python/cpython/commit/c5a6b9afd82cad3f6abd9dc71cd5fdd5781a53f5
commit: c5a6b9afd82cad3f6abd9dc71cd5fdd5781a53f5
branch: main
author: Victor Stinner 
committer: vstinner 
date: 2024-07-18T08:19:32+02:00
summary:

gh-121266: Remove Py_ALWAYS_INLINE in dictobject.c (#121493)

compare_unicode_generic(), compare_unicode_unicode() and
compare_generic() are callbacks used by do_lookup(). When enabling
assertions, it's not possible to inline these functions.

files:
M Objects/dictobject.c

diff --git a/Objects/dictobject.c b/Objects/dictobject.c
index 88f3025e5c51dc..ca91da7771be9d 100644
--- a/Objects/dictobject.c
+++ b/Objects/dictobject.c
@@ -1092,7 +1092,7 @@ do_lookup(PyDictObject *mp, PyDictKeysObject *dk, 
PyObject *key, Py_hash_t hash,
 Py_UNREACHABLE();
 }
 
-static inline Py_ALWAYS_INLINE int
+static inline int
 compare_unicode_generic(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t 
hash)
 {
@@ -1127,7 +1127,7 @@ unicodekeys_lookup_generic(PyDictObject *mp, 
PyDictKeysObject* dk, PyObject *key
 return do_lookup(mp, dk, key, hash, compare_unicode_generic);
 }
 
-static inline Py_ALWAYS_INLINE int
+static inline int
 compare_unicode_unicode(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t 
hash)
 {
@@ -1148,7 +1148,7 @@ unicodekeys_lookup_unicode(PyDictKeysObject* dk, PyObject 
*key, Py_hash_t hash)
 return do_lookup(NULL, dk, key, hash, compare_unicode_unicode);
 }
 
-static inline Py_ALWAYS_INLINE int
+static inline int
 compare_generic(PyDictObject *mp, PyDictKeysObject *dk,
 void *ep0, Py_ssize_t ix, PyObject *key, Py_hash_t hash)
 {

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