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 2022-11-01 13:41:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-more-itertools (Old)
and /work/SRC/openSUSE:Factory/.python-more-itertools.new.2275 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-more-itertools"
Tue Nov 1 13:41:10 2022 rev:21 rq:1032501 version:9.0.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-more-itertools/python-more-itertools.changes
2022-09-18 17:32:12.625768784 +0200
+++
/work/SRC/openSUSE:Factory/.python-more-itertools.new.2275/python-more-itertools.changes
2022-11-01 13:41:20.055502214 +0100
@@ -1,0 +2,17 @@
+Fri Oct 28 18:32:55 UTC 2022 - Yogalakshmi Arunachalam <[email protected]>
+
+- Update to 9.0.0
+ * Potentially breaking changes
+ grouper() no longer accepts an integer as its first argument. Previously
this raised a DeprecationWarning.
+ collate() has been removed. Use the built-in heapq.merge() instead.
+ windowed() now yields nothing when its iterable is empty.
+ This library now advertises support for Python 3.7+.
+ * New functions
+ constrained_batches()
+ batched() (from the Python itertools docs)
+ polynomial_from_roots() (from the Python itertools docs)
+ sieve() (from the Python itertools docs)
+ * Other changes
+ Some documentation issues were fixed (thanks to nanouasyn)
+
+-------------------------------------------------------------------
Old:
----
more-itertools-8.14.0.tar.gz
New:
----
more-itertools-9.0.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-more-itertools.spec ++++++
--- /var/tmp/diff_new_pack.sQLD4j/_old 2022-11-01 13:41:20.599505108 +0100
+++ /var/tmp/diff_new_pack.sQLD4j/_new 2022-11-01 13:41:20.603505128 +0100
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python3-%{**}}
%define skip_python2 1
Name: python-more-itertools
-Version: 8.14.0
+Version: 9.0.0
Release: 0
Summary: More routines for operating on iterables, beyond itertools
License: MIT
++++++ more-itertools-8.14.0.tar.gz -> more-itertools-9.0.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/more-itertools-8.14.0/.github/workflows/python-app.yml
new/more-itertools-9.0.0/.github/workflows/python-app.yml
--- old/more-itertools-8.14.0/.github/workflows/python-app.yml 2022-08-09
16:00:34.670124000 +0200
+++ new/more-itertools-9.0.0/.github/workflows/python-app.yml 2022-10-18
15:38:19.069835000 +0200
@@ -8,7 +8,7 @@
runs-on: ubuntu-latest
strategy:
matrix:
- python-version: [3.6, 3.7, 3.8, 3.9.0, 3.10.0, pypy3]
+ python-version: ["3.7", "3.8", "3.9", "3.10", "3.11.0-rc.2",
"pypy-3.8"]
steps:
- uses: actions/checkout@v2
@@ -31,28 +31,28 @@
run: |
flake8 .
- name: Check formatting with black
- if: "matrix.python-version == '3.6'"
+ if: "matrix.python-version == '3.7'"
run: |
pip install -U black
black --check .
- name: Check type stubs with mypy
- if: "matrix.python-version != 'pypy3'"
+ if: "matrix.python-version != 'pypy-3.8'"
run: |
pip install -U mypy
stubtest more_itertools.more more_itertools.recipes
- name: Build docs with sphinx
- if: "matrix.python-version == '3.6'"
+ if: "matrix.python-version == '3.7'"
run: |
pip install -U sphinx sphinx_rtd_theme
sphinx-build -W -b html docs docs/_build/html
- name: Build packages
- if: "matrix.python-version == '3.6'"
+ if: "matrix.python-version == '3.7'"
run: |
pip install -U flit twine
flit build --setup-py
twine check dist/*
- name: Upload packages
- if: "matrix.python-version == '3.6'"
+ if: "matrix.python-version == '3.7'"
uses: actions/upload-artifact@v2
with:
name: more-itertools-packages
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/PKG-INFO
new/more-itertools-9.0.0/PKG-INFO
--- old/more-itertools-8.14.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
+++ new/more-itertools-9.0.0/PKG-INFO 1970-01-01 01:00:00.000000000 +0100
@@ -1,21 +1,21 @@
Metadata-Version: 2.1
Name: more-itertools
-Version: 8.14.0
+Version: 9.0.0
Summary: More routines for operating on iterables, beyond itertools
-Keywords:
itertools,iterator,iteration,filter,peek,peekable,collate,chunk,chunked
+Keywords: itertools,iterator,iteration,filter,peek,peekable,chunk,chunked
Author-email: Erik Rose <[email protected]>
-Requires-Python: >=3.5
+Requires-Python: >=3.7
Description-Content-Type: text/x-rst
Classifier: Development Status :: 5 - Production/Stable
Classifier: Intended Audience :: Developers
Classifier: Natural Language :: English
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.6
Classifier: Programming Language :: Python :: 3.7
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
+Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Programming Language :: Python :: Implementation :: CPython
Classifier: Programming Language :: Python :: Implementation :: PyPy
@@ -39,6 +39,7 @@
| | `ichunked
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ichunked>`_,
|
| | `chunked_even
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked_even>`_,
|
| | `sliced
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliced>`_,
|
+| | `constrained_batches
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.constrained_batches>`_,
|
| | `distribute
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distribute>`_,
|
| | `divide
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.divide>`_,
|
| | `split_at
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_at>`_,
|
@@ -48,6 +49,7 @@
| | `split_when
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_when>`_,
|
| | `bucket
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.bucket>`_,
|
| | `unzip
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unzip>`_,
|
+| | `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>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -62,8 +64,8 @@
| | `windowed_complete
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.windowed_complete>`_,
|
| | `pairwise
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pairwise>`_,
|
| | `triplewise
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.triplewise>`_,
|
-| | `sliding_window
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliding_window>`_
|
-| | `subslices
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.subslices>`_,
|
+| | `sliding_window
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliding_window>`_,
|
+| | `subslices
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.subslices>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Augmenting | `count_cycle
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.count_cycle>`_,
|
| | `intersperse
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.intersperse>`_,
|
@@ -103,7 +105,7 @@
| | `all_unique
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.all_unique>`_,
|
| | `minmax
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.minmax>`_,
|
| | `first_true
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first_true>`_,
|
-| | `quantify
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.quantify>`_
|
+| | `quantify
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.quantify>`_,
|
| | `iequals
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iequals>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Selecting | `islice_extended
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.islice_extended>`_,
|
@@ -126,7 +128,7 @@
| | `unique_everseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertoo
ls.unique_everseen>`_,
|
| | `unique_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_justseen>`_,
|
| | `duplicates_everseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_everseen>`_,
|
-| | `duplicates_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_justseen>`_
|
+| | `duplicates_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_justseen>`_,
|
| | `longest_common_prefix
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.longest_common_prefix>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Combinatorics | `distinct_permutations
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_permutations>`_,
|
@@ -167,6 +169,8 @@
| | `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>`_
|
+| | `sieve
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sieve>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/README.rst
new/more-itertools-9.0.0/README.rst
--- old/more-itertools-8.14.0/README.rst 2022-08-09 15:50:39.706522700
+0200
+++ new/more-itertools-9.0.0/README.rst 2022-10-18 15:38:19.069835000 +0200
@@ -15,6 +15,7 @@
| | `ichunked
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ichunked>`_,
|
| | `chunked_even
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked_even>`_,
|
| | `sliced
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliced>`_,
|
+| | `constrained_batches
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.constrained_batches>`_,
|
| | `distribute
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distribute>`_,
|
| | `divide
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.divide>`_,
|
| | `split_at
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_at>`_,
|
@@ -24,6 +25,7 @@
| | `split_when
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_when>`_,
|
| | `bucket
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.bucket>`_,
|
| | `unzip
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unzip>`_,
|
+| | `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>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
@@ -38,8 +40,8 @@
| | `windowed_complete
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.windowed_complete>`_,
|
| | `pairwise
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pairwise>`_,
|
| | `triplewise
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.triplewise>`_,
|
-| | `sliding_window
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliding_window>`_
|
-| | `subslices
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.subslices>`_,
|
+| | `sliding_window
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliding_window>`_,
|
+| | `subslices
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.subslices>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Augmenting | `count_cycle
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.count_cycle>`_,
|
| | `intersperse
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.intersperse>`_,
|
@@ -79,7 +81,7 @@
| | `all_unique
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.all_unique>`_,
|
| | `minmax
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.minmax>`_,
|
| | `first_true
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first_true>`_,
|
-| | `quantify
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.quantify>`_
|
+| | `quantify
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.quantify>`_,
|
| | `iequals
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iequals>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Selecting | `islice_extended
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.islice_extended>`_,
|
@@ -102,7 +104,7 @@
| | `unique_everseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertoo
ls.unique_everseen>`_,
|
| | `unique_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_justseen>`_,
|
| | `duplicates_everseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_everseen>`_,
|
-| | `duplicates_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_justseen>`_
|
+| | `duplicates_justseen
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_justseen>`_,
|
| | `longest_common_prefix
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.longest_common_prefix>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
| Combinatorics | `distinct_permutations
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_permutations>`_,
|
@@ -143,6 +145,8 @@
| | `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>`_
|
+| | `sieve
<https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sieve>`_
|
+------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/docs/api.rst
new/more-itertools-9.0.0/docs/api.rst
--- old/more-itertools-8.14.0/docs/api.rst 2022-08-09 15:43:59.871538400
+0200
+++ new/more-itertools-9.0.0/docs/api.rst 2022-10-18 15:37:02.101069200
+0200
@@ -17,6 +17,7 @@
.. autofunction:: ichunked
.. autofunction:: chunked_even
.. autofunction:: sliced
+.. autofunction:: constrained_batches(iterable, max_size, max_count=None,
get_len=len, strict=True)
.. autofunction:: distribute
.. autofunction:: divide
.. autofunction:: split_at
@@ -31,6 +32,7 @@
**Itertools recipes**
+.. autofunction:: batched
.. autofunction:: grouper
.. autofunction:: partition
@@ -287,3 +289,5 @@
.. autofunction:: consume
.. autofunction:: tabulate
.. autofunction:: repeatfunc
+.. autofunction:: polynomial_from_roots
+.. autofunction:: sieve
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/docs/versions.rst
new/more-itertools-9.0.0/docs/versions.rst
--- old/more-itertools-8.14.0/docs/versions.rst 2022-08-09 15:49:41.910306700
+0200
+++ new/more-itertools-9.0.0/docs/versions.rst 2022-10-18 15:38:19.069835000
+0200
@@ -5,6 +5,24 @@
.. automodule:: more_itertools
:noindex:
+9.0.0
+------
+
+* Potentially breaking changes
+ * :func:`grouper` no longer accepts an integer as its first argument.
Previously this raised a ``DeprecationWarning``.
+ * :func:`collate` has been removed. Use the built-in :func:`heapq.merge`
instead.
+ * :func:`windowed` now yields nothing when its iterable is empty.
+ * This library now advertises support for Python 3.7+.
+
+* New functions
+ * :func:`constrained_batches`
+ * :func:`batched` (from the Python itertools docs)
+ * :func:`polynomial_from_roots` (from the Python itertools docs)
+ * :func:`sieve` (from the Python itertools docs)
+
+* Other changes
+ * Some documentation issues were fixed (thanks to nanouasyn)
+
8.14.0
------
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/more_itertools/__init__.py
new/more-itertools-9.0.0/more_itertools/__init__.py
--- old/more-itertools-8.14.0/more_itertools/__init__.py 2022-08-09
15:53:46.644506700 +0200
+++ new/more-itertools-9.0.0/more_itertools/__init__.py 2022-10-18
15:38:19.069835000 +0200
@@ -3,4 +3,4 @@
from .more import * # noqa
from .recipes import * # noqa
-__version__ = '8.14.0'
+__version__ = '9.0.0'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/more_itertools/more.py
new/more-itertools-9.0.0/more_itertools/more.py
--- old/more-itertools-8.14.0/more_itertools/more.py 2022-08-09
15:43:59.877477000 +0200
+++ new/more-itertools-9.0.0/more_itertools/more.py 2022-10-18
15:38:19.073834700 +0200
@@ -3,7 +3,7 @@
from collections import Counter, defaultdict, deque, abc
from collections.abc import Sequence
from functools import partial, reduce, wraps
-from heapq import merge, heapify, heapreplace, heappop
+from heapq import heapify, heapreplace, heappop
from itertools import (
chain,
compress,
@@ -52,9 +52,9 @@
'chunked_even',
'circular_shifts',
'collapse',
- 'collate',
'combination_index',
'consecutive_groups',
+ 'constrained_batches',
'consumer',
'count_cycle',
'countable',
@@ -412,44 +412,6 @@
return self._cache[index]
-def collate(*iterables, **kwargs):
- """Return a sorted merge of the items from each of several already-sorted
- *iterables*.
-
- >>> list(collate('ACDZ', 'AZ', 'JKL'))
- ['A', 'A', 'C', 'D', 'J', 'K', 'L', 'Z', 'Z']
-
- Works lazily, keeping only the next value from each iterable in memory. Use
- :func:`collate` to, for example, perform a n-way mergesort of items that
- don't fit in memory.
-
- If a *key* function is specified, the iterables will be sorted according
- to its result:
-
- >>> key = lambda s: int(s) # Sort by numeric value, not by string
- >>> list(collate(['1', '10'], ['2', '11'], key=key))
- ['1', '2', '10', '11']
-
-
- If the *iterables* are sorted in descending order, set *reverse* to
- ``True``:
-
- >>> list(collate([5, 3, 1], [4, 2, 0], reverse=True))
- [5, 4, 3, 2, 1, 0]
-
- If the elements of the passed-in iterables are out of order, you might get
- unexpected results.
-
- On Python 3.5+, this function is an alias for :func:`heapq.merge`.
-
- """
- warnings.warn(
- "collate is no longer part of more_itertools, use heapq.merge",
- DeprecationWarning,
- )
- return merge(*iterables, **kwargs)
-
-
def consumer(func):
"""Decorator that automatically advances a PEP-342-style "reverse iterator"
to its first yield point so you don't have to call ``next()`` on it
@@ -875,7 +837,9 @@
yield tuple(window)
size = len(window)
- if size < n:
+ if size == 0:
+ return
+ elif size < n:
yield tuple(chain(window, repeat(fillvalue, n - size)))
elif 0 < i < min(step, n):
window += (fillvalue,) * i
@@ -4331,3 +4295,53 @@
hi, hi_key = y, y_key
return lo, hi
+
+
+def constrained_batches(
+ iterable, max_size, max_count=None, get_len=len, strict=True
+):
+ """Yield batches of items from *iterable* with a combined size limited by
+ *max_size*.
+
+ >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
+ >>> list(constrained_batches(iterable, 10))
+ [(b'12345', b'123'), (b'12345678', b'1', b'1'), (b'12', b'1')]
+
+ If a *max_count* is supplied, the number of items per batch is also
+ limited:
+
+ >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
+ >>> list(constrained_batches(iterable, 10, max_count = 2))
+ [(b'12345', b'123'), (b'12345678', b'1'), (b'1', b'12'), (b'1',)]
+
+ If a *get_len* function is supplied, use that instead of :func:`len` to
+ determine item size.
+
+ If *strict* is ``True``, raise ``ValueError`` if any single item is bigger
+ than *max_size*. Otherwise, allow single items to exceed *max_size*.
+ """
+ if max_size <= 0:
+ raise ValueError('maximum size must be greater than zero')
+
+ batch = []
+ batch_size = 0
+ batch_count = 0
+ for item in iterable:
+ item_len = get_len(item)
+ if strict and item_len > max_size:
+ raise ValueError('item size exceeds maximum size')
+
+ reached_count = batch_count == max_count
+ reached_size = item_len + batch_size > max_size
+ if batch_count and (reached_size or reached_count):
+ yield tuple(batch)
+ batch.clear()
+ batch_size = 0
+ batch_count = 0
+
+ batch.append(item)
+ batch_size += item_len
+ batch_count += 1
+
+ if batch:
+ yield tuple(batch)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/more_itertools/more.pyi
new/more-itertools-9.0.0/more_itertools/more.pyi
--- old/more-itertools-8.14.0/more_itertools/more.pyi 2022-08-09
15:43:59.881166500 +0200
+++ new/more-itertools-9.0.0/more_itertools/more.pyi 2022-10-18
15:38:19.073834700 +0200
@@ -72,7 +72,6 @@
@overload
def __getitem__(self, index: slice) -> List[_T]: ...
-def collate(*iterables: Iterable[_T], **kwargs: Any) -> Iterable[_T]: ...
def consumer(func: _GenFn) -> _GenFn: ...
def ilen(iterable: Iterable[object]) -> int: ...
def iterate(func: Callable[[_T], _T], start: _T) -> Iterator[_T]: ...
@@ -179,7 +178,7 @@
iterable: Iterable[_T],
*,
n: Optional[int] = ...,
- next_multiple: bool = ...
+ next_multiple: bool = ...,
) -> Iterator[Optional[_T]]: ...
@overload
def padded(
@@ -225,7 +224,7 @@
__iter1: Iterable[_T],
__iter2: Iterable[_T],
__iter3: Iterable[_T],
- *iterables: Iterable[_T]
+ *iterables: Iterable[_T],
) -> Iterator[Tuple[_T, ...]]: ...
@overload
def zip_offset(
@@ -233,7 +232,7 @@
*,
offsets: _SizedIterable[int],
longest: bool = ...,
- fillvalue: None = None
+ fillvalue: None = None,
) -> Iterator[Tuple[Optional[_T1]]]: ...
@overload
def zip_offset(
@@ -242,7 +241,7 @@
*,
offsets: _SizedIterable[int],
longest: bool = ...,
- fillvalue: None = None
+ fillvalue: None = None,
) -> Iterator[Tuple[Optional[_T1], Optional[_T2]]]: ...
@overload
def zip_offset(
@@ -252,7 +251,7 @@
*iterables: Iterable[_T],
offsets: _SizedIterable[int],
longest: bool = ...,
- fillvalue: None = None
+ fillvalue: None = None,
) -> Iterator[Tuple[Optional[_T], ...]]: ...
@overload
def zip_offset(
@@ -420,7 +419,7 @@
iterable: Iterable[_T],
func: Callable[[_T, _T], _U] = ...,
*,
- initial: None = ...
+ initial: None = ...,
) -> Iterator[Union[_T, _U]]: ...
@overload
def difference(
@@ -529,12 +528,12 @@
def filter_except(
validator: Callable[[Any], object],
iterable: Iterable[_T],
- *exceptions: Type[BaseException]
+ *exceptions: Type[BaseException],
) -> Iterator[_T]: ...
def map_except(
function: Callable[[Any], _U],
iterable: Iterable[_T],
- *exceptions: Type[BaseException]
+ *exceptions: Type[BaseException],
) -> Iterator[_U]: ...
def map_if(
iterable: Iterable[Any],
@@ -610,7 +609,7 @@
scalar_types: Union[
type, Tuple[Union[type, Tuple[Any, ...]], ...], None
] = ...,
- strict: bool = ...
+ strict: bool = ...,
) -> Iterable[Tuple[_T, ...]]: ...
def unique_in_window(
iterable: Iterable[_T], n: int, key: Optional[Callable[[_T], _U]] = ...
@@ -640,7 +639,7 @@
iterable_or_value: Iterable[_SupportsLessThanT],
*,
key: None = None,
- default: _U
+ default: _U,
) -> Union[_U, Tuple[_SupportsLessThanT, _SupportsLessThanT]]: ...
@overload
def minmax(
@@ -653,16 +652,23 @@
def minmax(
iterable_or_value: _SupportsLessThanT,
__other: _SupportsLessThanT,
- *others: _SupportsLessThanT
+ *others: _SupportsLessThanT,
) -> Tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
@overload
def minmax(
iterable_or_value: _T,
__other: _T,
*others: _T,
- key: Callable[[_T], _SupportsLessThan]
+ key: Callable[[_T], _SupportsLessThan],
) -> Tuple[_T, _T]: ...
def longest_common_prefix(
iterables: Iterable[Iterable[_T]],
) -> Iterator[_T]: ...
def iequals(*iterables: Iterable[object]) -> bool: ...
+def constrained_batches(
+ iterable: Iterable[object],
+ max_size: int,
+ max_count: Optional[int] = ...,
+ get_len: Callable[[_T], object] = ...,
+ strict: bool = ...,
+) -> Iterator[Tuple[_T]]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/more_itertools/recipes.py
new/more-itertools-9.0.0/more_itertools/recipes.py
--- old/more-itertools-8.14.0/more_itertools/recipes.py 2022-08-09
15:43:59.884092800 +0200
+++ new/more-itertools-9.0.0/more_itertools/recipes.py 2022-10-18
15:38:19.073834700 +0200
@@ -7,14 +7,16 @@
.. [1] http://docs.python.org/library/itertools.html#recipes
"""
+import math
import operator
-import warnings
from collections import deque
from collections.abc import Sized
+from functools import reduce
from itertools import (
chain,
combinations,
+ compress,
count,
cycle,
groupby,
@@ -28,6 +30,7 @@
__all__ = [
'all_equal',
+ 'batched',
'before_and_after',
'consume',
'convolve',
@@ -43,6 +46,7 @@
'pad_none',
'pairwise',
'partition',
+ 'polynomial_from_roots',
'powerset',
'prepend',
'quantify',
@@ -52,6 +56,7 @@
'random_product',
'repeatfunc',
'roundrobin',
+ 'sieve',
'sliding_window',
'subslices',
'tabulate',
@@ -364,11 +369,6 @@
UnequalIterablesError
"""
- if isinstance(iterable, int):
- warnings.warn(
- "grouper expects iterable as first parameter", DeprecationWarning
- )
- n, iterable = iterable, n
args = [iter(iterable)] * n
if incomplete == 'fill':
return zip_longest(*args, fillvalue=fillvalue)
@@ -738,11 +738,12 @@
transition.append(elem)
return
- def remainder_iterator():
- yield from transition
- yield from it
+ # Note: this is different from itertools recipes to allow nesting
+ # before_and_after remainders into before_and_after again. See tests
+ # for an example.
+ remainder_iterator = chain(transition, it)
- return true_iterator(), remainder_iterator()
+ return true_iterator(), remainder_iterator
def triplewise(iterable):
@@ -790,3 +791,51 @@
seq = list(iterable)
slices = starmap(slice, combinations(range(len(seq) + 1), 2))
return map(operator.getitem, repeat(seq), slices)
+
+
+def polynomial_from_roots(roots):
+ """Compute a polynomial's coefficients from its roots.
+
+ >>> roots = [5, -4, 3] # (x - 5) * (x + 4) * (x - 3)
+ >>> polynomial_from_roots(roots) # x^3 - 4 * x^2 - 17 * x + 60
+ [1, -4, -17, 60]
+ """
+ # Use math.prod for Python 3.8+,
+ prod = getattr(math, 'prod', lambda x: reduce(operator.mul, x, 1))
+ roots = list(map(operator.neg, roots))
+ return [
+ sum(map(prod, combinations(roots, k))) for k in range(len(roots) + 1)
+ ]
+
+
+def sieve(n):
+ """Yield the primes less than n.
+
+ >>> list(sieve(30))
+ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
+ """
+ isqrt = getattr(math, 'isqrt', lambda x: int(math.sqrt(x)))
+ 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)
+
+
+def batched(iterable, n):
+ """Batch data into lists of length *n*. The last batch may be shorter.
+
+ >>> list(batched('ABCDEFG', 3))
+ [['A', 'B', 'C'], ['D', 'E', 'F'], ['G']]
+
+ This recipe is from the ``itertools`` docs. This library also provides
+ :func:`chunked`, which has a different implementation.
+ """
+ it = iter(iterable)
+ while True:
+ batch = list(islice(it, n))
+ if not batch:
+ break
+ yield batch
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/more_itertools/recipes.pyi
new/more-itertools-9.0.0/more_itertools/recipes.pyi
--- old/more-itertools-8.14.0/more_itertools/recipes.pyi 2022-04-29
16:09:30.648787500 +0200
+++ new/more-itertools-9.0.0/more_itertools/recipes.pyi 2022-10-18
15:38:19.073834700 +0200
@@ -6,6 +6,7 @@
Iterator,
List,
Optional,
+ Sequence,
Tuple,
TypeVar,
Union,
@@ -39,20 +40,12 @@
func: Callable[..., _U], times: Optional[int] = ..., *args: Any
) -> Iterator[_U]: ...
def pairwise(iterable: Iterable[_T]) -> Iterator[Tuple[_T, _T]]: ...
-@overload
def grouper(
iterable: Iterable[_T],
n: int,
incomplete: str = ...,
fillvalue: _U = ...,
) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
-@overload
-def grouper( # Deprecated interface
- iterable: int,
- n: Iterable[_T],
- incomplete: str = ...,
- fillvalue: _U = ...,
-) -> Iterator[Tuple[Union[_T, _U], ...]]: ...
def roundrobin(*iterables: Iterable[_T]) -> Iterator[_T]: ...
def partition(
pred: Optional[Callable[[_T], object]], iterable: Iterable[_T]
@@ -109,3 +102,9 @@
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]: ...
+def sieve(n: int) -> Iterator[int]: ...
+def batched(
+ iterable: Iterable[_T],
+ n: int,
+) -> Iterator[List[_T]]: ...
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/pyproject.toml
new/more-itertools-9.0.0/pyproject.toml
--- old/more-itertools-8.14.0/pyproject.toml 2022-08-09 15:43:59.886106300
+0200
+++ new/more-itertools-9.0.0/pyproject.toml 2022-10-18 15:38:19.073834700
+0200
@@ -6,7 +6,7 @@
name = "more-itertools"
authors = [{name = "Erik Rose", email = "[email protected]"}]
readme = "README.rst"
-requires-python = ">=3.5"
+requires-python = ">=3.7"
license = {file = "LICENSE"}
keywords = [
"itertools",
@@ -15,7 +15,6 @@
"filter",
"peek",
"peekable",
- "collate",
"chunk",
"chunked",
]
@@ -25,11 +24,11 @@
"Natural Language :: English",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
- "Programming Language :: Python :: 3.6",
"Programming Language :: Python :: 3.7",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Programming Language :: Python :: 3.10",
+ "Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3 :: Only",
"Programming Language :: Python :: Implementation :: CPython",
"Programming Language :: Python :: Implementation :: PyPy",
@@ -45,5 +44,5 @@
[tool.black]
line-length = 79
-target-version = ['py35']
+target-version = ['py37']
skip-string-normalization = true
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/setup.cfg
new/more-itertools-9.0.0/setup.cfg
--- old/more-itertools-8.14.0/setup.cfg 2022-08-09 15:53:46.644978300 +0200
+++ new/more-itertools-9.0.0/setup.cfg 2022-10-18 15:38:19.073834700 +0200
@@ -1,5 +1,5 @@
[bumpversion]
-current_version = 8.14.0
+current_version = 9.0.0
commit = True
tag = False
files = more_itertools/__init__.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/tests/test_more.py
new/more-itertools-9.0.0/tests/test_more.py
--- old/more-itertools-8.14.0/tests/test_more.py 2022-08-09
15:43:59.889434000 +0200
+++ new/more-itertools-9.0.0/tests/test_more.py 2022-10-18 15:38:19.073834700
+0200
@@ -7,7 +7,6 @@
from doctest import DocTestSuite
from fractions import Fraction
from functools import partial, reduce
-from heapq import merge
from io import StringIO
from itertools import (
accumulate,
@@ -41,51 +40,6 @@
return tests
-class CollateTests(TestCase):
- """Unit tests for ``collate()``"""
-
- # Also accidentally tests peekable, though that could use its own tests
-
- def test_default(self):
- """Test with the default `key` function."""
- iterables = [range(4), range(7), range(3, 6)]
- self.assertEqual(
- sorted(reduce(list.__add__, [list(it) for it in iterables])),
- list(mi.collate(*iterables)),
- )
-
- def test_key(self):
- """Test using a custom `key` function."""
- iterables = [range(5, 0, -1), range(4, 0, -1)]
- actual = sorted(
- reduce(list.__add__, [list(it) for it in iterables]), reverse=True
- )
- expected = list(mi.collate(*iterables, key=lambda x: -x))
- self.assertEqual(actual, expected)
-
- def test_empty(self):
- """Be nice if passed an empty list of iterables."""
- self.assertEqual([], list(mi.collate()))
-
- def test_one(self):
- """Work when only 1 iterable is passed."""
- self.assertEqual([0, 1], list(mi.collate(range(2))))
-
- def test_reverse(self):
- """Test the `reverse` kwarg."""
- iterables = [range(4, 0, -1), range(7, 0, -1), range(3, 6, -1)]
-
- actual = sorted(
- reduce(list.__add__, [list(it) for it in iterables]), reverse=True
- )
- expected = list(mi.collate(*iterables, reverse=True))
- self.assertEqual(actual, expected)
-
- def test_alias(self):
- self.assertNotEqual(merge.__doc__, mi.collate.__doc__)
- self.assertNotEqual(partial.__doc__, mi.collate.__doc__)
-
-
class ChunkedTests(TestCase):
"""Tests for ``chunked()``"""
@@ -289,11 +243,6 @@
class PeekableTests(PeekableMixinTests, TestCase):
- """Tests for ``peekable()`` behavior not incidentally covered by testing
- ``collate()``
-
- """
-
cls = mi.peekable
def test_indexing(self):
@@ -783,64 +732,55 @@
class WindowedTests(TestCase):
- """Tests for ``windowed()``"""
-
def test_basic(self):
- actual = list(mi.windowed([1, 2, 3, 4, 5], 3))
- expected = [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
- self.assertEqual(actual, expected)
-
- def test_large_size(self):
- """
- When the window size is larger than the iterable, and no fill value is
- given,``None`` should be filled in.
- """
- actual = list(mi.windowed([1, 2, 3, 4, 5], 6))
- expected = [(1, 2, 3, 4, 5, None)]
- self.assertEqual(actual, expected)
-
- def test_fillvalue(self):
- """
- When sizes don't match evenly, the given fill value should be used.
- """
iterable = [1, 2, 3, 4, 5]
- for n, kwargs, expected in [
- (6, {}, [(1, 2, 3, 4, 5, '!')]), # n > len(iterable)
- (3, {'step': 3}, [(1, 2, 3), (4, 5, '!')]), # using ``step``
- ]:
- actual = list(mi.windowed(iterable, n, fillvalue='!', **kwargs))
- self.assertEqual(actual, expected)
+ for n, expected in (
+ (6, [(1, 2, 3, 4, 5, None)]),
+ (5, [(1, 2, 3, 4, 5)]),
+ (4, [(1, 2, 3, 4), (2, 3, 4, 5)]),
+ (3, [(1, 2, 3), (2, 3, 4), (3, 4, 5)]),
+ (2, [(1, 2), (2, 3), (3, 4), (4, 5)]),
+ (1, [(1,), (2,), (3,), (4,), (5,)]),
+ (0, [()]),
+ ):
+ with self.subTest(n=n):
+ actual = list(mi.windowed(iterable, n))
+ self.assertEqual(actual, expected)
- def test_zero(self):
- """When the window size is zero, an empty tuple should be emitted."""
- actual = list(mi.windowed([1, 2, 3, 4, 5], 0))
- expected = [tuple()]
+ def test_fillvalue(self):
+ actual = list(mi.windowed([1, 2, 3, 4, 5], 6, fillvalue='!'))
+ expected = [(1, 2, 3, 4, 5, '!')]
self.assertEqual(actual, expected)
- def test_negative(self):
- """When the window size is negative, ValueError should be raised."""
- with self.assertRaises(ValueError):
- list(mi.windowed([1, 2, 3, 4, 5], -1))
-
def test_step(self):
- """The window should advance by the number of steps provided"""
iterable = [1, 2, 3, 4, 5, 6, 7]
for n, step, expected in [
(3, 2, [(1, 2, 3), (3, 4, 5), (5, 6, 7)]), # n > step
(3, 3, [(1, 2, 3), (4, 5, 6), (7, None, None)]), # n == step
- (3, 4, [(1, 2, 3), (5, 6, 7)]), # line up nicely
+ (3, 4, [(1, 2, 3), (5, 6, 7)]), # lines up nicely
(3, 5, [(1, 2, 3), (6, 7, None)]), # off by one
(3, 6, [(1, 2, 3), (7, None, None)]), # off by two
(3, 7, [(1, 2, 3)]), # step past the end
(7, 8, [(1, 2, 3, 4, 5, 6, 7)]), # step > len(iterable)
]:
- actual = list(mi.windowed(iterable, n, step=step))
- self.assertEqual(actual, expected)
+ with self.subTest(n=n, step=step):
+ actual = list(mi.windowed(iterable, n, step=step))
+ self.assertEqual(actual, expected)
+ def test_invalid_step(self):
# Step must be greater than or equal to 1
with self.assertRaises(ValueError):
- list(mi.windowed(iterable, 3, step=0))
+ list(mi.windowed([1, 2, 3, 4, 5], 3, step=0))
+
+ def test_fillvalue_step(self):
+ actual = list(mi.windowed([1, 2, 3, 4, 5], 3, fillvalue='!', step=3))
+ expected = [(1, 2, 3), (4, 5, '!')]
+ self.assertEqual(actual, expected)
+
+ def test_negative(self):
+ with self.assertRaises(ValueError):
+ list(mi.windowed([1, 2, 3, 4, 5], -1))
class SubstringsTests(TestCase):
@@ -5137,3 +5077,100 @@
def test_not_identical_but_equal(self):
self.assertTrue([1, True], [1.0, complex(1, 0)])
+
+
+class ConstrainedBatchesTests(TestCase):
+ def test_basic(self):
+ zen = [
+ 'Beautiful is better than ugly',
+ 'Explicit is better than implicit',
+ 'Simple is better than complex',
+ 'Complex is better than complicated',
+ 'Flat is better than nested',
+ 'Sparse is better than dense',
+ 'Readability counts',
+ ]
+ for size, expected in (
+ (
+ 34,
+ [
+ (zen[0],),
+ (zen[1],),
+ (zen[2],),
+ (zen[3],),
+ (zen[4],),
+ (zen[5],),
+ (zen[6],),
+ ],
+ ),
+ (
+ 61,
+ [
+ (zen[0], zen[1]),
+ (zen[2],),
+ (zen[3], zen[4]),
+ (zen[5], zen[6]),
+ ],
+ ),
+ (
+ 90,
+ [
+ (zen[0], zen[1], zen[2]),
+ (zen[3], zen[4], zen[5]),
+ (zen[6],),
+ ],
+ ),
+ (
+ 124,
+ [(zen[0], zen[1], zen[2], zen[3]), (zen[4], zen[5], zen[6])],
+ ),
+ (
+ 150,
+ [(zen[0], zen[1], zen[2], zen[3], zen[4]), (zen[5], zen[6])],
+ ),
+ (
+ 177,
+ [(zen[0], zen[1], zen[2], zen[3], zen[4], zen[5]), (zen[6],)],
+ ),
+ ):
+ with self.subTest(size=size):
+ actual = list(mi.constrained_batches(iter(zen), size))
+ self.assertEqual(actual, expected)
+
+ def test_max_count(self):
+ iterable = ['1', '1', '12345678', '12345', '12345']
+ max_size = 10
+ max_count = 2
+ actual = list(mi.constrained_batches(iterable, max_size, max_count))
+ expected = [('1', '1'), ('12345678',), ('12345', '12345')]
+ self.assertEqual(actual, expected)
+
+ def test_strict(self):
+ iterable = ['1', '123456789', '1']
+ size = 8
+ with self.assertRaises(ValueError):
+ list(mi.constrained_batches(iterable, size))
+
+ actual = list(mi.constrained_batches(iterable, size, strict=False))
+ expected = [('1',), ('123456789',), ('1',)]
+ self.assertEqual(actual, expected)
+
+ def test_get_len(self):
+ class Record(tuple):
+ def total_size(self):
+ return sum(len(x) for x in self)
+
+ record_3 = Record(('1', '23'))
+ record_5 = Record(('1234', '1'))
+ record_10 = Record(('1', '12345678', '1'))
+ record_2 = Record(('1', '1'))
+ iterable = [record_3, record_5, record_10, record_2]
+
+ self.assertEqual(
+ list(
+ mi.constrained_batches(
+ iterable, 10, get_len=lambda x: x.total_size()
+ )
+ ),
+ [(record_3, record_5), (record_10,), (record_2,)],
+ )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/more-itertools-8.14.0/tests/test_recipes.py
new/more-itertools-9.0.0/tests/test_recipes.py
--- old/more-itertools-8.14.0/tests/test_recipes.py 2022-08-09
15:43:59.891580000 +0200
+++ new/more-itertools-9.0.0/tests/test_recipes.py 2022-10-18
15:38:19.073834700 +0200
@@ -1,6 +1,5 @@
-import warnings
-
from doctest import DocTestSuite
+from functools import reduce
from itertools import combinations, count, permutations
from math import factorial
from unittest import TestCase
@@ -335,16 +334,6 @@
with self.assertRaises(ValueError):
list(mi.grouper(iter(seq), n, incomplete='strict'))
- def test_legacy_order(self):
- with warnings.catch_warnings(record=True) as caught:
- warnings.simplefilter('always')
- self.assertEqual(
- list(mi.grouper(3, 'ABCDEF')),
- [('A', 'B', 'C'), ('D', 'E', 'F')],
- )
-
- self.assertEqual(caught[0].category, DeprecationWarning)
-
def test_invalid_incomplete(self):
with self.assertRaises(ValueError):
list(mi.grouper('ABCD', 3, incomplete='bogus'))
@@ -783,6 +772,39 @@
self.assertEqual(list(before), [1, True])
self.assertEqual(list(after), [0, False])
+ @staticmethod
+ def _group_events(events):
+ events = iter(events)
+
+ while True:
+ try:
+ operation = next(events)
+ except StopIteration:
+ break
+ assert operation in ["SUM", "MULTIPLY"]
+
+ # Here, the remainder `events` is passed into `before_and_after`
+ # again, which would be problematic if the remainder is a
+ # generator function (as in Python 3.10 itertools recipes), since
+ # that creates recursion. `itertools.chain` solves this problem.
+ numbers, events = mi.before_and_after(
+ lambda e: isinstance(e, int), events
+ )
+
+ yield (operation, numbers)
+
+ def test_nested_remainder(self):
+ events = ["SUM", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
+ events += ["MULTIPLY", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
+
+ for operation, numbers in self._group_events(events):
+ if operation == "SUM":
+ res = sum(numbers)
+ self.assertEqual(res, 55)
+ elif operation == "MULTIPLY":
+ res = reduce(lambda a, b: a * b, numbers)
+ self.assertEqual(res, 3628800)
+
class TriplewiseTests(TestCase):
def test_basic(self):
@@ -843,3 +865,80 @@
with self.subTest(expected=expected):
actual = list(mi.subslices(iterable))
self.assertEqual(actual, expected)
+
+
+class PolynomialFromRootsTests(TestCase):
+ def test_basic(self):
+ for roots, expected in [
+ ((2, 1, -1), [1, -2, -1, 2]),
+ ((2, 3), [1, -5, 6]),
+ ((1, 2, 3), [1, -6, 11, -6]),
+ ((2, 4, 1), [1, -7, 14, -8]),
+ ]:
+ with self.subTest(roots=roots):
+ actual = mi.polynomial_from_roots(roots)
+ self.assertEqual(actual, expected)
+
+
+class SieveTests(TestCase):
+ def test_basic(self):
+ self.assertEqual(
+ list(mi.sieve(67)),
+ [
+ 2,
+ 3,
+ 5,
+ 7,
+ 11,
+ 13,
+ 17,
+ 19,
+ 23,
+ 29,
+ 31,
+ 37,
+ 41,
+ 43,
+ 47,
+ 53,
+ 59,
+ 61,
+ ],
+ )
+ self.assertEqual(list(mi.sieve(68))[-1], 67)
+
+ def test_prime_counts(self):
+ for n, expected in (
+ (100, 25),
+ (1_000, 168),
+ (10_000, 1229),
+ (100_000, 9592),
+ (1_000_000, 78498),
+ ):
+ with self.subTest(n=n):
+ self.assertEqual(mi.ilen(mi.sieve(n)), expected)
+
+ def test_small_numbers(self):
+ with self.assertRaises(ValueError):
+ list(mi.sieve(-1))
+
+ for n in (0, 1, 2):
+ with self.subTest(n=n):
+ self.assertEqual(list(mi.sieve(n)), [])
+
+
+class BatchedTests(TestCase):
+ def test_basic(self):
+ iterable = range(1, 5 + 1)
+ for n, expected in (
+ (0, []),
+ (1, [[1], [2], [3], [4], [5]]),
+ (2, [[1, 2], [3, 4], [5]]),
+ (3, [[1, 2, 3], [4, 5]]),
+ (4, [[1, 2, 3, 4], [5]]),
+ (5, [[1, 2, 3, 4, 5]]),
+ (6, [[1, 2, 3, 4, 5]]),
+ ):
+ with self.subTest(n=n):
+ actual = list(mi.batched(iterable, n))
+ self.assertEqual(actual, expected)