Upload folder using huggingface_hub
Browse filesThis view is limited to 50 files because it contains too many changes. See raw diff
- Dockerfile +20 -0
- README.md +34 -5
- __init__.py +19 -0
- client.py +5 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.claude/settings.local.json +9 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.gitattributes +2 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/other-issues.md +10 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.github/ISSUE_TEMPLATE/propose-a-new-itertool.md +20 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.github/PULL_REQUEST_TEMPLATE.md +12 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.github/workflows/python-app.yml +36 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.gitignore +47 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/.readthedocs.yaml +15 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/LICENSE +19 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/MANIFEST.in +10 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/Makefile +38 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/README.rst +259 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/Makefile +153 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/_static/theme_overrides.css +14 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/api.rst +367 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/conf.py +286 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/index.rst +1 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/license.rst +16 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/make.bat +190 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/requirements.txt +2 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/testing.rst +19 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/toctree.rst +15 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/docs/versions.rst +813 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.py +6 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/__init__.pyi +2 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.py +0 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/more.pyi +979 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/py.typed +0 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.py +1430 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/more_itertools/recipes.pyi +207 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/pyproject.toml +59 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/repo2env_manifest.json +35 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/requirements/development.txt +4 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/requirements/packaging.txt +4 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/requirements/testing.txt +2 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/requirements/typechecks.txt +1 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/setup.cfg +26 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/task_spec.json +30 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/tests/__init__.py +0 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_more.py +0 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/tests/test_recipes.py +1606 -0
- examples/repo2env-more-itertools-bug-intersperse-staged/tox.ini +6 -0
- models.py +15 -0
- openenv.yaml +6 -0
- pyproject.toml +31 -0
- 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:
|
| 3 |
-
emoji:
|
| 4 |
-
colorFrom:
|
| 5 |
-
colorTo:
|
| 6 |
sdk: docker
|
| 7 |
pinned: false
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
---
|
| 9 |
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
+
|