Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-more-itertools for 
openSUSE:Factory checked in at 2023-03-08 14:51:59
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-more-itertools (Old)
 and      /work/SRC/openSUSE:Factory/.python-more-itertools.new.31432 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-more-itertools"

Wed Mar  8 14:51:59 2023 rev:22 rq:1069920 version:9.1.0

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-more-itertools/python-more-itertools.changes  
    2022-11-01 13:41:20.055502214 +0100
+++ 
/work/SRC/openSUSE:Factory/.python-more-itertools.new.31432/python-more-itertools.changes
   2023-03-08 14:52:01.046494662 +0100
@@ -1,0 +2,6 @@
+Tue Mar  7 12:12:32 UTC 2023 - Dirk Müller <dmuel...@suse.com>
+
+- update to 9.1.0:
+  * See PR #678 for details.
+
+-------------------------------------------------------------------

Old:
----
  more-itertools-9.0.0.tar.gz

New:
----
  more-itertools-9.1.0.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-more-itertools.spec ++++++
--- /var/tmp/diff_new_pack.oSeeLC/_old  2023-03-08 14:52:01.622497799 +0100
+++ /var/tmp/diff_new_pack.oSeeLC/_new  2023-03-08 14:52:01.626497821 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package python-more-itertools
 #
-# Copyright (c) 2022 SUSE LLC
+# Copyright (c) 2023 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
 %{?!python_module:%define python_module() python3-%{**}}
 %define skip_python2 1
 Name:           python-more-itertools
-Version:        9.0.0
+Version:        9.1.0
 Release:        0
 Summary:        More routines for operating on iterables, beyond itertools
 License:        MIT

++++++ more-itertools-9.0.0.tar.gz -> more-itertools-9.1.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/more-itertools-9.0.0/.github/workflows/python-app.yml 
new/more-itertools-9.1.0/.github/workflows/python-app.yml
--- old/more-itertools-9.0.0/.github/workflows/python-app.yml   2022-10-18 
15:38:19.069835000 +0200
+++ new/more-itertools-9.1.0/.github/workflows/python-app.yml   2023-02-21 
18:00:55.991196000 +0100
@@ -8,12 +8,12 @@
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-rc.2", 
"pypy-3.8"]
+        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11", 
"3.12.0-alpha.1", "pypy-3.8"]
 
     steps:
-    - uses: actions/checkout@v2
+    - uses: actions/checkout@v3
     - name: Set up Python ${{ matrix.python-version }}
-      uses: actions/setup-python@v2
+      uses: actions/setup-python@v4
       with:
         python-version: ${{ matrix.python-version }}
     - name: Install dependencies
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/PKG-INFO 
new/more-itertools-9.1.0/PKG-INFO
--- old/more-itertools-9.0.0/PKG-INFO   1970-01-01 01:00:00.000000000 +0100
+++ new/more-itertools-9.1.0/PKG-INFO   1970-01-01 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: more-itertools
-Version: 9.0.0
+Version: 9.1.0
 Summary: More routines for operating on iterables, beyond itertools
 Keywords: itertools,iterator,iteration,filter,peek,peekable,chunk,chunked
 Author-email: Erik Rose <erikr...@grinchcentral.com>
@@ -52,6 +52,7 @@
 |                        | `batched 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.batched>`_,
                                                                               |
 |                        | `grouper 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.grouper>`_,
                                                                               |
 |                        | `partition 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partition>`_
                                                                            |
+|                        | `transpose 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.transpose>`_
                                                                            |
 
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | Lookahead and lookback | `spy 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.spy>`_,
                                                                                
       |
 |                        | `peekable 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.peekable>`_,
                                                                             |
@@ -139,6 +140,7 @@
 |                        | `product_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.product_index>`_,
                                                                   |
 |                        | `combination_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.combination_index>`_,
                                                           |
 |                        | `permutation_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.permutation_index>`_,
                                                           |
+|                        | `gray_product  
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.gray_product>`_,
                                                                    |
 |                        | `powerset 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.powerset>`_,
                                                                             |
 |                        | `random_product 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_product>`_,
                                                                 |
 |                        | `random_permutation 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_permutation>`_,
                                                         |
@@ -166,11 +168,14 @@
 |                        | `SequenceView 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.SequenceView>`_,
                                                                     |
 |                        | `time_limited 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.time_limited>`_,
                                                                     |
 |                        | `map_if 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_if>`_,
                                                                                
 |
+|                        | `iter_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_index>`_,
                                                                         |
 |                        | `consume 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consume>`_,
                                                                               |
 |                        | `tabulate 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.tabulate>`_,
                                                                             |
-|                        | `repeatfunc 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeatfunc>`_
                                                                          |
-|                        | `polynomial_from_roots 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_from_roots>`_
                                                    |
+|                        | `repeatfunc 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeatfunc>`_,
                                                                         |
+|                        | `polynomial_from_roots 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_from_roots>`_,
                                                   |
 |                        | `sieve 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sieve>`_
                                                                                
    |
+|                        | `factor 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.factor>`_
                                                                                
  |
+|                        | `matmul 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.matmul>`_
                                                                                
  |
 
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/README.rst 
new/more-itertools-9.1.0/README.rst
--- old/more-itertools-9.0.0/README.rst 2022-10-18 15:38:19.069835000 +0200
+++ new/more-itertools-9.1.0/README.rst 2023-02-27 15:41:12.542422800 +0100
@@ -28,6 +28,7 @@
 |                        | `batched 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.batched>`_,
                                                                               |
 |                        | `grouper 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.grouper>`_,
                                                                               |
 |                        | `partition 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partition>`_
                                                                            |
+|                        | `transpose 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.transpose>`_
                                                                            |
 
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 | Lookahead and lookback | `spy 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.spy>`_,
                                                                                
       |
 |                        | `peekable 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.peekable>`_,
                                                                             |
@@ -115,6 +116,7 @@
 |                        | `product_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.product_index>`_,
                                                                   |
 |                        | `combination_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.combination_index>`_,
                                                           |
 |                        | `permutation_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.permutation_index>`_,
                                                           |
+|                        | `gray_product  
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.gray_product>`_,
                                                                    |
 |                        | `powerset 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.powerset>`_,
                                                                             |
 |                        | `random_product 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_product>`_,
                                                                 |
 |                        | `random_permutation 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_permutation>`_,
                                                         |
@@ -142,11 +144,14 @@
 |                        | `SequenceView 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.SequenceView>`_,
                                                                     |
 |                        | `time_limited 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.time_limited>`_,
                                                                     |
 |                        | `map_if 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_if>`_,
                                                                                
 |
+|                        | `iter_index 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_index>`_,
                                                                         |
 |                        | `consume 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consume>`_,
                                                                               |
 |                        | `tabulate 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.tabulate>`_,
                                                                             |
-|                        | `repeatfunc 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeatfunc>`_
                                                                          |
-|                        | `polynomial_from_roots 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_from_roots>`_
                                                    |
+|                        | `repeatfunc 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeatfunc>`_,
                                                                         |
+|                        | `polynomial_from_roots 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_from_roots>`_,
                                                   |
 |                        | `sieve 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sieve>`_
                                                                                
    |
+|                        | `factor 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.factor>`_
                                                                                
  |
+|                        | `matmul 
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.matmul>`_
                                                                                
  |
 
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/docs/api.rst 
new/more-itertools-9.1.0/docs/api.rst
--- old/more-itertools-9.0.0/docs/api.rst       2022-10-18 15:37:02.101069200 
+0200
+++ new/more-itertools-9.1.0/docs/api.rst       2023-02-21 16:06:20.592258000 
+0100
@@ -35,6 +35,7 @@
 .. autofunction:: batched
 .. autofunction:: grouper
 .. autofunction:: partition
+.. autofunction:: transpose
 
 
 Lookahead and lookback
@@ -224,6 +225,7 @@
 .. autofunction:: product_index
 .. autofunction:: combination_index
 .. autofunction:: permutation_index
