tema7707 commited on
Commit
38039e3
·
verified ·
1 Parent(s): eabd53c

Upload folder using huggingface_hub

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. Dockerfile +20 -0
  2. README.md +34 -5
  3. __init__.py +19 -0
  4. client.py +5 -0
  5. examples/repo2env-more-itertools-bug-intersperse-staged/.claude/settings.local.json +9 -0
  6. examples/repo2env-more-itertools-bug-intersperse-staged/.gitattributes +2 -0
  7. examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/other-issues.md +10 -0
  8. examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/propose-a-new-itertool.md +20 -0
  9. examples/repo2env-more-itertools-bug-intersperse-staged/.github/PULL_REQUEST_TEMPLATE.md +12 -0
  10. examples/repo2env-more-itertools-bug-intersperse-staged/.github/workflows/python-app.yml +36 -0
  11. examples/repo2env-more-itertools-bug-intersperse-staged/.gitignore +47 -0
  12. examples/repo2env-more-itertools-bug-intersperse-staged/.readthedocs.yaml +15 -0
  13. examples/repo2env-more-itertools-bug-intersperse-staged/LICENSE +19 -0
  14. examples/repo2env-more-itertools-bug-intersperse-staged/MANIFEST.in +10 -0
  15. examples/repo2env-more-itertools-bug-intersperse-staged/Makefile +38 -0
  16. examples/repo2env-more-itertools-bug-intersperse-staged/README.rst +259 -0
  17. examples/repo2env-more-itertools-bug-intersperse-staged/docs/Makefile +153 -0
  18. examples/repo2env-more-itertools-bug-intersperse-staged/docs/_static/theme_overrides.css +14 -0
  19. examples/repo2env-more-itertools-bug-intersperse-staged/docs/api.rst +367 -0
  20. examples/repo2env-more-itertools-bug-intersperse-staged/docs/conf.py +286 -0
  21. examples/repo2env-more-itertools-bug-intersperse-staged/docs/index.rst +1 -0
  22. examples/repo2env-more-itertools-bug-intersperse-staged/docs/license.rst +16 -0
  23. examples/repo2env-more-itertools-bug-intersperse-staged/docs/make.bat +190 -0
  24. examples/repo2env-more-itertools-bug-intersperse-staged/docs/requirements.txt +2 -0
  25. examples/repo2env-more-itertools-bug-intersperse-staged/docs/testing.rst +19 -0
  26. examples/repo2env-more-itertools-bug-intersperse-staged/docs/toctree.rst +15 -0
  27. examples/repo2env-more-itertools-bug-intersperse-staged/docs/versions.rst +813 -0
  28. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.py +6 -0
  29. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.pyi +2 -0
  30. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.py +0 -0
  31. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.pyi +979 -0
  32. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/py.typed +0 -0
  33. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.py +1430 -0
  34. examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.pyi +207 -0
  35. examples/repo2env-more-itertools-bug-intersperse-staged/pyproject.toml +59 -0
  36. examples/repo2env-more-itertools-bug-intersperse-staged/repo2env_manifest.json +35 -0
  37. examples/repo2env-more-itertools-bug-intersperse-staged/requirements/development.txt +4 -0
  38. examples/repo2env-more-itertools-bug-intersperse-staged/requirements/packaging.txt +4 -0
  39. examples/repo2env-more-itertools-bug-intersperse-staged/requirements/testing.txt +2 -0
  40. examples/repo2env-more-itertools-bug-intersperse-staged/requirements/typechecks.txt +1 -0
  41. examples/repo2env-more-itertools-bug-intersperse-staged/setup.cfg +26 -0
  42. examples/repo2env-more-itertools-bug-intersperse-staged/task_spec.json +30 -0
  43. examples/repo2env-more-itertools-bug-intersperse-staged/tests/__init__.py +0 -0
  44. examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_more.py +0 -0
  45. examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_recipes.py +1606 -0
  46. examples/repo2env-more-itertools-bug-intersperse-staged/tox.ini +6 -0
  47. models.py +15 -0
  48. openenv.yaml +6 -0
  49. pyproject.toml +31 -0
  50. repo2env/__init__.py +4 -0
