Projects
openEuler:Mainline
python-more-itertools
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 4
View file
_service:tar_scm:python-more-itertools.spec
Changed
@@ -1,5 +1,5 @@ Name: python-more-itertools -Version: 8.12.0 +Version: 9.1.0 Release: 1 Summary: An opensource python library wrapping around itertools License: MIT @@ -15,6 +15,8 @@ %package -n python3-more-itertools Summary: An opensource python library wrapping around itertools BuildRequires: python3-devel python3-six +BuildRequires: python3-pip python3-wheel +BuildRequires: python3-flit-core %{?python_provide:%python_provide python3-more-itertools} %description -n python3-more-itertools @@ -26,21 +28,24 @@ %autosetup -n more-itertools-%{version} -p1 %build -%py3_build +%pyproject_build %install -%py3_install +%pyproject_install %check -%{__python3} ./setup.py test +export PYTHONPATH=%{buildroot}%{python3_sitelib} +%{__python3} -m unittest -v %files -n python3-more-itertools %doc README.rst LICENSE %{python3_sitelib}/more_itertools/ -%exclude %{python3_sitelib}/more_itertools/tests -%{python3_sitelib}/more_itertools-%{version}-py%{python3_version}.egg-info +%{python3_sitelib}/more_itertools-%{version}*-info %changelog +* Wed Jun 07 2023 yaoxin <yao_xin001@hoperun.com> - 9.1.0-1 +- Update to 9.1.0 + * Thu Jul 7 2022 wulei <wulei80@h-partners.com> - 8.12.0-1 - Upgrade to 8.12.0
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/.
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/.github
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/.github/ISSUE_TEMPLATE
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/.github/workflows
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/docs
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/docs/_static
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/tests
Deleted
-(directory)
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/.github/workflows/python-app.yml -> _service:tar_scm:more-itertools-9.1.0.tar.gz/.github/workflows/python-app.yml
Changed
@@ -8,12 +8,12 @@ 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", "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 @@ -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 twine wheel - python setup.py sdist bdist_wheel + 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
View file
_service:tar_scm:more-itertools-9.1.0.tar.gz/PKG-INFO
Added
@@ -0,0 +1,246 @@ +Metadata-Version: 2.1 +Name: more-itertools +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 <erikrose@grinchcentral.com> +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.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 +Classifier: Topic :: Software Development :: Libraries +Project-URL: Homepage, https://github.com/more-itertools/more-itertools + +============== +More Itertools +============== + +.. image:: https://readthedocs.org/projects/more-itertools/badge/?version=latest + :target: https://more-itertools.readthedocs.io/en/stable/ + +Python's ``itertools`` library is a gem - you can compose elegant solutions +for a variety of problems with the functions it provides. In ``more-itertools`` +we collect additional building blocks, recipes, and routines for working with +Python iterables. + ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Grouping | `chunked <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked>`_, | +| | `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>`_, | +| | `split_before <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_before>`_, | +| | `split_after <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_after>`_, | +| | `split_into <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_into>`_, | +| | `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>`_ | +| | `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>`_, | +| | `seekable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.seekable>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Windowing | `windowed <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.windowed>`_, | +| | `substrings <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.substrings>`_, | +| | `substrings_indexes <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.substrings_indexes>`_, | +| | `stagger <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.stagger>`_, | +| | `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>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| 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>`_, | +| | `padded <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.padded>`_, | +| | `repeat_each <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_each>`_, | +| | `mark_ends <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.mark_ends>`_, | +| | `repeat_last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_last>`_, | +| | `adjacent <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.adjacent>`_, | +| | `groupby_transform <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.groupby_transform>`_, | +| | `pad_none <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pad_none>`_, | +| | `ncycles <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ncycles>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Combining | `collapse <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse>`_, | +| | `sort_together <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sort_together>`_, | +| | `interleave <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave>`_, | +| | `interleave_longest <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_longest>`_, | +| | `interleave_evenly <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_evenly>`_, | +| | `zip_offset <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_offset>`_, | +| | `zip_equal <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_equal>`_, | +| | `zip_broadcast <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_broadcast>`_, | +| | `dotproduct <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.dotproduct>`_, | +| | `convolve <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.convolve>`_, | +| | `flatten <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.flatten>`_, | +| | `roundrobin <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.roundrobin>`_, | +| | `prepend <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.prepend>`_, | +| | `value_chain <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.value_chain>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Summarizing | `ilen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ilen>`_, | +| | `unique_to_each <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_to_each>`_, | +| | `sample <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sample>`_, | +| | `consecutive_groups <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consecutive_groups>`_, | +| | `run_length <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.run_length>`_, | +| | `map_reduce <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_reduce>`_, | +| | `exactly_n <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.exactly_n>`_, | +| | `is_sorted <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.is_sorted>`_, | +| | `all_equal <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.all_equal>`_, | +| | `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>`_, | +| | `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>`_, | +| | `first <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first>`_, | +| | `last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.last>`_, | +| | `one <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.one>`_, | +| | `only <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.only>`_, | +| | `strictly_n <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.strictly_n>`_, | +| | `strip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.strip>`_, | +| | `lstrip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.lstrip>`_, | +| | `rstrip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.rstrip>`_, | +| | `filter_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.filter_except>`_, | +| | `map_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_except>`_, | +| | `nth_or_last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_or_last>`_, | +| | `unique_in_window <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_in_window>`_, | +| | `before_and_after <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_, | +| | `nth <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth>`_, | +| | `take <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.take>`_, | +| | `tail <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.tail>`_, | +| | `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>`_, | +| | `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>`_, | +| | `distinct_combinations <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_combinations>`_, | +| | `circular_shifts <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.circular_shifts>`_, | +| | `partitions <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partitions>`_, | +| | `set_partitions <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.set_partitions>`_, | +| | `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>`_, | +| | `random_combination <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_combination>`_, | +| | `random_combination_with_replacement <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_combination_with_replacement>`_, | +| | `nth_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_product>`_, | +| | `nth_permutation <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_permutation>`_, | +| | `nth_combination <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_combination>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Wrapping | `always_iterable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable>`_, | +| | `always_reversible <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_reversible>`_, | +| | `countable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.countable>`_, | +| | `consumer <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consumer>`_, | +| | `with_iter <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.with_iter>`_, | +| | `iter_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_except>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ +| Others | `locate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.locate>`_, | +| | `rlocate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.rlocate>`_, | +| | `replace <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.replace>`_, | +| | `numeric_range <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.numeric_range>`_, | +| | `side_effect <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.side_effect>`_, | +| | `iterate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iterate>`_, | +| | `difference <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.difference>`_, | +| | `make_decorator <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.make_decorator>`_, | +| | `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>`_, | +| | `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>`_ | ++------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ + + +Getting started +=============== + +To get started, install the library with `pip <https://pip.pypa.io/en/stable/>`_: + +.. code-block:: shell + + pip install more-itertools + +The recipes from the `itertools docs <https://docs.python.org/3/library/itertools.html#itertools-recipes>`_ +are included in the top-level package: + +.. code-block:: python + + >>> from more_itertools import flatten + >>> iterable = (0, 1), (2, 3) + >>> list(flatten(iterable)) + 0, 1, 2, 3 + +Several new recipes are available as well: + +.. code-block:: python + + >>> from more_itertools import chunked + >>> iterable = 0, 1, 2, 3, 4, 5, 6, 7, 8 + >>> list(chunked(iterable, 3)) + 0, 1, 2, 3, 4, 5, 6, 7, 8 + + >>> from more_itertools import spy + >>> iterable = (x * x for x in range(1, 6)) + >>> head, iterable = spy(iterable, n=3) + >>> list(head) + 1, 4, 9 + >>> list(iterable) + 1, 4, 9, 16, 25 + + + +For the full listing of functions, see the `API documentation <https://more-itertools.readthedocs.io/en/stable/api.html>`_. + + +Links elsewhere +=============== + +Blog posts about ``more-itertools``: + +* `Yo, I heard you like decorators <https://www.bbayles.com/index/decorator_factory>`__ +* `Tour of Python Itertools <https://martinheinz.dev/blog/16>`__ (`Alternate <https://dev.to/martinheinz/tour-of-python-itertools-4122>`__) +* `Real-World Python More Itertools <https://www.gidware.com/real-world-more-itertools/>`_ + + +Development +=========== + +``more-itertools`` is maintained by `@erikrose <https://github.com/erikrose>`_ +and `@bbayles <https://github.com/bbayles>`_, with help from `many others <https://github.com/more-itertools/more-itertools/graphs/contributors>`_. +If you have a problem or suggestion, please file a bug or pull request in this +repository. Thanks for contributing! + + +Version History +=============== + +The version history can be found in `documentation <https://more-itertools.readthedocs.io/en/stable/versions.html>`_. +
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/README.rst -> _service:tar_scm:more-itertools-9.1.0.tar.gz/README.rst
Changed
@@ -13,7 +13,9 @@ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ | Grouping | `chunked <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked>`_, | | | `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>`_, | @@ -23,8 +25,10 @@ | | `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>`_ | +| | `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>`_, | @@ -37,11 +41,13 @@ | | `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>`_ | +| | `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>`_, | | | `padded <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.padded>`_, | +| | `repeat_each <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_each>`_, | | | `mark_ends <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.mark_ends>`_, | | | `repeat_last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_last>`_, | | | `adjacent <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.adjacent>`_, | @@ -76,7 +82,8 @@ | | `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>`_, | | | `first <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first>`_, | @@ -98,7 +105,8 @@ | | `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>`_, | | | `distinct_combinations <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_combinations>`_, | @@ -108,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>`_, | @@ -134,9 +143,15 @@ | | `make_decorator <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.make_decorator>`_, | | | `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>`_ | +| | `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>`_ | +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+ @@ -198,3 +213,9 @@ and `@bbayles <https://github.com/bbayles>`_, with help from `many others <https://github.com/more-itertools/more-itertools/graphs/contributors>`_. If you have a problem or suggestion, please file a bug or pull request in this repository. Thanks for contributing! + + +Version History +=============== + +The version history can be found in `documentation <https://more-itertools.readthedocs.io/en/stable/versions.html>`_.
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/docs/api.rst -> _service:tar_scm:more-itertools-9.1.0.tar.gz/docs/api.rst
Changed
@@ -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,8 +32,10 @@ **Itertools recipes** +.. autofunction:: batched .. autofunction:: grouper .. autofunction:: partition +.. autofunction:: transpose Lookahead and lookback @@ -72,6 +75,7 @@ .. autofunction:: pairwise .. autofunction:: triplewise .. autofunction:: sliding_window +.. autofunction:: subslices Augmenting @@ -152,6 +156,7 @@ .. function:: minmax(iterable, *, key, default) .. autofunction:: minmax(arg1, arg2, *args, key) :noindex: +.. autofunction:: iequals ---- @@ -189,6 +194,7 @@ .. autofunction:: unique_in_window .. autofunction:: duplicates_everseen .. autofunction:: duplicates_justseen +.. autofunction:: longest_common_prefix ---- @@ -219,6 +225,7 @@ .. autofunction:: product_index .. autofunction:: combination_index .. autofunction:: permutation_index +.. autofunction:: gray_product ---- @@ -281,6 +288,11 @@ **Itertools recipes** +.. autofunction:: iter_index .. autofunction:: consume .. autofunction:: tabulate .. autofunction:: repeatfunc +.. autofunction:: polynomial_from_roots +.. autofunction:: sieve +.. autofunction:: factor +.. autofunction:: matmul
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/docs/requirements.txt -> _service:tar_scm:more-itertools-9.1.0.tar.gz/docs/requirements.txt
Changed
@@ -1,27 +1,1 @@ -# What we want -Sphinx==4.3.0 - -# What we get -alabaster==0.7.12 -Babel==2.9.1 -certifi==2021.10.8 -charset-normalizer==2.0.7 -docutils==0.17.1 -idna==3.3 -imagesize==1.3.0 -Jinja2==3.0.3 -MarkupSafe==2.0.1 -packaging==21.2 -Pygments==2.10.0 -pyparsing==2.4.7 -pytz==2021.3 -requests==2.26.0 -six==1.16.0 -snowballstemmer==2.2.0 -sphinxcontrib-applehelp==1.0.2 -sphinxcontrib-devhelp==1.0.2 -sphinxcontrib-htmlhelp==2.0.0 -sphinxcontrib-jsmath==1.0.1 -sphinxcontrib-qthelp==1.0.3 -sphinxcontrib-serializinghtml==1.1.5 -urllib3==1.26.7 +Sphinx
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/docs/versions.rst -> _service:tar_scm:more-itertools-9.1.0.tar.gz/docs/versions.rst
Changed
@@ -5,6 +5,75 @@ .. 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 +------ + +* 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 +------ + +* New functions + * :func:`longest_common_prefix` (thanks to nanouasyn) + * :func:`iequals` (thanks to nanouasyn) + +* Changes to existing functions + * `concurrent.futures.ThreadPoolExecutor` is now imported lazily in :func:`callback_iter`. + * :func:`tail` is now optimized for iterables with a fixed length. + +* Other changes + * Some documentation issues were fixed (thanks to pochmann and timgates42) + * This library is now marked for Python 3.10 compatibility in PyPI (thanks to chayim) + +8.13.0 +------ + +* New functions + * The :func:`subslices` recipe from the `itertools` docs was added (thanks to rhettinger) + +* Changes to existing functions + * The :func:`ichunked` function is now more efficient (thanks to hjtran0 and seanmacavaney) + * The :func:`difference` function is now more efficient (thanks to Masynchin) + * The :func:`grouper` recipe now has more features, mirroring the one in the `itertools` docs (thanks to rhettinger) + +* Other changes + * Some documentation issues were fixed (thanks to medvied and Freed-Wu) + * The `more_itertools` package is now built with `flit` (thanks to mgorny) + 8.12.0 ------
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools/__init__.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/more_itertools/__init__.py
Changed
@@ -1,4 +1,6 @@ +"""More routines for operating on iterables, beyond itertools""" + from .more import * # noqa from .recipes import * # noqa -__version__ = '8.12.0' +__version__ = '9.1.0'
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools/more.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/more_itertools/more.py
Changed
@@ -2,9 +2,8 @@ from collections import Counter, defaultdict, deque, abc from collections.abc import Sequence -from concurrent.futures import ThreadPoolExecutor from functools import partial, reduce, wraps -from heapq import merge, heapify, heapreplace, heappop +from heapq import heapify, heapreplace, heappop from itertools import ( chain, compress, @@ -27,12 +26,16 @@ from time import monotonic from .recipes import ( + _marker, + _zip_equal, + UnequalIterablesError, consume, flatten, pairwise, powerset, take, unique_everseen, + all_equal, ) __all__ = @@ -49,9 +52,9 @@ 'chunked_even', 'circular_shifts', 'collapse', - 'collate', 'combination_index', 'consecutive_groups', + 'constrained_batches', 'consumer', 'count_cycle', 'countable', @@ -65,8 +68,10 @@ 'exactly_n', 'filter_except', 'first', + 'gray_product', 'groupby_transform', 'ichunked', + 'iequals', 'ilen', 'interleave', 'interleave_evenly', @@ -77,6 +82,7 @@ 'iterate', 'last', 'locate', + 'longest_common_prefix', 'lstrip', 'make_decorator', 'map_except', @@ -133,9 +139,6 @@ -_marker = object() - - def chunked(iterable, n, strict=False): """Break *iterable* into lists of length *n*: @@ -410,44 +413,6 @@ return self._cacheindex -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 @@ -694,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: @@ -873,7 +839,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 @@ -1335,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' @@ -1425,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 @@ -1646,45 +1616,6 @@ ) -class UnequalIterablesError(ValueError): - def __init__(self, details=None): - msg = 'Iterables have different lengths' - if details is not None: - msg += (': index 0 has length {}; index {} has length {}').format( - *details - ) - - super().__init__(msg) - - -def _zip_equal_generator(iterables): - for combo in zip_longest(*iterables, fillvalue=_marker): - for val in combo: - if val is _marker: - raise UnequalIterablesError() - yield combo - - -def _zip_equal(*iterables): - # Check whether the iterables are all the same size. - try: - first_size = len(iterables0) - for i, it in enumerate(iterables1:, 1): - size = len(it) - if size != first_size: - break - else: - # If we didn't break out, we can use the built-in zip. - return zip(*iterables) - - # If we did break out, there was a mismatch. - raise UnequalIterablesError(details=(first_size, i, size)) - # If any one of the iterables didn't have a length, start reading - # them until one runs out. - except TypeError: - return _zip_equal_generator(iterables) - - def zip_equal(*iterables): """``zip`` the input *iterables* together, but raise ``UnequalIterablesError`` if they aren't all the same length. @@ -1826,7 +1757,7 @@ of the zipped *iterable*. The ``i``-th iterable contains the ``i``-th element from each element - of the zipped iterable. The first element is used to to determine the + of the zipped iterable. The first element is used to determine the length of the remaining elements. >>> iterable = ('a', 1), ('b', 2), ('c', 3), ('d', 4) @@ -2376,6 +2307,16 @@ return compress(count(), starmap(pred, it)) +def longest_common_prefix(iterables): + """Yield elements of the longest common prefix amongst given *iterables*. + + >>> ''.join(longest_common_prefix('abcd', 'abc', 'abf')) + 'ab' + + """ + return (c0 for c in takewhile(all_equal, zip(*iterables))) + + def lstrip(iterable, pred): """Yield the items from *iterable*, but strip any from the beginning for which *pred* returns ``True``. @@ -2684,7 +2625,7 @@ if initial is not None: first = - return chain(first, starmap(func, zip(b, a))) + return chain(first, map(func, b, a)) class SequenceView(Sequence): @@ -2977,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): @@ -3327,6 +3269,27 @@ return first_value +class _IChunk: + def __init__(self, iterable, n): + self._it = islice(iterable, n) + self._cache = deque() + + def fill_cache(self): + self._cache.extend(self._it) + + def __iter__(self): + return self + + def __next__(self): + try: + return next(self._it) + except StopIteration: + if self._cache: + return self._cache.popleft() + else: + raise + + def ichunked(iterable, n): """Break *iterable* into sub-iterables with *n* elements each. :func:`ichunked` is like :func:`chunked`, but it yields iterables @@ -3348,20 +3311,39 @@ 8, 9, 10, 11 """ - source = iter(iterable) - + source = peekable(iter(iterable)) + ichunk_marker = object() while True: # Check to see whether we're at the end of the source iterable - item = next(source, _marker) - if item is _marker: + item = source.peek(ichunk_marker) + if item is ichunk_marker: return - # Clone the source and yield an n-length slice - source, it = tee(chain(item, source)) - yield islice(it, n) + chunk = _IChunk(source, n) + yield chunk - # Advance the source iterable - consume(source, n) + # Advance the source iterable and fill previous chunk's cache + chunk.fill_cache() + + +def iequals(*iterables): + """Return ``True`` if all given *iterables* are equal to each other, + which means that they contain the same elements in the same order. + + The function is useful for comparing iterables of different data types + or iterables that do not support equality checks. + + >>> iequals("abc", 'a', 'b', 'c', ('a', 'b', 'c'), iter("abc")) + True + + >>> iequals("abc", "acb") + False + + Not to be confused with :func:`all_equals`, which checks whether all + elements of iterable are equal to each other. + + """ + return all(map(all_equal, zip_longest(*iterables, fillvalue=object()))) def distinct_combinations(iterable, r): @@ -3487,7 +3469,6 @@ next_index = k + floor(log(random()) / log(1 - W)) for index, element in enumerate(iterable, k): - if index == next_index: reservoirrandrange(k) = element # The new W is the largest in a sample of k U(0, `old_W`) numbers @@ -3656,7 +3637,10 @@ self._aborted = False self._future = None self._wait_seconds = wait_seconds - self._executor = ThreadPoolExecutor(max_workers=1) + # Lazily import concurrent.future + self._executor = __import__( + 'concurrent.futures' + ).futures.ThreadPoolExecutor(max_workers=1) self._iterator = self._reader() def __enter__(self): @@ -3961,7 +3945,7 @@ n, _ = last(pool, default=(n, None)) - # Python versiosn below 3.8 don't have math.comb + # Python versions below 3.8 don't have math.comb index = 1 for i, j in enumerate(reversed(indexes), start=1): j = n - j @@ -4114,7 +4098,7 @@ If the *strict* keyword argument is ``True``, then ``UnequalIterablesError`` will be raised if any of the iterables have - different lengthss. + different lengths. """ def is_scalar(obj): @@ -4304,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: @@ -4315,3 +4298,95 @@ 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) + + +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_iterablesiai for i in range(iterable_count)) + j = f0 + f0 = 0 + if j == iterable_count: + break + aj = aj + oj + if aj == 0 or aj == len(all_iterablesj) - 1: + oj = -oj + fj = fj + 1 + fj + 1 = j + 1
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools/more.pyi -> _service:tar_scm:more-itertools-9.1.0.tar.gz/more_itertools/more.pyi
Changed
@@ -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..., Iteratorobject) -_Raisable = UnionBaseException, 'TypeBaseException' +_Raisable = BaseException | TypeBaseException @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: Optionalint, strict: bool = ... -) -> IteratorList_T: ... + iterable: Iterable_T, n: int | None, strict: bool = ... +) -> Iteratorlist_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,15 +65,14 @@ @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 collate(*iterables: Iterable_T, **kwargs: Any) -> Iterable_T: ... def consumer(func: _GenFn) -> _GenFn: ... def ilen(iterable: Iterableobject) -> int: ... def iterate(func: Callable_T, _T, start: _T) -> Iterator_T: ... @@ -81,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: Optionalint = ... -) -> IteratorTuple_T, ...: ... + iterable: Iterable_T, r: int | None = ... +) -> Iteratortuple_T, ...: ... def intersperse( e: _U, iterable: Iterable_T, n: int = ... -) -> IteratorUnion_T, _U: ... -def unique_to_each(*iterables: Iterable_T) -> ListList_T: ... +) -> Iterator_T | _U: ... +def unique_to_each(*iterables: Iterable_T) -> listlist_T: ... @overload def windowed( seq: Iterable_T, n: int, *, step: int = ... -) -> IteratorTupleOptional_T, ...: ... +) -> Iteratortuple_T | None, ...: ... @overload def windowed( seq: Iterable_T, n: int, fillvalue: _U, step: int = ... -) -> IteratorTupleUnion_T, _U, ...: ... -def substrings(iterable: Iterable_T) -> IteratorTuple_T, ...: ... +) -> Iteratortuple_T | _U, ...: ... +def substrings(iterable: Iterable_T) -> Iteratortuple_T, ...: ... def substrings_indexes( seq: Sequence_T, reverse: bool = ... -) -> IteratorTupleSequence_T, int, int: ... +) -> IteratortupleSequence_T, int, int: ... class bucket(Generic_T, _U, Container_U): def __init__( self, iterable: Iterable_T, key: Callable_T, _U, - validator: OptionalCallableobject, object = ..., + validator: Callableobject, object | None = ..., ) -> None: ... def __contains__(self, value: object) -> bool: ... def __iter__(self) -> Iterator_U: ... @@ -124,117 +124,113 @@ def spy( iterable: Iterable_T, n: int = ... -) -> TupleList_T, Iterator_T: ... +) -> tuplelist_T, Iterator_T: ... def interleave(*iterables: Iterable_T) -> Iterator_T: ... def interleave_longest(*iterables: Iterable_T) -> Iterator_T: ... def interleave_evenly( - iterables: ListIterable_T, lengths: OptionalListint = ... + iterables: listIterable_T, lengths: listint | None = ... ) -> Iterator_T: ... def collapse( iterable: IterableAny, - base_type: Optionaltype = ..., - levels: Optionalint = ..., + base_type: type | None = ..., + levels: int | None = ..., ) -> IteratorAny: ... @overload def side_effect( func: Callable_T, object, iterable: Iterable_T, chunk_size: None = ..., - before: OptionalCallable, object = ..., - after: OptionalCallable, object = ..., + before: Callable, object | None = ..., + after: Callable, object | None = ..., ) -> Iterator_T: ... @overload def side_effect( - func: CallableList_T, object, + func: Callablelist_T, object, iterable: Iterable_T, chunk_size: int, - before: OptionalCallable, object = ..., - after: OptionalCallable, object = ..., + before: Callable, object | None = ..., + after: Callable, object | None = ..., ) -> Iterator_T: ... def sliced( - seq: Sequence_T, n: int, strict: bool = ... -) -> IteratorSequence_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 = ..., -) -> IteratorList_T: ... +) -> Iteratorlist_T: ... def split_before( iterable: Iterable_T, pred: Callable_T, object, maxsplit: int = ... -) -> IteratorList_T: ... +) -> Iteratorlist_T: ... def split_after( iterable: Iterable_T, pred: Callable_T, object, maxsplit: int = ... -) -> IteratorList_T: ... +) -> Iteratorlist_T: ... def split_when( iterable: Iterable_T, pred: Callable_T, _T, object, maxsplit: int = ..., -) -> IteratorList_T: ... +) -> Iteratorlist_T: ... def split_into( - iterable: Iterable_T, sizes: IterableOptionalint -) -> IteratorList_T: ... + iterable: Iterable_T, sizes: Iterableint | None +) -> Iteratorlist_T: ... @overload def padded( iterable: Iterable_T, *, - n: Optionalint = ..., - next_multiple: bool = ... -) -> IteratorOptional_T: ... + n: int | None = ..., + next_multiple: bool = ..., +) -> Iterator_T | None: ... @overload def padded( iterable: Iterable_T, fillvalue: _U, - n: Optionalint = ..., + n: int | None = ..., next_multiple: bool = ..., -) -> IteratorUnion_T, _U: ... +) -> Iterator_T | _U: ... @overload def repeat_last(iterable: Iterable_T) -> Iterator_T: ... @overload -def repeat_last( - iterable: Iterable_T, default: _U -) -> IteratorUnion_T, _U: ... -def distribute(n: int, iterable: Iterable_T) -> ListIterator_T: ... +def repeat_last(iterable: Iterable_T, default: _U) -> Iterator_T | _U: ... +def distribute(n: int, iterable: Iterable_T) -> listIterator_T: ... @overload def stagger( iterable: Iterable_T, offsets: _SizedIterableint = ..., longest: bool = ..., -) -> IteratorTupleOptional_T, ...: ... +) -> Iteratortuple_T | None, ...: ... @overload def stagger( iterable: Iterable_T, offsets: _SizedIterableint = ..., longest: bool = ..., fillvalue: _U = ..., -) -> IteratorTupleUnion_T, _U, ...: ... +) -> Iteratortuple_T | _U, ...: ... class UnequalIterablesError(ValueError): - def __init__( - self, details: OptionalTupleint, int, int = ... - ) -> None: ... + def __init__(self, details: tupleint, int, int | None = ...) -> None: ... @overload -def zip_equal(__iter1: Iterable_T1) -> IteratorTuple_T1: ... +def zip_equal(__iter1: Iterable_T1) -> Iteratortuple_T1: ... @overload def zip_equal( __iter1: Iterable_T1, __iter2: Iterable_T2 -) -> IteratorTuple_T1, _T2: ... +) -> Iteratortuple_T1, _T2: ... @overload def zip_equal( __iter1: Iterable_T, __iter2: Iterable_T, __iter3: Iterable_T, - *iterables: Iterable_T -) -> IteratorTuple_T, ...: ... + *iterables: Iterable_T, +) -> Iteratortuple_T, ...: ... @overload def zip_offset( __iter1: Iterable_T1, *, offsets: _SizedIterableint, longest: bool = ..., - fillvalue: None = None -) -> IteratorTupleOptional_T1: ... + fillvalue: None = None, +) -> Iteratortuple_T1 | None: ... @overload def zip_offset( __iter1: Iterable_T1, @@ -242,8 +238,8 @@ *, offsets: _SizedIterableint, longest: bool = ..., - fillvalue: None = None -) -> IteratorTupleOptional_T1, Optional_T2: ... + fillvalue: None = None, +) -> Iteratortuple_T1 | None, _T2 | None: ... @overload def zip_offset( __iter1: Iterable_T, @@ -252,8 +248,8 @@ *iterables: Iterable_T, offsets: _SizedIterableint, longest: bool = ..., - fillvalue: None = None -) -> IteratorTupleOptional_T, ...: ... + fillvalue: None = None, +) -> Iteratortuple_T | None, ...: ... @overload def zip_offset( __iter1: Iterable_T1, @@ -261,7 +257,7 @@ offsets: _SizedIterableint, longest: bool = ..., fillvalue: _U, -) -> IteratorTupleUnion_T1, _U: ... +) -> Iteratortuple_T1 | _U: ... @overload def zip_offset( __iter1: Iterable_T1, @@ -270,7 +266,7 @@ offsets: _SizedIterableint, longest: bool = ..., fillvalue: _U, -) -> IteratorTupleUnion_T1, _U, Union_T2, _U: ... +) -> Iteratortuple_T1 | _U, _T2 | _U: ... @overload def zip_offset( __iter1: Iterable_T, @@ -280,82 +276,80 @@ offsets: _SizedIterableint, longest: bool = ..., fillvalue: _U, -) -> IteratorTupleUnion_T, _U, ...: ... +) -> Iteratortuple_T | _U, ...: ... def sort_together( iterables: IterableIterable_T, key_list: Iterableint = ..., - key: OptionalCallable..., Any = ..., + key: Callable..., Any | None = ..., reverse: bool = ..., -) -> ListTuple_T, ...: ... -def unzip(iterable: IterableSequence_T) -> TupleIterator_T, ...: ... -def divide(n: int, iterable: Iterable_T) -> ListIterator_T: ... +) -> listtuple_T, ...: ... +def unzip(iterable: IterableSequence_T) -> tupleIterator_T, ...: ... +def divide(n: int, iterable: Iterable_T) -> listIterator_T: ... def always_iterable( obj: object, - base_type: Union - type, TupleUniontype, TupleAny, ..., ..., None - = ..., + base_type: type | tupletype | tupleAny, ..., ... | None = ..., ) -> IteratorAny: ... def adjacent( predicate: Callable_T, bool, iterable: Iterable_T, distance: int = ..., -) -> IteratorTuplebool, _T: ... +) -> Iteratortuplebool, _T: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: None = None, valuefunc: None = None, reducefunc: None = None, -) -> IteratorTuple_T, Iterator_T: ... +) -> Iteratortuple_T, Iterator_T: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: Callable_T, _U, valuefunc: None, reducefunc: None, -) -> IteratorTuple_U, Iterator_T: ... +) -> Iteratortuple_U, Iterator_T: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: None, valuefunc: Callable_T, _V, reducefunc: None, -) -> IterableTuple_T, Iterable_V: ... +) -> Iterabletuple_T, Iterable_V: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: Callable_T, _U, valuefunc: Callable_T, _V, reducefunc: None, -) -> IterableTuple_U, Iterator_V: ... +) -> Iterabletuple_U, Iterator_V: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: None, valuefunc: None, reducefunc: CallableIterator_T, _W, -) -> IterableTuple_T, _W: ... +) -> Iterabletuple_T, _W: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: Callable_T, _U, valuefunc: None, reducefunc: CallableIterator_T, _W, -) -> IterableTuple_U, _W: ... +) -> Iterabletuple_U, _W: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: None, valuefunc: Callable_T, _V, reducefunc: CallableIterable_V, _W, -) -> IterableTuple_T, _W: ... +) -> Iterabletuple_T, _W: ... @overload def groupby_transform( iterable: Iterable_T, keyfunc: Callable_T, _U, valuefunc: Callable_T, _V, reducefunc: CallableIterable_V, _W, -) -> IterableTuple_U, _W: ... +) -> Iterabletuple_U, _W: ... class numeric_range(Generic_T, _U, Sequence_T, Hashable, Reversible_T): @overload @@ -376,22 +370,22 @@ def __len__(self) -> int: ... def __reduce__( self, - ) -> TupleTypenumeric_range_T, _U, Tuple_T, _T, _U: ... + ) -> tupleTypenumeric_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: Optionalint = ... -) -> IterableTupleint, _T: ... + iterable: Iterable_T, n: int | None = ... +) -> Iterabletupleint, _T: ... def mark_ends( iterable: Iterable_T, -) -> IterableTuplebool, bool, _T: ... +) -> Iterabletuplebool, bool, _T: ... def locate( iterable: Iterableobject, pred: Callable..., Any = ..., - window_size: Optionalint = ..., + window_size: int | None = ..., ) -> Iteratorint: ... def lstrip( iterable: Iterable_T, pred: Callable_T, object @@ -404,9 +398,7 @@ ) -> Iterator_T: ... class islice_extended(Generic_T, Iterator_T): - def __init__( - self, iterable: Iterable_T, *args: Optionalint - ) -> 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,8 +412,8 @@ iterable: Iterable_T, func: Callable_T, _T, _U = ..., *, - initial: None = ... -) -> IteratorUnion_T, _U: ... + initial: None = ..., +) -> Iterator_T | _U: ... @overload def difference( iterable: Iterable_T, func: Callable_T, _T, _U = ..., *, initial: _U @@ -437,7 +429,7 @@ class seekable(Generic_T, Iterator_T): def __init__( - self, iterable: Iterable_T, maxlen: Optionalint = ... + self, iterable: Iterable_T, maxlen: int | None = ... ) -> None: ... def __iter__(self) -> seekable_T: ... def __next__(self) -> _T: ... @@ -445,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) -> IteratorTuple_T, int: ... + def encode(iterable: Iterable_T) -> Iteratortuple_T, int: ... @staticmethod - def decode(iterable: IterableTuple_T, int) -> Iterator_T: ... + def decode(iterable: Iterabletuple_T, int) -> Iterator_T: ... def exactly_n( iterable: Iterable_T, n: int, predicate: Callable_T, object = ... ) -> bool: ... -def circular_shifts(iterable: Iterable_T) -> ListTuple_T, ...: ... +def circular_shifts(iterable: Iterable_T) -> listtuple_T, ...: ... def make_decorator( wrapping_func: Callable..., _U, result_index: int = ... ) -> Callable..., CallableCallable..., Any, Callable..., _U: ... @@ -468,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: CallableList_T, _W = ..., -) -> Dict_U, _W: ... + reducefunc: Callablelist_T, _W = ..., +) -> dict_U, _W: ... @overload def map_reduce( iterable: Iterable_T, keyfunc: Callable_T, _U, valuefunc: Callable_T, _V, - reducefunc: CallableList_V, _W, -) -> Dict_U, _W: ... + reducefunc: Callablelist_V, _W, +) -> dict_U, _W: ... def rlocate( iterable: Iterable_T, pred: Callable..., object = ..., - window_size: Optionalint = ..., + window_size: int | None = ..., ) -> Iteratorint: ... def replace( iterable: Iterable_T, pred: Callable..., object, substitutes: Iterable_U, - count: Optionalint = ..., + count: int | None = ..., window_size: int = ..., -) -> IteratorUnion_T, _U: ... -def partitions(iterable: Iterable_T) -> IteratorListList_T: ... +) -> Iterator_T | _U: ... +def partitions(iterable: Iterable_T) -> Iteratorlistlist_T: ... def set_partitions( - iterable: Iterable_T, k: Optionalint = ... -) -> IteratorListList_T: ... + iterable: Iterable_T, k: int | None = ... +) -> Iteratorlistlist_T: ... class time_limited(Generic_T, Iterator_T): def __init__( @@ -516,40 +508,40 @@ @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) -> IteratorIterator_T: ... def distinct_combinations( iterable: Iterable_T, r: int -) -> IteratorTuple_T, ...: ... +) -> Iteratortuple_T, ...: ... def filter_except( validator: CallableAny, object, iterable: Iterable_T, - *exceptions: TypeBaseException + *exceptions: TypeBaseException, ) -> Iterator_T: ... def map_except( function: CallableAny, _U, iterable: Iterable_T, - *exceptions: TypeBaseException + *exceptions: TypeBaseException, ) -> Iterator_U: ... def map_if( iterable: IterableAny, pred: CallableAny, bool, func: CallableAny, Any, - func_else: OptionalCallableAny, Any = ..., + func_else: CallableAny, Any | None = ..., ) -> IteratorAny: ... def sample( iterable: Iterable_T, k: int, - weights: OptionalIterablefloat = ..., -) -> List_T: ... + weights: Iterablefloat | None = ..., +) -> list_T: ... def is_sorted( iterable: Iterable_T, - key: OptionalCallable_T, _U = ..., + key: Callable_T, _U | None = ..., reverse: bool = False, strict: bool = False, ) -> bool: ... @@ -567,10 +559,10 @@ def __enter__(self) -> callback_iter_T: ... def __exit__( self, - exc_type: OptionalTypeBaseException, - exc_value: OptionalBaseException, - traceback: OptionalTracebackType, - ) -> Optionalbool: ... + exc_type: TypeBaseException | 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: ... @@ -581,15 +573,15 @@ def windowed_complete( iterable: Iterable_T, n: int -) -> IteratorTuple_T, ...: ... +) -> Iteratortuple_T, ...: ... def all_unique( - iterable: Iterable_T, key: OptionalCallable_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 @@ -604,22 +596,20 @@ def __iter__(self) -> countable_T: ... def __next__(self) -> _T: ... -def chunked_even(iterable: Iterable_T, n: int) -> IteratorList_T: ... +def chunked_even(iterable: Iterable_T, n: int) -> Iteratorlist_T: ... def zip_broadcast( - *objects: Union_T, Iterable_T, - scalar_types: Union - type, TupleUniontype, TupleAny, ..., ..., None - = ..., - strict: bool = ... -) -> IterableTuple_T, ...: ... + *objects: _T | Iterable_T, + scalar_types: type | tupletype | tupleAny, ..., ... | None = ..., + strict: bool = ..., +) -> Iterabletuple_T, ...: ... def unique_in_window( - iterable: Iterable_T, n: int, key: OptionalCallable_T, _U = ... + iterable: Iterable_T, n: int, key: Callable_T, _U | None = ... ) -> Iterator_T: ... def duplicates_everseen( - iterable: Iterable_T, key: OptionalCallable_T, _U = ... + iterable: Iterable_T, key: Callable_T, _U | None = ... ) -> Iterator_T: ... def duplicates_justseen( - iterable: Iterable_T, key: OptionalCallable_T, _U = ... + iterable: Iterable_T, key: Callable_T, _U | None = ... ) -> Iterator_T: ... class _SupportsLessThan(Protocol): @@ -630,35 +620,47 @@ @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: ... + default: _U, +) -> _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: ... + *others: _SupportsLessThanT, +) -> tuple_SupportsLessThanT, _SupportsLessThanT: ... @overload def minmax( iterable_or_value: _T, __other: _T, *others: _T, - key: Callable_T, _SupportsLessThan -) -> Tuple_T, _T: ... + key: Callable_T, _SupportsLessThan, +) -> tuple_T, _T: ... +def longest_common_prefix( + iterables: IterableIterable_T, +) -> Iterator_T: ... +def iequals(*iterables: Iterableobject) -> bool: ... +def constrained_batches( + iterable: Iterableobject, + max_size: int, + max_count: int | None = ..., + get_len: Callable_T, object = ..., + strict: bool = ..., +) -> Iteratortuple_T: ... +def gray_product(*iterables: Iterable_T) -> Iteratortuple_T, ...: ...
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools/recipes.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/more_itertools/recipes.py
Changed
@@ -7,33 +7,44 @@ .. 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, islice, + product, repeat, starmap, tee, zip_longest, ) -import operator from random import randrange, sample, choice +from sys import hexversion __all__ = 'all_equal', + 'batched', 'before_and_after', 'consume', 'convolve', 'dotproduct', 'first_true', + 'factor', 'flatten', 'grouper', 'iter_except', + 'iter_index', + 'matmul', 'ncycles', 'nth', 'nth_combination', @@ -41,6 +52,7 @@ 'pad_none', 'pairwise', 'partition', + 'polynomial_from_roots', 'powerset', 'prepend', 'quantify', @@ -50,15 +62,20 @@ 'random_product', 'repeatfunc', 'roundrobin', + 'sieve', 'sliding_window', + 'subslices', 'tabulate', 'tail', 'take', + 'transpose', 'triplewise', 'unique_everseen', 'unique_justseen', +_marker = object() + def take(n, iterable): """Return first *n* items of the iterable as a list. @@ -102,7 +119,14 @@ 'E', 'F', 'G' """ - return iter(deque(iterable, maxlen=n)) + # If the given iterable has a length, then we can use islice to get its + # final elements. Note that if the iterable is not actually Iterable, + # either islice or deque will throw a TypeError. This is why we don't + # check if it is Iterable. + if isinstance(iterable, Sized): + yield from islice(iterable, max(0, len(iterable) - n), None) + else: + yield from iter(deque(iterable, maxlen=n)) def consume(iterator, n=None): @@ -284,20 +308,83 @@ pairwise.__doc__ = _pairwise.__doc__ -def grouper(iterable, n, fillvalue=None): - """Collect data into fixed-length chunks or blocks. +class UnequalIterablesError(ValueError): + def __init__(self, details=None): + msg = 'Iterables have different lengths' + if details is not None: + msg += (': index 0 has length {}; index {} has length {}').format( + *details + ) + + super().__init__(msg) + + +def _zip_equal_generator(iterables): + for combo in zip_longest(*iterables, fillvalue=_marker): + for val in combo: + if val is _marker: + raise UnequalIterablesError() + yield combo + + +def _zip_equal(*iterables): + # Check whether the iterables are all the same size. + try: + first_size = len(iterables0) + for i, it in enumerate(iterables1:, 1): + size = len(it) + if size != first_size: + break + else: + # If we didn't break out, we can use the built-in zip. + return zip(*iterables) + + # If we did break out, there was a mismatch. + raise UnequalIterablesError(details=(first_size, i, size)) + # If any one of the iterables didn't have a length, start reading + # them until one runs out. + except TypeError: + return _zip_equal_generator(iterables) + + +def grouper(iterable, n, incomplete='fill', fillvalue=None): + """Group elements from *iterable* into fixed-length groups of length *n*. + + >>> list(grouper('ABCDEF', 3)) + ('A', 'B', 'C'), ('D', 'E', 'F') + + The keyword arguments *incomplete* and *fillvalue* control what happens for + iterables whose length is not a multiple of *n*. + + When *incomplete* is `'fill'`, the last group will contain instances of + *fillvalue*. - >>> list(grouper('ABCDEFG', 3, 'x')) + >>> list(grouper('ABCDEFG', 3, incomplete='fill', fillvalue='x')) ('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x') + When *incomplete* is `'ignore'`, the last group will not be emitted. + + >>> list(grouper('ABCDEFG', 3, incomplete='ignore', fillvalue='x')) + ('A', 'B', 'C'), ('D', 'E', 'F') + + When *incomplete* is `'strict'`, a subclass of `ValueError` will be raised. + + >>> it = grouper('ABCDEFG', 3, incomplete='strict') + >>> list(it) # doctest: +IGNORE_EXCEPTION_DETAIL + Traceback (most recent call last): + ... + UnequalIterablesError + """ - if isinstance(iterable, int): - warnings.warn( - "grouper expects iterable as first parameter", DeprecationWarning - ) - n, iterable = iterable, n args = iter(iterable) * n - return zip_longest(fillvalue=fillvalue, *args) + if incomplete == 'fill': + return zip_longest(*args, fillvalue=fillvalue) + if incomplete == 'strict': + return _zip_equal(*args) + if incomplete == 'ignore': + return zip(*args) + else: + raise ValueError('Expected fill, strict, or ignore') def roundrobin(*iterables): @@ -658,11 +745,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): @@ -696,3 +784,147 @@ for x in it: window.append(x) yield tuple(window) + + +def subslices(iterable): + """Return all contiguous non-empty subslices of *iterable*. + + >>> list(subslices('ABC')) + 'A', 'A', 'B', 'A', 'B', 'C', 'B', 'B', 'C', 'C' + + This is similar to :func:`substrings`, but emits items in a different + order. + """ + 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 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. + + >>> list(sieve(30)) + 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 + for p in compress(range(limit), data): + datap * p : n : p + p = bytes(len(range(p * p, n, p + p))) + data2 = 1 + return iter_index(data, 1) if n > 2 else iter() + + +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. + """ + 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(m20) + 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
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/more_itertools/recipes.pyi -> _service:tar_scm:more-itertools-9.1.0.tar.gz/more_itertools/recipes.pyi
Changed
@@ -1,112 +1,119 @@ """Stubs for more_itertools.recipes""" +from __future__ import annotations + from typing import ( Any, Callable, Iterable, Iterator, - List, - Optional, - Tuple, + overload, + Sequence, + 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: Callableint, _T, start: int = ... ) -> Iterator_T: ... def tail(n: int, iterable: Iterable_T) -> Iterator_T: ... -def consume(iterator: Iterableobject, n: Optionalint = ...) -> None: ... +def consume(iterator: Iterableobject, 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: Iterableobject) -> bool: ... def quantify( iterable: Iterable_T, pred: Callable_T, bool = ... ) -> int: ... -def pad_none(iterable: Iterable_T) -> IteratorOptional_T: ... -def padnone(iterable: Iterable_T) -> IteratorOptional_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: Iterableobject, vec2: Iterableobject) -> object: ... def flatten(listOfLists: IterableIterable_T) -> Iterator_T: ... def repeatfunc( - func: Callable..., _U, times: Optionalint = ..., *args: Any + func: Callable..., _U, times: int | None = ..., *args: Any ) -> Iterator_U: ... -def pairwise(iterable: Iterable_T) -> IteratorTuple_T, _T: ... -@overload -def grouper( - iterable: Iterable_T, n: int -) -> IteratorTupleOptional_T, ...: ... -@overload +def pairwise(iterable: Iterable_T) -> Iteratortuple_T, _T: ... def grouper( - iterable: Iterable_T, n: int, fillvalue: _U -) -> IteratorTupleUnion_T, _U, ...: ... -@overload -def grouper( # Deprecated interface - iterable: int, n: Iterable_T -) -> IteratorTupleOptional_T, ...: ... -@overload -def grouper( # Deprecated interface - iterable: int, n: Iterable_T, fillvalue: _U -) -> IteratorTupleUnion_T, _U, ...: ... + iterable: Iterable_T, + n: int, + incomplete: str = ..., + fillvalue: _U = ..., +) -> Iteratortuple_T | _U, ...: ... def roundrobin(*iterables: Iterable_T) -> Iterator_T: ... def partition( - pred: OptionalCallable_T, object, iterable: Iterable_T -) -> TupleIterator_T, Iterator_T: ... -def powerset(iterable: Iterable_T) -> IteratorTuple_T, ...: ... + pred: Callable_T, object | None, iterable: Iterable_T +) -> tupleIterator_T, Iterator_T: ... +def powerset(iterable: Iterable_T) -> Iteratortuple_T, ...: ... def unique_everseen( - iterable: Iterable_T, key: OptionalCallable_T, _U = ... + iterable: Iterable_T, key: Callable_T, _U | None = ... ) -> Iterator_T: ... def unique_justseen( - iterable: Iterable_T, key: OptionalCallable_T, object = ... + iterable: Iterable_T, key: Callable_T, object | None = ... ) -> Iterator_T: ... @overload def iter_except( func: Callable, _T, - exception: UnionTypeBaseException, TupleTypeBaseException, ..., + exception: TypeBaseException | tupleTypeBaseException, ..., first: None = ..., ) -> Iterator_T: ... @overload def iter_except( func: Callable, _T, - exception: UnionTypeBaseException, TupleTypeBaseException, ..., + exception: TypeBaseException | tupleTypeBaseException, ..., first: Callable, _U, -) -> IteratorUnion_T, _U: ... +) -> Iterator_T | _U: ... @overload def first_true( - iterable: Iterable_T, *, pred: OptionalCallable_T, object = ... -) -> Optional_T: ... + iterable: Iterable_T, *, pred: Callable_T, object | None = ... +) -> _T | None: ... @overload def first_true( iterable: Iterable_T, default: _U, - pred: OptionalCallable_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: Optionalint = ... -) -> 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) -> IteratorUnion_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 -) -> TupleIterator_T, Iterator_T: ... -def triplewise(iterable: Iterable_T) -> IteratorTuple_T, _T, _T: ... +) -> tupleIterator_T, Iterator_T: ... +def triplewise(iterable: Iterable_T) -> Iteratortuple_T, _T, _T: ... def sliding_window( iterable: Iterable_T, n: int -) -> IteratorTuple_T, ...: ... +) -> Iteratortuple_T, ...: ... +def subslices(iterable: Iterable_T) -> Iteratorlist_T: ... +def polynomial_from_roots(roots: Sequenceint) -> listint: ... +def iter_index( + iterable: Iterableobject, + value: Any, + start: int | None = ..., +) -> Iteratorint: ... +def sieve(n: int) -> Iteratorint: ... +def batched( + iterable: Iterable_T, + n: int, +) -> Iteratorlist_T: ... +def transpose( + it: IterableIterable_T, +) -> tupleIterator_T, ...: ... +def matmul(m1: Sequence_T, m2: Sequence_T) -> Iteratorlist_T: ... +def factor(n: int) -> Iteratorint: ...
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/pyproject.toml -> _service:tar_scm:more-itertools-9.1.0.tar.gz/pyproject.toml
Changed
@@ -1,4 +1,48 @@ +build-system +requires = "flit_core >=3.2,<4" +build-backend = "flit_core.buildapi" + +project +name = "more-itertools" +authors = {name = "Erik Rose", email = "erikrose@grinchcentral.com"} +readme = "README.rst" +requires-python = ">=3.7" +license = {file = "LICENSE"} +keywords = + "itertools", + "iterator", + "iteration", + "filter", + "peek", + "peekable", + "chunk", + "chunked", + +classifiers = + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Natural Language :: English", + "License :: OSI Approved :: MIT License", + "Programming Language :: Python :: 3", + "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", + "Topic :: Software Development :: Libraries", + +dynamic = "version", "description" + +project.urls +Homepage = "https://github.com/more-itertools/more-itertools" + +tool.flit.module +name = "more_itertools" + tool.black line-length = 79 -target-version = 'py35' +target-version = 'py37' skip-string-normalization = true
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/setup.cfg -> _service:tar_scm:more-itertools-9.1.0.tar.gz/setup.cfg
Changed
@@ -1,5 +1,5 @@ bumpversion -current_version = 8.12.0 +current_version = 9.1.0 commit = True tag = False files = more_itertools/__init__.py
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/setup.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/setup.py
Changed
@@ -1,66 +1,3 @@ -from re import sub - from setuptools import setup -from more_itertools import __version__ - - -def get_long_description(): - # Fix display issues on PyPI caused by RST markup - readme = open('README.rst').read() - - version_lines = - with open('docs/versions.rst') as infile: - next(infile) - for line in infile: - line = line.rstrip().replace('.. automodule:: more_itertools', '') - if line == '5.0.0': - break - version_lines.append(line) - version_history = '\n'.join(version_lines) - version_history = sub(r':func:`(a-zA-Z0-9._+)`', r'\1', version_history) - - ret = readme + '\n\n' + version_history - return ret - - -setup( - name='more-itertools', - version=__version__, - description='More routines for operating on iterables, beyond itertools', - long_description=get_long_description(), - long_description_content_type='text/x-rst', - author='Erik Rose', - author_email='erikrose@grinchcentral.com', - license='MIT', - packages='more_itertools', - package_data={'more_itertools': 'py.typed', '*.pyi'}, - python_requires='>=3.5', - url='https://github.com/more-itertools/more-itertools', - classifiers= - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - '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 :: Only', - 'Programming Language :: Python :: Implementation :: CPython', - 'Programming Language :: Python :: Implementation :: PyPy', - 'Topic :: Software Development :: Libraries', - , - keywords= - 'itertools', - 'iterator', - 'iteration', - 'filter', - 'peek', - 'peekable', - 'collate', - 'chunk', - 'chunked', - , -) +setup()
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/tests/test_more.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/tests/test_more.py
Changed
@@ -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, @@ -23,10 +22,11 @@ ) from operator import add, mul, itemgetter from pickle import loads, dumps +from platform import python_implementation from random import seed, Random from statistics import mean from string import ascii_letters -from sys import version_info +from sys import version_info, getsizeof from time import sleep from traceback import format_exc from unittest import skipIf, TestCase @@ -40,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()``""" @@ -288,11 +243,6 @@ class PeekableTests(PeekableMixinTests, TestCase): - """Tests for ``peekable()`` behavior not incidentally covered by testing - ``collate()`` - - """ - cls = mi.peekable def test_indexing(self): @@ -782,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): @@ -1507,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) @@ -3217,8 +3162,8 @@ class IsliceExtendedTests(TestCase): def test_all(self): iterable = '0', '1', '2', '3', '4', '5' - indexes = list(range(-4, len(iterable) + 4)) + None - steps = 1, 2, 3, 4, -1, -2, -3, 4 + indexes = *range(-4, 10), None + steps = 1, 2, 3, 4, -1, -2, -3, -4 for slice_args in product(indexes, indexes, steps): with self.subTest(slice_args=slice_args): actual = list(mi.islice_extended(iterable, *slice_args)) @@ -3654,8 +3599,8 @@ self.assertEqual(actual, expected) def test_efficient_reversal(self): - iterable = range(9 ** 9) # Is efficiently reversible - target = 9 ** 9 - 2 + iterable = range(9**9) # Is efficiently reversible + target = 9**9 - 2 pred = lambda x: x == target # Find-able from the right actual = next(mi.rlocate(iterable, pred)) self.assertEqual(actual, target) @@ -4037,6 +3982,28 @@ self.assertEqual(next(chunk), 0) self.assertRaises(RuntimeError, next, it) + @skipIf( + 'PyPy' == python_implementation(), + 'tracemalloc not implemented in pypy', + ) + def test_memory_in_order(self): + """Test that only one item is kept in memory at a time if chunks are + iterated over in order.""" + import tracemalloc + + def big_string_iterator(): + while True: + # Must be larger than 4096 to get around str interning + yield 'X' * 5000 + + ichunks = mi.ichunked(big_string_iterator(), 50) + ichunk = next(ichunks) + tracemalloc.start() + mi.consume(ichunk) + curr_mem, peak_mem = tracemalloc.get_traced_memory() + tracemalloc.stop() + self.assertLess(peak_mem, getsizeof('X' * 5000) * 2) + class DistinctCombinationsTests(TestCase): def test_basic(self): @@ -5031,3 +4998,233 @@ def test_nested(self): iterable = 1, 2, 1, 2, 5, 6, 5, 6 self.assertEqual(list(mi.duplicates_justseen(iterable)), 5, 6) + + +class LongestCommonPrefixTests(TestCase): + def test_basic(self): + iterables = 1, 2, 1, 2, 3, 1, 2, 4 + self.assertEqual(list(mi.longest_common_prefix(iterables)), 1, 2) + + def test_iterators(self): + iterables = iter(iter(1, 2), iter(1, 2, 3), iter(1, 2, 4)) + self.assertEqual(list(mi.longest_common_prefix(iterables)), 1, 2) + + def test_no_iterables(self): + iterables = + self.assertEqual(list(mi.longest_common_prefix(iterables)), ) + + def test_empty_iterables_only(self): + iterables = , , + self.assertEqual(list(mi.longest_common_prefix(iterables)), ) + + def test_includes_empty_iterables(self): + iterables = 1, 2, 1, 2, 3, 1, 2, 4, + self.assertEqual(list(mi.longest_common_prefix(iterables)), ) + + def test_non_hashable(self): + # See https://github.com/more-itertools/more-itertools/issues/603 + iterables = 1, 2, 1, 2, 3, 1, 2, 4 + self.assertEqual(list(mi.longest_common_prefix(iterables)), 1, 2) + + def test_prefix_contains_elements_of_the_first_iterable(self): + iterables = 1, 2, 1, 2, 3, 1, 2, 4 + prefix = list(mi.longest_common_prefix(iterables)) + self.assertIs(prefix0, iterables00) + self.assertIs(prefix1, iterables01) + self.assertIsNot(prefix0, iterables10) + self.assertIsNot(prefix1, iterables11) + self.assertIsNot(prefix0, iterables20) + self.assertIsNot(prefix1, iterables21) + + def test_infinite_iterables(self): + prefix = mi.longest_common_prefix(count(), count()) + self.assertEqual(next(prefix), 0) + self.assertEqual(next(prefix), 1) + self.assertEqual(next(prefix), 2) + + def test_contains_infinite_iterables(self): + iterables = 0, 1, 2, count() + self.assertEqual(list(mi.longest_common_prefix(iterables)), 0, 1, 2) + + +class IequalsTests(TestCase): + def test_basic(self): + self.assertTrue(mi.iequals("abc", iter("abc"))) + self.assertTrue(mi.iequals(range(3), 0, 1, 2)) + self.assertFalse(mi.iequals("abc", 0, 1, 2)) + + def test_no_iterables(self): + self.assertTrue(mi.iequals()) + + def test_one_iterable(self): + self.assertTrue(mi.iequals("abc")) + + def test_more_than_two_iterable(self): + self.assertTrue(mi.iequals("abc", iter("abc"), 'a', 'b', 'c')) + self.assertFalse(mi.iequals("abc", iter("abc"), 'a', 'b', 'd')) + + def test_order_matters(self): + self.assertFalse(mi.iequals("abc", "acb")) + + def test_not_equal_lengths(self): + self.assertFalse(mi.iequals("abc", "ab")) + self.assertFalse(mi.iequals("abc", "bc")) + self.assertFalse(mi.iequals("aaa", "aaaa")) + + def test_empty_iterables(self): + self.assertTrue(mi.iequals(, "")) + + def test_none_is_not_a_sentinel(self): + # See https://stackoverflow.com/a/900444 + self.assertFalse(mi.iequals(1, 2, 1, 2, None)) + self.assertFalse(mi.iequals(1, 2, None, 1, 2)) + + 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, + + (zen0,), + (zen1,), + (zen2,), + (zen3,), + (zen4,), + (zen5,), + (zen6,), + , + ), + ( + 61, + + (zen0, zen1), + (zen2,), + (zen3, zen4), + (zen5, zen6), + , + ), + ( + 90, + + (zen0, zen1, zen2), + (zen3, zen4, zen5), + (zen6,), + , + ), + ( + 124, + (zen0, zen1, zen2, zen3), (zen4, zen5, zen6), + ), + ( + 150, + (zen0, zen1, zen2, zen3, zen4), (zen5, zen6), + ), + ( + 177, + (zen0, zen1, zen2, zen3, zen4, zen5), (zen6,), + ), + ): + 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,), + ) + + +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)) + )
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/tests/test_recipes.py -> _service:tar_scm:more-itertools-9.1.0.tar.gz/tests/test_recipes.py
Changed
@@ -1,7 +1,7 @@ -import warnings - 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 @@ -59,21 +59,29 @@ class TailTests(TestCase): """Tests for ``tail()``""" - def test_greater(self): - """Length of iterable is greater than requested tail""" - self.assertEqual(list(mi.tail(3, 'ABCDEFG')), 'E', 'F', 'G') + def test_iterator_greater(self): + """Length of iterator is greater than requested tail""" + self.assertEqual(list(mi.tail(3, iter('ABCDEFG'))), list('EFG')) - def test_equal(self): - """Length of iterable is equal to the requested tail""" - self.assertEqual( - list(mi.tail(7, 'ABCDEFG')), 'A', 'B', 'C', 'D', 'E', 'F', 'G' - ) + def test_iterator_equal(self): + """Length of iterator is equal to the requested tail""" + self.assertEqual(list(mi.tail(7, iter('ABCDEFG'))), list('ABCDEFG')) - def test_less(self): - """Length of iterable is less than requested tail""" - self.assertEqual( - list(mi.tail(8, 'ABCDEFG')), 'A', 'B', 'C', 'D', 'E', 'F', 'G' - ) + def test_iterator_less(self): + """Length of iterator is less than requested tail""" + self.assertEqual(list(mi.tail(8, iter('ABCDEFG'))), list('ABCDEFG')) + + def test_sized_greater(self): + """Length of sized iterable is greater than requested tail""" + self.assertEqual(list(mi.tail(3, 'ABCDEFG')), list('EFG')) + + def test_sized_equal(self): + """Length of sized iterable is less than requested tail""" + self.assertEqual(list(mi.tail(7, 'ABCDEFG')), list('ABCDEFG')) + + def test_sized_less(self): + """Length of sized iterable is less than requested tail""" + self.assertEqual(list(mi.tail(8, 'ABCDEFG')), list('ABCDEFG')) class ConsumeTests(TestCase): @@ -259,44 +267,77 @@ class GrouperTests(TestCase): - """Tests for ``grouper()``""" - - def test_even(self): - """Test when group size divides evenly into the length of - the iterable. - - """ - self.assertEqual( - list(mi.grouper('ABCDEF', 3)), ('A', 'B', 'C'), ('D', 'E', 'F') - ) + def test_basic(self): + seq = 'ABCDEF' + for n, expected in + (3, ('A', 'B', 'C'), ('D', 'E', 'F')), + (4, ('A', 'B', 'C', 'D'), ('E', 'F', None, None)), + (5, ('A', 'B', 'C', 'D', 'E'), ('F', None, None, None, None)), + (6, ('A', 'B', 'C', 'D', 'E', 'F')), + (7, ('A', 'B', 'C', 'D', 'E', 'F', None)), + : + with self.subTest(n=n): + actual = list(mi.grouper(iter(seq), n)) + self.assertEqual(actual, expected) - def test_odd(self): - """Test when group size does not divide evenly into the length of the - iterable. + def test_fill(self): + seq = 'ABCDEF' + fillvalue = 'x' + for n, expected in + (1, 'A', 'B', 'C', 'D', 'E', 'F'), + (2, 'AB', 'CD', 'EF'), + (3, 'ABC', 'DEF'), + (4, 'ABCD', 'EFxx'), + (5, 'ABCDE', 'Fxxxx'), + (6, 'ABCDEF'), + (7, 'ABCDEFx'), + : + with self.subTest(n=n): + it = mi.grouper( + iter(seq), n, incomplete='fill', fillvalue=fillvalue + ) + actual = ''.join(x) for x in it + self.assertEqual(actual, expected) - """ - self.assertEqual( - list(mi.grouper('ABCDE', 3)), ('A', 'B', 'C'), ('D', 'E', None) - ) + def test_ignore(self): + seq = 'ABCDEF' + for n, expected in + (1, 'A', 'B', 'C', 'D', 'E', 'F'), + (2, 'AB', 'CD', 'EF'), + (3, 'ABC', 'DEF'), + (4, 'ABCD'), + (5, 'ABCDE'), + (6, 'ABCDEF'), + (7, ), + : + with self.subTest(n=n): + it = mi.grouper(iter(seq), n, incomplete='ignore') + actual = ''.join(x) for x in it + self.assertEqual(actual, expected) - def test_fill_value(self): - """Test that the fill value is used to pad the final group""" - self.assertEqual( - list(mi.grouper('ABCDE', 3, 'x')), - ('A', 'B', 'C'), ('D', 'E', 'x'), - ) + def test_strict(self): + seq = 'ABCDEF' + for n, expected in + (1, 'A', 'B', 'C', 'D', 'E', 'F'), + (2, 'AB', 'CD', 'EF'), + (3, 'ABC', 'DEF'), + (6, 'ABCDEF'), + : + with self.subTest(n=n): + it = mi.grouper(iter(seq), n, incomplete='strict') + actual = ''.join(x) for x in it + self.assertEqual(actual, expected) - def test_legacy_order(self): - """Historically, grouper expected the n as the first parameter""" - with warnings.catch_warnings(record=True) as caught: - warnings.simplefilter('always') - self.assertEqual( - list(mi.grouper(3, 'ABCDEF')), - ('A', 'B', 'C'), ('D', 'E', 'F'), - ) + def test_strict_fails(self): + seq = 'ABCDEF' + for n in 4, 5, 7: + with self.subTest(n=n): + with self.assertRaises(ValueError): + list(mi.grouper(iter(seq), n, incomplete='strict')) - (warning,) = caught - assert warning.category == DeprecationWarning + def test_invalid_incomplete(self): + with self.assertRaises(ValueError): + list(mi.grouper('ABCD', 3, incomplete='bogus')) class RoundrobinTests(TestCase): @@ -732,6 +773,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): @@ -763,3 +837,207 @@ with self.subTest(expected=expected): actual = list(mi.sliding_window(iterable, n)) self.assertEqual(actual, expected) + + +class SubslicesTests(TestCase): + def test_basic(self): + for iterable, expected in + (, ), + (1, 1), + (1, 2, 1, 1, 2, 2), + (iter(1, 2), 1, 1, 2, 2), + (2, 1, 2, 2, 1, 1), + ( + 'ABCD', + + 'A', + 'A', 'B', + 'A', 'B', 'C', + 'A', 'B', 'C', 'D', + 'B', + 'B', 'C', + 'B', 'C', 'D', + 'C', + 'C', 'D', + 'D', + , + ), + : + 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 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( + 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) + + +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) + ) + )
View file
_service:tar_scm:more-itertools-8.12.0.tar.gz/tox.ini -> _service:tar_scm:more-itertools-9.1.0.tar.gz/tox.ini
Changed
@@ -1,5 +1,6 @@ tox envlist = py{36,37,38,39} +isolated_build = True testenv commands = {envpython} -m unittest -v {posargs}
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.
浙ICP备2022010568号-2