+.. autofunction:: gray_product
 
 ----
 
@@ -286,8 +288,11 @@
 
 **Itertools recipes**
 
+.. autofunction:: iter_index
 .. autofunction:: consume
 .. autofunction:: tabulate
 .. autofunction:: repeatfunc
 .. autofunction:: polynomial_from_roots
 .. autofunction:: sieve
+.. autofunction:: factor
+.. autofunction:: matmul
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/docs/versions.rst 
new/more-itertools-9.1.0/docs/versions.rst
--- old/more-itertools-9.0.0/docs/versions.rst  2022-10-18 15:38:19.069835000 
+0200
+++ new/more-itertools-9.1.0/docs/versions.rst  2023-02-27 15:41:12.546871400 
+0100
@@ -5,6 +5,27 @@
 .. automodule:: more_itertools
    :noindex:
 
+8.14.0
+------
+
+* New functions
+    * :func:`iter_index` (from the Python itertools docs)
+    * :func:`transpose` (from the Python itertools docs)
+    * :func:`matmul` (from the Python itertools docs)
+    * :func:`factor` (from the Python itertools docs)
+    * :func:`gray_product` (thanks to haukex)
+
+* Changes to existing functions
+    * :func:`sieve` was updated to match the Python itertools docs
+    * :func:`maxsplit` was updated to fix a bug (thanks to abingham)
+    * :func:`sliced` had its `type hint 
<https://github.com/more-itertools/more-itertools/pull/667>`__ updated (thanks 
to ad-chaos)
+    
+
+* Other changes
+    * The ``batched`` function is marked as deprecated and will be removed in 
a future major release. For Python 3.12 and above, use ``itertools.batched`` 
instead. (thanks to neutrinoceros)
+    * The type hints now used postponed evaluation of annotations from PEP 563 
(thanks to Isira-Seneviratne)
+    * Some documentation issues were fixed (thanks to Voskov and jdkandersson)
+
 9.0.0
 ------
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/more_itertools/__init__.py 
new/more-itertools-9.1.0/more_itertools/__init__.py
--- old/more-itertools-9.0.0/more_itertools/__init__.py 2022-10-18 
15:38:19.069835000 +0200
+++ new/more-itertools-9.1.0/more_itertools/__init__.py 2023-02-27 
15:41:12.550684500 +0100
@@ -3,4 +3,4 @@
 from .more import *  # noqa
 from .recipes import *  # noqa
 
-__version__ = '9.0.0'
+__version__ = '9.1.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/more_itertools/more.py 
new/more-itertools-9.1.0/more_itertools/more.py
--- old/more-itertools-9.0.0/more_itertools/more.py     2022-10-18 
15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/more_itertools/more.py     2023-02-21 
16:05:46.935729700 +0100
@@ -68,6 +68,7 @@
     'exactly_n',
     'filter_except',
     'first',
+    'gray_product',
     'groupby_transform',
     'ichunked',
     'iequals',
@@ -658,6 +659,7 @@
         [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
 
     """
+
     # Algorithm: https://w.wiki/Qai
     def _full(A):
         while True:
@@ -1301,7 +1303,7 @@
         [[0], [2], [4, 5, 6, 7, 8, 9]]
 
     By default, the delimiting items are not included in the output.
-    The include them, set *keep_separator* to ``True``.
+    To include them, set *keep_separator* to ``True``.
 
         >>> list(split_at('abcdcba', lambda x: x == 'b', keep_separator=True))
         [['a'], ['b'], ['c', 'd', 'c'], ['b'], ['a']]
@@ -1391,7 +1393,9 @@
         if pred(item) and buf:
             yield buf
             if maxsplit == 1:
-                yield list(it)
+                buf = list(it)
+                if buf:
+                    yield buf
                 return
             buf = []
             maxsplit -= 1
@@ -2914,6 +2918,7 @@
         '7'
 
     """
+
     # See https://sites.google.com/site/bbayles/index/decorator_factory for
     # notes on how this works.
     def decorator(*wrapping_args, **wrapping_kwargs):
@@ -3464,7 +3469,6 @@
     next_index = k + floor(log(random()) / log(1 - W))
 
     for index, element in enumerate(iterable, k):
-
         if index == next_index:
             reservoir[randrange(k)] = element
             # The new W is the largest in a sample of k U(0, `old_W`) numbers
@@ -4284,7 +4288,6 @@
         lo_key = hi_key = key(lo)
 
         for x, y in zip_longest(it, it, fillvalue=lo):
-
             x_key, y_key = key(x), key(y)
 
             if y_key < x_key:
@@ -4345,3 +4348,45 @@
 
     if batch:
         yield tuple(batch)
+
+
+def gray_product(*iterables):
+    """Like :func:`itertools.product`, but return tuples in an order such
+    that only one element in the generated tuple changes from one iteration
+    to the next.
+
+        >>> list(gray_product('AB','CD'))
+        [('A', 'C'), ('B', 'C'), ('B', 'D'), ('A', 'D')]
+
+    This function consumes all of the input iterables before producing output.
+    If any of the input iterables have fewer than two items, ``ValueError``
+    is raised.
+
+    For information on the algorithm, see
+    `this section <https://www-cs-faculty.stanford.edu/~knuth/fasc2a.ps.gz>`__
+    of Donald Knuth's *The Art of Computer Programming*.
+    """
+    all_iterables = tuple(tuple(x) for x in iterables)
+    iterable_count = len(all_iterables)
+    for iterable in all_iterables:
+        if len(iterable) < 2:
+            raise ValueError("each iterable must have two or more items")
+
+    # This is based on "Algorithm H" from section 7.2.1.1, page 20.
+    # a holds the indexes of the source iterables for the n-tuple to be yielded
+    # f is the array of "focus pointers"
+    # o is the array of "directions"
+    a = [0] * iterable_count
+    f = list(range(iterable_count + 1))
+    o = [1] * iterable_count
+    while True:
+        yield tuple(all_iterables[i][a[i]] for i in range(iterable_count))
+        j = f[0]
+        f[0] = 0
+        if j == iterable_count:
+            break
+        a[j] = a[j] + o[j]
+        if a[j] == 0 or a[j] == len(all_iterables[j]) - 1:
+            o[j] = -o[j]
+            f[j] = f[j + 1]
+            f[j + 1] = j + 1
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/more_itertools/more.pyi 
new/more-itertools-9.1.0/more_itertools/more.pyi
--- old/more-itertools-9.0.0/more_itertools/more.pyi    2022-10-18 
15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/more_itertools/more.pyi    2023-02-21 
16:05:46.938101000 +0100
@@ -1,26 +1,25 @@
 """Stubs for more_itertools.more"""
+from __future__ import annotations
 
+from types import TracebackType
 from typing import (
     Any,
     Callable,
     Container,
-    Dict,
+    ContextManager,
     Generic,
     Hashable,
     Iterable,
     Iterator,
-    List,
-    Optional,
+    overload,
     Reversible,
     Sequence,
     Sized,
-    Tuple,
-    Union,
+    Type,
     TypeVar,
     type_check_only,
 )
-from types import TracebackType
-from typing_extensions import ContextManager, Protocol, Type, overload
+from typing_extensions import Protocol
 
 # Type and type variable definitions
 _T = TypeVar('_T')
@@ -31,7 +30,7 @@
 _W = TypeVar('_W')
 _T_co = TypeVar('_T_co', covariant=True)
 _GenFn = TypeVar('_GenFn', bound=Callable[..., Iterator[object]])
-_Raisable = Union[BaseException, 'Type[BaseException]']
+_Raisable = BaseException | Type[BaseException]
 
 @type_check_only
 class _SizedIterable(Protocol[_T_co], Sized, Iterable[_T_co]): ...
@@ -39,23 +38,25 @@
 @type_check_only
 class _SizedReversible(Protocol[_T_co], Sized, Reversible[_T_co]): ...
 
+@type_check_only
+class _SupportsSlicing(Protocol[_T_co]):
+    def __getitem__(self, __k: slice) -> _T_co: ...
+
 def chunked(
-    iterable: Iterable[_T], n: Optional[int], strict: bool = ...
-) -> Iterator[List[_T]]: ...
+    iterable: Iterable[_T], n: int | None, strict: bool = ...
+) -> Iterator[list[_T]]: ...
 @overload
 def first(iterable: Iterable[_T]) -> _T: ...
 @overload