Dockerfile ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ FROM python:3.11-slim
2
+
3
+ WORKDIR /app
4
+
5
+ RUN apt-get update \
6
+ && apt-get install -y --no-install-recommends git \
7
+ && rm -rf /var/lib/apt/lists/*
8
+
9
+ COPY . /app
10
+
11
+ RUN pip install --no-cache-dir -e .
12
+ # Repo-specific installs happen inside Repo2Env's per-episode runtime venv.
13
+ # Do not install the bundled repo into the server environment here, or target repo
14
+ # dependencies may downgrade server dependencies and break the OpenEnv app.
15
+
16
+ ENV REPO2ENV_DEFAULT_REPO=/app/examples/repo2env-more-itertools-bug-intersperse-staged
17
+
18
+ EXPOSE 8000
19
+
20
+ CMD ["repo2env-openenv-server", "--port", "8000"]
README.md CHANGED
@@ -1,10 +1,39 @@
1
  ---
2
- title: Repo2env Repo2env More Itertools Bug Intersperse Staged
3
- emoji: 🌍
4
- colorFrom: red
5
- colorTo: pink
6
  sdk: docker
7
  pinned: false
 
 
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  ---
2
+ title: repo2env-repo2env-more-itertools-bug-intersperse-staged
3
+ emoji: 🔧
4
+ colorFrom: blue
5
+ colorTo: green
6
  sdk: docker
7
  pinned: false
8
+ app_port: 8000
9
+ base_path: /web
10
+ tags:
11
+ - openenv
12
  ---
13
 
14
+ # repo2env-repo2env-more-itertools-bug-intersperse-staged
15
+
16
+ Generated by Repo2Env from `/tmp/repo2env-more-itertools-bug-intersperse-staged`.
17
+
18
+ This package bundles the source repo under `examples/repo2env-more-itertools-bug-intersperse-staged` and serves it through the generic Repo2Env OpenEnv runtime.
19
+
20
+ ## Task Mode
21
+
22
+ - mode: repo_editing
23
+ - title: Fix intersperse() prepending filler element at start of output
24
+
25
+ ## Support Assessment
26
+
27
+ - supported: yes
28
+ - repo name: repo2env-more-itertools-bug-intersperse-staged
29
+
30
+ ## Warnings
31
+
32
+ - Baseline pytest run already has failing or erroring tests.
33
+
34
+ ## Local Commands
35
+
36
+ ```bash
37
+ openenv validate
38
+ openenv push .
39
+ ```
__init__.py ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Repo2Env OpenEnv package compatibility exports."""
2
+
3
+ from .client import Repo2EnvClient
4
+ from .models import (
5
+ REPO2ENV_TOOL_NAMES,
6
+ Repo2EnvAction,
7
+ Repo2EnvObservation,
8
+ Repo2EnvState,
9
+ )
10
+ from repo2env.openenv.environment import Repo2EnvOpenEnvEnvironment
11
+
12
+ __all__ = [
13
+ "REPO2ENV_TOOL_NAMES",
14
+ "Repo2EnvAction",
15
+ "Repo2EnvClient",
16
+ "Repo2EnvObservation",
17
+ "Repo2EnvOpenEnvEnvironment",
18
+ "Repo2EnvState",
19
+ ]
client.py ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ """Repo2Env OpenEnv client compatibility shim."""
2
+
3
+ from repo2env.openenv.client import Repo2EnvClient
4
+
5
+ __all__ = ["Repo2EnvClient"]
examples/repo2env-more-itertools-bug-intersperse-staged/.claude/settings.local.json ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "mcp__repo2env__analyze_repo",
5
+ "mcp__repo2env__convert_repo",
6
+ "Bash(cp -r /Users/artemiy/Projects/repos_to_convert/more-itertools /tmp/repo2env-more-itertools-bug-intersperse-staged)"
7
+ ]
8
+ }
9
+ }
examples/repo2env-more-itertools-bug-intersperse-staged/.gitattributes ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ more_itertools/more.py merge=union
2
+ more_itertools/tests/test_more.py merge=union
examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/other-issues.md ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Other issues
3
+ about: Any other issue
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+
examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/propose-a-new-itertool.md ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ name: Propose a new itertool
3
+ about: Suggest a new itertool for the library
4
+ title: ''
5
+ labels: ''
6
+ assignees: ''
7
+
8
+ ---
9
+
10
+ ### Description
11
+ <!-- Explain what your proposed itertools does here -->
12
+
13
+ ### References
14
+ <!-- Link to a discussion on, e.g. Stack Overflow, showing where the new tool would have been useful -->
15
+ <!-- Or link to a GitHub issue in another repository -->
16
+ <!-- Or a discussion on the python-ideas mailing list -->
17
+ <!-- Alternatively, describe a real problem you had to solve with this itertool -->
18
+
19
+ ### Examples
20
+ <!-- Provide a code sample showing how your itertool works -->
examples/repo2env-more-itertools-bug-intersperse-staged/.github/PULL_REQUEST_TEMPLATE.md ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ### Issue reference
2
+ <!-- If you're adding a new feature, please make an issue first -->
3
+ <!-- If you're fixing a trivial bug (e.g. a typo) you need not make an issue first -->
4
+ <!-- If you're fixing a non-trivial bug, please go ahead and make an issue first -->
5
+ <!-- Not all proposals for new functionality will be accepted, so please save yourself some work by checking first with an issue -->
6
+ more-itertools/more-itertools#XXXX
7
+
8
+ ### Changes
9
+ <!-- Describe what your PR adds, fixes, or changes here -->
10
+
11
+ ### Checks and tests
12
+ <!-- Please create and activate a virtual environment and then run `make all-checks` to ensure sure your branch meets the standards enforced by GitHub Actions. -->
examples/repo2env-more-itertools-bug-intersperse-staged/.github/workflows/python-app.yml ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ name: Python package
2
+
3
+ on: [push, pull_request]
4
+
5
+ jobs:
6
+ build:
7
+
8
+ runs-on: ubuntu-latest
9
+ strategy:
10
+ matrix:
11
+ python-version: ["3.10", "3.11", "3.12", "3.13", "3.14.0-rc.2", "pypy-3.10"]
12
+
13
+ steps:
14
+ - uses: actions/checkout@v4
15
+ - name: Set up Python ${{ matrix.python-version }}
16
+ uses: actions/setup-python@v5
17
+ with:
18
+ python-version: ${{ matrix.python-version }}
19
+ allow-prereleases: true
20
+ - name: Run tests
21
+ run: make coverage
22
+ - name: Static checks
23
+ if: "matrix.python-version == '3.10'"
24
+ run: make requirements check
25
+ - name: Build docs with sphinx
26
+ if: "matrix.python-version == '3.10'"
27
+ run: make docs
28
+ - name: Build packages
29
+ if: "matrix.python-version == '3.10'"
30
+ run: make package
31
+ - name: Upload packages
32
+ if: "matrix.python-version == '3.10'"
33
+ uses: actions/upload-artifact@v4
34
+ with:
35
+ name: more-itertools-packages
36
+ path: dist/*
examples/repo2env-more-itertools-bug-intersperse-staged/.gitignore ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.py[co]
2
+
3
+ # Packages
4
+ *.egg
5
+ *.eggs
6
+ *.egg-info
7
+ dist
8
+ build
9
+ eggs
10
+ parts
11
+ bin
12
+ var
13
+ sdist
14
+ develop-eggs
15
+ .installed.cfg
16
+
17
+ # Installer logs
18
+ pip-log.txt
19
+
20
+ # Unit test / coverage reports
21
+ .coverage
22
+ .tox
23
+ .noseids
24
+ htmlcov/
25
+ coverage.xml
26
+ .pytest_cache
27
+
28
+ # Docs by Sphinx
29
+ _build
30
+
31
+ # Environment
32
+ .env/
33
+ .venv/
34
+ env/
35
+ venv/
36
+
37
+ # IDE files
38
+ .idea
39
+ .vscode
40
+ .DS_Store
41
+
42
+ # Mypy
43
+ .mypy_cache
44
+ .dmypy.json
45
+
46
+ # Ruff
47
+ .ruff_cache/
examples/repo2env-more-itertools-bug-intersperse-staged/.readthedocs.yaml ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ version: 2
2
+
3
+ build:
4
+ os: ubuntu-22.04
5
+ tools:
6
+ python: "3.13"
7
+
8
+ sphinx:
9
+ configuration: docs/conf.py
10
+
11
+ python:
12
+ install:
13
+ - requirements: docs/requirements.txt
14
+ - method: pip
15
+ path: .
examples/repo2env-more-itertools-bug-intersperse-staged/LICENSE ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Copyright (c) 2012 Erik Rose
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the "Software"), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7
+ of the Software, and to permit persons to whom the Software is furnished to do
8
+ so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
examples/repo2env-more-itertools-bug-intersperse-staged/MANIFEST.in ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ include README.rst
2
+ include LICENSE
3
+ include docs/*.rst
4
+ include docs/Makefile
5
+ include docs/make.bat
6
+ include docs/conf.py
7
+ include docs/_static/*
8
+ include fabfile.py
9
+ include tox.ini
10
+ include tests/*.py
examples/repo2env-more-itertools-bug-intersperse-staged/Makefile ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .PHONY: all-checks
2
+ all-checks: requirements coverage check docs package
3
+
4
+ .PHONY: requirements
5
+ requirements:
6
+ python -m pip install -r requirements/development.txt
7
+ python -m pip install --editable .
8
+
9
+ .PHONY: check
10
+ check:
11
+ ruff format --check .
12
+ ruff check more_itertools tests
13
+ stubtest more_itertools.more more_itertools.recipes
14
+
15
+ .PHONY: format
16
+ format:
17
+ ruff format .
18
+
19
+ .PHONY: coverage
20
+ coverage:
21
+ python -m pip install -r requirements/testing.txt
22
+ coverage run --include="more_itertools/*.py" -m unittest
23
+ coverage report --show-missing --fail-under=99
24
+
25
+ .PHONY: test
26
+ test:
27
+ python -m unittest -v ${tests}
28
+
29
+ .PHONY: docs
30
+ docs:
31
+ python -m pip install -r docs/requirements.txt
32
+ sphinx-build -W -b html docs docs/_build/html
33
+
34
+ .PHONY: package
35
+ package:
36
+ python -m pip install -r requirements/packaging.txt
37
+ flit build --setup-py
38
+ twine check dist/*
examples/repo2env-more-itertools-bug-intersperse-staged/README.rst ADDED
@@ -0,0 +1,259 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ==============
2
+ More Itertools
3
+ ==============
4
+
5
+ .. image:: https://readthedocs.org/projects/more-itertools/badge/?version=latest
6
+ :target: https://more-itertools.readthedocs.io/en/stable/
7
+
8
+ Python's ``itertools`` library is a gem - you can compose elegant solutions
9
+ for a variety of problems with the functions it provides. In ``more-itertools``
10
+ we collect additional building blocks, recipes, and routines for working with
11
+ Python iterables.
12
+
13
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
14
+ | Grouping | `chunked <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked>`_, |
15
+ | | `ichunked <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ichunked>`_, |
16
+ | | `chunked_even <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.chunked_even>`_, |
17
+ | | `sliced <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliced>`_, |
18
+ | | `constrained_batches <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.constrained_batches>`_, |
19
+ | | `distribute <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distribute>`_, |
20
+ | | `divide <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.divide>`_, |
21
+ | | `split_at <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_at>`_, |
22
+ | | `split_before <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_before>`_, |
23
+ | | `split_after <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_after>`_, |
24
+ | | `split_into <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_into>`_, |
25
+ | | `split_when <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.split_when>`_, |
26
+ | | `bucket <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.bucket>`_, |
27
+ | | `unzip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unzip>`_, |
28
+ | | `batched <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.batched>`_, |
29
+ | | `grouper <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.grouper>`_, |
30
+ | | `partition <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partition>`_, |
31
+ | | `transpose <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.transpose>`_ |
32
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
33
+ | Lookahead and lookback | `spy <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.spy>`_, |
34
+ | | `peekable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.peekable>`_, |
35
+ | | `seekable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.seekable>`_ |
36
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
37
+ | Windowing | `windowed <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.windowed>`_, |
38
+ | | `substrings <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.substrings>`_, |
39
+ | | `substrings_indexes <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.substrings_indexes>`_, |
40
+ | | `stagger <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.stagger>`_, |
41
+ | | `windowed_complete <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.windowed_complete>`_, |
42
+ | | `triplewise <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.triplewise>`_, |
43
+ | | `sliding_window <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sliding_window>`_, |
44
+ | | `subslices <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.subslices>`_ |
45
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
46
+ | Augmenting | `count_cycle <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.count_cycle>`_, |
47
+ | | `intersperse <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.intersperse>`_, |
48
+ | | `padded <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.padded>`_, |
49
+ | | `repeat_each <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_each>`_, |
50
+ | | `mark_ends <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.mark_ends>`_, |
51
+ | | `repeat_last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeat_last>`_, |
52
+ | | `adjacent <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.adjacent>`_, |
53
+ | | `groupby_transform <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.groupby_transform>`_, |
54
+ | | `pad_none <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.pad_none>`_, |
55
+ | | `ncycles <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ncycles>`_ |
56
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
57
+ | Combining | `collapse <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.collapse>`_, |
58
+ | | `sort_together <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sort_together>`_, |
59
+ | | `interleave <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave>`_, |
60
+ | | `interleave_longest <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_longest>`_, |
61
+ | | `interleave_evenly <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_evenly>`_, |
62
+ | | `interleave_randomly <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.interleave_randomly>`_, |
63
+ | | `zip_offset <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_offset>`_, |
64
+ | | `zip_broadcast <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.zip_broadcast>`_, |
65
+ | | `flatten <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.flatten>`_, |
66
+ | | `roundrobin <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.roundrobin>`_, |
67
+ | | `prepend <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.prepend>`_, |
68
+ | | `value_chain <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.value_chain>`_, |
69
+ | | `partial_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partial_product>`_ |
70
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
71
+ | Concurrency | `concurrent_tee <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.concurrent_tee>`_, |
72
+ | | `serialize <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.serialize>`_, |
73
+ | | `synchronized <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.synchronized>`_ |
74
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
75
+ | Summarizing | `ilen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.ilen>`_, |
76
+ | | `unique_to_each <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_to_each>`_, |
77
+ | | `sample <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sample>`_, |
78
+ | | `consecutive_groups <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consecutive_groups>`_, |
79
+ | | `run_length <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.run_length>`_, |
80
+ | | `map_reduce <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_reduce>`_, |
81
+ | | `join_mappings <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.join_mappings>`_, |
82
+ | | `exactly_n <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.exactly_n>`_, |
83
+ | | `is_sorted <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.is_sorted>`_, |
84
+ | | `all_equal <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.all_equal>`_, |
85
+ | | `all_unique <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.all_unique>`_, |
86
+ | | `argmin <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.argmin>`_, |
87
+ | | `argmax <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.argmax>`_, |
88
+ | | `minmax <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.minmax>`_, |
89
+ | | `first_true <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first_true>`_, |
90
+ | | `quantify <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.quantify>`_, |
91
+ | | `iequals <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iequals>`_ |
92
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
93
+ | Selecting | `islice_extended <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.islice_extended>`_, |
94
+ | | `first <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.first>`_, |
95
+ | | `last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.last>`_, |
96
+ | | `one <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.one>`_, |
97
+ | | `only <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.only>`_, |
98
+ | | `strictly_n <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.strictly_n>`_, |
99
+ | | `strip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.strip>`_, |
100
+ | | `lstrip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.lstrip>`_, |
101
+ | | `rstrip <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.rstrip>`_, |
102
+ | | `filter_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.filter_except>`_, |
103
+ | | `map_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_except>`_, |
104
+ | | `filter_map <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.filter_map>`_, |
105
+ | | `iter_suppress <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_suppress>`_, |
106
+ | | `nth_or_last <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_or_last>`_, |
107
+ | | `extract <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.extract>`_, |
108
+ | | `unique_in_window <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_in_window>`_, |
109
+ | | `before_and_after <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.before_and_after>`_, |
110
+ | | `nth <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth>`_, |
111
+ | | `take <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.take>`_, |
112
+ | | `tail <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.tail>`_, |
113
+ | | `unique_everseen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_everseen>`_, |
114
+ | | `unique_justseen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique_justseen>`_, |
115
+ | | `unique <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.unique>`_, |
116
+ | | `duplicates_everseen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_everseen>`_, |
117
+ | | `duplicates_justseen <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.duplicates_justseen>`_, |
118
+ | | `classify_unique <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.classify_unique>`_, |
119
+ | | `longest_common_prefix <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.longest_common_prefix>`_, |
120
+ | | `takewhile_inclusive <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.takewhile_inclusive>`_ |
121
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
122
+ | Math | `dft <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.dft>`_, |
123
+ | | `idft <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.idft>`_, |
124
+ | | `convolve <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.convolve>`_, |
125
+ | | `dotproduct <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.dotproduct>`_, |
126
+ | | `matmul <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.matmul>`_, |
127
+ | | `polynomial_from_roots <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_from_roots>`_, |
128
+ | | `polynomial_derivative <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_derivative>`_, |
129
+ | | `polynomial_eval <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.polynomial_eval>`_, |
130
+ | | `sum_of_squares <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sum_of_squares>`_, |
131
+ | | `running_median <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.running_median>`_, |
132
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
133
+ | Integer math | `factor <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.factor>`_, |
134
+ | | `is_prime <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.is_prime>`_, |
135
+ | | `multinomial <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.multinomial>`_, |
136
+ | | `nth_prime <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_prime>`_, |
137
+ | | `sieve <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.sieve>`_ |
138
+ | | `totient <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.totient>`_ |
139
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
140
+ | Combinatorics | `circular_shifts <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.circular_shifts>`_, |
141
+ | | `derangements <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.derangements>`_, |
142
+ | | `gray_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.gray_product>`_, |
143
+ | | `outer_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.outer_product>`_, |
144
+ | | `partitions <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.partitions>`_, |
145
+ | | `set_partitions <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.set_partitions>`_, |
146
+ | | `powerset <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.powerset>`_, |
147
+ | | `powerset_of_sets <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.powerset_of_sets>`_ |
148
+ | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
149
+ | | `distinct_combinations <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_combinations>`_, |
150
+ | | `distinct_permutations <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.distinct_permutations>`_ |
151
+ | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
152
+ | | `combination_index <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.combination_index>`_, |
153
+ | | `combination_with_replacement_index <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.combination_with_replacement_index>`_, |
154
+ | | `permutation_index <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.permutation_index>`_, |
155
+ | | `product_index <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.product_index>`_ |
156
+ | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
157
+ | | `nth_combination <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_combination>`_, |
158
+ | | `nth_combination_with_replacement <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_combination_with_replacement>`_, |
159
+ | | `nth_permutation <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_permutation>`_, |
160
+ | | `nth_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.nth_product>`_ |
161
+ | +-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
162
+ | | `random_combination <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_combination>`_, |
163
+ | | `random_combination_with_replacement <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_combination_with_replacement>`_, |
164
+ | | `random_derangement <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_derangement>`_, |
165
+ | | `random_permutation <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_permutation>`_, |
166
+ | | `random_product <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.random_product>`_ |
167
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
168
+ | Wrapping | `always_iterable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_iterable>`_, |
169
+ | | `always_reversible <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.always_reversible>`_, |
170
+ | | `countable <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.countable>`_, |
171
+ | | `consumer <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consumer>`_, |
172
+ | | `iter_except <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_except>`_, |
173
+ | | `with_iter <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.with_iter>`_ |
174
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
175
+ | Others | `locate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.locate>`_, |
176
+ | | `rlocate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.rlocate>`_, |
177
+ | | `replace <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.replace>`_, |
178
+ | | `numeric_range <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.numeric_range>`_, |
179
+ | | `side_effect <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.side_effect>`_, |
180
+ | | `iterate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iterate>`_, |
181
+ | | `loops <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.loops>`_, |
182
+ | | `difference <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.difference>`_, |
183
+ | | `make_decorator <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.make_decorator>`_, |
184
+ | | `SequenceView <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.SequenceView>`_, |
185
+ | | `time_limited <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.time_limited>`_, |
186
+ | | `map_if <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.map_if>`_, |
187
+ | | `iter_index <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.iter_index>`_, |
188
+ | | `consume <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.consume>`_, |
189
+ | | `tabulate <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.tabulate>`_, |
190
+ | | `repeatfunc <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.repeatfunc>`_, |
191
+ | | `reshape <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.reshape>`_, |
192
+ | | `doublestarmap <https://more-itertools.readthedocs.io/en/stable/api.html#more_itertools.doublestarmap>`_ |
193
+ +------------------------+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------+
194
+
195
+
196
+ Getting started
197
+ ===============
198
+
199
+ To get started, install the library with `pip <https://pip.pypa.io/en/stable/>`_:
200
+
201
+ .. code-block:: shell
202
+
203
+ pip install more-itertools
204
+
205
+ The recipes from the `itertools docs <https://docs.python.org/3/library/itertools.html#itertools-recipes>`_
206
+ are included in the top-level package:
207
+
208
+ .. code-block:: python
209
+
210
+ >>> from more_itertools import flatten
211
+ >>> iterable = [(0, 1), (2, 3)]
212
+ >>> list(flatten(iterable))
213
+ [0, 1, 2, 3]
214
+
215
+ Several new recipes are available as well:
216
+
217
+ .. code-block:: python
218
+
219
+ >>> from more_itertools import chunked
220
+ >>> iterable = [0, 1, 2, 3, 4, 5, 6, 7, 8]
221
+ >>> list(chunked(iterable, 3))
222
+ [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
223
+
224
+ >>> from more_itertools import spy
225
+ >>> iterable = (x * x for x in range(1, 6))
226
+ >>> head, iterable = spy(iterable, n=3)
227
+ >>> list(head)
228
+ [1, 4, 9]
229
+ >>> list(iterable)
230
+ [1, 4, 9, 16, 25]
231
+
232
+
233
+
234
+ For the full listing of functions, see the `API documentation <https://more-itertools.readthedocs.io/en/stable/api.html>`_.
235
+
236
+
237
+ Links elsewhere
238
+ ===============
239
+
240
+ Blog posts about ``more-itertools``:
241
+
242
+ * `Yo, I heard you like decorators <https://www.bbayles.com/index/decorator_factory>`__
243
+ * `Tour of Python Itertools <https://martinheinz.dev/blog/16>`__ (`Alternate <https://dev.to/martinheinz/tour-of-python-itertools-4122>`__)
244
+ * `Real-World Python More Itertools <https://python.plainenglish.io/real-world-more-itertools-gideons-blog-a3901c607550>`_
245
+
246
+
247
+ Development
248
+ ===========
249
+
250
+ ``more-itertools`` is maintained by `@erikrose <https://github.com/erikrose>`_
251
+ and `@bbayles <https://github.com/bbayles>`_, with help from `many others <https://github.com/more-itertools/more-itertools/graphs/contributors>`_.
252
+ If you have a problem or suggestion, please file a bug or pull request in this
253
+ repository. Thanks for contributing!
254
+
255
+
256
+ Version History
257
+ ===============
258
+
259
+ The version history can be found in `documentation <https://more-itertools.readthedocs.io/en/stable/versions.html>`_.
examples/repo2env-more-itertools-bug-intersperse-staged/docs/Makefile ADDED
@@ -0,0 +1,153 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Makefile for Sphinx documentation
2
+ #
3
+
4
+ # You can set these variables from the command line.
5
+ SPHINXOPTS =
6
+ SPHINXBUILD = sphinx-build
7
+ PAPER =
8
+ BUILDDIR = _build
9
+
10
+ # Internal variables.
11
+ PAPEROPT_a4 = -D latex_paper_size=a4
12
+ PAPEROPT_letter = -D latex_paper_size=letter
13
+ ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
14
+ # the i18n builder cannot share the environment and doctrees with the others
15
+ I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
16
+
17
+ .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
18
+
19
+ help:
20
+ @echo "Please use \`make <target>' where <target> is one of"
21
+ @echo " html to make standalone HTML files"
22
+ @echo " dirhtml to make HTML files named index.html in directories"
23
+ @echo " singlehtml to make a single large HTML file"
24
+ @echo " pickle to make pickle files"
25
+ @echo " json to make JSON files"
26
+ @echo " htmlhelp to make HTML files and a HTML help project"
27
+ @echo " qthelp to make HTML files and a qthelp project"
28
+ @echo " devhelp to make HTML files and a Devhelp project"
29
+ @echo " epub to make an epub"
30
+ @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
31
+ @echo " latexpdf to make LaTeX files and run them through pdflatex"
32
+ @echo " text to make text files"
33
+ @echo " man to make manual pages"
34
+ @echo " texinfo to make Texinfo files"
35
+ @echo " info to make Texinfo files and run them through makeinfo"
36
+ @echo " gettext to make PO message catalogs"
37
+ @echo " changes to make an overview of all changed/added/deprecated items"
38
+ @echo " linkcheck to check all external links for integrity"
39
+ @echo " doctest to run all doctests embedded in the documentation (if enabled)"
40
+
41
+ clean:
42
+ -rm -rf $(BUILDDIR)/*
43
+
44
+ html:
45
+ $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
46
+ @echo
47
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
48
+
49
+ dirhtml:
50
+ $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
51
+ @echo
52
+ @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
53
+
54
+ singlehtml:
55
+ $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
56
+ @echo
57
+ @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
58
+
59
+ pickle:
60
+ $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
61
+ @echo
62
+ @echo "Build finished; now you can process the pickle files."
63
+
64
+ json:
65
+ $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
66
+ @echo
67
+ @echo "Build finished; now you can process the JSON files."
68
+
69
+ htmlhelp:
70
+ $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
71
+ @echo
72
+ @echo "Build finished; now you can run HTML Help Workshop with the" \
73
+ ".hhp project file in $(BUILDDIR)/htmlhelp."
74
+
75
+ qthelp:
76
+ $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
77
+ @echo
78
+ @echo "Build finished; now you can run "qcollectiongenerator" with the" \
79
+ ".qhcp project file in $(BUILDDIR)/qthelp, like this:"
80
+ @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/more-itertools.qhcp"
81
+ @echo "To view the help file:"
82
+ @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/more-itertools.qhc"
83
+
84
+ devhelp:
85
+ $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
86
+ @echo
87
+ @echo "Build finished."
88
+ @echo "To view the help file:"
89
+ @echo "# mkdir -p $$HOME/.local/share/devhelp/more-itertools"
90
+ @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/more-itertools"
91
+ @echo "# devhelp"
92
+
93
+ epub:
94
+ $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
95
+ @echo
96
+ @echo "Build finished. The epub file is in $(BUILDDIR)/epub."
97
+
98
+ latex:
99
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
100
+ @echo
101
+ @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
102
+ @echo "Run \`make' in that directory to run these through (pdf)latex" \
103
+ "(use \`make latexpdf' here to do that automatically)."
104
+
105
+ latexpdf:
106
+ $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
107
+ @echo "Running LaTeX files through pdflatex..."
108
+ $(MAKE) -C $(BUILDDIR)/latex all-pdf
109
+ @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
110
+
111
+ text:
112
+ $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
113
+ @echo
114
+ @echo "Build finished. The text files are in $(BUILDDIR)/text."
115
+
116
+ man:
117
+ $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
118
+ @echo
119
+ @echo "Build finished. The manual pages are in $(BUILDDIR)/man."
120
+
121
+ texinfo:
122
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
123
+ @echo
124
+ @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
125
+ @echo "Run \`make' in that directory to run these through makeinfo" \
126
+ "(use \`make info' here to do that automatically)."
127
+
128
+ info:
129
+ $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
130
+ @echo "Running Texinfo files through makeinfo..."
131
+ make -C $(BUILDDIR)/texinfo info
132
+ @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
133
+
134
+ gettext:
135
+ $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
136
+ @echo
137
+ @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
138
+
139
+ changes:
140
+ $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
141
+ @echo
142
+ @echo "The overview file is in $(BUILDDIR)/changes."
143
+
144
+ linkcheck:
145
+ $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
146
+ @echo
147
+ @echo "Link check complete; look for any errors in the above output " \
148
+ "or in $(BUILDDIR)/linkcheck/output.txt."
149
+
150
+ doctest:
151
+ $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
152
+ @echo "Testing of doctests in the sources finished, look at the " \
153
+ "results in $(BUILDDIR)/doctest/output.txt."
examples/repo2env-more-itertools-bug-intersperse-staged/docs/_static/theme_overrides.css ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* https://rackerlabs.github.io/docs-rackspace/tools/rtd-tables.html */
2
+ /* override table width restrictions */
3
+ @media screen and (min-width: 767px) {
4
+
5
+ .wy-table-responsive table td {
6
+ /* !important prevents the common CSS stylesheets from overriding
7
+ this as on RTD they are loaded after this stylesheet */
8
+ white-space: normal !important;
9
+ }
10
+
11
+ .wy-table-responsive {
12
+ overflow: visible !important;
13
+ }
14
+ }
examples/repo2env-more-itertools-bug-intersperse-staged/docs/api.rst ADDED
@@ -0,0 +1,367 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =============
2
+ API Reference
3
+ =============
4
+
5
+ .. automodule:: more_itertools
6
+
7
+ Grouping
8
+ ========
9
+
10
+ These tools yield groups of items from a source iterable.
11
+
12
+ ----
13
+
14
+ **New itertools**
15
+
16
+ .. autofunction:: chunked
17
+ .. autofunction:: ichunked
18
+ .. autofunction:: chunked_even
19
+ .. autofunction:: sliced
20
+ .. autofunction:: constrained_batches(iterable, max_size, max_count=None, get_len=len, strict=True)
21
+ .. autofunction:: distribute
22
+ .. autofunction:: divide
23
+ .. autofunction:: split_at
24
+ .. autofunction:: split_before
25
+ .. autofunction:: split_after
26
+ .. autofunction:: split_into
27
+ .. autofunction:: split_when
28
+ .. autofunction:: bucket
29
+ .. autofunction:: unzip
30
+
31
+ ----
32
+
33
+ **Itertools recipes**
34
+
35
+ .. autofunction:: batched
36
+ .. autofunction:: grouper
37
+ .. autofunction:: partition
38
+ .. autofunction:: transpose
39
+
40
+
41
+ Lookahead and lookback
42
+ ======================
43
+
44
+ These tools peek at an iterable's values without advancing it.
45
+
46
+ ----
47
+
48
+ **New itertools**
49
+
50
+
51
+ .. autofunction:: spy
52
+ .. autoclass:: peekable
53
+ .. autoclass:: seekable
54
+
55
+
56
+ Windowing
57
+ =========
58
+
59
+ These tools yield windows of items from an iterable.
60
+
61
+ ----
62
+
63
+ **New itertools**
64
+
65
+ .. autofunction:: windowed
66
+ .. autofunction:: substrings
67
+ .. autofunction:: substrings_indexes
68
+ .. autofunction:: stagger
69
+ .. autofunction:: windowed_complete
70
+
71
+ ----
72
+
73
+ **Itertools recipes**
74
+
75
+ .. autofunction:: triplewise
76
+ .. autofunction:: sliding_window
77
+ .. autofunction:: subslices
78
+
79
+
80
+ Augmenting
81
+ ==========
82
+
83
+ These tools yield items from an iterable, plus additional data.
84
+
85
+ ----
86
+
87
+ **New itertools**
88
+
89
+ .. autofunction:: count_cycle
90
+ .. autofunction:: intersperse
91
+ .. autofunction:: padded
92
+ .. autofunction:: mark_ends
93
+ .. autofunction:: repeat_each
94
+ .. autofunction:: repeat_last
95
+ .. autofunction:: adjacent
96
+ .. autofunction:: groupby_transform
97
+
98
+ ----
99
+
100
+ **Itertools recipes**
101
+
102
+ .. function:: padnone
103
+ :noindex:
104
+ .. autofunction:: pad_none
105
+ .. autofunction:: ncycles
106
+
107
+ Combining
108
+ =========
109
+
110
+ These tools combine multiple iterables.
111
+
112
+ ----
113
+
114
+ **New itertools**
115
+
116
+ .. autofunction:: collapse
117
+ .. autofunction:: interleave
118
+ .. autofunction:: interleave_longest
119
+ .. autofunction:: interleave_evenly
120
+ .. autofunction:: interleave_randomly
121
+ .. autofunction:: partial_product
122
+ .. autofunction:: sort_together
123
+ .. autofunction:: value_chain
124
+ .. autofunction:: zip_offset(*iterables, offsets, longest=False, fillvalue=None)
125
+ .. autofunction:: zip_broadcast(*objects, scalar_types=(str, bytes), strict=False)
126
+
127
+ ----
128
+
129
+ **Itertools recipes**
130
+
131
+ .. autofunction:: flatten
132
+ .. autofunction:: roundrobin
133
+ .. autofunction:: prepend
134
+
135
+
136
+ Concurrency
137
+ ===========
138
+
139
+ These tools support thread-safe concurrency.
140
+
141
+ ----
142
+
143
+ .. autofunction:: concurrent_tee
144
+ .. autoclass:: serialize
145
+ .. autofunction:: synchronized
146
+
147
+
148
+ Summarizing
149
+ ===========
150
+
151
+ These tools return summarized or aggregated data from an iterable.
152
+
153
+ ----
154
+
155
+ **New itertools**
156
+
157
+ .. autofunction:: ilen
158
+ .. autofunction:: unique_to_each
159
+ .. autofunction:: sample(iterable, k=1, weights=None)
160
+ .. autofunction:: consecutive_groups(iterable, ordering=lambda x: x)
161
+ .. autoclass:: run_length
162
+ .. autofunction:: map_reduce
163
+ .. autofunction:: join_mappings
164
+ .. autofunction:: exactly_n(iterable, n, predicate=bool)
165
+ .. autofunction:: is_sorted
166
+ .. autofunction:: all_unique
167
+ .. autofunction:: argmin
168
+ .. autofunction:: argmax
169
+ .. function:: minmax(iterable, *[, key, default])
170
+ .. autofunction:: minmax(arg1, arg2, *args[, key])
171
+ :noindex:
172
+ .. autofunction:: iequals
173
+
174
+ ----
175
+
176
+ **Itertools recipes**
177
+
178
+ .. autofunction:: all_equal
179
+ .. autofunction:: first_true
180
+ .. autofunction:: quantify(iterable, pred=bool)
181
+
182
+
183
+ Selecting
184
+ =========
185
+
186
+ These tools yield certain items from an iterable.
187
+
188
+ ----
189
+
190
+ **New itertools**
191
+
192
+ .. class:: islice_extended(iterable, stop)
193
+ .. autoclass:: islice_extended(iterable, start, stop[, step])
194
+ :noindex:
195
+ .. autofunction:: first(iterable[, default])
196
+ .. autofunction:: last(iterable[, default])
197
+ .. autofunction:: one(iterable, too_short=ValueError, too_long=ValueError)
198
+ .. autofunction:: only(iterable, default=None, too_long=ValueError)
199
+ .. autofunction:: strictly_n(iterable, n, too_short=None, too_long=None)
200
+ .. autofunction:: strip
201
+ .. autofunction:: lstrip
202
+ .. autofunction:: rstrip
203
+ .. autofunction:: filter_except
204
+ .. autofunction:: map_except
205
+ .. autofunction:: filter_map
206
+ .. autofunction:: iter_suppress
207
+ .. autofunction:: nth_or_last(iterable, n[, default])
208
+ .. autofunction:: extract
209
+ .. autofunction:: unique_in_window
210
+ .. autofunction:: duplicates_everseen
211
+ .. autofunction:: duplicates_justseen
212
+ .. autofunction:: classify_unique
213
+ .. autofunction:: longest_common_prefix
214
+ .. autofunction:: takewhile_inclusive
215
+
216
+ ----
217
+
218
+ **Itertools recipes**
219
+
220
+ .. autofunction:: nth
221
+ .. autofunction:: before_and_after
222
+ .. autofunction:: take
223
+ .. autofunction:: tail
224
+ .. autofunction:: unique_everseen
225
+ .. autofunction:: unique_justseen
226
+ .. autofunction:: unique
227
+
228
+
229
+ Combinatorics
230
+ =============
231
+
232
+ These tools yield combinatorial arrangements of items from iterables.
233
+
234
+ ----
235
+
236
+ **New itertools**
237
+
238
+ .. autofunction:: distinct_permutations
239
+ .. autofunction:: distinct_combinations
240
+ .. autofunction:: nth_combination_with_replacement
241
+ .. autofunction:: circular_shifts
242
+ .. autofunction:: partitions
243
+ .. autofunction:: set_partitions
244
+ .. autofunction:: product_index
245
+ .. autofunction:: combination_index
246
+ .. autofunction:: permutation_index
247
+ .. autofunction:: combination_with_replacement_index
248
+ .. autofunction:: derangements
249
+ .. autofunction:: gray_product
250
+ .. autofunction:: outer_product
251
+ .. autofunction:: powerset_of_sets
252
+
253
+ ----
254
+
255
+ **Itertools recipes**
256
+
257
+ .. autofunction:: powerset
258
+ .. autofunction:: random_product
259
+ .. autofunction:: random_permutation
260
+ .. autofunction:: random_combination
261
+ .. autofunction:: random_combination_with_replacement
262
+ .. autofunction:: random_derangement
263
+ .. autofunction:: nth_product
264
+ .. autofunction:: nth_permutation
265
+ .. autofunction:: nth_combination
266
+
267
+
268
+ Wrapping
269
+ ========
270
+
271
+ These tools provide wrappers to smooth working with objects that produce or
272
+ consume iterables.
273
+
274
+ ----
275
+
276
+ **New itertools**
277
+
278
+ .. autofunction:: always_iterable
279
+ .. autofunction:: always_reversible
280
+ .. autoclass:: callback_iter
281
+ .. autofunction:: countable
282
+ .. autofunction:: consumer
283
+ .. autoclass:: sized_iterator
284
+ .. autofunction:: with_iter
285
+
286
+ ----
287
+
288
+ **Itertools recipes**
289
+
290
+ .. autofunction:: iter_except
291
+
292
+ Math
293
+ ====
294
+
295
+ These tools work with most numeric data types.
296
+
297
+ **New itertools**
298
+
299
+ .. autofunction:: dft
300
+ .. autofunction:: idft
301
+
302
+ ----
303
+
304
+ **Itertools recipes**
305
+
306
+ .. autofunction:: convolve
307
+ .. autofunction:: dotproduct
308
+ .. autofunction:: matmul
309
+ .. autofunction:: polynomial_from_roots
310
+ .. autofunction:: polynomial_derivative
311
+ .. autofunction:: polynomial_eval
312
+ .. autofunction:: running_median
313
+ .. autofunction:: sum_of_squares
314
+
315
+
316
+ Integer Math
317
+ ============
318
+
319
+ **New itertools**
320
+
321
+ The tools focus on math with integers.
322
+
323
+ ----
324
+
325
+ .. autofunction:: nth_prime
326
+
327
+ ----
328
+
329
+ **Itertools recipes**
330
+
331
+ .. autofunction:: factor
332
+ .. autofunction:: is_prime
333
+ .. autofunction:: multinomial
334
+ .. autofunction:: sieve
335
+ .. autofunction:: totient
336
+
337
+
338
+ Others
339
+ ======
340
+
341
+ **New itertools**
342
+
343
+ .. autofunction:: locate(iterable, pred=bool, window_size=None)
344
+ .. autofunction:: rlocate(iterable, pred=bool, window_size=None)
345
+ .. autofunction:: replace
346
+ .. function:: numeric_range(stop)
347
+ .. autofunction:: numeric_range(start, stop[, step])
348
+ :noindex:
349
+ .. autofunction:: side_effect
350
+ .. autofunction:: iterate
351
+ .. autofunction:: difference(iterable, func=operator.sub, *, initial=None)
352
+ .. autofunction:: make_decorator
353
+ .. autoclass:: SequenceView
354
+ .. autofunction:: time_limited
355
+ .. autofunction:: map_if(iterable, pred, func, func_else=lambda x: x)
356
+ .. autofunction:: doublestarmap
357
+
358
+ ----
359
+
360
+ **Itertools recipes**
361
+
362
+ .. autofunction:: iter_index
363
+ .. autofunction:: consume
364
+ .. autofunction:: tabulate
365
+ .. autofunction:: repeatfunc
366
+ .. autofunction:: reshape
367
+ .. autofunction:: loops
examples/repo2env-more-itertools-bug-intersperse-staged/docs/conf.py ADDED
@@ -0,0 +1,286 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #
2
+ # more-itertools documentation build configuration file, created by
3
+ # sphinx-quickstart on Mon Jun 25 20:42:39 2012.
4
+ #
5
+ # This file is execfile()d with the current directory set to its containing dir.
6
+ #
7
+ # Note that not all possible configuration values are present in this
8
+ # autogenerated file.
9
+ #
10
+ # All configuration values have a default; values that are commented out
11
+ # serve to show the default.
12
+
13
+ import sys
14
+ import os
15
+
16
+
17
+ # If extensions (or modules to document with autodoc) are in another directory,
18
+ # add these directories to sys.path here. If the directory is relative to the
19
+ # documentation root, use os.path.abspath to make it absolute, like shown here.
20
+ sys.path.insert(0, os.path.abspath('..'))
21
+
22
+ import more_itertools
23
+
24
+ # -- Preprocess README.rst -----------------------------------------------------
25
+ # We include README.rst from the root directory. It has absolute links
26
+ # to readthedocs.io for display on github.com, but those links can be
27
+ # relative when being built for Sphinx.
28
+
29
+ with open('../README.rst') as source:
30
+ readme_file = source.readlines()
31
+
32
+ build_dir = '_build'
33
+ os.makedirs(build_dir, exist_ok=True)
34
+
35
+ rtd_path = 'https://more-itertools.readthedocs.io/en/stable/'
36
+ table_width = 200
37
+ in_table = False
38
+ with open(os.path.join('.', build_dir, 'README.pprst'), 'w') as target:
39
+ for line in readme_file:
40
+ old_len = len(line)
41
+ if line.startswith('|') and line.endswith('|\n'): # Inside table
42
+ line = line.replace(rtd_path, '').rstrip(' |\n')
43
+ spaces = ' ' * (table_width - len(line) - 1)
44
+ line = f'{line}{spaces}|\n'
45
+
46
+ target.write(line)
47
+
48
+ # -- General configuration -----------------------------------------------------
49
+
50
+ # If your documentation needs a minimal Sphinx version, state it here.
51
+ # needs_sphinx = '1.0'
52
+
53
+ # Add any Sphinx extension module names here, as strings. They can be extensions
54
+ # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
55
+ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode']
56
+
57
+ # Add any paths that contain templates here, relative to this directory.
58
+ templates_path = ['_templates']
59
+
60
+ # The suffix of source filenames.
61
+ source_suffix = '.rst'
62
+
63
+ # The encoding of source files.
64
+ # source_encoding = 'utf-8-sig'
65
+
66
+ # The master toctree document.
67
+ master_doc = 'toctree'
68
+
69
+ # General information about the project.
70
+ project = 'more-itertools'
71
+ copyright = '2012, Erik Rose'
72
+
73
+ # The version info for the project you're documenting, acts as replacement for
74
+ # |version| and |release|, also used in various other places throughout the
75
+ # built documents.
76
+ #
77
+ # The short X.Y version.
78
+ version = more_itertools.__version__
79
+ # The full version, including alpha/beta/rc tags.
80
+ release = version
81
+
82
+ # The language for content autogenerated by Sphinx. Refer to documentation
83
+ # for a list of supported languages.
84
+ # language = None
85
+
86
+ # There are two options for replacing |today|: either, you set today to some
87
+ # non-false value, then it is used:
88
+ # today = ''
89
+ # Else, today_fmt is used as the format for a strftime call.
90
+ # today_fmt = '%B %d, %Y'
91
+
92
+ # List of patterns, relative to source directory, that match files and
93
+ # directories to ignore when looking for source files.
94
+ exclude_patterns = [build_dir]
95
+
96
+ # The reST default role (used for this markup: `text`) to use for all documents.
97
+ # default_role = None
98
+
99
+ # If true, '()' will be appended to :func: etc. cross-reference text.
100
+ # add_function_parentheses = True
101
+
102
+ # If true, the current module name will be prepended to all description
103
+ # unit titles (such as .. function::).
104
+ # add_module_names = True
105
+
106
+ # If true, sectionauthor and moduleauthor directives will be shown in the
107
+ # output. They are ignored by default.
108
+ # show_authors = False
109
+
110
+ # The name of the Pygments (syntax highlighting) style to use.
111
+ pygments_style = 'sphinx'
112
+
113
+ # Pygments syntax highlighting theme when browser or user has chosen dark mode.
114
+ # Setting is specific to furo HTML theme.
115
+ pygments_dark_style = "monokai"
116
+
117
+ # A list of ignored prefixes for module index sorting.
118
+ # modindex_common_prefix = []
119
+
120
+
121
+ # -- Options for HTML output ---------------------------------------------------
122
+
123
+ # The theme to use for HTML and HTML Help pages. See the documentation for
124
+ # a list of builtin themes.
125
+ html_theme = 'furo'
126
+
127
+ # Theme options are theme-specific and customize the look and feel of a theme
128
+ # further. For a list of options available for each theme, see the
129
+ # documentation.
130
+ # html_theme_options = {}
131
+
132
+ # The name for this set of Sphinx documents. If None, it defaults to
133
+ # "<project> v<release> documentation".
134
+ # html_title = None
135
+
136
+ # A shorter title for the navigation bar. Default is the same as html_title.
137
+ # html_short_title = None
138
+
139
+ # The name of an image file (relative to this directory) to place at the top
140
+ # of the sidebar.
141
+ # html_logo = None
142
+
143
+ # The name of an image file (within the static path) to use as favicon of the
144
+ # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
145
+ # pixels large.
146
+ # html_favicon = None
147
+
148
+ # Add any paths that contain custom static files (such as style sheets) here,
149
+ # relative to this directory. They are copied after the builtin static files,
150
+ # so a file named "default.css" will overwrite the builtin "default.css".
151
+ html_static_path = ['_static']
152
+
153
+ html_css_files = ["_static/theme_overrides.css"]
154
+
155
+ # If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
156
+ # using the given strftime format.
157
+ # html_last_updated_fmt = '%b %d, %Y'
158
+
159
+ # If true, SmartyPants will be used to convert quotes and dashes to
160
+ # typographically correct entities.
161
+ # html_use_smartypants = True
162
+
163
+ # Custom sidebar templates, maps document names to template names.
164
+ # html_sidebars = {}
165
+
166
+ # Additional templates that should be rendered to pages, maps page names to
167
+ # template names.
168
+ # html_additional_pages = {}
169
+
170
+ # If false, no module index is generated.
171
+ # html_domain_indices = True
172
+
173
+ # If false, no index is generated.
174
+ # html_use_index = True
175
+
176
+ # If true, the index is split into individual pages for each letter.
177
+ # html_split_index = False
178
+
179
+ # If true, links to the reST sources are added to the pages.
180
+ # html_show_sourcelink = True
181
+
182
+ # If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
183
+ # html_show_sphinx = True
184
+
185
+ # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
186
+ # html_show_copyright = True
187
+
188
+ # If true, an OpenSearch description file will be output, and all pages will
189
+ # contain a <link> tag referring to it. The value of this option must be the
190
+ # base URL from which the finished HTML is served.
191
+ # html_use_opensearch = ''
192
+
193
+ # This is the file name suffix for HTML files (e.g. ".xhtml").
194
+ # html_file_suffix = None
195
+
196
+ # Output file base name for HTML help builder.
197
+ htmlhelp_basename = 'more-itertoolsdoc'
198
+
199
+
200
+ # -- Options for LaTeX output --------------------------------------------------
201
+
202
+ latex_elements = {
203
+ # The paper size ('letterpaper' or 'a4paper').
204
+ #'papersize': 'letterpaper',
205
+ # The font size ('10pt', '11pt' or '12pt').
206
+ #'pointsize': '10pt',
207
+ # Additional stuff for the LaTeX preamble.
208
+ #'preamble': '',
209
+ }
210
+
211
+ # Grouping the document tree into LaTeX files. List of tuples
212
+ # (source start file, target name, title, author, documentclass [howto/manual]).
213
+ latex_documents = [
214
+ (
215
+ 'index',
216
+ 'more-itertools.tex',
217
+ 'more-itertools Documentation',
218
+ 'Erik Rose',
219
+ 'manual',
220
+ ),
221
+ ]
222
+
223
+ # The name of an image file (relative to this directory) to place at the top of
224
+ # the title page.
225
+ # latex_logo = None
226
+
227
+ # For "manual" documents, if this is true, then toplevel headings are parts,
228
+ # not chapters.
229
+ # latex_use_parts = False
230
+
231
+ # If true, show page references after internal links.
232
+ # latex_show_pagerefs = False
233
+
234
+ # If true, show URL addresses after external links.
235
+ # latex_show_urls = False
236
+
237
+ # Documents to append as an appendix to all manuals.
238
+ # latex_appendices = []
239
+
240
+ # If false, no module index is generated.
241
+ # latex_domain_indices = True
242
+
243
+
244
+ # -- Options for manual page output --------------------------------------------
245
+
246
+ # One entry per manual page. List of tuples
247
+ # (source start file, name, description, authors, manual section).
248
+ man_pages = [
249
+ (
250
+ 'index',
251
+ 'more-itertools',
252
+ 'more-itertools Documentation',
253
+ ['Erik Rose'],
254
+ 1,
255
+ )
256
+ ]
257
+
258
+ # If true, show URL addresses after external links.
259
+ # man_show_urls = False
260
+
261
+
262
+ # -- Options for Texinfo output ------------------------------------------------
263
+
264
+ # Grouping the document tree into Texinfo files. List of tuples
265
+ # (source start file, target name, title, author,
266
+ # dir menu entry, description, category)
267
+ texinfo_documents = [
268
+ (
269
+ 'index',
270
+ 'more-itertools',
271
+ 'more-itertools Documentation',
272
+ 'Erik Rose',
273
+ 'more-itertools',
274
+ 'One line description of project.',
275
+ 'Miscellaneous',
276
+ ),
277
+ ]
278
+
279
+ # Documents to append as an appendix to all manuals.
280
+ # texinfo_appendices = []
281
+
282
+ # If false, no module index is generated.
283
+ # texinfo_domain_indices = True
284
+
285
+ # How to display URL addresses: 'footnote', 'no', or 'inline'.
286
+ # texinfo_show_urls = 'footnote'
examples/repo2env-more-itertools-bug-intersperse-staged/docs/index.rst ADDED
@@ -0,0 +1 @@
 
 
1
+ .. include:: ./_build/README.pprst
examples/repo2env-more-itertools-bug-intersperse-staged/docs/license.rst ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ License
3
+ =======
4
+
5
+ more-itertools is under the MIT License. See the LICENSE file.
6
+
7
+ Conditions for Contributors
8
+ ===========================
9
+
10
+ By contributing to this software project, you are agreeing to the following
11
+ terms and conditions for your contributions: First, you agree your
12
+ contributions are submitted under the MIT license. Second, you represent you
13
+ are authorized to make the contributions and grant the license. If your
14
+ employer has rights to intellectual property that includes your contributions,
15
+ you represent that you have received permission to make contributions and grant
16
+ the required license on behalf of that employer.
examples/repo2env-more-itertools-bug-intersperse-staged/docs/make.bat ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @ECHO OFF
2
+
3
+ REM Command file for Sphinx documentation
4
+
5
+ if "%SPHINXBUILD%" == "" (
6
+ set SPHINXBUILD=sphinx-build
7
+ )
8
+ set BUILDDIR=_build
9
+ set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
10
+ set I18NSPHINXOPTS=%SPHINXOPTS% .
11
+ if NOT "%PAPER%" == "" (
12
+ set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
13
+ set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
14
+ )
15
+
16
+ if "%1" == "" goto help
17
+
18
+ if "%1" == "help" (
19
+ :help
20
+ echo.Please use `make ^<target^>` where ^<target^> is one of
21
+ echo. html to make standalone HTML files
22
+ echo. dirhtml to make HTML files named index.html in directories
23
+ echo. singlehtml to make a single large HTML file
24
+ echo. pickle to make pickle files
25
+ echo. json to make JSON files
26
+ echo. htmlhelp to make HTML files and a HTML help project
27
+ echo. qthelp to make HTML files and a qthelp project
28
+ echo. devhelp to make HTML files and a Devhelp project
29
+ echo. epub to make an epub
30
+ echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
31
+ echo. text to make text files
32
+ echo. man to make manual pages
33
+ echo. texinfo to make Texinfo files
34
+ echo. gettext to make PO message catalogs
35
+ echo. changes to make an overview over all changed/added/deprecated items
36
+ echo. linkcheck to check all external links for integrity
37
+ echo. doctest to run all doctests embedded in the documentation if enabled
38
+ goto end
39
+ )
40
+
41
+ if "%1" == "clean" (
42
+ for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
43
+ del /q /s %BUILDDIR%\*
44
+ goto end
45
+ )
46
+
47
+ if "%1" == "html" (
48
+ %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
49
+ if errorlevel 1 exit /b 1
50
+ echo.
51
+ echo.Build finished. The HTML pages are in %BUILDDIR%/html.
52
+ goto end
53
+ )
54
+
55
+ if "%1" == "dirhtml" (
56
+ %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
57
+ if errorlevel 1 exit /b 1
58
+ echo.
59
+ echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
60
+ goto end
61
+ )
62
+
63
+ if "%1" == "singlehtml" (
64
+ %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
65
+ if errorlevel 1 exit /b 1
66
+ echo.
67
+ echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
68
+ goto end
69
+ )
70
+
71
+ if "%1" == "pickle" (
72
+ %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
73
+ if errorlevel 1 exit /b 1
74
+ echo.
75
+ echo.Build finished; now you can process the pickle files.
76
+ goto end
77
+ )
78
+
79
+ if "%1" == "json" (
80
+ %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
81
+ if errorlevel 1 exit /b 1
82
+ echo.
83
+ echo.Build finished; now you can process the JSON files.
84
+ goto end
85
+ )
86
+
87
+ if "%1" == "htmlhelp" (
88
+ %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
89
+ if errorlevel 1 exit /b 1
90
+ echo.
91
+ echo.Build finished; now you can run HTML Help Workshop with the ^
92
+ .hhp project file in %BUILDDIR%/htmlhelp.
93
+ goto end
94
+ )
95
+
96
+ if "%1" == "qthelp" (
97
+ %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
98
+ if errorlevel 1 exit /b 1
99
+ echo.
100
+ echo.Build finished; now you can run "qcollectiongenerator" with the ^
101
+ .qhcp project file in %BUILDDIR%/qthelp, like this:
102
+ echo.^> qcollectiongenerator %BUILDDIR%\qthelp\more-itertools.qhcp
103
+ echo.To view the help file:
104
+ echo.^> assistant -collectionFile %BUILDDIR%\qthelp\more-itertools.ghc
105
+ goto end
106
+ )
107
+
108
+ if "%1" == "devhelp" (
109
+ %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
110
+ if errorlevel 1 exit /b 1
111
+ echo.
112
+ echo.Build finished.
113
+ goto end
114
+ )
115
+
116
+ if "%1" == "epub" (
117
+ %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
118
+ if errorlevel 1 exit /b 1
119
+ echo.
120
+ echo.Build finished. The epub file is in %BUILDDIR%/epub.
121
+ goto end
122
+ )
123
+
124
+ if "%1" == "latex" (
125
+ %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
126
+ if errorlevel 1 exit /b 1
127
+ echo.
128
+ echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
129
+ goto end
130
+ )
131
+
132
+ if "%1" == "text" (
133
+ %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
134
+ if errorlevel 1 exit /b 1
135
+ echo.
136
+ echo.Build finished. The text files are in %BUILDDIR%/text.
137
+ goto end
138
+ )
139
+
140
+ if "%1" == "man" (
141
+ %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
142
+ if errorlevel 1 exit /b 1
143
+ echo.
144
+ echo.Build finished. The manual pages are in %BUILDDIR%/man.
145
+ goto end
146
+ )
147
+
148
+ if "%1" == "texinfo" (
149
+ %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
150
+ if errorlevel 1 exit /b 1
151
+ echo.
152
+ echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
153
+ goto end
154
+ )
155
+
156
+ if "%1" == "gettext" (
157
+ %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
158
+ if errorlevel 1 exit /b 1
159
+ echo.
160
+ echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
161
+ goto end
162
+ )
163
+
164
+ if "%1" == "changes" (
165
+ %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
166
+ if errorlevel 1 exit /b 1
167
+ echo.
168
+ echo.The overview file is in %BUILDDIR%/changes.
169
+ goto end
170
+ )
171
+
172
+ if "%1" == "linkcheck" (
173
+ %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
174
+ if errorlevel 1 exit /b 1
175
+ echo.
176
+ echo.Link check complete; look for any errors in the above output ^
177
+ or in %BUILDDIR%/linkcheck/output.txt.
178
+ goto end
179
+ )
180
+
181
+ if "%1" == "doctest" (
182
+ %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
183
+ if errorlevel 1 exit /b 1
184
+ echo.
185
+ echo.Testing of doctests in the sources finished, look at the ^
186
+ results in %BUILDDIR%/doctest/output.txt.
187
+ goto end
188
+ )
189
+
190
+ :end
examples/repo2env-more-itertools-bug-intersperse-staged/docs/requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ Sphinx
2
+ furo>=2025.07.19
examples/repo2env-more-itertools-bug-intersperse-staged/docs/testing.rst ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ =======
2
+ Testing
3
+ =======
4
+
5
+ To run install dependencies and run tests, use this command::
6
+
7
+ python -m unittest
8
+
9
+ Multiple Python Versions
10
+ ========================
11
+
12
+ To run the tests on all the versions of Python more-itertools supports, install
13
+ tox::
14
+
15
+ pip install tox
16
+
17
+ Then, run the tests::
18
+
19
+ tox
examples/repo2env-more-itertools-bug-intersperse-staged/docs/toctree.rst ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ Contents
2
+ ========
3
+
4
+ .. toctree::
5
+ :maxdepth: 2
6
+
7
+ index
8
+ api
9
+
10
+ .. toctree::
11
+ :maxdepth: 1
12
+
13
+ license
14
+ testing
15
+ versions
examples/repo2env-more-itertools-bug-intersperse-staged/docs/versions.rst ADDED
@@ -0,0 +1,813 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ===============
2
+ Version History
3
+ ===============
4
+
5
+ .. automodule:: more_itertools
6
+ :noindex:
7
+
8
+ 10.8.0
9
+ ------
10
+
11
+ * New functions:
12
+ * :func:`derangements` was added (thanks to debruijn)
13
+ * :func:`argmin` and :func:`argmax` were added (thanks to rhettinger)
14
+ * :func:`running_median` was added (thanks to rhettinger)
15
+ * :func:`extract` was added (thanks to rhettinger)
16
+ * :func:`interleave_randomly` was added (thanks to ktbarrett)
17
+
18
+ * Changes to existing functions:
19
+ * The type hints and docstring for :func:`batched` were improved (thanks to qobilidop and inventshah)
20
+ * The memory usage of :func:`islice_extended` was reduced (thanks to ben42code)
21
+ * The performance of :func:`sample` and :func:`consecutive_groups`, :func:`dft`, :func:`idft`, :func:`map_if`, :func:`count_cycle`, and :func:`tail` were improved (thanks to rhettinger)
22
+ * The performance of :func:`before_and_after`, :func:`mark_ends`, and :func:`interleave_longest` were improved (thanks to pochmann3)
23
+ * :func:`nth_prime` now accepts an ``approximate`` keyword. When set to ``True``, a faster but less accurate method is used to return a result. (thanks to rhettinger)
24
+ * :func:`last` now works when its input has ``__reversed__`` set to ``None`` (thanks to inventshah)
25
+ * The :func:`unzip` function was simplified (thanks to pochmann3)
26
+ * The :func:`reshape` function now accepts ``shape`` values that represent multidimensional matrices (thanks to rhettinger)
27
+
28
+ * Other changes:
29
+ * An issue with dark themes and documentation display was fixed (thanks to pochmann3, moreati, and pradyunsg)
30
+ * Variable names in several functions were improved (thanks to rhettinger)
31
+ * The docstrings for :func:`dft`, :func:`idft`, :func:`minmax`, :func:`sample`, and :func:`multinomial` were improved (thanks to rhettinger)
32
+ * Packaging and package index metadata were improved (thanks to cdce8p)
33
+ * Several aspects of the documentation were improved (thanks to rhettinger, saadmanrafat)
34
+ * The Makefile now refers to `python` instead of `python3` (thanks to ktbarrett)
35
+ * Test coverage was improved (thanks to rhettinger)
36
+ * Python 3.14 is now tested by GitHub Actions
37
+
38
+ 10.7.0
39
+ ------
40
+
41
+ * New functions:
42
+ * :func:`multinomial` was added (thanks to rhettinger)
43
+
44
+ * Changes to existing functions:
45
+ * :func:`ichunked`, :func:`iterate`, :func:`one`, :func:`only`, :func:`powerset_of_sets`, and :func:`strictly_n` were optimized (thanks to rhettinger)
46
+ * :func:`exactly_n` now uses less memory (thanks to rhettinger)
47
+ * :func:`dft` and :func:`idft` were optimized for Python versions below 3.12 (thanks to rhettinger)
48
+ * :func:`is_prime` no longer shares state with the users random number generator (thanks to rhettinger)
49
+
50
+ * Other changes:
51
+ * Some docstring issues were fixed (thanks to lpulley and ricbit)
52
+ * The type hints for :func:`groupby_transform` were improved (thanks to rhettinger)
53
+ * The ``furo`` theme is now used for docs (thanks to AA-turner)
54
+
55
+
56
+ 10.6.0
57
+ ------
58
+
59
+ * New functions:
60
+ * :func:`is_prime` and :func:`nth_prime` were added (thanks to JamesParrott and rhettinger)
61
+ * :func:`loops` was added (thanks to rhettinger)
62
+
63
+ * Changes to existing functions:
64
+ * :func:`factor` was optimized to handle larger inputs and use less memory (thanks to rhettinger)
65
+ * :func:`spy` was optimized to enable nested calls (thanks to rhettinger)
66
+ * :func:`polynomial_from_roots` was made non-recursive and able to handle larger numbers of roots (thanks to pochmann3 and rhettinger)
67
+ * :func:`is_sorted` now only relies on less than comparisons (thanks to rhettinger)
68
+ * The docstring for :func:`outer_product` was improved (thanks to rhettinger)
69
+ * The type annotations for :func:`sample` were improved (thanks to rhettinger)
70
+
71
+ * Other changes:
72
+ * Python 3.13 is officially supported. Python 3.8 is no longer officially supported. (thanks to hugovk, JamesParrott, and stankudrow)
73
+ * `mypy` checks were fixed (thanks to JamesParrott)
74
+
75
+ 10.5.0
76
+ ------
77
+
78
+ * Bug fixes
79
+ * A missing symbol in ``more.pyi`` was fixed (thanks to eberts-google and nathanielmanistaatgoogle)
80
+
81
+ * Other changes
82
+ * :func:`all_equal` was optimized (thanks to pochmann3 and rhettinger)
83
+
84
+ 10.4.0
85
+ ------
86
+
87
+ * Changes to existing functions
88
+ * :func:`circular_shifts` now accepts a ``steps`` parameter (thanks to rhettinger)
89
+ * :func:`distinct_permutations` now accepts iterables with non-comparable items (thanks to hgustafsson, JamesParrott, and pochmann3)
90
+ * :class:`run_length`, :func:`totient`, :func:`sliding_window`, and :func:`triplewise` were optimized (thanks to rhettinger)
91
+ * :class:`ilen` was optimized (thanks to pochmann3 and rhettinger)
92
+ * :func:`sample` was improved, and now accepts ``counts`` and ``strict`` parameters (thanks to rhettinger)
93
+ * :func:`set_partitions` now accepts ``min_size`` and ``max_size`` parameters (thanks to Pandede)
94
+ * :func:`seekable`'s ``relative_seek`` method remembers previous calls (thanks to dkrikun)
95
+ * :func:`sort_together` now accepts a ``strict`` parameter (thanks to rhettinger and Pandede)
96
+
97
+ * Other changes
98
+ * The docs for :func:`is_sorted` and :func:`strictly_n` were improved (thanks to pochmann3 and fakuivan)
99
+ * The typing information for :func:`windowed_complete`, :func:`zip_broadcast`, and :func:`zip_equal` were improved (thanks to m472, eyalho, akisatoon1, jbosboom, and Pandede)
100
+
101
+ 10.3.0
102
+ ------
103
+
104
+ * New functions
105
+ * :func:`powerset_of_sets`, :func:`dft`, and :func:`idft` (thanks to rhettinger)
106
+ * :func:`join_mappings` (thanks to NeilGirdhar and rhettinger)
107
+ * :func:`doublestarmap` (thanks to Skeen, monk-time, DamianB-BitFlipper, and ergoithz)
108
+ * :func:`unique` (thanks to rhettinger)
109
+
110
+ * Changes to existing functions
111
+ * :func:`collapse`, :func:`chunked_even`, :func:`ichunked`, :func:`padded`, and :func:`windowed` were optimized and improved (thanks to james-wasson)
112
+ * :func:`totient` was optimized (thanks to rhettinger)
113
+ * :func:`roundrobin` was updated and improved (thanks to rhettinger)
114
+ * :func:`all_equal` now accepts a *key* parameter.
115
+ * The docs for :func:`value_chain` were improved (thanks to bjrtx)
116
+ * The type annotations for :class:`countable` were improved (thanks to aidanholm)
117
+
118
+ * Other changes
119
+ * Unit tests were improved (thanks to haukex)
120
+ * Some documentation issues were fixed (thanks to bjrtx and DimitriPapadopoulos)
121
+
122
+ 10.2.0
123
+ ------
124
+
125
+ * New functions
126
+ * :func:`iter_suppress` (thanks to jaraco, pochmann, and rhettinger)
127
+ * :func:`filter_map` (thanks to struktured)
128
+ * :func:`classify_unique` (thanks to haukex)
129
+ * :func:`totient` (from the itertools docs)
130
+ * :func:`reshape` (from the itertools docs)
131
+
132
+ * Changes to existing functions
133
+ * :func:`factor`, :func:`iter_index`, :func:`sieve`, and :func:`unique_justseen` were updated to match the itertools docs
134
+ * :func:`first` was optimized (thanks to pochmann)
135
+ * :func:`takewhile_inclusive` was refactored (thanks to eltoder)
136
+ * :func:`combination_with_replacement_index` was optimized (thanks to elliotwutingfeng and rhettinger)
137
+ * :func:`nth_permutation`, :func:`nth_combination_with_replacement`, :func:`combination_index`, and :func:`combination_with_replacement_index` were optimized (thanks to rhettinger)
138
+ * :func:`batched` now accepts a `strict` argument (adapted from itertools docs)
139
+ * :func:`time_limited` was improved for Windows (thanks to haukex)
140
+
141
+ * Other changes
142
+ * Several typing updates were made (thanks to obaltian and ilai-deutel)
143
+ * Some documentation issues were fixed (thanks to F-park, DimitriPapadopoulos, peterbygrave, shuuji3, eltoder, and homeworkprod)
144
+
145
+ 10.1.0
146
+ ------
147
+
148
+ * New functions
149
+ * :func:`takewhile_inclusive` (thanks to OlegAlexander)
150
+ * :func:`outer_product` (thanks to OlegAlexander)
151
+
152
+ * Changes to existing functions
153
+ * :func:`zip_broadcast` was improved (thanks to kalekundert and pochmann)
154
+ * :func:`consume` had its type annotation fixed (thanks to obaltian)
155
+
156
+ * Other changes
157
+ * Some documentation and testing issues were fixed (thanks to OlegAlexander)
158
+
159
+ 10.0.0
160
+ ------
161
+
162
+ * Potentially breaking changes
163
+ * Python 3.7 support was dropped, since it went EOL on 2023-06-27
164
+ * :func:`batched` no longer issues a ``DeprecationWarning``; it is now an alias for ``itertools.batched`` for Python 3.12+
165
+ * :func:`batched` and :func:`matmul` now yield tuples instead of lists
166
+
167
+ * New functions
168
+ * :func:`combination_with_replacement_index` (thanks to Schoyen)
169
+ * :func:`nth_combination_with_replacement` (thanks to Schoyen)
170
+ * :func:`polynomial_eval` (from the Python itertools docs)
171
+ * :func:`polynomial_derivative` (from the Python itertools docs)
172
+ * :func:`sum_of_squares` (from the Python itertools docs)
173
+
174
+ * Changes to existing functions
175
+ * :func:`seekable` now has ``relative_seek`` method (thanks to karlb)
176
+ * :func:`chunked_even` was optimized (thanks to elliotwutingfeng)
177
+ * :func:`numeric_range` was optimized (thanks to eltoder)
178
+ * :func:`duplicates_justseen`, :func:`pairwise`, :func:`partial_product`, and :func:`partition` were updated and optimized (thanks to pochmann)
179
+ * :func:`unique_in_window` had its implementation updated (thanks to elliotwutingfeng)
180
+ * :func:`iterate` now breaks when its ``func`` argument raises ``StopIteration`` (thanks to jrebiffe)
181
+
182
+ * Other changes
183
+ * Some documentation and testing issues were fixed (thanks to lonnen and XuehaiPan)
184
+
185
+ 9.1.0
186
+ -----
187
+
188
+ * New functions
189
+ * :func:`iter_index` (from the Python itertools docs)
190
+ * :func:`transpose` (from the Python itertools docs)
191
+ * :func:`matmul` (from the Python itertools docs)
192
+ * :func:`factor` (from the Python itertools docs)
193
+ * :func:`gray_product` (thanks to haukex)
194
+ * :func:`partial_product` (thanks to lonnen)
195
+
196
+ * Changes to existing functions
197
+ * :func:`sieve` was updated to match the Python itertools docs
198
+ * :func:`maxsplit` was updated to fix a bug (thanks to abingham)
199
+ * :func:`sliced` had its `type hint <https://github.com/more-itertools/more-itertools/pull/667>`__ updated (thanks to ad-chaos)
200
+
201
+
202
+ * Other changes
203
+ * 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)
204
+ * The type hints now used postponed evaluation of annotations from PEP 563 (thanks to Isira-Seneviratne)
205
+ * Some documentation issues were fixed (thanks to Voskov and jdkandersson)
206
+
207
+ 9.0.0
208
+ -----
209
+
210
+ * Potentially breaking changes
211
+ * :func:`grouper` no longer accepts an integer as its first argument. Previously this raised a ``DeprecationWarning``.
212
+ * :func:`collate` has been removed. Use the built-in :func:`heapq.merge` instead.
213
+ * :func:`windowed` now yields nothing when its iterable is empty.
214
+ * This library now advertises support for Python 3.7+.
215
+
216
+ * New functions
217
+ * :func:`constrained_batches`
218
+ * :func:`batched` (from the Python itertools docs)
219
+ * :func:`polynomial_from_roots` (from the Python itertools docs)
220
+ * :func:`sieve` (from the Python itertools docs)
221
+
222
+ * Other changes
223
+ * Some documentation issues were fixed (thanks to nanouasyn)
224
+
225
+ 8.14.0
226
+ ------
227
+
228
+ * New functions
229
+ * :func:`longest_common_prefix` (thanks to nanouasyn)
230
+ * :func:`iequals` (thanks to nanouasyn)
231
+
232
+ * Changes to existing functions
233
+ * `concurrent.futures.ThreadPoolExecutor` is now imported lazily in :func:`callback_iter`.
234
+ * :func:`tail` is now optimized for iterables with a fixed length.
235
+
236
+ * Other changes
237
+ * Some documentation issues were fixed (thanks to pochmann and timgates42)
238
+ * This library is now marked for Python 3.10 compatibility in PyPI (thanks to chayim)
239
+
240
+ 8.13.0
241
+ ------
242
+
243
+ * New functions
244
+ * The :func:`subslices` recipe from the `itertools` docs was added (thanks to rhettinger)
245
+
246
+ * Changes to existing functions
247
+ * The :func:`ichunked` function is now more efficient (thanks to hjtran0 and seanmacavaney)
248
+ * The :func:`difference` function is now more efficient (thanks to Masynchin)
249
+ * The :func:`grouper` recipe now has more features, mirroring the one in the `itertools` docs (thanks to rhettinger)
250
+
251
+ * Other changes
252
+ * Some documentation issues were fixed (thanks to medvied and Freed-Wu)
253
+ * The `more_itertools` package is now built with `flit` (thanks to mgorny)
254
+
255
+ 8.12.0
256
+ ------
257
+
258
+ * Bug fixes
259
+ * Some documentation issues were fixed (thanks to Masynchin, spookylukey, astrojuanlu, and stephengmatthews)
260
+ * Python 3.5 support was temporarily restored (thanks to mattbonnell)
261
+
262
+ 8.11.0
263
+ ------
264
+
265
+ * New functions
266
+ * The :func:`before_and_after`, :func:`sliding_window`, and :func:`triplewise` recipes from the Python 3.10 docs were added
267
+ * :func:`duplicates_everseen` and :func:`duplicates_justseen` (thanks to OrBin and DavidPratt512)
268
+ * :func:`minmax` (thanks to Ricocotam, MSeifert04, and ruancomelli)
269
+ * :func:`strictly_n` (thanks to hwalinga and NotWearingPants)
270
+ * :func:`unique_in_window`
271
+
272
+ * Changes to existing functions
273
+ * :func:`groupby_transform` had its type stub improved (thanks to mjk4 and ruancomelli)
274
+ * :func:`is_sorted` now accepts a ``strict`` parameter (thanks to Dutcho and ruancomelli)
275
+ * :func:`zip_broadcast` was updated to fix a bug (thanks to kalekundert)
276
+
277
+ 8.10.0
278
+ ------
279
+
280
+ * Changes to existing functions
281
+ * The type stub for :func:`iter_except` was improved (thanks to MarcinKonowalczyk)
282
+
283
+ * Other changes:
284
+ * Type stubs now ship with the source release (thanks to saaketp)
285
+ * The Sphinx docs were improved (thanks to MarcinKonowalczyk)
286
+
287
+ 8.9.0
288
+ -----
289
+
290
+ * New functions
291
+ * :func:`interleave_evenly` (thanks to mbugert)
292
+ * :func:`repeat_each` (thanks to FinalSh4re)
293
+ * :func:`chunked_even` (thanks to valtron)
294
+ * :func:`map_if` (thanks to sassbalint)
295
+ * :func:`zip_broadcast` (thanks to kalekundert)
296
+
297
+ * Changes to existing functions
298
+ * The type stub for :func:`chunked` was improved (thanks to PhilMacKay)
299
+ * The type stubs for :func:`zip_equal` and `zip_offset` were improved (thanks to maffoo)
300
+ * Building Sphinx docs locally was improved (thanks to MarcinKonowalczyk)
301
+
302
+ 8.8.0
303
+ -----
304
+
305
+ * New functions
306
+ * :func:`countable` (thanks to krzysieq)
307
+
308
+ * Changes to existing functions
309
+ * :func:`split_before` was updated to handle empty collections (thanks to TiunovNN)
310
+ * :func:`unique_everseen` got a performance boost (thanks to Numerlor)
311
+ * The type hint for :func:`value_chain` was corrected (thanks to vr2262)
312
+
313
+ 8.7.0
314
+ -----
315
+
316
+ * New functions
317
+ * :func:`convolve` (from the Python itertools docs)
318
+ * :func:`product_index`, :func:`combination_index`, and :func:`permutation_index` (thanks to N8Brooks)
319
+ * :func:`value_chain` (thanks to jenstroeger)
320
+
321
+ * Changes to existing functions
322
+ * :func:`distinct_combinations` now uses a non-recursive algorithm (thanks to knutdrand)
323
+ * :func:`pad_none` is now the preferred name for :func:`padnone`, though the latter remains available.
324
+ * :func:`pairwise` will now use the Python standard library implementation on Python 3.10+
325
+ * :func:`sort_together` now accepts a ``key`` argument (thanks to brianmaissy)
326
+ * :func:`seekable` now has a ``peek`` method, and can indicate whether the iterator it's wrapping is exhausted (thanks to gsakkis)
327
+ * :func:`time_limited` can now indicate whether its iterator has expired (thanks to roysmith)
328
+ * The implementation of :func:`unique_everseen` was improved (thanks to plammens)
329
+
330
+ * Other changes:
331
+ * Various documentation updates (thanks to cthoyt, Evantm, and cyphase)
332
+
333
+ 8.6.0
334
+ -----
335
+
336
+ * New itertools
337
+ * :func:`all_unique` (thanks to brianmaissy)
338
+ * :func:`nth_product` and :func:`nth_permutation` (thanks to N8Brooks)
339
+
340
+ * Changes to existing itertools
341
+ * :func:`chunked` and :func:`sliced` now accept a ``strict`` parameter (thanks to shlomif and jtwool)
342
+
343
+ * Other changes
344
+ * Python 3.5 has reached its end of life and is no longer supported.
345
+ * Python 3.9 is officially supported.
346
+ * Various documentation fixes (thanks to timgates42)
347
+
348
+ 8.5.0
349
+ -----
350
+
351
+ * New itertools
352
+ * :func:`windowed_complete` (thanks to MarcinKonowalczyk)
353
+
354
+ * Changes to existing itertools:
355
+ * The :func:`is_sorted` implementation was improved (thanks to cool-RR)
356
+ * The :func:`groupby_transform` now accepts a ``reducefunc`` parameter.
357
+ * The :func:`last` implementation was improved (thanks to brianmaissy)
358
+
359
+ * Other changes
360
+ * Various documentation fixes (thanks to craigrosie, samuelstjean, PiCT0)
361
+ * The tests for :func:`distinct_combinations` were improved (thanks to Minabsapi)
362
+ * Automated tests now run on GitHub Actions. All commits now check:
363
+ * That unit tests pass
364
+ * That the examples in docstrings work
365
+ * That test coverage remains high (using `coverage`)
366
+ * For linting errors (using `flake8`)
367
+ * For consistent style (using `black`)
368
+ * That the type stubs work (using `mypy`)
369
+ * That the docs build correctly (using `sphinx`)
370
+ * That packages build correctly (using `twine`)
371
+
372
+ 8.4.0
373
+ -----
374
+
375
+ * New itertools
376
+ * :func:`mark_ends` (thanks to kalekundert)
377
+ * :func:`is_sorted`
378
+
379
+ * Changes to existing itertools:
380
+ * :func:`islice_extended` can now be used with real slices (thanks to cool-RR)
381
+ * The implementations for :func:`filter_except` and :func:`map_except` were improved (thanks to SergBobrovsky)
382
+
383
+ * Other changes
384
+ * Automated tests now enforce code style (using `black <https://github.com/psf/black>`__)
385
+ * The various signatures of :func:`islice_extended` and :func:`numeric_range` now appear in the docs (thanks to dsfulf)
386
+ * The test configuration for mypy was updated (thanks to blueyed)
387
+
388
+
389
+ 8.3.0
390
+ -----
391
+
392
+ * New itertools
393
+ * :func:`zip_equal` (thanks to frankier and alexmojaki)
394
+
395
+ * Changes to existing itertools:
396
+ * :func:`split_at`, :func:`split_before`, :func:`split_after`, and :func:`split_when` all got a ``maxsplit`` parameter (thanks to jferard and ilai-deutel)
397
+ * :func:`split_at` now accepts a ``keep_separator`` parameter (thanks to jferard)
398
+ * :func:`distinct_permutations` can now generate ``r``-length permutations (thanks to SergBobrovsky and ilai-deutel)
399
+ * The :func:`windowed` implementation was improved (thanks to SergBobrovsky)
400
+ * The :func:`spy` implementation was improved (thanks to has2k1)
401
+
402
+ * Other changes
403
+ * Type stubs are now tested with ``stubtest`` (thanks to ilai-deutel)
404
+ * Tests now run with ``python -m unittest`` instead of ``python setup.py test`` (thanks to jdufresne)
405
+
406
+ 8.2.0
407
+ -----
408
+
409
+ * Bug fixes
410
+ * The .pyi files for typing were updated. (thanks to blueyed and ilai-deutel)
411
+
412
+ * Changes to existing itertools:
413
+ * :func:`numeric_range` now behaves more like the built-in :func:`range`. (thanks to jferard)
414
+ * :func:`bucket` now allows for enumerating keys. (thanks to alexchandel)
415
+ * :func:`sliced` should work for numpy arrays. (thanks to sswingle)
416
+ * :func:`seekable` now has a ``maxlen`` parameter.
417
+
418
+ 8.1.0
419
+ -----
420
+
421
+ * Bug fixes
422
+ * :func:`partition` works with ``pred=None`` again. (thanks to MSeifert04)
423
+
424
+ * New itertools
425
+ * :func:`sample` (thanks to tommyod)
426
+ * :func:`nth_or_last` (thanks to d-ryzhikov)
427
+
428
+ * Changes to existing itertools:
429
+ * The implementation for :func:`divide` was improved. (thanks to jferard)
430
+
431
+ 8.0.2
432
+ -----
433
+
434
+ * Bug fixes
435
+ * The type stub files are now part of the wheel distribution (thanks to keisheiled)
436
+
437
+ 8.0.1
438
+ -----
439
+
440
+ * Bug fixes
441
+ * The type stub files now work for functions imported from the
442
+ root package (thanks to keisheiled)
443
+
444
+ 8.0.0
445
+ -----
446
+
447
+ * New itertools and other additions
448
+ * This library now ships type hints for use with mypy.
449
+ (thanks to ilai-deutel for the implementation, and to gabbard and fmagin for assistance)
450
+ * :func:`split_when` (thanks to jferard)
451
+ * :func:`repeat_last` (thanks to d-ryzhikov)
452
+
453
+ * Changes to existing itertools:
454
+ * The implementation for :func:`set_partitions` was improved. (thanks to jferard)
455
+ * :func:`partition` was optimized for expensive predicates. (thanks to stevecj)
456
+ * :func:`unique_everseen` and :func:`groupby_transform` were re-factored. (thanks to SergBobrovsky)
457
+ * The implementation for :func:`difference` was improved. (thanks to Jabbey92)
458
+
459
+ * Other changes
460
+ * Python 3.4 has reached its end of life and is no longer supported.
461
+ * Python 3.8 is officially supported. (thanks to jdufresne)
462
+ * The ``collate`` function has been deprecated.
463
+ It raises a ``DeprecationWarning`` if used, and will be removed in a future release.
464
+ * :func:`one` and :func:`only` now provide more informative error messages. (thanks to gabbard)
465
+ * Unit tests were moved outside of the main package (thanks to jdufresne)
466
+ * Various documentation fixes (thanks to kriomant, gabbard, jdufresne)
467
+
468
+
469
+ 7.2.0
470
+ -----
471
+
472
+ * New itertools
473
+ * :func:`distinct_combinations`
474
+ * :func:`set_partitions` (thanks to kbarrett)
475
+ * :func:`filter_except`
476
+ * :func:`map_except`
477
+
478
+ 7.1.0
479
+ -----
480
+
481
+ * New itertools
482
+ * :func:`ichunked` (thanks davebelais and youtux)
483
+ * :func:`only` (thanks jaraco)
484
+
485
+ * Changes to existing itertools:
486
+ * :func:`numeric_range` now supports ranges specified by
487
+ ``datetime.datetime`` and ``datetime.timedelta`` objects (thanks to MSeifert04 for tests).
488
+ * :func:`difference` now supports an *initial* keyword argument.
489
+
490
+
491
+ * Other changes
492
+ * Various documentation fixes (thanks raimon49, pylang)
493
+
494
+ 7.0.0
495
+ -----
496
+
497
+ * New itertools:
498
+ * :func:`time_limited`
499
+ * :func:`partitions` (thanks to rominf and Saluev)
500
+ * :func:`substrings_indexes` (thanks to rominf)
501
+
502
+ * Changes to existing itertools:
503
+ * :func:`collapse` now treats ``bytes`` objects the same as ``str`` objects. (thanks to Sweenpet)
504
+
505
+ The major version update is due to the change in the default behavior of
506
+ :func:`collapse`. It now treats ``bytes`` objects the same as ``str`` objects.
507
+ This aligns its behavior with :func:`always_iterable`.
508
+
509
+ .. code-block:: python
510
+
511
+ >>> from more_itertools import collapse
512
+ >>> iterable = [[1, 2], b'345', [6]]
513
+ >>> print(list(collapse(iterable)))
514
+ [1, 2, b'345', 6]
515
+
516
+ 6.0.0
517
+ -----
518
+
519
+ * Major changes:
520
+ * Python 2.7 is no longer supported. The 5.0.0 release will be the last
521
+ version targeting Python 2.7.
522
+ * All future releases will target the active versions of Python 3.
523
+ As of 2019, those are Python 3.4 and above.
524
+ * The ``six`` library is no longer a dependency.
525
+ * The :func:`accumulate` function is no longer part of this library. You
526
+ may import a better version from the standard ``itertools`` module.
527
+
528
+ * Changes to existing itertools:
529
+ * The order of the parameters in :func:`grouper` have changed to match
530
+ the latest recipe in the itertools documentation. Use of the old order
531
+ will be supported in this release, but emit a ``DeprecationWarning``.
532
+ The legacy behavior will be dropped in a future release. (thanks to jaraco)
533
+ * :func:`distinct_permutations` was improved (thanks to jferard - see also `permutations with unique values <https://stackoverflow.com/questions/6284396/permutations-with-unique-values>`_ at StackOverflow.)
534
+ * An unused parameter was removed from :func:`substrings`. (thanks to pylang)
535
+
536
+ * Other changes:
537
+ * The docs for :func:`unique_everseen` were improved. (thanks to jferard and MSeifert04)
538
+ * Several Python 2-isms were removed. (thanks to jaraco, MSeifert04, and hugovk)
539
+
540
+ 5.0.0
541
+ -----
542
+
543
+ * New itertools:
544
+ * :func:`split_into` (thanks to rovyko)
545
+ * :func:`unzip` (thanks to bmintz)
546
+ * :func:`substrings` (thanks to pylang)
547
+
548
+ * Changes to existing itertools:
549
+ * :func:`ilen` was optimized a bit (thanks to MSeifert04, achampion, and bmintz)
550
+ * :func:`first_true` now returns ``None`` by default. This is the reason for the major version bump - see below. (thanks to sk and OJFord)
551
+
552
+ * Other changes:
553
+ * Some code for old Python versions was removed (thanks to hugovk)
554
+ * Some documentation mistakes were corrected (thanks to belm0 and hugovk)
555
+ * Tests now run properly on 32-bit versions of Python (thanks to Millak)
556
+ * Newer versions of CPython and PyPy are now tested against
557
+
558
+ The major version update is due to the change in the default return value of
559
+ :func:`first_true`. It's now ``None``.
560
+
561
+ .. code-block:: python
562
+
563
+ >>> from more_itertools import first_true
564
+ >>> iterable = [0, '', False, [], ()] # All these are False
565
+ >>> answer = first_true(iterable)
566
+ >>> print(answer)
567
+ None
568
+
569
+ 4.3.0
570
+ -----
571
+
572
+ * New itertools:
573
+ * :func:`last` (thanks to tmshn)
574
+ * :func:`replace` (thanks to pylang)
575
+ * :func:`rlocate` (thanks to jferard and pylang)
576
+
577
+ * Improvements to existing itertools:
578
+ * :func:`locate` can now search for multiple items
579
+
580
+ * Other changes:
581
+ * The docs now include a nice table of tools (thanks MSeifert04)
582
+
583
+ 4.2.0
584
+ -----
585
+
586
+ * New itertools:
587
+ * :func:`map_reduce` (thanks to pylang)
588
+ * :func:`prepend` (from the `Python 3.7 docs <https://docs.python.org/3.7/library/itertools.html#itertools-recipes>`_)
589
+
590
+ * Improvements to existing itertools:
591
+ * :func:`bucket` now complies with PEP 479 (thanks to irmen)
592
+
593
+ * Other changes:
594
+ * Python 3.7 is now supported (thanks to irmen)
595
+ * Python 3.3 is no longer supported
596
+ * The test suite no longer requires third-party modules to run
597
+ * The API docs now include links to source code
598
+
599
+ 4.1.0
600
+ -----
601
+
602
+ * New itertools:
603
+ * :func:`split_at` (thanks to michael-celani)
604
+ * :func:`circular_shifts` (thanks to hiqua)
605
+ * :func:`make_decorator` - see the blog post `Yo, I heard you like decorators <https://sites.google.com/site/bbayles/index/decorator_factory>`_
606
+ for a tour (thanks to pylang)
607
+ * :func:`always_reversible` (thanks to michael-celani)
608
+ * :func:`nth_combination` (from the `Python 3.7 docs <https://docs.python.org/3.7/library/itertools.html#itertools-recipes>`_)
609
+
610
+ * Improvements to existing itertools:
611
+ * :func:`seekable` now has an ``elements`` method to return cached items.
612
+ * The performance tradeoffs between :func:`roundrobin` and
613
+ :func:`interleave_longest` are now documented (thanks michael-celani,
614
+ pylang, and MSeifert04)
615
+
616
+ 4.0.1
617
+ -----
618
+
619
+ * No code changes - this release fixes how the docs display on PyPI.
620
+
621
+ 4.0.0
622
+ -----
623
+
624
+ * New itertools:
625
+ * :func:`consecutive_groups` (Based on the example in the `Python 2.4 docs <https://docs.python.org/release/2.4.4/lib/itertools-example.html>`_)
626
+ * :func:`seekable` (If you're looking for how to "reset" an iterator,
627
+ you're in luck!)
628
+ * :func:`exactly_n` (thanks to michael-celani)
629
+ * :func:`run_length.encode` and :func:`run_length.decode`
630
+ * :func:`difference`
631
+
632
+ * Improvements to existing itertools:
633
+ * The number of items between filler elements in :func:`intersperse` can
634
+ now be specified (thanks to pylang)
635
+ * :func:`distinct_permutations` and :func:`peekable` got some minor
636
+ adjustments (thanks to MSeifert04)
637
+ * :func:`always_iterable` now returns an iterator object. It also now
638
+ allows different types to be considered iterable (thanks to jaraco)
639
+ * :func:`bucket` can now limit the keys it stores in memory
640
+ * :func:`one` now allows for custom exceptions (thanks to kalekundert)
641
+
642
+ * Other changes:
643
+ * A few typos were fixed (thanks to EdwardBetts)
644
+ * All tests can now be run with ``python setup.py test``
645
+
646
+ The major version update is due to the change in the return value of :func:`always_iterable`.
647
+ It now always returns iterator objects:
648
+
649
+ .. code-block:: python
650
+
651
+ >>> from more_itertools import always_iterable
652
+ # Non-iterable objects are wrapped with iter(tuple(obj))
653
+ >>> always_iterable(12345)
654
+ <tuple_iterator object at 0x7fb24c9488d0>
655
+ >>> list(always_iterable(12345))
656
+ [12345]
657
+ # Iterable objects are wrapped with iter()
658
+ >>> always_iterable([1, 2, 3, 4, 5])
659
+ <list_iterator object at 0x7fb24c948c50>
660
+
661
+ 3.2.0
662
+ -----
663
+
664
+ * New itertools:
665
+ * :func:`lstrip`, :func:`rstrip`, and :func:`strip`
666
+ (thanks to MSeifert04 and pylang)
667
+ * :func:`islice_extended`
668
+ * Improvements to existing itertools:
669
+ * Some bugs with slicing :func:`peekable`-wrapped iterables were fixed
670
+
671
+ 3.1.0
672
+ -----
673
+
674
+ * New itertools:
675
+ * :func:`numeric_range` (Thanks to BebeSparkelSparkel and MSeifert04)
676
+ * :func:`count_cycle` (Thanks to BebeSparkelSparkel)
677
+ * :func:`locate` (Thanks to pylang and MSeifert04)
678
+ * Improvements to existing itertools:
679
+ * A few itertools are now slightly faster due to some function
680
+ optimizations. (Thanks to MSeifert04)
681
+ * The docs have been substantially revised with installation notes,
682
+ categories for library functions, links, and more. (Thanks to pylang)
683
+
684
+
685
+ 3.0.0
686
+ -----
687
+
688
+ * Removed itertools:
689
+ * ``context`` has been removed due to a design flaw - see below for
690
+ replacement options. (thanks to NeilGirdhar)
691
+ * Improvements to existing itertools:
692
+ * ``side_effect`` now supports ``before`` and ``after`` keyword
693
+ arguments. (Thanks to yardsale8)
694
+ * PyPy and PyPy3 are now supported.
695
+
696
+ The major version change is due to the removal of the ``context`` function.
697
+ Replace it with standard ``with`` statement context management:
698
+
699
+ .. code-block:: python
700
+
701
+ # Don't use context() anymore
702
+ file_obj = StringIO()
703
+ consume(print(x, file=f) for f in context(file_obj) for x in u'123')
704
+
705
+ # Use a with statement instead
706
+ file_obj = StringIO()
707
+ with file_obj as f:
708
+ consume(print(x, file=f) for x in u'123')
709
+
710
+ 2.6.0
711
+ -----
712
+
713
+ * New itertools:
714
+ * ``adjacent`` and ``groupby_transform`` (Thanks to diazona)
715
+ * ``always_iterable`` (Thanks to jaraco)
716
+ * (Removed in 3.0.0) ``context`` (Thanks to yardsale8)
717
+ * ``divide`` (Thanks to mozbhearsum)
718
+ * Improvements to existing itertools:
719
+ * ``ilen`` is now slightly faster. (Thanks to wbolster)
720
+ * ``peekable`` can now prepend items to an iterable. (Thanks to diazona)
721
+
722
+ 2.5.0
723
+ -----
724
+
725
+ * New itertools:
726
+ * ``distribute`` (Thanks to mozbhearsum and coady)
727
+ * ``sort_together`` (Thanks to clintval)
728
+ * ``stagger`` and ``zip_offset`` (Thanks to joshbode)
729
+ * ``padded``
730
+ * Improvements to existing itertools:
731
+ * ``peekable`` now handles negative indexes and slices with negative
732
+ components properly.
733
+ * ``intersperse`` is now slightly faster. (Thanks to pylang)
734
+ * ``windowed`` now accepts a ``step`` keyword argument.
735
+ (Thanks to pylang)
736
+ * Python 3.6 is now supported.
737
+
738
+ 2.4.1
739
+ -----
740
+
741
+ * Move docs 100% to readthedocs.io.
742
+
743
+ 2.4
744
+ -----
745
+
746
+ * New itertools:
747
+ * ``accumulate``, ``all_equal``, ``first_true``, ``partition``, and
748
+ ``tail`` from the itertools documentation.
749
+ * ``bucket`` (Thanks to Rosuav and cvrebert)
750
+ * ``collapse`` (Thanks to abarnet)
751
+ * ``interleave`` and ``interleave_longest`` (Thanks to abarnet)
752
+ * ``side_effect`` (Thanks to nvie)
753
+ * ``sliced`` (Thanks to j4mie and coady)
754
+ * ``split_before`` and ``split_after`` (Thanks to astronouth7303)
755
+ * ``spy`` (Thanks to themiurgo and mathieulongtin)
756
+ * Improvements to existing itertools:
757
+ * ``chunked`` is now simpler and more friendly to garbage collection.
758
+ (Contributed by coady, with thanks to piskvorky)
759
+ * ``collate`` now delegates to ``heapq.merge`` when possible.
760
+ (Thanks to kmike and julianpistorius)
761
+ * ``peekable``-wrapped iterables are now indexable and sliceable.
762
+ Iterating through ``peekable``-wrapped iterables is also faster.
763
+ * ``one`` and ``unique_to_each`` have been simplified.
764
+ (Thanks to coady)
765
+
766
+
767
+ 2.3
768
+ -----
769
+
770
+ * Added ``one`` from ``jaraco.util.itertools``. (Thanks, jaraco!)
771
+ * Added ``distinct_permutations`` and ``unique_to_each``. (Contributed by
772
+ bbayles)
773
+ * Added ``windowed``. (Contributed by bbayles, with thanks to buchanae,
774
+ jaraco, and abarnert)
775
+ * Simplified the implementation of ``chunked``. (Thanks, nvie!)
776
+ * Python 3.5 is now supported. Python 2.6 is no longer supported.
777
+ * Python 3 is now supported directly; there is no 2to3 step.
778
+
779
+ 2.2
780
+ -----
781
+
782
+ * Added ``iterate`` and ``with_iter``. (Thanks, abarnert!)
783
+
784
+ 2.1
785
+ -----
786
+
787
+ * Added (tested!) implementations of the recipes from the itertools
788
+ documentation. (Thanks, Chris Lonnen!)
789
+ * Added ``ilen``. (Thanks for the inspiration, Matt Basta!)
790
+
791
+ 2.0
792
+ -----
793
+
794
+ * ``chunked`` now returns lists rather than tuples. After all, they're
795
+ homogeneous. This slightly backward-incompatible change is the reason for
796
+ the major version bump.
797
+ * Added ``@consumer``.
798
+ * Improved test machinery.
799
+
800
+ 1.1
801
+ -----
802
+
803
+ * Added ``first`` function.
804
+ * Added Python 3 support.
805
+ * Added a default arg to ``peekable.peek()``.
806
+ * Noted how to easily test whether a peekable iterator is exhausted.
807
+ * Rewrote documentation.
808
+
809
+ 1.0
810
+ -----
811
+
812
+ * Initial release, with ``collate``, ``peekable``, and ``chunked``. Could
813
+ really use better docs.
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ """More routines for operating on iterables, beyond itertools"""
2
+
3
+ from .more import * # noqa
4
+ from .recipes import * # noqa
5
+
6
+ __version__ = '10.8.0'
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.pyi ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ from .more import *
2
+ from .recipes import *
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.py ADDED
The diff for this file is too large to render. See raw diff
 
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.pyi ADDED
@@ -0,0 +1,979 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Stubs for more_itertools.more"""
2
+
3
+ from __future__ import annotations
4
+
5
+ import types
6
+
7
+ from collections.abc import (
8
+ Container,
9
+ Hashable,
10
+ Iterable,
11
+ Iterator,
12
+ Mapping,
13
+ Reversible,
14
+ Sequence,
15
+ Sized,
16
+ )
17
+ from contextlib import AbstractContextManager
18
+ from threading import Lock
19
+ from typing import (
20
+ Any,
21
+ Callable,
22
+ Generic,
23
+ Literal,
24
+ TypeVar,
25
+ overload,
26
+ type_check_only,
27
+ )
28
+ from typing_extensions import Protocol
29
+
30
+ __all__ = [
31
+ 'AbortThread',
32
+ 'SequenceView',
33
+ 'adjacent',
34
+ 'all_unique',
35
+ 'always_iterable',
36
+ 'always_reversible',
37
+ 'argmax',
38
+ 'argmin',
39
+ 'bucket',
40
+ 'callback_iter',
41
+ 'chunked',
42
+ 'chunked_even',
43
+ 'circular_shifts',
44
+ 'collapse',
45
+ 'combination_index',
46
+ 'combination_with_replacement_index',
47
+ 'concurrent_tee',
48
+ 'consecutive_groups',
49
+ 'constrained_batches',
50
+ 'consumer',
51
+ 'count_cycle',
52
+ 'countable',
53
+ 'derangements',
54
+ 'dft',
55
+ 'difference',
56
+ 'distinct_combinations',
57
+ 'distinct_permutations',
58
+ 'distribute',
59
+ 'divide',
60
+ 'doublestarmap',
61
+ 'duplicates_everseen',
62
+ 'duplicates_justseen',
63
+ 'classify_unique',
64
+ 'exactly_n',
65
+ 'extract',
66
+ 'filter_except',
67
+ 'filter_map',
68
+ 'first',
69
+ 'gray_product',
70
+ 'groupby_transform',
71
+ 'ichunked',
72
+ 'iequals',
73
+ 'idft',
74
+ 'ilen',
75
+ 'interleave',
76
+ 'interleave_evenly',
77
+ 'interleave_longest',
78
+ 'interleave_randomly',
79
+ 'intersperse',
80
+ 'is_sorted',
81
+ 'islice_extended',
82
+ 'iterate',
83
+ 'iter_suppress',
84
+ 'join_mappings',
85
+ 'last',
86
+ 'locate',
87
+ 'longest_common_prefix',
88
+ 'lstrip',
89
+ 'make_decorator',
90
+ 'map_except',
91
+ 'map_if',
92
+ 'map_reduce',
93
+ 'mark_ends',
94
+ 'minmax',
95
+ 'nth_or_last',
96
+ 'nth_permutation',
97
+ 'nth_prime',
98
+ 'nth_product',
99
+ 'nth_combination_with_replacement',
100
+ 'numeric_range',
101
+ 'one',
102
+ 'only',
103
+ 'outer_product',
104
+ 'padded',
105
+ 'partial_product',
106
+ 'partitions',
107
+ 'peekable',
108
+ 'permutation_index',
109
+ 'powerset_of_sets',
110
+ 'product_index',
111
+ 'raise_',
112
+ 'repeat_each',
113
+ 'repeat_last',
114
+ 'replace',
115
+ 'rlocate',
116
+ 'rstrip',
117
+ 'run_length',
118
+ 'sample',
119
+ 'seekable',
120
+ 'serialize',
121
+ 'set_partitions',
122
+ 'side_effect',
123
+ 'sized_iterator',
124
+ 'sliced',
125
+ 'sort_together',
126
+ 'split_after',
127
+ 'split_at',
128
+ 'split_before',
129
+ 'split_into',
130
+ 'split_when',
131
+ 'spy',
132
+ 'stagger',
133
+ 'strip',
134
+ 'strictly_n',
135
+ 'substrings',
136
+ 'substrings_indexes',
137
+ 'synchronized',
138
+ 'takewhile_inclusive',
139
+ 'time_limited',
140
+ 'unique_in_window',
141
+ 'unique_to_each',
142
+ 'unzip',
143
+ 'value_chain',
144
+ 'windowed',
145
+ 'windowed_complete',
146
+ 'with_iter',
147
+ 'zip_broadcast',
148
+ 'zip_offset',
149
+ ]
150
+
151
+ # Type and type variable definitions
152
+ _T = TypeVar('_T')
153
+ _T1 = TypeVar('_T1')
154
+ _T2 = TypeVar('_T2')
155
+ _T3 = TypeVar('_T3')
156
+ _T4 = TypeVar('_T4')
157
+ _T5 = TypeVar('_T5')
158
+ _U = TypeVar('_U')
159
+ _V = TypeVar('_V')
160
+ _W = TypeVar('_W')
161
+ _T_co = TypeVar('_T_co', covariant=True)
162
+ _GenFn = TypeVar('_GenFn', bound=Callable[..., Iterator[Any]])
163
+ _Raisable = BaseException | type[BaseException]
164
+
165
+ _ClassInfo = type | types.UnionType | tuple[_ClassInfo, ...]
166
+
167
+ @type_check_only
168
+ class _SizedIterable(Protocol[_T_co], Sized, Iterable[_T_co]): ...
169
+
170
+ @type_check_only
171
+ class _SizedReversible(Protocol[_T_co], Sized, Reversible[_T_co]): ...
172
+
173
+ @type_check_only
174
+ class _SupportsSlicing(Protocol[_T_co]):
175
+ def __getitem__(self, __k: slice) -> _T_co: ...
176
+
177
+ def chunked(
178
+ iterable: Iterable[_T], n: int | None, strict: bool = ...
179
+ ) -> Iterator[list[_T]]: ...
180
+ @overload
181
+ def first(iterable: Iterable[_T]) -> _T: ...
182
+ @overload
183
+ def first(iterable: Iterable[_T], default: _U) -> _T | _U: ...
184
+ @overload
185
+ def last(iterable: Iterable[_T]) -> _T: ...
186
+ @overload
187
+ def last(iterable: Iterable[_T], default: _U) -> _T | _U: ...
188
+ @overload
189
+ def nth_or_last(iterable: Iterable[_T], n: int) -> _T: ...
190
+ @overload
191
+ def nth_or_last(iterable: Iterable[_T], n: int, default: _U) -> _T | _U: ...
192
+
193
+ class peekable(Generic[_T], Iterator[_T]):
194
+ def __init__(self, iterable: Iterable[_T]) -> None: ...
195
+ def __iter__(self) -> peekable[_T]: ...
196
+ def __bool__(self) -> bool: ...
197
+ @overload
198
+ def peek(self) -> _T: ...
199
+ @overload
200
+ def peek(self, default: _U) -> _T | _U: ...
201
+ def prepend(self, *items: _T) -> None: ...
202
+ def __next__(self) -> _T: ...
203
+ @overload
204
+ def __getitem__(self, index: int) -> _T: ...
205
+ @overload
206
+ def __getitem__(self, index: slice) -> list[_T]: ...
207
+
208
+ def consumer(func: _GenFn) -> _GenFn: ...
209
+ def ilen(iterable: Iterable[_T]) -> int: ...
210
+ def iterate(func: Callable[[_T], _T], start: _T) -> Iterator[_T]: ...
211
+ def with_iter(
212
+ context_manager: AbstractContextManager[Iterable[_T]],
213
+ ) -> Iterator[_T]: ...
214
+
215
+ class sized_iterator(Generic[_T], Iterator[_T], Sized):
216
+ def __init__(self, iterable: Iterable[_T], length: int) -> None: ...
217
+ def __next__(self) -> _T: ...
218
+ def __iter__(self) -> sized_iterator[_T]: ...
219
+ def __len__(self) -> int: ...
220
+
221
+ def one(
222
+ iterable: Iterable[_T],
223
+ too_short: _Raisable | None = ...,
224
+ too_long: _Raisable | None = ...,
225
+ ) -> _T: ...
226
+ def raise_(exception: _Raisable, *args: Any) -> None: ...
227
+ def strictly_n(
228
+ iterable: Iterable[_T],
229
+ n: int,
230
+ too_short: _GenFn | None = ...,
231
+ too_long: _GenFn | None = ...,
232
+ ) -> list[_T]: ...
233
+ def distinct_permutations(
234
+ iterable: Iterable[_T], r: int | None = ...
235
+ ) -> Iterator[tuple[_T, ...]]: ...
236
+ def derangements(
237
+ iterable: Iterable[_T], r: int | None = None
238
+ ) -> Iterator[tuple[_T, ...]]: ...
239
+ def intersperse(
240
+ e: _U, iterable: Iterable[_T], n: int = ...
241
+ ) -> Iterator[_T | _U]: ...
242
+ def unique_to_each(*iterables: Iterable[_T]) -> list[list[_T]]: ...
243
+ @overload
244
+ def windowed(
245
+ seq: Iterable[_T], n: int, *, step: int = ...
246
+ ) -> Iterator[tuple[_T | None, ...]]: ...
247
+ @overload
248
+ def windowed(
249
+ seq: Iterable[_T], n: int, fillvalue: _U, step: int = ...
250
+ ) -> Iterator[tuple[_T | _U, ...]]: ...
251
+ def substrings(iterable: Iterable[_T]) -> Iterator[tuple[_T, ...]]: ...
252
+ def substrings_indexes(
253
+ seq: Sequence[_T], reverse: bool = ...
254
+ ) -> Iterator[tuple[Sequence[_T], int, int]]: ...
255
+
256
+ class bucket(Generic[_T, _U], Container[_U]):
257
+ def __init__(
258
+ self,
259
+ iterable: Iterable[_T],
260
+ key: Callable[[_T], _U],
261
+ validator: Callable[[_U], object] | None = ...,
262
+ ) -> None: ...
263
+ def __contains__(self, value: object) -> bool: ...
264
+ def __iter__(self) -> Iterator[_U]: ...
265
+ def __getitem__(self, value: object) -> Iterator[_T]: ...
266
+
267
+ def spy(
268
+ iterable: Iterable[_T], n: int = ...
269
+ ) -> tuple[list[_T], Iterator[_T]]: ...
270
+ def interleave(*iterables: Iterable[_T]) -> Iterator[_T]: ...
271
+ def interleave_longest(*iterables: Iterable[_T]) -> Iterator[_T]: ...
272
+ def interleave_evenly(
273
+ iterables: list[Iterable[_T]], lengths: list[int] | None = ...
274
+ ) -> Iterator[_T]: ...
275
+ def interleave_randomly(*iterables: Iterable[_T]) -> Iterable[_T]: ...
276
+ def collapse(
277
+ iterable: Iterable[Any],
278
+ base_type: _ClassInfo | None = ...,
279
+ levels: int | None = ...,
280
+ ) -> Iterator[Any]: ...
281
+ @overload
282
+ def side_effect(
283
+ func: Callable[[_T], object],
284
+ iterable: Iterable[_T],
285
+ chunk_size: None = ...,
286
+ before: Callable[[], object] | None = ...,
287
+ after: Callable[[], object] | None = ...,
288
+ ) -> Iterator[_T]: ...
289
+ @overload
290
+ def side_effect(
291
+ func: Callable[[list[_T]], object],
292
+ iterable: Iterable[_T],
293
+ chunk_size: int,
294
+ before: Callable[[], object] | None = ...,
295
+ after: Callable[[], object] | None = ...,
296
+ ) -> Iterator[_T]: ...
297
+ def sliced(
298
+ seq: _SupportsSlicing[_T], n: int, strict: bool = ...
299
+ ) -> Iterator[_T]: ...
300
+ def split_at(
301
+ iterable: Iterable[_T],
302
+ pred: Callable[[_T], object],
303
+ maxsplit: int = ...,
304
+ keep_separator: bool = ...,
305
+ ) -> Iterator[list[_T]]: ...
306
+ def split_before(
307
+ iterable: Iterable[_T], pred: Callable[[_T], object], maxsplit: int = ...
308
+ ) -> Iterator[list[_T]]: ...
309
+ def split_after(
310
+ iterable: Iterable[_T], pred: Callable[[_T], object], maxsplit: int = ...
311
+ ) -> Iterator[list[_T]]: ...
312
+ def split_when(
313
+ iterable: Iterable[_T],
314
+ pred: Callable[[_T, _T], object],
315
+ maxsplit: int = ...,
316
+ ) -> Iterator[list[_T]]: ...
317
+ def split_into(
318
+ iterable: Iterable[_T], sizes: Iterable[int | None]
319
+ ) -> Iterator[list[_T]]: ...
320
+ @overload
321
+ def padded(
322
+ iterable: Iterable[_T],
323
+ *,
324
+ n: int | None = ...,
325
+ next_multiple: bool = ...,
326
+ ) -> Iterator[_T | None]: ...
327
+ @overload
328
+ def padded(
329
+ iterable: Iterable[_T],
330
+ fillvalue: _U,
331
+ n: int | None = ...,
332
+ next_multiple: bool = ...,
333
+ ) -> Iterator[_T | _U]: ...
334
+ @overload
335
+ def repeat_last(iterable: Iterable[_T]) -> Iterator[_T]: ...
336
+ @overload
337
+ def repeat_last(iterable: Iterable[_T], default: _U) -> Iterator[_T | _U]: ...
338
+ def distribute(n: int, iterable: Iterable[_T]) -> list[Iterator[_T]]: ...
339
+ @overload
340
+ def stagger(
341
+ iterable: Iterable[_T],
342
+ offsets: _SizedIterable[int] = ...,
343
+ longest: Literal[False] = ...,
344
+ ) -> Iterator[tuple[_T, ...]]: ...
345
+ @overload
346
+ def stagger(
347
+ iterable: Iterable[_T],
348
+ offsets: _SizedIterable[int] = ...,
349
+ longest: Literal[False] = ...,
350
+ fillvalue: object = ...,
351
+ ) -> Iterator[tuple[_T, ...]]: ...
352
+ @overload
353
+ def stagger(
354
+ iterable: Iterable[_T],
355
+ offsets: _SizedIterable[int] = ...,
356
+ longest: Literal[True] = ...,
357
+ ) -> Iterator[tuple[_T | None, ...]]: ...
358
+ @overload
359
+ def stagger(
360
+ iterable: Iterable[_T],
361
+ offsets: _SizedIterable[int] = ...,
362
+ longest: Literal[True] = ...,
363
+ fillvalue: _U = ...,
364
+ ) -> Iterator[tuple[_T | _U, ...]]: ...
365
+
366
+ # zip_offset
367
+ @overload
368
+ def zip_offset(
369
+ __iter1: Iterable[_T1],
370
+ *,
371
+ offsets: _SizedIterable[int],
372
+ longest: bool = ...,
373
+ fillvalue: None = None,
374
+ ) -> Iterator[tuple[_T1 | None]]: ...
375
+ @overload
376
+ def zip_offset(
377
+ __iter1: Iterable[_T1],
378
+ __iter2: Iterable[_T2],
379
+ *,
380
+ offsets: _SizedIterable[int],
381
+ longest: bool = ...,
382
+ fillvalue: None = None,
383
+ ) -> Iterator[tuple[_T1 | None, _T2 | None]]: ...
384
+ @overload
385
+ def zip_offset(
386
+ __iter1: Iterable[_T],
387
+ __iter2: Iterable[_T],
388
+ __iter3: Iterable[_T],
389
+ *iterables: Iterable[_T],
390
+ offsets: _SizedIterable[int],
391
+ longest: bool = ...,
392
+ fillvalue: None = None,
393
+ ) -> Iterator[tuple[_T | None, ...]]: ...
394
+ @overload
395
+ def zip_offset(
396
+ __iter1: Iterable[_T1],
397
+ *,
398
+ offsets: _SizedIterable[int],
399
+ longest: bool = ...,
400
+ fillvalue: _U,
401
+ ) -> Iterator[tuple[_T1 | _U]]: ...
402
+ @overload
403
+ def zip_offset(
404
+ __iter1: Iterable[_T1],
405
+ __iter2: Iterable[_T2],
406
+ *,
407
+ offsets: _SizedIterable[int],
408
+ longest: bool = ...,
409
+ fillvalue: _U,
410
+ ) -> Iterator[tuple[_T1 | _U, _T2 | _U]]: ...
411
+ @overload
412
+ def zip_offset(
413
+ __iter1: Iterable[_T],
414
+ __iter2: Iterable[_T],
415
+ __iter3: Iterable[_T],
416
+ *iterables: Iterable[_T],
417
+ offsets: _SizedIterable[int],
418
+ longest: bool = ...,
419
+ fillvalue: _U,
420
+ ) -> Iterator[tuple[_T | _U, ...]]: ...
421
+ def sort_together(
422
+ iterables: Iterable[Iterable[_T]],
423
+ key_list: Iterable[int] = ...,
424
+ key: Callable[..., Any] | None = ...,
425
+ reverse: bool = ...,
426
+ strict: bool = ...,
427
+ ) -> list[tuple[_T, ...]]: ...
428
+ def unzip(iterable: Iterable[Sequence[_T]]) -> tuple[Iterator[_T], ...]: ...
429
+ def divide(n: int, iterable: Iterable[_T]) -> list[Iterator[_T]]: ...
430
+ @overload
431
+ def always_iterable(
432
+ obj: None, base_type: Any = ...
433
+ ) -> Iterator[tuple[()]]: ...
434
+ @overload
435
+ def always_iterable(obj: bytes, base_type: None) -> Iterator[int]: ...
436
+ @overload
437
+ def always_iterable(obj: Iterable[_T], base_type: None) -> Iterator[_T]: ...
438
+ @overload
439
+ def always_iterable(obj: _T, base_type: None) -> Iterator[_T]: ...
440
+ @overload
441
+ def always_iterable(
442
+ obj: bytes, base_type: type[bytes] | tuple[type[str], type[bytes]] = ...
443
+ ) -> Iterator[bytes]: ...
444
+ @overload
445
+ def always_iterable(
446
+ obj: Iterable[_T],
447
+ base_type: type[bytes] | type[str] | tuple[type[str], type[bytes]] = ...,
448
+ ) -> Iterator[_T]: ...
449
+ @overload
450
+ def always_iterable(
451
+ obj: _T, base_type: tuple[type[str], type[bytes]] = ...
452
+ ) -> Iterator[_T]: ...
453
+ @overload
454
+ def always_iterable(
455
+ obj: object,
456
+ base_type: _ClassInfo | None = ...,
457
+ ) -> Iterator[Any]: ...
458
+ def adjacent(
459
+ predicate: Callable[[_T], bool],
460
+ iterable: Iterable[_T],
461
+ distance: int = ...,
462
+ ) -> Iterator[tuple[bool, _T]]: ...
463
+ @overload
464
+ def groupby_transform(
465
+ iterable: Iterable[_T],
466
+ keyfunc: None = None,
467
+ valuefunc: None = None,
468
+ reducefunc: None = None,
469
+ ) -> Iterator[tuple[_T, Iterator[_T]]]: ...
470
+ @overload
471
+ def groupby_transform(
472
+ iterable: Iterable[_T],
473
+ keyfunc: Callable[[_T], _U],
474
+ valuefunc: None,
475
+ reducefunc: None,
476
+ ) -> Iterator[tuple[_U, Iterator[_T]]]: ...
477
+ @overload
478
+ def groupby_transform(
479
+ iterable: Iterable[_T],
480
+ keyfunc: None,
481
+ valuefunc: Callable[[_T], _V],
482
+ reducefunc: None,
483
+ ) -> Iterator[tuple[_T, Iterator[_V]]]: ...
484
+ @overload
485
+ def groupby_transform(
486
+ iterable: Iterable[_T],
487
+ keyfunc: Callable[[_T], _U],
488
+ valuefunc: Callable[[_T], _V],
489
+ reducefunc: None,
490
+ ) -> Iterator[tuple[_U, Iterator[_V]]]: ...
491
+ @overload
492
+ def groupby_transform(
493
+ iterable: Iterable[_T],
494
+ keyfunc: None,
495
+ valuefunc: None,
496
+ reducefunc: Callable[[Iterator[_T]], _W],
497
+ ) -> Iterator[tuple[_T, _W]]: ...
498
+ @overload
499
+ def groupby_transform(
500
+ iterable: Iterable[_T],
501
+ keyfunc: Callable[[_T], _U],
502
+ valuefunc: None,
503
+ reducefunc: Callable[[Iterator[_T]], _W],
504
+ ) -> Iterator[tuple[_U, _W]]: ...
505
+ @overload
506
+ def groupby_transform(
507
+ iterable: Iterable[_T],
508
+ keyfunc: None,
509
+ valuefunc: Callable[[_T], _V],
510
+ reducefunc: Callable[[Iterator[_V]], _W],
511
+ ) -> Iterator[tuple[_T, _W]]: ...
512
+ @overload
513
+ def groupby_transform(
514
+ iterable: Iterable[_T],
515
+ keyfunc: Callable[[_T], _U],
516
+ valuefunc: Callable[[_T], _V],
517
+ reducefunc: Callable[[Iterator[_V]], _W],
518
+ ) -> Iterator[tuple[_U, _W]]: ...
519
+
520
+ class numeric_range(Generic[_T, _U], Sequence[_T], Hashable, Reversible[_T]):
521
+ @overload
522
+ def __init__(self, __stop: _T) -> None: ...
523
+ @overload
524
+ def __init__(self, __start: _T, __stop: _T) -> None: ...
525
+ @overload
526
+ def __init__(self, __start: _T, __stop: _T, __step: _U) -> None: ...
527
+ def __bool__(self) -> bool: ...
528
+ def __contains__(self, elem: object) -> bool: ...
529
+ def __eq__(self, other: object) -> bool: ...
530
+ @overload
531
+ def __getitem__(self, key: int) -> _T: ...
532
+ @overload
533
+ def __getitem__(self, key: slice) -> numeric_range[_T, _U]: ...
534
+ def __hash__(self) -> int: ...
535
+ def __iter__(self) -> Iterator[_T]: ...
536
+ def __len__(self) -> int: ...
537
+ def __reduce__(
538
+ self,
539
+ ) -> tuple[type[numeric_range[_T, _U]], tuple[_T, _T, _U]]: ...
540
+ def __repr__(self) -> str: ...
541
+ def __reversed__(self) -> Iterator[_T]: ...
542
+ def count(self, value: _T) -> int: ...
543
+ def index(self, value: _T) -> int: ... # type: ignore
544
+
545
+ def count_cycle(
546
+ iterable: Iterable[_T], n: int | None = ...
547
+ ) -> Iterable[tuple[int, _T]]: ...
548
+ def mark_ends(
549
+ iterable: Iterable[_T],
550
+ ) -> Iterable[tuple[bool, bool, _T]]: ...
551
+ def locate(
552
+ iterable: Iterable[_T],
553
+ pred: Callable[..., Any] = ...,
554
+ window_size: int | None = ...,
555
+ ) -> Iterator[int]: ...
556
+ def lstrip(
557
+ iterable: Iterable[_T], pred: Callable[[_T], object]
558
+ ) -> Iterator[_T]: ...
559
+ def rstrip(
560
+ iterable: Iterable[_T], pred: Callable[[_T], object]
561
+ ) -> Iterator[_T]: ...
562
+ def strip(
563
+ iterable: Iterable[_T], pred: Callable[[_T], object]
564
+ ) -> Iterator[_T]: ...
565
+
566
+ class islice_extended(Generic[_T], Iterator[_T]):
567
+ def __init__(self, iterable: Iterable[_T], *args: int | None) -> None: ...
568
+ def __iter__(self) -> islice_extended[_T]: ...
569
+ def __next__(self) -> _T: ...
570
+ def __getitem__(self, index: slice) -> islice_extended[_T]: ...
571
+
572
+ def always_reversible(iterable: Iterable[_T]) -> Iterator[_T]: ...
573
+ def consecutive_groups(
574
+ iterable: Iterable[_T], ordering: None | Callable[[_T], int] = ...
575
+ ) -> Iterator[Iterator[_T]]: ...
576
+ @overload
577
+ def difference(
578
+ iterable: Iterable[_T],
579
+ func: Callable[[_T, _T], _U] = ...,
580
+ *,
581
+ initial: None = ...,
582
+ ) -> Iterator[_T | _U]: ...
583
+ @overload
584
+ def difference(
585
+ iterable: Iterable[_T], func: Callable[[_T, _T], _U] = ..., *, initial: _U
586
+ ) -> Iterator[_U]: ...
587
+
588
+ class SequenceView(Generic[_T], Sequence[_T]):
589
+ def __init__(self, target: Sequence[_T]) -> None: ...
590
+ @overload
591
+ def __getitem__(self, index: int) -> _T: ...
592
+ @overload
593
+ def __getitem__(self, index: slice) -> Sequence[_T]: ...
594
+ def __len__(self) -> int: ...
595
+
596
+ class seekable(Generic[_T], Iterator[_T]):
597
+ def __init__(
598
+ self, iterable: Iterable[_T], maxlen: int | None = ...
599
+ ) -> None: ...
600
+ def __iter__(self) -> seekable[_T]: ...
601
+ def __next__(self) -> _T: ...
602
+ def __bool__(self) -> bool: ...
603
+ @overload
604
+ def peek(self) -> _T: ...
605
+ @overload
606
+ def peek(self, default: _U) -> _T | _U: ...
607
+ def elements(self) -> SequenceView[_T]: ...
608
+ def seek(self, index: int) -> None: ...
609
+ def relative_seek(self, count: int) -> None: ...
610
+
611
+ class run_length:
612
+ @staticmethod
613
+ def encode(iterable: Iterable[_T]) -> Iterator[tuple[_T, int]]: ...
614
+ @staticmethod
615
+ def decode(iterable: Iterable[tuple[_T, int]]) -> Iterator[_T]: ...
616
+
617
+ def exactly_n(
618
+ iterable: Iterable[_T], n: int, predicate: Callable[[_T], object] = ...
619
+ ) -> bool: ...
620
+ def circular_shifts(
621
+ iterable: Iterable[_T], steps: int = 1
622
+ ) -> list[tuple[_T, ...]]: ...
623
+ def make_decorator(
624
+ wrapping_func: Callable[..., _U], result_index: int = ...
625
+ ) -> Callable[..., Callable[[Callable[..., Any]], Callable[..., _U]]]: ...
626
+ @overload
627
+ def map_reduce(
628
+ iterable: Iterable[_T],
629
+ keyfunc: Callable[[_T], _U],
630
+ valuefunc: None = ...,
631
+ reducefunc: None = ...,
632
+ ) -> dict[_U, list[_T]]: ...
633
+ @overload
634
+ def map_reduce(
635
+ iterable: Iterable[_T],
636
+ keyfunc: Callable[[_T], _U],
637
+ valuefunc: Callable[[_T], _V],
638
+ reducefunc: None = ...,
639
+ ) -> dict[_U, list[_V]]: ...
640
+ @overload
641
+ def map_reduce(
642
+ iterable: Iterable[_T],
643
+ keyfunc: Callable[[_T], _U],
644
+ valuefunc: None = ...,
645
+ reducefunc: Callable[[list[_T]], _W] = ...,
646
+ ) -> dict[_U, _W]: ...
647
+ @overload
648
+ def map_reduce(
649
+ iterable: Iterable[_T],
650
+ keyfunc: Callable[[_T], _U],
651
+ valuefunc: Callable[[_T], _V],
652
+ reducefunc: Callable[[list[_V]], _W],
653
+ ) -> dict[_U, _W]: ...
654
+ def rlocate(
655
+ iterable: Iterable[_T],
656
+ pred: Callable[..., object] = ...,
657
+ window_size: int | None = ...,
658
+ ) -> Iterator[int]: ...
659
+ def replace(
660
+ iterable: Iterable[_T],
661
+ pred: Callable[..., object],
662
+ substitutes: Iterable[_U],
663
+ count: int | None = ...,
664
+ window_size: int = ...,
665
+ ) -> Iterator[_T | _U]: ...
666
+ def partitions(iterable: Iterable[_T]) -> Iterator[list[list[_T]]]: ...
667
+ def set_partitions(
668
+ iterable: Iterable[_T],
669
+ k: int | None = ...,
670
+ min_size: int | None = ...,
671
+ max_size: int | None = ...,
672
+ ) -> Iterator[list[list[_T]]]: ...
673
+
674
+ class time_limited(Generic[_T], Iterator[_T]):
675
+ def __init__(
676
+ self, limit_seconds: float, iterable: Iterable[_T]
677
+ ) -> None: ...
678
+ def __iter__(self) -> islice_extended[_T]: ...
679
+ def __next__(self) -> _T: ...
680
+
681
+ @overload
682
+ def only(
683
+ iterable: Iterable[_T], *, too_long: _Raisable | None = ...
684
+ ) -> _T | None: ...
685
+ @overload
686
+ def only(
687
+ iterable: Iterable[_T], default: _U, too_long: _Raisable | None = ...
688
+ ) -> _T | _U: ...
689
+ def ichunked(iterable: Iterable[_T], n: int) -> Iterator[Iterator[_T]]: ...
690
+ def distinct_combinations(
691
+ iterable: Iterable[_T], r: int
692
+ ) -> Iterator[tuple[_T, ...]]: ...
693
+ def filter_except(
694
+ validator: Callable[[Any], object],
695
+ iterable: Iterable[_T],
696
+ *exceptions: type[BaseException],
697
+ ) -> Iterator[_T]: ...
698
+ def map_except(
699
+ function: Callable[[Any], _U],
700
+ iterable: Iterable[_T],
701
+ *exceptions: type[BaseException],
702
+ ) -> Iterator[_U]: ...
703
+ def map_if(
704
+ iterable: Iterable[Any],
705
+ pred: Callable[[Any], bool],
706
+ func: Callable[[Any], Any],
707
+ func_else: Callable[[Any], Any] | None = ...,
708
+ ) -> Iterator[Any]: ...
709
+ def _sample_unweighted(
710
+ iterator: Iterator[_T], k: int, strict: bool
711
+ ) -> list[_T]: ...
712
+ def _sample_counted(
713
+ population: Iterator[_T], k: int, counts: Iterable[int], strict: bool
714
+ ) -> list[_T]: ...
715
+ def _sample_weighted(
716
+ iterator: Iterator[_T], k: int, weights: Iterator[float], strict: bool
717
+ ) -> list[_T]: ...
718
+ def sample(
719
+ iterable: Iterable[_T],
720
+ k: int,
721
+ weights: Iterable[float] | None = ...,
722
+ *,
723
+ counts: Iterable[int] | None = ...,
724
+ strict: bool = False,
725
+ ) -> list[_T]: ...
726
+ def is_sorted(
727
+ iterable: Iterable[_T],
728
+ key: Callable[[_T], _U] | None = ...,
729
+ reverse: bool = False,
730
+ strict: bool = False,
731
+ ) -> bool: ...
732
+
733
+ class AbortThread(BaseException):
734
+ pass
735
+
736
+ class callback_iter(Generic[_T], Iterator[_T]):
737
+ def __init__(
738
+ self,
739
+ func: Callable[..., Any],
740
+ callback_kwd: str = ...,
741
+ wait_seconds: float = ...,
742
+ ) -> None: ...
743
+ def __enter__(self) -> callback_iter[_T]: ...
744
+ def __exit__(
745
+ self,
746
+ exc_type: type[BaseException] | None,
747
+ exc_value: BaseException | None,
748
+ traceback: types.TracebackType | None,
749
+ ) -> bool | None: ...
750
+ def __iter__(self) -> callback_iter[_T]: ...
751
+ def __next__(self) -> _T: ...
752
+ def _reader(self) -> Iterator[_T]: ...
753
+ @property
754
+ def done(self) -> bool: ...
755
+ @property
756
+ def result(self) -> Any: ...
757
+
758
+ def windowed_complete(
759
+ iterable: Iterable[_T], n: int
760
+ ) -> Iterator[tuple[tuple[_T, ...], tuple[_T, ...], tuple[_T, ...]]]: ...
761
+ def all_unique(
762
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
763
+ ) -> bool: ...
764
+ def nth_product(
765
+ index: int, *iterables: Iterable[_T], repeat: int = ...
766
+ ) -> tuple[_T, ...]: ...
767
+ def nth_combination_with_replacement(
768
+ iterable: Iterable[_T], r: int, index: int
769
+ ) -> tuple[_T, ...]: ...
770
+ def nth_permutation(
771
+ iterable: Iterable[_T], r: int, index: int
772
+ ) -> tuple[_T, ...]: ...
773
+ def value_chain(*args: _T | Iterable[_T]) -> Iterable[_T]: ...
774
+ def product_index(
775
+ element: Iterable[_T], *iterables: Iterable[_T], repeat: int = ...
776
+ ) -> int: ...
777
+ def combination_index(
778
+ element: Iterable[_T], iterable: Iterable[_T]
779
+ ) -> int: ...
780
+ def combination_with_replacement_index(
781
+ element: Iterable[_T], iterable: Iterable[_T]
782
+ ) -> int: ...
783
+ def permutation_index(
784
+ element: Iterable[_T], iterable: Iterable[_T]
785
+ ) -> int: ...
786
+ def repeat_each(iterable: Iterable[_T], n: int = ...) -> Iterator[_T]: ...
787
+
788
+ class countable(Generic[_T], Iterator[_T]):
789
+ def __init__(self, iterable: Iterable[_T]) -> None: ...
790
+ def __iter__(self) -> countable[_T]: ...
791
+ def __next__(self) -> _T: ...
792
+ items_seen: int
793
+
794
+ def chunked_even(iterable: Iterable[_T], n: int) -> Iterator[list[_T]]: ...
795
+ @overload
796
+ def zip_broadcast(
797
+ __obj1: _T | Iterable[_T],
798
+ *,
799
+ scalar_types: _ClassInfo | None = ...,
800
+ strict: bool = ...,
801
+ ) -> Iterable[tuple[_T, ...]]: ...
802
+ @overload
803
+ def zip_broadcast(
804
+ __obj1: _T | Iterable[_T],
805
+ __obj2: _T | Iterable[_T],
806
+ *,
807
+ scalar_types: _ClassInfo | None = ...,
808
+ strict: bool = ...,
809
+ ) -> Iterable[tuple[_T, ...]]: ...
810
+ @overload
811
+ def zip_broadcast(
812
+ __obj1: _T | Iterable[_T],
813
+ __obj2: _T | Iterable[_T],
814
+ __obj3: _T | Iterable[_T],
815
+ *,
816
+ scalar_types: _ClassInfo | None = ...,
817
+ strict: bool = ...,
818
+ ) -> Iterable[tuple[_T, ...]]: ...
819
+ @overload
820
+ def zip_broadcast(
821
+ __obj1: _T | Iterable[_T],
822
+ __obj2: _T | Iterable[_T],
823
+ __obj3: _T | Iterable[_T],
824
+ __obj4: _T | Iterable[_T],
825
+ *,
826
+ scalar_types: _ClassInfo | None = ...,
827
+ strict: bool = ...,
828
+ ) -> Iterable[tuple[_T, ...]]: ...
829
+ @overload
830
+ def zip_broadcast(
831
+ __obj1: _T | Iterable[_T],
832
+ __obj2: _T | Iterable[_T],
833
+ __obj3: _T | Iterable[_T],
834
+ __obj4: _T | Iterable[_T],
835
+ __obj5: _T | Iterable[_T],
836
+ *,
837
+ scalar_types: _ClassInfo | None = ...,
838
+ strict: bool = ...,
839
+ ) -> Iterable[tuple[_T, ...]]: ...
840
+ @overload
841
+ def zip_broadcast(
842
+ __obj1: _T | Iterable[_T],
843
+ __obj2: _T | Iterable[_T],
844
+ __obj3: _T | Iterable[_T],
845
+ __obj4: _T | Iterable[_T],
846
+ __obj5: _T | Iterable[_T],
847
+ __obj6: _T | Iterable[_T],
848
+ *objects: _T | Iterable[_T],
849
+ scalar_types: _ClassInfo | None = ...,
850
+ strict: bool = ...,
851
+ ) -> Iterable[tuple[_T, ...]]: ...
852
+ def unique_in_window(
853
+ iterable: Iterable[_T], n: int, key: Callable[[_T], _U] | None = ...
854
+ ) -> Iterator[_T]: ...
855
+ def duplicates_everseen(
856
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
857
+ ) -> Iterator[_T]: ...
858
+ def duplicates_justseen(
859
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
860
+ ) -> Iterator[_T]: ...
861
+ def classify_unique(
862
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
863
+ ) -> Iterator[tuple[_T, bool, bool]]: ...
864
+
865
+ class _SupportsLessThan(Protocol):
866
+ def __lt__(self, __other: Any) -> bool: ...
867
+
868
+ _SupportsLessThanT = TypeVar("_SupportsLessThanT", bound=_SupportsLessThan)
869
+
870
+ @overload
871
+ def minmax(
872
+ iterable_or_value: Iterable[_SupportsLessThanT], *, key: None = None
873
+ ) -> tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
874
+ @overload
875
+ def minmax(
876
+ iterable_or_value: Iterable[_T], *, key: Callable[[_T], _SupportsLessThan]
877
+ ) -> tuple[_T, _T]: ...
878
+ @overload
879
+ def minmax(
880
+ iterable_or_value: Iterable[_SupportsLessThanT],
881
+ *,
882
+ key: None = None,
883
+ default: _U,
884
+ ) -> _U | tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
885
+ @overload
886
+ def minmax(
887
+ iterable_or_value: Iterable[_T],
888
+ *,
889
+ key: Callable[[_T], _SupportsLessThan],
890
+ default: _U,
891
+ ) -> _U | tuple[_T, _T]: ...
892
+ @overload
893
+ def minmax(
894
+ iterable_or_value: _SupportsLessThanT,
895
+ __other: _SupportsLessThanT,
896
+ *others: _SupportsLessThanT,
897
+ ) -> tuple[_SupportsLessThanT, _SupportsLessThanT]: ...
898
+ @overload
899
+ def minmax(
900
+ iterable_or_value: _T,
901
+ __other: _T,
902
+ *others: _T,
903
+ key: Callable[[_T], _SupportsLessThan],
904
+ ) -> tuple[_T, _T]: ...
905
+ def longest_common_prefix(
906
+ iterables: Iterable[Iterable[_T]],
907
+ ) -> Iterator[_T]: ...
908
+ def iequals(*iterables: Iterable[Any]) -> bool: ...
909
+ def constrained_batches(
910
+ iterable: Iterable[_T],
911
+ max_size: int,
912
+ max_count: int | None = ...,
913
+ get_len: Callable[[_T], object] = ...,
914
+ strict: bool = ...,
915
+ ) -> Iterator[tuple[_T]]: ...
916
+ def gray_product(
917
+ *iterables: Iterable[_T], repeat: int = ...
918
+ ) -> Iterator[tuple[_T, ...]]: ...
919
+ def partial_product(
920
+ *iterables: Iterable[_T], repeat: int = ...
921
+ ) -> Iterator[tuple[_T, ...]]: ...
922
+ def takewhile_inclusive(
923
+ predicate: Callable[[_T], bool], iterable: Iterable[_T]
924
+ ) -> Iterator[_T]: ...
925
+ def outer_product(
926
+ func: Callable[[_T, _U], _V],
927
+ xs: Iterable[_T],
928
+ ys: Iterable[_U],
929
+ *args: Any,
930
+ **kwargs: Any,
931
+ ) -> Iterator[tuple[_V, ...]]: ...
932
+ def iter_suppress(
933
+ iterable: Iterable[_T],
934
+ *exceptions: type[BaseException],
935
+ ) -> Iterator[_T]: ...
936
+ def filter_map(
937
+ func: Callable[[_T], _V | None],
938
+ iterable: Iterable[_T],
939
+ ) -> Iterator[_V]: ...
940
+ def powerset_of_sets(
941
+ iterable: Iterable[_T], *, baseset: type = ...
942
+ ) -> Iterator[set[_T]] | Iterator[frozenset[_T]]: ...
943
+ def join_mappings(
944
+ **field_to_map: Mapping[_T, _V],
945
+ ) -> dict[_T, dict[str, _V]]: ...
946
+ def doublestarmap(
947
+ func: Callable[..., _T],
948
+ iterable: Iterable[Mapping[str, Any]],
949
+ ) -> Iterator[_T]: ...
950
+ def dft(xarr: Sequence[complex]) -> Iterator[complex]: ...
951
+ def idft(Xarr: Sequence[complex]) -> Iterator[complex]: ...
952
+ def _nth_prime_ub(n: int) -> float: ...
953
+ def nth_prime(n: int, *, approximate: bool = ...) -> int: ...
954
+ def argmin(
955
+ iterable: Iterable[_T], *, key: Callable[[_T], _U] | None = ...
956
+ ) -> int: ...
957
+ def argmax(
958
+ iterable: Iterable[_T], *, key: Callable[[_T], _U] | None = ...
959
+ ) -> int: ...
960
+ def extract(
961
+ iterable: Iterable[_T],
962
+ indices: Iterable[int],
963
+ *,
964
+ monotonic: bool = ...,
965
+ ) -> Iterator[_T]: ...
966
+
967
+ class serialize(Generic[_T], Iterator[_T]):
968
+ iterator: Iterator[_T]
969
+ lock: Lock
970
+ def __init__(self, iterable: Iterable[_T]) -> None: ...
971
+ def __iter__(self) -> serialize[_T]: ...
972
+ def __next__(self) -> _T: ...
973
+
974
+ def concurrent_tee(
975
+ iterable: Iterable[_T], n: int = ...
976
+ ) -> tuple[Iterator[_T]]: ...
977
+ def synchronized(
978
+ func: Callable[..., Iterator[_T]],
979
+ ) -> Callable[..., Iterator[_T]]: ...
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/py.typed ADDED
File without changes
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.py ADDED
@@ -0,0 +1,1430 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Imported from the recipes section of the itertools documentation.
2
+
3
+ All functions taken from the recipes section of the itertools library docs
4
+ [1]_.
5
+ Some backward-compatible usability improvements have been made.
6
+
7
+ .. [1] http://docs.python.org/library/itertools.html#recipes
8
+
9
+ """
10
+
11
+ import random
12
+
13
+ from bisect import bisect_left, insort
14
+ from collections import deque
15
+ from contextlib import suppress
16
+ from functools import lru_cache, reduce
17
+ from heapq import heappush, heappushpop
18
+ from itertools import (
19
+ accumulate,
20
+ chain,
21
+ combinations,
22
+ compress,
23
+ count,
24
+ cycle,
25
+ groupby,
26
+ islice,
27
+ pairwise,
28
+ product,
29
+ repeat,
30
+ starmap,
31
+ takewhile,
32
+ tee,
33
+ zip_longest,
34
+ )
35
+ from math import prod, comb, isqrt, gcd
36
+ from operator import mul, getitem, index, is_, itemgetter, not_, truediv
37
+ from random import randrange, sample, choice, shuffle
38
+ from sys import hexversion
39
+
40
+ __all__ = [
41
+ 'all_equal',
42
+ 'batched',
43
+ 'before_and_after',
44
+ 'consume',
45
+ 'convolve',
46
+ 'dotproduct',
47
+ 'first_true',
48
+ 'factor',
49
+ 'flatten',
50
+ 'grouper',
51
+ 'is_prime',
52
+ 'iter_except',
53
+ 'iter_index',
54
+ 'loops',
55
+ 'matmul',
56
+ 'multinomial',
57
+ 'ncycles',
58
+ 'nth',
59
+ 'nth_combination',
60
+ 'padnone',
61
+ 'pad_none',
62
+ 'partition',
63
+ 'polynomial_eval',
64
+ 'polynomial_from_roots',
65
+ 'polynomial_derivative',
66
+ 'powerset',
67
+ 'prepend',
68
+ 'quantify',
69
+ 'reshape',
70
+ 'random_combination_with_replacement',
71
+ 'random_combination',
72
+ 'random_derangement',
73
+ 'random_permutation',
74
+ 'random_product',
75
+ 'repeatfunc',
76
+ 'roundrobin',
77
+ 'running_mean',
78
+ 'running_median',
79
+ 'sieve',
80
+ 'sliding_window',
81
+ 'subslices',
82
+ 'sum_of_squares',
83
+ 'tabulate',
84
+ 'tail',
85
+ 'take',
86
+ 'totient',
87
+ 'transpose',
88
+ 'triplewise',
89
+ 'unique',
90
+ 'unique_everseen',
91
+ 'unique_justseen',
92
+ ]
93
+
94
+ _marker = object()
95
+
96
+
97
+ # heapq max-heap functions are available for Python 3.14+
98
+ try:
99
+ from heapq import heappush_max, heappushpop_max
100
+ except ImportError: # pragma: no cover
101
+ _max_heap_available = False
102
+ else: # pragma: no cover
103
+ _max_heap_available = True
104
+
105
+
106
+ def take(n, iterable):
107
+ """Return first *n* items of the *iterable* as a list.
108
+
109
+ >>> take(3, range(10))
110
+ [0, 1, 2]
111
+
112
+ If there are fewer than *n* items in the iterable, all of them are
113
+ returned.
114
+
115
+ >>> take(10, range(3))
116
+ [0, 1, 2]
117
+
118
+ """
119
+ return list(islice(iterable, n))
120
+
121
+
122
+ def tabulate(function, start=0):
123
+ """Return an iterator over the results of ``func(start)``,
124
+ ``func(start + 1)``, ``func(start + 2)``...
125
+
126
+ *func* should be a function that accepts one integer argument.
127
+
128
+ If *start* is not specified it defaults to 0. It will be incremented each
129
+ time the iterator is advanced.
130
+
131
+ >>> square = lambda x: x ** 2
132
+ >>> iterator = tabulate(square, -3)
133
+ >>> take(4, iterator)
134
+ [9, 4, 1, 0]
135
+
136
+ """
137
+ return map(function, count(start))
138
+
139
+
140
+ def tail(n, iterable):
141
+ """Return an iterator over the last *n* items of *iterable*.
142
+
143
+ >>> t = tail(3, 'ABCDEFG')
144
+ >>> list(t)
145
+ ['E', 'F', 'G']
146
+
147
+ """
148
+ try:
149
+ size = len(iterable)
150
+ except TypeError:
151
+ return iter(deque(iterable, maxlen=n))
152
+ else:
153
+ return islice(iterable, max(0, size - n), None)
154
+
155
+
156
+ def consume(iterator, n=None):
157
+ """Advance *iterable* by *n* steps. If *n* is ``None``, consume it
158
+ entirely.
159
+
160
+ Efficiently exhausts an iterator without returning values. Defaults to
161
+ consuming the whole iterator, but an optional second argument may be
162
+ provided to limit consumption.
163
+
164
+ >>> i = (x for x in range(10))
165
+ >>> next(i)
166
+ 0
167
+ >>> consume(i, 3)
168
+ >>> next(i)
169
+ 4
170
+ >>> consume(i)
171
+ >>> next(i)
172
+ Traceback (most recent call last):
173
+ File "<stdin>", line 1, in <module>
174
+ StopIteration
175
+
176
+ If the iterator has fewer items remaining than the provided limit, the
177
+ whole iterator will be consumed.
178
+
179
+ >>> i = (x for x in range(3))
180
+ >>> consume(i, 5)
181
+ >>> next(i)
182
+ Traceback (most recent call last):
183
+ File "<stdin>", line 1, in <module>
184
+ StopIteration
185
+
186
+ """
187
+ # Use functions that consume iterators at C speed.
188
+ if n is None:
189
+ # feed the entire iterator into a zero-length deque
190
+ deque(iterator, maxlen=0)
191
+ else:
192
+ # advance to the empty slice starting at position n
193
+ next(islice(iterator, n, n), None)
194
+
195
+
196
+ def nth(iterable, n, default=None):
197
+ """Returns the nth item or a default value.
198
+
199
+ >>> l = range(10)
200
+ >>> nth(l, 3)
201
+ 3
202
+ >>> nth(l, 20, "zebra")
203
+ 'zebra'
204
+
205
+ """
206
+ return next(islice(iterable, n, None), default)
207
+
208
+
209
+ def all_equal(iterable, key=None):
210
+ """
211
+ Returns ``True`` if all the elements are equal to each other.
212
+
213
+ >>> all_equal('aaaa')
214
+ True
215
+ >>> all_equal('aaab')
216
+ False
217
+
218
+ A function that accepts a single argument and returns a transformed version
219
+ of each input item can be specified with *key*:
220
+
221
+ >>> all_equal('AaaA', key=str.casefold)
222
+ True
223
+ >>> all_equal([1, 2, 3], key=lambda x: x < 10)
224
+ True
225
+
226
+ """
227
+ iterator = groupby(iterable, key)
228
+ for first in iterator:
229
+ for second in iterator:
230
+ return False
231
+ return True
232
+ return True
233
+
234
+
235
+ def quantify(iterable, pred=bool):
236
+ """Return the how many times the predicate is true.
237
+
238
+ >>> quantify([True, False, True])
239
+ 2
240
+
241
+ """
242
+ return sum(map(pred, iterable))
243
+
244
+
245
+ def pad_none(iterable):
246
+ """Returns the sequence of elements and then returns ``None`` indefinitely.
247
+
248
+ >>> take(5, pad_none(range(3)))
249
+ [0, 1, 2, None, None]
250
+
251
+ Useful for emulating the behavior of the built-in :func:`map` function.
252
+
253
+ See also :func:`padded`.
254
+
255
+ """
256
+ return chain(iterable, repeat(None))
257
+
258
+
259
+ padnone = pad_none
260
+
261
+
262
+ def ncycles(iterable, n):
263
+ """Returns the sequence elements *n* times
264
+
265
+ >>> list(ncycles(["a", "b"], 3))
266
+ ['a', 'b', 'a', 'b', 'a', 'b']
267
+
268
+ """
269
+ return chain.from_iterable(repeat(tuple(iterable), n))
270
+
271
+
272
+ def dotproduct(vec1, vec2):
273
+ """Returns the dot product of the two iterables.
274
+
275
+ >>> dotproduct([10, 15, 12], [0.65, 0.80, 1.25])
276
+ 33.5
277
+ >>> 10 * 0.65 + 15 * 0.80 + 12 * 1.25
278
+ 33.5
279
+
280
+ In Python 3.12 and later, use ``math.sumprod()`` instead.
281
+ """
282
+ return sum(map(mul, vec1, vec2))
283
+
284
+
285
+ # math.sumprod is available for Python 3.12+
286
+ try:
287
+ from math import sumprod as _sumprod
288
+ except ImportError: # pragma: no cover
289
+ _sumprod = dotproduct
290
+
291
+
292
+ def flatten(listOfLists):
293
+ """Return an iterator flattening one level of nesting in a list of lists.
294
+
295
+ >>> list(flatten([[0, 1], [2, 3]]))
296
+ [0, 1, 2, 3]
297
+
298
+ See also :func:`collapse`, which can flatten multiple levels of nesting.
299
+
300
+ """
301
+ return chain.from_iterable(listOfLists)
302
+
303
+
304
+ def repeatfunc(func, times=None, *args):
305
+ """Call *func* with *args* repeatedly, returning an iterable over the
306
+ results.
307
+
308
+ If *times* is specified, the iterable will terminate after that many
309
+ repetitions:
310
+
311
+ >>> from operator import add
312
+ >>> times = 4
313
+ >>> args = 3, 5
314
+ >>> list(repeatfunc(add, times, *args))
315
+ [8, 8, 8, 8]
316
+
317
+ If *times* is ``None`` the iterable will not terminate:
318
+
319
+ >>> from random import randrange
320
+ >>> times = None
321
+ >>> args = 1, 11
322
+ >>> take(6, repeatfunc(randrange, times, *args)) # doctest:+SKIP
323
+ [2, 4, 8, 1, 8, 4]
324
+
325
+ """
326
+ if times is None:
327
+ return starmap(func, repeat(args))
328
+ return starmap(func, repeat(args, times))
329
+
330
+
331
+ def grouper(iterable, n, incomplete='fill', fillvalue=None):
332
+ """Group elements from *iterable* into fixed-length groups of length *n*.
333
+
334
+ >>> list(grouper('ABCDEF', 3))
335
+ [('A', 'B', 'C'), ('D', 'E', 'F')]
336
+
337
+ The keyword arguments *incomplete* and *fillvalue* control what happens for
338
+ iterables whose length is not a multiple of *n*.
339
+
340
+ When *incomplete* is `'fill'`, the last group will contain instances of
341
+ *fillvalue*.
342
+
343
+ >>> list(grouper('ABCDEFG', 3, incomplete='fill', fillvalue='x'))
344
+ [('A', 'B', 'C'), ('D', 'E', 'F'), ('G', 'x', 'x')]
345
+
346
+ When *incomplete* is `'ignore'`, the last group will not be emitted.
347
+
348
+ >>> list(grouper('ABCDEFG', 3, incomplete='ignore', fillvalue='x'))
349
+ [('A', 'B', 'C'), ('D', 'E', 'F')]
350
+
351
+ When *incomplete* is `'strict'`, a `ValueError` will be raised.
352
+
353
+ >>> iterator = grouper('ABCDEFG', 3, incomplete='strict')
354
+ >>> list(iterator) # doctest: +IGNORE_EXCEPTION_DETAIL
355
+ Traceback (most recent call last):
356
+ ...
357
+ ValueError
358
+
359
+ """
360
+ iterators = [iter(iterable)] * n
361
+ match incomplete:
362
+ case 'fill':
363
+ return zip_longest(*iterators, fillvalue=fillvalue)
364
+ case 'strict':
365
+ return zip(*iterators, strict=True)
366
+ case 'ignore':
367
+ return zip(*iterators)
368
+ case _:
369
+ raise ValueError('Expected fill, strict, or ignore')
370
+
371
+
372
+ def roundrobin(*iterables):
373
+ """Visit input iterables in a cycle until each is exhausted.
374
+
375
+ >>> list(roundrobin('ABC', 'D', 'EF'))
376
+ ['A', 'D', 'E', 'B', 'F', 'C']
377
+
378
+ This function produces the same output as :func:`interleave_longest`, but
379
+ may perform better for some inputs (in particular when the number of
380
+ iterables is small).
381
+
382
+ """
383
+ # Algorithm credited to George Sakkis
384
+ iterators = map(iter, iterables)
385
+ for num_active in range(len(iterables), 0, -1):
386
+ iterators = cycle(islice(iterators, num_active))
387
+ yield from map(next, iterators)
388
+
389
+
390
+ def partition(pred, iterable):
391
+ """
392
+ Returns a 2-tuple of iterables derived from the input iterable.
393
+ The first yields the items that have ``pred(item) == False``.
394
+ The second yields the items that have ``pred(item) == True``.
395
+
396
+ >>> is_odd = lambda x: x % 2 != 0
397
+ >>> iterable = range(10)
398
+ >>> even_items, odd_items = partition(is_odd, iterable)
399
+ >>> list(even_items), list(odd_items)
400
+ ([0, 2, 4, 6, 8], [1, 3, 5, 7, 9])
401
+
402
+ If *pred* is None, :func:`bool` is used.
403
+
404
+ >>> iterable = [0, 1, False, True, '', ' ']
405
+ >>> false_items, true_items = partition(None, iterable)
406
+ >>> list(false_items), list(true_items)
407
+ ([0, False, ''], [1, True, ' '])
408
+
409
+ """
410
+ if pred is None:
411
+ pred = bool
412
+
413
+ t1, t2, p = tee(iterable, 3)
414
+ p1, p2 = tee(map(pred, p))
415
+ return (compress(t1, map(not_, p1)), compress(t2, p2))
416
+
417
+
418
+ def powerset(iterable):
419
+ """Yields all possible subsets of the iterable.
420
+
421
+ >>> list(powerset([1, 2, 3]))
422
+ [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
423
+
424
+ :func:`powerset` will operate on iterables that aren't :class:`set`
425
+ instances, so repeated elements in the input will produce repeated elements
426
+ in the output.
427
+
428
+ >>> seq = [1, 1, 0]
429
+ >>> list(powerset(seq))
430
+ [(), (1,), (1,), (0,), (1, 1), (1, 0), (1, 0), (1, 1, 0)]
431
+
432
+ For a variant that efficiently yields actual :class:`set` instances, see
433
+ :func:`powerset_of_sets`.
434
+ """
435
+ s = list(iterable)
436
+ return chain.from_iterable(combinations(s, r) for r in range(len(s) + 1))
437
+
438
+
439
+ def unique_everseen(iterable, key=None):
440
+ """
441
+ Yield unique elements, preserving order.
442
+
443
+ >>> list(unique_everseen('AAAABBBCCDAABBB'))
444
+ ['A', 'B', 'C', 'D']
445
+ >>> list(unique_everseen('ABBCcAD', str.lower))
446
+ ['A', 'B', 'C', 'D']
447
+
448
+ Sequences with a mix of hashable and unhashable items can be used.
449
+ The function will be slower (i.e., `O(n^2)`) for unhashable items.
450
+
451
+ Remember that ``list`` objects are unhashable - you can use the *key*
452
+ parameter to transform the list to a tuple (which is hashable) to
453
+ avoid a slowdown.
454
+
455
+ >>> iterable = ([1, 2], [2, 3], [1, 2])
456
+ >>> list(unique_everseen(iterable)) # Slow
457
+ [[1, 2], [2, 3]]
458
+ >>> list(unique_everseen(iterable, key=tuple)) # Faster
459
+ [[1, 2], [2, 3]]
460
+
461
+ Similarly, you may want to convert unhashable ``set`` objects with
462
+ ``key=frozenset``. For ``dict`` objects,
463
+ ``key=lambda x: frozenset(x.items())`` can be used.
464
+
465
+ """
466
+ seenset = set()
467
+ seenset_add = seenset.add
468
+ seenlist = []
469
+ seenlist_add = seenlist.append
470
+ use_key = key is not None
471
+
472
+ for element in iterable:
473
+ k = key(element) if use_key else element
474
+ try:
475
+ if k not in seenset:
476
+ seenset_add(k)
477
+ yield element
478
+ except TypeError:
479
+ if k not in seenlist:
480
+ seenlist_add(k)
481
+ yield element
482
+
483
+
484
+ def unique_justseen(iterable, key=None):
485
+ """Yields elements in order, ignoring serial duplicates
486
+
487
+ >>> list(unique_justseen('AAAABBBCCDAABBB'))
488
+ ['A', 'B', 'C', 'D', 'A', 'B']
489
+ >>> list(unique_justseen('ABBCcAD', str.lower))
490
+ ['A', 'B', 'C', 'A', 'D']
491
+
492
+ """
493
+ if key is None:
494
+ return map(itemgetter(0), groupby(iterable))
495
+
496
+ return map(next, map(itemgetter(1), groupby(iterable, key)))
497
+
498
+
499
+ def unique(iterable, key=None, reverse=False):
500
+ """Yields unique elements in sorted order.
501
+
502
+ >>> list(unique([[1, 2], [3, 4], [1, 2]]))
503
+ [[1, 2], [3, 4]]
504
+
505
+ *key* and *reverse* are passed to :func:`sorted`.
506
+
507
+ >>> list(unique('ABBcCAD', str.casefold))
508
+ ['A', 'B', 'c', 'D']
509
+ >>> list(unique('ABBcCAD', str.casefold, reverse=True))
510
+ ['D', 'c', 'B', 'A']
511
+
512
+ The elements in *iterable* need not be hashable, but they must be
513
+ comparable for sorting to work.
514
+ """
515
+ sequenced = sorted(iterable, key=key, reverse=reverse)
516
+ return unique_justseen(sequenced, key=key)
517
+
518
+
519
+ def iter_except(func, exception, first=None):
520
+ """Yields results from a function repeatedly until an exception is raised.
521
+
522
+ Converts a call-until-exception interface to an iterator interface.
523
+ Like ``iter(func, sentinel)``, but uses an exception instead of a sentinel
524
+ to end the loop.
525
+
526
+ >>> l = [0, 1, 2]
527
+ >>> list(iter_except(l.pop, IndexError))
528
+ [2, 1, 0]
529
+
530
+ Multiple exceptions can be specified as a stopping condition:
531
+
532
+ >>> l = [1, 2, 3, '...', 4, 5, 6]
533
+ >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
534
+ [7, 6, 5]
535
+ >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
536
+ [4, 3, 2]
537
+ >>> list(iter_except(lambda: 1 + l.pop(), (IndexError, TypeError)))
538
+ []
539
+
540
+ """
541
+ with suppress(exception):
542
+ if first is not None:
543
+ yield first()
544
+ while True:
545
+ yield func()
546
+
547
+
548
+ def first_true(iterable, default=None, pred=None):
549
+ """
550
+ Returns the first true value in the iterable.
551
+
552
+ If no true value is found, returns *default*
553
+
554
+ If *pred* is not None, returns the first item for which
555
+ ``pred(item) == True`` .
556
+
557
+ >>> first_true(range(10))
558
+ 1
559
+ >>> first_true(range(10), pred=lambda x: x > 5)
560
+ 6
561
+ >>> first_true(range(10), default='missing', pred=lambda x: x > 9)
562
+ 'missing'
563
+
564
+ """
565
+ return next(filter(pred, iterable), default)
566
+
567
+
568
+ def random_product(*iterables, repeat=1):
569
+ """Draw an item at random from each of the input iterables.
570
+
571
+ >>> random_product('abc', range(4), 'XYZ') # doctest:+SKIP
572
+ ('c', 3, 'Z')
573
+
574
+ If *repeat* is provided as a keyword argument, that many items will be
575
+ drawn from each iterable.
576
+
577
+ >>> random_product('abcd', range(4), repeat=2) # doctest:+SKIP
578
+ ('a', 2, 'd', 3)
579
+
580
+ This equivalent to taking a random selection from
581
+ ``itertools.product(*args, repeat=repeat)``.
582
+
583
+ """
584
+ pools = tuple(map(tuple, iterables)) * repeat
585
+ return tuple(map(choice, pools))
586
+
587
+
588
+ def random_permutation(iterable, r=None):
589
+ """Return a random *r* length permutation of the elements in *iterable*.
590
+
591
+ If *r* is not specified or is ``None``, then *r* defaults to the length of
592
+ *iterable*.
593
+
594
+ >>> random_permutation(range(5)) # doctest:+SKIP
595
+ (3, 4, 0, 1, 2)
596
+
597
+ This equivalent to taking a random selection from
598
+ ``itertools.permutations(iterable, r)``.
599
+
600
+ """
601
+ pool = tuple(iterable)
602
+ r = len(pool) if r is None else r
603
+ return tuple(sample(pool, r))
604
+
605
+
606
+ def random_combination(iterable, r):
607
+ """Return a random *r* length subsequence of the elements in *iterable*.
608
+
609
+ >>> random_combination(range(5), 3) # doctest:+SKIP
610
+ (2, 3, 4)
611
+
612
+ This equivalent to taking a random selection from
613
+ ``itertools.combinations(iterable, r)``.
614
+
615
+ """
616
+ pool = tuple(iterable)
617
+ n = len(pool)
618
+ indices = sorted(sample(range(n), r))
619
+ return tuple([pool[i] for i in indices])
620
+
621
+
622
+ def random_combination_with_replacement(iterable, r):
623
+ """Return a random *r* length subsequence of elements in *iterable*,
624
+ allowing individual elements to be repeated.
625
+
626
+ >>> random_combination_with_replacement(range(3), 5) # doctest:+SKIP
627
+ (0, 0, 1, 2, 2)
628
+
629
+ This equivalent to taking a random selection from
630
+ ``itertools.combinations_with_replacement(iterable, r)``.
631
+
632
+ """
633
+ pool = tuple(iterable)
634
+ n = len(pool)
635
+ indices = sorted(randrange(n) for i in range(r))
636
+ return tuple([pool[i] for i in indices])
637
+
638
+
639
+ def nth_combination(iterable, r, index):
640
+ """Equivalent to ``list(combinations(iterable, r))[index]``.
641
+
642
+ The subsequences of *iterable* that are of length *r* can be ordered
643
+ lexicographically. :func:`nth_combination` computes the subsequence at
644
+ sort position *index* directly, without computing the previous
645
+ subsequences.
646
+
647
+ >>> nth_combination(range(5), 3, 5)
648
+ (0, 3, 4)
649
+
650
+ ``ValueError`` will be raised If *r* is negative.
651
+ ``IndexError`` will be raised if the given *index* is invalid.
652
+ """
653
+ pool = tuple(iterable)
654
+ n = len(pool)
655
+ c = comb(n, r)
656
+
657
+ if index < 0:
658
+ index += c
659
+ if not 0 <= index < c:
660
+ raise IndexError
661
+
662
+ result = []
663
+ while r:
664
+ c, n, r = c * r // n, n - 1, r - 1
665
+ while index >= c:
666
+ index -= c
667
+ c, n = c * (n - r) // n, n - 1
668
+ result.append(pool[-1 - n])
669
+
670
+ return tuple(result)
671
+
672
+
673
+ def prepend(value, iterator):
674
+ """Yield *value*, followed by the elements in *iterator*.
675
+
676
+ >>> value = '0'
677
+ >>> iterator = ['1', '2', '3']
678
+ >>> list(prepend(value, iterator))
679
+ ['0', '1', '2', '3']
680
+
681
+ To prepend multiple values, see :func:`itertools.chain`
682
+ or :func:`value_chain`.
683
+
684
+ """
685
+ return chain([value], iterator)
686
+
687
+
688
+ def convolve(signal, kernel):
689
+ """Discrete linear convolution of two iterables.
690
+ Equivalent to polynomial multiplication.
691
+
692
+ For example, multiplying ``(x² -x - 20)`` by ``(x - 3)``
693
+ gives ``(x³ -4x² -17x + 60)``.
694
+
695
+ >>> list(convolve([1, -1, -20], [1, -3]))
696
+ [1, -4, -17, 60]
697
+
698
+ Examples of popular kinds of kernels:
699
+
700
+ * The kernel ``[0.25, 0.25, 0.25, 0.25]`` computes a moving average.
701
+ For image data, this blurs the image and reduces noise.
702
+ * The kernel ``[1/2, 0, -1/2]`` estimates the first derivative of
703
+ a function evaluated at evenly spaced inputs.
704
+ * The kernel ``[1, -2, 1]`` estimates the second derivative of a
705
+ function evaluated at evenly spaced inputs.
706
+
707
+ Convolutions are mathematically commutative; however, the inputs are
708
+ evaluated differently. The signal is consumed lazily and can be
709
+ infinite. The kernel is fully consumed before the calculations begin.
710
+
711
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
712
+
713
+ References:
714
+
715
+ * Article: https://betterexplained.com/articles/intuitive-convolution/
716
+ * Video by 3Blue1Brown: https://www.youtube.com/watch?v=KuXjwB4LzSA
717
+
718
+ """
719
+ # This implementation comes from an older version of the itertools
720
+ # documentation. While the newer implementation is a bit clearer,
721
+ # this one was kept because the inlined window logic is faster
722
+ # and it avoids an unnecessary deque-to-tuple conversion.
723
+ kernel = tuple(kernel)[::-1]
724
+ n = len(kernel)
725
+ window = deque([0], maxlen=n) * n
726
+ for x in chain(signal, repeat(0, n - 1)):
727
+ window.append(x)
728
+ yield _sumprod(kernel, window)
729
+
730
+
731
+ def before_and_after(predicate, it):
732
+ """A variant of :func:`takewhile` that allows complete access to the
733
+ remainder of the iterator.
734
+
735
+ >>> it = iter('ABCdEfGhI')
736
+ >>> all_upper, remainder = before_and_after(str.isupper, it)
737
+ >>> ''.join(all_upper)
738
+ 'ABC'
739
+ >>> ''.join(remainder) # takewhile() would lose the 'd'
740
+ 'dEfGhI'
741
+
742
+ Note that the first iterator must be fully consumed before the second
743
+ iterator can generate valid results.
744
+ """
745
+ trues, after = tee(it)
746
+ trues = compress(takewhile(predicate, trues), zip(after))
747
+ return trues, after
748
+
749
+
750
+ def triplewise(iterable):
751
+ """Return overlapping triplets from *iterable*.
752
+
753
+ >>> list(triplewise('ABCDE'))
754
+ [('A', 'B', 'C'), ('B', 'C', 'D'), ('C', 'D', 'E')]
755
+
756
+ """
757
+ # This deviates from the itertools documentation recipe - see
758
+ # https://github.com/more-itertools/more-itertools/issues/889
759
+ t1, t2, t3 = tee(iterable, 3)
760
+ next(t3, None)
761
+ next(t3, None)
762
+ next(t2, None)
763
+ return zip(t1, t2, t3)
764
+
765
+
766
+ def _sliding_window_islice(iterable, n):
767
+ # Fast path for small, non-zero values of n.
768
+ iterators = tee(iterable, n)
769
+ for i, iterator in enumerate(iterators):
770
+ next(islice(iterator, i, i), None)
771
+ return zip(*iterators)
772
+
773
+
774
+ def _sliding_window_deque(iterable, n):
775
+ # Normal path for other values of n.
776
+ iterator = iter(iterable)
777
+ window = deque(islice(iterator, n - 1), maxlen=n)
778
+ for x in iterator:
779
+ window.append(x)
780
+ yield tuple(window)
781
+
782
+
783
+ def sliding_window(iterable, n):
784
+ """Return a sliding window of width *n* over *iterable*.
785
+
786
+ >>> list(sliding_window(range(6), 4))
787
+ [(0, 1, 2, 3), (1, 2, 3, 4), (2, 3, 4, 5)]
788
+
789
+ If *iterable* has fewer than *n* items, then nothing is yielded:
790
+
791
+ >>> list(sliding_window(range(3), 4))
792
+ []
793
+
794
+ For a variant with more features, see :func:`windowed`.
795
+ """
796
+ if n > 20:
797
+ return _sliding_window_deque(iterable, n)
798
+ elif n > 2:
799
+ return _sliding_window_islice(iterable, n)
800
+ elif n == 2:
801
+ return pairwise(iterable)
802
+ elif n == 1:
803
+ return zip(iterable)
804
+ else:
805
+ raise ValueError(f'n should be at least one, not {n}')
806
+
807
+
808
+ def subslices(iterable):
809
+ """Return all contiguous non-empty subslices of *iterable*.
810
+
811
+ >>> list(subslices('ABC'))
812
+ [['A'], ['A', 'B'], ['A', 'B', 'C'], ['B'], ['B', 'C'], ['C']]
813
+
814
+ This is similar to :func:`substrings`, but emits items in a different
815
+ order.
816
+ """
817
+ seq = list(iterable)
818
+ slices = starmap(slice, combinations(range(len(seq) + 1), 2))
819
+ return map(getitem, repeat(seq), slices)
820
+
821
+
822
+ def polynomial_from_roots(roots):
823
+ """Compute a polynomial's coefficients from its roots.
824
+
825
+ >>> roots = [5, -4, 3] # (x - 5) * (x + 4) * (x - 3)
826
+ >>> polynomial_from_roots(roots) # x³ - 4 x² - 17 x + 60
827
+ [1, -4, -17, 60]
828
+
829
+ Note that polynomial coefficients are specified in descending power order.
830
+
831
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
832
+ """
833
+
834
+ # This recipe differs from the one in itertools docs in that it
835
+ # applies list() after each call to convolve(). This avoids
836
+ # hitting stack limits with nested generators.
837
+
838
+ poly = [1]
839
+ for root in roots:
840
+ poly = list(convolve(poly, (1, -root)))
841
+ return poly
842
+
843
+
844
+ def iter_index(iterable, value, start=0, stop=None):
845
+ """Yield the index of each place in *iterable* that *value* occurs,
846
+ beginning with index *start* and ending before index *stop*.
847
+
848
+
849
+ >>> list(iter_index('AABCADEAF', 'A'))
850
+ [0, 1, 4, 7]
851
+ >>> list(iter_index('AABCADEAF', 'A', 1)) # start index is inclusive
852
+ [1, 4, 7]
853
+ >>> list(iter_index('AABCADEAF', 'A', 1, 7)) # stop index is not inclusive
854
+ [1, 4]
855
+
856
+ The behavior for non-scalar *values* matches the built-in Python types.
857
+
858
+ >>> list(iter_index('ABCDABCD', 'AB'))
859
+ [0, 4]
860
+ >>> list(iter_index([0, 1, 2, 3, 0, 1, 2, 3], [0, 1]))
861
+ []
862
+ >>> list(iter_index([[0, 1], [2, 3], [0, 1], [2, 3]], [0, 1]))
863
+ [0, 2]
864
+
865
+ See :func:`locate` for a more general means of finding the indexes
866
+ associated with particular values.
867
+
868
+ """
869
+ seq_index = getattr(iterable, 'index', None)
870
+ if seq_index is None:
871
+ # Slow path for general iterables
872
+ iterator = islice(iterable, start, stop)
873
+ for i, element in enumerate(iterator, start):
874
+ if element is value or element == value:
875
+ yield i
876
+ else:
877
+ # Fast path for sequences
878
+ stop = len(iterable) if stop is None else stop
879
+ i = start - 1
880
+ with suppress(ValueError):
881
+ while True:
882
+ yield (i := seq_index(value, i + 1, stop))
883
+
884
+
885
+ def sieve(n):
886
+ """Yield the primes less than n.
887
+
888
+ >>> list(sieve(30))
889
+ [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
890
+
891
+ """
892
+ # This implementation comes from an older version of the itertools
893
+ # documentation. The newer implementation is easier to read but is
894
+ # less lazy.
895
+ if n > 2:
896
+ yield 2
897
+ start = 3
898
+ data = bytearray((0, 1)) * (n // 2)
899
+ for p in iter_index(data, 1, start, stop=isqrt(n) + 1):
900
+ yield from iter_index(data, 1, start, p * p)
901
+ data[p * p : n : p + p] = bytes(len(range(p * p, n, p + p)))
902
+ start = p * p
903
+ yield from iter_index(data, 1, start)
904
+
905
+
906
+ def _batched(iterable, n, *, strict=False): # pragma: no cover
907
+ """Batch data into tuples of length *n*. If the number of items in
908
+ *iterable* is not divisible by *n*:
909
+ * The last batch will be shorter if *strict* is ``False``.
910
+ * :exc:`ValueError` will be raised if *strict* is ``True``.
911
+
912
+ >>> list(batched('ABCDEFG', 3))
913
+ [('A', 'B', 'C'), ('D', 'E', 'F'), ('G',)]
914
+
915
+ On Python 3.13 and above, this is an alias for :func:`itertools.batched`.
916
+ """
917
+ if n < 1:
918
+ raise ValueError('n must be at least one')
919
+ iterator = iter(iterable)
920
+ while batch := tuple(islice(iterator, n)):
921
+ if strict and len(batch) != n:
922
+ raise ValueError('batched(): incomplete batch')
923
+ yield batch
924
+
925
+
926
+ if hexversion >= 0x30D00A2: # pragma: no cover
927
+ from itertools import batched as itertools_batched
928
+
929
+ def batched(iterable, n, *, strict=False):
930
+ return itertools_batched(iterable, n, strict=strict)
931
+
932
+ batched.__doc__ = _batched.__doc__
933
+ else: # pragma: no cover
934
+ batched = _batched
935
+
936
+
937
+ def transpose(it):
938
+ """Swap the rows and columns of the input matrix.
939
+
940
+ >>> list(transpose([(1, 2, 3), (11, 22, 33)]))
941
+ [(1, 11), (2, 22), (3, 33)]
942
+
943
+ The caller should ensure that the dimensions of the input are compatible.
944
+ If the input is empty, no output will be produced.
945
+ """
946
+ return zip(*it, strict=True)
947
+
948
+
949
+ def _is_scalar(value, stringlike=(str, bytes)):
950
+ "Scalars are bytes, strings, and non-iterables."
951
+ try:
952
+ iter(value)
953
+ except TypeError:
954
+ return True
955
+ return isinstance(value, stringlike)
956
+
957
+
958
+ def _flatten_tensor(tensor):
959
+ "Depth-first iterator over scalars in a tensor."
960
+ iterator = iter(tensor)
961
+ while True:
962
+ try:
963
+ value = next(iterator)
964
+ except StopIteration:
965
+ return iterator
966
+ iterator = chain((value,), iterator)
967
+ if _is_scalar(value):
968
+ return iterator
969
+ iterator = chain.from_iterable(iterator)
970
+
971
+
972
+ def reshape(matrix, shape):
973
+ """Change the shape of a *matrix*.
974
+
975
+ If *shape* is an integer, the matrix must be two dimensional
976
+ and the shape is interpreted as the desired number of columns:
977
+
978
+ >>> matrix = [(0, 1), (2, 3), (4, 5)]
979
+ >>> cols = 3
980
+ >>> list(reshape(matrix, cols))
981
+ [(0, 1, 2), (3, 4, 5)]
982
+
983
+ If *shape* is a tuple (or other iterable), the input matrix can have
984
+ any number of dimensions. It will first be flattened and then rebuilt
985
+ to the desired shape which can also be multidimensional:
986
+
987
+ >>> matrix = [(0, 1), (2, 3), (4, 5)] # Start with a 3 x 2 matrix
988
+
989
+ >>> list(reshape(matrix, (2, 3))) # Make a 2 x 3 matrix
990
+ [(0, 1, 2), (3, 4, 5)]
991
+
992
+ >>> list(reshape(matrix, (6,))) # Make a vector of length six
993
+ [0, 1, 2, 3, 4, 5]
994
+
995
+ >>> list(reshape(matrix, (2, 1, 3, 1))) # Make 2 x 1 x 3 x 1 tensor
996
+ [(((0,), (1,), (2,)),), (((3,), (4,), (5,)),)]
997
+
998
+ Each dimension is assumed to be uniform, either all arrays or all scalars.
999
+ Flattening stops when the first value in a dimension is a scalar.
1000
+ Scalars are bytes, strings, and non-iterables.
1001
+ The reshape iterator stops when the requested shape is complete
1002
+ or when the input is exhausted, whichever comes first.
1003
+
1004
+ """
1005
+ if isinstance(shape, int):
1006
+ return batched(chain.from_iterable(matrix), shape)
1007
+ first_dim, *dims = shape
1008
+ scalar_stream = _flatten_tensor(matrix)
1009
+ reshaped = reduce(batched, reversed(dims), scalar_stream)
1010
+ return islice(reshaped, first_dim)
1011
+
1012
+
1013
+ def matmul(m1, m2):
1014
+ """Multiply two matrices.
1015
+
1016
+ >>> list(matmul([(7, 5), (3, 5)], [(2, 5), (7, 9)]))
1017
+ [(49, 80), (41, 60)]
1018
+
1019
+ The caller should ensure that the dimensions of the input matrices are
1020
+ compatible with each other.
1021
+
1022
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
1023
+ """
1024
+ n = len(m2[0])
1025
+ return batched(starmap(_sumprod, product(m1, transpose(m2))), n)
1026
+
1027
+
1028
+ def _factor_pollard(n):
1029
+ # Return a factor of n using Pollard's rho algorithm.
1030
+ # Efficient when n is odd and composite.
1031
+ for b in range(1, n):
1032
+ x = y = 2
1033
+ d = 1
1034
+ while d == 1:
1035
+ x = (x * x + b) % n
1036
+ y = (y * y + b) % n
1037
+ y = (y * y + b) % n
1038
+ d = gcd(x - y, n)
1039
+ if d != n:
1040
+ return d
1041
+ raise ValueError('prime or under 5') # pragma: no cover
1042
+
1043
+
1044
+ _primes_below_211 = tuple(sieve(211))
1045
+
1046
+
1047
+ def factor(n):
1048
+ """Yield the prime factors of n.
1049
+
1050
+ >>> list(factor(360))
1051
+ [2, 2, 2, 3, 3, 5]
1052
+
1053
+ Finds small factors with trial division. Larger factors are
1054
+ either verified as prime with ``is_prime`` or split into
1055
+ smaller factors with Pollard's rho algorithm.
1056
+ """
1057
+
1058
+ # Corner case reduction
1059
+ if n < 2:
1060
+ return
1061
+
1062
+ # Trial division reduction
1063
+ for prime in _primes_below_211:
1064
+ while not n % prime:
1065
+ yield prime
1066
+ n //= prime
1067
+
1068
+ # Pollard's rho reduction
1069
+ primes = []
1070
+ todo = [n] if n > 1 else []
1071
+ for n in todo:
1072
+ if n < 211**2 or is_prime(n):
1073
+ primes.append(n)
1074
+ else:
1075
+ fact = _factor_pollard(n)
1076
+ todo += (fact, n // fact)
1077
+ yield from sorted(primes)
1078
+
1079
+
1080
+ def polynomial_eval(coefficients, x):
1081
+ """Evaluate a polynomial at a specific value.
1082
+
1083
+ Computes with better numeric stability than Horner's method.
1084
+
1085
+ Evaluate ``x^3 - 4 * x^2 - 17 * x + 60`` at ``x = 2.5``:
1086
+
1087
+ >>> coefficients = [1, -4, -17, 60]
1088
+ >>> x = 2.5
1089
+ >>> polynomial_eval(coefficients, x)
1090
+ 8.125
1091
+
1092
+ Note that polynomial coefficients are specified in descending power order.
1093
+
1094
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
1095
+ """
1096
+ n = len(coefficients)
1097
+ if n == 0:
1098
+ return type(x)(0)
1099
+ powers = map(pow, repeat(x), reversed(range(n)))
1100
+ return _sumprod(coefficients, powers)
1101
+
1102
+
1103
+ def sum_of_squares(it):
1104
+ """Return the sum of the squares of the input values.
1105
+
1106
+ >>> sum_of_squares([10, 20, 30])
1107
+ 1400
1108
+
1109
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
1110
+ """
1111
+ return _sumprod(*tee(it))
1112
+
1113
+
1114
+ def polynomial_derivative(coefficients):
1115
+ """Compute the first derivative of a polynomial.
1116
+
1117
+ Evaluate the derivative of ``x³ - 4 x² - 17 x + 60``:
1118
+
1119
+ >>> coefficients = [1, -4, -17, 60]
1120
+ >>> derivative_coefficients = polynomial_derivative(coefficients)
1121
+ >>> derivative_coefficients
1122
+ [3, -8, -17]
1123
+
1124
+ Note that polynomial coefficients are specified in descending power order.
1125
+
1126
+ Supports all numeric types: int, float, complex, Decimal, Fraction.
1127
+ """
1128
+ n = len(coefficients)
1129
+ powers = reversed(range(1, n))
1130
+ return list(map(mul, coefficients, powers))
1131
+
1132
+
1133
+ def totient(n):
1134
+ """Return the count of natural numbers up to *n* that are coprime with *n*.
1135
+
1136
+ Euler's totient function φ(n) gives the number of totatives.
1137
+ Totative are integers k in the range 1 ≤ k ≤ n such that gcd(n, k) = 1.
1138
+
1139
+ >>> n = 9
1140
+ >>> totient(n)
1141
+ 6
1142
+
1143
+ >>> totatives = [x for x in range(1, n) if gcd(n, x) == 1]
1144
+ >>> totatives
1145
+ [1, 2, 4, 5, 7, 8]
1146
+ >>> len(totatives)
1147
+ 6
1148
+
1149
+ Reference: https://en.wikipedia.org/wiki/Euler%27s_totient_function
1150
+
1151
+ """
1152
+ for prime in set(factor(n)):
1153
+ n -= n // prime
1154
+ return n
1155
+
1156
+
1157
+ # Miller–Rabin primality test: https://oeis.org/A014233
1158
+ _perfect_tests = [
1159
+ (2047, (2,)),
1160
+ (9080191, (31, 73)),
1161
+ (4759123141, (2, 7, 61)),
1162
+ (1122004669633, (2, 13, 23, 1662803)),
1163
+ (2152302898747, (2, 3, 5, 7, 11)),
1164
+ (3474749660383, (2, 3, 5, 7, 11, 13)),
1165
+ (18446744073709551616, (2, 325, 9375, 28178, 450775, 9780504, 1795265022)),
1166
+ (
1167
+ 3317044064679887385961981,
1168
+ (2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41),
1169
+ ),
1170
+ ]
1171
+
1172
+
1173
+ @lru_cache
1174
+ def _shift_to_odd(n):
1175
+ 'Return s, d such that 2**s * d == n'
1176
+ s = ((n - 1) ^ n).bit_length() - 1
1177
+ d = n >> s
1178
+ assert (1 << s) * d == n and d & 1 and s >= 0
1179
+ return s, d
1180
+
1181
+
1182
+ def _strong_probable_prime(n, base):
1183
+ assert (n > 2) and (n & 1) and (2 <= base < n)
1184
+
1185
+ s, d = _shift_to_odd(n - 1)
1186
+
1187
+ x = pow(base, d, n)
1188
+ if x == 1 or x == n - 1:
1189
+ return True
1190
+
1191
+ for _ in range(s - 1):
1192
+ x = x * x % n
1193
+ if x == n - 1:
1194
+ return True
1195
+
1196
+ return False
1197
+
1198
+
1199
+ # Separate instance of Random() that doesn't share state
1200
+ # with the default user instance of Random().
1201
+ _private_randrange = random.Random().randrange
1202
+
1203
+
1204
+ def is_prime(n):
1205
+ """Return ``True`` if *n* is prime and ``False`` otherwise.
1206
+
1207
+ Basic examples:
1208
+
1209
+ >>> is_prime(37)
1210
+ True
1211
+ >>> is_prime(3 * 13)
1212
+ False
1213
+ >>> is_prime(18_446_744_073_709_551_557)
1214
+ True
1215
+
1216
+ Find the next prime over one billion:
1217
+
1218
+ >>> next(filter(is_prime, count(10**9)))
1219
+ 1000000007
1220
+
1221
+ Generate random primes up to 200 bits and up to 60 decimal digits:
1222
+
1223
+ >>> from random import seed, randrange, getrandbits
1224
+ >>> seed(18675309)
1225
+
1226
+ >>> next(filter(is_prime, map(getrandbits, repeat(200))))
1227
+ 893303929355758292373272075469392561129886005037663238028407
1228
+
1229
+ >>> next(filter(is_prime, map(randrange, repeat(10**60))))
1230
+ 269638077304026462407872868003560484232362454342414618963649
1231
+
1232
+ This function is exact for values of *n* below 10**24. For larger inputs,
1233
+ the probabilistic Miller-Rabin primality test has a less than 1 in 2**128
1234
+ chance of a false positive.
1235
+ """
1236
+
1237
+ if n < 17:
1238
+ return n in {2, 3, 5, 7, 11, 13}
1239
+
1240
+ if not (n & 1 and n % 3 and n % 5 and n % 7 and n % 11 and n % 13):
1241
+ return False
1242
+
1243
+ for limit, bases in _perfect_tests:
1244
+ if n < limit:
1245
+ break
1246
+ else:
1247
+ bases = (_private_randrange(2, n - 1) for i in range(64))
1248
+
1249
+ return all(_strong_probable_prime(n, base) for base in bases)
1250
+
1251
+
1252
+ def loops(n):
1253
+ """Returns an iterable with *n* elements for efficient looping.
1254
+ Like ``range(n)`` but doesn't create integers.
1255
+
1256
+ >>> i = 0
1257
+ >>> for _ in loops(5):
1258
+ ... i += 1
1259
+ >>> i
1260
+ 5
1261
+
1262
+ """
1263
+ return repeat(None, n)
1264
+
1265
+
1266
+ def multinomial(*counts):
1267
+ """Number of distinct arrangements of a multiset.
1268
+
1269
+ The expression ``multinomial(3, 4, 2)`` has several equivalent
1270
+ interpretations:
1271
+
1272
+ * In the expansion of ``(a + b + c)⁹``, the coefficient of the
1273
+ ``a³b⁴c²`` term is 1260.
1274
+
1275
+ * There are 1260 distinct ways to arrange 9 balls consisting of 3 reds, 4
1276
+ greens, and 2 blues.
1277
+
1278
+ * There are 1260 unique ways to place 9 distinct objects into three bins
1279
+ with sizes 3, 4, and 2.
1280
+
1281
+ The :func:`multinomial` function computes the length of
1282
+ :func:`distinct_permutations`. For example, there are 83,160 distinct
1283
+ anagrams of the word "abracadabra":
1284
+
1285
+ >>> from more_itertools import distinct_permutations, ilen
1286
+ >>> ilen(distinct_permutations('abracadabra'))
1287
+ 83160
1288
+
1289
+ This can be computed directly from the letter counts, 5a 2b 2r 1c 1d:
1290
+
1291
+ >>> from collections import Counter
1292
+ >>> list(Counter('abracadabra').values())
1293
+ [5, 2, 2, 1, 1]
1294
+ >>> multinomial(5, 2, 2, 1, 1)
1295
+ 83160
1296
+
1297
+ A binomial coefficient is a special case of multinomial where there are
1298
+ only two categories. For example, the number of ways to arrange 12 balls
1299
+ with 5 reds and 7 blues is ``multinomial(5, 7)`` or ``math.comb(12, 5)``.
1300
+
1301
+ Likewise, factorial is a special case of multinomial where
1302
+ the multiplicities are all just 1 so that
1303
+ ``multinomial(1, 1, 1, 1, 1, 1, 1) == math.factorial(7)``.
1304
+
1305
+ Reference: https://en.wikipedia.org/wiki/Multinomial_theorem
1306
+
1307
+ """
1308
+ return prod(map(comb, accumulate(counts), counts))
1309
+
1310
+
1311
+ def _running_median_minheap_and_maxheap(iterator): # pragma: no cover
1312
+ "Non-windowed running_median() for Python 3.14+"
1313
+
1314
+ read = iterator.__next__
1315
+ lo = [] # max-heap
1316
+ hi = [] # min-heap (same size as or one smaller than lo)
1317
+
1318
+ with suppress(StopIteration):
1319
+ while True:
1320
+ heappush_max(lo, heappushpop(hi, read()))
1321
+ yield lo[0]
1322
+
1323
+ heappush(hi, heappushpop_max(lo, read()))
1324
+ yield (lo[0] + hi[0]) / 2
1325
+
1326
+
1327
+ def _running_median_minheap_only(iterator): # pragma: no cover
1328
+ "Backport of non-windowed running_median() for Python 3.13 and prior."
1329
+
1330
+ read = iterator.__next__
1331
+ lo = [] # max-heap (actually a minheap with negated values)
1332
+ hi = [] # min-heap (same size as or one smaller than lo)
1333
+
1334
+ with suppress(StopIteration):
1335
+ while True:
1336
+ heappush(lo, -heappushpop(hi, read()))
1337
+ yield -lo[0]
1338
+
1339
+ heappush(hi, -heappushpop(lo, -read()))
1340
+ yield (hi[0] - lo[0]) / 2
1341
+
1342
+
1343
+ def _running_median_windowed(iterator, maxlen):
1344
+ "Yield median of values in a sliding window."
1345
+
1346
+ window = deque()
1347
+ ordered = []
1348
+
1349
+ for x in iterator:
1350
+ window.append(x)
1351
+ insort(ordered, x)
1352
+
1353
+ if len(ordered) > maxlen:
1354
+ i = bisect_left(ordered, window.popleft())
1355
+ del ordered[i]
1356
+
1357
+ n = len(ordered)
1358
+ m = n // 2
1359
+ yield ordered[m] if n & 1 else (ordered[m - 1] + ordered[m]) / 2
1360
+
1361
+
1362
+ def running_median(iterable, *, maxlen=None):
1363
+ """Cumulative median of values seen so far or values in a sliding window.
1364
+
1365
+ Set *maxlen* to a positive integer to specify the maximum size
1366
+ of the sliding window. The default of *None* is equivalent to
1367
+ an unbounded window.
1368
+
1369
+ For example:
1370
+
1371
+ >>> list(running_median([5.0, 9.0, 4.0, 12.0, 8.0, 9.0]))
1372
+ [5.0, 7.0, 5.0, 7.0, 8.0, 8.5]
1373
+ >>> list(running_median([5.0, 9.0, 4.0, 12.0, 8.0, 9.0], maxlen=3))
1374
+ [5.0, 7.0, 5.0, 9.0, 8.0, 9.0]
1375
+
1376
+ Supports numeric types such as int, float, Decimal, and Fraction,
1377
+ but not complex numbers which are unorderable.
1378
+
1379
+ On version Python 3.13 and prior, max-heaps are simulated with
1380
+ negative values. The negation causes Decimal inputs to apply context
1381
+ rounding, making the results slightly different than that obtained
1382
+ by statistics.median().
1383
+ """
1384
+
1385
+ iterator = iter(iterable)
1386
+
1387
+ if maxlen is not None:
1388
+ maxlen = index(maxlen)
1389
+ if maxlen <= 0:
1390
+ raise ValueError('Window size should be positive')
1391
+ return _running_median_windowed(iterator, maxlen)
1392
+
1393
+ if not _max_heap_available:
1394
+ return _running_median_minheap_only(iterator) # pragma: no cover
1395
+
1396
+ return _running_median_minheap_and_maxheap(iterator) # pragma: no cover
1397
+
1398
+
1399
+ def running_mean(iterable):
1400
+ """Yield the average of all values seen so far.
1401
+
1402
+ >>> iterable = [100, 200, 600]
1403
+ >>> all_means = running_mean(iterable)
1404
+ >>> next(all_means)
1405
+ 100.0
1406
+ >>> next(all_means)
1407
+ 150.0
1408
+ >>> next(all_means)
1409
+ 300.0
1410
+ """
1411
+ return map(truediv, accumulate(iterable), count(1))
1412
+
1413
+
1414
+ def random_derangement(iterable):
1415
+ """Return a random derangement of elements in the iterable.
1416
+
1417
+ Equivalent to but much faster than ``choice(list(derangements(iterable)))``.
1418
+
1419
+ """
1420
+ seq = tuple(iterable)
1421
+ if len(seq) < 2:
1422
+ if len(seq) == 0:
1423
+ return ()
1424
+ raise IndexError('No derangments to choose from')
1425
+ perm = list(range(len(seq)))
1426
+ start = tuple(perm)
1427
+ while True:
1428
+ shuffle(perm)
1429
+ if not any(map(is_, start, perm)):
1430
+ return itemgetter(*perm)(seq)
examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.pyi ADDED
@@ -0,0 +1,207 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Stubs for more_itertools.recipes"""
2
+
3
+ from __future__ import annotations
4
+
5
+ from collections.abc import Iterable, Iterator, Sequence
6
+ from decimal import Decimal
7
+ from fractions import Fraction
8
+ from typing import (
9
+ Any,
10
+ Callable,
11
+ TypeVar,
12
+ overload,
13
+ )
14
+
15
+ __all__ = [
16
+ 'all_equal',
17
+ 'batched',
18
+ 'before_and_after',
19
+ 'consume',
20
+ 'convolve',
21
+ 'dotproduct',
22
+ 'first_true',
23
+ 'factor',
24
+ 'flatten',
25
+ 'grouper',
26
+ 'is_prime',
27
+ 'iter_except',
28
+ 'iter_index',
29
+ 'loops',
30
+ 'matmul',
31
+ 'multinomial',
32
+ 'ncycles',
33
+ 'nth',
34
+ 'nth_combination',
35
+ 'padnone',
36
+ 'pad_none',
37
+ 'partition',
38
+ 'polynomial_eval',
39
+ 'polynomial_from_roots',
40
+ 'polynomial_derivative',
41
+ 'powerset',
42
+ 'prepend',
43
+ 'quantify',
44
+ 'reshape',
45
+ 'random_combination_with_replacement',
46
+ 'random_combination',
47
+ 'random_derangement',
48
+ 'random_permutation',
49
+ 'random_product',
50
+ 'repeatfunc',
51
+ 'roundrobin',
52
+ 'running_mean',
53
+ 'running_median',
54
+ 'sieve',
55
+ 'sliding_window',
56
+ 'subslices',
57
+ 'sum_of_squares',
58
+ 'tabulate',
59
+ 'tail',
60
+ 'take',
61
+ 'totient',
62
+ 'transpose',
63
+ 'triplewise',
64
+ 'unique',
65
+ 'unique_everseen',
66
+ 'unique_justseen',
67
+ ]
68
+
69
+ # Type and type variable definitions
70
+ _T = TypeVar('_T')
71
+ _T1 = TypeVar('_T1')
72
+ _T2 = TypeVar('_T2')
73
+ _U = TypeVar('_U')
74
+ _NumberT = TypeVar("_NumberT", float, Decimal, Fraction)
75
+
76
+ def take(n: int, iterable: Iterable[_T]) -> list[_T]: ...
77
+ def tabulate(
78
+ function: Callable[[int], _T], start: int = ...
79
+ ) -> Iterator[_T]: ...
80
+ def tail(n: int, iterable: Iterable[_T]) -> Iterator[_T]: ...
81
+ def consume(iterator: Iterable[_T], n: int | None = ...) -> None: ...
82
+ @overload
83
+ def nth(iterable: Iterable[_T], n: int) -> _T | None: ...
84
+ @overload
85
+ def nth(iterable: Iterable[_T], n: int, default: _U) -> _T | _U: ...
86
+ def all_equal(
87
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
88
+ ) -> bool: ...
89
+ def quantify(
90
+ iterable: Iterable[_T], pred: Callable[[_T], bool] = ...
91
+ ) -> int: ...
92
+ def pad_none(iterable: Iterable[_T]) -> Iterator[_T | None]: ...
93
+ def padnone(iterable: Iterable[_T]) -> Iterator[_T | None]: ...
94
+ def ncycles(iterable: Iterable[_T], n: int) -> Iterator[_T]: ...
95
+ def dotproduct(vec1: Iterable[_T1], vec2: Iterable[_T2]) -> Any: ...
96
+ def flatten(listOfLists: Iterable[Iterable[_T]]) -> Iterator[_T]: ...
97
+ def repeatfunc(
98
+ func: Callable[..., _U], times: int | None = ..., *args: Any
99
+ ) -> Iterator[_U]: ...
100
+ def grouper(
101
+ iterable: Iterable[_T],
102
+ n: int,
103
+ incomplete: str = ...,
104
+ fillvalue: _U = ...,
105
+ ) -> Iterator[tuple[_T | _U, ...]]: ...
106
+ def roundrobin(*iterables: Iterable[_T]) -> Iterator[_T]: ...
107
+ def partition(
108
+ pred: Callable[[_T], object] | None, iterable: Iterable[_T]
109
+ ) -> tuple[Iterator[_T], Iterator[_T]]: ...
110
+ def powerset(iterable: Iterable[_T]) -> Iterator[tuple[_T, ...]]: ...
111
+ def unique_everseen(
112
+ iterable: Iterable[_T], key: Callable[[_T], _U] | None = ...
113
+ ) -> Iterator[_T]: ...
114
+ def unique_justseen(
115
+ iterable: Iterable[_T], key: Callable[[_T], object] | None = ...
116
+ ) -> Iterator[_T]: ...
117
+ def unique(
118
+ iterable: Iterable[_T],
119
+ key: Callable[[_T], object] | None = ...,
120
+ reverse: bool = False,
121
+ ) -> Iterator[_T]: ...
122
+ @overload
123
+ def iter_except(
124
+ func: Callable[[], _T],
125
+ exception: type[BaseException] | tuple[type[BaseException], ...],
126
+ first: None = ...,
127
+ ) -> Iterator[_T]: ...
128
+ @overload
129
+ def iter_except(
130
+ func: Callable[[], _T],
131
+ exception: type[BaseException] | tuple[type[BaseException], ...],
132
+ first: Callable[[], _U],
133
+ ) -> Iterator[_T | _U]: ...
134
+ @overload
135
+ def first_true(
136
+ iterable: Iterable[_T], *, pred: Callable[[_T], object] | None = ...
137
+ ) -> _T | None: ...
138
+ @overload
139
+ def first_true(
140
+ iterable: Iterable[_T],
141
+ default: _U,
142
+ pred: Callable[[_T], object] | None = ...,
143
+ ) -> _T | _U: ...
144
+ def random_product(
145
+ *iterables: Iterable[_T], repeat: int = ...
146
+ ) -> tuple[_T, ...]: ...
147
+ def random_permutation(
148
+ iterable: Iterable[_T], r: int | None = ...
149
+ ) -> tuple[_T, ...]: ...
150
+ def random_combination(iterable: Iterable[_T], r: int) -> tuple[_T, ...]: ...
151
+ def random_combination_with_replacement(
152
+ iterable: Iterable[_T], r: int
153
+ ) -> tuple[_T, ...]: ...
154
+ def nth_combination(
155
+ iterable: Iterable[_T], r: int, index: int
156
+ ) -> tuple[_T, ...]: ...
157
+ def prepend(value: _T, iterator: Iterable[_U]) -> Iterator[_T | _U]: ...
158
+ def convolve(signal: Iterable[_T], kernel: Iterable[_T]) -> Iterator[_T]: ...
159
+ def before_and_after(
160
+ predicate: Callable[[_T], bool], it: Iterable[_T]
161
+ ) -> tuple[Iterator[_T], Iterator[_T]]: ...
162
+ def triplewise(iterable: Iterable[_T]) -> Iterator[tuple[_T, _T, _T]]: ...
163
+ def sliding_window(
164
+ iterable: Iterable[_T], n: int
165
+ ) -> Iterator[tuple[_T, ...]]: ...
166
+ def subslices(iterable: Iterable[_T]) -> Iterator[list[_T]]: ...
167
+ def polynomial_from_roots(roots: Sequence[_T]) -> list[_T]: ...
168
+ def iter_index(
169
+ iterable: Iterable[_T],
170
+ value: Any,
171
+ start: int | None = ...,
172
+ stop: int | None = ...,
173
+ ) -> Iterator[int]: ...
174
+ def sieve(n: int) -> Iterator[int]: ...
175
+ def _batched(
176
+ iterable: Iterable[_T], n: int, *, strict: bool = False
177
+ ) -> Iterator[tuple[_T, ...]]: ...
178
+
179
+ batched = _batched
180
+
181
+ def transpose(
182
+ it: Iterable[Iterable[_T]],
183
+ ) -> Iterator[tuple[_T, ...]]: ...
184
+ @overload
185
+ def reshape(
186
+ matrix: Iterable[Iterable[_T]], shape: int
187
+ ) -> Iterator[tuple[_T, ...]]: ...
188
+ @overload
189
+ def reshape(matrix: Iterable[Any], shape: Iterable[int]) -> Iterator[Any]: ...
190
+ def matmul(m1: Sequence[_T], m2: Sequence[_T]) -> Iterator[tuple[_T]]: ...
191
+ def _factor_trial(n: int) -> Iterator[int]: ...
192
+ def _factor_pollard(n: int) -> int: ...
193
+ def factor(n: int) -> Iterator[int]: ...
194
+ def polynomial_eval(coefficients: Sequence[_T], x: _U) -> _U: ...
195
+ def sum_of_squares(it: Iterable[_T]) -> _T: ...
196
+ def polynomial_derivative(coefficients: Sequence[_T]) -> list[_T]: ...
197
+ def totient(n: int) -> int: ...
198
+ def _shift_to_odd(n: int) -> tuple[int, int]: ...
199
+ def _strong_probable_prime(n: int, base: int) -> bool: ...
200
+ def is_prime(n: int) -> bool: ...
201
+ def loops(n: int) -> Iterator[None]: ...
202
+ def multinomial(*counts: int) -> int: ...
203
+ def running_mean(iterable: Iterable[_NumberT]) -> Iterator[_NumberT]: ...
204
+ def running_median(
205
+ iterable: Iterable[_NumberT], *, maxlen: int | None = ...
206
+ ) -> Iterator[_NumberT]: ...
207
+ def random_derangement(iterable: Iterable[_T]) -> tuple[_T, ...]: ...
examples/repo2env-more-itertools-bug-intersperse-staged/pyproject.toml ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["flit_core >=3.12,<4"]
3
+ build-backend = "flit_core.buildapi"
4
+
5
+ [project]
6
+ name = "more-itertools"
7
+ authors = [{name = "Erik Rose", email = "erikrose@grinchcentral.com"}]
8
+ readme = "README.rst"
9
+ requires-python = ">=3.10"
10
+ license = "MIT"
11
+ license-files = ["LICENSE"]
12
+ keywords = [
13
+ "itertools",
14
+ "iterator",
15
+ "iteration",
16
+ "filter",
17
+ "peek",
18
+ "peekable",
19
+ "chunk",
20
+ "chunked",
21
+ ]
22
+ classifiers = [
23
+ "Development Status :: 5 - Production/Stable",
24
+ "Intended Audience :: Developers",
25
+ "Natural Language :: English",
26
+ "Programming Language :: Python :: 3",
27
+ "Programming Language :: Python :: 3.10",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Programming Language :: Python :: 3.13",
31
+ "Programming Language :: Python :: 3.14",
32
+ "Programming Language :: Python :: 3 :: Only",
33
+ "Programming Language :: Python :: Implementation :: CPython",
34
+ "Programming Language :: Python :: Implementation :: PyPy",
35
+ "Topic :: Software Development :: Libraries",
36
+ ]
37
+ dynamic = ["version", "description"]
38
+
39
+ [project.urls]
40
+ Homepage = "https://github.com/more-itertools/more-itertools"
41
+ Documentation = "https://more-itertools.readthedocs.io/en/stable/"
42
+
43
+ [tool.flit.module]
44
+ name = "more_itertools"
45
+
46
+ [tool.ruff]
47
+ indent-width = 4
48
+ line-length = 79
49
+ target-version = "py310"
50
+
51
+ [tool.ruff.format]
52
+ quote-style = "preserve"
53
+
54
+ [tool.ruff.lint]
55
+ ignore = ["E731", "E741"]
56
+
57
+ [tool.ruff.lint.per-file-ignores]
58
+ "__init__.py" = ["F403"]
59
+ "__init__.pyi" = ["F403"]
examples/repo2env-more-itertools-bug-intersperse-staged/repo2env_manifest.json ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "repo_name": "repo2env-more-itertools-bug-intersperse-staged",
3
+ "repo_root": "/private/var/folders/6p/6329_nhs4pb7bys_knmsj99w0000gn/T/repo2env-stage-05qr_odg/repo2env-more-itertools-bug-intersperse-staged",
4
+ "python_files": [
5
+ "docs/conf.py",
6
+ "more_itertools/__init__.py",
7
+ "more_itertools/more.py",
8
+ "more_itertools/recipes.py",
9
+ "tests/__init__.py",
10
+ "tests/test_more.py",
11
+ "tests/test_recipes.py"
12
+ ],
13
+ "source_files": [
14
+ "docs/conf.py",
15
+ "more_itertools/__init__.py",
16
+ "more_itertools/more.py",
17
+ "more_itertools/recipes.py"
18
+ ],
19
+ "test_files": [
20
+ "tests/__init__.py",
21
+ "tests/test_more.py",
22
+ "tests/test_recipes.py"
23
+ ],
24
+ "packages": [
25
+ "more_itertools",
26
+ "tests"
27
+ ],
28
+ "pytest_config_files": [
29
+ "pyproject.toml",
30
+ "setup.cfg",
31
+ "tox.ini"
32
+ ],
33
+ "layout": "flat",
34
+ "default_test_dir": "tests"
35
+ }
examples/repo2env-more-itertools-bug-intersperse-staged/requirements/development.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ --requirement testing.txt
2
+ --requirement typechecks.txt
3
+ --requirement ../docs/requirements.txt
4
+ --requirement packaging.txt
examples/repo2env-more-itertools-bug-intersperse-staged/requirements/packaging.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ flit
2
+ setuptools
3
+ twine
4
+ wheel
examples/repo2env-more-itertools-bug-intersperse-staged/requirements/testing.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ coverage
2
+ ruff
examples/repo2env-more-itertools-bug-intersperse-staged/requirements/typechecks.txt ADDED
@@ -0,0 +1 @@
 
 
1
+ mypy
examples/repo2env-more-itertools-bug-intersperse-staged/setup.cfg ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [bumpversion]
2
+ current_version = 10.8.0
3
+ commit = True
4
+ tag = False
5
+ files = more_itertools/__init__.py
6
+
7
+ [mypy]
8
+ check_untyped_defs = true
9
+ disallow_any_generics = true
10
+ disallow_incomplete_defs = true
11
+ disallow_subclassing_any = true
12
+ disallow_untyped_calls = true
13
+ disallow_untyped_decorators = true
14
+ disallow_untyped_defs = true
15
+ ignore_missing_imports = true
16
+ no_implicit_optional = true
17
+ show_error_codes = true
18
+ strict_equality = true
19
+ warn_redundant_casts = true
20
+ warn_return_any = true
21
+ warn_unreachable = true
22
+ warn_unused_configs = true
23
+ warn_unused_ignores = true
24
+
25
+ [mypy-tests.*]
26
+ disallow_untyped_defs = false
examples/repo2env-more-itertools-bug-intersperse-staged/task_spec.json ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "spec_version": 1,
3
+ "instance_id": "repo2env-more-itertools-bug-intersperse-staged-repo-editing",
4
+ "task_mode": "repo_editing",
5
+ "title": "Fix intersperse() prepending filler element at start of output",
6
+ "problem_statement": "The `intersperse` function in `more_itertools` is incorrectly prepending the filler element at the beginning of the output when called with the default `n=1` parameter.\n\nFor example:\n```python\n>>> list(intersperse('!', [1, 2, 3, 4, 5]))\n['!', 1, '!', 2, '!', 3, '!', 4, '!', 5] # BUG: filler appears at start\n```\n\nExpected behavior:\n```python\n>>> list(intersperse('!', [1, 2, 3, 4, 5]))\n[1, '!', 2, '!', 3, '!', 4, '!', 5] # filler only between items\n```\n\nThe bug only affects the `n=1` (default) code path. When `n >= 2`, intersperse works correctly. The issue is in `more_itertools/more.py` in the `intersperse` function \u2014 the `islice` call that strips the leading filler element from the interleaved sequence uses the wrong start index.",
7
+ "hints_text": "Use small edits, rerun tests, and stop when further changes are not helping.",
8
+ "install_config": {
9
+ "strategy": "editable",
10
+ "commands": [
11
+ "pip install --no-cache-dir 'flit_core >=3.12,<4'",
12
+ "pip install --no-cache-dir --no-build-isolation -e {repo_dir}"
13
+ ],
14
+ "detected_files": [
15
+ "pyproject.toml"
16
+ ],
17
+ "notes": []
18
+ },
19
+ "test_command": "python -m pytest tests/test_more.py::IntersperseTest",
20
+ "test_targets": [
21
+ "tests/test_more.py::IntersperseTest"
22
+ ],
23
+ "starter_paths": [
24
+ "more_itertools/more.py"
25
+ ],
26
+ "allow_source_edits": true,
27
+ "metadata": {
28
+ "repo_name": "repo2env-more-itertools-bug-intersperse-staged"
29
+ }
30
+ }
examples/repo2env-more-itertools-bug-intersperse-staged/tests/__init__.py ADDED
File without changes
examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_more.py ADDED
The diff for this file is too large to render. See raw diff
 
examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_recipes.py ADDED
@@ -0,0 +1,1606 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from collections import Counter
2
+ from decimal import Decimal
3
+ from doctest import DocTestSuite
4
+ from fractions import Fraction
5
+ from functools import reduce
6
+ from itertools import (
7
+ combinations,
8
+ count,
9
+ groupby,
10
+ permutations,
11
+ islice,
12
+ pairwise,
13
+ )
14
+ from operator import mul, eq
15
+ from math import comb, prod, factorial
16
+ from statistics import mean
17
+ from unittest import TestCase
18
+ from unittest.mock import patch
19
+
20
+ import more_itertools as mi
21
+ import statistics
22
+ import random
23
+
24
+
25
+ def load_tests(loader, tests, ignore):
26
+ # Add the doctests
27
+ tests.addTests(DocTestSuite('more_itertools.recipes'))
28
+ return tests
29
+
30
+
31
+ class TakeTests(TestCase):
32
+ """Tests for ``take()``"""
33
+
34
+ def test_simple_take(self):
35
+ """Test basic usage"""
36
+ t = mi.take(5, range(10))
37
+ self.assertEqual(t, [0, 1, 2, 3, 4])
38
+
39
+ def test_null_take(self):
40
+ """Check the null case"""
41
+ t = mi.take(0, range(10))
42
+ self.assertEqual(t, [])
43
+
44
+ def test_negative_take(self):
45
+ """Make sure taking negative items results in a ValueError"""
46
+ self.assertRaises(ValueError, lambda: mi.take(-3, range(10)))
47
+
48
+ def test_take_too_much(self):
49
+ """Taking more than an iterator has remaining should return what the
50
+ iterator has remaining.
51
+
52
+ """
53
+ t = mi.take(10, range(5))
54
+ self.assertEqual(t, [0, 1, 2, 3, 4])
55
+
56
+
57
+ class TabulateTests(TestCase):
58
+ """Tests for ``tabulate()``"""
59
+
60
+ def test_simple_tabulate(self):
61
+ """Test the happy path"""
62
+ t = mi.tabulate(lambda x: x)
63
+ f = tuple([next(t) for _ in range(3)])
64
+ self.assertEqual(f, (0, 1, 2))
65
+
66
+ def test_count(self):
67
+ """Ensure tabulate accepts specific count"""
68
+ t = mi.tabulate(lambda x: 2 * x, -1)
69
+ f = (next(t), next(t), next(t))
70
+ self.assertEqual(f, (-2, 0, 2))
71
+
72
+
73
+ class TailTests(TestCase):
74
+ """Tests for ``tail()``"""
75
+
76
+ def test_iterator_greater(self):
77
+ """Length of iterator is greater than requested tail"""
78
+ self.assertEqual(list(mi.tail(3, iter('ABCDEFG'))), list('EFG'))
79
+
80
+ def test_iterator_equal(self):
81
+ """Length of iterator is equal to the requested tail"""
82
+ self.assertEqual(list(mi.tail(7, iter('ABCDEFG'))), list('ABCDEFG'))
83
+
84
+ def test_iterator_less(self):
85
+ """Length of iterator is less than requested tail"""
86
+ self.assertEqual(list(mi.tail(8, iter('ABCDEFG'))), list('ABCDEFG'))
87
+
88
+ def test_sized_greater(self):
89
+ """Length of sized iterable is greater than requested tail"""
90
+ self.assertEqual(list(mi.tail(3, 'ABCDEFG')), list('EFG'))
91
+
92
+ def test_sized_equal(self):
93
+ """Length of sized iterable is less than requested tail"""
94
+ self.assertEqual(list(mi.tail(7, 'ABCDEFG')), list('ABCDEFG'))
95
+
96
+ def test_sized_less(self):
97
+ """Length of sized iterable is less than requested tail"""
98
+ self.assertEqual(list(mi.tail(8, 'ABCDEFG')), list('ABCDEFG'))
99
+
100
+
101
+ class ConsumeTests(TestCase):
102
+ """Tests for ``consume()``"""
103
+
104
+ def test_sanity(self):
105
+ """Test basic functionality"""
106
+ r = (x for x in range(10))
107
+ mi.consume(r, 3)
108
+ self.assertEqual(3, next(r))
109
+
110
+ def test_null_consume(self):
111
+ """Check the null case"""
112
+ r = (x for x in range(10))
113
+ mi.consume(r, 0)
114
+ self.assertEqual(0, next(r))
115
+
116
+ def test_negative_consume(self):
117
+ """Check that negative consumption throws an error"""
118
+ r = (x for x in range(10))
119
+ self.assertRaises(ValueError, lambda: mi.consume(r, -1))
120
+
121
+ def test_total_consume(self):
122
+ """Check that iterator is totally consumed by default"""
123
+ r = (x for x in range(10))
124
+ mi.consume(r)
125
+ self.assertRaises(StopIteration, lambda: next(r))
126
+
127
+
128
+ class NthTests(TestCase):
129
+ """Tests for ``nth()``"""
130
+
131
+ def test_basic(self):
132
+ """Make sure the nth item is returned"""
133
+ l = range(10)
134
+ for i, v in enumerate(l):
135
+ self.assertEqual(mi.nth(l, i), v)
136
+
137
+ def test_default(self):
138
+ """Ensure a default value is returned when nth item not found"""
139
+ l = range(3)
140
+ self.assertEqual(mi.nth(l, 100, "zebra"), "zebra")
141
+
142
+ def test_negative_item_raises(self):
143
+ """Ensure asking for a negative item raises an exception"""
144
+ self.assertRaises(ValueError, lambda: mi.nth(range(10), -3))
145
+
146
+
147
+ class AllEqualTests(TestCase):
148
+ def test_true(self):
149
+ self.assertTrue(mi.all_equal('aaaaaa'))
150
+ self.assertTrue(mi.all_equal([0, 0, 0, 0]))
151
+
152
+ def test_false(self):
153
+ self.assertFalse(mi.all_equal('aaaaab'))
154
+ self.assertFalse(mi.all_equal([0, 0, 0, 1]))
155
+
156
+ def test_tricky(self):
157
+ items = [1, complex(1, 0), 1.0]
158
+ self.assertTrue(mi.all_equal(items))
159
+
160
+ def test_empty(self):
161
+ self.assertTrue(mi.all_equal(''))
162
+ self.assertTrue(mi.all_equal([]))
163
+
164
+ def test_one(self):
165
+ self.assertTrue(mi.all_equal('0'))
166
+ self.assertTrue(mi.all_equal([0]))
167
+
168
+ def test_key(self):
169
+ self.assertTrue(mi.all_equal('4٤໔4৪', key=int))
170
+ self.assertFalse(mi.all_equal('Abc', key=str.casefold))
171
+
172
+ @patch('more_itertools.recipes.groupby', autospec=True)
173
+ def test_groupby_calls(self, mock_groupby):
174
+ next_count = 0
175
+
176
+ class _groupby(groupby):
177
+ def __next__(true_self):
178
+ nonlocal next_count
179
+ next_count += 1
180
+ return super().__next__()
181
+
182
+ mock_groupby.side_effect = _groupby
183
+ iterable = iter('aaaaa')
184
+ self.assertTrue(mi.all_equal(iterable))
185
+ self.assertEqual(list(iterable), [])
186
+ self.assertEqual(next_count, 2)
187
+
188
+
189
+ class QuantifyTests(TestCase):
190
+ """Tests for ``quantify()``"""
191
+
192
+ def test_happy_path(self):
193
+ """Make sure True count is returned"""
194
+ q = [True, False, True]
195
+ self.assertEqual(mi.quantify(q), 2)
196
+
197
+ def test_custom_predicate(self):
198
+ """Ensure non-default predicates return as expected"""
199
+ q = range(10)
200
+ self.assertEqual(mi.quantify(q, lambda x: x % 2 == 0), 5)
201
+
202
+
203
+ class PadnoneTests(TestCase):
204
+ def test_basic(self):
205
+ iterable = range(2)
206
+ for func in (mi.pad_none, mi.padnone):
207
+ with self.subTest(func=func):
208
+ p = func(iterable)
209
+ self.assertEqual(
210
+ [0, 1, None, None], [next(p) for _ in range(4)]
211
+ )
212
+
213
+
214
+ class NcyclesTests(TestCase):
215
+ """Tests for ``nyclces()``"""
216
+
217
+ def test_happy_path(self):
218
+ """cycle a sequence three times"""
219
+ r = ["a", "b", "c"]
220
+ n = mi.ncycles(r, 3)
221
+ self.assertEqual(
222
+ ["a", "b", "c", "a", "b", "c", "a", "b", "c"], list(n)
223
+ )
224
+
225
+ def test_null_case(self):
226
+ """asking for 0 cycles should return an empty iterator"""
227
+ n = mi.ncycles(range(100), 0)
228
+ self.assertRaises(StopIteration, lambda: next(n))
229
+
230
+ def test_pathological_case(self):
231
+ """asking for negative cycles should return an empty iterator"""
232
+ n = mi.ncycles(range(100), -10)
233
+ self.assertRaises(StopIteration, lambda: next(n))
234
+
235
+
236
+ class DotproductTests(TestCase):
237
+ """Tests for ``dotproduct()``'"""
238
+
239
+ def test_happy_path(self):
240
+ """simple dotproduct example"""
241
+ self.assertEqual(400, mi.dotproduct([10, 10], [20, 20]))
242
+
243
+
244
+ class FlattenTests(TestCase):
245
+ """Tests for ``flatten()``"""
246
+
247
+ def test_basic_usage(self):
248
+ """ensure list of lists is flattened one level"""
249
+ f = [[0, 1, 2], [3, 4, 5]]
250
+ self.assertEqual(list(range(6)), list(mi.flatten(f)))
251
+
252
+ def test_single_level(self):
253
+ """ensure list of lists is flattened only one level"""
254
+ f = [[0, [1, 2]], [[3, 4], 5]]
255
+ self.assertEqual([0, [1, 2], [3, 4], 5], list(mi.flatten(f)))
256
+
257
+
258
+ class RepeatfuncTests(TestCase):
259
+ """Tests for ``repeatfunc()``"""
260
+
261
+ def test_simple_repeat(self):
262
+ """test simple repeated functions"""
263
+ r = mi.repeatfunc(lambda: 5)
264
+ self.assertEqual([5, 5, 5, 5, 5], [next(r) for _ in range(5)])
265
+
266
+ def test_finite_repeat(self):
267
+ """ensure limited repeat when times is provided"""
268
+ r = mi.repeatfunc(lambda: 5, times=5)
269
+ self.assertEqual([5, 5, 5, 5, 5], list(r))
270
+
271
+ def test_added_arguments(self):
272
+ """ensure arguments are applied to the function"""
273
+ r = mi.repeatfunc(lambda x: x, 2, 3)
274
+ self.assertEqual([3, 3], list(r))
275
+
276
+ def test_null_times(self):
277
+ """repeat 0 should return an empty iterator"""
278
+ r = mi.repeatfunc(range, 0, 3)
279
+ self.assertRaises(StopIteration, lambda: next(r))
280
+
281
+
282
+ class GrouperTests(TestCase):
283
+ def test_basic(self):
284
+ seq = 'ABCDEF'
285
+ for n, expected in [
286
+ (3, [('A', 'B', 'C'), ('D', 'E', 'F')]),
287
+ (4, [('A', 'B', 'C', 'D'), ('E', 'F', None, None)]),
288
+ (5, [('A', 'B', 'C', 'D', 'E'), ('F', None, None, None, None)]),
289
+ (6, [('A', 'B', 'C', 'D', 'E', 'F')]),
290
+ (7, [('A', 'B', 'C', 'D', 'E', 'F', None)]),
291
+ ]:
292
+ with self.subTest(n=n):
293
+ actual = list(mi.grouper(iter(seq), n))
294
+ self.assertEqual(actual, expected)
295
+
296
+ def test_fill(self):
297
+ seq = 'ABCDEF'
298
+ fillvalue = 'x'
299
+ for n, expected in [
300
+ (1, ['A', 'B', 'C', 'D', 'E', 'F']),
301
+ (2, ['AB', 'CD', 'EF']),
302
+ (3, ['ABC', 'DEF']),
303
+ (4, ['ABCD', 'EFxx']),
304
+ (5, ['ABCDE', 'Fxxxx']),
305
+ (6, ['ABCDEF']),
306
+ (7, ['ABCDEFx']),
307
+ ]:
308
+ with self.subTest(n=n):
309
+ it = mi.grouper(
310
+ iter(seq), n, incomplete='fill', fillvalue=fillvalue
311
+ )
312
+ actual = [''.join(x) for x in it]
313
+ self.assertEqual(actual, expected)
314
+
315
+ def test_ignore(self):
316
+ seq = 'ABCDEF'
317
+ for n, expected in [
318
+ (1, ['A', 'B', 'C', 'D', 'E', 'F']),
319
+ (2, ['AB', 'CD', 'EF']),
320
+ (3, ['ABC', 'DEF']),
321
+ (4, ['ABCD']),
322
+ (5, ['ABCDE']),
323
+ (6, ['ABCDEF']),
324
+ (7, []),
325
+ ]:
326
+ with self.subTest(n=n):
327
+ it = mi.grouper(iter(seq), n, incomplete='ignore')
328
+ actual = [''.join(x) for x in it]
329
+ self.assertEqual(actual, expected)
330
+
331
+ def test_strict(self):
332
+ seq = 'ABCDEF'
333
+ for n, expected in [
334
+ (1, ['A', 'B', 'C', 'D', 'E', 'F']),
335
+ (2, ['AB', 'CD', 'EF']),
336
+ (3, ['ABC', 'DEF']),
337
+ (6, ['ABCDEF']),
338
+ ]:
339
+ with self.subTest(n=n):
340
+ it = mi.grouper(iter(seq), n, incomplete='strict')
341
+ actual = [''.join(x) for x in it]
342
+ self.assertEqual(actual, expected)
343
+
344
+ def test_strict_fails(self):
345
+ seq = 'ABCDEF'
346
+ for n in [4, 5, 7]:
347
+ with self.subTest(n=n):
348
+ with self.assertRaises(ValueError):
349
+ list(mi.grouper(iter(seq), n, incomplete='strict'))
350
+
351
+ def test_invalid_incomplete(self):
352
+ with self.assertRaises(ValueError):
353
+ list(mi.grouper('ABCD', 3, incomplete='bogus'))
354
+
355
+
356
+ class RoundrobinTests(TestCase):
357
+ """Tests for ``roundrobin()``"""
358
+
359
+ def test_even_groups(self):
360
+ """Ensure ordered output from evenly populated iterables"""
361
+ self.assertEqual(
362
+ list(mi.roundrobin('ABC', [1, 2, 3], range(3))),
363
+ ['A', 1, 0, 'B', 2, 1, 'C', 3, 2],
364
+ )
365
+
366
+ def test_uneven_groups(self):
367
+ """Ensure ordered output from unevenly populated iterables"""
368
+ self.assertEqual(
369
+ list(mi.roundrobin('ABCD', [1, 2], range(0))),
370
+ ['A', 1, 'B', 2, 'C', 'D'],
371
+ )
372
+
373
+
374
+ class PartitionTests(TestCase):
375
+ """Tests for ``partition()``"""
376
+
377
+ def test_bool(self):
378
+ lesser, greater = mi.partition(lambda x: x > 5, range(10))
379
+ self.assertEqual(list(lesser), [0, 1, 2, 3, 4, 5])
380
+ self.assertEqual(list(greater), [6, 7, 8, 9])
381
+
382
+ def test_arbitrary(self):
383
+ divisibles, remainders = mi.partition(lambda x: x % 3, range(10))
384
+ self.assertEqual(list(divisibles), [0, 3, 6, 9])
385
+ self.assertEqual(list(remainders), [1, 2, 4, 5, 7, 8])
386
+
387
+ def test_pred_is_none(self):
388
+ falses, trues = mi.partition(None, range(3))
389
+ self.assertEqual(list(falses), [0])
390
+ self.assertEqual(list(trues), [1, 2])
391
+
392
+
393
+ class PowersetTests(TestCase):
394
+ """Tests for ``powerset()``"""
395
+
396
+ def test_combinatorics(self):
397
+ """Ensure a proper enumeration"""
398
+ p = mi.powerset([1, 2, 3])
399
+ self.assertEqual(
400
+ list(p), [(), (1,), (2,), (3,), (1, 2), (1, 3), (2, 3), (1, 2, 3)]
401
+ )
402
+
403
+
404
+ class UniqueEverseenTests(TestCase):
405
+ def test_everseen(self):
406
+ u = mi.unique_everseen('AAAABBBBCCDAABBB')
407
+ self.assertEqual(['A', 'B', 'C', 'D'], list(u))
408
+
409
+ def test_custom_key(self):
410
+ u = mi.unique_everseen('aAbACCc', key=str.lower)
411
+ self.assertEqual(list('abC'), list(u))
412
+
413
+ def test_unhashable(self):
414
+ iterable = ['a', [1, 2, 3], [1, 2, 3], 'a']
415
+ u = mi.unique_everseen(iterable)
416
+ self.assertEqual(list(u), ['a', [1, 2, 3]])
417
+
418
+ def test_unhashable_key(self):
419
+ iterable = ['a', [1, 2, 3], [1, 2, 3], 'a']
420
+ u = mi.unique_everseen(iterable, key=lambda x: x)
421
+ self.assertEqual(list(u), ['a', [1, 2, 3]])
422
+
423
+
424
+ class UniqueJustseenTests(TestCase):
425
+ def test_justseen(self):
426
+ u = mi.unique_justseen('AAAABBBCCDABB')
427
+ self.assertEqual(list('ABCDAB'), list(u))
428
+
429
+ def test_custom_key(self):
430
+ u = mi.unique_justseen('AABCcAD', str.lower)
431
+ self.assertEqual(list('ABCAD'), list(u))
432
+
433
+
434
+ class UniqueTests(TestCase):
435
+ def test_basic(self):
436
+ iterable = [0, 1, 1, 8, 9, 9, 9, 8, 8, 1, 9, 9]
437
+ actual = list(mi.unique(iterable))
438
+ expected = [0, 1, 8, 9]
439
+ self.assertEqual(actual, expected)
440
+
441
+ def test_key(self):
442
+ iterable = ['1', '1', '10', '10', '2', '2', '20', '20']
443
+ actual = list(mi.unique(iterable, key=int))
444
+ expected = ['1', '2', '10', '20']
445
+ self.assertEqual(actual, expected)
446
+
447
+ def test_reverse(self):
448
+ iterable = ['1', '1', '10', '10', '2', '2', '20', '20']
449
+ actual = list(mi.unique(iterable, key=int, reverse=True))
450
+ expected = ['20', '10', '2', '1']
451
+ self.assertEqual(actual, expected)
452
+
453
+
454
+ class IterExceptTests(TestCase):
455
+ """Tests for ``iter_except()``"""
456
+
457
+ def test_exact_exception(self):
458
+ """ensure the exact specified exception is caught"""
459
+ l = [1, 2, 3]
460
+ i = mi.iter_except(l.pop, IndexError)
461
+ self.assertEqual(list(i), [3, 2, 1])
462
+
463
+ def test_generic_exception(self):
464
+ """ensure the generic exception can be caught"""
465
+ l = [1, 2]
466
+ i = mi.iter_except(l.pop, Exception)
467
+ self.assertEqual(list(i), [2, 1])
468
+
469
+ def test_uncaught_exception_is_raised(self):
470
+ """ensure a non-specified exception is raised"""
471
+ l = [1, 2, 3]
472
+ i = mi.iter_except(l.pop, KeyError)
473
+ self.assertRaises(IndexError, lambda: list(i))
474
+
475
+ def test_first(self):
476
+ """ensure first is run before the function"""
477
+ l = [1, 2, 3]
478
+ f = lambda: 25
479
+ i = mi.iter_except(l.pop, IndexError, f)
480
+ self.assertEqual(list(i), [25, 3, 2, 1])
481
+
482
+ def test_multiple(self):
483
+ """ensure can catch multiple exceptions"""
484
+
485
+ class Fiz(Exception):
486
+ pass
487
+
488
+ class Buzz(Exception):
489
+ pass
490
+
491
+ i = 0
492
+
493
+ def fizbuzz():
494
+ nonlocal i
495
+ i += 1
496
+ if i % 3 == 0:
497
+ raise Fiz
498
+ if i % 5 == 0:
499
+ raise Buzz
500
+ return i
501
+
502
+ expected = ([1, 2], [4], [], [7, 8], [])
503
+ for x in expected:
504
+ self.assertEqual(list(mi.iter_except(fizbuzz, (Fiz, Buzz))), x)
505
+
506
+
507
+ class FirstTrueTests(TestCase):
508
+ """Tests for ``first_true()``"""
509
+
510
+ def test_something_true(self):
511
+ """Test with no keywords"""
512
+ self.assertEqual(mi.first_true(range(10)), 1)
513
+
514
+ def test_nothing_true(self):
515
+ """Test default return value."""
516
+ self.assertIsNone(mi.first_true([0, 0, 0]))
517
+
518
+ def test_default(self):
519
+ """Test with a default keyword"""
520
+ self.assertEqual(mi.first_true([0, 0, 0], default='!'), '!')
521
+
522
+ def test_pred(self):
523
+ """Test with a custom predicate"""
524
+ self.assertEqual(
525
+ mi.first_true([2, 4, 6], pred=lambda x: x % 3 == 0), 6
526
+ )
527
+
528
+
529
+ class RandomProductTests(TestCase):
530
+ """Tests for ``random_product()``
531
+
532
+ Since random.choice() has different results with the same seed across
533
+ python versions 2.x and 3.x, these tests use highly probably events to
534
+ create predictable outcomes across platforms.
535
+ """
536
+
537
+ def test_simple_lists(self):
538
+ """Ensure that one item is chosen from each list in each pair.
539
+ Also ensure that each item from each list eventually appears in
540
+ the chosen combinations.
541
+
542
+ Odds are roughly 1 in 7.1 * 10e16 that one item from either list will
543
+ not be chosen after 100 samplings of one item from each list. Just to
544
+ be safe, better use a known random seed, too.
545
+
546
+ """
547
+ nums = [1, 2, 3]
548
+ lets = ['a', 'b', 'c']
549
+ n, m = zip(*[mi.random_product(nums, lets) for _ in range(100)])
550
+ n, m = set(n), set(m)
551
+ self.assertEqual(n, set(nums))
552
+ self.assertEqual(m, set(lets))
553
+ self.assertEqual(len(n), len(nums))
554
+ self.assertEqual(len(m), len(lets))
555
+
556
+ def test_list_with_repeat(self):
557
+ """ensure multiple items are chosen, and that they appear to be chosen
558
+ from one list then the next, in proper order.
559
+
560
+ """
561
+ nums = [1, 2, 3]
562
+ lets = ['a', 'b', 'c']
563
+ r = list(mi.random_product(nums, lets, repeat=100))
564
+ self.assertEqual(2 * 100, len(r))
565
+ n, m = set(r[::2]), set(r[1::2])
566
+ self.assertEqual(n, set(nums))
567
+ self.assertEqual(m, set(lets))
568
+ self.assertEqual(len(n), len(nums))
569
+ self.assertEqual(len(m), len(lets))
570
+
571
+ r = list(mi.random_product(iter(nums), iter(lets), repeat=100))
572
+ self.assertEqual(2 * 100, len(r))
573
+ n, m = set(r[::2]), set(r[1::2])
574
+ self.assertEqual(n, set(nums))
575
+ self.assertEqual(m, set(lets))
576
+ self.assertEqual(len(n), len(nums))
577
+ self.assertEqual(len(m), len(lets))
578
+
579
+
580
+ class RandomPermutationTests(TestCase):
581
+ """Tests for ``random_permutation()``"""
582
+
583
+ def test_full_permutation(self):
584
+ """ensure every item from the iterable is returned in a new ordering
585
+
586
+ 15 elements have a 1 in 1.3 * 10e12 of appearing in sorted order, so
587
+ we fix a seed value just to be sure.
588
+
589
+ """
590
+ i = range(15)
591
+ r = mi.random_permutation(i)
592
+ self.assertEqual(set(i), set(r))
593
+ if i == r:
594
+ raise AssertionError("Values were not permuted")
595
+
596
+ def test_partial_permutation(self):
597
+ """ensure all returned items are from the iterable, that the returned
598
+ permutation is of the desired length, and that all items eventually
599
+ get returned.
600
+
601
+ Sampling 100 permutations of length 5 from a set of 15 leaves a
602
+ (2/3)^100 chance that an item will not be chosen. Multiplied by 15
603
+ items, there is a 1 in 2.6e16 chance that at least 1 item will not
604
+ show up in the resulting output. Using a random seed will fix that.
605
+
606
+ """
607
+ items = range(15)
608
+ item_set = set(items)
609
+ all_items = set()
610
+ for _ in range(100):
611
+ permutation = mi.random_permutation(items, 5)
612
+ self.assertEqual(len(permutation), 5)
613
+ permutation_set = set(permutation)
614
+ self.assertLessEqual(permutation_set, item_set)
615
+ all_items |= permutation_set
616
+ self.assertEqual(all_items, item_set)
617
+
618
+
619
+ class RandomCombinationTests(TestCase):
620
+ """Tests for ``random_combination()``"""
621
+
622
+ def test_pseudorandomness(self):
623
+ """ensure different subsets of the iterable get returned over many
624
+ samplings of random combinations"""
625
+ items = range(15)
626
+ all_items = set()
627
+ for _ in range(50):
628
+ combination = mi.random_combination(items, 5)
629
+ all_items |= set(combination)
630
+ self.assertEqual(all_items, set(items))
631
+
632
+ def test_no_replacement(self):
633
+ """ensure that elements are sampled without replacement"""
634
+ items = range(15)
635
+ for _ in range(50):
636
+ combination = mi.random_combination(items, len(items))
637
+ self.assertEqual(len(combination), len(set(combination)))
638
+ self.assertRaises(
639
+ ValueError, lambda: mi.random_combination(items, len(items) + 1)
640
+ )
641
+
642
+
643
+ class RandomCombinationWithReplacementTests(TestCase):
644
+ """Tests for ``random_combination_with_replacement()``"""
645
+
646
+ def test_replacement(self):
647
+ """ensure that elements are sampled with replacement"""
648
+ items = range(5)
649
+ combo = mi.random_combination_with_replacement(items, len(items) * 2)
650
+ self.assertEqual(2 * len(items), len(combo))
651
+ if len(set(combo)) == len(combo):
652
+ raise AssertionError("Combination contained no duplicates")
653
+
654
+ def test_pseudorandomness(self):
655
+ """ensure different subsets of the iterable get returned over many
656
+ samplings of random combinations"""
657
+ items = range(15)
658
+ all_items = set()
659
+ for _ in range(50):
660
+ combination = mi.random_combination_with_replacement(items, 5)
661
+ all_items |= set(combination)
662
+ self.assertEqual(all_items, set(items))
663
+
664
+
665
+ class TestRandomDerangement(TestCase):
666
+ def test_basics(self):
667
+ word = tuple('love')
668
+ for _ in range(20):
669
+ d = mi.random_derangement(word)
670
+ self.assertEqual(len(d), len(word)) # Same size
671
+ self.assertEqual(set(d), set(word)) # Same values
672
+ self.assertFalse(any(map(eq, d, word))) # No fixed points
673
+
674
+ c = Counter(mi.random_derangement(word) for _ in range(10_000))
675
+
676
+ # Repeated calls generate exactly the set of valid derangements.
677
+ self.assertEqual(set(c), set(mi.derangements(word)))
678
+
679
+ # Check approximate equidistribution (all counts within eight
680
+ # standard deviations of the expected mean).
681
+ self.assertTrue(940 <= min(c.values()) and max(c.values()) <= 1280)
682
+
683
+ # Corner case for empty input
684
+ self.assertEqual(mi.random_derangement(''), ())
685
+
686
+ # Error case
687
+ with self.assertRaises(IndexError):
688
+ mi.random_derangement('x') # Not enough values
689
+
690
+
691
+ class NthCombinationTests(TestCase):
692
+ def test_basic(self):
693
+ iterable = 'abcdefg'
694
+ r = 4
695
+ for index, expected in enumerate(combinations(iterable, r)):
696
+ actual = mi.nth_combination(iterable, r, index)
697
+ self.assertEqual(actual, expected)
698
+
699
+ def test_long(self):
700
+ actual = mi.nth_combination(range(180), 4, 2000000)
701
+ expected = (2, 12, 35, 126)
702
+ self.assertEqual(actual, expected)
703
+
704
+ def test_invalid_r(self):
705
+ with self.assertRaises(ValueError):
706
+ mi.nth_combination([], -1, 0)
707
+ with self.assertRaises(IndexError):
708
+ mi.nth_combination('abc', 5, 0)
709
+
710
+ def test_invalid_index(self):
711
+ with self.assertRaises(IndexError):
712
+ mi.nth_combination('abcdefg', 3, -36)
713
+
714
+
715
+ class NthPermutationTests(TestCase):
716
+ def test_r_less_than_n(self):
717
+ iterable = 'abcde'
718
+ r = 4
719
+ for index, expected in enumerate(permutations(iterable, r)):
720
+ actual = mi.nth_permutation(iterable, r, index)
721
+ self.assertEqual(actual, expected)
722
+
723
+ def test_r_equal_to_n(self):
724
+ iterable = 'abcde'
725
+ for index, expected in enumerate(permutations(iterable)):
726
+ actual = mi.nth_permutation(iterable, None, index)
727
+ self.assertEqual(actual, expected)
728
+
729
+ def test_long(self):
730
+ iterable = tuple(range(180))
731
+ r = 4
732
+ index = 1000000
733
+ actual = mi.nth_permutation(iterable, r, index)
734
+ expected = mi.nth(permutations(iterable, r), index)
735
+ self.assertEqual(actual, expected)
736
+
737
+ def test_null(self):
738
+ actual = mi.nth_permutation([], 0, 0)
739
+ expected = tuple()
740
+ self.assertEqual(actual, expected)
741
+
742
+ def test_negative_index(self):
743
+ iterable = 'abcde'
744
+ r = 4
745
+ n = factorial(len(iterable)) // factorial(len(iterable) - r)
746
+ for index, expected in enumerate(permutations(iterable, r)):
747
+ actual = mi.nth_permutation(iterable, r, index - n)
748
+ self.assertEqual(actual, expected)
749
+
750
+ def test_invalid_index(self):
751
+ iterable = 'abcde'
752
+ r = 4
753
+ n = factorial(len(iterable)) // factorial(len(iterable) - r)
754
+ for index in [-1 - n, n + 1]:
755
+ with self.assertRaises(IndexError):
756
+ mi.nth_permutation(iterable, r, index)
757
+ with self.assertRaises(IndexError):
758
+ mi.nth_permutation('abc', 5, 0)
759
+
760
+ def test_invalid_r(self):
761
+ with self.assertRaises(ValueError):
762
+ mi.nth_permutation('abcde', -1, 0)
763
+
764
+
765
+ class PrependTests(TestCase):
766
+ def test_basic(self):
767
+ value = 'a'
768
+ iterator = iter('bcdefg')
769
+ actual = list(mi.prepend(value, iterator))
770
+ expected = list('abcdefg')
771
+ self.assertEqual(actual, expected)
772
+
773
+ def test_multiple(self):
774
+ value = 'ab'
775
+ iterator = iter('cdefg')
776
+ actual = tuple(mi.prepend(value, iterator))
777
+ expected = ('ab',) + tuple('cdefg')
778
+ self.assertEqual(actual, expected)
779
+
780
+
781
+ class Convolvetests(TestCase):
782
+ def test_moving_average(self):
783
+ signal = iter([10, 20, 30, 40, 50])
784
+ kernel = [0.5, 0.5]
785
+ actual = list(mi.convolve(signal, kernel))
786
+ expected = [
787
+ (10 + 0) / 2,
788
+ (20 + 10) / 2,
789
+ (30 + 20) / 2,
790
+ (40 + 30) / 2,
791
+ (50 + 40) / 2,
792
+ (0 + 50) / 2,
793
+ ]
794
+ self.assertEqual(actual, expected)
795
+
796
+ def test_derivative(self):
797
+ signal = iter([10, 20, 30, 40, 50])
798
+ kernel = [1, -1]
799
+ actual = list(mi.convolve(signal, kernel))
800
+ expected = [10 - 0, 20 - 10, 30 - 20, 40 - 30, 50 - 40, 0 - 50]
801
+ self.assertEqual(actual, expected)
802
+
803
+ def test_infinite_signal(self):
804
+ signal = count()
805
+ kernel = [1, -1]
806
+ actual = mi.take(5, mi.convolve(signal, kernel))
807
+ expected = [0, 1, 1, 1, 1]
808
+ self.assertEqual(actual, expected)
809
+
810
+
811
+ class BeforeAndAfterTests(TestCase):
812
+ def test_empty(self):
813
+ before, after = mi.before_and_after(bool, [])
814
+ self.assertEqual(list(before), [])
815
+ self.assertEqual(list(after), [])
816
+
817
+ def test_never_true(self):
818
+ before, after = mi.before_and_after(bool, [0, False, None, ''])
819
+ self.assertEqual(list(before), [])
820
+ self.assertEqual(list(after), [0, False, None, ''])
821
+
822
+ def test_never_false(self):
823
+ before, after = mi.before_and_after(bool, [1, True, Ellipsis, ' '])
824
+ self.assertEqual(list(before), [1, True, Ellipsis, ' '])
825
+ self.assertEqual(list(after), [])
826
+
827
+ def test_some_true(self):
828
+ before, after = mi.before_and_after(bool, [1, True, 0, False])
829
+ self.assertEqual(list(before), [1, True])
830
+ self.assertEqual(list(after), [0, False])
831
+
832
+ @staticmethod
833
+ def _group_events(events):
834
+ events = iter(events)
835
+
836
+ while True:
837
+ try:
838
+ operation = next(events)
839
+ except StopIteration:
840
+ break
841
+ assert operation in ["SUM", "MULTIPLY"]
842
+
843
+ # Here, the remainder `events` is passed into `before_and_after`
844
+ # again, which would be problematic if the remainder is a
845
+ # generator function (as in Python 3.10 itertools recipes), since
846
+ # that creates recursion. `itertools.chain` solves this problem.
847
+ numbers, events = mi.before_and_after(
848
+ lambda e: isinstance(e, int), events
849
+ )
850
+
851
+ yield (operation, numbers)
852
+
853
+ def test_nested_remainder(self):
854
+ events = ["SUM", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
855
+ events += ["MULTIPLY", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10] * 1000
856
+
857
+ for operation, numbers in self._group_events(events):
858
+ if operation == "SUM":
859
+ res = sum(numbers)
860
+ self.assertEqual(res, 55)
861
+ elif operation == "MULTIPLY":
862
+ res = reduce(lambda a, b: a * b, numbers)
863
+ self.assertEqual(res, 3628800)
864
+
865
+
866
+ class TriplewiseTests(TestCase):
867
+ def test_basic(self):
868
+ for iterable, expected in [
869
+ ([0], []),
870
+ ([0, 1], []),
871
+ ([0, 1, 2], [(0, 1, 2)]),
872
+ ([0, 1, 2, 3], [(0, 1, 2), (1, 2, 3)]),
873
+ ([0, 1, 2, 3, 4], [(0, 1, 2), (1, 2, 3), (2, 3, 4)]),
874
+ ]:
875
+ with self.subTest(expected=expected):
876
+ actual = list(mi.triplewise(iterable))
877
+ self.assertEqual(actual, expected)
878
+
879
+
880
+ class SlidingWindowTests(TestCase):
881
+ def test_islice_version(self):
882
+ for iterable, n, expected in [
883
+ ([], 1, []),
884
+ ([0], 1, [(0,)]),
885
+ ([0, 1], 1, [(0,), (1,)]),
886
+ ([0, 1, 2], 2, [(0, 1), (1, 2)]),
887
+ ([0, 1, 2], 3, [(0, 1, 2)]),
888
+ ([0, 1, 2], 4, []),
889
+ ([0, 1, 2, 3], 4, [(0, 1, 2, 3)]),
890
+ ([0, 1, 2, 3, 4], 4, [(0, 1, 2, 3), (1, 2, 3, 4)]),
891
+ ]:
892
+ with self.subTest(expected=expected):
893
+ actual = list(mi.sliding_window(iterable, n))
894
+ self.assertEqual(actual, expected)
895
+
896
+ def test_deque_version(self):
897
+ iterable = map(str, range(100))
898
+ all_windows = list(mi.sliding_window(iterable, 95))
899
+ self.assertEqual(all_windows[0], tuple(map(str, range(95))))
900
+ self.assertEqual(all_windows[-1], tuple(map(str, range(5, 100))))
901
+
902
+ def test_zero(self):
903
+ iterable = map(str, range(100))
904
+ with self.assertRaises(ValueError):
905
+ list(mi.sliding_window(iterable, 0))
906
+
907
+
908
+ class SubslicesTests(TestCase):
909
+ def test_basic(self):
910
+ for iterable, expected in [
911
+ ([], []),
912
+ ([1], [[1]]),
913
+ ([1, 2], [[1], [1, 2], [2]]),
914
+ (iter([1, 2]), [[1], [1, 2], [2]]),
915
+ ([2, 1], [[2], [2, 1], [1]]),
916
+ (
917
+ 'ABCD',
918
+ [
919
+ ['A'],
920
+ ['A', 'B'],
921
+ ['A', 'B', 'C'],
922
+ ['A', 'B', 'C', 'D'],
923
+ ['B'],
924
+ ['B', 'C'],
925
+ ['B', 'C', 'D'],
926
+ ['C'],
927
+ ['C', 'D'],
928
+ ['D'],
929
+ ],
930
+ ),
931
+ ]:
932
+ with self.subTest(expected=expected):
933
+ actual = list(mi.subslices(iterable))
934
+ self.assertEqual(actual, expected)
935
+
936
+
937
+ class PolynomialFromRootsTests(TestCase):
938
+ def test_basic(self):
939
+ for roots, expected in [
940
+ ((2, 1, -1), [1, -2, -1, 2]),
941
+ ((2, 3), [1, -5, 6]),
942
+ ((1, 2, 3), [1, -6, 11, -6]),
943
+ ((2, 4, 1), [1, -7, 14, -8]),
944
+ ]:
945
+ with self.subTest(roots=roots):
946
+ actual = mi.polynomial_from_roots(roots)
947
+ self.assertEqual(actual, expected)
948
+
949
+ def test_large(self):
950
+ n = 1_500
951
+ actual = mi.polynomial_from_roots([-1] * n)
952
+ expected = [comb(n, k) for k in range(n + 1)]
953
+ self.assertEqual(actual, expected)
954
+
955
+
956
+ class PolynomialEvalTests(TestCase):
957
+ def test_basic(self):
958
+ for coefficients, x, expected in [
959
+ ([1, -4, -17, 60], 2, 18),
960
+ ([1, -4, -17, 60], 2.5, 8.125),
961
+ ([1, -4, -17, 60], Fraction(2, 3), Fraction(1274, 27)),
962
+ ([1, -4, -17, 60], Decimal('1.75'), Decimal('23.359375')),
963
+ ([], 2, 0),
964
+ ([], 2.5, 0.0),
965
+ ([], Fraction(2, 3), Fraction(0, 1)),
966
+ ([], Decimal('1.75'), Decimal('0.00')),
967
+ ([11], 7, 11),
968
+ ([11, 2], 7, 79),
969
+ ]:
970
+ with self.subTest(x=x):
971
+ actual = mi.polynomial_eval(coefficients, x)
972
+ self.assertEqual(actual, expected)
973
+ self.assertEqual(type(actual), type(x))
974
+
975
+
976
+ class IterIndexTests(TestCase):
977
+ def test_basic(self):
978
+ iterable = 'AABCADEAF'
979
+ for wrapper in (list, iter):
980
+ with self.subTest(wrapper=wrapper):
981
+ actual = list(mi.iter_index(wrapper(iterable), 'A'))
982
+ expected = [0, 1, 4, 7]
983
+ self.assertEqual(actual, expected)
984
+
985
+ def test_start(self):
986
+ for wrapper in (list, iter):
987
+ with self.subTest(wrapper=wrapper):
988
+ iterable = 'AABCADEAF'
989
+ i = -1
990
+ actual = []
991
+ while True:
992
+ try:
993
+ i = next(
994
+ mi.iter_index(wrapper(iterable), 'A', start=i + 1)
995
+ )
996
+ except StopIteration:
997
+ break
998
+ else:
999
+ actual.append(i)
1000
+
1001
+ expected = [0, 1, 4, 7]
1002
+ self.assertEqual(actual, expected)
1003
+
1004
+ def test_stop(self):
1005
+ actual = list(mi.iter_index('AABCADEAF', 'A', stop=7))
1006
+ expected = [0, 1, 4]
1007
+ self.assertEqual(actual, expected)
1008
+
1009
+
1010
+ class SieveTests(TestCase):
1011
+ def test_basic(self):
1012
+ self.assertEqual(
1013
+ list(mi.sieve(67)),
1014
+ [
1015
+ 2,
1016
+ 3,
1017
+ 5,
1018
+ 7,
1019
+ 11,
1020
+ 13,
1021
+ 17,
1022
+ 19,
1023
+ 23,
1024
+ 29,
1025
+ 31,
1026
+ 37,
1027
+ 41,
1028
+ 43,
1029
+ 47,
1030
+ 53,
1031
+ 59,
1032
+ 61,
1033
+ ],
1034
+ )
1035
+ self.assertEqual(list(mi.sieve(68))[-1], 67)
1036
+
1037
+ def test_prime_counts(self):
1038
+ for n, expected in (
1039
+ (100, 25),
1040
+ (1_000, 168),
1041
+ (10_000, 1229),
1042
+ (100_000, 9592),
1043
+ (1_000_000, 78498),
1044
+ ):
1045
+ with self.subTest(n=n):
1046
+ self.assertEqual(mi.ilen(mi.sieve(n)), expected)
1047
+
1048
+ def test_small_numbers(self):
1049
+ with self.assertRaises(ValueError):
1050
+ list(mi.sieve(-1))
1051
+
1052
+ for n in (0, 1, 2):
1053
+ with self.subTest(n=n):
1054
+ self.assertEqual(list(mi.sieve(n)), [])
1055
+
1056
+
1057
+ class BatchedTests(TestCase):
1058
+ def test_basic(self):
1059
+ iterable = range(1, 5 + 1)
1060
+ for n, expected in (
1061
+ (1, [(1,), (2,), (3,), (4,), (5,)]),
1062
+ (2, [(1, 2), (3, 4), (5,)]),
1063
+ (3, [(1, 2, 3), (4, 5)]),
1064
+ (4, [(1, 2, 3, 4), (5,)]),
1065
+ (5, [(1, 2, 3, 4, 5)]),
1066
+ (6, [(1, 2, 3, 4, 5)]),
1067
+ ):
1068
+ with self.subTest(n=n):
1069
+ actual = list(mi.batched(iterable, n))
1070
+ self.assertEqual(actual, expected)
1071
+
1072
+ def test_strict(self):
1073
+ with self.assertRaises(ValueError):
1074
+ list(mi.batched('ABCDEFG', 3, strict=True))
1075
+
1076
+ self.assertEqual(
1077
+ list(mi.batched('ABCDEF', 3, strict=True)),
1078
+ [('A', 'B', 'C'), ('D', 'E', 'F')],
1079
+ )
1080
+
1081
+
1082
+ class TransposeTests(TestCase):
1083
+ def test_empty(self):
1084
+ it = []
1085
+ actual = list(mi.transpose(it))
1086
+ expected = []
1087
+ self.assertEqual(actual, expected)
1088
+
1089
+ def test_basic(self):
1090
+ it = [(10, 11, 12), (20, 21, 22), (30, 31, 32)]
1091
+ actual = list(mi.transpose(it))
1092
+ expected = [(10, 20, 30), (11, 21, 31), (12, 22, 32)]
1093
+ self.assertEqual(actual, expected)
1094
+
1095
+ def test_incompatible_error(self):
1096
+ it = [(10, 11, 12, 13), (20, 21, 22), (30, 31, 32)]
1097
+ with self.assertRaises(ValueError):
1098
+ list(mi.transpose(it))
1099
+
1100
+
1101
+ class ReshapeTests(TestCase):
1102
+ def test_empty(self):
1103
+ actual = list(mi.reshape([], 3))
1104
+ self.assertEqual(actual, [])
1105
+
1106
+ def test_zero(self):
1107
+ matrix = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
1108
+ with self.assertRaises(ValueError):
1109
+ list(mi.reshape(matrix, 0))
1110
+
1111
+ def test_basic(self):
1112
+ matrix = [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]
1113
+ for cols, expected in (
1114
+ (
1115
+ 1,
1116
+ [
1117
+ (0,),
1118
+ (1,),
1119
+ (2,),
1120
+ (3,),
1121
+ (4,),
1122
+ (5,),
1123
+ (6,),
1124
+ (7,),
1125
+ (8,),
1126
+ (9,),
1127
+ (10,),
1128
+ (11,),
1129
+ ],
1130
+ ),
1131
+ (2, [(0, 1), (2, 3), (4, 5), (6, 7), (8, 9), (10, 11)]),
1132
+ (3, [(0, 1, 2), (3, 4, 5), (6, 7, 8), (9, 10, 11)]),
1133
+ (4, [(0, 1, 2, 3), (4, 5, 6, 7), (8, 9, 10, 11)]),
1134
+ (6, [(0, 1, 2, 3, 4, 5), (6, 7, 8, 9, 10, 11)]),
1135
+ (12, [(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)]),
1136
+ ):
1137
+ with self.subTest(cols=cols):
1138
+ actual = list(mi.reshape(matrix, cols))
1139
+ self.assertEqual(actual, expected)
1140
+
1141
+ def test_multidimensional(self):
1142
+ reshape = mi.reshape
1143
+
1144
+ def shape(tensor):
1145
+ if not hasattr(tensor, '__iter__'):
1146
+ return ()
1147
+ seq = list(tensor)
1148
+ return (len(seq),) + shape(seq[0])
1149
+
1150
+ matrix = [(0, 1), (2, 3), (4, 5)]
1151
+ self.assertEqual(shape(matrix), (3, 2))
1152
+
1153
+ for new_shape in [
1154
+ (2, 3),
1155
+ (6,),
1156
+ (6, 1),
1157
+ (1, 6),
1158
+ (2, 1, 3, 1),
1159
+ (1, 1, 3, 1, 2),
1160
+ ]:
1161
+ with self.subTest(new_shape=new_shape):
1162
+ new_matrix = reshape(matrix, new_shape)
1163
+ self.assertEqual(shape(new_matrix), new_shape)
1164
+
1165
+ # Truncation: Input larger than the requested shape
1166
+ self.assertEqual(list(reshape(matrix, [3])), [0, 1, 2])
1167
+
1168
+ # Incomplete structure: Input smaller than the requested shape
1169
+ self.assertEqual(list(reshape(matrix, [8])), [0, 1, 2, 3, 4, 5])
1170
+
1171
+ # Str and bytes treated as scalars
1172
+ word_matrix = [[['ab', b'de', 'gh', b'jk']]] # Shape: 1 x 1 x 4
1173
+ self.assertEqual(
1174
+ list(reshape(word_matrix, (2, 2))),
1175
+ [('ab', b'de'), ('gh', b'jk')],
1176
+ )
1177
+
1178
+ # Empty input
1179
+ self.assertEqual(list(reshape([[]], shape=(1,))), [])
1180
+
1181
+ # Non-uniform input: scalar where a tensor is expected
1182
+ with self.assertRaises(TypeError):
1183
+ list(mi.reshape([[10, 20, 30], 40], shape=(4,)))
1184
+
1185
+ # Non-integer indices
1186
+ with self.assertRaises((TypeError, ValueError)):
1187
+ matrix = [(0, 1), (2, 3), (4, 5)]
1188
+ list(reshape(matrix, ('a', 'b', 'c')))
1189
+
1190
+ # Indices smaller than one
1191
+ with self.assertRaises(ValueError):
1192
+ list(reshape(matrix, (6, 0, 1)))
1193
+
1194
+
1195
+ class MatMulTests(TestCase):
1196
+ def test_n_by_n(self):
1197
+ actual = list(mi.matmul([(7, 5), (3, 5)], [[2, 5], [7, 9]]))
1198
+ expected = [(49, 80), (41, 60)]
1199
+ self.assertEqual(actual, expected)
1200
+
1201
+ def test_m_by_n(self):
1202
+ m1 = [[2, 5], [7, 9], [3, 4]]
1203
+ m2 = [[7, 11, 5, 4, 9], [3, 5, 2, 6, 3]]
1204
+ actual = list(mi.matmul(m1, m2))
1205
+ expected = [
1206
+ (29, 47, 20, 38, 33),
1207
+ (76, 122, 53, 82, 90),
1208
+ (33, 53, 23, 36, 39),
1209
+ ]
1210
+ self.assertEqual(actual, expected)
1211
+
1212
+
1213
+ class FactorTests(TestCase):
1214
+ def test_basic(self):
1215
+ for n, expected in (
1216
+ (0, []),
1217
+ (1, []),
1218
+ (2, [2]),
1219
+ (3, [3]),
1220
+ (4, [2, 2]),
1221
+ (6, [2, 3]),
1222
+ (360, [2, 2, 2, 3, 3, 5]),
1223
+ (128_884_753_939, [128_884_753_939]),
1224
+ (999_953 * 999_983, [999_953, 999_983]),
1225
+ (909_909_090_909, [3, 3, 7, 13, 13, 751, 1_137_97]),
1226
+ (
1227
+ 1_647_403_876_764_101_672_307_088,
1228
+ [2, 2, 2, 2, 19, 23, 109471, 13571009, 158594251],
1229
+ ),
1230
+ ):
1231
+ with self.subTest(n=n):
1232
+ actual = list(mi.factor(n))
1233
+ self.assertEqual(actual, expected)
1234
+
1235
+ def test_cross_check(self):
1236
+ prod = lambda x: reduce(mul, x, 1)
1237
+ self.assertTrue(all(prod(mi.factor(n)) == n for n in range(1, 2000)))
1238
+ self.assertTrue(
1239
+ all(set(mi.factor(n)) <= set(mi.sieve(n + 1)) for n in range(2000))
1240
+ )
1241
+ self.assertTrue(
1242
+ all(
1243
+ list(mi.factor(n)) == sorted(mi.factor(n)) for n in range(2000)
1244
+ )
1245
+ )
1246
+
1247
+
1248
+ class SumOfSquaresTests(TestCase):
1249
+ def test_basic(self):
1250
+ for it, expected in (
1251
+ ([], 0),
1252
+ ([1, 2, 3], 1 + 4 + 9),
1253
+ ([2, 4, 6, 8], 4 + 16 + 36 + 64),
1254
+ ):
1255
+ with self.subTest(it=it):
1256
+ actual = mi.sum_of_squares(it)
1257
+ self.assertEqual(actual, expected)
1258
+
1259
+
1260
+ class PolynomialDerivativeTests(TestCase):
1261
+ def test_basic(self):
1262
+ for coefficients, expected in [
1263
+ ([], []),
1264
+ ([1], []),
1265
+ ([1, 2], [1]),
1266
+ ([1, 2, 3], [2, 2]),
1267
+ ([1, 2, 3, 4], [3, 4, 3]),
1268
+ ([1.1, 2, 3, 4], [(1.1 * 3), 4, 3]),
1269
+ ]:
1270
+ with self.subTest(coefficients=coefficients):
1271
+ actual = mi.polynomial_derivative(coefficients)
1272
+ self.assertEqual(actual, expected)
1273
+
1274
+
1275
+ class TotientTests(TestCase):
1276
+ def test_basic(self):
1277
+ for n, expected in (
1278
+ (1, 1),
1279
+ (2, 1),
1280
+ (3, 2),
1281
+ (4, 2),
1282
+ (9, 6),
1283
+ (12, 4),
1284
+ (128_884_753_939, 128_884_753_938),
1285
+ (999953 * 999983, 999952 * 999982),
1286
+ (6**20, 1 * 2**19 * 2 * 3**19),
1287
+ ):
1288
+ with self.subTest(n=n):
1289
+ self.assertEqual(mi.totient(n), expected)
1290
+
1291
+
1292
+ class PrimeFunctionTests(TestCase):
1293
+ def test_is_prime_pseudoprimes(self):
1294
+ # Carmichael number that strong pseudoprime to prime bases < 307
1295
+ # https://doi.org/10.1006/jsco.1995.1042
1296
+ p = 29674495668685510550154174642905332730771991799853043350995075531276838753171770199594238596428121188033664754218345562493168782883 # noqa:E501
1297
+ gnarly_carmichael = (313 * (p - 1) + 1) * (353 * (p - 1) + 1)
1298
+
1299
+ for n in (
1300
+ # Least Carmichael number with n prime factors:
1301
+ # https://oeis.org/A006931
1302
+ 561,
1303
+ 41041,
1304
+ 825265,
1305
+ 321197185,
1306
+ 5394826801,
1307
+ 232250619601,
1308
+ 9746347772161,
1309
+ 1436697831295441,
1310
+ 60977817398996785,
1311
+ 7156857700403137441,
1312
+ 1791562810662585767521,
1313
+ 87674969936234821377601,
1314
+ 6553130926752006031481761,
1315
+ 1590231231043178376951698401,
1316
+ # Carmichael numbers with exactly 4 prime factors:
1317
+ # https://oeis.org/A074379
1318
+ 41041,
1319
+ 62745,
1320
+ 63973,
1321
+ 75361,
1322
+ 101101,
1323
+ 126217,
1324
+ 172081,
1325
+ 188461,
1326
+ 278545,
1327
+ 340561,
1328
+ 449065,
1329
+ 552721,
1330
+ 656601,
1331
+ 658801,
1332
+ 670033,
1333
+ 748657,
1334
+ 838201,
1335
+ 852841,
1336
+ 997633,
1337
+ 1033669,
1338
+ 1082809,
1339
+ 1569457,
1340
+ 1773289,
1341
+ 2100901,
1342
+ 2113921,
1343
+ 2433601,
1344
+ 2455921,
1345
+ # Lucas-Carmichael numbers:
1346
+ # https://oeis.org/A006972
1347
+ 399,
1348
+ 935,
1349
+ 2015,
1350
+ 2915,
1351
+ 4991,
1352
+ 5719,
1353
+ 7055,
1354
+ 8855,
1355
+ 12719,
1356
+ 18095,
1357
+ 20705,
1358
+ 20999,
1359
+ 22847,
1360
+ 29315,
1361
+ 31535,
1362
+ 46079,
1363
+ 51359,
1364
+ 60059,
1365
+ 63503,
1366
+ 67199,
1367
+ 73535,
1368
+ 76751,
1369
+ 80189,
1370
+ 81719,
1371
+ 88559,
1372
+ 90287,
1373
+ # Strong pseudoprimes to bases 2, 3 and 5:
1374
+ # https://oeis.org/A056915
1375
+ 25326001,
1376
+ 161304001,
1377
+ 960946321,
1378
+ 1157839381,
1379
+ 3215031751,
1380
+ 3697278427,
1381
+ 5764643587,
1382
+ 6770862367,
1383
+ 14386156093,
1384
+ 15579919981,
1385
+ 18459366157,
1386
+ 19887974881,
1387
+ 21276028621,
1388
+ 27716349961,
1389
+ 29118033181,
1390
+ 37131467521,
1391
+ 41752650241,
1392
+ 42550716781,
1393
+ 43536545821,
1394
+ # Strong pseudoprimes to bases 2, 3, 5, and 7:
1395
+ # https://oeis.org/A211112
1396
+ 39365185894561,
1397
+ 52657210792621,
1398
+ 11377272352951,
1399
+ 15070413782971,
1400
+ 3343433905957,
1401
+ 16603327018981,
1402
+ 3461715915661,
1403
+ 52384617784801,
1404
+ 3477707481751,
1405
+ 18996486073489,
1406
+ 55712149574381,
1407
+ gnarly_carmichael,
1408
+ ):
1409
+ with self.subTest(n=n):
1410
+ self.assertFalse(mi.is_prime(n))
1411
+
1412
+ def test_primes(self):
1413
+ for i, n in enumerate(mi.sieve(10**5)):
1414
+ with self.subTest(n=n):
1415
+ self.assertTrue(mi.is_prime(n))
1416
+ self.assertEqual(mi.nth_prime(i), n)
1417
+
1418
+ self.assertFalse(mi.is_prime(-1))
1419
+ with self.assertRaises(ValueError):
1420
+ mi.nth_prime(-1)
1421
+
1422
+ def test_special_primes(self):
1423
+ for n in (
1424
+ # Mersenee primes:
1425
+ # https://oeis.org/A211112
1426
+ 3,
1427
+ 7,
1428
+ 31,
1429
+ 127,
1430
+ 8191,
1431
+ 131071,
1432
+ 524287,
1433
+ 2147483647,
1434
+ 2305843009213693951,
1435
+ 618970019642690137449562111,
1436
+ 162259276829213363391578010288127,
1437
+ 170141183460469231731687303715884105727,
1438
+ # Various big primes:
1439
+ # https://bigprimes.org/
1440
+ 7990614013,
1441
+ 80358337843874809987,
1442
+ 814847562949580526031364519741,
1443
+ 1982427225022428178169740526258124929077,
1444
+ 91828213828508622559862344537590739566883686537727,
1445
+ 406414746815201693481517584049440077164779143248351060891669,
1446
+ ):
1447
+ with self.subTest(n=n):
1448
+ self.assertTrue(mi.is_prime(n))
1449
+
1450
+
1451
+ class LoopsTests(TestCase):
1452
+ def test_basic(self):
1453
+ self.assertTrue(
1454
+ all(list(mi.loops(n)) == [None] * n for n in range(-10, 10))
1455
+ )
1456
+
1457
+
1458
+ class MultinomialTests(TestCase):
1459
+ def test_basic(self):
1460
+ multinomial = mi.multinomial
1461
+
1462
+ # Case M(11; 5, 2, 1, 1, 2) = 83160
1463
+ # https://www.wolframalpha.com/input?i=Multinomia%285%2C+2%2C+1%2C+1%2C+2%29
1464
+ self.assertEqual(multinomial(5, 2, 1, 1, 2), 83160)
1465
+
1466
+ # Commutative
1467
+ self.assertEqual(multinomial(2, 1, 1, 2, 5), 83160)
1468
+
1469
+ # Unaffected by zero-sized bins
1470
+ self.assertEqual(multinomial(2, 0, 1, 0, 1, 2, 5, 0), 83160)
1471
+
1472
+ # Matches definition
1473
+ self.assertEqual(
1474
+ multinomial(5, 2, 1, 1, 2),
1475
+ (
1476
+ factorial(sum([5, 2, 1, 1, 2]))
1477
+ // prod(map(factorial, [5, 2, 1, 1, 2]))
1478
+ ),
1479
+ )
1480
+
1481
+ # Corner cases and identities
1482
+ self.assertEqual(multinomial(), 1)
1483
+ self.assertEqual(multinomial(5), 1)
1484
+ self.assertEqual(multinomial(5, 7), comb(12, 5))
1485
+ self.assertEqual(multinomial(1, 1, 1, 1, 1, 1, 1), factorial(7))
1486
+
1487
+ # Relationship to distinct_permuations() and permutations()
1488
+ for word in ['plain', 'pizza', 'coffee', 'honolulu', 'assists']:
1489
+ with self.subTest(word=word):
1490
+ self.assertEqual(
1491
+ multinomial(*Counter(word).values()),
1492
+ mi.ilen(mi.distinct_permutations(word)),
1493
+ )
1494
+ self.assertEqual(
1495
+ multinomial(*Counter(word).values()),
1496
+ len(set(permutations(word))),
1497
+ )
1498
+
1499
+ # Error cases
1500
+ with self.assertRaises(ValueError):
1501
+ multinomial(-5, 7) # No negative inputs
1502
+ with self.assertRaises(TypeError):
1503
+ multinomial(5, 7.25) # No float inputs
1504
+ with self.assertRaises(TypeError):
1505
+ multinomial(5, 'x') # No non-numeric inputs
1506
+ with self.assertRaises(TypeError):
1507
+ multinomial([5, 7]) # No sequence inputs
1508
+
1509
+
1510
+ class RunningMeanTests(TestCase):
1511
+ def test_basic(self):
1512
+ for i, (iterable, expected) in enumerate(
1513
+ [
1514
+ ([], []),
1515
+ ([1], [1.0]),
1516
+ ([1, 2], [1.0, 1.5]),
1517
+ (
1518
+ [Fraction(1, 1), Fraction(2, 1)],
1519
+ [Fraction(1, 1), Fraction(3, 2)],
1520
+ ),
1521
+ (
1522
+ [Decimal('1.0'), Decimal('2.0')],
1523
+ [Decimal('1.0'), Decimal('1.5')],
1524
+ ),
1525
+ ([8.5, 9.5, 7.5, 6.5], [8.5, 9.0, 8.5, 8.0]),
1526
+ ]
1527
+ ):
1528
+ with self.subTest(i=i):
1529
+ actual = list(mi.running_mean(iterable))
1530
+ self.assertEqual(actual, expected)
1531
+
1532
+
1533
+ class RunningMedianTests(TestCase):
1534
+ def test_vs_statistics_median(self):
1535
+ running_median = mi.running_median
1536
+
1537
+ for data in [
1538
+ random.choices(range(-500, 500), k=500),
1539
+ # Apply unary plus to force context rounding.
1540
+ [+Decimal(random.uniform(-500, 500)) for _ in range(500)],
1541
+ [
1542
+ Fraction(random.randrange(-500, 500), random.randrange(1, 500))
1543
+ for _ in range(500)
1544
+ ],
1545
+ ]:
1546
+ with self.subTest(data=data):
1547
+ for k, rm in enumerate(running_median(iter(data)), start=1):
1548
+ expected = statistics.median(data[:k])
1549
+ self.assertEqual(rm, expected)
1550
+ self.assertEqual(type(rm), type(expected))
1551
+
1552
+ self.assertEqual(list(running_median([])), []) # Empty input
1553
+
1554
+ def test_vs_statistics_median_windowed(self):
1555
+ running_median = mi.running_median
1556
+ size = 10
1557
+
1558
+ for data in [
1559
+ random.choices(range(-500, 500), k=500),
1560
+ # Apply unary plus to force context rounding.
1561
+ [+Decimal(random.uniform(-500, 500)) for _ in range(500)],
1562
+ [
1563
+ Fraction(random.randrange(-500, 500), random.randrange(1, 500))
1564
+ for _ in range(500)
1565
+ ],
1566
+ ]:
1567
+ with self.subTest(data=data):
1568
+ iterator = running_median(iter(data), maxlen=size)
1569
+ for k, rm in enumerate(iterator, start=1):
1570
+ expected = statistics.median(data[max(0, k - size) : k])
1571
+ self.assertEqual(rm, expected)
1572
+ self.assertEqual(type(rm), type(expected))
1573
+
1574
+ self.assertEqual(list(running_median([], maxlen=1)), []) # Empty input
1575
+
1576
+ # Window size of 1 should return the original dataset unchanged
1577
+ data = random.choices(range(-500, 500), k=500)
1578
+ self.assertEqual(list(running_median(data, maxlen=1)), data)
1579
+
1580
+ # Window size of 2 is a moving average of pairs
1581
+ data = random.choices(range(-500, 500), k=500)
1582
+ expected = list(map(mean, pairwise(data)))
1583
+ actual = list(islice(running_median(data, maxlen=2), 1, None))
1584
+ self.assertEqual(actual, expected)
1585
+
1586
+ # A window larger than the dataset should give the same
1587
+ # result as an unbounded running median.
1588
+ data = random.choices(range(-500, 500), k=500)
1589
+ self.assertEqual(
1590
+ list(running_median(data, maxlen=600)), list(running_median(data))
1591
+ )
1592
+
1593
+ def test_error_cases(self):
1594
+ running_median = mi.running_median
1595
+ with self.assertRaises(TypeError):
1596
+ running_median(1234) # Non-iterable input
1597
+ with self.assertRaises(TypeError):
1598
+ running_median([], maxlen=3.0) # Non-integer type for window size
1599
+ with self.assertRaises(ValueError):
1600
+ running_median([], maxlen=0) # Invalid window size
1601
+ with self.assertRaises(TypeError):
1602
+ list(running_median([3 + 4j, 5 - 7j])) # Unorderable input type
1603
+ with self.assertRaises(TypeError):
1604
+ list(
1605
+ running_median(['abc', 'def', 'ghi'])
1606
+ ) # Input type that doesn't support division
examples/repo2env-more-itertools-bug-intersperse-staged/tox.ini ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ [tox]
2
+ envlist = py{310,311,312,313,314}
3
+ isolated_build = True
4
+
5
+ [testenv]
6
+ commands = {envpython} -m unittest -v {posargs}
models.py ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ """Repo2Env OpenEnv model compatibility shim."""
2
+
3
+ from repo2env.openenv.models import (
4
+ REPO2ENV_TOOL_NAMES,
5
+ Repo2EnvAction,
6
+ Repo2EnvObservation,
7
+ Repo2EnvState,
8
+ )
9
+
10
+ __all__ = [
11
+ "REPO2ENV_TOOL_NAMES",
12
+ "Repo2EnvAction",
13
+ "Repo2EnvObservation",
14
+ "Repo2EnvState",
15
+ ]
openenv.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ spec_version: 1
2
+ name: repo2env-repo2env-more-itertools-bug-intersperse-staged
3
+ type: space
4
+ runtime: fastapi
5
+ app: repo2env.openenv.server:app
6
+ port: 8000
pyproject.toml ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ [build-system]
2
+ requires = ["setuptools>=68"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "repo2env"
7
+ version = "0.1.0"
8
+ description = "Turn small Python repositories into rewardable coding environments."
9
+ readme = "README.md"
10
+ requires-python = ">=3.10"
11
+ dependencies = [
12
+ "fastmcp>=3.1.0",
13
+ "openenv-core==0.2.1",
14
+ "pytest>=8.0",
15
+ "uvicorn>=0.41.0",
16
+ ]
17
+
18
+ [project.scripts]
19
+ repo2env-demo = "repo2env.app.demo:main"
20
+ repo2env-infer = "repo2env.app.inference:main"
21
+ repo2env-mcp = "repo2env.mcp.server:main"
22
+ repo2env-openenv-server = "repo2env.openenv.server:main"
23
+ repo2env-smoke-test = "repo2env.app.smoke_test:main"
24
+ repo2env-train-stub = "repo2env.app.training_stub:main"
25
+ server = "repo2env.openenv.server:main"
26
+
27
+ [tool.pytest.ini_options]
28
+ testpaths = ["tests"]
29
+
30
+ [tool.setuptools.packages.find]
31
+ include = ["repo2env*"]
repo2env/__init__.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ __all__ = ["__version__"]
2
+
3
+ __version__ = "0.1.0"
4
+