From 0bb4ecafcb54931c4f93cde3b9a590e61ec02c0b Mon Sep 17 00:00:00 2001 From: Lucas Colley Date: Wed, 4 Feb 2026 12:36:14 +0000 Subject: [PATCH 1/6] gh-142903: add conda-forge license for pixi-packages (#143468) Co-authored-by: Adam Turner <9087854+AA-Turner@users.noreply.github.com> Co-authored-by: h-vetinari Co-authored-by: Petr Viktorin Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/license.rst | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/Doc/license.rst b/Doc/license.rst index 269d14cefbcefa..e0683c34967c83 100644 --- a/Doc/license.rst +++ b/Doc/license.rst @@ -1199,3 +1199,39 @@ The d3.js library contains the following notice:: OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + +Pixi packages +------------- + +The Pixi package definitions found in :file:`Tools/pixi-packages` are derived +from https://github.com/conda-forge/python-feedstock which contains the following +license:: + + BSD-3-Clause license + Copyright (c) 2015-2026, conda-forge contributors + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR + ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH + DAMAGE. From 2aea861fe07283fb00f3705d156dac7a852c8f58 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 4 Feb 2026 16:06:35 +0100 Subject: [PATCH 2/6] gh-140824: Fix _Py_DumpExtensionModules() to ignore sub-modules (#144339) Ignore "math.integer" extension if "math" is in sys.stdlib_module_names. --- Lib/test/test_faulthandler.py | 17 +++++++++++-- ...-01-30-13-23-06.gh-issue-140824.J1OCrC.rst | 2 ++ Python/pylifecycle.c | 24 +++++++++++++++---- 3 files changed, 36 insertions(+), 7 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst diff --git a/Lib/test/test_faulthandler.py b/Lib/test/test_faulthandler.py index 874f52af857b94..5e88ae47775dbd 100644 --- a/Lib/test/test_faulthandler.py +++ b/Lib/test/test_faulthandler.py @@ -388,10 +388,11 @@ def test_disable(self): @skip_segfault_on_android def test_dump_ext_modules(self): + # Don't filter stdlib module names: disable sys.stdlib_module_names code = """ import faulthandler import sys - # Don't filter stdlib module names + import math sys.stdlib_module_names = frozenset() faulthandler.enable() faulthandler._sigsegv() @@ -403,9 +404,21 @@ def test_dump_ext_modules(self): if not match: self.fail(f"Cannot find 'Extension modules:' in {stderr!r}") modules = set(match.group(1).strip().split(', ')) - for name in ('sys', 'faulthandler'): + for name in ('sys', 'faulthandler', 'math'): self.assertIn(name, modules) + # Ignore "math.integer" sub-module if "math" package is + # in sys.stdlib_module_names + code = """ + import faulthandler + import math.integer + faulthandler.enable() + faulthandler._sigsegv() + """ + stderr, exitcode = self.get_output(code) + stderr = '\n'.join(stderr) + self.assertNotIn('Extension modules:', stderr) + def test_is_enabled(self): orig_stderr = sys.stderr try: diff --git a/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst b/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst new file mode 100644 index 00000000000000..dd90b6a21d135d --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-01-30-13-23-06.gh-issue-140824.J1OCrC.rst @@ -0,0 +1,2 @@ +When :mod:`faulthandler` dumps the list of third-party extension modules, +ignore sub-modules of stdlib packages. Patch by Victor Stinner. diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index d3ed08de1d15d3..bb51f8d191c1c3 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -3393,11 +3393,25 @@ _Py_DumpExtensionModules(int fd, PyInterpreterState *interp) Py_hash_t hash; // if stdlib_module_names is not NULL, it is always a frozenset. while (_PySet_NextEntry(stdlib_module_names, &i, &item, &hash)) { - if (PyUnicode_Check(item) - && PyUnicode_Compare(key, item) == 0) - { - is_stdlib_ext = 1; - break; + if (!PyUnicode_Check(item)) { + continue; + } + Py_ssize_t len = PyUnicode_GET_LENGTH(item); + if (PyUnicode_Tailmatch(key, item, 0, len, -1) == 1) { + Py_ssize_t key_len = PyUnicode_GET_LENGTH(key); + if (key_len == len) { + is_stdlib_ext = 1; + break; + } + assert(key_len > len); + + // Ignore sub-modules of stdlib packages. For example, + // ignore "math.integer" if key starts with "math.". + Py_UCS4 ch = PyUnicode_ReadChar(key, len); + if (ch == '.') { + is_stdlib_ext = 1; + break; + } } } if (is_stdlib_ext) { From e423e0c2cc06fd36689f45b9e818f2455c20e682 Mon Sep 17 00:00:00 2001 From: Petr Viktorin Date: Wed, 4 Feb 2026 17:08:23 +0100 Subject: [PATCH 3/6] gh-141984: Reword and reorganize Subscription (and Slicing) docs (GH-141985) Co-authored-by: Blaise Pabon Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/glossary.rst | 33 ++++- Doc/library/functions.rst | 20 +-- Doc/reference/datamodel.rst | 88 +++++++---- Doc/reference/expressions.rst | 257 +++++++++++++++++++++------------ Doc/reference/simple_stmts.rst | 41 +++--- 5 files changed, 283 insertions(+), 156 deletions(-) diff --git a/Doc/glossary.rst b/Doc/glossary.rst index 7c41f5bc27b070..24b95b88dfb651 100644 --- a/Doc/glossary.rst +++ b/Doc/glossary.rst @@ -786,6 +786,19 @@ Glossary An object that both finds and loads a module; both a :term:`finder` and :term:`loader` object. + index + A numeric value that represents the position of an element in + a :term:`sequence`. + + In Python, indexing starts at zero. + For example, ``things[0]`` names the *first* element of ``things``; + ``things[1]`` names the second one. + + In some contexts, Python allows negative indexes for counting from the + end of a sequence, and indexing using :term:`slices `. + + See also :term:`subscript`. + interactive Python has an interactive interpreter which means you can enter statements and expressions at the interpreter prompt, immediately @@ -863,6 +876,9 @@ Glossary CPython does not guarantee :term:`thread-safe` behavior of iterator operations. + key + A value that identifies an entry in a :term:`mapping`. + See also :term:`subscript`. key function A key function or collation function is a callable that returns a value @@ -1417,10 +1433,11 @@ Glossary chosen based on the type of a single argument. slice - An object usually containing a portion of a :term:`sequence`. A slice is - created using the subscript notation, ``[]`` with colons between numbers - when several are given, such as in ``variable_name[1:3:5]``. The bracket - (subscript) notation uses :class:`slice` objects internally. + An object of type :class:`slice`, used to describe a portion of + a :term:`sequence`. + A slice object is created when using the :ref:`slicing ` form + of :ref:`subscript notation `, with colons inside square + brackets, such as in ``variable_name[1:3:5]``. soft deprecated A soft deprecated API should not be used in new code, @@ -1478,6 +1495,14 @@ Glossary See also :term:`borrowed reference`. + subscript + The expression in square brackets of a + :ref:`subscription expression `, for example, + the ``3`` in ``items[3]``. + Usually used to select an element of a container. + Also called a :term:`key` when subscripting a :term:`mapping`, + or an :term:`index` when subscripting a :term:`sequence`. + synchronization primitive A basic building block for coordinating (synchronizing) the execution of multiple threads to ensure :term:`thread-safe` access to shared resources. diff --git a/Doc/library/functions.rst b/Doc/library/functions.rst index cd819b8d06480a..65b8ffdb23111d 100644 --- a/Doc/library/functions.rst +++ b/Doc/library/functions.rst @@ -1824,19 +1824,19 @@ are always available. They are listed here in alphabetical order. ``range(start, stop, step)``. The *start* and *step* arguments default to ``None``. - Slice objects have read-only data attributes :attr:`!start`, - :attr:`!stop`, and :attr:`!step` which merely return the argument - values (or their default). They have no other explicit functionality; - however, they are used by NumPy and other third-party packages. + Slice objects are also generated when :ref:`slicing syntax ` + is used. For example: ``a[start:stop:step]`` or ``a[start:stop, i]``. + + See :func:`itertools.islice` for an alternate version that returns an + :term:`iterator`. .. attribute:: slice.start - .. attribute:: slice.stop - .. attribute:: slice.step + slice.stop + slice.step - Slice objects are also generated when extended indexing syntax is used. For - example: ``a[start:stop:step]`` or ``a[start:stop, i]``. See - :func:`itertools.islice` for an alternate version that returns an - :term:`iterator`. + These read-only attributes are set to the argument values + (or their default). They have no other explicit functionality; + however, they are used by NumPy and other third-party packages. .. versionchanged:: 3.12 Slice objects are now :term:`hashable` (provided :attr:`~slice.start`, diff --git a/Doc/reference/datamodel.rst b/Doc/reference/datamodel.rst index f784d963f9d3e1..27aedfa878af9a 100644 --- a/Doc/reference/datamodel.rst +++ b/Doc/reference/datamodel.rst @@ -290,6 +290,7 @@ floating-point numbers. The same caveats apply as for floating-point numbers. The real and imaginary parts of a complex number ``z`` can be retrieved through the read-only attributes ``z.real`` and ``z.imag``. +.. _datamodel-sequences: Sequences --------- @@ -309,12 +310,25 @@ including built-in sequences, interpret negative subscripts by adding the sequence length. For example, ``a[-2]`` equals ``a[n-2]``, the second to last item of sequence a with length ``n``. -.. index:: single: slicing +The resulting value must be a nonnegative integer less than the number of items +in the sequence. If it is not, an :exc:`IndexError` is raised. -Sequences also support slicing: ``a[i:j]`` selects all items with index *k* such -that *i* ``<=`` *k* ``<`` *j*. When used as an expression, a slice is a -sequence of the same type. The comment above about negative indexes also applies +.. index:: + single: slicing + single: start (slice object attribute) + single: stop (slice object attribute) + single: step (slice object attribute) + +Sequences also support slicing: ``a[start:stop]`` selects all items with index *k* such +that *start* ``<=`` *k* ``<`` *stop*. When used as an expression, a slice is a +sequence of the same type. The comment above about negative subscripts also applies to negative slice positions. +Note that no error is raised if a slice position is less than zero or larger +than the length of the sequence. + +If *start* is missing or :data:`None`, slicing behaves as if *start* was zero. +If *stop* is missing or ``None``, slicing behaves as if *stop* was equal to +the length of the sequence. Some sequences also support "extended slicing" with a third "step" parameter: ``a[i:j:k]`` selects all items of *a* with index *x* where ``x = i + n*k``, *n* @@ -345,17 +359,22 @@ Strings pair: built-in function; chr pair: built-in function; ord single: character - single: integer + pair: string; item single: Unicode - A string is a sequence of values that represent Unicode code points. - All the code points in the range ``U+0000 - U+10FFFF`` can be - represented in a string. Python doesn't have a :c:expr:`char` type; - instead, every code point in the string is represented as a string - object with length ``1``. The built-in function :func:`ord` + A string (:class:`str`) is a sequence of values that represent + :dfn:`characters`, or more formally, *Unicode code points*. + All the code points in the range ``0`` to ``0x10FFFF`` can be + represented in a string. + + Python doesn't have a dedicated *character* type. + Instead, every code point in the string is represented as a string + object with length ``1``. + + The built-in function :func:`ord` converts a code point from its string form to an integer in the - range ``0 - 10FFFF``; :func:`chr` converts an integer in the range - ``0 - 10FFFF`` to the corresponding length ``1`` string object. + range ``0`` to ``0x10FFFF``; :func:`chr` converts an integer in the range + ``0`` to ``0x10FFFF`` to the corresponding length ``1`` string object. :meth:`str.encode` can be used to convert a :class:`str` to :class:`bytes` using the given text encoding, and :meth:`bytes.decode` can be used to achieve the opposite. @@ -366,7 +385,7 @@ Tuples pair: singleton; tuple pair: empty; tuple - The items of a tuple are arbitrary Python objects. Tuples of two or + The items of a :class:`tuple` are arbitrary Python objects. Tuples of two or more items are formed by comma-separated lists of expressions. A tuple of one item (a 'singleton') can be formed by affixing a comma to an expression (an expression by itself does not create a tuple, since @@ -376,7 +395,7 @@ Tuples Bytes .. index:: bytes, byte - A bytes object is an immutable array. The items are 8-bit bytes, + A :class:`bytes` object is an immutable array. The items are 8-bit bytes, represented by integers in the range 0 <= x < 256. Bytes literals (like ``b'abc'``) and the built-in :func:`bytes` constructor can be used to create bytes objects. Also, bytes objects can be @@ -461,6 +480,8 @@ Frozen sets a dictionary key. +.. _datamodel-mappings: + Mappings -------- @@ -3217,28 +3238,39 @@ through the object's keys; for sequences, it should iterate through the values. and so forth. Missing slice items are always filled in with ``None``. -.. method:: object.__getitem__(self, key) +.. method:: object.__getitem__(self, subscript) + + Called to implement *subscription*, that is, ``self[subscript]``. + See :ref:`subscriptions` for details on the syntax. + + There are two types of built-in objects that support subscription + via :meth:`!__getitem__`: + + - **sequences**, where *subscript* (also called + :term:`index`) should be an integer or a :class:`slice` object. + See the :ref:`sequence documentation ` for the expected + behavior, including handling :class:`slice` objects and negative indices. + - **mappings**, where *subscript* is also called the :term:`key`. + See :ref:`mapping documentation ` for the expected + behavior. - Called to implement evaluation of ``self[key]``. For :term:`sequence` types, - the accepted keys should be integers. Optionally, they may support - :class:`slice` objects as well. Negative index support is also optional. - If *key* is - of an inappropriate type, :exc:`TypeError` may be raised; if *key* is a value - outside the set of indexes for the sequence (after any special - interpretation of negative values), :exc:`IndexError` should be raised. For - :term:`mapping` types, if *key* is missing (not in the container), - :exc:`KeyError` should be raised. + If *subscript* is of an inappropriate type, :meth:`!__getitem__` + should raise :exc:`TypeError`. + If *subscript* has an inappropriate value, :meth:`!__getitem__` + should raise an :exc:`LookupError` or one of its subclasses + (:exc:`IndexError` for sequences; :exc:`KeyError` for mappings). .. note:: - :keyword:`for` loops expect that an :exc:`IndexError` will be raised for - illegal indexes to allow proper detection of the end of the sequence. + The sequence iteration protocol (used, for example, in :keyword:`for` + loops), expects that an :exc:`IndexError` will be raised for illegal + indexes to allow proper detection of the end of a sequence. .. note:: - When :ref:`subscripting` a *class*, the special + When :ref:`subscripting ` a *class*, the special class method :meth:`~object.__class_getitem__` may be called instead of - ``__getitem__()``. See :ref:`classgetitem-versus-getitem` for more + :meth:`!__getitem__`. See :ref:`classgetitem-versus-getitem` for more details. diff --git a/Doc/reference/expressions.rst b/Doc/reference/expressions.rst index 32f2d4596fe632..281d032b2a0f16 100644 --- a/Doc/reference/expressions.rst +++ b/Doc/reference/expressions.rst @@ -911,7 +911,7 @@ Primaries represent the most tightly bound operations of the language. Their syntax is: .. productionlist:: python-grammar - primary: `atom` | `attributeref` | `subscription` | `slicing` | `call` + primary: `atom` | `attributeref` | `subscription` | `call` .. _attribute-references: @@ -950,8 +950,8 @@ method, that method is called as a fallback. .. _subscriptions: -Subscriptions -------------- +Subscriptions and slicings +-------------------------- .. index:: single: subscription @@ -966,67 +966,74 @@ Subscriptions pair: object; dictionary pair: sequence; item -The subscription of an instance of a :ref:`container class ` -will generally select an element from the container. The subscription of a -:term:`generic class ` will generally return a -:ref:`GenericAlias ` object. +The :dfn:`subscription` syntax is usually used for selecting an element from a +:ref:`container ` -- for example, to get a value from +a :class:`dict`:: -.. productionlist:: python-grammar - subscription: `primary` "[" `flexible_expression_list` "]" - -When an object is subscripted, the interpreter will evaluate the primary and -the expression list. + >>> digits_by_name = {'one': 1, 'two': 2} + >>> digits_by_name['two'] # Subscripting a dictionary using the key 'two' + 2 -The primary must evaluate to an object that supports subscription. An object -may support subscription through defining one or both of -:meth:`~object.__getitem__` and :meth:`~object.__class_getitem__`. When the -primary is subscripted, the evaluated result of the expression list will be -passed to one of these methods. For more details on when ``__class_getitem__`` -is called instead of ``__getitem__``, see :ref:`classgetitem-versus-getitem`. +In the subscription syntax, the object being subscribed -- a +:ref:`primary ` -- is followed by a :dfn:`subscript` in +square brackets. +In the simplest case, the subscript is a single expression. + +Depending on the type of the object being subscribed, the subscript is +sometimes called a :term:`key` (for mappings), :term:`index` (for sequences), +or *type argument* (for :term:`generic types `). +Syntactically, these are all equivalent:: + + >>> colors = ['red', 'blue', 'green', 'black'] + >>> colors[3] # Subscripting a list using the index 3 + 'black' + + >>> list[str] # Parameterizing the list type using the type argument str + list[str] + +At runtime, the interpreter will evaluate the primary and +the subscript, and call the primary's :meth:`~object.__getitem__` or +:meth:`~object.__class_getitem__` :term:`special method` with the subscript +as argument. +For more details on which of these methods is called, see +:ref:`classgetitem-versus-getitem`. + +To show how subscription works, we can define a custom object that +implements :meth:`~object.__getitem__` and prints out the value of +the subscript:: + + >>> class SubscriptionDemo: + ... def __getitem__(self, key): + ... print(f'subscripted with: {key!r}') + ... + >>> demo = SubscriptionDemo() + >>> demo[1] + subscripted with: 1 + >>> demo['a' * 3] + subscripted with: 'aaa' -If the expression list contains at least one comma, or if any of the expressions -are starred, the expression list will evaluate to a :class:`tuple` containing -the items of the expression list. Otherwise, the expression list will evaluate -to the value of the list's sole member. +See :meth:`~object.__getitem__` documentation for how built-in types handle +subscription. -.. versionchanged:: 3.11 - Expressions in an expression list may be starred. See :pep:`646`. - -For built-in objects, there are two types of objects that support subscription -via :meth:`~object.__getitem__`: - -1. Mappings. If the primary is a :term:`mapping`, the expression list must - evaluate to an object whose value is one of the keys of the mapping, and the - subscription selects the value in the mapping that corresponds to that key. - An example of a builtin mapping class is the :class:`dict` class. -2. Sequences. If the primary is a :term:`sequence`, the expression list must - evaluate to an :class:`int` or a :class:`slice` (as discussed in the - following section). Examples of builtin sequence classes include the - :class:`str`, :class:`list` and :class:`tuple` classes. - -The formal syntax makes no special provision for negative indices in -:term:`sequences `. However, built-in sequences all provide a :meth:`~object.__getitem__` -method that interprets negative indices by adding the length of the sequence -to the index so that, for example, ``x[-1]`` selects the last item of ``x``. The -resulting value must be a nonnegative integer less than the number of items in -the sequence, and the subscription selects the item whose index is that value -(counting from zero). Since the support for negative indices and slicing -occurs in the object's :meth:`~object.__getitem__` method, subclasses overriding -this method will need to explicitly add that support. +Subscriptions may also be used as targets in :ref:`assignment ` or +:ref:`deletion ` statements. +In these cases, the interpreter will call the subscripted object's +:meth:`~object.__setitem__` or :meth:`~object.__delitem__` +:term:`special method`, respectively, instead of :meth:`~object.__getitem__`. -.. index:: - single: character - pair: string; item +.. code-block:: -A :class:`string ` is a special kind of sequence whose items are -*characters*. A character is not a separate data type but a -string of exactly one character. + >>> colors = ['red', 'blue', 'green', 'black'] + >>> colors[3] = 'white' # Setting item at index + >>> colors + ['red', 'blue', 'green', 'white'] + >>> del colors[3] # Deleting item at index 3 + >>> colors + ['red', 'blue', 'green'] +All advanced forms of *subscript* documented in the following sections +are also usable for assignment and deletion. -.. _slicings: - -Slicings --------- .. index:: single: slicing @@ -1040,43 +1047,111 @@ Slicings pair: object; tuple pair: object; list -A slicing selects a range of items in a sequence object (e.g., a string, tuple -or list). Slicings may be used as expressions or as targets in assignment or -:keyword:`del` statements. The syntax for a slicing: +.. _slicings: -.. productionlist:: python-grammar - slicing: `primary` "[" `slice_list` "]" - slice_list: `slice_item` ("," `slice_item`)* [","] - slice_item: `expression` | `proper_slice` - proper_slice: [`lower_bound`] ":" [`upper_bound`] [ ":" [`stride`] ] - lower_bound: `expression` - upper_bound: `expression` - stride: `expression` - -There is ambiguity in the formal syntax here: anything that looks like an -expression list also looks like a slice list, so any subscription can be -interpreted as a slicing. Rather than further complicating the syntax, this is -disambiguated by defining that in this case the interpretation as a subscription -takes priority over the interpretation as a slicing (this is the case if the -slice list contains no proper slice). +Slicings +^^^^^^^^ -.. index:: - single: start (slice object attribute) - single: stop (slice object attribute) - single: step (slice object attribute) - -The semantics for a slicing are as follows. The primary is indexed (using the -same :meth:`~object.__getitem__` method as -normal subscription) with a key that is constructed from the slice list, as -follows. If the slice list contains at least one comma, the key is a tuple -containing the conversion of the slice items; otherwise, the conversion of the -lone slice item is the key. The conversion of a slice item that is an -expression is that expression. The conversion of a proper slice is a slice -object (see section :ref:`types`) whose :attr:`~slice.start`, -:attr:`~slice.stop` and :attr:`~slice.step` attributes are the values of the -expressions given as lower bound, upper bound and stride, respectively, -substituting ``None`` for missing expressions. +A more advanced form of subscription, :dfn:`slicing`, is commonly used +to extract a portion of a :ref:`sequence `. +In this form, the subscript is a :term:`slice`: up to three +expressions separated by colons. +Any of the expressions may be omitted, but a slice must contain at least one +colon:: + + >>> number_names = ['zero', 'one', 'two', 'three', 'four', 'five'] + >>> number_names[1:3] + ['one', 'two'] + >>> number_names[1:] + ['one', 'two', 'three', 'four', 'five'] + >>> number_names[:3] + ['zero', 'one', 'two'] + >>> number_names[:] + ['zero', 'one', 'two', 'three', 'four', 'five'] + >>> number_names[::2] + ['zero', 'two', 'four'] + >>> number_names[:-3] + ['zero', 'one', 'two'] + >>> del number_names[4:] + >>> number_names + ['zero', 'one', 'two', 'three'] + +When a slice is evaluated, the interpreter constructs a :class:`slice` object +whose :attr:`~slice.start`, :attr:`~slice.stop` and +:attr:`~slice.step` attributes, respectively, are the results of the +expressions between the colons. +Any missing expression evaluates to :const:`None`. +This :class:`!slice` object is then passed to the :meth:`~object.__getitem__` +or :meth:`~object.__class_getitem__` :term:`special method`, as above. :: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[2:3] + subscripted with: slice(2, 3, None) + >>> demo[::'spam'] + subscripted with: slice(None, None, 'spam') + + +Comma-separated subscripts +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The subscript can also be given as two or more comma-separated expressions +or slices:: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[1, 2, 3] + subscripted with: (1, 2, 3) + >>> demo[1:2, 3] + subscripted with: (slice(1, 2, None), 3) + +This form is commonly used with numerical libraries for slicing +multi-dimensional data. +In this case, the interpreter constructs a :class:`tuple` of the results of the +expressions or slices, and passes this tuple to the :meth:`~object.__getitem__` +or :meth:`~object.__class_getitem__` :term:`special method`, as above. + +The subscript may also be given as a single expression or slice followed +by a comma, to specify a one-element tuple:: + + >>> demo['spam',] + subscripted with: ('spam',) + + +"Starred" subscriptions +^^^^^^^^^^^^^^^^^^^^^^^ + +.. versionadded:: 3.11 + Expressions in *tuple_slices* may be starred. See :pep:`646`. + +The subscript can also contain a starred expression. +In this case, the interpreter unpacks the result into a tuple, and passes +this tuple to :meth:`~object.__getitem__` or :meth:`~object.__class_getitem__`:: + + # continuing with the SubscriptionDemo instance defined above: + >>> demo[*range(10)] + subscripted with: (0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + +Starred expressions may be combined with comma-separated expressions +and slices:: + + >>> demo['a', 'b', *range(3), 'c'] + subscripted with: ('a', 'b', 0, 1, 2, 'c') + + +Formal subscription grammar +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. grammar-snippet:: + :group: python-grammar + + subscription: `primary` '[' `subscript` ']' + subscript: `single_subscript` | `tuple_subscript` + single_subscript: `proper_slice` | `assignment_expression` + proper_slice: [`expression`] ":" [`expression`] [ ":" [`expression`] ] + tuple_subscript: ','.(`single_subscript` | `starred_expression`)+ [','] +Recall that the ``|`` operator :ref:`denotes ordered choice `. +Specifically, in :token:`!subscript`, if both alternatives would match, the +first (:token:`!single_subscript`) has priority. .. index:: pair: object; callable @@ -2094,7 +2169,7 @@ precedence and have a left-to-right chaining feature as described in the | ``{key: value...}``, | dictionary display, | | ``{expressions...}`` | set display | +-----------------------------------------------+-------------------------------------+ -| ``x[index]``, ``x[index:index]``, | Subscription, slicing, | +| ``x[index]``, ``x[index:index]`` | Subscription (including slicing), | | ``x(arguments...)``, ``x.attribute`` | call, attribute reference | +-----------------------------------------------+-------------------------------------+ | :keyword:`await x ` | Await expression | diff --git a/Doc/reference/simple_stmts.rst b/Doc/reference/simple_stmts.rst index 9c022570e7e847..643ca106548367 100644 --- a/Doc/reference/simple_stmts.rst +++ b/Doc/reference/simple_stmts.rst @@ -91,11 +91,10 @@ attributes or items of mutable objects: : | "[" [`target_list`] "]" : | `attributeref` : | `subscription` - : | `slicing` : | "*" `target` -(See section :ref:`primaries` for the syntax definitions for *attributeref*, -*subscription*, and *slicing*.) +(See section :ref:`primaries` for the syntax definitions for *attributeref* +and *subscription*.) An assignment statement evaluates the expression list (remember that this can be a single expression or a comma-separated list, the latter yielding a tuple) and @@ -107,8 +106,8 @@ right. pair: target; list Assignment is defined recursively depending on the form of the target (list). -When a target is part of a mutable object (an attribute reference, subscription -or slicing), the mutable object must ultimately perform the assignment and +When a target is part of a mutable object (an attribute reference or +subscription), the mutable object must ultimately perform the assignment and decide about its validity, and may raise an exception if the assignment is unacceptable. The rules observed by various types and the exceptions raised are given with the definition of the object types (see section :ref:`types`). @@ -189,9 +188,14 @@ Assignment of an object to a single target is recursively defined as follows. pair: object; mutable * If the target is a subscription: The primary expression in the reference is - evaluated. It should yield either a mutable sequence object (such as a list) - or a mapping object (such as a dictionary). Next, the subscript expression is evaluated. + Next, the subscript expression is evaluated. + Then, the primary's :meth:`~object.__setitem__` method is called with + two arguments: the subscript and the assigned object. + + Typically, :meth:`~object.__setitem__` is defined on mutable sequence objects + (such as lists) and mapping objects (such as dictionaries), and behaves as + follows. .. index:: pair: object; sequence @@ -214,16 +218,13 @@ Assignment of an object to a single target is recursively defined as follows. object. This can either replace an existing key/value pair with the same key value, or insert a new key/value pair (if no key with the same value existed). - For user-defined objects, the :meth:`~object.__setitem__` method is called with - appropriate arguments. - .. index:: pair: slicing; assignment -* If the target is a slicing: The primary expression in the reference is - evaluated. It should yield a mutable sequence object (such as a list). The - assigned object should be a sequence object of the same type. Next, the lower - and upper bound expressions are evaluated, insofar they are present; defaults - are zero and the sequence's length. The bounds should evaluate to integers. + If the target is a slicing: The primary expression should evaluate to + a mutable sequence object (such as a list). + The assigned object should be :term:`iterable`. + The slicing's lower and upper bounds should be integers; if they are ``None`` + (or not present), the defaults are zero and the sequence's length. If either bound is negative, the sequence's length is added to it. The resulting bounds are clipped to lie between zero and the sequence's length, inclusive. Finally, the sequence object is asked to replace the slice with @@ -231,12 +232,6 @@ Assignment of an object to a single target is recursively defined as follows. from the length of the assigned sequence, thus changing the length of the target sequence, if the target sequence allows it. -.. impl-detail:: - - In the current implementation, the syntax for targets is taken to be the same - as for expressions, and invalid syntax is rejected during the code generation - phase, causing less detailed error messages. - Although the definition of assignment implies that overlaps between the left-hand side and the right-hand side are 'simultaneous' (for example ``a, b = b, a`` swaps two variables), overlaps *within* the collection of assigned-to @@ -281,7 +276,7 @@ operation and an assignment statement: .. productionlist:: python-grammar augmented_assignment_stmt: `augtarget` `augop` (`expression_list` | `yield_expression`) - augtarget: `identifier` | `attributeref` | `subscription` | `slicing` + augtarget: `identifier` | `attributeref` | `subscription` augop: "+=" | "-=" | "*=" | "@=" | "/=" | "//=" | "%=" | "**=" : | ">>=" | "<<=" | "&=" | "^=" | "|=" @@ -470,7 +465,7 @@ in the same code block. Trying to delete an unbound name raises a .. index:: pair: attribute; deletion -Deletion of attribute references, subscriptions and slicings is passed to the +Deletion of attribute references and subscriptions is passed to the primary object involved; deletion of a slicing is in general equivalent to assignment of an empty slice of the right type (but even this is determined by the sliced object). From 914fbec21458a0344468734489f29254033fafc5 Mon Sep 17 00:00:00 2001 From: Peter Bierma Date: Wed, 4 Feb 2026 11:43:47 -0500 Subject: [PATCH 4/6] gh-141004: Document remaining `pyport.h` utility macros (GH-144279) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bénédikt Tran <10796600+picnixz@users.noreply.github.com> Co-authored-by: Victor Stinner --- Doc/c-api/intro.rst | 96 ++++++++++++++++++++++++ Tools/check-c-api-docs/ignored_c_api.txt | 9 --- 2 files changed, 96 insertions(+), 9 deletions(-) diff --git a/Doc/c-api/intro.rst b/Doc/c-api/intro.rst index 6886cd85b09a7d..9828e537a90654 100644 --- a/Doc/c-api/intro.rst +++ b/Doc/c-api/intro.rst @@ -167,6 +167,35 @@ complete listing. .. versionadded:: 3.3 +.. c:macro:: Py_ALIGNED(num) + + Specify alignment to *num* bytes on compilers that support it. + + Consider using the C11 standard ``_Alignas`` specifier over this macro. + +.. c:macro:: Py_ARITHMETIC_RIGHT_SHIFT(type, integer, positions) + + Similar to ``integer >> positions``, but forces sign extension, as the C + standard does not define whether a right-shift of a signed integer will + perform sign extension or a zero-fill. + + *integer* should be any signed integer type. + *positions* is the number of positions to shift to the right. + + Both *integer* and *positions* can be evaluated more than once; + consequently, avoid directly passing a function call or some other + operation with side-effects to this macro. Instead, store the result as a + variable and then pass it. + + *type* is unused and only kept for backwards compatibility. Historically, + *type* was used to cast *integer*. + + .. versionchanged:: 3.1 + + This macro is now valid for all signed integer types, not just those for + which ``unsigned type`` is legal. As a result, *type* is no longer + used. + .. c:macro:: Py_ALWAYS_INLINE Ask the compiler to always inline a static inline function. The compiler can @@ -189,6 +218,15 @@ complete listing. .. versionadded:: 3.11 +.. c:macro:: Py_CAN_START_THREADS + + If this macro is defined, then the current system is able to start threads. + + Currently, all systems supported by CPython (per :pep:`11`), with the + exception of some WebAssembly platforms, support starting threads. + + .. versionadded:: 3.13 + .. c:macro:: Py_CHARMASK(c) Argument must be a character or an integer in the range [-128, 127] or [0, @@ -206,11 +244,35 @@ complete listing. .. versionchanged:: 3.8 MSVC support was added. +.. c:macro:: Py_FORCE_EXPANSION(X) + + This is equivalent to ``X``, which is useful for token-pasting in + macros, as macro expansions in *X* are forcefully evaluated by the + preprocessor. + +.. c:macro:: Py_GCC_ATTRIBUTE(name) + + Use a GCC attribute *name*, hiding it from compilers that don't support GCC + attributes (such as MSVC). + + This expands to ``__attribute__((name))`` on a GCC compiler, and expands + to nothing on compilers that don't support GCC attributes. + .. c:macro:: Py_GETENV(s) Like ``getenv(s)``, but returns ``NULL`` if :option:`-E` was passed on the command line (see :c:member:`PyConfig.use_environment`). +.. c:macro:: Py_LL(number) + + Use *number* as a ``long long`` integer literal. + + This usally expands to *number* followed by ``LL``, but will expand to some + compiler-specific suffixes (such as ``I64``) on older compilers. + + In modern versions of Python, this macro is not very useful, as C99 and + later require the ``LL`` suffix to be valid for an integer. + .. c:macro:: Py_LOCAL(type) Declare a function returning the specified *type* using a fast-calling @@ -268,6 +330,22 @@ complete listing. .. versionadded:: 3.11 +.. c:macro:: Py_SAFE_DOWNCAST(value, larger, smaller) + + Cast *value* to type *smaller* from type *larger*, validating that no + information was lost. + + On release builds of Python, this is roughly equivalent to + ``(smaller) value`` (in C++, ``static_cast(value)`` will be + used instead). + + On debug builds (implying that :c:macro:`Py_DEBUG` is defined), this asserts + that no information was lost with the cast from *larger* to *smaller*. + + *value*, *larger*, and *smaller* may all be evaluated more than once in the + expression; consequently, do not pass an expression with side-effects directly to + this macro. + .. c:macro:: Py_STRINGIFY(x) Convert ``x`` to a C string. E.g. ``Py_STRINGIFY(123)`` returns @@ -275,6 +353,14 @@ complete listing. .. versionadded:: 3.4 +.. c:macro:: Py_ULL(number) + + Similar to :c:macro:`Py_LL`, but *number* will be an ``unsigned long long`` + literal instead. This is done by appending ``U`` to the result of ``Py_LL``. + + In modern versions of Python, this macro is not very useful, as C99 and + later require the ``ULL``/``LLU`` suffixes to be valid for an integer. + .. c:macro:: Py_UNREACHABLE() Use this when you have a code path that cannot be reached by design. @@ -415,6 +501,16 @@ complete listing. This macro is intended for defining CPython's C API itself; extension modules should not use it for their own symbols. +.. c:macro:: Py_VA_COPY + + This is a :term:`soft deprecated` alias to the C99-standard ``va_copy`` + function. + + Historically, this would use a compiler-specific method to copy a ``va_list``. + + .. versionchanged:: 3.6 + This is now an alias to ``va_copy``. + .. _api-objects: diff --git a/Tools/check-c-api-docs/ignored_c_api.txt b/Tools/check-c-api-docs/ignored_c_api.txt index e0b2670808c79c..e628bdfebcbded 100644 --- a/Tools/check-c-api-docs/ignored_c_api.txt +++ b/Tools/check-c-api-docs/ignored_c_api.txt @@ -31,15 +31,6 @@ Py_TPFLAGS_IS_ABSTRACT PyExpat_CAPI_MAGIC PyExpat_CAPSULE_NAME # pyport.h -Py_ALIGNED -Py_ARITHMETIC_RIGHT_SHIFT -Py_CAN_START_THREADS -Py_FORCE_EXPANSION -Py_GCC_ATTRIBUTE -Py_LL -Py_SAFE_DOWNCAST -Py_ULL -Py_VA_COPY PYLONG_BITS_IN_DIGIT PY_DWORD_MAX PY_FORMAT_SIZE_T From 1b6d737ee0205521333cf5fe6ca6df2d3a6d4ec2 Mon Sep 17 00:00:00 2001 From: Adorilson Bezerra Date: Wed, 4 Feb 2026 17:17:42 +0000 Subject: [PATCH 5/6] gh-106318: Add examples for `str.startswith()` method (#144369) Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com> --- Doc/library/stdtypes.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 99479091cd5bd2..0f20163e69509c 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -2751,6 +2751,19 @@ expression support in the :mod:`re` module). test string beginning at that position. With optional *end*, stop comparing string at that position. + For example: + + .. doctest:: + + >>> 'Python'.startswith('Py') + True + >>> 'a tuple of prefixes'.startswith(('at', 'a')) + True + >>> 'Python is amazing'.startswith('is', 7) + True + + See also :meth:`endswith` and :meth:`removeprefix`. + .. method:: str.strip(chars=None, /) From dd0fde58cce1e664c095949404d91807e1b45c55 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Wed, 4 Feb 2026 19:23:09 +0200 Subject: [PATCH 6/6] gh-143962: Improve name suggestions for not normalized names (GH-144154) Suggest the normalized name or the closest name to the normalized name. If the suggested name is not ASCII, include also its ASCII representation. --- Lib/test/test_traceback.py | 46 +++++++++++++++++++ Lib/traceback.py | 21 ++++++++- ...-01-22-17-04-30.gh-issue-143962.dQR1a9.rst | 3 ++ 3 files changed, 68 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst diff --git a/Lib/test/test_traceback.py b/Lib/test/test_traceback.py index 96510eeec54640..a4a49fd44bb2e0 100644 --- a/Lib/test/test_traceback.py +++ b/Lib/test/test_traceback.py @@ -4250,6 +4250,24 @@ def __dir__(self): actual = self.get_suggestion(A(), 'blech') self.assertNotIn("Did you mean", actual) + def test_suggestions_not_normalized(self): + class A: + analization = None + fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = None + + suggestion = self.get_suggestion(A(), 'fiⁿₐˡᵢᶻₐᵗᵢᵒₙ') + self.assertIn("'finalization'", suggestion) + self.assertNotIn("analization", suggestion) + + class B: + attr_a = None + attr_µ = None # attr_\xb5 + + suggestion = self.get_suggestion(B(), 'attr_\xb5') + self.assertIn("'attr_\u03bc'", suggestion) + self.assertIn(r"'attr_\u03bc'", suggestion) + self.assertNotIn("attr_a", suggestion) + class GetattrSuggestionTests(BaseSuggestionTests): def test_suggestions_no_args(self): @@ -4872,6 +4890,34 @@ def foo(self): actual = self.get_suggestion(instance.foo) self.assertIn("self.blech", actual) + def test_name_error_with_instance_not_normalized(self): + class A: + def __init__(self): + self.fiⁿₐˡᵢᶻₐᵗᵢᵒₙ = None + def foo(self): + analization = 1 + x = fiⁿₐˡᵢᶻₐᵗᵢᵒₙ + + instance = A() + actual = self.get_suggestion(instance.foo) + self.assertIn("self.finalization", actual) + self.assertNotIn("fiⁿₐˡᵢᶻₐᵗᵢᵒₙ", actual) + self.assertNotIn("analization", actual) + + class B: + def __init__(self): + self.attr_µ = None # attr_\xb5 + def foo(self): + attr_a = 1 + x = attr_µ # attr_\xb5 + + instance = B() + actual = self.get_suggestion(instance.foo) + self.assertIn("self.attr_\u03bc", actual) + self.assertIn(r"self.attr_\u03bc", actual) + self.assertNotIn("attr_\xb5", actual) + self.assertNotIn("attr_a", actual) + def test_unbound_local_error_with_instance(self): class A: def __init__(self): diff --git a/Lib/traceback.py b/Lib/traceback.py index f95d6bdbd016ac..97d83f3ddd3297 100644 --- a/Lib/traceback.py +++ b/Lib/traceback.py @@ -1111,7 +1111,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, wrong_name = getattr(exc_value, "name_from", None) suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: - self._str += f". Did you mean: '{suggestion}'?" + if suggestion.isascii(): + self._str += f". Did you mean: '{suggestion}'?" + else: + self._str += f". Did you mean: '{suggestion}' ({suggestion!a})?" elif exc_type and issubclass(exc_type, ModuleNotFoundError): module_name = getattr(exc_value, "name", None) if module_name in sys.stdlib_module_names: @@ -1129,7 +1132,10 @@ def __init__(self, exc_type, exc_value, exc_traceback, *, limit=None, wrong_name = getattr(exc_value, "name", None) suggestion = _compute_suggestion_error(exc_value, exc_traceback, wrong_name) if suggestion: - self._str += f". Did you mean: '{suggestion}'?" + if suggestion.isascii(): + self._str += f". Did you mean: '{suggestion}'?" + else: + self._str += f". Did you mean: '{suggestion}' ({suggestion!a})?" if issubclass(exc_type, NameError): wrong_name = getattr(exc_value, "name", None) if wrong_name is not None and wrong_name in sys.stdlib_module_names: @@ -1654,6 +1660,13 @@ def _check_for_nested_attribute(obj, wrong_name, attrs): def _compute_suggestion_error(exc_value, tb, wrong_name): if wrong_name is None or not isinstance(wrong_name, str): return None + not_normalized = False + if not wrong_name.isascii(): + from unicodedata import normalize + normalized_name = normalize('NFKC', wrong_name) + if normalized_name != wrong_name: + not_normalized = True + wrong_name = normalized_name if isinstance(exc_value, AttributeError): obj = exc_value.obj try: @@ -1699,6 +1712,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): + list(frame.f_builtins) ) d = [x for x in d if isinstance(x, str)] + if not_normalized and wrong_name in d: + return wrong_name # Check first if we are in a method and the instance # has the wrong name as attribute @@ -1711,6 +1726,8 @@ def _compute_suggestion_error(exc_value, tb, wrong_name): if has_wrong_name: return f"self.{wrong_name}" + if not_normalized and wrong_name in d: + return wrong_name try: import _suggestions except ImportError: diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst new file mode 100644 index 00000000000000..71c2476c02b89d --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2026-01-22-17-04-30.gh-issue-143962.dQR1a9.rst @@ -0,0 +1,3 @@ +Name suggestion for not normalized name suggests now the normalized name or +the closest name to the normalized name. If the suggested name is not ASCII, +include also its ASCII representation.