-def first(iterable: Iterable[_T], default: _U) -> Union[_T, _U]: ...
+def first(iterable: Iterable[_T], default: _U) -> _T | _U: ...
 @overload
 def last(iterable: Iterable[_T]) -> _T: ...
 @overload
-def last(iterable: Iterable[_T], default: _U) -> Union[_T, _U]: ...
+def last(iterable: Iterable[_T], default: _U) -> _T | _U: ...
 @overload
 def nth_or_last(iterable: Iterable[_T], n: int) -> _T: ...
 @overload
-def nth_or_last(
-    iterable: Iterable[_T], n: int, default: _U
-) -> Union[_T, _U]: ...
+def nth_or_last(iterable: Iterable[_T], n: int, default: _U) -> _T | _U: ...
 
 class peekable(Generic[_T], Iterator[_T]):
     def __init__(self, iterable: Iterable[_T]) -> None: ...
@@ -64,13 +65,13 @@
     @overload
     def peek(self) -> _T: ...
     @overload
-    def peek(self, default: _U) -> Union[_T, _U]: ...
+    def peek(self, default: _U) -> _T | _U: ...
     def prepend(self, *items: _T) -> None: ...
     def __next__(self) -> _T: ...
     @overload
     def __getitem__(self, index: int) -> _T: ...
     @overload
-    def __getitem__(self, index: slice) -> List[_T]: ...
+    def __getitem__(self, index: slice) -> list[_T]: ...
 
 def consumer(func: _GenFn) -> _GenFn: ...
 def ilen(iterable: Iterable[object]) -> int: ...
@@ -80,42 +81,42 @@
 ) -> Iterator[_T]: ...
 def one(
     iterable: Iterable[_T],
-    too_short: Optional[_Raisable] = ...,
-    too_long: Optional[_Raisable] = ...,
+    too_short: _Raisable | None = ...,
+    too_long: _Raisable | None = ...,
 ) -> _T: ...
 def raise_(exception: _Raisable, *args: Any) -> None: ...
 def strictly_n(
     iterable: Iterable[_T],
     n: int,
-    too_short: Optional[_GenFn] = ...,
-    too_long: Optional[_GenFn] = ...,
-) -> List[_T]: ...
+    too_short: _GenFn | None = ...,
+    too_long: _GenFn | None = ...,
+) -> list[_T]: ...
 def distinct_permutations(
-    iterable: Iterable[_T], r: Optional[int] = ...
-) -> Iterator[Tuple[_T, ...]]: ...
+    iterable: Iterable[_T], r: int | None = ...
+) -> Iterator[tuple[_T, ...]]: ...
 def intersperse(
     e: _U, iterable: Iterable[_T], n: int = ...
-) -> Iterator[Union[_T, _U]]: ...
-def unique_to_each(*iterables: Iterable[_T]) -> List[List[_T]]: ...
+) -> Iterator[_T | _U]: ...
+def unique_to_each(*iterables: Iterable[_T]) -> list[list[_T]]: ...
 @overload
 def windowed(
     seq: Iterable[_T], n: int, *, step: int = ...
-) -> Iterator[Tuple[Optional[_T], ...]]: ...
+) -> Iterator[tuple[_T | None, ...]]: ...
 @overload
 def windowed(
     seq: Iterable[_T], n: int, fillvalue: _U, step: int = ...
-) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
-def substrings(iterable: Iterable[_T]) -> Iterator[Tuple[_T, ...]]: ...
+) -> Iterator[tuple[_T | _U, ...]]: ...
+def substrings(iterable: Iterable[_T]) -> Iterator[tuple[_T, ...]]: ...
 def substrings_indexes(
     seq: Sequence[_T], reverse: bool = ...
-) -> Iterator[Tuple[Sequence[_T], int, int]]: ...
+) -> Iterator[tuple[Sequence[_T], int, int]]: ...
 
 class bucket(Generic[_T, _U], Container[_U]):
     def __init__(
         self,
         iterable: Iterable[_T],
         key: Callable[[_T], _U],
-        validator: Optional[Callable[[object], object]] = ...,
+        validator: Callable[[object], object] | None = ...,
     ) -> None: ...
     def __contains__(self, value: object) -> bool: ...
     def __iter__(self) -> Iterator[_U]: ...
@@ -123,109 +124,105 @@
 
 def spy(
     iterable: Iterable[_T], n: int = ...
-) -> Tuple[List[_T], Iterator[_T]]: ...
+) -> tuple[list[_T], Iterator[_T]]: ...
 def interleave(*iterables: Iterable[_T]) -> Iterator[_T]: ...
 def interleave_longest(*iterables: Iterable[_T]) -> Iterator[_T]: ...
 def interleave_evenly(
-    iterables: List[Iterable[_T]], lengths: Optional[List[int]] = ...
+    iterables: list[Iterable[_T]], lengths: list[int] | None = ...
 ) -> Iterator[_T]: ...
 def collapse(
     iterable: Iterable[Any],
-    base_type: Optional[type] = ...,
-    levels: Optional[int] = ...,
+    base_type: type | None = ...,
+    levels: int | None = ...,
 ) -> Iterator[Any]: ...
 @overload
 def side_effect(
     func: Callable[[_T], object],
     iterable: Iterable[_T],
     chunk_size: None = ...,
-    before: Optional[Callable[[], object]] = ...,
-    after: Optional[Callable[[], object]] = ...,
+    before: Callable[[], object] | None = ...,
+    after: Callable[[], object] | None = ...,
 ) -> Iterator[_T]: ...
 @overload
 def side_effect(
-    func: Callable[[List[_T]], object],
+    func: Callable[[list[_T]], object],
     iterable: Iterable[_T],
     chunk_size: int,
-    before: Optional[Callable[[], object]] = ...,
-    after: Optional[Callable[[], object]] = ...,
+    before: Callable[[], object] | None = ...,
+    after: Callable[[], object] | None = ...,
 ) -> Iterator[_T]: ...
 def sliced(
-    seq: Sequence[_T], n: int, strict: bool = ...
-) -> Iterator[Sequence[_T]]: ...
+    seq: _SupportsSlicing[_T], n: int, strict: bool = ...
+) -> Iterator[_T]: ...
 def split_at(
     iterable: Iterable[_T],
     pred: Callable[[_T], object],
     maxsplit: int = ...,
     keep_separator: bool = ...,
-) -> Iterator[List[_T]]: ...
+) -> Iterator[list[_T]]: ...
 def split_before(
     iterable: Iterable[_T], pred: Callable[[_T], object], maxsplit: int = ...
-) -> Iterator[List[_T]]: ...
+) -> Iterator[list[_T]]: ...
 def split_after(
     iterable: Iterable[_T], pred: Callable[[_T], object], maxsplit: int = ...
-) -> Iterator[List[_T]]: ...
+) -> Iterator[list[_T]]: ...
 def split_when(
     iterable: Iterable[_T],
     pred: Callable[[_T, _T], object],
     maxsplit: int = ...,
-) -> Iterator[List[_T]]: ...
+) -> Iterator[list[_T]]: ...
 def split_into(
-    iterable: Iterable[_T], sizes: Iterable[Optional[int]]
-) -> Iterator[List[_T]]: ...
+    iterable: Iterable[_T], sizes: Iterable[int | None]
+) -> Iterator[list[_T]]: ...
 @overload
 def padded(
     iterable: Iterable[_T],
     *,
-    n: Optional[int] = ...,
+    n: int | None = ...,
     next_multiple: bool = ...,
-) -> Iterator[Optional[_T]]: ...
+) -> Iterator[_T | None]: ...
 @overload
 def padded(
     iterable: Iterable[_T],
     fillvalue: _U,
-    n: Optional[int] = ...,
+    n: int | None = ...,
     next_multiple: bool = ...,
-) -> Iterator[Union[_T, _U]]: ...
+) -> Iterator[_T | _U]: ...
 @overload
 def repeat_last(iterable: Iterable[_T]) -> Iterator[_T]: ...
 @overload
-def repeat_last(
-    iterable: Iterable[_T], default: _U
-) -> Iterator[Union[_T, _U]]: ...
-def distribute(n: int, iterable: Iterable[_T]) -> List[Iterator[_T]]: ...
+def repeat_last(iterable: Iterable[_T], default: _U) -> Iterator[_T | _U]: ...
+def distribute(n: int, iterable: Iterable[_T]) -> list[Iterator[_T]]: ...
 @overload
 def stagger(
     iterable: Iterable[_T],
     offsets: _SizedIterable[int] = ...,
     longest: bool = ...,
-) -> Iterator[Tuple[Optional[_T], ...]]: ...
+) -> Iterator[tuple[_T | None, ...]]: ...
 @overload
 def stagger(
     iterable: Iterable[_T],
     offsets: _SizedIterable[int] = ...,
     longest: bool = ...,
     fillvalue: _U = ...,
-) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
+) -> Iterator[tuple[_T | _U, ...]]: ...
 
 class UnequalIterablesError(ValueError):
-    def __init__(
-        self, details: Optional[Tuple[int, int, int]] = ...
-    ) -> None: ...
+    def __init__(self, details: tuple[int, int, int] | None = ...) -> None: ...
 
 @overload
-def zip_equal(__iter1: Iterable[_T1]) -> Iterator[Tuple[_T1]]: ...
+def zip_equal(__iter1: Iterable[_T1]) -> Iterator[tuple[_T1]]: ...
 @overload
 def zip_equal(
     __iter1: Iterable[_T1], __iter2: Iterable[_T2]
-) -> Iterator[Tuple[_T1, _T2]]: ...
+) -> Iterator[tuple[_T1, _T2]]: ...
 @overload
 def zip_equal(
     __iter1: Iterable[_T],
     __iter2: Iterable[_T],
     __iter3: Iterable[_T],
     *iterables: Iterable[_T],
-) -> Iterator[Tuple[_T, ...]]: ...
+) -> Iterator[tuple[_T, ...]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T1],
@@ -233,7 +230,7 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: None = None,
-) -> Iterator[Tuple[Optional[_T1]]]: ...
+) -> Iterator[tuple[_T1 | None]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T1],
@@ -242,7 +239,7 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: None = None,
-) -> Iterator[Tuple[Optional[_T1], Optional[_T2]]]: ...
+) -> Iterator[tuple[_T1 | None, _T2 | None]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T],
@@ -252,7 +249,7 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: None = None,
-) -> Iterator[Tuple[Optional[_T], ...]]: ...
+) -> Iterator[tuple[_T | None, ...]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T1],
@@ -260,7 +257,7 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: _U,
-) -> Iterator[Tuple[Union[_T1, _U]]]: ...
+) -> Iterator[tuple[_T1 | _U]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T1],
@@ -269,7 +266,7 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: _U,
-) -> Iterator[Tuple[Union[_T1, _U], Union[_T2, _U]]]: ...
+) -> Iterator[tuple[_T1 | _U, _T2 | _U]]: ...
 @overload
 def zip_offset(
     __iter1: Iterable[_T],
@@ -279,82 +276,80 @@
     offsets: _SizedIterable[int],
     longest: bool = ...,
     fillvalue: _U,
-) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
+) -> Iterator[tuple[_T | _U, ...]]: ...
 def sort_together(
     iterables: Iterable[Iterable[_T]],
     key_list: Iterable[int] = ...,
-    key: Optional[Callable[..., Any]] = ...,
+    key: Callable[..., Any] | None = ...,
     reverse: bool = ...,
-) -> List[Tuple[_T, ...]]: ...
-def unzip(iterable: Iterable[Sequence[_T]]) -> Tuple[Iterator[_T], ...]: ...
-def divide(n: int, iterable: Iterable[_T]) -> List[Iterator[_T]]: ...
+) -> list[tuple[_T, ...]]: ...
+def unzip(iterable: Iterable[Sequence[_T]]) -> tuple[Iterator[_T], ...]: ...
+def divide(n: int, iterable: Iterable[_T]) -> list[Iterator[_T]]: ...
 def always_iterable(
     obj: object,
-    base_type: Union[
-        type, Tuple[Union[type, Tuple[Any, ...]], ...], None
-    ] = ...,
+    base_type: type | tuple[type | tuple[Any, ...], ...] | None = ...,
 ) -> Iterator[Any]: ...
 def adjacent(
     predicate: Callable[[_T], bool],
     iterable: Iterable[_T],
     distance: int = ...,
-) -> Iterator[Tuple[bool, _T]]: ...
+) -> Iterator[tuple[bool, _T]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: None = None,
     valuefunc: None = None,
     reducefunc: None = None,
-) -> Iterator[Tuple[_T, Iterator[_T]]]: ...
+) -> Iterator[tuple[_T, Iterator[_T]]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: None,
     reducefunc: None,
-) -> Iterator[Tuple[_U, Iterator[_T]]]: ...
+) -> Iterator[tuple[_U, Iterator[_T]]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: None,
     valuefunc: Callable[[_T], _V],
     reducefunc: None,
-) -> Iterable[Tuple[_T, Iterable[_V]]]: ...
+) -> Iterable[tuple[_T, Iterable[_V]]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: Callable[[_T], _V],
     reducefunc: None,
-) -> Iterable[Tuple[_U, Iterator[_V]]]: ...
+) -> Iterable[tuple[_U, Iterator[_V]]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: None,
     valuefunc: None,
     reducefunc: Callable[[Iterator[_T]], _W],
-) -> Iterable[Tuple[_T, _W]]: ...
+) -> Iterable[tuple[_T, _W]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: None,
     reducefunc: Callable[[Iterator[_T]], _W],
-) -> Iterable[Tuple[_U, _W]]: ...
+) -> Iterable[tuple[_U, _W]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: None,
     valuefunc: Callable[[_T], _V],
     reducefunc: Callable[[Iterable[_V]], _W],
-) -> Iterable[Tuple[_T, _W]]: ...
+) -> Iterable[tuple[_T, _W]]: ...
 @overload
 def groupby_transform(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: Callable[[_T], _V],
     reducefunc: Callable[[Iterable[_V]], _W],
-) -> Iterable[Tuple[_U, _W]]: ...
+) -> Iterable[tuple[_U, _W]]: ...
 
 class numeric_range(Generic[_T, _U], Sequence[_T], Hashable, Reversible[_T]):
     @overload
@@ -375,22 +370,22 @@
     def __len__(self) -> int: ...
     def __reduce__(
         self,
-    ) -> Tuple[Type[numeric_range[_T, _U]], Tuple[_T, _T, _U]]: ...
+    ) -> tuple[Type[numeric_range[_T, _U]], tuple[_T, _T, _U]]: ...
     def __repr__(self) -> str: ...
     def __reversed__(self) -> Iterator[_T]: ...
     def count(self, value: _T) -> int: ...
     def index(self, value: _T) -> int: ...  # type: ignore
 
 def count_cycle(
-    iterable: Iterable[_T], n: Optional[int] = ...
-) -> Iterable[Tuple[int, _T]]: ...
+    iterable: Iterable[_T], n: int | None = ...
+) -> Iterable[tuple[int, _T]]: ...
 def mark_ends(
     iterable: Iterable[_T],
-) -> Iterable[Tuple[bool, bool, _T]]: ...
+) -> Iterable[tuple[bool, bool, _T]]: ...
 def locate(
     iterable: Iterable[object],
     pred: Callable[..., Any] = ...,
-    window_size: Optional[int] = ...,
+    window_size: int | None = ...,
 ) -> Iterator[int]: ...
 def lstrip(
     iterable: Iterable[_T], pred: Callable[[_T], object]
@@ -403,9 +398,7 @@
 ) -> Iterator[_T]: ...
 
 class islice_extended(Generic[_T], Iterator[_T]):
-    def __init__(
-        self, iterable: Iterable[_T], *args: Optional[int]
-    ) -> None: ...
+    def __init__(self, iterable: Iterable[_T], *args: int | None) -> None: ...
     def __iter__(self) -> islice_extended[_T]: ...
     def __next__(self) -> _T: ...
     def __getitem__(self, index: slice) -> islice_extended[_T]: ...
@@ -420,7 +413,7 @@
     func: Callable[[_T, _T], _U] = ...,
     *,
     initial: None = ...,
-) -> Iterator[Union[_T, _U]]: ...
+) -> Iterator[_T | _U]: ...
 @overload
 def difference(
     iterable: Iterable[_T], func: Callable[[_T, _T], _U] = ..., *, initial: _U
@@ -436,7 +429,7 @@
 
 class seekable(Generic[_T], Iterator[_T]):
     def __init__(
-        self, iterable: Iterable[_T], maxlen: Optional[int] = ...
+        self, iterable: Iterable[_T], maxlen: int | None = ...
     ) -> None: ...
     def __iter__(self) -> seekable[_T]: ...
     def __next__(self) -> _T: ...
@@ -444,20 +437,20 @@
     @overload
     def peek(self) -> _T: ...
     @overload
-    def peek(self, default: _U) -> Union[_T, _U]: ...
+    def peek(self, default: _U) -> _T | _U: ...
     def elements(self) -> SequenceView[_T]: ...
     def seek(self, index: int) -> None: ...
 
 class run_length:
     @staticmethod
-    def encode(iterable: Iterable[_T]) -> Iterator[Tuple[_T, int]]: ...
+    def encode(iterable: Iterable[_T]) -> Iterator[tuple[_T, int]]: ...
     @staticmethod
-    def decode(iterable: Iterable[Tuple[_T, int]]) -> Iterator[_T]: ...
+    def decode(iterable: Iterable[tuple[_T, int]]) -> Iterator[_T]: ...
 
 def exactly_n(
     iterable: Iterable[_T], n: int, predicate: Callable[[_T], object] = ...
 ) -> bool: ...
-def circular_shifts(iterable: Iterable[_T]) -> List[Tuple[_T, ...]]: ...
+def circular_shifts(iterable: Iterable[_T]) -> list[tuple[_T, ...]]: ...
 def make_decorator(
     wrapping_func: Callable[..., _U], result_index: int = ...
 ) -> Callable[..., Callable[[Callable[..., Any]], Callable[..., _U]]]: ...
@@ -467,44 +460,44 @@
     keyfunc: Callable[[_T], _U],
     valuefunc: None = ...,
     reducefunc: None = ...,
-) -> Dict[_U, List[_T]]: ...
+) -> dict[_U, list[_T]]: ...
 @overload
 def map_reduce(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: Callable[[_T], _V],
     reducefunc: None = ...,
-) -> Dict[_U, List[_V]]: ...
+) -> dict[_U, list[_V]]: ...
 @overload
 def map_reduce(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: None = ...,
-    reducefunc: Callable[[List[_T]], _W] = ...,
-) -> Dict[_U, _W]: ...
+    reducefunc: Callable[[list[_T]], _W] = ...,
+) -> dict[_U, _W]: ...
 @overload
 def map_reduce(
     iterable: Iterable[_T],
     keyfunc: Callable[[_T], _U],
     valuefunc: Callable[[_T], _V],
-    reducefunc: Callable[[List[_V]], _W],
-) -> Dict[_U, _W]: ...
+    reducefunc: Callable[[list[_V]], _W],
+) -> dict[_U, _W]: ...
 def rlocate(
     iterable: Iterable[_T],
     pred: Callable[..., object] = ...,
-    window_size: Optional[int] = ...,
+    window_size: int | None = ...,
 ) -> Iterator[int]: ...
 def replace(
     iterable: Iterable[_T],
     pred: Callable[..., object],
     substitutes: Iterable[_U],
-    count: Optional[int] = ...,
+    count: int | None = ...,
     window_size: int = ...,
-) -> Iterator[Union[_T, _U]]: ...
-def partitions(iterable: Iterable[_T]) -> Iterator[List[List[_T]]]: ...
+) -> Iterator[_T | _U]: ...
+def partitions(iterable: Iterable[_T]) -> Iterator[list[list[_T]]]: ...
 def set_partitions(
-    iterable: Iterable[_T], k: Optional[int] = ...
-) -> Iterator[List[List[_T]]]: ...
+    iterable: Iterable[_T], k: int | None = ...
+) -> Iterator[list[list[_T]]]: ...
 
 class time_limited(Generic[_T], Iterator[_T]):
     def __init__(
@@ -515,16 +508,16 @@
 
 @overload
 def only(
-    iterable: Iterable[_T], *, too_long: Optional[_Raisable] = ...
-) -> Optional[_T]: ...
+    iterable: Iterable[_T], *, too_long: _Raisable | None = ...
+) -> _T | None: ...
 @overload
 def only(
-    iterable: Iterable[_T], default: _U, too_long: Optional[_Raisable] = ...
-) -> Union[_T, _U]: ...
+    iterable: Iterable[_T], default: _U, too_long: _Raisable | None = ...
+) -> _T | _U: ...
 def ichunked(iterable: Iterable[_T], n: int) -> Iterator[Iterator[_T]]: ...
 def distinct_combinations(
     iterable: Iterable[_T], r: int
-) -> Iterator[Tuple[_T, ...]]: ...
+) -> Iterator[tuple[_T, ...]]: ...
 def filter_except(
     validator: Callable[[Any], object],
     iterable: Iterable[_T],
@@ -539,16 +532,16 @@
     iterable: Iterable[Any],
     pred: Callable[[Any], bool],
     func: Callable[[Any], Any],
-    func_else: Optional[Callable[[Any], Any]] = ...,
+    func_else: Callable[[Any], Any] | None = ...,
 ) -> Iterator[Any]: ...
 def sample(
     iterable: Iterable[_T],
     k: int,
-    weights: Optional[Iterable[float]] = ...,
-) -> List[_T]: ...
+    weights: Iterable[float] | None = ...,
+) -> list[_T]: ...
 def is_sorted(
     iterable: Iterable[_T],
-    key: Optional[Callable[[_T], _U]] = ...,
+    key: Callable[[_T], _U] | None = ...,
     reverse: bool = False,
     strict: bool = False,
 ) -> bool: ...
@@ -566,10 +559,10 @@
     def __enter__(self) -> callback_iter[_T]: ...
     def __exit__(
         self,
-        exc_type: Optional[Type[BaseException]],
-        exc_value: Optional[BaseException],
-        traceback: Optional[TracebackType],
-    ) -> Optional[bool]: ...
+        exc_type: Type[BaseException] | None,
+        exc_value: BaseException | None,
+        traceback: TracebackType | None,
+    ) -> bool | None: ...
     def __iter__(self) -> callback_iter[_T]: ...
     def __next__(self) -> _T: ...
     def _reader(self) -> Iterator[_T]: ...
@@ -580,15 +573,15 @@
 
 def windowed_complete(
     iterable: Iterable[_T], n: int
-) -> Iterator[Tuple[_T, ...]]: ...
+) -> Iterator[tuple[_T, ...]]: ...
 def all_unique(
-    iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = ...
+    iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
 ) -> bool: ...
-def nth_product(index: int, *args: Iterable[_T]) -> Tuple[_T, ...]: ...
+def nth_product(index: int, *args: Iterable[_T]) -> tuple[_T, ...]: ...
 def nth_permutation(
     iterable: Iterable[_T], r: int, index: int
-) -> Tuple[_T, ...]: ...
-def value_chain(*args: Union[_T, Iterable[_T]]) -> Iterable[_T]: ...
+) -> tuple[_T, ...]: ...
+def value_chain(*args: _T | Iterable[_T]) -> Iterable[_T]: ...
 def product_index(element: Iterable[_T], *args: Iterable[_T]) -> int: ...
 def combination_index(
     element: Iterable[_T], iterable: Iterable[_T]
@@ -603,22 +596,20 @@
     def __iter__(self) -> countable[_T]: ...
     def __next__(self) -> _T: ...
 
-def chunked_even(iterable: Iterable[_T], n: int) -> Iterator[List[_T]]: ...
+def chunked_even(iterable: Iterable[_T], n: int) -> Iterator[list[_T]]: ...
 def zip_broadcast(
-    *objects: Union[_T, Iterable[_T]],
-    scalar_types: Union[
-        type, Tuple[Union[type, Tuple[Any, ...]], ...], None
-    ] = ...,
+    *objects: _T | Iterable[_T],
+    scalar_types: type | tuple[type | tuple[Any, ...], ...] | None = ...,
     strict: bool = ...,
-) -> Iterable[Tuple[_T, ...]]: ...
+) -> Iterable[tuple[_T, ...]]: ...
 def unique_in_window(
-    iterable: Iterable[_T], n: int, key: Optional[Callable[[_T], _U]] = ...
+    iterable: Iterable[_T], n: int, key: Callable[[_T], _U] | None = ...
 ) -> Iterator[_T]: ...
 def duplicates_everseen(
-    iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = ...
+    iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
 ) -> Iterator[_T]: ...
 def duplicates_justseen(
-    iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = ...
+    iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
 ) -> Iterator[_T]: ...
 
 class _SupportsLessThan(Protocol):
@@ -629,38 +620,38 @@
 @overload
 def minmax(
     iterable_or_value: Iterable[_SupportsLessThanT], *, key: None = None
-) -> Tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
+) -> tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
 @overload
 def minmax(
     iterable_or_value: Iterable[_T], *, key: Callable[[_T], _SupportsLessThan]
-) -> Tuple[_T, _T]: ...
+) -> tuple[_T, _T]: ...
 @overload
 def minmax(
     iterable_or_value: Iterable[_SupportsLessThanT],
     *,
     key: None = None,
     default: _U,
-) -> Union[_U, Tuple[_SupportsLessThanT, _SupportsLessThanT]]: ...
+) -> _U | tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
 @overload
 def minmax(
     iterable_or_value: Iterable[_T],
     *,
     key: Callable[[_T], _SupportsLessThan],
     default: _U,
-) -> Union[_U, Tuple[_T, _T]]: ...
+) -> _U | tuple[_T, _T]: ...
 @overload
 def minmax(
     iterable_or_value: _SupportsLessThanT,
     __other: _SupportsLessThanT,
     *others: _SupportsLessThanT,
-) -> Tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
+) -> tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
 @overload
 def minmax(
     iterable_or_value: _T,
     __other: _T,
     *others: _T,
     key: Callable[[_T], _SupportsLessThan],
-) -> Tuple[_T, _T]: ...
+) -> tuple[_T, _T]: ...
 def longest_common_prefix(
     iterables: Iterable[Iterable[_T]],
 ) -> Iterator[_T]: ...
@@ -668,7 +659,8 @@
 def constrained_batches(
     iterable: Iterable[object],
     max_size: int,
-    max_count: Optional[int] = ...,
+    max_count: int | None = ...,
     get_len: Callable[[_T], object] = ...,
     strict: bool = ...,
-) -> Iterator[Tuple[_T]]: ...
+) -> Iterator[tuple[_T]]: ...
+def gray_product(*iterables: Iterable[_T]) -> Iterator[tuple[_T, ...]]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/more_itertools/recipes.py 
new/more-itertools-9.1.0/more_itertools/recipes.py
--- old/more-itertools-9.0.0/more_itertools/recipes.py  2022-10-18 
15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/more_itertools/recipes.py  2023-02-21 
16:05:46.940384600 +0100
@@ -9,6 +9,7 @@
 """
 import math
 import operator
+import warnings
 
 from collections import deque
 from collections.abc import Sized
@@ -21,12 +22,14 @@
     cycle,
     groupby,
     islice,
+    product,
     repeat,
     starmap,
     tee,
     zip_longest,
 )
 from random import randrange, sample, choice
+from sys import hexversion
 
 __all__ = [
     'all_equal',
@@ -36,9 +39,12 @@
     'convolve',
     'dotproduct',
     'first_true',
+    'factor',
     'flatten',
     'grouper',
     'iter_except',
+    'iter_index',
+    'matmul',
     'ncycles',
     'nth',
     'nth_combination',
@@ -62,6 +68,7 @@
     'tabulate',
     'tail',
     'take',
+    'transpose',
     'triplewise',
     'unique_everseen',
     'unique_justseen',
@@ -808,6 +815,35 @@
     ]
 
 
+def iter_index(iterable, value, start=0):
+    """Yield the index of each place in *iterable* that *value* occurs,
+    beginning with index *start*.
+
+    See :func:`locate` for a more general means of finding the indexes
+    associated with particular values.
+
+    >>> list(iter_index('AABCADEAF', 'A'))
+    [0, 1, 4, 7]
+    """
+    try:
+        seq_index = iterable.index
+    except AttributeError:
+        # Slow path for general iterables
+        it = islice(iterable, start, None)
+        for i, element in enumerate(it, start):
+            if element is value or element == value:
+                yield i
+    else:
+        # Fast path for sequences
+        i = start - 1
+        try:
+            while True:
+                i = seq_index(value, i + 1)
+                yield i
+        except ValueError:
+            pass
+
+
 def sieve(n):
     """Yield the primes less than n.
 
@@ -815,13 +851,13 @@
     [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
     """
     isqrt = getattr(math, 'isqrt', lambda x: int(math.sqrt(x)))
+    data = bytearray((0, 1)) * (n // 2)
+    data[:3] = 0, 0, 0
     limit = isqrt(n) + 1
-    data = bytearray([1]) * n
-    data[:2] = 0, 0
     for p in compress(range(limit), data):
-        data[p + p : n : p] = bytearray(len(range(p + p, n, p)))
-
-    return compress(count(), data)
+        data[p * p : n : p + p] = bytes(len(range(p * p, n, p + p)))
+    data[2] = 1
+    return iter_index(data, 1) if n > 2 else iter([])
 
 
 def batched(iterable, n):
@@ -833,9 +869,62 @@
     This recipe is from the ``itertools`` docs. This library also provides
     :func:`chunked`, which has a different implementation.
     """
+    if hexversion >= 0x30C00A0:  # Python 3.12.0a0
+        warnings.warn(
+            (
+                'batched will be removed in a future version of '
+                'more-itertools. Use the standard library '
+                'itertools.batched function instead'
+            ),
+            DeprecationWarning,
+        )
+
     it = iter(iterable)
     while True:
         batch = list(islice(it, n))
         if not batch:
             break
         yield batch
+
+
+def transpose(it):
+    """Swap the rows and columns of the input.
+
+    >>> list(transpose([(1, 2, 3), (11, 22, 33)]))
+    [(1, 11), (2, 22), (3, 33)]
+
+    The caller should ensure that the dimensions of the input are compatible.
+    """
+    # TODO: when 3.9 goes end-of-life, add stric=True to this.
+    return zip(*it)
+
+
+def matmul(m1, m2):
+    """Multiply two matrices.
+    >>> list(matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]))
+    [[49, 80], [41, 60]]
+
+    The caller should ensure that the dimensions of the input matrices are
+    compatible with each other.
+    """
+    n = len(m2[0])
+    return batched(starmap(dotproduct, product(m1, transpose(m2))), n)
+
+
+def factor(n):
+    """Yield the prime factors of n.
+    >>> list(factor(360))
+    [2, 2, 2, 3, 3, 5]
+    """
+    isqrt = getattr(math, 'isqrt', lambda x: int(math.sqrt(x)))
+    for prime in sieve(isqrt(n) + 1):
+        while True:
+            quotient, remainder = divmod(n, prime)
+            if remainder:
+                break
+            yield prime
+            n = quotient
+            if n == 1:
+                return
+    if n >= 2:
+        yield n
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/more_itertools/recipes.pyi 
new/more-itertools-9.1.0/more_itertools/recipes.pyi
--- old/more-itertools-9.0.0/more_itertools/recipes.pyi 2022-10-18 
15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/more_itertools/recipes.pyi 2023-02-21 
16:05:46.943320300 +0100
@@ -1,110 +1,119 @@
 """Stubs for more_itertools.recipes"""
+from __future__ import annotations
+
 from typing import (
     Any,
     Callable,
     Iterable,
     Iterator,
-    List,
-    Optional,
+    overload,
     Sequence,
-    Tuple,
+    Type,
     TypeVar,
-    Union,
 )
-from typing_extensions import overload, Type
 
 # Type and type variable definitions
 _T = TypeVar('_T')
 _U = TypeVar('_U')
 
-def take(n: int, iterable: Iterable[_T]) -> List[_T]: ...
+def take(n: int, iterable: Iterable[_T]) -> list[_T]: ...
 def tabulate(
     function: Callable[[int], _T], start: int = ...
 ) -> Iterator[_T]: ...
 def tail(n: int, iterable: Iterable[_T]) -> Iterator[_T]: ...
-def consume(iterator: Iterable[object], n: Optional[int] = ...) -> None: ...
+def consume(iterator: Iterable[object], n: int | None = ...) -> None: ...
 @overload
-def nth(iterable: Iterable[_T], n: int) -> Optional[_T]: ...
+def nth(iterable: Iterable[_T], n: int) -> _T | None: ...
 @overload
-def nth(iterable: Iterable[_T], n: int, default: _U) -> Union[_T, _U]: ...
+def nth(iterable: Iterable[_T], n: int, default: _U) -> _T | _U: ...
 def all_equal(iterable: Iterable[object]) -> bool: ...
 def quantify(
     iterable: Iterable[_T], pred: Callable[[_T], bool] = ...
 ) -> int: ...
-def pad_none(iterable: Iterable[_T]) -> Iterator[Optional[_T]]: ...
-def padnone(iterable: Iterable[_T]) -> Iterator[Optional[_T]]: ...
+def pad_none(iterable: Iterable[_T]) -> Iterator[_T | None]: ...
+def padnone(iterable: Iterable[_T]) -> Iterator[_T | None]: ...
 def ncycles(iterable: Iterable[_T], n: int) -> Iterator[_T]: ...
 def dotproduct(vec1: Iterable[object], vec2: Iterable[object]) -> object: ...
 def flatten(listOfLists: Iterable[Iterable[_T]]) -> Iterator[_T]: ...
 def repeatfunc(
-    func: Callable[..., _U], times: Optional[int] = ..., *args: Any
+    func: Callable[..., _U], times: int | None = ..., *args: Any
 ) -> Iterator[_U]: ...
-def pairwise(iterable: Iterable[_T]) -> Iterator[Tuple[_T, _T]]: ...
+def pairwise(iterable: Iterable[_T]) -> Iterator[tuple[_T, _T]]: ...
 def grouper(
     iterable: Iterable[_T],
     n: int,
     incomplete: str = ...,
     fillvalue: _U = ...,
-) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
+) -> Iterator[tuple[_T | _U, ...]]: ...
 def roundrobin(*iterables: Iterable[_T]) -> Iterator[_T]: ...
 def partition(
-    pred: Optional[Callable[[_T], object]], iterable: Iterable[_T]
-) -> Tuple[Iterator[_T], Iterator[_T]]: ...
-def powerset(iterable: Iterable[_T]) -> Iterator[Tuple[_T, ...]]: ...
+    pred: Callable[[_T], object] | None, iterable: Iterable[_T]
+) -> tuple[Iterator[_T], Iterator[_T]]: ...
+def powerset(iterable: Iterable[_T]) -> Iterator[tuple[_T, ...]]: ...
 def unique_everseen(
-    iterable: Iterable[_T], key: Optional[Callable[[_T], _U]] = ...
+    iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
 ) -> Iterator[_T]: ...
 def unique_justseen(
-    iterable: Iterable[_T], key: Optional[Callable[[_T], object]] = ...
+    iterable: Iterable[_T], key: Callable[[_T], object] | None = ...
 ) -> Iterator[_T]: ...
 @overload
 def iter_except(
     func: Callable[[], _T],
-    exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
+    exception: Type[BaseException] | tuple[Type[BaseException], ...],
     first: None = ...,
 ) -> Iterator[_T]: ...
 @overload
 def iter_except(
     func: Callable[[], _T],
-    exception: Union[Type[BaseException], Tuple[Type[BaseException], ...]],
+    exception: Type[BaseException] | tuple[Type[BaseException], ...],
     first: Callable[[], _U],
-) -> Iterator[Union[_T, _U]]: ...
+) -> Iterator[_T | _U]: ...
 @overload
 def first_true(
-    iterable: Iterable[_T], *, pred: Optional[Callable[[_T], object]] = ...
-) -> Optional[_T]: ...
+    iterable: Iterable[_T], *, pred: Callable[[_T], object] | None = ...
+) -> _T | None: ...
 @overload
 def first_true(
     iterable: Iterable[_T],
     default: _U,
-    pred: Optional[Callable[[_T], object]] = ...,
-) -> Union[_T, _U]: ...
+    pred: Callable[[_T], object] | None = ...,
+) -> _T | _U: ...
 def random_product(
     *args: Iterable[_T], repeat: int = ...
-) -> Tuple[_T, ...]: ...
+) -> tuple[_T, ...]: ...
 def random_permutation(
-    iterable: Iterable[_T], r: Optional[int] = ...
-) -> Tuple[_T, ...]: ...
-def random_combination(iterable: Iterable[_T], r: int) -> Tuple[_T, ...]: ...
+    iterable: Iterable[_T], r: int | None = ...
+) -> tuple[_T, ...]: ...
+def random_combination(iterable: Iterable[_T], r: int) -> tuple[_T, ...]: ...
 def random_combination_with_replacement(
     iterable: Iterable[_T], r: int
-) -> Tuple[_T, ...]: ...
+) -> tuple[_T, ...]: ...
 def nth_combination(
     iterable: Iterable[_T], r: int, index: int
-) -> Tuple[_T, ...]: ...
-def prepend(value: _T, iterator: Iterable[_U]) -> Iterator[Union[_T, _U]]: ...
+) -> tuple[_T, ...]: ...
+def prepend(value: _T, iterator: Iterable[_U]) -> Iterator[_T | _U]: ...
 def convolve(signal: Iterable[_T], kernel: Iterable[_T]) -> Iterator[_T]: ...
 def before_and_after(
     predicate: Callable[[_T], bool], it: Iterable[_T]
-) -> Tuple[Iterator[_T], Iterator[_T]]: ...
-def triplewise(iterable: Iterable[_T]) -> Iterator[Tuple[_T, _T, _T]]: ...
+) -> tuple[Iterator[_T], Iterator[_T]]: ...
+def triplewise(iterable: Iterable[_T]) -> Iterator[tuple[_T, _T, _T]]: ...
 def sliding_window(
     iterable: Iterable[_T], n: int
-) -> Iterator[Tuple[_T, ...]]: ...
-def subslices(iterable: Iterable[_T]) -> Iterator[List[_T]]: ...
-def polynomial_from_roots(roots: Sequence[int]) -> List[int]: ...
+) -> Iterator[tuple[_T, ...]]: ...
+def subslices(iterable: Iterable[_T]) -> Iterator[list[_T]]: ...
+def polynomial_from_roots(roots: Sequence[int]) -> list[int]: ...
+def iter_index(
+    iterable: Iterable[object],
+    value: Any,
+    start: int | None = ...,
+) -> Iterator[int]: ...
 def sieve(n: int) -> Iterator[int]: ...
 def batched(
     iterable: Iterable[_T],
     n: int,
-) -> Iterator[List[_T]]: ...
+) -> Iterator[list[_T]]: ...
+def transpose(
+    it: Iterable[Iterable[_T]],
+) -> tuple[Iterator[_T], ...]: ...
+def matmul(m1: Sequence[_T], m2: Sequence[_T]) -> Iterator[list[_T]]: ...
+def factor(n: int) -> Iterator[int]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/setup.cfg 
new/more-itertools-9.1.0/setup.cfg
--- old/more-itertools-9.0.0/setup.cfg  2022-10-18 15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/setup.cfg  2023-02-27 15:41:12.554733800 +0100
@@ -1,5 +1,5 @@
 [bumpversion]
-current_version = 9.0.0
+current_version = 9.1.0
 commit = True
 tag = False
 files = more_itertools/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/tests/test_more.py 
new/more-itertools-9.1.0/tests/test_more.py
--- old/more-itertools-9.0.0/tests/test_more.py 2022-10-18 15:38:19.073834700 
+0200
+++ new/more-itertools-9.1.0/tests/test_more.py 2023-01-13 21:05:28.316245600 
+0100
@@ -1448,6 +1448,10 @@
                 ('a,b,c,d', lambda c: c != ',', 2),
                 [['a'], [',', 'b'], [',', 'c', ',', 'd']],
             ),
+            (
+                ([1], lambda x: x == 1, 1),
+                [[1]],
+            ),
         ]:
             actual = list(mi.split_after(*args))
             self.assertEqual(actual, expected)
@@ -5174,3 +5178,53 @@
             ),
             [(record_3, record_5), (record_10,), (record_2,)],
         )
+
+
+class GrayProductTests(TestCase):
+    def test_basic(self):
+        self.assertEqual(
+            tuple(mi.gray_product(('a', 'b', 'c'), range(1, 3))),
+            (("a", 1), ("b", 1), ("c", 1), ("c", 2), ("b", 2), ("a", 2)),
+        )
+        out = mi.gray_product(('foo', 'bar'), (3, 4, 5, 6), ['quz', 'baz'])
+        self.assertEqual(next(out), ('foo', 3, 'quz'))
+        self.assertEqual(
+            list(out),
+            [
+                ('bar', 3, 'quz'),
+                ('bar', 4, 'quz'),
+                ('foo', 4, 'quz'),
+                ('foo', 5, 'quz'),
+                ('bar', 5, 'quz'),
+                ('bar', 6, 'quz'),
+                ('foo', 6, 'quz'),
+                ('foo', 6, 'baz'),
+                ('bar', 6, 'baz'),
+                ('bar', 5, 'baz'),
+                ('foo', 5, 'baz'),
+                ('foo', 4, 'baz'),
+                ('bar', 4, 'baz'),
+                ('bar', 3, 'baz'),
+                ('foo', 3, 'baz'),
+            ],
+        )
+        self.assertEqual(tuple(mi.gray_product()), ((),))
+        self.assertEqual(tuple(mi.gray_product((1, 2))), ((1,), (2,)))
+
+    def test_errors(self):
+        with self.assertRaises(ValueError):
+            list(mi.gray_product((1, 2), ()))
+        with self.assertRaises(ValueError):
+            list(mi.gray_product((1, 2), (2,)))
+
+    def test_vs_product(self):
+        iters = (
+            ("a", "b"),
+            range(3, 6),
+            [None, None],
+            {"i", "j", "k", "l"},
+            "XYZ",
+        )
+        self.assertEqual(
+            sorted(product(*iters)), sorted(mi.gray_product(*iters))
+        )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/more-itertools-9.0.0/tests/test_recipes.py 
new/more-itertools-9.1.0/tests/test_recipes.py
--- old/more-itertools-9.0.0/tests/test_recipes.py      2022-10-18 
15:38:19.073834700 +0200
+++ new/more-itertools-9.1.0/tests/test_recipes.py      2023-02-21 
16:05:46.945628600 +0100
@@ -1,6 +1,7 @@
 from doctest import DocTestSuite
 from functools import reduce
 from itertools import combinations, count, permutations
+from operator import mul
 from math import factorial
 from unittest import TestCase
 
@@ -880,6 +881,35 @@
                 self.assertEqual(actual, expected)
 
 
+class IterIndexTests(TestCase):
+    def test_basic(self):
+        iterable = 'AABCADEAF'
+        for wrapper in (list, iter):
+            with self.subTest(wrapper=wrapper):
+                actual = list(mi.iter_index(wrapper(iterable), 'A'))
+                expected = [0, 1, 4, 7]
+                self.assertEqual(actual, expected)
+
+    def test_start(self):
+        for wrapper in (list, iter):
+            with self.subTest(wrapper=wrapper):
+                iterable = 'AABCADEAF'
+                i = -1
+                actual = []
+                while True:
+                    try:
+                        i = next(
+                            mi.iter_index(wrapper(iterable), 'A', start=i + 1)
+                        )
+                    except StopIteration:
+                        break
+                    else:
+                        actual.append(i)
+
+                expected = [0, 1, 4, 7]
+                self.assertEqual(actual, expected)
+
+
 class SieveTests(TestCase):
     def test_basic(self):
         self.assertEqual(
@@ -942,3 +972,72 @@
             with self.subTest(n=n):
                 actual = list(mi.batched(iterable, n))
                 self.assertEqual(actual, expected)
+
+
+class TransposeTests(TestCase):
+    def test_empty(self):
+        it = []
+        actual = list(mi.transpose(it))
+        expected = []
+        self.assertEqual(actual, expected)
+
+    def test_basic(self):
+        it = [(10, 11, 12), (20, 21, 22), (30, 31, 32)]
+        actual = list(mi.transpose(it))
+        expected = [(10, 20, 30), (11, 21, 31), (12, 22, 32)]
+        self.assertEqual(actual, expected)
+
+    def test_incompatible(self):
+        it = [(10, 11, 12, 13), (20, 21, 22), (30, 31, 32)]
+        actual = list(mi.transpose(it))
+        expected = [(10, 20, 30), (11, 21, 31), (12, 22, 32)]
+        self.assertEqual(actual, expected)
+
+
+class MatMulTests(TestCase):
+    def test_n_by_n(self):
+        actual = list(mi.matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]))
+        expected = [[49, 80], [41, 60]]
+        self.assertEqual(actual, expected)
+
+    def test_m_by_n(self):
+        m1 = [[2, 5], [7, 9], [3, 4]]
+        m2 = [[7, 11, 5, 4, 9], [3, 5, 2, 6, 3]]
+        actual = list(mi.matmul(m1, m2))
+        expected = [
+            [29, 47, 20, 38, 33],
+            [76, 122, 53, 82, 90],
+            [33, 53, 23, 36, 39],
+        ]
+        self.assertEqual(actual, expected)
+
+
+class FactorTests(TestCase):
+    def test_basic(self):
+        for n, expected in (
+            (0, []),
+            (1, []),
+            (2, [2]),
+            (3, [3]),
+            (4, [2, 2]),
+            (6, [2, 3]),
+            (360, [2, 2, 2, 3, 3, 5]),
+            (128_884_753_939, [128_884_753_939]),
+            (999953 * 999983, [999953, 999983]),
+            (909_909_090_909, [3, 3, 7, 13, 13, 751, 113797]),
+        ):
+            with self.subTest(n=n):
+                actual = list(mi.factor(n))
+                self.assertEqual(actual, expected)
+
+    def test_cross_check(self):
+        prod = lambda x: reduce(mul, x, 1)
+        self.assertTrue(all(prod(mi.factor(n)) == n for n in range(1, 2000)))
+        self.assertTrue(
+            all(set(mi.factor(n)) <= set(mi.sieve(n + 1)) for n in range(2000))
+        )
+        self.assertTrue(
+            all(
+                list(mi.factor(n)) == sorted(mi.factor(n)) for n in range(2000)
+            )
+        )

Reply via email to