#
tokens: 94043/50000 1/958 files (page 234/236)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 234 of 236. Use http://codebase.md/seanivore/mcp-code-analyzer?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .DS_Store
├── .gitignore
├── bin
│   └── mcp-code-analyzer.js
├── dist
│   ├── mcp_code_analyzer-0.1.0-py3-none-any.whl
│   └── mcp_code_analyzer-0.1.0.tar.gz
├── LICENSE
├── package-lock.json
├── package.json
├── pyproject.toml
├── README.md
├── setup.py
├── src
│   ├── index.ts
│   └── mcp_code_analyzer
│       ├── __init__.py
│       ├── __main__.py
│       ├── __pycache__
│       │   ├── __init__.cpython-311.pyc
│       │   └── server.cpython-311.pyc
│       └── server.py
├── test_analyzer.py
├── test_code.py
├── test_package.py
├── test.py
├── tsconfig.json
└── venv
    ├── bin
    │   ├── activate
    │   ├── activate.csh
    │   ├── activate.fish
    │   ├── Activate.ps1
    │   ├── hatchling
    │   ├── pip
    │   ├── pip3
    │   ├── pip3.11
    │   ├── pyproject-build
    │   ├── python
    │   ├── python3
    │   └── python3.11
    ├── lib
    │   └── python3.11
    │       └── site-packages
    │           ├── _distutils_hack
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   └── override.cpython-311.pyc
    │           │   └── override.py
    │           ├── _mcp_code_analyzer.pth
    │           ├── build-1.2.2.post1.dist-info
    │           │   ├── entry_points.txt
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── REQUESTED
    │           │   └── WHEEL
    │           ├── distutils-precedence.pth
    │           ├── hatchling
    │           │   ├── __about__.py
    │           │   ├── __init__.py
    │           │   ├── __main__.py
    │           │   ├── __pycache__
    │           │   │   ├── __about__.cpython-311.pyc
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── __main__.cpython-311.pyc
    │           │   │   ├── build.cpython-311.pyc
    │           │   │   └── ouroboros.cpython-311.pyc
    │           │   ├── bridge
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── app.cpython-311.pyc
    │           │   │   └── app.py
    │           │   ├── build.py
    │           │   ├── builders
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── app.cpython-311.pyc
    │           │   │   │   ├── binary.cpython-311.pyc
    │           │   │   │   ├── config.cpython-311.pyc
    │           │   │   │   ├── constants.cpython-311.pyc
    │           │   │   │   ├── custom.cpython-311.pyc
    │           │   │   │   ├── macos.cpython-311.pyc
    │           │   │   │   ├── sdist.cpython-311.pyc
    │           │   │   │   ├── utils.cpython-311.pyc
    │           │   │   │   └── wheel.cpython-311.pyc
    │           │   │   ├── app.py
    │           │   │   ├── binary.py
    │           │   │   ├── config.py
    │           │   │   ├── constants.py
    │           │   │   ├── custom.py
    │           │   │   ├── hooks
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── custom.cpython-311.pyc
    │           │   │   │   │   └── version.cpython-311.pyc
    │           │   │   │   ├── custom.py
    │           │   │   │   ├── plugin
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── hooks.cpython-311.pyc
    │           │   │   │   │   │   └── interface.cpython-311.pyc
    │           │   │   │   │   ├── hooks.py
    │           │   │   │   │   └── interface.py
    │           │   │   │   └── version.py
    │           │   │   ├── macos.py
    │           │   │   ├── plugin
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── hooks.cpython-311.pyc
    │           │   │   │   │   └── interface.cpython-311.pyc
    │           │   │   │   ├── hooks.py
    │           │   │   │   └── interface.py
    │           │   │   ├── sdist.py
    │           │   │   ├── utils.py
    │           │   │   └── wheel.py
    │           │   ├── cli
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   └── __init__.cpython-311.pyc
    │           │   │   ├── dep
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   └── core.cpython-311.pyc
    │           │   │   │   └── core.py
    │           │   │   ├── metadata
    │           │   │   │   ├── __init__.py
    │           │   │   │   └── __pycache__
    │           │   │   │       └── __init__.cpython-311.pyc
    │           │   │   └── version
    │           │   │       ├── __init__.py
    │           │   │       └── __pycache__
    │           │   │           └── __init__.cpython-311.pyc
    │           │   ├── dep
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── core.cpython-311.pyc
    │           │   │   └── core.py
    │           │   ├── licenses
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── supported.cpython-311.pyc
    │           │   │   └── supported.py
    │           │   ├── metadata
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── core.cpython-311.pyc
    │           │   │   │   ├── custom.cpython-311.pyc
    │           │   │   │   ├── spec.cpython-311.pyc
    │           │   │   │   └── utils.cpython-311.pyc
    │           │   │   ├── core.py
    │           │   │   ├── custom.py
    │           │   │   ├── plugin
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── hooks.cpython-311.pyc
    │           │   │   │   │   └── interface.cpython-311.pyc
    │           │   │   │   ├── hooks.py
    │           │   │   │   └── interface.py
    │           │   │   ├── spec.py
    │           │   │   └── utils.py
    │           │   ├── ouroboros.py
    │           │   ├── plugin
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── exceptions.cpython-311.pyc
    │           │   │   │   ├── manager.cpython-311.pyc
    │           │   │   │   ├── specs.cpython-311.pyc
    │           │   │   │   └── utils.cpython-311.pyc
    │           │   │   ├── exceptions.py
    │           │   │   ├── manager.py
    │           │   │   ├── specs.py
    │           │   │   └── utils.py
    │           │   ├── py.typed
    │           │   ├── utils
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── constants.cpython-311.pyc
    │           │   │   │   ├── context.cpython-311.pyc
    │           │   │   │   └── fs.cpython-311.pyc
    │           │   │   ├── constants.py
    │           │   │   ├── context.py
    │           │   │   └── fs.py
    │           │   └── version
    │           │       ├── __init__.py
    │           │       ├── __pycache__
    │           │       │   ├── __init__.cpython-311.pyc
    │           │       │   └── core.cpython-311.pyc
    │           │       ├── core.py
    │           │       ├── scheme
    │           │       │   ├── __init__.py
    │           │       │   ├── __pycache__
    │           │       │   │   ├── __init__.cpython-311.pyc
    │           │       │   │   └── standard.cpython-311.pyc
    │           │       │   ├── plugin
    │           │       │   │   ├── __init__.py
    │           │       │   │   ├── __pycache__
    │           │       │   │   │   ├── __init__.cpython-311.pyc
    │           │       │   │   │   ├── hooks.cpython-311.pyc
    │           │       │   │   │   └── interface.cpython-311.pyc
    │           │       │   │   ├── hooks.py
    │           │       │   │   └── interface.py
    │           │       │   └── standard.py
    │           │       └── source
    │           │           ├── __init__.py
    │           │           ├── __pycache__
    │           │           │   ├── __init__.cpython-311.pyc
    │           │           │   ├── code.cpython-311.pyc
    │           │           │   ├── env.cpython-311.pyc
    │           │           │   └── regex.cpython-311.pyc
    │           │           ├── code.py
    │           │           ├── env.py
    │           │           ├── plugin
    │           │           │   ├── __init__.py
    │           │           │   ├── __pycache__
    │           │           │   │   ├── __init__.cpython-311.pyc
    │           │           │   │   ├── hooks.cpython-311.pyc
    │           │           │   │   └── interface.cpython-311.pyc
    │           │           │   ├── hooks.py
    │           │           │   └── interface.py
    │           │           └── regex.py
    │           ├── hatchling-1.26.3.dist-info
    │           │   ├── entry_points.txt
    │           │   ├── INSTALLER
    │           │   ├── licenses
    │           │   │   └── LICENSE.txt
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── REQUESTED
    │           │   └── WHEEL
    │           ├── mcp_code_analyzer-0.1.0.dist-info
    │           │   ├── direct_url.json
    │           │   ├── INSTALLER
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── REQUESTED
    │           │   └── WHEEL
    │           ├── packaging
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── _elffile.cpython-311.pyc
    │           │   │   ├── _manylinux.cpython-311.pyc
    │           │   │   ├── _musllinux.cpython-311.pyc
    │           │   │   ├── _parser.cpython-311.pyc
    │           │   │   ├── _structures.cpython-311.pyc
    │           │   │   ├── _tokenizer.cpython-311.pyc
    │           │   │   ├── markers.cpython-311.pyc
    │           │   │   ├── metadata.cpython-311.pyc
    │           │   │   ├── requirements.cpython-311.pyc
    │           │   │   ├── specifiers.cpython-311.pyc
    │           │   │   ├── tags.cpython-311.pyc
    │           │   │   ├── utils.cpython-311.pyc
    │           │   │   └── version.cpython-311.pyc
    │           │   ├── _elffile.py
    │           │   ├── _manylinux.py
    │           │   ├── _musllinux.py
    │           │   ├── _parser.py
    │           │   ├── _structures.py
    │           │   ├── _tokenizer.py
    │           │   ├── licenses
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── _spdx.cpython-311.pyc
    │           │   │   └── _spdx.py
    │           │   ├── markers.py
    │           │   ├── metadata.py
    │           │   ├── py.typed
    │           │   ├── requirements.py
    │           │   ├── specifiers.py
    │           │   ├── tags.py
    │           │   ├── utils.py
    │           │   └── version.py
    │           ├── packaging-24.2.dist-info
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── LICENSE.APACHE
    │           │   ├── LICENSE.BSD
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   └── WHEEL
    │           ├── pathspec
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── _meta.cpython-311.pyc
    │           │   │   ├── gitignore.cpython-311.pyc
    │           │   │   ├── pathspec.cpython-311.pyc
    │           │   │   ├── pattern.cpython-311.pyc
    │           │   │   └── util.cpython-311.pyc
    │           │   ├── _meta.py
    │           │   ├── gitignore.py
    │           │   ├── pathspec.py
    │           │   ├── pattern.py
    │           │   ├── patterns
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── gitwildmatch.cpython-311.pyc
    │           │   │   └── gitwildmatch.py
    │           │   ├── py.typed
    │           │   └── util.py
    │           ├── pathspec-0.12.1.dist-info
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   └── WHEEL
    │           ├── pip
    │           │   ├── __init__.py
    │           │   ├── __main__.py
    │           │   ├── __pip-runner__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── __main__.cpython-311.pyc
    │           │   │   └── __pip-runner__.cpython-311.pyc
    │           │   ├── _internal
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── build_env.cpython-311.pyc
    │           │   │   │   ├── cache.cpython-311.pyc
    │           │   │   │   ├── configuration.cpython-311.pyc
    │           │   │   │   ├── exceptions.cpython-311.pyc
    │           │   │   │   ├── main.cpython-311.pyc
    │           │   │   │   ├── pyproject.cpython-311.pyc
    │           │   │   │   ├── self_outdated_check.cpython-311.pyc
    │           │   │   │   └── wheel_builder.cpython-311.pyc
    │           │   │   ├── build_env.py
    │           │   │   ├── cache.py
    │           │   │   ├── cli
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── autocompletion.cpython-311.pyc
    │           │   │   │   │   ├── base_command.cpython-311.pyc
    │           │   │   │   │   ├── cmdoptions.cpython-311.pyc
    │           │   │   │   │   ├── command_context.cpython-311.pyc
    │           │   │   │   │   ├── index_command.cpython-311.pyc
    │           │   │   │   │   ├── main_parser.cpython-311.pyc
    │           │   │   │   │   ├── main.cpython-311.pyc
    │           │   │   │   │   ├── parser.cpython-311.pyc
    │           │   │   │   │   ├── progress_bars.cpython-311.pyc
    │           │   │   │   │   ├── req_command.cpython-311.pyc
    │           │   │   │   │   ├── spinners.cpython-311.pyc
    │           │   │   │   │   └── status_codes.cpython-311.pyc
    │           │   │   │   ├── autocompletion.py
    │           │   │   │   ├── base_command.py
    │           │   │   │   ├── cmdoptions.py
    │           │   │   │   ├── command_context.py
    │           │   │   │   ├── index_command.py
    │           │   │   │   ├── main_parser.py
    │           │   │   │   ├── main.py
    │           │   │   │   ├── parser.py
    │           │   │   │   ├── progress_bars.py
    │           │   │   │   ├── req_command.py
    │           │   │   │   ├── spinners.py
    │           │   │   │   └── status_codes.py
    │           │   │   ├── commands
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── cache.cpython-311.pyc
    │           │   │   │   │   ├── check.cpython-311.pyc
    │           │   │   │   │   ├── completion.cpython-311.pyc
    │           │   │   │   │   ├── configuration.cpython-311.pyc
    │           │   │   │   │   ├── debug.cpython-311.pyc
    │           │   │   │   │   ├── download.cpython-311.pyc
    │           │   │   │   │   ├── freeze.cpython-311.pyc
    │           │   │   │   │   ├── hash.cpython-311.pyc
    │           │   │   │   │   ├── help.cpython-311.pyc
    │           │   │   │   │   ├── index.cpython-311.pyc
    │           │   │   │   │   ├── inspect.cpython-311.pyc
    │           │   │   │   │   ├── install.cpython-311.pyc
    │           │   │   │   │   ├── list.cpython-311.pyc
    │           │   │   │   │   ├── search.cpython-311.pyc
    │           │   │   │   │   ├── show.cpython-311.pyc
    │           │   │   │   │   ├── uninstall.cpython-311.pyc
    │           │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   ├── cache.py
    │           │   │   │   ├── check.py
    │           │   │   │   ├── completion.py
    │           │   │   │   ├── configuration.py
    │           │   │   │   ├── debug.py
    │           │   │   │   ├── download.py
    │           │   │   │   ├── freeze.py
    │           │   │   │   ├── hash.py
    │           │   │   │   ├── help.py
    │           │   │   │   ├── index.py
    │           │   │   │   ├── inspect.py
    │           │   │   │   ├── install.py
    │           │   │   │   ├── list.py
    │           │   │   │   ├── search.py
    │           │   │   │   ├── show.py
    │           │   │   │   ├── uninstall.py
    │           │   │   │   └── wheel.py
    │           │   │   ├── configuration.py
    │           │   │   ├── distributions
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── base.cpython-311.pyc
    │           │   │   │   │   ├── installed.cpython-311.pyc
    │           │   │   │   │   ├── sdist.cpython-311.pyc
    │           │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   ├── base.py
    │           │   │   │   ├── installed.py
    │           │   │   │   ├── sdist.py
    │           │   │   │   └── wheel.py
    │           │   │   ├── exceptions.py
    │           │   │   ├── index
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── collector.cpython-311.pyc
    │           │   │   │   │   ├── package_finder.cpython-311.pyc
    │           │   │   │   │   └── sources.cpython-311.pyc
    │           │   │   │   ├── collector.py
    │           │   │   │   ├── package_finder.py
    │           │   │   │   └── sources.py
    │           │   │   ├── locations
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _distutils.cpython-311.pyc
    │           │   │   │   │   ├── _sysconfig.cpython-311.pyc
    │           │   │   │   │   └── base.cpython-311.pyc
    │           │   │   │   ├── _distutils.py
    │           │   │   │   ├── _sysconfig.py
    │           │   │   │   └── base.py
    │           │   │   ├── main.py
    │           │   │   ├── metadata
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _json.cpython-311.pyc
    │           │   │   │   │   ├── base.cpython-311.pyc
    │           │   │   │   │   └── pkg_resources.cpython-311.pyc
    │           │   │   │   ├── _json.py
    │           │   │   │   ├── base.py
    │           │   │   │   ├── importlib
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── _compat.cpython-311.pyc
    │           │   │   │   │   │   ├── _dists.cpython-311.pyc
    │           │   │   │   │   │   └── _envs.cpython-311.pyc
    │           │   │   │   │   ├── _compat.py
    │           │   │   │   │   ├── _dists.py
    │           │   │   │   │   └── _envs.py
    │           │   │   │   └── pkg_resources.py
    │           │   │   ├── models
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── candidate.cpython-311.pyc
    │           │   │   │   │   ├── direct_url.cpython-311.pyc
    │           │   │   │   │   ├── format_control.cpython-311.pyc
    │           │   │   │   │   ├── index.cpython-311.pyc
    │           │   │   │   │   ├── installation_report.cpython-311.pyc
    │           │   │   │   │   ├── link.cpython-311.pyc
    │           │   │   │   │   ├── scheme.cpython-311.pyc
    │           │   │   │   │   ├── search_scope.cpython-311.pyc
    │           │   │   │   │   ├── selection_prefs.cpython-311.pyc
    │           │   │   │   │   ├── target_python.cpython-311.pyc
    │           │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   ├── candidate.py
    │           │   │   │   ├── direct_url.py
    │           │   │   │   ├── format_control.py
    │           │   │   │   ├── index.py
    │           │   │   │   ├── installation_report.py
    │           │   │   │   ├── link.py
    │           │   │   │   ├── scheme.py
    │           │   │   │   ├── search_scope.py
    │           │   │   │   ├── selection_prefs.py
    │           │   │   │   ├── target_python.py
    │           │   │   │   └── wheel.py
    │           │   │   ├── network
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── auth.cpython-311.pyc
    │           │   │   │   │   ├── cache.cpython-311.pyc
    │           │   │   │   │   ├── download.cpython-311.pyc
    │           │   │   │   │   ├── lazy_wheel.cpython-311.pyc
    │           │   │   │   │   ├── session.cpython-311.pyc
    │           │   │   │   │   ├── utils.cpython-311.pyc
    │           │   │   │   │   └── xmlrpc.cpython-311.pyc
    │           │   │   │   ├── auth.py
    │           │   │   │   ├── cache.py
    │           │   │   │   ├── download.py
    │           │   │   │   ├── lazy_wheel.py
    │           │   │   │   ├── session.py
    │           │   │   │   ├── utils.py
    │           │   │   │   └── xmlrpc.py
    │           │   │   ├── operations
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── check.cpython-311.pyc
    │           │   │   │   │   ├── freeze.cpython-311.pyc
    │           │   │   │   │   └── prepare.cpython-311.pyc
    │           │   │   │   ├── check.py
    │           │   │   │   ├── freeze.py
    │           │   │   │   ├── install
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── editable_legacy.cpython-311.pyc
    │           │   │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   │   ├── editable_legacy.py
    │           │   │   │   │   └── wheel.py
    │           │   │   │   └── prepare.py
    │           │   │   ├── pyproject.py
    │           │   │   ├── req
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── constructors.cpython-311.pyc
    │           │   │   │   │   ├── req_file.cpython-311.pyc
    │           │   │   │   │   ├── req_install.cpython-311.pyc
    │           │   │   │   │   ├── req_set.cpython-311.pyc
    │           │   │   │   │   └── req_uninstall.cpython-311.pyc
    │           │   │   │   ├── constructors.py
    │           │   │   │   ├── req_file.py
    │           │   │   │   ├── req_install.py
    │           │   │   │   ├── req_set.py
    │           │   │   │   └── req_uninstall.py
    │           │   │   ├── resolution
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   └── base.cpython-311.pyc
    │           │   │   │   ├── base.py
    │           │   │   │   ├── legacy
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── resolver.cpython-311.pyc
    │           │   │   │   │   └── resolver.py
    │           │   │   │   └── resolvelib
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   ├── base.cpython-311.pyc
    │           │   │   │       │   ├── candidates.cpython-311.pyc
    │           │   │   │       │   ├── factory.cpython-311.pyc
    │           │   │   │       │   ├── found_candidates.cpython-311.pyc
    │           │   │   │       │   ├── provider.cpython-311.pyc
    │           │   │   │       │   ├── reporter.cpython-311.pyc
    │           │   │   │       │   ├── requirements.cpython-311.pyc
    │           │   │   │       │   └── resolver.cpython-311.pyc
    │           │   │   │       ├── base.py
    │           │   │   │       ├── candidates.py
    │           │   │   │       ├── factory.py
    │           │   │   │       ├── found_candidates.py
    │           │   │   │       ├── provider.py
    │           │   │   │       ├── reporter.py
    │           │   │   │       ├── requirements.py
    │           │   │   │       └── resolver.py
    │           │   │   ├── self_outdated_check.py
    │           │   │   ├── utils
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _jaraco_text.cpython-311.pyc
    │           │   │   │   │   ├── _log.cpython-311.pyc
    │           │   │   │   │   ├── appdirs.cpython-311.pyc
    │           │   │   │   │   ├── compat.cpython-311.pyc
    │           │   │   │   │   ├── compatibility_tags.cpython-311.pyc
    │           │   │   │   │   ├── datetime.cpython-311.pyc
    │           │   │   │   │   ├── deprecation.cpython-311.pyc
    │           │   │   │   │   ├── direct_url_helpers.cpython-311.pyc
    │           │   │   │   │   ├── egg_link.cpython-311.pyc
    │           │   │   │   │   ├── encoding.cpython-311.pyc
    │           │   │   │   │   ├── entrypoints.cpython-311.pyc
    │           │   │   │   │   ├── filesystem.cpython-311.pyc
    │           │   │   │   │   ├── filetypes.cpython-311.pyc
    │           │   │   │   │   ├── glibc.cpython-311.pyc
    │           │   │   │   │   ├── hashes.cpython-311.pyc
    │           │   │   │   │   ├── logging.cpython-311.pyc
    │           │   │   │   │   ├── misc.cpython-311.pyc
    │           │   │   │   │   ├── packaging.cpython-311.pyc
    │           │   │   │   │   ├── retry.cpython-311.pyc
    │           │   │   │   │   ├── setuptools_build.cpython-311.pyc
    │           │   │   │   │   ├── subprocess.cpython-311.pyc
    │           │   │   │   │   ├── temp_dir.cpython-311.pyc
    │           │   │   │   │   ├── unpacking.cpython-311.pyc
    │           │   │   │   │   ├── urls.cpython-311.pyc
    │           │   │   │   │   ├── virtualenv.cpython-311.pyc
    │           │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   ├── _jaraco_text.py
    │           │   │   │   ├── _log.py
    │           │   │   │   ├── appdirs.py
    │           │   │   │   ├── compat.py
    │           │   │   │   ├── compatibility_tags.py
    │           │   │   │   ├── datetime.py
    │           │   │   │   ├── deprecation.py
    │           │   │   │   ├── direct_url_helpers.py
    │           │   │   │   ├── egg_link.py
    │           │   │   │   ├── encoding.py
    │           │   │   │   ├── entrypoints.py
    │           │   │   │   ├── filesystem.py
    │           │   │   │   ├── filetypes.py
    │           │   │   │   ├── glibc.py
    │           │   │   │   ├── hashes.py
    │           │   │   │   ├── logging.py
    │           │   │   │   ├── misc.py
    │           │   │   │   ├── packaging.py
    │           │   │   │   ├── retry.py
    │           │   │   │   ├── setuptools_build.py
    │           │   │   │   ├── subprocess.py
    │           │   │   │   ├── temp_dir.py
    │           │   │   │   ├── unpacking.py
    │           │   │   │   ├── urls.py
    │           │   │   │   ├── virtualenv.py
    │           │   │   │   └── wheel.py
    │           │   │   ├── vcs
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── bazaar.cpython-311.pyc
    │           │   │   │   │   ├── git.cpython-311.pyc
    │           │   │   │   │   ├── mercurial.cpython-311.pyc
    │           │   │   │   │   ├── subversion.cpython-311.pyc
    │           │   │   │   │   └── versioncontrol.cpython-311.pyc
    │           │   │   │   ├── bazaar.py
    │           │   │   │   ├── git.py
    │           │   │   │   ├── mercurial.py
    │           │   │   │   ├── subversion.py
    │           │   │   │   └── versioncontrol.py
    │           │   │   └── wheel_builder.py
    │           │   ├── _vendor
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── typing_extensions.cpython-311.pyc
    │           │   │   ├── cachecontrol
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _cmd.cpython-311.pyc
    │           │   │   │   │   ├── adapter.cpython-311.pyc
    │           │   │   │   │   ├── cache.cpython-311.pyc
    │           │   │   │   │   ├── controller.cpython-311.pyc
    │           │   │   │   │   ├── filewrapper.cpython-311.pyc
    │           │   │   │   │   ├── heuristics.cpython-311.pyc
    │           │   │   │   │   ├── serialize.cpython-311.pyc
    │           │   │   │   │   └── wrapper.cpython-311.pyc
    │           │   │   │   ├── _cmd.py
    │           │   │   │   ├── adapter.py
    │           │   │   │   ├── cache.py
    │           │   │   │   ├── caches
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── file_cache.cpython-311.pyc
    │           │   │   │   │   │   └── redis_cache.cpython-311.pyc
    │           │   │   │   │   ├── file_cache.py
    │           │   │   │   │   └── redis_cache.py
    │           │   │   │   ├── controller.py
    │           │   │   │   ├── filewrapper.py
    │           │   │   │   ├── heuristics.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── serialize.py
    │           │   │   │   └── wrapper.py
    │           │   │   ├── certifi
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   └── core.cpython-311.pyc
    │           │   │   │   ├── cacert.pem
    │           │   │   │   ├── core.py
    │           │   │   │   └── py.typed
    │           │   │   ├── distlib
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── compat.cpython-311.pyc
    │           │   │   │   │   ├── database.cpython-311.pyc
    │           │   │   │   │   ├── index.cpython-311.pyc
    │           │   │   │   │   ├── locators.cpython-311.pyc
    │           │   │   │   │   ├── manifest.cpython-311.pyc
    │           │   │   │   │   ├── markers.cpython-311.pyc
    │           │   │   │   │   ├── metadata.cpython-311.pyc
    │           │   │   │   │   ├── resources.cpython-311.pyc
    │           │   │   │   │   ├── scripts.cpython-311.pyc
    │           │   │   │   │   ├── util.cpython-311.pyc
    │           │   │   │   │   ├── version.cpython-311.pyc
    │           │   │   │   │   └── wheel.cpython-311.pyc
    │           │   │   │   ├── compat.py
    │           │   │   │   ├── database.py
    │           │   │   │   ├── index.py
    │           │   │   │   ├── locators.py
    │           │   │   │   ├── manifest.py
    │           │   │   │   ├── markers.py
    │           │   │   │   ├── metadata.py
    │           │   │   │   ├── resources.py
    │           │   │   │   ├── scripts.py
    │           │   │   │   ├── t32.exe
    │           │   │   │   ├── t64-arm.exe
    │           │   │   │   ├── t64.exe
    │           │   │   │   ├── util.py
    │           │   │   │   ├── version.py
    │           │   │   │   ├── w32.exe
    │           │   │   │   ├── w64-arm.exe
    │           │   │   │   ├── w64.exe
    │           │   │   │   └── wheel.py
    │           │   │   ├── distro
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   └── distro.cpython-311.pyc
    │           │   │   │   ├── distro.py
    │           │   │   │   └── py.typed
    │           │   │   ├── idna
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── codec.cpython-311.pyc
    │           │   │   │   │   ├── compat.cpython-311.pyc
    │           │   │   │   │   ├── core.cpython-311.pyc
    │           │   │   │   │   ├── idnadata.cpython-311.pyc
    │           │   │   │   │   ├── intranges.cpython-311.pyc
    │           │   │   │   │   ├── package_data.cpython-311.pyc
    │           │   │   │   │   └── uts46data.cpython-311.pyc
    │           │   │   │   ├── codec.py
    │           │   │   │   ├── compat.py
    │           │   │   │   ├── core.py
    │           │   │   │   ├── idnadata.py
    │           │   │   │   ├── intranges.py
    │           │   │   │   ├── package_data.py
    │           │   │   │   ├── py.typed
    │           │   │   │   └── uts46data.py
    │           │   │   ├── msgpack
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── exceptions.cpython-311.pyc
    │           │   │   │   │   ├── ext.cpython-311.pyc
    │           │   │   │   │   └── fallback.cpython-311.pyc
    │           │   │   │   ├── exceptions.py
    │           │   │   │   ├── ext.py
    │           │   │   │   └── fallback.py
    │           │   │   ├── packaging
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _elffile.cpython-311.pyc
    │           │   │   │   │   ├── _manylinux.cpython-311.pyc
    │           │   │   │   │   ├── _musllinux.cpython-311.pyc
    │           │   │   │   │   ├── _parser.cpython-311.pyc
    │           │   │   │   │   ├── _structures.cpython-311.pyc
    │           │   │   │   │   ├── _tokenizer.cpython-311.pyc
    │           │   │   │   │   ├── markers.cpython-311.pyc
    │           │   │   │   │   ├── metadata.cpython-311.pyc
    │           │   │   │   │   ├── requirements.cpython-311.pyc
    │           │   │   │   │   ├── specifiers.cpython-311.pyc
    │           │   │   │   │   ├── tags.cpython-311.pyc
    │           │   │   │   │   ├── utils.cpython-311.pyc
    │           │   │   │   │   └── version.cpython-311.pyc
    │           │   │   │   ├── _elffile.py
    │           │   │   │   ├── _manylinux.py
    │           │   │   │   ├── _musllinux.py
    │           │   │   │   ├── _parser.py
    │           │   │   │   ├── _structures.py
    │           │   │   │   ├── _tokenizer.py
    │           │   │   │   ├── markers.py
    │           │   │   │   ├── metadata.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── requirements.py
    │           │   │   │   ├── specifiers.py
    │           │   │   │   ├── tags.py
    │           │   │   │   ├── utils.py
    │           │   │   │   └── version.py
    │           │   │   ├── pkg_resources
    │           │   │   │   ├── __init__.py
    │           │   │   │   └── __pycache__
    │           │   │   │       └── __init__.cpython-311.pyc
    │           │   │   ├── platformdirs
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   ├── android.cpython-311.pyc
    │           │   │   │   │   ├── api.cpython-311.pyc
    │           │   │   │   │   ├── macos.cpython-311.pyc
    │           │   │   │   │   ├── unix.cpython-311.pyc
    │           │   │   │   │   ├── version.cpython-311.pyc
    │           │   │   │   │   └── windows.cpython-311.pyc
    │           │   │   │   ├── android.py
    │           │   │   │   ├── api.py
    │           │   │   │   ├── macos.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── unix.py
    │           │   │   │   ├── version.py
    │           │   │   │   └── windows.py
    │           │   │   ├── pygments
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   ├── cmdline.cpython-311.pyc
    │           │   │   │   │   ├── console.cpython-311.pyc
    │           │   │   │   │   ├── filter.cpython-311.pyc
    │           │   │   │   │   ├── formatter.cpython-311.pyc
    │           │   │   │   │   ├── lexer.cpython-311.pyc
    │           │   │   │   │   ├── modeline.cpython-311.pyc
    │           │   │   │   │   ├── plugin.cpython-311.pyc
    │           │   │   │   │   ├── regexopt.cpython-311.pyc
    │           │   │   │   │   ├── scanner.cpython-311.pyc
    │           │   │   │   │   ├── sphinxext.cpython-311.pyc
    │           │   │   │   │   ├── style.cpython-311.pyc
    │           │   │   │   │   ├── token.cpython-311.pyc
    │           │   │   │   │   ├── unistring.cpython-311.pyc
    │           │   │   │   │   └── util.cpython-311.pyc
    │           │   │   │   ├── cmdline.py
    │           │   │   │   ├── console.py
    │           │   │   │   ├── filter.py
    │           │   │   │   ├── filters
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   └── __pycache__
    │           │   │   │   │       └── __init__.cpython-311.pyc
    │           │   │   │   ├── formatter.py
    │           │   │   │   ├── formatters
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── _mapping.cpython-311.pyc
    │           │   │   │   │   │   ├── bbcode.cpython-311.pyc
    │           │   │   │   │   │   ├── groff.cpython-311.pyc
    │           │   │   │   │   │   ├── html.cpython-311.pyc
    │           │   │   │   │   │   ├── img.cpython-311.pyc
    │           │   │   │   │   │   ├── irc.cpython-311.pyc
    │           │   │   │   │   │   ├── latex.cpython-311.pyc
    │           │   │   │   │   │   ├── other.cpython-311.pyc
    │           │   │   │   │   │   ├── pangomarkup.cpython-311.pyc
    │           │   │   │   │   │   ├── rtf.cpython-311.pyc
    │           │   │   │   │   │   ├── svg.cpython-311.pyc
    │           │   │   │   │   │   ├── terminal.cpython-311.pyc
    │           │   │   │   │   │   └── terminal256.cpython-311.pyc
    │           │   │   │   │   ├── _mapping.py
    │           │   │   │   │   ├── bbcode.py
    │           │   │   │   │   ├── groff.py
    │           │   │   │   │   ├── html.py
    │           │   │   │   │   ├── img.py
    │           │   │   │   │   ├── irc.py
    │           │   │   │   │   ├── latex.py
    │           │   │   │   │   ├── other.py
    │           │   │   │   │   ├── pangomarkup.py
    │           │   │   │   │   ├── rtf.py
    │           │   │   │   │   ├── svg.py
    │           │   │   │   │   ├── terminal.py
    │           │   │   │   │   └── terminal256.py
    │           │   │   │   ├── lexer.py
    │           │   │   │   ├── lexers
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── _mapping.cpython-311.pyc
    │           │   │   │   │   │   └── python.cpython-311.pyc
    │           │   │   │   │   ├── _mapping.py
    │           │   │   │   │   └── python.py
    │           │   │   │   ├── modeline.py
    │           │   │   │   ├── plugin.py
    │           │   │   │   ├── regexopt.py
    │           │   │   │   ├── scanner.py
    │           │   │   │   ├── sphinxext.py
    │           │   │   │   ├── style.py
    │           │   │   │   ├── styles
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── _mapping.cpython-311.pyc
    │           │   │   │   │   └── _mapping.py
    │           │   │   │   ├── token.py
    │           │   │   │   ├── unistring.py
    │           │   │   │   └── util.py
    │           │   │   ├── pyproject_hooks
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _compat.cpython-311.pyc
    │           │   │   │   │   └── _impl.cpython-311.pyc
    │           │   │   │   ├── _compat.py
    │           │   │   │   ├── _impl.py
    │           │   │   │   └── _in_process
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   └── _in_process.cpython-311.pyc
    │           │   │   │       └── _in_process.py
    │           │   │   ├── requests
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __version__.cpython-311.pyc
    │           │   │   │   │   ├── _internal_utils.cpython-311.pyc
    │           │   │   │   │   ├── adapters.cpython-311.pyc
    │           │   │   │   │   ├── api.cpython-311.pyc
    │           │   │   │   │   ├── auth.cpython-311.pyc
    │           │   │   │   │   ├── certs.cpython-311.pyc
    │           │   │   │   │   ├── compat.cpython-311.pyc
    │           │   │   │   │   ├── cookies.cpython-311.pyc
    │           │   │   │   │   ├── exceptions.cpython-311.pyc
    │           │   │   │   │   ├── help.cpython-311.pyc
    │           │   │   │   │   ├── hooks.cpython-311.pyc
    │           │   │   │   │   ├── models.cpython-311.pyc
    │           │   │   │   │   ├── packages.cpython-311.pyc
    │           │   │   │   │   ├── sessions.cpython-311.pyc
    │           │   │   │   │   ├── status_codes.cpython-311.pyc
    │           │   │   │   │   ├── structures.cpython-311.pyc
    │           │   │   │   │   └── utils.cpython-311.pyc
    │           │   │   │   ├── __version__.py
    │           │   │   │   ├── _internal_utils.py
    │           │   │   │   ├── adapters.py
    │           │   │   │   ├── api.py
    │           │   │   │   ├── auth.py
    │           │   │   │   ├── certs.py
    │           │   │   │   ├── compat.py
    │           │   │   │   ├── cookies.py
    │           │   │   │   ├── exceptions.py
    │           │   │   │   ├── help.py
    │           │   │   │   ├── hooks.py
    │           │   │   │   ├── models.py
    │           │   │   │   ├── packages.py
    │           │   │   │   ├── sessions.py
    │           │   │   │   ├── status_codes.py
    │           │   │   │   ├── structures.py
    │           │   │   │   └── utils.py
    │           │   │   ├── resolvelib
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── providers.cpython-311.pyc
    │           │   │   │   │   ├── reporters.cpython-311.pyc
    │           │   │   │   │   ├── resolvers.cpython-311.pyc
    │           │   │   │   │   └── structs.cpython-311.pyc
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── collections_abc.cpython-311.pyc
    │           │   │   │   │   └── collections_abc.py
    │           │   │   │   ├── providers.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── reporters.py
    │           │   │   │   ├── resolvers.py
    │           │   │   │   └── structs.py
    │           │   │   ├── rich
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   ├── _cell_widths.cpython-311.pyc
    │           │   │   │   │   ├── _emoji_codes.cpython-311.pyc
    │           │   │   │   │   ├── _emoji_replace.cpython-311.pyc
    │           │   │   │   │   ├── _export_format.cpython-311.pyc
    │           │   │   │   │   ├── _extension.cpython-311.pyc
    │           │   │   │   │   ├── _fileno.cpython-311.pyc
    │           │   │   │   │   ├── _inspect.cpython-311.pyc
    │           │   │   │   │   ├── _log_render.cpython-311.pyc
    │           │   │   │   │   ├── _loop.cpython-311.pyc
    │           │   │   │   │   ├── _null_file.cpython-311.pyc
    │           │   │   │   │   ├── _palettes.cpython-311.pyc
    │           │   │   │   │   ├── _pick.cpython-311.pyc
    │           │   │   │   │   ├── _ratio.cpython-311.pyc
    │           │   │   │   │   ├── _spinners.cpython-311.pyc
    │           │   │   │   │   ├── _stack.cpython-311.pyc
    │           │   │   │   │   ├── _timer.cpython-311.pyc
    │           │   │   │   │   ├── _win32_console.cpython-311.pyc
    │           │   │   │   │   ├── _windows_renderer.cpython-311.pyc
    │           │   │   │   │   ├── _windows.cpython-311.pyc
    │           │   │   │   │   ├── _wrap.cpython-311.pyc
    │           │   │   │   │   ├── abc.cpython-311.pyc
    │           │   │   │   │   ├── align.cpython-311.pyc
    │           │   │   │   │   ├── ansi.cpython-311.pyc
    │           │   │   │   │   ├── bar.cpython-311.pyc
    │           │   │   │   │   ├── box.cpython-311.pyc
    │           │   │   │   │   ├── cells.cpython-311.pyc
    │           │   │   │   │   ├── color_triplet.cpython-311.pyc
    │           │   │   │   │   ├── color.cpython-311.pyc
    │           │   │   │   │   ├── columns.cpython-311.pyc
    │           │   │   │   │   ├── console.cpython-311.pyc
    │           │   │   │   │   ├── constrain.cpython-311.pyc
    │           │   │   │   │   ├── containers.cpython-311.pyc
    │           │   │   │   │   ├── control.cpython-311.pyc
    │           │   │   │   │   ├── default_styles.cpython-311.pyc
    │           │   │   │   │   ├── diagnose.cpython-311.pyc
    │           │   │   │   │   ├── emoji.cpython-311.pyc
    │           │   │   │   │   ├── errors.cpython-311.pyc
    │           │   │   │   │   ├── file_proxy.cpython-311.pyc
    │           │   │   │   │   ├── filesize.cpython-311.pyc
    │           │   │   │   │   ├── highlighter.cpython-311.pyc
    │           │   │   │   │   ├── json.cpython-311.pyc
    │           │   │   │   │   ├── jupyter.cpython-311.pyc
    │           │   │   │   │   ├── layout.cpython-311.pyc
    │           │   │   │   │   ├── live_render.cpython-311.pyc
    │           │   │   │   │   ├── live.cpython-311.pyc
    │           │   │   │   │   ├── logging.cpython-311.pyc
    │           │   │   │   │   ├── markup.cpython-311.pyc
    │           │   │   │   │   ├── measure.cpython-311.pyc
    │           │   │   │   │   ├── padding.cpython-311.pyc
    │           │   │   │   │   ├── pager.cpython-311.pyc
    │           │   │   │   │   ├── palette.cpython-311.pyc
    │           │   │   │   │   ├── panel.cpython-311.pyc
    │           │   │   │   │   ├── pretty.cpython-311.pyc
    │           │   │   │   │   ├── progress_bar.cpython-311.pyc
    │           │   │   │   │   ├── progress.cpython-311.pyc
    │           │   │   │   │   ├── prompt.cpython-311.pyc
    │           │   │   │   │   ├── protocol.cpython-311.pyc
    │           │   │   │   │   ├── region.cpython-311.pyc
    │           │   │   │   │   ├── repr.cpython-311.pyc
    │           │   │   │   │   ├── rule.cpython-311.pyc
    │           │   │   │   │   ├── scope.cpython-311.pyc
    │           │   │   │   │   ├── screen.cpython-311.pyc
    │           │   │   │   │   ├── segment.cpython-311.pyc
    │           │   │   │   │   ├── spinner.cpython-311.pyc
    │           │   │   │   │   ├── status.cpython-311.pyc
    │           │   │   │   │   ├── style.cpython-311.pyc
    │           │   │   │   │   ├── styled.cpython-311.pyc
    │           │   │   │   │   ├── syntax.cpython-311.pyc
    │           │   │   │   │   ├── table.cpython-311.pyc
    │           │   │   │   │   ├── terminal_theme.cpython-311.pyc
    │           │   │   │   │   ├── text.cpython-311.pyc
    │           │   │   │   │   ├── theme.cpython-311.pyc
    │           │   │   │   │   ├── themes.cpython-311.pyc
    │           │   │   │   │   ├── traceback.cpython-311.pyc
    │           │   │   │   │   └── tree.cpython-311.pyc
    │           │   │   │   ├── _cell_widths.py
    │           │   │   │   ├── _emoji_codes.py
    │           │   │   │   ├── _emoji_replace.py
    │           │   │   │   ├── _export_format.py
    │           │   │   │   ├── _extension.py
    │           │   │   │   ├── _fileno.py
    │           │   │   │   ├── _inspect.py
    │           │   │   │   ├── _log_render.py
    │           │   │   │   ├── _loop.py
    │           │   │   │   ├── _null_file.py
    │           │   │   │   ├── _palettes.py
    │           │   │   │   ├── _pick.py
    │           │   │   │   ├── _ratio.py
    │           │   │   │   ├── _spinners.py
    │           │   │   │   ├── _stack.py
    │           │   │   │   ├── _timer.py
    │           │   │   │   ├── _win32_console.py
    │           │   │   │   ├── _windows_renderer.py
    │           │   │   │   ├── _windows.py
    │           │   │   │   ├── _wrap.py
    │           │   │   │   ├── abc.py
    │           │   │   │   ├── align.py
    │           │   │   │   ├── ansi.py
    │           │   │   │   ├── bar.py
    │           │   │   │   ├── box.py
    │           │   │   │   ├── cells.py
    │           │   │   │   ├── color_triplet.py
    │           │   │   │   ├── color.py
    │           │   │   │   ├── columns.py
    │           │   │   │   ├── console.py
    │           │   │   │   ├── constrain.py
    │           │   │   │   ├── containers.py
    │           │   │   │   ├── control.py
    │           │   │   │   ├── default_styles.py
    │           │   │   │   ├── diagnose.py
    │           │   │   │   ├── emoji.py
    │           │   │   │   ├── errors.py
    │           │   │   │   ├── file_proxy.py
    │           │   │   │   ├── filesize.py
    │           │   │   │   ├── highlighter.py
    │           │   │   │   ├── json.py
    │           │   │   │   ├── jupyter.py
    │           │   │   │   ├── layout.py
    │           │   │   │   ├── live_render.py
    │           │   │   │   ├── live.py
    │           │   │   │   ├── logging.py
    │           │   │   │   ├── markup.py
    │           │   │   │   ├── measure.py
    │           │   │   │   ├── padding.py
    │           │   │   │   ├── pager.py
    │           │   │   │   ├── palette.py
    │           │   │   │   ├── panel.py
    │           │   │   │   ├── pretty.py
    │           │   │   │   ├── progress_bar.py
    │           │   │   │   ├── progress.py
    │           │   │   │   ├── prompt.py
    │           │   │   │   ├── protocol.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── region.py
    │           │   │   │   ├── repr.py
    │           │   │   │   ├── rule.py
    │           │   │   │   ├── scope.py
    │           │   │   │   ├── screen.py
    │           │   │   │   ├── segment.py
    │           │   │   │   ├── spinner.py
    │           │   │   │   ├── status.py
    │           │   │   │   ├── style.py
    │           │   │   │   ├── styled.py
    │           │   │   │   ├── syntax.py
    │           │   │   │   ├── table.py
    │           │   │   │   ├── terminal_theme.py
    │           │   │   │   ├── text.py
    │           │   │   │   ├── theme.py
    │           │   │   │   ├── themes.py
    │           │   │   │   ├── traceback.py
    │           │   │   │   └── tree.py
    │           │   │   ├── tomli
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _parser.cpython-311.pyc
    │           │   │   │   │   ├── _re.cpython-311.pyc
    │           │   │   │   │   └── _types.cpython-311.pyc
    │           │   │   │   ├── _parser.py
    │           │   │   │   ├── _re.py
    │           │   │   │   ├── _types.py
    │           │   │   │   └── py.typed
    │           │   │   ├── truststore
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _api.cpython-311.pyc
    │           │   │   │   │   ├── _macos.cpython-311.pyc
    │           │   │   │   │   ├── _openssl.cpython-311.pyc
    │           │   │   │   │   ├── _ssl_constants.cpython-311.pyc
    │           │   │   │   │   └── _windows.cpython-311.pyc
    │           │   │   │   ├── _api.py
    │           │   │   │   ├── _macos.py
    │           │   │   │   ├── _openssl.py
    │           │   │   │   ├── _ssl_constants.py
    │           │   │   │   ├── _windows.py
    │           │   │   │   └── py.typed
    │           │   │   ├── typing_extensions.py
    │           │   │   ├── urllib3
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _collections.cpython-311.pyc
    │           │   │   │   │   ├── _version.cpython-311.pyc
    │           │   │   │   │   ├── connection.cpython-311.pyc
    │           │   │   │   │   ├── connectionpool.cpython-311.pyc
    │           │   │   │   │   ├── exceptions.cpython-311.pyc
    │           │   │   │   │   ├── fields.cpython-311.pyc
    │           │   │   │   │   ├── filepost.cpython-311.pyc
    │           │   │   │   │   ├── poolmanager.cpython-311.pyc
    │           │   │   │   │   ├── request.cpython-311.pyc
    │           │   │   │   │   └── response.cpython-311.pyc
    │           │   │   │   ├── _collections.py
    │           │   │   │   ├── _version.py
    │           │   │   │   ├── connection.py
    │           │   │   │   ├── connectionpool.py
    │           │   │   │   ├── contrib
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── _appengine_environ.cpython-311.pyc
    │           │   │   │   │   │   ├── appengine.cpython-311.pyc
    │           │   │   │   │   │   ├── ntlmpool.cpython-311.pyc
    │           │   │   │   │   │   ├── pyopenssl.cpython-311.pyc
    │           │   │   │   │   │   ├── securetransport.cpython-311.pyc
    │           │   │   │   │   │   └── socks.cpython-311.pyc
    │           │   │   │   │   ├── _appengine_environ.py
    │           │   │   │   │   ├── _securetransport
    │           │   │   │   │   │   ├── __init__.py
    │           │   │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   │   ├── bindings.cpython-311.pyc
    │           │   │   │   │   │   │   └── low_level.cpython-311.pyc
    │           │   │   │   │   │   ├── bindings.py
    │           │   │   │   │   │   └── low_level.py
    │           │   │   │   │   ├── appengine.py
    │           │   │   │   │   ├── ntlmpool.py
    │           │   │   │   │   ├── pyopenssl.py
    │           │   │   │   │   ├── securetransport.py
    │           │   │   │   │   └── socks.py
    │           │   │   │   ├── exceptions.py
    │           │   │   │   ├── fields.py
    │           │   │   │   ├── filepost.py
    │           │   │   │   ├── packages
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── six.cpython-311.pyc
    │           │   │   │   │   ├── backports
    │           │   │   │   │   │   ├── __init__.py
    │           │   │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   │   ├── makefile.cpython-311.pyc
    │           │   │   │   │   │   │   └── weakref_finalize.cpython-311.pyc
    │           │   │   │   │   │   ├── makefile.py
    │           │   │   │   │   │   └── weakref_finalize.py
    │           │   │   │   │   └── six.py
    │           │   │   │   ├── poolmanager.py
    │           │   │   │   ├── request.py
    │           │   │   │   ├── response.py
    │           │   │   │   └── util
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   ├── connection.cpython-311.pyc
    │           │   │   │       │   ├── proxy.cpython-311.pyc
    │           │   │   │       │   ├── queue.cpython-311.pyc
    │           │   │   │       │   ├── request.cpython-311.pyc
    │           │   │   │       │   ├── response.cpython-311.pyc
    │           │   │   │       │   ├── retry.cpython-311.pyc
    │           │   │   │       │   ├── ssl_.cpython-311.pyc
    │           │   │   │       │   ├── ssl_match_hostname.cpython-311.pyc
    │           │   │   │       │   ├── ssltransport.cpython-311.pyc
    │           │   │   │       │   ├── timeout.cpython-311.pyc
    │           │   │   │       │   ├── url.cpython-311.pyc
    │           │   │   │       │   └── wait.cpython-311.pyc
    │           │   │   │       ├── connection.py
    │           │   │   │       ├── proxy.py
    │           │   │   │       ├── queue.py
    │           │   │   │       ├── request.py
    │           │   │   │       ├── response.py
    │           │   │   │       ├── retry.py
    │           │   │   │       ├── ssl_.py
    │           │   │   │       ├── ssl_match_hostname.py
    │           │   │   │       ├── ssltransport.py
    │           │   │   │       ├── timeout.py
    │           │   │   │       ├── url.py
    │           │   │   │       └── wait.py
    │           │   │   └── vendor.txt
    │           │   └── py.typed
    │           ├── pip-24.3.1.dist-info
    │           │   ├── AUTHORS.txt
    │           │   ├── entry_points.txt
    │           │   ├── INSTALLER
    │           │   ├── LICENSE.txt
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── REQUESTED
    │           │   ├── top_level.txt
    │           │   └── WHEEL
    │           ├── pkg_resources
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   └── __init__.cpython-311.pyc
    │           │   ├── api_tests.txt
    │           │   ├── py.typed
    │           │   └── tests
    │           │       ├── __init__.py
    │           │       ├── __pycache__
    │           │       │   ├── __init__.cpython-311.pyc
    │           │       │   ├── test_find_distributions.cpython-311.pyc
    │           │       │   ├── test_integration_zope_interface.cpython-311.pyc
    │           │       │   ├── test_markers.cpython-311.pyc
    │           │       │   ├── test_pkg_resources.cpython-311.pyc
    │           │       │   ├── test_resources.cpython-311.pyc
    │           │       │   └── test_working_set.cpython-311.pyc
    │           │       ├── data
    │           │       │   ├── my-test-package_unpacked-egg
    │           │       │   │   └── my_test_package-1.0-py3.7.egg
    │           │       │   │       └── EGG-INFO
    │           │       │   │           ├── dependency_links.txt
    │           │       │   │           ├── PKG-INFO
    │           │       │   │           ├── SOURCES.txt
    │           │       │   │           ├── top_level.txt
    │           │       │   │           └── zip-safe
    │           │       │   ├── my-test-package_zipped-egg
    │           │       │   │   └── my_test_package-1.0-py3.7.egg
    │           │       │   ├── my-test-package-source
    │           │       │   │   ├── __pycache__
    │           │       │   │   │   └── setup.cpython-311.pyc
    │           │       │   │   ├── setup.cfg
    │           │       │   │   └── setup.py
    │           │       │   └── my-test-package-zip
    │           │       │       └── my-test-package.zip
    │           │       ├── test_find_distributions.py
    │           │       ├── test_integration_zope_interface.py
    │           │       ├── test_markers.py
    │           │       ├── test_pkg_resources.py
    │           │       ├── test_resources.py
    │           │       └── test_working_set.py
    │           ├── pluggy
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── _callers.cpython-311.pyc
    │           │   │   ├── _hooks.cpython-311.pyc
    │           │   │   ├── _manager.cpython-311.pyc
    │           │   │   ├── _result.cpython-311.pyc
    │           │   │   ├── _tracing.cpython-311.pyc
    │           │   │   ├── _version.cpython-311.pyc
    │           │   │   └── _warnings.cpython-311.pyc
    │           │   ├── _callers.py
    │           │   ├── _hooks.py
    │           │   ├── _manager.py
    │           │   ├── _result.py
    │           │   ├── _tracing.py
    │           │   ├── _version.py
    │           │   ├── _warnings.py
    │           │   └── py.typed
    │           ├── pluggy-1.5.0.dist-info
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── top_level.txt
    │           │   └── WHEEL
    │           ├── pyproject_hooks
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   └── _impl.cpython-311.pyc
    │           │   ├── _impl.py
    │           │   ├── _in_process
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   └── _in_process.cpython-311.pyc
    │           │   │   └── _in_process.py
    │           │   └── py.typed
    │           ├── pyproject_hooks-1.2.0.dist-info
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   └── WHEEL
    │           ├── setuptools
    │           │   ├── __init__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   ├── _core_metadata.cpython-311.pyc
    │           │   │   ├── _entry_points.cpython-311.pyc
    │           │   │   ├── _imp.cpython-311.pyc
    │           │   │   ├── _importlib.cpython-311.pyc
    │           │   │   ├── _itertools.cpython-311.pyc
    │           │   │   ├── _normalization.cpython-311.pyc
    │           │   │   ├── _path.cpython-311.pyc
    │           │   │   ├── _reqs.cpython-311.pyc
    │           │   │   ├── archive_util.cpython-311.pyc
    │           │   │   ├── build_meta.cpython-311.pyc
    │           │   │   ├── depends.cpython-311.pyc
    │           │   │   ├── discovery.cpython-311.pyc
    │           │   │   ├── dist.cpython-311.pyc
    │           │   │   ├── errors.cpython-311.pyc
    │           │   │   ├── extension.cpython-311.pyc
    │           │   │   ├── glob.cpython-311.pyc
    │           │   │   ├── installer.cpython-311.pyc
    │           │   │   ├── launch.cpython-311.pyc
    │           │   │   ├── logging.cpython-311.pyc
    │           │   │   ├── modified.cpython-311.pyc
    │           │   │   ├── monkey.cpython-311.pyc
    │           │   │   ├── msvc.cpython-311.pyc
    │           │   │   ├── namespaces.cpython-311.pyc
    │           │   │   ├── package_index.cpython-311.pyc
    │           │   │   ├── sandbox.cpython-311.pyc
    │           │   │   ├── unicode_utils.cpython-311.pyc
    │           │   │   ├── version.cpython-311.pyc
    │           │   │   ├── warnings.cpython-311.pyc
    │           │   │   ├── wheel.cpython-311.pyc
    │           │   │   └── windows_support.cpython-311.pyc
    │           │   ├── _core_metadata.py
    │           │   ├── _distutils
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── _collections.cpython-311.pyc
    │           │   │   │   ├── _functools.cpython-311.pyc
    │           │   │   │   ├── _itertools.cpython-311.pyc
    │           │   │   │   ├── _log.cpython-311.pyc
    │           │   │   │   ├── _macos_compat.cpython-311.pyc
    │           │   │   │   ├── _modified.cpython-311.pyc
    │           │   │   │   ├── _msvccompiler.cpython-311.pyc
    │           │   │   │   ├── archive_util.cpython-311.pyc
    │           │   │   │   ├── bcppcompiler.cpython-311.pyc
    │           │   │   │   ├── ccompiler.cpython-311.pyc
    │           │   │   │   ├── cmd.cpython-311.pyc
    │           │   │   │   ├── config.cpython-311.pyc
    │           │   │   │   ├── core.cpython-311.pyc
    │           │   │   │   ├── cygwinccompiler.cpython-311.pyc
    │           │   │   │   ├── debug.cpython-311.pyc
    │           │   │   │   ├── dep_util.cpython-311.pyc
    │           │   │   │   ├── dir_util.cpython-311.pyc
    │           │   │   │   ├── dist.cpython-311.pyc
    │           │   │   │   ├── errors.cpython-311.pyc
    │           │   │   │   ├── extension.cpython-311.pyc
    │           │   │   │   ├── fancy_getopt.cpython-311.pyc
    │           │   │   │   ├── file_util.cpython-311.pyc
    │           │   │   │   ├── filelist.cpython-311.pyc
    │           │   │   │   ├── log.cpython-311.pyc
    │           │   │   │   ├── spawn.cpython-311.pyc
    │           │   │   │   ├── sysconfig.cpython-311.pyc
    │           │   │   │   ├── text_file.cpython-311.pyc
    │           │   │   │   ├── unixccompiler.cpython-311.pyc
    │           │   │   │   ├── util.cpython-311.pyc
    │           │   │   │   ├── version.cpython-311.pyc
    │           │   │   │   ├── versionpredicate.cpython-311.pyc
    │           │   │   │   └── zosccompiler.cpython-311.pyc
    │           │   │   ├── _collections.py
    │           │   │   ├── _functools.py
    │           │   │   ├── _itertools.py
    │           │   │   ├── _log.py
    │           │   │   ├── _macos_compat.py
    │           │   │   ├── _modified.py
    │           │   │   ├── _msvccompiler.py
    │           │   │   ├── archive_util.py
    │           │   │   ├── bcppcompiler.py
    │           │   │   ├── ccompiler.py
    │           │   │   ├── cmd.py
    │           │   │   ├── command
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _framework_compat.cpython-311.pyc
    │           │   │   │   │   ├── bdist_dumb.cpython-311.pyc
    │           │   │   │   │   ├── bdist_rpm.cpython-311.pyc
    │           │   │   │   │   ├── bdist.cpython-311.pyc
    │           │   │   │   │   ├── build_clib.cpython-311.pyc
    │           │   │   │   │   ├── build_ext.cpython-311.pyc
    │           │   │   │   │   ├── build_py.cpython-311.pyc
    │           │   │   │   │   ├── build_scripts.cpython-311.pyc
    │           │   │   │   │   ├── build.cpython-311.pyc
    │           │   │   │   │   ├── check.cpython-311.pyc
    │           │   │   │   │   ├── clean.cpython-311.pyc
    │           │   │   │   │   ├── config.cpython-311.pyc
    │           │   │   │   │   ├── install_data.cpython-311.pyc
    │           │   │   │   │   ├── install_egg_info.cpython-311.pyc
    │           │   │   │   │   ├── install_headers.cpython-311.pyc
    │           │   │   │   │   ├── install_lib.cpython-311.pyc
    │           │   │   │   │   ├── install_scripts.cpython-311.pyc
    │           │   │   │   │   ├── install.cpython-311.pyc
    │           │   │   │   │   ├── register.cpython-311.pyc
    │           │   │   │   │   ├── sdist.cpython-311.pyc
    │           │   │   │   │   └── upload.cpython-311.pyc
    │           │   │   │   ├── _framework_compat.py
    │           │   │   │   ├── bdist_dumb.py
    │           │   │   │   ├── bdist_rpm.py
    │           │   │   │   ├── bdist.py
    │           │   │   │   ├── build_clib.py
    │           │   │   │   ├── build_ext.py
    │           │   │   │   ├── build_py.py
    │           │   │   │   ├── build_scripts.py
    │           │   │   │   ├── build.py
    │           │   │   │   ├── check.py
    │           │   │   │   ├── clean.py
    │           │   │   │   ├── config.py
    │           │   │   │   ├── install_data.py
    │           │   │   │   ├── install_egg_info.py
    │           │   │   │   ├── install_headers.py
    │           │   │   │   ├── install_lib.py
    │           │   │   │   ├── install_scripts.py
    │           │   │   │   ├── install.py
    │           │   │   │   ├── register.py
    │           │   │   │   ├── sdist.py
    │           │   │   │   └── upload.py
    │           │   │   ├── compat
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── py38.cpython-311.pyc
    │           │   │   │   │   └── py39.cpython-311.pyc
    │           │   │   │   ├── py38.py
    │           │   │   │   └── py39.py
    │           │   │   ├── config.py
    │           │   │   ├── core.py
    │           │   │   ├── cygwinccompiler.py
    │           │   │   ├── debug.py
    │           │   │   ├── dep_util.py
    │           │   │   ├── dir_util.py
    │           │   │   ├── dist.py
    │           │   │   ├── errors.py
    │           │   │   ├── extension.py
    │           │   │   ├── fancy_getopt.py
    │           │   │   ├── file_util.py
    │           │   │   ├── filelist.py
    │           │   │   ├── log.py
    │           │   │   ├── spawn.py
    │           │   │   ├── sysconfig.py
    │           │   │   ├── tests
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── support.cpython-311.pyc
    │           │   │   │   │   ├── test_archive_util.cpython-311.pyc
    │           │   │   │   │   ├── test_bdist_dumb.cpython-311.pyc
    │           │   │   │   │   ├── test_bdist_rpm.cpython-311.pyc
    │           │   │   │   │   ├── test_bdist.cpython-311.pyc
    │           │   │   │   │   ├── test_build_clib.cpython-311.pyc
    │           │   │   │   │   ├── test_build_ext.cpython-311.pyc
    │           │   │   │   │   ├── test_build_py.cpython-311.pyc
    │           │   │   │   │   ├── test_build_scripts.cpython-311.pyc
    │           │   │   │   │   ├── test_build.cpython-311.pyc
    │           │   │   │   │   ├── test_ccompiler.cpython-311.pyc
    │           │   │   │   │   ├── test_check.cpython-311.pyc
    │           │   │   │   │   ├── test_clean.cpython-311.pyc
    │           │   │   │   │   ├── test_cmd.cpython-311.pyc
    │           │   │   │   │   ├── test_config_cmd.cpython-311.pyc
    │           │   │   │   │   ├── test_config.cpython-311.pyc
    │           │   │   │   │   ├── test_core.cpython-311.pyc
    │           │   │   │   │   ├── test_cygwinccompiler.cpython-311.pyc
    │           │   │   │   │   ├── test_dir_util.cpython-311.pyc
    │           │   │   │   │   ├── test_dist.cpython-311.pyc
    │           │   │   │   │   ├── test_extension.cpython-311.pyc
    │           │   │   │   │   ├── test_file_util.cpython-311.pyc
    │           │   │   │   │   ├── test_filelist.cpython-311.pyc
    │           │   │   │   │   ├── test_install_data.cpython-311.pyc
    │           │   │   │   │   ├── test_install_headers.cpython-311.pyc
    │           │   │   │   │   ├── test_install_lib.cpython-311.pyc
    │           │   │   │   │   ├── test_install_scripts.cpython-311.pyc
    │           │   │   │   │   ├── test_install.cpython-311.pyc
    │           │   │   │   │   ├── test_log.cpython-311.pyc
    │           │   │   │   │   ├── test_mingwccompiler.cpython-311.pyc
    │           │   │   │   │   ├── test_modified.cpython-311.pyc
    │           │   │   │   │   ├── test_msvccompiler.cpython-311.pyc
    │           │   │   │   │   ├── test_register.cpython-311.pyc
    │           │   │   │   │   ├── test_sdist.cpython-311.pyc
    │           │   │   │   │   ├── test_spawn.cpython-311.pyc
    │           │   │   │   │   ├── test_sysconfig.cpython-311.pyc
    │           │   │   │   │   ├── test_text_file.cpython-311.pyc
    │           │   │   │   │   ├── test_unixccompiler.cpython-311.pyc
    │           │   │   │   │   ├── test_upload.cpython-311.pyc
    │           │   │   │   │   ├── test_util.cpython-311.pyc
    │           │   │   │   │   ├── test_version.cpython-311.pyc
    │           │   │   │   │   ├── test_versionpredicate.cpython-311.pyc
    │           │   │   │   │   └── unix_compat.cpython-311.pyc
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── py38.cpython-311.pyc
    │           │   │   │   │   └── py38.py
    │           │   │   │   ├── support.py
    │           │   │   │   ├── test_archive_util.py
    │           │   │   │   ├── test_bdist_dumb.py
    │           │   │   │   ├── test_bdist_rpm.py
    │           │   │   │   ├── test_bdist.py
    │           │   │   │   ├── test_build_clib.py
    │           │   │   │   ├── test_build_ext.py
    │           │   │   │   ├── test_build_py.py
    │           │   │   │   ├── test_build_scripts.py
    │           │   │   │   ├── test_build.py
    │           │   │   │   ├── test_ccompiler.py
    │           │   │   │   ├── test_check.py
    │           │   │   │   ├── test_clean.py
    │           │   │   │   ├── test_cmd.py
    │           │   │   │   ├── test_config_cmd.py
    │           │   │   │   ├── test_config.py
    │           │   │   │   ├── test_core.py
    │           │   │   │   ├── test_cygwinccompiler.py
    │           │   │   │   ├── test_dir_util.py
    │           │   │   │   ├── test_dist.py
    │           │   │   │   ├── test_extension.py
    │           │   │   │   ├── test_file_util.py
    │           │   │   │   ├── test_filelist.py
    │           │   │   │   ├── test_install_data.py
    │           │   │   │   ├── test_install_headers.py
    │           │   │   │   ├── test_install_lib.py
    │           │   │   │   ├── test_install_scripts.py
    │           │   │   │   ├── test_install.py
    │           │   │   │   ├── test_log.py
    │           │   │   │   ├── test_mingwccompiler.py
    │           │   │   │   ├── test_modified.py
    │           │   │   │   ├── test_msvccompiler.py
    │           │   │   │   ├── test_register.py
    │           │   │   │   ├── test_sdist.py
    │           │   │   │   ├── test_spawn.py
    │           │   │   │   ├── test_sysconfig.py
    │           │   │   │   ├── test_text_file.py
    │           │   │   │   ├── test_unixccompiler.py
    │           │   │   │   ├── test_upload.py
    │           │   │   │   ├── test_util.py
    │           │   │   │   ├── test_version.py
    │           │   │   │   ├── test_versionpredicate.py
    │           │   │   │   └── unix_compat.py
    │           │   │   ├── text_file.py
    │           │   │   ├── unixccompiler.py
    │           │   │   ├── util.py
    │           │   │   ├── version.py
    │           │   │   ├── versionpredicate.py
    │           │   │   └── zosccompiler.py
    │           │   ├── _entry_points.py
    │           │   ├── _imp.py
    │           │   ├── _importlib.py
    │           │   ├── _itertools.py
    │           │   ├── _normalization.py
    │           │   ├── _path.py
    │           │   ├── _reqs.py
    │           │   ├── _vendor
    │           │   │   ├── __pycache__
    │           │   │   │   └── typing_extensions.cpython-311.pyc
    │           │   │   ├── autocommand
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── autoasync.cpython-311.pyc
    │           │   │   │   │   ├── autocommand.cpython-311.pyc
    │           │   │   │   │   ├── automain.cpython-311.pyc
    │           │   │   │   │   ├── autoparse.cpython-311.pyc
    │           │   │   │   │   └── errors.cpython-311.pyc
    │           │   │   │   ├── autoasync.py
    │           │   │   │   ├── autocommand.py
    │           │   │   │   ├── automain.py
    │           │   │   │   ├── autoparse.py
    │           │   │   │   └── errors.py
    │           │   │   ├── autocommand-2.2.2.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── backports
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │   └── tarfile
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __main__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   └── __main__.cpython-311.pyc
    │           │   │   │       └── compat
    │           │   │   │           ├── __init__.py
    │           │   │   │           ├── __pycache__
    │           │   │   │           │   ├── __init__.cpython-311.pyc
    │           │   │   │           │   └── py38.cpython-311.pyc
    │           │   │   │           └── py38.py
    │           │   │   ├── backports.tarfile-1.2.0.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── importlib_metadata
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _adapters.cpython-311.pyc
    │           │   │   │   │   ├── _collections.cpython-311.pyc
    │           │   │   │   │   ├── _compat.cpython-311.pyc
    │           │   │   │   │   ├── _functools.cpython-311.pyc
    │           │   │   │   │   ├── _itertools.cpython-311.pyc
    │           │   │   │   │   ├── _meta.cpython-311.pyc
    │           │   │   │   │   ├── _text.cpython-311.pyc
    │           │   │   │   │   └── diagnose.cpython-311.pyc
    │           │   │   │   ├── _adapters.py
    │           │   │   │   ├── _collections.py
    │           │   │   │   ├── _compat.py
    │           │   │   │   ├── _functools.py
    │           │   │   │   ├── _itertools.py
    │           │   │   │   ├── _meta.py
    │           │   │   │   ├── _text.py
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── py311.cpython-311.pyc
    │           │   │   │   │   │   └── py39.cpython-311.pyc
    │           │   │   │   │   ├── py311.py
    │           │   │   │   │   └── py39.py
    │           │   │   │   ├── diagnose.py
    │           │   │   │   └── py.typed
    │           │   │   ├── importlib_metadata-8.0.0.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── importlib_resources
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _adapters.cpython-311.pyc
    │           │   │   │   │   ├── _common.cpython-311.pyc
    │           │   │   │   │   ├── _itertools.cpython-311.pyc
    │           │   │   │   │   ├── abc.cpython-311.pyc
    │           │   │   │   │   ├── functional.cpython-311.pyc
    │           │   │   │   │   ├── readers.cpython-311.pyc
    │           │   │   │   │   └── simple.cpython-311.pyc
    │           │   │   │   ├── _adapters.py
    │           │   │   │   ├── _common.py
    │           │   │   │   ├── _itertools.py
    │           │   │   │   ├── abc.py
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── py38.cpython-311.pyc
    │           │   │   │   │   │   └── py39.cpython-311.pyc
    │           │   │   │   │   ├── py38.py
    │           │   │   │   │   └── py39.py
    │           │   │   │   ├── functional.py
    │           │   │   │   ├── future
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── adapters.cpython-311.pyc
    │           │   │   │   │   └── adapters.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── readers.py
    │           │   │   │   ├── simple.py
    │           │   │   │   └── tests
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   ├── _path.cpython-311.pyc
    │           │   │   │       │   ├── test_compatibilty_files.cpython-311.pyc
    │           │   │   │       │   ├── test_contents.cpython-311.pyc
    │           │   │   │       │   ├── test_custom.cpython-311.pyc
    │           │   │   │       │   ├── test_files.cpython-311.pyc
    │           │   │   │       │   ├── test_functional.cpython-311.pyc
    │           │   │   │       │   ├── test_open.cpython-311.pyc
    │           │   │   │       │   ├── test_path.cpython-311.pyc
    │           │   │   │       │   ├── test_read.cpython-311.pyc
    │           │   │   │       │   ├── test_reader.cpython-311.pyc
    │           │   │   │       │   ├── test_resource.cpython-311.pyc
    │           │   │   │       │   ├── util.cpython-311.pyc
    │           │   │   │       │   └── zip.cpython-311.pyc
    │           │   │   │       ├── _path.py
    │           │   │   │       ├── compat
    │           │   │   │       │   ├── __init__.py
    │           │   │   │       │   ├── __pycache__
    │           │   │   │       │   │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   │   ├── py312.cpython-311.pyc
    │           │   │   │       │   │   └── py39.cpython-311.pyc
    │           │   │   │       │   ├── py312.py
    │           │   │   │       │   └── py39.py
    │           │   │   │       ├── data01
    │           │   │   │       │   ├── __init__.py
    │           │   │   │       │   ├── __pycache__
    │           │   │   │       │   │   └── __init__.cpython-311.pyc
    │           │   │   │       │   ├── binary.file
    │           │   │   │       │   ├── subdirectory
    │           │   │   │       │   │   ├── __init__.py
    │           │   │   │       │   │   ├── __pycache__
    │           │   │   │       │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │       │   │   └── binary.file
    │           │   │   │       │   ├── utf-16.file
    │           │   │   │       │   └── utf-8.file
    │           │   │   │       ├── data02
    │           │   │   │       │   ├── __init__.py
    │           │   │   │       │   ├── __pycache__
    │           │   │   │       │   │   └── __init__.cpython-311.pyc
    │           │   │   │       │   ├── one
    │           │   │   │       │   │   ├── __init__.py
    │           │   │   │       │   │   ├── __pycache__
    │           │   │   │       │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │       │   │   └── resource1.txt
    │           │   │   │       │   ├── subdirectory
    │           │   │   │       │   │   └── subsubdir
    │           │   │   │       │   │       └── resource.txt
    │           │   │   │       │   └── two
    │           │   │   │       │       ├── __init__.py
    │           │   │   │       │       ├── __pycache__
    │           │   │   │       │       │   └── __init__.cpython-311.pyc
    │           │   │   │       │       └── resource2.txt
    │           │   │   │       ├── namespacedata01
    │           │   │   │       │   ├── binary.file
    │           │   │   │       │   ├── subdirectory
    │           │   │   │       │   │   └── binary.file
    │           │   │   │       │   ├── utf-16.file
    │           │   │   │       │   └── utf-8.file
    │           │   │   │       ├── test_compatibilty_files.py
    │           │   │   │       ├── test_contents.py
    │           │   │   │       ├── test_custom.py
    │           │   │   │       ├── test_files.py
    │           │   │   │       ├── test_functional.py
    │           │   │   │       ├── test_open.py
    │           │   │   │       ├── test_path.py
    │           │   │   │       ├── test_read.py
    │           │   │   │       ├── test_reader.py
    │           │   │   │       ├── test_resource.py
    │           │   │   │       ├── util.py
    │           │   │   │       └── zip.py
    │           │   │   ├── importlib_resources-6.4.0.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── inflect
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── py38.cpython-311.pyc
    │           │   │   │   │   └── py38.py
    │           │   │   │   └── py.typed
    │           │   │   ├── inflect-7.3.1.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── jaraco
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   └── context.cpython-311.pyc
    │           │   │   │   ├── context.py
    │           │   │   │   ├── functools
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __init__.pyi
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │   │   └── py.typed
    │           │   │   │   └── text
    │           │   │   │       ├── __init__.py
    │           │   │   │       ├── __pycache__
    │           │   │   │       │   ├── __init__.cpython-311.pyc
    │           │   │   │       │   ├── layouts.cpython-311.pyc
    │           │   │   │       │   ├── show-newlines.cpython-311.pyc
    │           │   │   │       │   ├── strip-prefix.cpython-311.pyc
    │           │   │   │       │   ├── to-dvorak.cpython-311.pyc
    │           │   │   │       │   └── to-qwerty.cpython-311.pyc
    │           │   │   │       ├── layouts.py
    │           │   │   │       ├── Lorem ipsum.txt
    │           │   │   │       ├── show-newlines.py
    │           │   │   │       ├── strip-prefix.py
    │           │   │   │       ├── to-dvorak.py
    │           │   │   │       └── to-qwerty.py
    │           │   │   ├── jaraco.context-5.3.0.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── jaraco.functools-4.0.1.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── jaraco.text-3.12.1.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── more_itertools
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __init__.pyi
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── more.cpython-311.pyc
    │           │   │   │   │   └── recipes.cpython-311.pyc
    │           │   │   │   ├── more.py
    │           │   │   │   ├── more.pyi
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── recipes.py
    │           │   │   │   └── recipes.pyi
    │           │   │   ├── more_itertools-10.3.0.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   └── WHEEL
    │           │   │   ├── packaging
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _elffile.cpython-311.pyc
    │           │   │   │   │   ├── _manylinux.cpython-311.pyc
    │           │   │   │   │   ├── _musllinux.cpython-311.pyc
    │           │   │   │   │   ├── _parser.cpython-311.pyc
    │           │   │   │   │   ├── _structures.cpython-311.pyc
    │           │   │   │   │   ├── _tokenizer.cpython-311.pyc
    │           │   │   │   │   ├── markers.cpython-311.pyc
    │           │   │   │   │   ├── metadata.cpython-311.pyc
    │           │   │   │   │   ├── requirements.cpython-311.pyc
    │           │   │   │   │   ├── specifiers.cpython-311.pyc
    │           │   │   │   │   ├── tags.cpython-311.pyc
    │           │   │   │   │   ├── utils.cpython-311.pyc
    │           │   │   │   │   └── version.cpython-311.pyc
    │           │   │   │   ├── _elffile.py
    │           │   │   │   ├── _manylinux.py
    │           │   │   │   ├── _musllinux.py
    │           │   │   │   ├── _parser.py
    │           │   │   │   ├── _structures.py
    │           │   │   │   ├── _tokenizer.py
    │           │   │   │   ├── markers.py
    │           │   │   │   ├── metadata.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── requirements.py
    │           │   │   │   ├── specifiers.py
    │           │   │   │   ├── tags.py
    │           │   │   │   ├── utils.py
    │           │   │   │   └── version.py
    │           │   │   ├── packaging-24.1.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── LICENSE.APACHE
    │           │   │   │   ├── LICENSE.BSD
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   └── WHEEL
    │           │   │   ├── platformdirs
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   ├── android.cpython-311.pyc
    │           │   │   │   │   ├── api.cpython-311.pyc
    │           │   │   │   │   ├── macos.cpython-311.pyc
    │           │   │   │   │   ├── unix.cpython-311.pyc
    │           │   │   │   │   ├── version.cpython-311.pyc
    │           │   │   │   │   └── windows.cpython-311.pyc
    │           │   │   │   ├── android.py
    │           │   │   │   ├── api.py
    │           │   │   │   ├── macos.py
    │           │   │   │   ├── py.typed
    │           │   │   │   ├── unix.py
    │           │   │   │   ├── version.py
    │           │   │   │   └── windows.py
    │           │   │   ├── platformdirs-4.2.2.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── licenses
    │           │   │   │   │   └── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   └── WHEEL
    │           │   │   ├── ruff.toml
    │           │   │   ├── tomli
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _parser.cpython-311.pyc
    │           │   │   │   │   ├── _re.cpython-311.pyc
    │           │   │   │   │   └── _types.cpython-311.pyc
    │           │   │   │   ├── _parser.py
    │           │   │   │   ├── _re.py
    │           │   │   │   ├── _types.py
    │           │   │   │   └── py.typed
    │           │   │   ├── tomli-2.0.1.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   └── WHEEL
    │           │   │   ├── typeguard
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── _checkers.cpython-311.pyc
    │           │   │   │   │   ├── _config.cpython-311.pyc
    │           │   │   │   │   ├── _decorators.cpython-311.pyc
    │           │   │   │   │   ├── _exceptions.cpython-311.pyc
    │           │   │   │   │   ├── _functions.cpython-311.pyc
    │           │   │   │   │   ├── _importhook.cpython-311.pyc
    │           │   │   │   │   ├── _memo.cpython-311.pyc
    │           │   │   │   │   ├── _pytest_plugin.cpython-311.pyc
    │           │   │   │   │   ├── _suppression.cpython-311.pyc
    │           │   │   │   │   ├── _transformer.cpython-311.pyc
    │           │   │   │   │   ├── _union_transformer.cpython-311.pyc
    │           │   │   │   │   └── _utils.cpython-311.pyc
    │           │   │   │   ├── _checkers.py
    │           │   │   │   ├── _config.py
    │           │   │   │   ├── _decorators.py
    │           │   │   │   ├── _exceptions.py
    │           │   │   │   ├── _functions.py
    │           │   │   │   ├── _importhook.py
    │           │   │   │   ├── _memo.py
    │           │   │   │   ├── _pytest_plugin.py
    │           │   │   │   ├── _suppression.py
    │           │   │   │   ├── _transformer.py
    │           │   │   │   ├── _union_transformer.py
    │           │   │   │   ├── _utils.py
    │           │   │   │   └── py.typed
    │           │   │   ├── typeguard-4.3.0.dist-info
    │           │   │   │   ├── entry_points.txt
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── top_level.txt
    │           │   │   │   └── WHEEL
    │           │   │   ├── typing_extensions-4.12.2.dist-info
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   └── WHEEL
    │           │   │   ├── typing_extensions.py
    │           │   │   ├── wheel
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __main__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── __main__.cpython-311.pyc
    │           │   │   │   │   ├── _setuptools_logging.cpython-311.pyc
    │           │   │   │   │   ├── bdist_wheel.cpython-311.pyc
    │           │   │   │   │   ├── macosx_libfile.cpython-311.pyc
    │           │   │   │   │   ├── metadata.cpython-311.pyc
    │           │   │   │   │   ├── util.cpython-311.pyc
    │           │   │   │   │   └── wheelfile.cpython-311.pyc
    │           │   │   │   ├── _setuptools_logging.py
    │           │   │   │   ├── bdist_wheel.py
    │           │   │   │   ├── cli
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   ├── convert.cpython-311.pyc
    │           │   │   │   │   │   ├── pack.cpython-311.pyc
    │           │   │   │   │   │   ├── tags.cpython-311.pyc
    │           │   │   │   │   │   └── unpack.cpython-311.pyc
    │           │   │   │   │   ├── convert.py
    │           │   │   │   │   ├── pack.py
    │           │   │   │   │   ├── tags.py
    │           │   │   │   │   └── unpack.py
    │           │   │   │   ├── macosx_libfile.py
    │           │   │   │   ├── metadata.py
    │           │   │   │   ├── util.py
    │           │   │   │   ├── vendored
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   └── __init__.cpython-311.pyc
    │           │   │   │   │   ├── packaging
    │           │   │   │   │   │   ├── __init__.py
    │           │   │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _elffile.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _manylinux.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _musllinux.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _parser.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _structures.cpython-311.pyc
    │           │   │   │   │   │   │   ├── _tokenizer.cpython-311.pyc
    │           │   │   │   │   │   │   ├── markers.cpython-311.pyc
    │           │   │   │   │   │   │   ├── requirements.cpython-311.pyc
    │           │   │   │   │   │   │   ├── specifiers.cpython-311.pyc
    │           │   │   │   │   │   │   ├── tags.cpython-311.pyc
    │           │   │   │   │   │   │   ├── utils.cpython-311.pyc
    │           │   │   │   │   │   │   └── version.cpython-311.pyc
    │           │   │   │   │   │   ├── _elffile.py
    │           │   │   │   │   │   ├── _manylinux.py
    │           │   │   │   │   │   ├── _musllinux.py
    │           │   │   │   │   │   ├── _parser.py
    │           │   │   │   │   │   ├── _structures.py
    │           │   │   │   │   │   ├── _tokenizer.py
    │           │   │   │   │   │   ├── markers.py
    │           │   │   │   │   │   ├── requirements.py
    │           │   │   │   │   │   ├── specifiers.py
    │           │   │   │   │   │   ├── tags.py
    │           │   │   │   │   │   ├── utils.py
    │           │   │   │   │   │   └── version.py
    │           │   │   │   │   └── vendor.txt
    │           │   │   │   └── wheelfile.py
    │           │   │   ├── wheel-0.43.0.dist-info
    │           │   │   │   ├── entry_points.txt
    │           │   │   │   ├── INSTALLER
    │           │   │   │   ├── LICENSE.txt
    │           │   │   │   ├── METADATA
    │           │   │   │   ├── RECORD
    │           │   │   │   ├── REQUESTED
    │           │   │   │   └── WHEEL
    │           │   │   ├── zipp
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   └── glob.cpython-311.pyc
    │           │   │   │   ├── compat
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── py310.cpython-311.pyc
    │           │   │   │   │   └── py310.py
    │           │   │   │   └── glob.py
    │           │   │   └── zipp-3.19.2.dist-info
    │           │   │       ├── INSTALLER
    │           │   │       ├── LICENSE
    │           │   │       ├── METADATA
    │           │   │       ├── RECORD
    │           │   │       ├── REQUESTED
    │           │   │       ├── top_level.txt
    │           │   │       └── WHEEL
    │           │   ├── archive_util.py
    │           │   ├── build_meta.py
    │           │   ├── cli-32.exe
    │           │   ├── cli-64.exe
    │           │   ├── cli-arm64.exe
    │           │   ├── cli.exe
    │           │   ├── command
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── _requirestxt.cpython-311.pyc
    │           │   │   │   ├── alias.cpython-311.pyc
    │           │   │   │   ├── bdist_egg.cpython-311.pyc
    │           │   │   │   ├── bdist_rpm.cpython-311.pyc
    │           │   │   │   ├── bdist_wheel.cpython-311.pyc
    │           │   │   │   ├── build_clib.cpython-311.pyc
    │           │   │   │   ├── build_ext.cpython-311.pyc
    │           │   │   │   ├── build_py.cpython-311.pyc
    │           │   │   │   ├── build.cpython-311.pyc
    │           │   │   │   ├── develop.cpython-311.pyc
    │           │   │   │   ├── dist_info.cpython-311.pyc
    │           │   │   │   ├── easy_install.cpython-311.pyc
    │           │   │   │   ├── editable_wheel.cpython-311.pyc
    │           │   │   │   ├── egg_info.cpython-311.pyc
    │           │   │   │   ├── install_egg_info.cpython-311.pyc
    │           │   │   │   ├── install_lib.cpython-311.pyc
    │           │   │   │   ├── install_scripts.cpython-311.pyc
    │           │   │   │   ├── install.cpython-311.pyc
    │           │   │   │   ├── register.cpython-311.pyc
    │           │   │   │   ├── rotate.cpython-311.pyc
    │           │   │   │   ├── saveopts.cpython-311.pyc
    │           │   │   │   ├── sdist.cpython-311.pyc
    │           │   │   │   ├── setopt.cpython-311.pyc
    │           │   │   │   ├── test.cpython-311.pyc
    │           │   │   │   ├── upload_docs.cpython-311.pyc
    │           │   │   │   └── upload.cpython-311.pyc
    │           │   │   ├── _requirestxt.py
    │           │   │   ├── alias.py
    │           │   │   ├── bdist_egg.py
    │           │   │   ├── bdist_rpm.py
    │           │   │   ├── bdist_wheel.py
    │           │   │   ├── build_clib.py
    │           │   │   ├── build_ext.py
    │           │   │   ├── build_py.py
    │           │   │   ├── build.py
    │           │   │   ├── develop.py
    │           │   │   ├── dist_info.py
    │           │   │   ├── easy_install.py
    │           │   │   ├── editable_wheel.py
    │           │   │   ├── egg_info.py
    │           │   │   ├── install_egg_info.py
    │           │   │   ├── install_lib.py
    │           │   │   ├── install_scripts.py
    │           │   │   ├── install.py
    │           │   │   ├── launcher manifest.xml
    │           │   │   ├── register.py
    │           │   │   ├── rotate.py
    │           │   │   ├── saveopts.py
    │           │   │   ├── sdist.py
    │           │   │   ├── setopt.py
    │           │   │   ├── test.py
    │           │   │   ├── upload_docs.py
    │           │   │   └── upload.py
    │           │   ├── compat
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── py310.cpython-311.pyc
    │           │   │   │   ├── py311.cpython-311.pyc
    │           │   │   │   ├── py312.cpython-311.pyc
    │           │   │   │   └── py39.cpython-311.pyc
    │           │   │   ├── py310.py
    │           │   │   ├── py311.py
    │           │   │   ├── py312.py
    │           │   │   └── py39.py
    │           │   ├── config
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── _apply_pyprojecttoml.cpython-311.pyc
    │           │   │   │   ├── expand.cpython-311.pyc
    │           │   │   │   ├── pyprojecttoml.cpython-311.pyc
    │           │   │   │   └── setupcfg.cpython-311.pyc
    │           │   │   ├── _apply_pyprojecttoml.py
    │           │   │   ├── _validate_pyproject
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── error_reporting.cpython-311.pyc
    │           │   │   │   │   ├── extra_validations.cpython-311.pyc
    │           │   │   │   │   ├── fastjsonschema_exceptions.cpython-311.pyc
    │           │   │   │   │   ├── fastjsonschema_validations.cpython-311.pyc
    │           │   │   │   │   └── formats.cpython-311.pyc
    │           │   │   │   ├── error_reporting.py
    │           │   │   │   ├── extra_validations.py
    │           │   │   │   ├── fastjsonschema_exceptions.py
    │           │   │   │   ├── fastjsonschema_validations.py
    │           │   │   │   ├── formats.py
    │           │   │   │   └── NOTICE
    │           │   │   ├── distutils.schema.json
    │           │   │   ├── expand.py
    │           │   │   ├── NOTICE
    │           │   │   ├── pyprojecttoml.py
    │           │   │   ├── setupcfg.py
    │           │   │   └── setuptools.schema.json
    │           │   ├── depends.py
    │           │   ├── discovery.py
    │           │   ├── dist.py
    │           │   ├── errors.py
    │           │   ├── extension.py
    │           │   ├── glob.py
    │           │   ├── gui-32.exe
    │           │   ├── gui-64.exe
    │           │   ├── gui-arm64.exe
    │           │   ├── gui.exe
    │           │   ├── installer.py
    │           │   ├── launch.py
    │           │   ├── logging.py
    │           │   ├── modified.py
    │           │   ├── monkey.py
    │           │   ├── msvc.py
    │           │   ├── namespaces.py
    │           │   ├── package_index.py
    │           │   ├── sandbox.py
    │           │   ├── script (dev).tmpl
    │           │   ├── script.tmpl
    │           │   ├── tests
    │           │   │   ├── __init__.py
    │           │   │   ├── __pycache__
    │           │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   ├── contexts.cpython-311.pyc
    │           │   │   │   ├── environment.cpython-311.pyc
    │           │   │   │   ├── fixtures.cpython-311.pyc
    │           │   │   │   ├── mod_with_constant.cpython-311.pyc
    │           │   │   │   ├── namespaces.cpython-311.pyc
    │           │   │   │   ├── script-with-bom.cpython-311.pyc
    │           │   │   │   ├── server.cpython-311.pyc
    │           │   │   │   ├── test_archive_util.cpython-311.pyc
    │           │   │   │   ├── test_bdist_deprecations.cpython-311.pyc
    │           │   │   │   ├── test_bdist_egg.cpython-311.pyc
    │           │   │   │   ├── test_bdist_wheel.cpython-311.pyc
    │           │   │   │   ├── test_build_clib.cpython-311.pyc
    │           │   │   │   ├── test_build_ext.cpython-311.pyc
    │           │   │   │   ├── test_build_meta.cpython-311.pyc
    │           │   │   │   ├── test_build_py.cpython-311.pyc
    │           │   │   │   ├── test_build.cpython-311.pyc
    │           │   │   │   ├── test_config_discovery.cpython-311.pyc
    │           │   │   │   ├── test_core_metadata.cpython-311.pyc
    │           │   │   │   ├── test_depends.cpython-311.pyc
    │           │   │   │   ├── test_develop.cpython-311.pyc
    │           │   │   │   ├── test_dist_info.cpython-311.pyc
    │           │   │   │   ├── test_dist.cpython-311.pyc
    │           │   │   │   ├── test_distutils_adoption.cpython-311.pyc
    │           │   │   │   ├── test_easy_install.cpython-311.pyc
    │           │   │   │   ├── test_editable_install.cpython-311.pyc
    │           │   │   │   ├── test_egg_info.cpython-311.pyc
    │           │   │   │   ├── test_extern.cpython-311.pyc
    │           │   │   │   ├── test_find_packages.cpython-311.pyc
    │           │   │   │   ├── test_find_py_modules.cpython-311.pyc
    │           │   │   │   ├── test_glob.cpython-311.pyc
    │           │   │   │   ├── test_install_scripts.cpython-311.pyc
    │           │   │   │   ├── test_logging.cpython-311.pyc
    │           │   │   │   ├── test_manifest.cpython-311.pyc
    │           │   │   │   ├── test_namespaces.cpython-311.pyc
    │           │   │   │   ├── test_packageindex.cpython-311.pyc
    │           │   │   │   ├── test_register.cpython-311.pyc
    │           │   │   │   ├── test_sandbox.cpython-311.pyc
    │           │   │   │   ├── test_sdist.cpython-311.pyc
    │           │   │   │   ├── test_setopt.cpython-311.pyc
    │           │   │   │   ├── test_setuptools.cpython-311.pyc
    │           │   │   │   ├── test_unicode_utils.cpython-311.pyc
    │           │   │   │   ├── test_upload.cpython-311.pyc
    │           │   │   │   ├── test_virtualenv.cpython-311.pyc
    │           │   │   │   ├── test_warnings.cpython-311.pyc
    │           │   │   │   ├── test_wheel.cpython-311.pyc
    │           │   │   │   ├── test_windows_wrappers.cpython-311.pyc
    │           │   │   │   ├── text.cpython-311.pyc
    │           │   │   │   └── textwrap.cpython-311.pyc
    │           │   │   ├── compat
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   └── py39.cpython-311.pyc
    │           │   │   │   └── py39.py
    │           │   │   ├── config
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── test_apply_pyprojecttoml.cpython-311.pyc
    │           │   │   │   │   ├── test_expand.cpython-311.pyc
    │           │   │   │   │   ├── test_pyprojecttoml_dynamic_deps.cpython-311.pyc
    │           │   │   │   │   ├── test_pyprojecttoml.cpython-311.pyc
    │           │   │   │   │   └── test_setupcfg.cpython-311.pyc
    │           │   │   │   ├── downloads
    │           │   │   │   │   ├── __init__.py
    │           │   │   │   │   ├── __pycache__
    │           │   │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   │   └── preload.cpython-311.pyc
    │           │   │   │   │   └── preload.py
    │           │   │   │   ├── setupcfg_examples.txt
    │           │   │   │   ├── test_apply_pyprojecttoml.py
    │           │   │   │   ├── test_expand.py
    │           │   │   │   ├── test_pyprojecttoml_dynamic_deps.py
    │           │   │   │   ├── test_pyprojecttoml.py
    │           │   │   │   └── test_setupcfg.py
    │           │   │   ├── contexts.py
    │           │   │   ├── environment.py
    │           │   │   ├── fixtures.py
    │           │   │   ├── indexes
    │           │   │   │   └── test_links_priority
    │           │   │   │       ├── external.html
    │           │   │   │       └── simple
    │           │   │   │           └── foobar
    │           │   │   │               └── index.html
    │           │   │   ├── integration
    │           │   │   │   ├── __init__.py
    │           │   │   │   ├── __pycache__
    │           │   │   │   │   ├── __init__.cpython-311.pyc
    │           │   │   │   │   ├── helpers.cpython-311.pyc
    │           │   │   │   │   └── test_pip_install_sdist.cpython-311.pyc
    │           │   │   │   ├── helpers.py
    │           │   │   │   └── test_pip_install_sdist.py
    │           │   │   ├── mod_with_constant.py
    │           │   │   ├── namespaces.py
    │           │   │   ├── script-with-bom.py
    │           │   │   ├── server.py
    │           │   │   ├── test_archive_util.py
    │           │   │   ├── test_bdist_deprecations.py
    │           │   │   ├── test_bdist_egg.py
    │           │   │   ├── test_bdist_wheel.py
    │           │   │   ├── test_build_clib.py
    │           │   │   ├── test_build_ext.py
    │           │   │   ├── test_build_meta.py
    │           │   │   ├── test_build_py.py
    │           │   │   ├── test_build.py
    │           │   │   ├── test_config_discovery.py
    │           │   │   ├── test_core_metadata.py
    │           │   │   ├── test_depends.py
    │           │   │   ├── test_develop.py
    │           │   │   ├── test_dist_info.py
    │           │   │   ├── test_dist.py
    │           │   │   ├── test_distutils_adoption.py
    │           │   │   ├── test_easy_install.py
    │           │   │   ├── test_editable_install.py
    │           │   │   ├── test_egg_info.py
    │           │   │   ├── test_extern.py
    │           │   │   ├── test_find_packages.py
    │           │   │   ├── test_find_py_modules.py
    │           │   │   ├── test_glob.py
    │           │   │   ├── test_install_scripts.py
    │           │   │   ├── test_logging.py
    │           │   │   ├── test_manifest.py
    │           │   │   ├── test_namespaces.py
    │           │   │   ├── test_packageindex.py
    │           │   │   ├── test_register.py
    │           │   │   ├── test_sandbox.py
    │           │   │   ├── test_sdist.py
    │           │   │   ├── test_setopt.py
    │           │   │   ├── test_setuptools.py
    │           │   │   ├── test_unicode_utils.py
    │           │   │   ├── test_upload.py
    │           │   │   ├── test_virtualenv.py
    │           │   │   ├── test_warnings.py
    │           │   │   ├── test_wheel.py
    │           │   │   ├── test_windows_wrappers.py
    │           │   │   ├── text.py
    │           │   │   └── textwrap.py
    │           │   ├── unicode_utils.py
    │           │   ├── version.py
    │           │   ├── warnings.py
    │           │   ├── wheel.py
    │           │   └── windows_support.py
    │           ├── setuptools-74.1.2.dist-info
    │           │   ├── entry_points.txt
    │           │   ├── INSTALLER
    │           │   ├── LICENSE
    │           │   ├── METADATA
    │           │   ├── RECORD
    │           │   ├── REQUESTED
    │           │   ├── top_level.txt
    │           │   └── WHEEL
    │           ├── trove_classifiers
    │           │   ├── __init__.py
    │           │   ├── __main__.py
    │           │   ├── __pycache__
    │           │   │   ├── __init__.cpython-311.pyc
    │           │   │   └── __main__.cpython-311.pyc
    │           │   └── py.typed
    │           └── trove_classifiers-2024.10.21.16.dist-info
    │               ├── INSTALLER
    │               ├── LICENSE
    │               ├── METADATA
    │               ├── RECORD
    │               ├── top_level.txt
    │               └── WHEEL
    └── pyvenv.cfg
```

# Files

--------------------------------------------------------------------------------
/venv/lib/python3.11/site-packages/setuptools/_vendor/more_itertools/more.py:
--------------------------------------------------------------------------------

```python
   1 | import math
   2 | import warnings
   3 | 
   4 | from collections import Counter, defaultdict, deque, abc
   5 | from collections.abc import Sequence
   6 | from functools import cached_property, partial, reduce, wraps
   7 | from heapq import heapify, heapreplace, heappop
   8 | from itertools import (
   9 |     chain,
  10 |     combinations,
  11 |     compress,
  12 |     count,
  13 |     cycle,
  14 |     dropwhile,
  15 |     groupby,
  16 |     islice,
  17 |     repeat,
  18 |     starmap,
  19 |     takewhile,
  20 |     tee,
  21 |     zip_longest,
  22 |     product,
  23 | )
  24 | from math import comb, e, exp, factorial, floor, fsum, log, perm, tau
  25 | from queue import Empty, Queue
  26 | from random import random, randrange, uniform
  27 | from operator import itemgetter, mul, sub, gt, lt, ge, le
  28 | from sys import hexversion, maxsize
  29 | from time import monotonic
  30 | 
  31 | from .recipes import (
  32 |     _marker,
  33 |     _zip_equal,
  34 |     UnequalIterablesError,
  35 |     consume,
  36 |     flatten,
  37 |     pairwise,
  38 |     powerset,
  39 |     take,
  40 |     unique_everseen,
  41 |     all_equal,
  42 |     batched,
  43 | )
  44 | 
  45 | __all__ = [
  46 |     'AbortThread',
  47 |     'SequenceView',
  48 |     'UnequalIterablesError',
  49 |     'adjacent',
  50 |     'all_unique',
  51 |     'always_iterable',
  52 |     'always_reversible',
  53 |     'bucket',
  54 |     'callback_iter',
  55 |     'chunked',
  56 |     'chunked_even',
  57 |     'circular_shifts',
  58 |     'collapse',
  59 |     'combination_index',
  60 |     'combination_with_replacement_index',
  61 |     'consecutive_groups',
  62 |     'constrained_batches',
  63 |     'consumer',
  64 |     'count_cycle',
  65 |     'countable',
  66 |     'dft',
  67 |     'difference',
  68 |     'distinct_combinations',
  69 |     'distinct_permutations',
  70 |     'distribute',
  71 |     'divide',
  72 |     'doublestarmap',
  73 |     'duplicates_everseen',
  74 |     'duplicates_justseen',
  75 |     'classify_unique',
  76 |     'exactly_n',
  77 |     'filter_except',
  78 |     'filter_map',
  79 |     'first',
  80 |     'gray_product',
  81 |     'groupby_transform',
  82 |     'ichunked',
  83 |     'iequals',
  84 |     'idft',
  85 |     'ilen',
  86 |     'interleave',
  87 |     'interleave_evenly',
  88 |     'interleave_longest',
  89 |     'intersperse',
  90 |     'is_sorted',
  91 |     'islice_extended',
  92 |     'iterate',
  93 |     'iter_suppress',
  94 |     'join_mappings',
  95 |     'last',
  96 |     'locate',
  97 |     'longest_common_prefix',
  98 |     'lstrip',
  99 |     'make_decorator',
 100 |     'map_except',
 101 |     'map_if',
 102 |     'map_reduce',
 103 |     'mark_ends',
 104 |     'minmax',
 105 |     'nth_or_last',
 106 |     'nth_permutation',
 107 |     'nth_product',
 108 |     'nth_combination_with_replacement',
 109 |     'numeric_range',
 110 |     'one',
 111 |     'only',
 112 |     'outer_product',
 113 |     'padded',
 114 |     'partial_product',
 115 |     'partitions',
 116 |     'peekable',
 117 |     'permutation_index',
 118 |     'powerset_of_sets',
 119 |     'product_index',
 120 |     'raise_',
 121 |     'repeat_each',
 122 |     'repeat_last',
 123 |     'replace',
 124 |     'rlocate',
 125 |     'rstrip',
 126 |     'run_length',
 127 |     'sample',
 128 |     'seekable',
 129 |     'set_partitions',
 130 |     'side_effect',
 131 |     'sliced',
 132 |     'sort_together',
 133 |     'split_after',
 134 |     'split_at',
 135 |     'split_before',
 136 |     'split_into',
 137 |     'split_when',
 138 |     'spy',
 139 |     'stagger',
 140 |     'strip',
 141 |     'strictly_n',
 142 |     'substrings',
 143 |     'substrings_indexes',
 144 |     'takewhile_inclusive',
 145 |     'time_limited',
 146 |     'unique_in_window',
 147 |     'unique_to_each',
 148 |     'unzip',
 149 |     'value_chain',
 150 |     'windowed',
 151 |     'windowed_complete',
 152 |     'with_iter',
 153 |     'zip_broadcast',
 154 |     'zip_equal',
 155 |     'zip_offset',
 156 | ]
 157 | 
 158 | # math.sumprod is available for Python 3.12+
 159 | _fsumprod = getattr(math, 'sumprod', lambda x, y: fsum(map(mul, x, y)))
 160 | 
 161 | 
 162 | def chunked(iterable, n, strict=False):
 163 |     """Break *iterable* into lists of length *n*:
 164 | 
 165 |         >>> list(chunked([1, 2, 3, 4, 5, 6], 3))
 166 |         [[1, 2, 3], [4, 5, 6]]
 167 | 
 168 |     By the default, the last yielded list will have fewer than *n* elements
 169 |     if the length of *iterable* is not divisible by *n*:
 170 | 
 171 |         >>> list(chunked([1, 2, 3, 4, 5, 6, 7, 8], 3))
 172 |         [[1, 2, 3], [4, 5, 6], [7, 8]]
 173 | 
 174 |     To use a fill-in value instead, see the :func:`grouper` recipe.
 175 | 
 176 |     If the length of *iterable* is not divisible by *n* and *strict* is
 177 |     ``True``, then ``ValueError`` will be raised before the last
 178 |     list is yielded.
 179 | 
 180 |     """
 181 |     iterator = iter(partial(take, n, iter(iterable)), [])
 182 |     if strict:
 183 |         if n is None:
 184 |             raise ValueError('n must not be None when using strict mode.')
 185 | 
 186 |         def ret():
 187 |             for chunk in iterator:
 188 |                 if len(chunk) != n:
 189 |                     raise ValueError('iterable is not divisible by n.')
 190 |                 yield chunk
 191 | 
 192 |         return iter(ret())
 193 |     else:
 194 |         return iterator
 195 | 
 196 | 
 197 | def first(iterable, default=_marker):
 198 |     """Return the first item of *iterable*, or *default* if *iterable* is
 199 |     empty.
 200 | 
 201 |         >>> first([0, 1, 2, 3])
 202 |         0
 203 |         >>> first([], 'some default')
 204 |         'some default'
 205 | 
 206 |     If *default* is not provided and there are no items in the iterable,
 207 |     raise ``ValueError``.
 208 | 
 209 |     :func:`first` is useful when you have a generator of expensive-to-retrieve
 210 |     values and want any arbitrary one. It is marginally shorter than
 211 |     ``next(iter(iterable), default)``.
 212 | 
 213 |     """
 214 |     for item in iterable:
 215 |         return item
 216 |     if default is _marker:
 217 |         raise ValueError(
 218 |             'first() was called on an empty iterable, and no '
 219 |             'default value was provided.'
 220 |         )
 221 |     return default
 222 | 
 223 | 
 224 | def last(iterable, default=_marker):
 225 |     """Return the last item of *iterable*, or *default* if *iterable* is
 226 |     empty.
 227 | 
 228 |         >>> last([0, 1, 2, 3])
 229 |         3
 230 |         >>> last([], 'some default')
 231 |         'some default'
 232 | 
 233 |     If *default* is not provided and there are no items in the iterable,
 234 |     raise ``ValueError``.
 235 |     """
 236 |     try:
 237 |         if isinstance(iterable, Sequence):
 238 |             return iterable[-1]
 239 |         # Work around https://bugs.python.org/issue38525
 240 |         elif hasattr(iterable, '__reversed__') and (hexversion != 0x030800F0):
 241 |             return next(reversed(iterable))
 242 |         else:
 243 |             return deque(iterable, maxlen=1)[-1]
 244 |     except (IndexError, TypeError, StopIteration):
 245 |         if default is _marker:
 246 |             raise ValueError(
 247 |                 'last() was called on an empty iterable, and no default was '
 248 |                 'provided.'
 249 |             )
 250 |         return default
 251 | 
 252 | 
 253 | def nth_or_last(iterable, n, default=_marker):
 254 |     """Return the nth or the last item of *iterable*,
 255 |     or *default* if *iterable* is empty.
 256 | 
 257 |         >>> nth_or_last([0, 1, 2, 3], 2)
 258 |         2
 259 |         >>> nth_or_last([0, 1], 2)
 260 |         1
 261 |         >>> nth_or_last([], 0, 'some default')
 262 |         'some default'
 263 | 
 264 |     If *default* is not provided and there are no items in the iterable,
 265 |     raise ``ValueError``.
 266 |     """
 267 |     return last(islice(iterable, n + 1), default=default)
 268 | 
 269 | 
 270 | class peekable:
 271 |     """Wrap an iterator to allow lookahead and prepending elements.
 272 | 
 273 |     Call :meth:`peek` on the result to get the value that will be returned
 274 |     by :func:`next`. This won't advance the iterator:
 275 | 
 276 |         >>> p = peekable(['a', 'b'])
 277 |         >>> p.peek()
 278 |         'a'
 279 |         >>> next(p)
 280 |         'a'
 281 | 
 282 |     Pass :meth:`peek` a default value to return that instead of raising
 283 |     ``StopIteration`` when the iterator is exhausted.
 284 | 
 285 |         >>> p = peekable([])
 286 |         >>> p.peek('hi')
 287 |         'hi'
 288 | 
 289 |     peekables also offer a :meth:`prepend` method, which "inserts" items
 290 |     at the head of the iterable:
 291 | 
 292 |         >>> p = peekable([1, 2, 3])
 293 |         >>> p.prepend(10, 11, 12)
 294 |         >>> next(p)
 295 |         10
 296 |         >>> p.peek()
 297 |         11
 298 |         >>> list(p)
 299 |         [11, 12, 1, 2, 3]
 300 | 
 301 |     peekables can be indexed. Index 0 is the item that will be returned by
 302 |     :func:`next`, index 1 is the item after that, and so on:
 303 |     The values up to the given index will be cached.
 304 | 
 305 |         >>> p = peekable(['a', 'b', 'c', 'd'])
 306 |         >>> p[0]
 307 |         'a'
 308 |         >>> p[1]
 309 |         'b'
 310 |         >>> next(p)
 311 |         'a'
 312 | 
 313 |     Negative indexes are supported, but be aware that they will cache the
 314 |     remaining items in the source iterator, which may require significant
 315 |     storage.
 316 | 
 317 |     To check whether a peekable is exhausted, check its truth value:
 318 | 
 319 |         >>> p = peekable(['a', 'b'])
 320 |         >>> if p:  # peekable has items
 321 |         ...     list(p)
 322 |         ['a', 'b']
 323 |         >>> if not p:  # peekable is exhausted
 324 |         ...     list(p)
 325 |         []
 326 | 
 327 |     """
 328 | 
 329 |     def __init__(self, iterable):
 330 |         self._it = iter(iterable)
 331 |         self._cache = deque()
 332 | 
 333 |     def __iter__(self):
 334 |         return self
 335 | 
 336 |     def __bool__(self):
 337 |         try:
 338 |             self.peek()
 339 |         except StopIteration:
 340 |             return False
 341 |         return True
 342 | 
 343 |     def peek(self, default=_marker):
 344 |         """Return the item that will be next returned from ``next()``.
 345 | 
 346 |         Return ``default`` if there are no items left. If ``default`` is not
 347 |         provided, raise ``StopIteration``.
 348 | 
 349 |         """
 350 |         if not self._cache:
 351 |             try:
 352 |                 self._cache.append(next(self._it))
 353 |             except StopIteration:
 354 |                 if default is _marker:
 355 |                     raise
 356 |                 return default
 357 |         return self._cache[0]
 358 | 
 359 |     def prepend(self, *items):
 360 |         """Stack up items to be the next ones returned from ``next()`` or
 361 |         ``self.peek()``. The items will be returned in
 362 |         first in, first out order::
 363 | 
 364 |             >>> p = peekable([1, 2, 3])
 365 |             >>> p.prepend(10, 11, 12)
 366 |             >>> next(p)
 367 |             10
 368 |             >>> list(p)
 369 |             [11, 12, 1, 2, 3]
 370 | 
 371 |         It is possible, by prepending items, to "resurrect" a peekable that
 372 |         previously raised ``StopIteration``.
 373 | 
 374 |             >>> p = peekable([])
 375 |             >>> next(p)
 376 |             Traceback (most recent call last):
 377 |               ...
 378 |             StopIteration
 379 |             >>> p.prepend(1)
 380 |             >>> next(p)
 381 |             1
 382 |             >>> next(p)
 383 |             Traceback (most recent call last):
 384 |               ...
 385 |             StopIteration
 386 | 
 387 |         """
 388 |         self._cache.extendleft(reversed(items))
 389 | 
 390 |     def __next__(self):
 391 |         if self._cache:
 392 |             return self._cache.popleft()
 393 | 
 394 |         return next(self._it)
 395 | 
 396 |     def _get_slice(self, index):
 397 |         # Normalize the slice's arguments
 398 |         step = 1 if (index.step is None) else index.step
 399 |         if step > 0:
 400 |             start = 0 if (index.start is None) else index.start
 401 |             stop = maxsize if (index.stop is None) else index.stop
 402 |         elif step < 0:
 403 |             start = -1 if (index.start is None) else index.start
 404 |             stop = (-maxsize - 1) if (index.stop is None) else index.stop
 405 |         else:
 406 |             raise ValueError('slice step cannot be zero')
 407 | 
 408 |         # If either the start or stop index is negative, we'll need to cache
 409 |         # the rest of the iterable in order to slice from the right side.
 410 |         if (start < 0) or (stop < 0):
 411 |             self._cache.extend(self._it)
 412 |         # Otherwise we'll need to find the rightmost index and cache to that
 413 |         # point.
 414 |         else:
 415 |             n = min(max(start, stop) + 1, maxsize)
 416 |             cache_len = len(self._cache)
 417 |             if n >= cache_len:
 418 |                 self._cache.extend(islice(self._it, n - cache_len))
 419 | 
 420 |         return list(self._cache)[index]
 421 | 
 422 |     def __getitem__(self, index):
 423 |         if isinstance(index, slice):
 424 |             return self._get_slice(index)
 425 | 
 426 |         cache_len = len(self._cache)
 427 |         if index < 0:
 428 |             self._cache.extend(self._it)
 429 |         elif index >= cache_len:
 430 |             self._cache.extend(islice(self._it, index + 1 - cache_len))
 431 | 
 432 |         return self._cache[index]
 433 | 
 434 | 
 435 | def consumer(func):
 436 |     """Decorator that automatically advances a PEP-342-style "reverse iterator"
 437 |     to its first yield point so you don't have to call ``next()`` on it
 438 |     manually.
 439 | 
 440 |         >>> @consumer
 441 |         ... def tally():
 442 |         ...     i = 0
 443 |         ...     while True:
 444 |         ...         print('Thing number %s is %s.' % (i, (yield)))
 445 |         ...         i += 1
 446 |         ...
 447 |         >>> t = tally()
 448 |         >>> t.send('red')
 449 |         Thing number 0 is red.
 450 |         >>> t.send('fish')
 451 |         Thing number 1 is fish.
 452 | 
 453 |     Without the decorator, you would have to call ``next(t)`` before
 454 |     ``t.send()`` could be used.
 455 | 
 456 |     """
 457 | 
 458 |     @wraps(func)
 459 |     def wrapper(*args, **kwargs):
 460 |         gen = func(*args, **kwargs)
 461 |         next(gen)
 462 |         return gen
 463 | 
 464 |     return wrapper
 465 | 
 466 | 
 467 | def ilen(iterable):
 468 |     """Return the number of items in *iterable*.
 469 | 
 470 |         >>> ilen(x for x in range(1000000) if x % 3 == 0)
 471 |         333334
 472 | 
 473 |     This consumes the iterable, so handle with care.
 474 | 
 475 |     """
 476 |     # This approach was selected because benchmarks showed it's likely the
 477 |     # fastest of the known implementations at the time of writing.
 478 |     # See GitHub tracker: #236, #230.
 479 |     counter = count()
 480 |     deque(zip(iterable, counter), maxlen=0)
 481 |     return next(counter)
 482 | 
 483 | 
 484 | def iterate(func, start):
 485 |     """Return ``start``, ``func(start)``, ``func(func(start))``, ...
 486 | 
 487 |     >>> from itertools import islice
 488 |     >>> list(islice(iterate(lambda x: 2*x, 1), 10))
 489 |     [1, 2, 4, 8, 16, 32, 64, 128, 256, 512]
 490 | 
 491 |     """
 492 |     while True:
 493 |         yield start
 494 |         try:
 495 |             start = func(start)
 496 |         except StopIteration:
 497 |             break
 498 | 
 499 | 
 500 | def with_iter(context_manager):
 501 |     """Wrap an iterable in a ``with`` statement, so it closes once exhausted.
 502 | 
 503 |     For example, this will close the file when the iterator is exhausted::
 504 | 
 505 |         upper_lines = (line.upper() for line in with_iter(open('foo')))
 506 | 
 507 |     Any context manager which returns an iterable is a candidate for
 508 |     ``with_iter``.
 509 | 
 510 |     """
 511 |     with context_manager as iterable:
 512 |         yield from iterable
 513 | 
 514 | 
 515 | def one(iterable, too_short=None, too_long=None):
 516 |     """Return the first item from *iterable*, which is expected to contain only
 517 |     that item. Raise an exception if *iterable* is empty or has more than one
 518 |     item.
 519 | 
 520 |     :func:`one` is useful for ensuring that an iterable contains only one item.
 521 |     For example, it can be used to retrieve the result of a database query
 522 |     that is expected to return a single row.
 523 | 
 524 |     If *iterable* is empty, ``ValueError`` will be raised. You may specify a
 525 |     different exception with the *too_short* keyword:
 526 | 
 527 |         >>> it = []
 528 |         >>> one(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
 529 |         Traceback (most recent call last):
 530 |         ...
 531 |         ValueError: too many items in iterable (expected 1)'
 532 |         >>> too_short = IndexError('too few items')
 533 |         >>> one(it, too_short=too_short)  # doctest: +IGNORE_EXCEPTION_DETAIL
 534 |         Traceback (most recent call last):
 535 |         ...
 536 |         IndexError: too few items
 537 | 
 538 |     Similarly, if *iterable* contains more than one item, ``ValueError`` will
 539 |     be raised. You may specify a different exception with the *too_long*
 540 |     keyword:
 541 | 
 542 |         >>> it = ['too', 'many']
 543 |         >>> one(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
 544 |         Traceback (most recent call last):
 545 |         ...
 546 |         ValueError: Expected exactly one item in iterable, but got 'too',
 547 |         'many', and perhaps more.
 548 |         >>> too_long = RuntimeError
 549 |         >>> one(it, too_long=too_long)  # doctest: +IGNORE_EXCEPTION_DETAIL
 550 |         Traceback (most recent call last):
 551 |         ...
 552 |         RuntimeError
 553 | 
 554 |     Note that :func:`one` attempts to advance *iterable* twice to ensure there
 555 |     is only one item. See :func:`spy` or :func:`peekable` to check iterable
 556 |     contents less destructively.
 557 | 
 558 |     """
 559 |     it = iter(iterable)
 560 | 
 561 |     try:
 562 |         first_value = next(it)
 563 |     except StopIteration as exc:
 564 |         raise (
 565 |             too_short or ValueError('too few items in iterable (expected 1)')
 566 |         ) from exc
 567 | 
 568 |     try:
 569 |         second_value = next(it)
 570 |     except StopIteration:
 571 |         pass
 572 |     else:
 573 |         msg = (
 574 |             'Expected exactly one item in iterable, but got {!r}, {!r}, '
 575 |             'and perhaps more.'.format(first_value, second_value)
 576 |         )
 577 |         raise too_long or ValueError(msg)
 578 | 
 579 |     return first_value
 580 | 
 581 | 
 582 | def raise_(exception, *args):
 583 |     raise exception(*args)
 584 | 
 585 | 
 586 | def strictly_n(iterable, n, too_short=None, too_long=None):
 587 |     """Validate that *iterable* has exactly *n* items and return them if
 588 |     it does. If it has fewer than *n* items, call function *too_short*
 589 |     with those items. If it has more than *n* items, call function
 590 |     *too_long* with the first ``n + 1`` items.
 591 | 
 592 |         >>> iterable = ['a', 'b', 'c', 'd']
 593 |         >>> n = 4
 594 |         >>> list(strictly_n(iterable, n))
 595 |         ['a', 'b', 'c', 'd']
 596 | 
 597 |     Note that the returned iterable must be consumed in order for the check to
 598 |     be made.
 599 | 
 600 |     By default, *too_short* and *too_long* are functions that raise
 601 |     ``ValueError``.
 602 | 
 603 |         >>> list(strictly_n('ab', 3))  # doctest: +IGNORE_EXCEPTION_DETAIL
 604 |         Traceback (most recent call last):
 605 |         ...
 606 |         ValueError: too few items in iterable (got 2)
 607 | 
 608 |         >>> list(strictly_n('abc', 2))  # doctest: +IGNORE_EXCEPTION_DETAIL
 609 |         Traceback (most recent call last):
 610 |         ...
 611 |         ValueError: too many items in iterable (got at least 3)
 612 | 
 613 |     You can instead supply functions that do something else.
 614 |     *too_short* will be called with the number of items in *iterable*.
 615 |     *too_long* will be called with `n + 1`.
 616 | 
 617 |         >>> def too_short(item_count):
 618 |         ...     raise RuntimeError
 619 |         >>> it = strictly_n('abcd', 6, too_short=too_short)
 620 |         >>> list(it)  # doctest: +IGNORE_EXCEPTION_DETAIL
 621 |         Traceback (most recent call last):
 622 |         ...
 623 |         RuntimeError
 624 | 
 625 |         >>> def too_long(item_count):
 626 |         ...     print('The boss is going to hear about this')
 627 |         >>> it = strictly_n('abcdef', 4, too_long=too_long)
 628 |         >>> list(it)
 629 |         The boss is going to hear about this
 630 |         ['a', 'b', 'c', 'd']
 631 | 
 632 |     """
 633 |     if too_short is None:
 634 |         too_short = lambda item_count: raise_(
 635 |             ValueError,
 636 |             'Too few items in iterable (got {})'.format(item_count),
 637 |         )
 638 | 
 639 |     if too_long is None:
 640 |         too_long = lambda item_count: raise_(
 641 |             ValueError,
 642 |             'Too many items in iterable (got at least {})'.format(item_count),
 643 |         )
 644 | 
 645 |     it = iter(iterable)
 646 |     for i in range(n):
 647 |         try:
 648 |             item = next(it)
 649 |         except StopIteration:
 650 |             too_short(i)
 651 |             return
 652 |         else:
 653 |             yield item
 654 | 
 655 |     try:
 656 |         next(it)
 657 |     except StopIteration:
 658 |         pass
 659 |     else:
 660 |         too_long(n + 1)
 661 | 
 662 | 
 663 | def distinct_permutations(iterable, r=None):
 664 |     """Yield successive distinct permutations of the elements in *iterable*.
 665 | 
 666 |         >>> sorted(distinct_permutations([1, 0, 1]))
 667 |         [(0, 1, 1), (1, 0, 1), (1, 1, 0)]
 668 | 
 669 |     Equivalent to ``set(permutations(iterable))``, except duplicates are not
 670 |     generated and thrown away. For larger input sequences this is much more
 671 |     efficient.
 672 | 
 673 |     Duplicate permutations arise when there are duplicated elements in the
 674 |     input iterable. The number of items returned is
 675 |     `n! / (x_1! * x_2! * ... * x_n!)`, where `n` is the total number of
 676 |     items input, and each `x_i` is the count of a distinct item in the input
 677 |     sequence.
 678 | 
 679 |     If *r* is given, only the *r*-length permutations are yielded.
 680 | 
 681 |         >>> sorted(distinct_permutations([1, 0, 1], r=2))
 682 |         [(0, 1), (1, 0), (1, 1)]
 683 |         >>> sorted(distinct_permutations(range(3), r=2))
 684 |         [(0, 1), (0, 2), (1, 0), (1, 2), (2, 0), (2, 1)]
 685 | 
 686 |     """
 687 | 
 688 |     # Algorithm: https://w.wiki/Qai
 689 |     def _full(A):
 690 |         while True:
 691 |             # Yield the permutation we have
 692 |             yield tuple(A)
 693 | 
 694 |             # Find the largest index i such that A[i] < A[i + 1]
 695 |             for i in range(size - 2, -1, -1):
 696 |                 if A[i] < A[i + 1]:
 697 |                     break
 698 |             #  If no such index exists, this permutation is the last one
 699 |             else:
 700 |                 return
 701 | 
 702 |             # Find the largest index j greater than j such that A[i] < A[j]
 703 |             for j in range(size - 1, i, -1):
 704 |                 if A[i] < A[j]:
 705 |                     break
 706 | 
 707 |             # Swap the value of A[i] with that of A[j], then reverse the
 708 |             # sequence from A[i + 1] to form the new permutation
 709 |             A[i], A[j] = A[j], A[i]
 710 |             A[i + 1 :] = A[: i - size : -1]  # A[i + 1:][::-1]
 711 | 
 712 |     # Algorithm: modified from the above
 713 |     def _partial(A, r):
 714 |         # Split A into the first r items and the last r items
 715 |         head, tail = A[:r], A[r:]
 716 |         right_head_indexes = range(r - 1, -1, -1)
 717 |         left_tail_indexes = range(len(tail))
 718 | 
 719 |         while True:
 720 |             # Yield the permutation we have
 721 |             yield tuple(head)
 722 | 
 723 |             # Starting from the right, find the first index of the head with
 724 |             # value smaller than the maximum value of the tail - call it i.
 725 |             pivot = tail[-1]
 726 |             for i in right_head_indexes:
 727 |                 if head[i] < pivot:
 728 |                     break
 729 |                 pivot = head[i]
 730 |             else:
 731 |                 return
 732 | 
 733 |             # Starting from the left, find the first value of the tail
 734 |             # with a value greater than head[i] and swap.
 735 |             for j in left_tail_indexes:
 736 |                 if tail[j] > head[i]:
 737 |                     head[i], tail[j] = tail[j], head[i]
 738 |                     break
 739 |             # If we didn't find one, start from the right and find the first
 740 |             # index of the head with a value greater than head[i] and swap.
 741 |             else:
 742 |                 for j in right_head_indexes:
 743 |                     if head[j] > head[i]:
 744 |                         head[i], head[j] = head[j], head[i]
 745 |                         break
 746 | 
 747 |             # Reverse head[i + 1:] and swap it with tail[:r - (i + 1)]
 748 |             tail += head[: i - r : -1]  # head[i + 1:][::-1]
 749 |             i += 1
 750 |             head[i:], tail[:] = tail[: r - i], tail[r - i :]
 751 | 
 752 |     items = sorted(iterable)
 753 | 
 754 |     size = len(items)
 755 |     if r is None:
 756 |         r = size
 757 | 
 758 |     if 0 < r <= size:
 759 |         return _full(items) if (r == size) else _partial(items, r)
 760 | 
 761 |     return iter(() if r else ((),))
 762 | 
 763 | 
 764 | def intersperse(e, iterable, n=1):
 765 |     """Intersperse filler element *e* among the items in *iterable*, leaving
 766 |     *n* items between each filler element.
 767 | 
 768 |         >>> list(intersperse('!', [1, 2, 3, 4, 5]))
 769 |         [1, '!', 2, '!', 3, '!', 4, '!', 5]
 770 | 
 771 |         >>> list(intersperse(None, [1, 2, 3, 4, 5], n=2))
 772 |         [1, 2, None, 3, 4, None, 5]
 773 | 
 774 |     """
 775 |     if n == 0:
 776 |         raise ValueError('n must be > 0')
 777 |     elif n == 1:
 778 |         # interleave(repeat(e), iterable) -> e, x_0, e, x_1, e, x_2...
 779 |         # islice(..., 1, None) -> x_0, e, x_1, e, x_2...
 780 |         return islice(interleave(repeat(e), iterable), 1, None)
 781 |     else:
 782 |         # interleave(filler, chunks) -> [e], [x_0, x_1], [e], [x_2, x_3]...
 783 |         # islice(..., 1, None) -> [x_0, x_1], [e], [x_2, x_3]...
 784 |         # flatten(...) -> x_0, x_1, e, x_2, x_3...
 785 |         filler = repeat([e])
 786 |         chunks = chunked(iterable, n)
 787 |         return flatten(islice(interleave(filler, chunks), 1, None))
 788 | 
 789 | 
 790 | def unique_to_each(*iterables):
 791 |     """Return the elements from each of the input iterables that aren't in the
 792 |     other input iterables.
 793 | 
 794 |     For example, suppose you have a set of packages, each with a set of
 795 |     dependencies::
 796 | 
 797 |         {'pkg_1': {'A', 'B'}, 'pkg_2': {'B', 'C'}, 'pkg_3': {'B', 'D'}}
 798 | 
 799 |     If you remove one package, which dependencies can also be removed?
 800 | 
 801 |     If ``pkg_1`` is removed, then ``A`` is no longer necessary - it is not
 802 |     associated with ``pkg_2`` or ``pkg_3``. Similarly, ``C`` is only needed for
 803 |     ``pkg_2``, and ``D`` is only needed for ``pkg_3``::
 804 | 
 805 |         >>> unique_to_each({'A', 'B'}, {'B', 'C'}, {'B', 'D'})
 806 |         [['A'], ['C'], ['D']]
 807 | 
 808 |     If there are duplicates in one input iterable that aren't in the others
 809 |     they will be duplicated in the output. Input order is preserved::
 810 | 
 811 |         >>> unique_to_each("mississippi", "missouri")
 812 |         [['p', 'p'], ['o', 'u', 'r']]
 813 | 
 814 |     It is assumed that the elements of each iterable are hashable.
 815 | 
 816 |     """
 817 |     pool = [list(it) for it in iterables]
 818 |     counts = Counter(chain.from_iterable(map(set, pool)))
 819 |     uniques = {element for element in counts if counts[element] == 1}
 820 |     return [list(filter(uniques.__contains__, it)) for it in pool]
 821 | 
 822 | 
 823 | def windowed(seq, n, fillvalue=None, step=1):
 824 |     """Return a sliding window of width *n* over the given iterable.
 825 | 
 826 |         >>> all_windows = windowed([1, 2, 3, 4, 5], 3)
 827 |         >>> list(all_windows)
 828 |         [(1, 2, 3), (2, 3, 4), (3, 4, 5)]
 829 | 
 830 |     When the window is larger than the iterable, *fillvalue* is used in place
 831 |     of missing values:
 832 | 
 833 |         >>> list(windowed([1, 2, 3], 4))
 834 |         [(1, 2, 3, None)]
 835 | 
 836 |     Each window will advance in increments of *step*:
 837 | 
 838 |         >>> list(windowed([1, 2, 3, 4, 5, 6], 3, fillvalue='!', step=2))
 839 |         [(1, 2, 3), (3, 4, 5), (5, 6, '!')]
 840 | 
 841 |     To slide into the iterable's items, use :func:`chain` to add filler items
 842 |     to the left:
 843 | 
 844 |         >>> iterable = [1, 2, 3, 4]
 845 |         >>> n = 3
 846 |         >>> padding = [None] * (n - 1)
 847 |         >>> list(windowed(chain(padding, iterable), 3))
 848 |         [(None, None, 1), (None, 1, 2), (1, 2, 3), (2, 3, 4)]
 849 |     """
 850 |     if n < 0:
 851 |         raise ValueError('n must be >= 0')
 852 |     if n == 0:
 853 |         yield ()
 854 |         return
 855 |     if step < 1:
 856 |         raise ValueError('step must be >= 1')
 857 | 
 858 |     iterable = iter(seq)
 859 | 
 860 |     # Generate first window
 861 |     window = deque(islice(iterable, n), maxlen=n)
 862 | 
 863 |     # Deal with the first window not being full
 864 |     if not window:
 865 |         return
 866 |     if len(window) < n:
 867 |         yield tuple(window) + ((fillvalue,) * (n - len(window)))
 868 |         return
 869 |     yield tuple(window)
 870 | 
 871 |     # Create the filler for the next windows. The padding ensures
 872 |     # we have just enough elements to fill the last window.
 873 |     padding = (fillvalue,) * (n - 1 if step >= n else step - 1)
 874 |     filler = map(window.append, chain(iterable, padding))
 875 | 
 876 |     # Generate the rest of the windows
 877 |     for _ in islice(filler, step - 1, None, step):
 878 |         yield tuple(window)
 879 | 
 880 | 
 881 | def substrings(iterable):
 882 |     """Yield all of the substrings of *iterable*.
 883 | 
 884 |         >>> [''.join(s) for s in substrings('more')]
 885 |         ['m', 'o', 'r', 'e', 'mo', 'or', 're', 'mor', 'ore', 'more']
 886 | 
 887 |     Note that non-string iterables can also be subdivided.
 888 | 
 889 |         >>> list(substrings([0, 1, 2]))
 890 |         [(0,), (1,), (2,), (0, 1), (1, 2), (0, 1, 2)]
 891 | 
 892 |     """
 893 |     # The length-1 substrings
 894 |     seq = []
 895 |     for item in iter(iterable):
 896 |         seq.append(item)
 897 |         yield (item,)
 898 |     seq = tuple(seq)
 899 |     item_count = len(seq)
 900 | 
 901 |     # And the rest
 902 |     for n in range(2, item_count + 1):
 903 |         for i in range(item_count - n + 1):
 904 |             yield seq[i : i + n]
 905 | 
 906 | 
 907 | def substrings_indexes(seq, reverse=False):
 908 |     """Yield all substrings and their positions in *seq*
 909 | 
 910 |     The items yielded will be a tuple of the form ``(substr, i, j)``, where
 911 |     ``substr == seq[i:j]``.
 912 | 
 913 |     This function only works for iterables that support slicing, such as
 914 |     ``str`` objects.
 915 | 
 916 |     >>> for item in substrings_indexes('more'):
 917 |     ...    print(item)
 918 |     ('m', 0, 1)
 919 |     ('o', 1, 2)
 920 |     ('r', 2, 3)
 921 |     ('e', 3, 4)
 922 |     ('mo', 0, 2)
 923 |     ('or', 1, 3)
 924 |     ('re', 2, 4)
 925 |     ('mor', 0, 3)
 926 |     ('ore', 1, 4)
 927 |     ('more', 0, 4)
 928 | 
 929 |     Set *reverse* to ``True`` to yield the same items in the opposite order.
 930 | 
 931 | 
 932 |     """
 933 |     r = range(1, len(seq) + 1)
 934 |     if reverse:
 935 |         r = reversed(r)
 936 |     return (
 937 |         (seq[i : i + L], i, i + L) for L in r for i in range(len(seq) - L + 1)
 938 |     )
 939 | 
 940 | 
 941 | class bucket:
 942 |     """Wrap *iterable* and return an object that buckets the iterable into
 943 |     child iterables based on a *key* function.
 944 | 
 945 |         >>> iterable = ['a1', 'b1', 'c1', 'a2', 'b2', 'c2', 'b3']
 946 |         >>> s = bucket(iterable, key=lambda x: x[0])  # Bucket by 1st character
 947 |         >>> sorted(list(s))  # Get the keys
 948 |         ['a', 'b', 'c']
 949 |         >>> a_iterable = s['a']
 950 |         >>> next(a_iterable)
 951 |         'a1'
 952 |         >>> next(a_iterable)
 953 |         'a2'
 954 |         >>> list(s['b'])
 955 |         ['b1', 'b2', 'b3']
 956 | 
 957 |     The original iterable will be advanced and its items will be cached until
 958 |     they are used by the child iterables. This may require significant storage.
 959 | 
 960 |     By default, attempting to select a bucket to which no items belong  will
 961 |     exhaust the iterable and cache all values.
 962 |     If you specify a *validator* function, selected buckets will instead be
 963 |     checked against it.
 964 | 
 965 |         >>> from itertools import count
 966 |         >>> it = count(1, 2)  # Infinite sequence of odd numbers
 967 |         >>> key = lambda x: x % 10  # Bucket by last digit
 968 |         >>> validator = lambda x: x in {1, 3, 5, 7, 9}  # Odd digits only
 969 |         >>> s = bucket(it, key=key, validator=validator)
 970 |         >>> 2 in s
 971 |         False
 972 |         >>> list(s[2])
 973 |         []
 974 | 
 975 |     """
 976 | 
 977 |     def __init__(self, iterable, key, validator=None):
 978 |         self._it = iter(iterable)
 979 |         self._key = key
 980 |         self._cache = defaultdict(deque)
 981 |         self._validator = validator or (lambda x: True)
 982 | 
 983 |     def __contains__(self, value):
 984 |         if not self._validator(value):
 985 |             return False
 986 | 
 987 |         try:
 988 |             item = next(self[value])
 989 |         except StopIteration:
 990 |             return False
 991 |         else:
 992 |             self._cache[value].appendleft(item)
 993 | 
 994 |         return True
 995 | 
 996 |     def _get_values(self, value):
 997 |         """
 998 |         Helper to yield items from the parent iterator that match *value*.
 999 |         Items that don't match are stored in the local cache as they
1000 |         are encountered.
1001 |         """
1002 |         while True:
1003 |             # If we've cached some items that match the target value, emit
1004 |             # the first one and evict it from the cache.
1005 |             if self._cache[value]:
1006 |                 yield self._cache[value].popleft()
1007 |             # Otherwise we need to advance the parent iterator to search for
1008 |             # a matching item, caching the rest.
1009 |             else:
1010 |                 while True:
1011 |                     try:
1012 |                         item = next(self._it)
1013 |                     except StopIteration:
1014 |                         return
1015 |                     item_value = self._key(item)
1016 |                     if item_value == value:
1017 |                         yield item
1018 |                         break
1019 |                     elif self._validator(item_value):
1020 |                         self._cache[item_value].append(item)
1021 | 
1022 |     def __iter__(self):
1023 |         for item in self._it:
1024 |             item_value = self._key(item)
1025 |             if self._validator(item_value):
1026 |                 self._cache[item_value].append(item)
1027 | 
1028 |         yield from self._cache.keys()
1029 | 
1030 |     def __getitem__(self, value):
1031 |         if not self._validator(value):
1032 |             return iter(())
1033 | 
1034 |         return self._get_values(value)
1035 | 
1036 | 
1037 | def spy(iterable, n=1):
1038 |     """Return a 2-tuple with a list containing the first *n* elements of
1039 |     *iterable*, and an iterator with the same items as *iterable*.
1040 |     This allows you to "look ahead" at the items in the iterable without
1041 |     advancing it.
1042 | 
1043 |     There is one item in the list by default:
1044 | 
1045 |         >>> iterable = 'abcdefg'
1046 |         >>> head, iterable = spy(iterable)
1047 |         >>> head
1048 |         ['a']
1049 |         >>> list(iterable)
1050 |         ['a', 'b', 'c', 'd', 'e', 'f', 'g']
1051 | 
1052 |     You may use unpacking to retrieve items instead of lists:
1053 | 
1054 |         >>> (head,), iterable = spy('abcdefg')
1055 |         >>> head
1056 |         'a'
1057 |         >>> (first, second), iterable = spy('abcdefg', 2)
1058 |         >>> first
1059 |         'a'
1060 |         >>> second
1061 |         'b'
1062 | 
1063 |     The number of items requested can be larger than the number of items in
1064 |     the iterable:
1065 | 
1066 |         >>> iterable = [1, 2, 3, 4, 5]
1067 |         >>> head, iterable = spy(iterable, 10)
1068 |         >>> head
1069 |         [1, 2, 3, 4, 5]
1070 |         >>> list(iterable)
1071 |         [1, 2, 3, 4, 5]
1072 | 
1073 |     """
1074 |     it = iter(iterable)
1075 |     head = take(n, it)
1076 | 
1077 |     return head.copy(), chain(head, it)
1078 | 
1079 | 
1080 | def interleave(*iterables):
1081 |     """Return a new iterable yielding from each iterable in turn,
1082 |     until the shortest is exhausted.
1083 | 
1084 |         >>> list(interleave([1, 2, 3], [4, 5], [6, 7, 8]))
1085 |         [1, 4, 6, 2, 5, 7]
1086 | 
1087 |     For a version that doesn't terminate after the shortest iterable is
1088 |     exhausted, see :func:`interleave_longest`.
1089 | 
1090 |     """
1091 |     return chain.from_iterable(zip(*iterables))
1092 | 
1093 | 
1094 | def interleave_longest(*iterables):
1095 |     """Return a new iterable yielding from each iterable in turn,
1096 |     skipping any that are exhausted.
1097 | 
1098 |         >>> list(interleave_longest([1, 2, 3], [4, 5], [6, 7, 8]))
1099 |         [1, 4, 6, 2, 5, 7, 3, 8]
1100 | 
1101 |     This function produces the same output as :func:`roundrobin`, but may
1102 |     perform better for some inputs (in particular when the number of iterables
1103 |     is large).
1104 | 
1105 |     """
1106 |     i = chain.from_iterable(zip_longest(*iterables, fillvalue=_marker))
1107 |     return (x for x in i if x is not _marker)
1108 | 
1109 | 
1110 | def interleave_evenly(iterables, lengths=None):
1111 |     """
1112 |     Interleave multiple iterables so that their elements are evenly distributed
1113 |     throughout the output sequence.
1114 | 
1115 |     >>> iterables = [1, 2, 3, 4, 5], ['a', 'b']
1116 |     >>> list(interleave_evenly(iterables))
1117 |     [1, 2, 'a', 3, 4, 'b', 5]
1118 | 
1119 |     >>> iterables = [[1, 2, 3], [4, 5], [6, 7, 8]]
1120 |     >>> list(interleave_evenly(iterables))
1121 |     [1, 6, 4, 2, 7, 3, 8, 5]
1122 | 
1123 |     This function requires iterables of known length. Iterables without
1124 |     ``__len__()`` can be used by manually specifying lengths with *lengths*:
1125 | 
1126 |     >>> from itertools import combinations, repeat
1127 |     >>> iterables = [combinations(range(4), 2), ['a', 'b', 'c']]
1128 |     >>> lengths = [4 * (4 - 1) // 2, 3]
1129 |     >>> list(interleave_evenly(iterables, lengths=lengths))
1130 |     [(0, 1), (0, 2), 'a', (0, 3), (1, 2), 'b', (1, 3), (2, 3), 'c']
1131 | 
1132 |     Based on Bresenham's algorithm.
1133 |     """
1134 |     if lengths is None:
1135 |         try:
1136 |             lengths = [len(it) for it in iterables]
1137 |         except TypeError:
1138 |             raise ValueError(
1139 |                 'Iterable lengths could not be determined automatically. '
1140 |                 'Specify them with the lengths keyword.'
1141 |             )
1142 |     elif len(iterables) != len(lengths):
1143 |         raise ValueError('Mismatching number of iterables and lengths.')
1144 | 
1145 |     dims = len(lengths)
1146 | 
1147 |     # sort iterables by length, descending
1148 |     lengths_permute = sorted(
1149 |         range(dims), key=lambda i: lengths[i], reverse=True
1150 |     )
1151 |     lengths_desc = [lengths[i] for i in lengths_permute]
1152 |     iters_desc = [iter(iterables[i]) for i in lengths_permute]
1153 | 
1154 |     # the longest iterable is the primary one (Bresenham: the longest
1155 |     # distance along an axis)
1156 |     delta_primary, deltas_secondary = lengths_desc[0], lengths_desc[1:]
1157 |     iter_primary, iters_secondary = iters_desc[0], iters_desc[1:]
1158 |     errors = [delta_primary // dims] * len(deltas_secondary)
1159 | 
1160 |     to_yield = sum(lengths)
1161 |     while to_yield:
1162 |         yield next(iter_primary)
1163 |         to_yield -= 1
1164 |         # update errors for each secondary iterable
1165 |         errors = [e - delta for e, delta in zip(errors, deltas_secondary)]
1166 | 
1167 |         # those iterables for which the error is negative are yielded
1168 |         # ("diagonal step" in Bresenham)
1169 |         for i, e_ in enumerate(errors):
1170 |             if e_ < 0:
1171 |                 yield next(iters_secondary[i])
1172 |                 to_yield -= 1
1173 |                 errors[i] += delta_primary
1174 | 
1175 | 
1176 | def collapse(iterable, base_type=None, levels=None):
1177 |     """Flatten an iterable with multiple levels of nesting (e.g., a list of
1178 |     lists of tuples) into non-iterable types.
1179 | 
1180 |         >>> iterable = [(1, 2), ([3, 4], [[5], [6]])]
1181 |         >>> list(collapse(iterable))
1182 |         [1, 2, 3, 4, 5, 6]
1183 | 
1184 |     Binary and text strings are not considered iterable and
1185 |     will not be collapsed.
1186 | 
1187 |     To avoid collapsing other types, specify *base_type*:
1188 | 
1189 |         >>> iterable = ['ab', ('cd', 'ef'), ['gh', 'ij']]
1190 |         >>> list(collapse(iterable, base_type=tuple))
1191 |         ['ab', ('cd', 'ef'), 'gh', 'ij']
1192 | 
1193 |     Specify *levels* to stop flattening after a certain level:
1194 | 
1195 |     >>> iterable = [('a', ['b']), ('c', ['d'])]
1196 |     >>> list(collapse(iterable))  # Fully flattened
1197 |     ['a', 'b', 'c', 'd']
1198 |     >>> list(collapse(iterable, levels=1))  # Only one level flattened
1199 |     ['a', ['b'], 'c', ['d']]
1200 | 
1201 |     """
1202 |     stack = deque()
1203 |     # Add our first node group, treat the iterable as a single node
1204 |     stack.appendleft((0, repeat(iterable, 1)))
1205 | 
1206 |     while stack:
1207 |         node_group = stack.popleft()
1208 |         level, nodes = node_group
1209 | 
1210 |         # Check if beyond max level
1211 |         if levels is not None and level > levels:
1212 |             yield from nodes
1213 |             continue
1214 | 
1215 |         for node in nodes:
1216 |             # Check if done iterating
1217 |             if isinstance(node, (str, bytes)) or (
1218 |                 (base_type is not None) and isinstance(node, base_type)
1219 |             ):
1220 |                 yield node
1221 |             # Otherwise try to create child nodes
1222 |             else:
1223 |                 try:
1224 |                     tree = iter(node)
1225 |                 except TypeError:
1226 |                     yield node
1227 |                 else:
1228 |                     # Save our current location
1229 |                     stack.appendleft(node_group)
1230 |                     # Append the new child node
1231 |                     stack.appendleft((level + 1, tree))
1232 |                     # Break to process child node
1233 |                     break
1234 | 
1235 | 
1236 | def side_effect(func, iterable, chunk_size=None, before=None, after=None):
1237 |     """Invoke *func* on each item in *iterable* (or on each *chunk_size* group
1238 |     of items) before yielding the item.
1239 | 
1240 |     `func` must be a function that takes a single argument. Its return value
1241 |     will be discarded.
1242 | 
1243 |     *before* and *after* are optional functions that take no arguments. They
1244 |     will be executed before iteration starts and after it ends, respectively.
1245 | 
1246 |     `side_effect` can be used for logging, updating progress bars, or anything
1247 |     that is not functionally "pure."
1248 | 
1249 |     Emitting a status message:
1250 | 
1251 |         >>> from more_itertools import consume
1252 |         >>> func = lambda item: print('Received {}'.format(item))
1253 |         >>> consume(side_effect(func, range(2)))
1254 |         Received 0
1255 |         Received 1
1256 | 
1257 |     Operating on chunks of items:
1258 | 
1259 |         >>> pair_sums = []
1260 |         >>> func = lambda chunk: pair_sums.append(sum(chunk))
1261 |         >>> list(side_effect(func, [0, 1, 2, 3, 4, 5], 2))
1262 |         [0, 1, 2, 3, 4, 5]
1263 |         >>> list(pair_sums)
1264 |         [1, 5, 9]
1265 | 
1266 |     Writing to a file-like object:
1267 | 
1268 |         >>> from io import StringIO
1269 |         >>> from more_itertools import consume
1270 |         >>> f = StringIO()
1271 |         >>> func = lambda x: print(x, file=f)
1272 |         >>> before = lambda: print(u'HEADER', file=f)
1273 |         >>> after = f.close
1274 |         >>> it = [u'a', u'b', u'c']
1275 |         >>> consume(side_effect(func, it, before=before, after=after))
1276 |         >>> f.closed
1277 |         True
1278 | 
1279 |     """
1280 |     try:
1281 |         if before is not None:
1282 |             before()
1283 | 
1284 |         if chunk_size is None:
1285 |             for item in iterable:
1286 |                 func(item)
1287 |                 yield item
1288 |         else:
1289 |             for chunk in chunked(iterable, chunk_size):
1290 |                 func(chunk)
1291 |                 yield from chunk
1292 |     finally:
1293 |         if after is not None:
1294 |             after()
1295 | 
1296 | 
1297 | def sliced(seq, n, strict=False):
1298 |     """Yield slices of length *n* from the sequence *seq*.
1299 | 
1300 |     >>> list(sliced((1, 2, 3, 4, 5, 6), 3))
1301 |     [(1, 2, 3), (4, 5, 6)]
1302 | 
1303 |     By the default, the last yielded slice will have fewer than *n* elements
1304 |     if the length of *seq* is not divisible by *n*:
1305 | 
1306 |     >>> list(sliced((1, 2, 3, 4, 5, 6, 7, 8), 3))
1307 |     [(1, 2, 3), (4, 5, 6), (7, 8)]
1308 | 
1309 |     If the length of *seq* is not divisible by *n* and *strict* is
1310 |     ``True``, then ``ValueError`` will be raised before the last
1311 |     slice is yielded.
1312 | 
1313 |     This function will only work for iterables that support slicing.
1314 |     For non-sliceable iterables, see :func:`chunked`.
1315 | 
1316 |     """
1317 |     iterator = takewhile(len, (seq[i : i + n] for i in count(0, n)))
1318 |     if strict:
1319 | 
1320 |         def ret():
1321 |             for _slice in iterator:
1322 |                 if len(_slice) != n:
1323 |                     raise ValueError("seq is not divisible by n.")
1324 |                 yield _slice
1325 | 
1326 |         return iter(ret())
1327 |     else:
1328 |         return iterator
1329 | 
1330 | 
1331 | def split_at(iterable, pred, maxsplit=-1, keep_separator=False):
1332 |     """Yield lists of items from *iterable*, where each list is delimited by
1333 |     an item where callable *pred* returns ``True``.
1334 | 
1335 |         >>> list(split_at('abcdcba', lambda x: x == 'b'))
1336 |         [['a'], ['c', 'd', 'c'], ['a']]
1337 | 
1338 |         >>> list(split_at(range(10), lambda n: n % 2 == 1))
1339 |         [[0], [2], [4], [6], [8], []]
1340 | 
1341 |     At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
1342 |     then there is no limit on the number of splits:
1343 | 
1344 |         >>> list(split_at(range(10), lambda n: n % 2 == 1, maxsplit=2))
1345 |         [[0], [2], [4, 5, 6, 7, 8, 9]]
1346 | 
1347 |     By default, the delimiting items are not included in the output.
1348 |     To include them, set *keep_separator* to ``True``.
1349 | 
1350 |         >>> list(split_at('abcdcba', lambda x: x == 'b', keep_separator=True))
1351 |         [['a'], ['b'], ['c', 'd', 'c'], ['b'], ['a']]
1352 | 
1353 |     """
1354 |     if maxsplit == 0:
1355 |         yield list(iterable)
1356 |         return
1357 | 
1358 |     buf = []
1359 |     it = iter(iterable)
1360 |     for item in it:
1361 |         if pred(item):
1362 |             yield buf
1363 |             if keep_separator:
1364 |                 yield [item]
1365 |             if maxsplit == 1:
1366 |                 yield list(it)
1367 |                 return
1368 |             buf = []
1369 |             maxsplit -= 1
1370 |         else:
1371 |             buf.append(item)
1372 |     yield buf
1373 | 
1374 | 
1375 | def split_before(iterable, pred, maxsplit=-1):
1376 |     """Yield lists of items from *iterable*, where each list ends just before
1377 |     an item for which callable *pred* returns ``True``:
1378 | 
1379 |         >>> list(split_before('OneTwo', lambda s: s.isupper()))
1380 |         [['O', 'n', 'e'], ['T', 'w', 'o']]
1381 | 
1382 |         >>> list(split_before(range(10), lambda n: n % 3 == 0))
1383 |         [[0, 1, 2], [3, 4, 5], [6, 7, 8], [9]]
1384 | 
1385 |     At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
1386 |     then there is no limit on the number of splits:
1387 | 
1388 |         >>> list(split_before(range(10), lambda n: n % 3 == 0, maxsplit=2))
1389 |         [[0, 1, 2], [3, 4, 5], [6, 7, 8, 9]]
1390 |     """
1391 |     if maxsplit == 0:
1392 |         yield list(iterable)
1393 |         return
1394 | 
1395 |     buf = []
1396 |     it = iter(iterable)
1397 |     for item in it:
1398 |         if pred(item) and buf:
1399 |             yield buf
1400 |             if maxsplit == 1:
1401 |                 yield [item] + list(it)
1402 |                 return
1403 |             buf = []
1404 |             maxsplit -= 1
1405 |         buf.append(item)
1406 |     if buf:
1407 |         yield buf
1408 | 
1409 | 
1410 | def split_after(iterable, pred, maxsplit=-1):
1411 |     """Yield lists of items from *iterable*, where each list ends with an
1412 |     item where callable *pred* returns ``True``:
1413 | 
1414 |         >>> list(split_after('one1two2', lambda s: s.isdigit()))
1415 |         [['o', 'n', 'e', '1'], ['t', 'w', 'o', '2']]
1416 | 
1417 |         >>> list(split_after(range(10), lambda n: n % 3 == 0))
1418 |         [[0], [1, 2, 3], [4, 5, 6], [7, 8, 9]]
1419 | 
1420 |     At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
1421 |     then there is no limit on the number of splits:
1422 | 
1423 |         >>> list(split_after(range(10), lambda n: n % 3 == 0, maxsplit=2))
1424 |         [[0], [1, 2, 3], [4, 5, 6, 7, 8, 9]]
1425 | 
1426 |     """
1427 |     if maxsplit == 0:
1428 |         yield list(iterable)
1429 |         return
1430 | 
1431 |     buf = []
1432 |     it = iter(iterable)
1433 |     for item in it:
1434 |         buf.append(item)
1435 |         if pred(item) and buf:
1436 |             yield buf
1437 |             if maxsplit == 1:
1438 |                 buf = list(it)
1439 |                 if buf:
1440 |                     yield buf
1441 |                 return
1442 |             buf = []
1443 |             maxsplit -= 1
1444 |     if buf:
1445 |         yield buf
1446 | 
1447 | 
1448 | def split_when(iterable, pred, maxsplit=-1):
1449 |     """Split *iterable* into pieces based on the output of *pred*.
1450 |     *pred* should be a function that takes successive pairs of items and
1451 |     returns ``True`` if the iterable should be split in between them.
1452 | 
1453 |     For example, to find runs of increasing numbers, split the iterable when
1454 |     element ``i`` is larger than element ``i + 1``:
1455 | 
1456 |         >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2], lambda x, y: x > y))
1457 |         [[1, 2, 3, 3], [2, 5], [2, 4], [2]]
1458 | 
1459 |     At most *maxsplit* splits are done. If *maxsplit* is not specified or -1,
1460 |     then there is no limit on the number of splits:
1461 | 
1462 |         >>> list(split_when([1, 2, 3, 3, 2, 5, 2, 4, 2],
1463 |         ...                 lambda x, y: x > y, maxsplit=2))
1464 |         [[1, 2, 3, 3], [2, 5], [2, 4, 2]]
1465 | 
1466 |     """
1467 |     if maxsplit == 0:
1468 |         yield list(iterable)
1469 |         return
1470 | 
1471 |     it = iter(iterable)
1472 |     try:
1473 |         cur_item = next(it)
1474 |     except StopIteration:
1475 |         return
1476 | 
1477 |     buf = [cur_item]
1478 |     for next_item in it:
1479 |         if pred(cur_item, next_item):
1480 |             yield buf
1481 |             if maxsplit == 1:
1482 |                 yield [next_item] + list(it)
1483 |                 return
1484 |             buf = []
1485 |             maxsplit -= 1
1486 | 
1487 |         buf.append(next_item)
1488 |         cur_item = next_item
1489 | 
1490 |     yield buf
1491 | 
1492 | 
1493 | def split_into(iterable, sizes):
1494 |     """Yield a list of sequential items from *iterable* of length 'n' for each
1495 |     integer 'n' in *sizes*.
1496 | 
1497 |         >>> list(split_into([1,2,3,4,5,6], [1,2,3]))
1498 |         [[1], [2, 3], [4, 5, 6]]
1499 | 
1500 |     If the sum of *sizes* is smaller than the length of *iterable*, then the
1501 |     remaining items of *iterable* will not be returned.
1502 | 
1503 |         >>> list(split_into([1,2,3,4,5,6], [2,3]))
1504 |         [[1, 2], [3, 4, 5]]
1505 | 
1506 |     If the sum of *sizes* is larger than the length of *iterable*, fewer items
1507 |     will be returned in the iteration that overruns *iterable* and further
1508 |     lists will be empty:
1509 | 
1510 |         >>> list(split_into([1,2,3,4], [1,2,3,4]))
1511 |         [[1], [2, 3], [4], []]
1512 | 
1513 |     When a ``None`` object is encountered in *sizes*, the returned list will
1514 |     contain items up to the end of *iterable* the same way that itertools.slice
1515 |     does:
1516 | 
1517 |         >>> list(split_into([1,2,3,4,5,6,7,8,9,0], [2,3,None]))
1518 |         [[1, 2], [3, 4, 5], [6, 7, 8, 9, 0]]
1519 | 
1520 |     :func:`split_into` can be useful for grouping a series of items where the
1521 |     sizes of the groups are not uniform. An example would be where in a row
1522 |     from a table, multiple columns represent elements of the same feature
1523 |     (e.g. a point represented by x,y,z) but, the format is not the same for
1524 |     all columns.
1525 |     """
1526 |     # convert the iterable argument into an iterator so its contents can
1527 |     # be consumed by islice in case it is a generator
1528 |     it = iter(iterable)
1529 | 
1530 |     for size in sizes:
1531 |         if size is None:
1532 |             yield list(it)
1533 |             return
1534 |         else:
1535 |             yield list(islice(it, size))
1536 | 
1537 | 
1538 | def padded(iterable, fillvalue=None, n=None, next_multiple=False):
1539 |     """Yield the elements from *iterable*, followed by *fillvalue*, such that
1540 |     at least *n* items are emitted.
1541 | 
1542 |         >>> list(padded([1, 2, 3], '?', 5))
1543 |         [1, 2, 3, '?', '?']
1544 | 
1545 |     If *next_multiple* is ``True``, *fillvalue* will be emitted until the
1546 |     number of items emitted is a multiple of *n*:
1547 | 
1548 |         >>> list(padded([1, 2, 3, 4], n=3, next_multiple=True))
1549 |         [1, 2, 3, 4, None, None]
1550 | 
1551 |     If *n* is ``None``, *fillvalue* will be emitted indefinitely.
1552 | 
1553 |     To create an *iterable* of exactly size *n*, you can truncate with
1554 |     :func:`islice`.
1555 | 
1556 |         >>> list(islice(padded([1, 2, 3], '?'), 5))
1557 |         [1, 2, 3, '?', '?']
1558 |         >>> list(islice(padded([1, 2, 3, 4, 5, 6, 7, 8], '?'), 5))
1559 |         [1, 2, 3, 4, 5]
1560 | 
1561 |     """
1562 |     iterable = iter(iterable)
1563 |     iterable_with_repeat = chain(iterable, repeat(fillvalue))
1564 | 
1565 |     if n is None:
1566 |         return iterable_with_repeat
1567 |     elif n < 1:
1568 |         raise ValueError('n must be at least 1')
1569 |     elif next_multiple:
1570 | 
1571 |         def slice_generator():
1572 |             for first in iterable:
1573 |                 yield (first,)
1574 |                 yield islice(iterable_with_repeat, n - 1)
1575 | 
1576 |         # While elements exist produce slices of size n
1577 |         return chain.from_iterable(slice_generator())
1578 |     else:
1579 |         # Ensure the first batch is at least size n then iterate
1580 |         return chain(islice(iterable_with_repeat, n), iterable)
1581 | 
1582 | 
1583 | def repeat_each(iterable, n=2):
1584 |     """Repeat each element in *iterable* *n* times.
1585 | 
1586 |     >>> list(repeat_each('ABC', 3))
1587 |     ['A', 'A', 'A', 'B', 'B', 'B', 'C', 'C', 'C']
1588 |     """
1589 |     return chain.from_iterable(map(repeat, iterable, repeat(n)))
1590 | 
1591 | 
1592 | def repeat_last(iterable, default=None):
1593 |     """After the *iterable* is exhausted, keep yielding its last element.
1594 | 
1595 |         >>> list(islice(repeat_last(range(3)), 5))
1596 |         [0, 1, 2, 2, 2]
1597 | 
1598 |     If the iterable is empty, yield *default* forever::
1599 | 
1600 |         >>> list(islice(repeat_last(range(0), 42), 5))
1601 |         [42, 42, 42, 42, 42]
1602 | 
1603 |     """
1604 |     item = _marker
1605 |     for item in iterable:
1606 |         yield item
1607 |     final = default if item is _marker else item
1608 |     yield from repeat(final)
1609 | 
1610 | 
1611 | def distribute(n, iterable):
1612 |     """Distribute the items from *iterable* among *n* smaller iterables.
1613 | 
1614 |         >>> group_1, group_2 = distribute(2, [1, 2, 3, 4, 5, 6])
1615 |         >>> list(group_1)
1616 |         [1, 3, 5]
1617 |         >>> list(group_2)
1618 |         [2, 4, 6]
1619 | 
1620 |     If the length of *iterable* is not evenly divisible by *n*, then the
1621 |     length of the returned iterables will not be identical:
1622 | 
1623 |         >>> children = distribute(3, [1, 2, 3, 4, 5, 6, 7])
1624 |         >>> [list(c) for c in children]
1625 |         [[1, 4, 7], [2, 5], [3, 6]]
1626 | 
1627 |     If the length of *iterable* is smaller than *n*, then the last returned
1628 |     iterables will be empty:
1629 | 
1630 |         >>> children = distribute(5, [1, 2, 3])
1631 |         >>> [list(c) for c in children]
1632 |         [[1], [2], [3], [], []]
1633 | 
1634 |     This function uses :func:`itertools.tee` and may require significant
1635 |     storage.
1636 | 
1637 |     If you need the order items in the smaller iterables to match the
1638 |     original iterable, see :func:`divide`.
1639 | 
1640 |     """
1641 |     if n < 1:
1642 |         raise ValueError('n must be at least 1')
1643 | 
1644 |     children = tee(iterable, n)
1645 |     return [islice(it, index, None, n) for index, it in enumerate(children)]
1646 | 
1647 | 
1648 | def stagger(iterable, offsets=(-1, 0, 1), longest=False, fillvalue=None):
1649 |     """Yield tuples whose elements are offset from *iterable*.
1650 |     The amount by which the `i`-th item in each tuple is offset is given by
1651 |     the `i`-th item in *offsets*.
1652 | 
1653 |         >>> list(stagger([0, 1, 2, 3]))
1654 |         [(None, 0, 1), (0, 1, 2), (1, 2, 3)]
1655 |         >>> list(stagger(range(8), offsets=(0, 2, 4)))
1656 |         [(0, 2, 4), (1, 3, 5), (2, 4, 6), (3, 5, 7)]
1657 | 
1658 |     By default, the sequence will end when the final element of a tuple is the
1659 |     last item in the iterable. To continue until the first element of a tuple
1660 |     is the last item in the iterable, set *longest* to ``True``::
1661 | 
1662 |         >>> list(stagger([0, 1, 2, 3], longest=True))
1663 |         [(None, 0, 1), (0, 1, 2), (1, 2, 3), (2, 3, None), (3, None, None)]
1664 | 
1665 |     By default, ``None`` will be used to replace offsets beyond the end of the
1666 |     sequence. Specify *fillvalue* to use some other value.
1667 | 
1668 |     """
1669 |     children = tee(iterable, len(offsets))
1670 | 
1671 |     return zip_offset(
1672 |         *children, offsets=offsets, longest=longest, fillvalue=fillvalue
1673 |     )
1674 | 
1675 | 
1676 | def zip_equal(*iterables):
1677 |     """``zip`` the input *iterables* together, but raise
1678 |     ``UnequalIterablesError`` if they aren't all the same length.
1679 | 
1680 |         >>> it_1 = range(3)
1681 |         >>> it_2 = iter('abc')
1682 |         >>> list(zip_equal(it_1, it_2))
1683 |         [(0, 'a'), (1, 'b'), (2, 'c')]
1684 | 
1685 |         >>> it_1 = range(3)
1686 |         >>> it_2 = iter('abcd')
1687 |         >>> list(zip_equal(it_1, it_2)) # doctest: +IGNORE_EXCEPTION_DETAIL
1688 |         Traceback (most recent call last):
1689 |         ...
1690 |         more_itertools.more.UnequalIterablesError: Iterables have different
1691 |         lengths
1692 | 
1693 |     """
1694 |     if hexversion >= 0x30A00A6:
1695 |         warnings.warn(
1696 |             (
1697 |                 'zip_equal will be removed in a future version of '
1698 |                 'more-itertools. Use the builtin zip function with '
1699 |                 'strict=True instead.'
1700 |             ),
1701 |             DeprecationWarning,
1702 |         )
1703 | 
1704 |     return _zip_equal(*iterables)
1705 | 
1706 | 
1707 | def zip_offset(*iterables, offsets, longest=False, fillvalue=None):
1708 |     """``zip`` the input *iterables* together, but offset the `i`-th iterable
1709 |     by the `i`-th item in *offsets*.
1710 | 
1711 |         >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1)))
1712 |         [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e')]
1713 | 
1714 |     This can be used as a lightweight alternative to SciPy or pandas to analyze
1715 |     data sets in which some series have a lead or lag relationship.
1716 | 
1717 |     By default, the sequence will end when the shortest iterable is exhausted.
1718 |     To continue until the longest iterable is exhausted, set *longest* to
1719 |     ``True``.
1720 | 
1721 |         >>> list(zip_offset('0123', 'abcdef', offsets=(0, 1), longest=True))
1722 |         [('0', 'b'), ('1', 'c'), ('2', 'd'), ('3', 'e'), (None, 'f')]
1723 | 
1724 |     By default, ``None`` will be used to replace offsets beyond the end of the
1725 |     sequence. Specify *fillvalue* to use some other value.
1726 | 
1727 |     """
1728 |     if len(iterables) != len(offsets):
1729 |         raise ValueError("Number of iterables and offsets didn't match")
1730 | 
1731 |     staggered = []
1732 |     for it, n in zip(iterables, offsets):
1733 |         if n < 0:
1734 |             staggered.append(chain(repeat(fillvalue, -n), it))
1735 |         elif n > 0:
1736 |             staggered.append(islice(it, n, None))
1737 |         else:
1738 |             staggered.append(it)
1739 | 
1740 |     if longest:
1741 |         return zip_longest(*staggered, fillvalue=fillvalue)
1742 | 
1743 |     return zip(*staggered)
1744 | 
1745 | 
1746 | def sort_together(iterables, key_list=(0,), key=None, reverse=False):
1747 |     """Return the input iterables sorted together, with *key_list* as the
1748 |     priority for sorting. All iterables are trimmed to the length of the
1749 |     shortest one.
1750 | 
1751 |     This can be used like the sorting function in a spreadsheet. If each
1752 |     iterable represents a column of data, the key list determines which
1753 |     columns are used for sorting.
1754 | 
1755 |     By default, all iterables are sorted using the ``0``-th iterable::
1756 | 
1757 |         >>> iterables = [(4, 3, 2, 1), ('a', 'b', 'c', 'd')]
1758 |         >>> sort_together(iterables)
1759 |         [(1, 2, 3, 4), ('d', 'c', 'b', 'a')]
1760 | 
1761 |     Set a different key list to sort according to another iterable.
1762 |     Specifying multiple keys dictates how ties are broken::
1763 | 
1764 |         >>> iterables = [(3, 1, 2), (0, 1, 0), ('c', 'b', 'a')]
1765 |         >>> sort_together(iterables, key_list=(1, 2))
1766 |         [(2, 3, 1), (0, 0, 1), ('a', 'c', 'b')]
1767 | 
1768 |     To sort by a function of the elements of the iterable, pass a *key*
1769 |     function. Its arguments are the elements of the iterables corresponding to
1770 |     the key list::
1771 | 
1772 |         >>> names = ('a', 'b', 'c')
1773 |         >>> lengths = (1, 2, 3)
1774 |         >>> widths = (5, 2, 1)
1775 |         >>> def area(length, width):
1776 |         ...     return length * width
1777 |         >>> sort_together([names, lengths, widths], key_list=(1, 2), key=area)
1778 |         [('c', 'b', 'a'), (3, 2, 1), (1, 2, 5)]
1779 | 
1780 |     Set *reverse* to ``True`` to sort in descending order.
1781 | 
1782 |         >>> sort_together([(1, 2, 3), ('c', 'b', 'a')], reverse=True)
1783 |         [(3, 2, 1), ('a', 'b', 'c')]
1784 | 
1785 |     """
1786 |     if key is None:
1787 |         # if there is no key function, the key argument to sorted is an
1788 |         # itemgetter
1789 |         key_argument = itemgetter(*key_list)
1790 |     else:
1791 |         # if there is a key function, call it with the items at the offsets
1792 |         # specified by the key function as arguments
1793 |         key_list = list(key_list)
1794 |         if len(key_list) == 1:
1795 |             # if key_list contains a single item, pass the item at that offset
1796 |             # as the only argument to the key function
1797 |             key_offset = key_list[0]
1798 |             key_argument = lambda zipped_items: key(zipped_items[key_offset])
1799 |         else:
1800 |             # if key_list contains multiple items, use itemgetter to return a
1801 |             # tuple of items, which we pass as *args to the key function
1802 |             get_key_items = itemgetter(*key_list)
1803 |             key_argument = lambda zipped_items: key(
1804 |                 *get_key_items(zipped_items)
1805 |             )
1806 | 
1807 |     return list(
1808 |         zip(*sorted(zip(*iterables), key=key_argument, reverse=reverse))
1809 |     )
1810 | 
1811 | 
1812 | def unzip(iterable):
1813 |     """The inverse of :func:`zip`, this function disaggregates the elements
1814 |     of the zipped *iterable*.
1815 | 
1816 |     The ``i``-th iterable contains the ``i``-th element from each element
1817 |     of the zipped iterable. The first element is used to determine the
1818 |     length of the remaining elements.
1819 | 
1820 |         >>> iterable = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
1821 |         >>> letters, numbers = unzip(iterable)
1822 |         >>> list(letters)
1823 |         ['a', 'b', 'c', 'd']
1824 |         >>> list(numbers)
1825 |         [1, 2, 3, 4]
1826 | 
1827 |     This is similar to using ``zip(*iterable)``, but it avoids reading
1828 |     *iterable* into memory. Note, however, that this function uses
1829 |     :func:`itertools.tee` and thus may require significant storage.
1830 | 
1831 |     """
1832 |     head, iterable = spy(iter(iterable))
1833 |     if not head:
1834 |         # empty iterable, e.g. zip([], [], [])
1835 |         return ()
1836 |     # spy returns a one-length iterable as head
1837 |     head = head[0]
1838 |     iterables = tee(iterable, len(head))
1839 | 
1840 |     def itemgetter(i):
1841 |         def getter(obj):
1842 |             try:
1843 |                 return obj[i]
1844 |             except IndexError:
1845 |                 # basically if we have an iterable like
1846 |                 # iter([(1, 2, 3), (4, 5), (6,)])
1847 |                 # the second unzipped iterable would fail at the third tuple
1848 |                 # since it would try to access tup[1]
1849 |                 # same with the third unzipped iterable and the second tuple
1850 |                 # to support these "improperly zipped" iterables,
1851 |                 # we create a custom itemgetter
1852 |                 # which just stops the unzipped iterables
1853 |                 # at first length mismatch
1854 |                 raise StopIteration
1855 | 
1856 |         return getter
1857 | 
1858 |     return tuple(map(itemgetter(i), it) for i, it in enumerate(iterables))
1859 | 
1860 | 
1861 | def divide(n, iterable):
1862 |     """Divide the elements from *iterable* into *n* parts, maintaining
1863 |     order.
1864 | 
1865 |         >>> group_1, group_2 = divide(2, [1, 2, 3, 4, 5, 6])
1866 |         >>> list(group_1)
1867 |         [1, 2, 3]
1868 |         >>> list(group_2)
1869 |         [4, 5, 6]
1870 | 
1871 |     If the length of *iterable* is not evenly divisible by *n*, then the
1872 |     length of the returned iterables will not be identical:
1873 | 
1874 |         >>> children = divide(3, [1, 2, 3, 4, 5, 6, 7])
1875 |         >>> [list(c) for c in children]
1876 |         [[1, 2, 3], [4, 5], [6, 7]]
1877 | 
1878 |     If the length of the iterable is smaller than n, then the last returned
1879 |     iterables will be empty:
1880 | 
1881 |         >>> children = divide(5, [1, 2, 3])
1882 |         >>> [list(c) for c in children]
1883 |         [[1], [2], [3], [], []]
1884 | 
1885 |     This function will exhaust the iterable before returning.
1886 |     If order is not important, see :func:`distribute`, which does not first
1887 |     pull the iterable into memory.
1888 | 
1889 |     """
1890 |     if n < 1:
1891 |         raise ValueError('n must be at least 1')
1892 | 
1893 |     try:
1894 |         iterable[:0]
1895 |     except TypeError:
1896 |         seq = tuple(iterable)
1897 |     else:
1898 |         seq = iterable
1899 | 
1900 |     q, r = divmod(len(seq), n)
1901 | 
1902 |     ret = []
1903 |     stop = 0
1904 |     for i in range(1, n + 1):
1905 |         start = stop
1906 |         stop += q + 1 if i <= r else q
1907 |         ret.append(iter(seq[start:stop]))
1908 | 
1909 |     return ret
1910 | 
1911 | 
1912 | def always_iterable(obj, base_type=(str, bytes)):
1913 |     """If *obj* is iterable, return an iterator over its items::
1914 | 
1915 |         >>> obj = (1, 2, 3)
1916 |         >>> list(always_iterable(obj))
1917 |         [1, 2, 3]
1918 | 
1919 |     If *obj* is not iterable, return a one-item iterable containing *obj*::
1920 | 
1921 |         >>> obj = 1
1922 |         >>> list(always_iterable(obj))
1923 |         [1]
1924 | 
1925 |     If *obj* is ``None``, return an empty iterable:
1926 | 
1927 |         >>> obj = None
1928 |         >>> list(always_iterable(None))
1929 |         []
1930 | 
1931 |     By default, binary and text strings are not considered iterable::
1932 | 
1933 |         >>> obj = 'foo'
1934 |         >>> list(always_iterable(obj))
1935 |         ['foo']
1936 | 
1937 |     If *base_type* is set, objects for which ``isinstance(obj, base_type)``
1938 |     returns ``True`` won't be considered iterable.
1939 | 
1940 |         >>> obj = {'a': 1}
1941 |         >>> list(always_iterable(obj))  # Iterate over the dict's keys
1942 |         ['a']
1943 |         >>> list(always_iterable(obj, base_type=dict))  # Treat dicts as a unit
1944 |         [{'a': 1}]
1945 | 
1946 |     Set *base_type* to ``None`` to avoid any special handling and treat objects
1947 |     Python considers iterable as iterable:
1948 | 
1949 |         >>> obj = 'foo'
1950 |         >>> list(always_iterable(obj, base_type=None))
1951 |         ['f', 'o', 'o']
1952 |     """
1953 |     if obj is None:
1954 |         return iter(())
1955 | 
1956 |     if (base_type is not None) and isinstance(obj, base_type):
1957 |         return iter((obj,))
1958 | 
1959 |     try:
1960 |         return iter(obj)
1961 |     except TypeError:
1962 |         return iter((obj,))
1963 | 
1964 | 
1965 | def adjacent(predicate, iterable, distance=1):
1966 |     """Return an iterable over `(bool, item)` tuples where the `item` is
1967 |     drawn from *iterable* and the `bool` indicates whether
1968 |     that item satisfies the *predicate* or is adjacent to an item that does.
1969 | 
1970 |     For example, to find whether items are adjacent to a ``3``::
1971 | 
1972 |         >>> list(adjacent(lambda x: x == 3, range(6)))
1973 |         [(False, 0), (False, 1), (True, 2), (True, 3), (True, 4), (False, 5)]
1974 | 
1975 |     Set *distance* to change what counts as adjacent. For example, to find
1976 |     whether items are two places away from a ``3``:
1977 | 
1978 |         >>> list(adjacent(lambda x: x == 3, range(6), distance=2))
1979 |         [(False, 0), (True, 1), (True, 2), (True, 3), (True, 4), (True, 5)]
1980 | 
1981 |     This is useful for contextualizing the results of a search function.
1982 |     For example, a code comparison tool might want to identify lines that
1983 |     have changed, but also surrounding lines to give the viewer of the diff
1984 |     context.
1985 | 
1986 |     The predicate function will only be called once for each item in the
1987 |     iterable.
1988 | 
1989 |     See also :func:`groupby_transform`, which can be used with this function
1990 |     to group ranges of items with the same `bool` value.
1991 | 
1992 |     """
1993 |     # Allow distance=0 mainly for testing that it reproduces results with map()
1994 |     if distance < 0:
1995 |         raise ValueError('distance must be at least 0')
1996 | 
1997 |     i1, i2 = tee(iterable)
1998 |     padding = [False] * distance
1999 |     selected = chain(padding, map(predicate, i1), padding)
2000 |     adjacent_to_selected = map(any, windowed(selected, 2 * distance + 1))
2001 |     return zip(adjacent_to_selected, i2)
2002 | 
2003 | 
2004 | def groupby_transform(iterable, keyfunc=None, valuefunc=None, reducefunc=None):
2005 |     """An extension of :func:`itertools.groupby` that can apply transformations
2006 |     to the grouped data.
2007 | 
2008 |     * *keyfunc* is a function computing a key value for each item in *iterable*
2009 |     * *valuefunc* is a function that transforms the individual items from
2010 |       *iterable* after grouping
2011 |     * *reducefunc* is a function that transforms each group of items
2012 | 
2013 |     >>> iterable = 'aAAbBBcCC'
2014 |     >>> keyfunc = lambda k: k.upper()
2015 |     >>> valuefunc = lambda v: v.lower()
2016 |     >>> reducefunc = lambda g: ''.join(g)
2017 |     >>> list(groupby_transform(iterable, keyfunc, valuefunc, reducefunc))
2018 |     [('A', 'aaa'), ('B', 'bbb'), ('C', 'ccc')]
2019 | 
2020 |     Each optional argument defaults to an identity function if not specified.
2021 | 
2022 |     :func:`groupby_transform` is useful when grouping elements of an iterable
2023 |     using a separate iterable as the key. To do this, :func:`zip` the iterables
2024 |     and pass a *keyfunc* that extracts the first element and a *valuefunc*
2025 |     that extracts the second element::
2026 | 
2027 |         >>> from operator import itemgetter
2028 |         >>> keys = [0, 0, 1, 1, 1, 2, 2, 2, 3]
2029 |         >>> values = 'abcdefghi'
2030 |         >>> iterable = zip(keys, values)
2031 |         >>> grouper = groupby_transform(iterable, itemgetter(0), itemgetter(1))
2032 |         >>> [(k, ''.join(g)) for k, g in grouper]
2033 |         [(0, 'ab'), (1, 'cde'), (2, 'fgh'), (3, 'i')]
2034 | 
2035 |     Note that the order of items in the iterable is significant.
2036 |     Only adjacent items are grouped together, so if you don't want any
2037 |     duplicate groups, you should sort the iterable by the key function.
2038 | 
2039 |     """
2040 |     ret = groupby(iterable, keyfunc)
2041 |     if valuefunc:
2042 |         ret = ((k, map(valuefunc, g)) for k, g in ret)
2043 |     if reducefunc:
2044 |         ret = ((k, reducefunc(g)) for k, g in ret)
2045 | 
2046 |     return ret
2047 | 
2048 | 
2049 | class numeric_range(abc.Sequence, abc.Hashable):
2050 |     """An extension of the built-in ``range()`` function whose arguments can
2051 |     be any orderable numeric type.
2052 | 
2053 |     With only *stop* specified, *start* defaults to ``0`` and *step*
2054 |     defaults to ``1``. The output items will match the type of *stop*:
2055 | 
2056 |         >>> list(numeric_range(3.5))
2057 |         [0.0, 1.0, 2.0, 3.0]
2058 | 
2059 |     With only *start* and *stop* specified, *step* defaults to ``1``. The
2060 |     output items will match the type of *start*:
2061 | 
2062 |         >>> from decimal import Decimal
2063 |         >>> start = Decimal('2.1')
2064 |         >>> stop = Decimal('5.1')
2065 |         >>> list(numeric_range(start, stop))
2066 |         [Decimal('2.1'), Decimal('3.1'), Decimal('4.1')]
2067 | 
2068 |     With *start*, *stop*, and *step*  specified the output items will match
2069 |     the type of ``start + step``:
2070 | 
2071 |         >>> from fractions import Fraction
2072 |         >>> start = Fraction(1, 2)  # Start at 1/2
2073 |         >>> stop = Fraction(5, 2)  # End at 5/2
2074 |         >>> step = Fraction(1, 2)  # Count by 1/2
2075 |         >>> list(numeric_range(start, stop, step))
2076 |         [Fraction(1, 2), Fraction(1, 1), Fraction(3, 2), Fraction(2, 1)]
2077 | 
2078 |     If *step* is zero, ``ValueError`` is raised. Negative steps are supported:
2079 | 
2080 |         >>> list(numeric_range(3, -1, -1.0))
2081 |         [3.0, 2.0, 1.0, 0.0]
2082 | 
2083 |     Be aware of the limitations of floating point numbers; the representation
2084 |     of the yielded numbers may be surprising.
2085 | 
2086 |     ``datetime.datetime`` objects can be used for *start* and *stop*, if *step*
2087 |     is a ``datetime.timedelta`` object:
2088 | 
2089 |         >>> import datetime
2090 |         >>> start = datetime.datetime(2019, 1, 1)
2091 |         >>> stop = datetime.datetime(2019, 1, 3)
2092 |         >>> step = datetime.timedelta(days=1)
2093 |         >>> items = iter(numeric_range(start, stop, step))
2094 |         >>> next(items)
2095 |         datetime.datetime(2019, 1, 1, 0, 0)
2096 |         >>> next(items)
2097 |         datetime.datetime(2019, 1, 2, 0, 0)
2098 | 
2099 |     """
2100 | 
2101 |     _EMPTY_HASH = hash(range(0, 0))
2102 | 
2103 |     def __init__(self, *args):
2104 |         argc = len(args)
2105 |         if argc == 1:
2106 |             (self._stop,) = args
2107 |             self._start = type(self._stop)(0)
2108 |             self._step = type(self._stop - self._start)(1)
2109 |         elif argc == 2:
2110 |             self._start, self._stop = args
2111 |             self._step = type(self._stop - self._start)(1)
2112 |         elif argc == 3:
2113 |             self._start, self._stop, self._step = args
2114 |         elif argc == 0:
2115 |             raise TypeError(
2116 |                 'numeric_range expected at least '
2117 |                 '1 argument, got {}'.format(argc)
2118 |             )
2119 |         else:
2120 |             raise TypeError(
2121 |                 'numeric_range expected at most '
2122 |                 '3 arguments, got {}'.format(argc)
2123 |             )
2124 | 
2125 |         self._zero = type(self._step)(0)
2126 |         if self._step == self._zero:
2127 |             raise ValueError('numeric_range() arg 3 must not be zero')
2128 |         self._growing = self._step > self._zero
2129 | 
2130 |     def __bool__(self):
2131 |         if self._growing:
2132 |             return self._start < self._stop
2133 |         else:
2134 |             return self._start > self._stop
2135 | 
2136 |     def __contains__(self, elem):
2137 |         if self._growing:
2138 |             if self._start <= elem < self._stop:
2139 |                 return (elem - self._start) % self._step == self._zero
2140 |         else:
2141 |             if self._start >= elem > self._stop:
2142 |                 return (self._start - elem) % (-self._step) == self._zero
2143 | 
2144 |         return False
2145 | 
2146 |     def __eq__(self, other):
2147 |         if isinstance(other, numeric_range):
2148 |             empty_self = not bool(self)
2149 |             empty_other = not bool(other)
2150 |             if empty_self or empty_other:
2151 |                 return empty_self and empty_other  # True if both empty
2152 |             else:
2153 |                 return (
2154 |                     self._start == other._start
2155 |                     and self._step == other._step
2156 |                     and self._get_by_index(-1) == other._get_by_index(-1)
2157 |                 )
2158 |         else:
2159 |             return False
2160 | 
2161 |     def __getitem__(self, key):
2162 |         if isinstance(key, int):
2163 |             return self._get_by_index(key)
2164 |         elif isinstance(key, slice):
2165 |             step = self._step if key.step is None else key.step * self._step
2166 | 
2167 |             if key.start is None or key.start <= -self._len:
2168 |                 start = self._start
2169 |             elif key.start >= self._len:
2170 |                 start = self._stop
2171 |             else:  # -self._len < key.start < self._len
2172 |                 start = self._get_by_index(key.start)
2173 | 
2174 |             if key.stop is None or key.stop >= self._len:
2175 |                 stop = self._stop
2176 |             elif key.stop <= -self._len:
2177 |                 stop = self._start
2178 |             else:  # -self._len < key.stop < self._len
2179 |                 stop = self._get_by_index(key.stop)
2180 | 
2181 |             return numeric_range(start, stop, step)
2182 |         else:
2183 |             raise TypeError(
2184 |                 'numeric range indices must be '
2185 |                 'integers or slices, not {}'.format(type(key).__name__)
2186 |             )
2187 | 
2188 |     def __hash__(self):
2189 |         if self:
2190 |             return hash((self._start, self._get_by_index(-1), self._step))
2191 |         else:
2192 |             return self._EMPTY_HASH
2193 | 
2194 |     def __iter__(self):
2195 |         values = (self._start + (n * self._step) for n in count())
2196 |         if self._growing:
2197 |             return takewhile(partial(gt, self._stop), values)
2198 |         else:
2199 |             return takewhile(partial(lt, self._stop), values)
2200 | 
2201 |     def __len__(self):
2202 |         return self._len
2203 | 
2204 |     @cached_property
2205 |     def _len(self):
2206 |         if self._growing:
2207 |             start = self._start
2208 |             stop = self._stop
2209 |             step = self._step
2210 |         else:
2211 |             start = self._stop
2212 |             stop = self._start
2213 |             step = -self._step
2214 |         distance = stop - start
2215 |         if distance <= self._zero:
2216 |             return 0
2217 |         else:  # distance > 0 and step > 0: regular euclidean division
2218 |             q, r = divmod(distance, step)
2219 |             return int(q) + int(r != self._zero)
2220 | 
2221 |     def __reduce__(self):
2222 |         return numeric_range, (self._start, self._stop, self._step)
2223 | 
2224 |     def __repr__(self):
2225 |         if self._step == 1:
2226 |             return "numeric_range({}, {})".format(
2227 |                 repr(self._start), repr(self._stop)
2228 |             )
2229 |         else:
2230 |             return "numeric_range({}, {}, {})".format(
2231 |                 repr(self._start), repr(self._stop), repr(self._step)
2232 |             )
2233 | 
2234 |     def __reversed__(self):
2235 |         return iter(
2236 |             numeric_range(
2237 |                 self._get_by_index(-1), self._start - self._step, -self._step
2238 |             )
2239 |         )
2240 | 
2241 |     def count(self, value):
2242 |         return int(value in self)
2243 | 
2244 |     def index(self, value):
2245 |         if self._growing:
2246 |             if self._start <= value < self._stop:
2247 |                 q, r = divmod(value - self._start, self._step)
2248 |                 if r == self._zero:
2249 |                     return int(q)
2250 |         else:
2251 |             if self._start >= value > self._stop:
2252 |                 q, r = divmod(self._start - value, -self._step)
2253 |                 if r == self._zero:
2254 |                     return int(q)
2255 | 
2256 |         raise ValueError("{} is not in numeric range".format(value))
2257 | 
2258 |     def _get_by_index(self, i):
2259 |         if i < 0:
2260 |             i += self._len
2261 |         if i < 0 or i >= self._len:
2262 |             raise IndexError("numeric range object index out of range")
2263 |         return self._start + i * self._step
2264 | 
2265 | 
2266 | def count_cycle(iterable, n=None):
2267 |     """Cycle through the items from *iterable* up to *n* times, yielding
2268 |     the number of completed cycles along with each item. If *n* is omitted the
2269 |     process repeats indefinitely.
2270 | 
2271 |     >>> list(count_cycle('AB', 3))
2272 |     [(0, 'A'), (0, 'B'), (1, 'A'), (1, 'B'), (2, 'A'), (2, 'B')]
2273 | 
2274 |     """
2275 |     iterable = tuple(iterable)
2276 |     if not iterable:
2277 |         return iter(())
2278 |     counter = count() if n is None else range(n)
2279 |     return ((i, item) for i in counter for item in iterable)
2280 | 
2281 | 
2282 | def mark_ends(iterable):
2283 |     """Yield 3-tuples of the form ``(is_first, is_last, item)``.
2284 | 
2285 |     >>> list(mark_ends('ABC'))
2286 |     [(True, False, 'A'), (False, False, 'B'), (False, True, 'C')]
2287 | 
2288 |     Use this when looping over an iterable to take special action on its first
2289 |     and/or last items:
2290 | 
2291 |     >>> iterable = ['Header', 100, 200, 'Footer']
2292 |     >>> total = 0
2293 |     >>> for is_first, is_last, item in mark_ends(iterable):
2294 |     ...     if is_first:
2295 |     ...         continue  # Skip the header
2296 |     ...     if is_last:
2297 |     ...         continue  # Skip the footer
2298 |     ...     total += item
2299 |     >>> print(total)
2300 |     300
2301 |     """
2302 |     it = iter(iterable)
2303 | 
2304 |     try:
2305 |         b = next(it)
2306 |     except StopIteration:
2307 |         return
2308 | 
2309 |     try:
2310 |         for i in count():
2311 |             a = b
2312 |             b = next(it)
2313 |             yield i == 0, False, a
2314 | 
2315 |     except StopIteration:
2316 |         yield i == 0, True, a
2317 | 
2318 | 
2319 | def locate(iterable, pred=bool, window_size=None):
2320 |     """Yield the index of each item in *iterable* for which *pred* returns
2321 |     ``True``.
2322 | 
2323 |     *pred* defaults to :func:`bool`, which will select truthy items:
2324 | 
2325 |         >>> list(locate([0, 1, 1, 0, 1, 0, 0]))
2326 |         [1, 2, 4]
2327 | 
2328 |     Set *pred* to a custom function to, e.g., find the indexes for a particular
2329 |     item.
2330 | 
2331 |         >>> list(locate(['a', 'b', 'c', 'b'], lambda x: x == 'b'))
2332 |         [1, 3]
2333 | 
2334 |     If *window_size* is given, then the *pred* function will be called with
2335 |     that many items. This enables searching for sub-sequences:
2336 | 
2337 |         >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
2338 |         >>> pred = lambda *args: args == (1, 2, 3)
2339 |         >>> list(locate(iterable, pred=pred, window_size=3))
2340 |         [1, 5, 9]
2341 | 
2342 |     Use with :func:`seekable` to find indexes and then retrieve the associated
2343 |     items:
2344 | 
2345 |         >>> from itertools import count
2346 |         >>> from more_itertools import seekable
2347 |         >>> source = (3 * n + 1 if (n % 2) else n // 2 for n in count())
2348 |         >>> it = seekable(source)
2349 |         >>> pred = lambda x: x > 100
2350 |         >>> indexes = locate(it, pred=pred)
2351 |         >>> i = next(indexes)
2352 |         >>> it.seek(i)
2353 |         >>> next(it)
2354 |         106
2355 | 
2356 |     """
2357 |     if window_size is None:
2358 |         return compress(count(), map(pred, iterable))
2359 | 
2360 |     if window_size < 1:
2361 |         raise ValueError('window size must be at least 1')
2362 | 
2363 |     it = windowed(iterable, window_size, fillvalue=_marker)
2364 |     return compress(count(), starmap(pred, it))
2365 | 
2366 | 
2367 | def longest_common_prefix(iterables):
2368 |     """Yield elements of the longest common prefix amongst given *iterables*.
2369 | 
2370 |     >>> ''.join(longest_common_prefix(['abcd', 'abc', 'abf']))
2371 |     'ab'
2372 | 
2373 |     """
2374 |     return (c[0] for c in takewhile(all_equal, zip(*iterables)))
2375 | 
2376 | 
2377 | def lstrip(iterable, pred):
2378 |     """Yield the items from *iterable*, but strip any from the beginning
2379 |     for which *pred* returns ``True``.
2380 | 
2381 |     For example, to remove a set of items from the start of an iterable:
2382 | 
2383 |         >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
2384 |         >>> pred = lambda x: x in {None, False, ''}
2385 |         >>> list(lstrip(iterable, pred))
2386 |         [1, 2, None, 3, False, None]
2387 | 
2388 |     This function is analogous to to :func:`str.lstrip`, and is essentially
2389 |     an wrapper for :func:`itertools.dropwhile`.
2390 | 
2391 |     """
2392 |     return dropwhile(pred, iterable)
2393 | 
2394 | 
2395 | def rstrip(iterable, pred):
2396 |     """Yield the items from *iterable*, but strip any from the end
2397 |     for which *pred* returns ``True``.
2398 | 
2399 |     For example, to remove a set of items from the end of an iterable:
2400 | 
2401 |         >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
2402 |         >>> pred = lambda x: x in {None, False, ''}
2403 |         >>> list(rstrip(iterable, pred))
2404 |         [None, False, None, 1, 2, None, 3]
2405 | 
2406 |     This function is analogous to :func:`str.rstrip`.
2407 | 
2408 |     """
2409 |     cache = []
2410 |     cache_append = cache.append
2411 |     cache_clear = cache.clear
2412 |     for x in iterable:
2413 |         if pred(x):
2414 |             cache_append(x)
2415 |         else:
2416 |             yield from cache
2417 |             cache_clear()
2418 |             yield x
2419 | 
2420 | 
2421 | def strip(iterable, pred):
2422 |     """Yield the items from *iterable*, but strip any from the
2423 |     beginning and end for which *pred* returns ``True``.
2424 | 
2425 |     For example, to remove a set of items from both ends of an iterable:
2426 | 
2427 |         >>> iterable = (None, False, None, 1, 2, None, 3, False, None)
2428 |         >>> pred = lambda x: x in {None, False, ''}
2429 |         >>> list(strip(iterable, pred))
2430 |         [1, 2, None, 3]
2431 | 
2432 |     This function is analogous to :func:`str.strip`.
2433 | 
2434 |     """
2435 |     return rstrip(lstrip(iterable, pred), pred)
2436 | 
2437 | 
2438 | class islice_extended:
2439 |     """An extension of :func:`itertools.islice` that supports negative values
2440 |     for *stop*, *start*, and *step*.
2441 | 
2442 |         >>> iterable = iter('abcdefgh')
2443 |         >>> list(islice_extended(iterable, -4, -1))
2444 |         ['e', 'f', 'g']
2445 | 
2446 |     Slices with negative values require some caching of *iterable*, but this
2447 |     function takes care to minimize the amount of memory required.
2448 | 
2449 |     For example, you can use a negative step with an infinite iterator:
2450 | 
2451 |         >>> from itertools import count
2452 |         >>> list(islice_extended(count(), 110, 99, -2))
2453 |         [110, 108, 106, 104, 102, 100]
2454 | 
2455 |     You can also use slice notation directly:
2456 | 
2457 |         >>> iterable = map(str, count())
2458 |         >>> it = islice_extended(iterable)[10:20:2]
2459 |         >>> list(it)
2460 |         ['10', '12', '14', '16', '18']
2461 | 
2462 |     """
2463 | 
2464 |     def __init__(self, iterable, *args):
2465 |         it = iter(iterable)
2466 |         if args:
2467 |             self._iterable = _islice_helper(it, slice(*args))
2468 |         else:
2469 |             self._iterable = it
2470 | 
2471 |     def __iter__(self):
2472 |         return self
2473 | 
2474 |     def __next__(self):
2475 |         return next(self._iterable)
2476 | 
2477 |     def __getitem__(self, key):
2478 |         if isinstance(key, slice):
2479 |             return islice_extended(_islice_helper(self._iterable, key))
2480 | 
2481 |         raise TypeError('islice_extended.__getitem__ argument must be a slice')
2482 | 
2483 | 
2484 | def _islice_helper(it, s):
2485 |     start = s.start
2486 |     stop = s.stop
2487 |     if s.step == 0:
2488 |         raise ValueError('step argument must be a non-zero integer or None.')
2489 |     step = s.step or 1
2490 | 
2491 |     if step > 0:
2492 |         start = 0 if (start is None) else start
2493 | 
2494 |         if start < 0:
2495 |             # Consume all but the last -start items
2496 |             cache = deque(enumerate(it, 1), maxlen=-start)
2497 |             len_iter = cache[-1][0] if cache else 0
2498 | 
2499 |             # Adjust start to be positive
2500 |             i = max(len_iter + start, 0)
2501 | 
2502 |             # Adjust stop to be positive
2503 |             if stop is None:
2504 |                 j = len_iter
2505 |             elif stop >= 0:
2506 |                 j = min(stop, len_iter)
2507 |             else:
2508 |                 j = max(len_iter + stop, 0)
2509 | 
2510 |             # Slice the cache
2511 |             n = j - i
2512 |             if n <= 0:
2513 |                 return
2514 | 
2515 |             for index, item in islice(cache, 0, n, step):
2516 |                 yield item
2517 |         elif (stop is not None) and (stop < 0):
2518 |             # Advance to the start position
2519 |             next(islice(it, start, start), None)
2520 | 
2521 |             # When stop is negative, we have to carry -stop items while
2522 |             # iterating
2523 |             cache = deque(islice(it, -stop), maxlen=-stop)
2524 | 
2525 |             for index, item in enumerate(it):
2526 |                 cached_item = cache.popleft()
2527 |                 if index % step == 0:
2528 |                     yield cached_item
2529 |                 cache.append(item)
2530 |         else:
2531 |             # When both start and stop are positive we have the normal case
2532 |             yield from islice(it, start, stop, step)
2533 |     else:
2534 |         start = -1 if (start is None) else start
2535 | 
2536 |         if (stop is not None) and (stop < 0):
2537 |             # Consume all but the last items
2538 |             n = -stop - 1
2539 |             cache = deque(enumerate(it, 1), maxlen=n)
2540 |             len_iter = cache[-1][0] if cache else 0
2541 | 
2542 |             # If start and stop are both negative they are comparable and
2543 |             # we can just slice. Otherwise we can adjust start to be negative
2544 |             # and then slice.
2545 |             if start < 0:
2546 |                 i, j = start, stop
2547 |             else:
2548 |                 i, j = min(start - len_iter, -1), None
2549 | 
2550 |             for index, item in list(cache)[i:j:step]:
2551 |                 yield item
2552 |         else:
2553 |             # Advance to the stop position
2554 |             if stop is not None:
2555 |                 m = stop + 1
2556 |                 next(islice(it, m, m), None)
2557 | 
2558 |             # stop is positive, so if start is negative they are not comparable
2559 |             # and we need the rest of the items.
2560 |             if start < 0:
2561 |                 i = start
2562 |                 n = None
2563 |             # stop is None and start is positive, so we just need items up to
2564 |             # the start index.
2565 |             elif stop is None:
2566 |                 i = None
2567 |                 n = start + 1
2568 |             # Both stop and start are positive, so they are comparable.
2569 |             else:
2570 |                 i = None
2571 |                 n = start - stop
2572 |                 if n <= 0:
2573 |                     return
2574 | 
2575 |             cache = list(islice(it, n))
2576 | 
2577 |             yield from cache[i::step]
2578 | 
2579 | 
2580 | def always_reversible(iterable):
2581 |     """An extension of :func:`reversed` that supports all iterables, not
2582 |     just those which implement the ``Reversible`` or ``Sequence`` protocols.
2583 | 
2584 |         >>> print(*always_reversible(x for x in range(3)))
2585 |         2 1 0
2586 | 
2587 |     If the iterable is already reversible, this function returns the
2588 |     result of :func:`reversed()`. If the iterable is not reversible,
2589 |     this function will cache the remaining items in the iterable and
2590 |     yield them in reverse order, which may require significant storage.
2591 |     """
2592 |     try:
2593 |         return reversed(iterable)
2594 |     except TypeError:
2595 |         return reversed(list(iterable))
2596 | 
2597 | 
2598 | def consecutive_groups(iterable, ordering=lambda x: x):
2599 |     """Yield groups of consecutive items using :func:`itertools.groupby`.
2600 |     The *ordering* function determines whether two items are adjacent by
2601 |     returning their position.
2602 | 
2603 |     By default, the ordering function is the identity function. This is
2604 |     suitable for finding runs of numbers:
2605 | 
2606 |         >>> iterable = [1, 10, 11, 12, 20, 30, 31, 32, 33, 40]
2607 |         >>> for group in consecutive_groups(iterable):
2608 |         ...     print(list(group))
2609 |         [1]
2610 |         [10, 11, 12]
2611 |         [20]
2612 |         [30, 31, 32, 33]
2613 |         [40]
2614 | 
2615 |     For finding runs of adjacent letters, try using the :meth:`index` method
2616 |     of a string of letters:
2617 | 
2618 |         >>> from string import ascii_lowercase
2619 |         >>> iterable = 'abcdfgilmnop'
2620 |         >>> ordering = ascii_lowercase.index
2621 |         >>> for group in consecutive_groups(iterable, ordering):
2622 |         ...     print(list(group))
2623 |         ['a', 'b', 'c', 'd']
2624 |         ['f', 'g']
2625 |         ['i']
2626 |         ['l', 'm', 'n', 'o', 'p']
2627 | 
2628 |     Each group of consecutive items is an iterator that shares it source with
2629 |     *iterable*. When an an output group is advanced, the previous group is
2630 |     no longer available unless its elements are copied (e.g., into a ``list``).
2631 | 
2632 |         >>> iterable = [1, 2, 11, 12, 21, 22]
2633 |         >>> saved_groups = []
2634 |         >>> for group in consecutive_groups(iterable):
2635 |         ...     saved_groups.append(list(group))  # Copy group elements
2636 |         >>> saved_groups
2637 |         [[1, 2], [11, 12], [21, 22]]
2638 | 
2639 |     """
2640 |     for k, g in groupby(
2641 |         enumerate(iterable), key=lambda x: x[0] - ordering(x[1])
2642 |     ):
2643 |         yield map(itemgetter(1), g)
2644 | 
2645 | 
2646 | def difference(iterable, func=sub, *, initial=None):
2647 |     """This function is the inverse of :func:`itertools.accumulate`. By default
2648 |     it will compute the first difference of *iterable* using
2649 |     :func:`operator.sub`:
2650 | 
2651 |         >>> from itertools import accumulate
2652 |         >>> iterable = accumulate([0, 1, 2, 3, 4])  # produces 0, 1, 3, 6, 10
2653 |         >>> list(difference(iterable))
2654 |         [0, 1, 2, 3, 4]
2655 | 
2656 |     *func* defaults to :func:`operator.sub`, but other functions can be
2657 |     specified. They will be applied as follows::
2658 | 
2659 |         A, B, C, D, ... --> A, func(B, A), func(C, B), func(D, C), ...
2660 | 
2661 |     For example, to do progressive division:
2662 | 
2663 |         >>> iterable = [1, 2, 6, 24, 120]
2664 |         >>> func = lambda x, y: x // y
2665 |         >>> list(difference(iterable, func))
2666 |         [1, 2, 3, 4, 5]
2667 | 
2668 |     If the *initial* keyword is set, the first element will be skipped when
2669 |     computing successive differences.
2670 | 
2671 |         >>> it = [10, 11, 13, 16]  # from accumulate([1, 2, 3], initial=10)
2672 |         >>> list(difference(it, initial=10))
2673 |         [1, 2, 3]
2674 | 
2675 |     """
2676 |     a, b = tee(iterable)
2677 |     try:
2678 |         first = [next(b)]
2679 |     except StopIteration:
2680 |         return iter([])
2681 | 
2682 |     if initial is not None:
2683 |         first = []
2684 | 
2685 |     return chain(first, map(func, b, a))
2686 | 
2687 | 
2688 | class SequenceView(Sequence):
2689 |     """Return a read-only view of the sequence object *target*.
2690 | 
2691 |     :class:`SequenceView` objects are analogous to Python's built-in
2692 |     "dictionary view" types. They provide a dynamic view of a sequence's items,
2693 |     meaning that when the sequence updates, so does the view.
2694 | 
2695 |         >>> seq = ['0', '1', '2']
2696 |         >>> view = SequenceView(seq)
2697 |         >>> view
2698 |         SequenceView(['0', '1', '2'])
2699 |         >>> seq.append('3')
2700 |         >>> view
2701 |         SequenceView(['0', '1', '2', '3'])
2702 | 
2703 |     Sequence views support indexing, slicing, and length queries. They act
2704 |     like the underlying sequence, except they don't allow assignment:
2705 | 
2706 |         >>> view[1]
2707 |         '1'
2708 |         >>> view[1:-1]
2709 |         ['1', '2']
2710 |         >>> len(view)
2711 |         4
2712 | 
2713 |     Sequence views are useful as an alternative to copying, as they don't
2714 |     require (much) extra storage.
2715 | 
2716 |     """
2717 | 
2718 |     def __init__(self, target):
2719 |         if not isinstance(target, Sequence):
2720 |             raise TypeError
2721 |         self._target = target
2722 | 
2723 |     def __getitem__(self, index):
2724 |         return self._target[index]
2725 | 
2726 |     def __len__(self):
2727 |         return len(self._target)
2728 | 
2729 |     def __repr__(self):
2730 |         return '{}({})'.format(self.__class__.__name__, repr(self._target))
2731 | 
2732 | 
2733 | class seekable:
2734 |     """Wrap an iterator to allow for seeking backward and forward. This
2735 |     progressively caches the items in the source iterable so they can be
2736 |     re-visited.
2737 | 
2738 |     Call :meth:`seek` with an index to seek to that position in the source
2739 |     iterable.
2740 | 
2741 |     To "reset" an iterator, seek to ``0``:
2742 | 
2743 |         >>> from itertools import count
2744 |         >>> it = seekable((str(n) for n in count()))
2745 |         >>> next(it), next(it), next(it)
2746 |         ('0', '1', '2')
2747 |         >>> it.seek(0)
2748 |         >>> next(it), next(it), next(it)
2749 |         ('0', '1', '2')
2750 |         >>> next(it)
2751 |         '3'
2752 | 
2753 |     You can also seek forward:
2754 | 
2755 |         >>> it = seekable((str(n) for n in range(20)))
2756 |         >>> it.seek(10)
2757 |         >>> next(it)
2758 |         '10'
2759 |         >>> it.relative_seek(-2)  # Seeking relative to the current position
2760 |         >>> next(it)
2761 |         '9'
2762 |         >>> it.seek(20)  # Seeking past the end of the source isn't a problem
2763 |         >>> list(it)
2764 |         []
2765 |         >>> it.seek(0)  # Resetting works even after hitting the end
2766 |         >>> next(it), next(it), next(it)
2767 |         ('0', '1', '2')
2768 | 
2769 |     Call :meth:`peek` to look ahead one item without advancing the iterator:
2770 | 
2771 |         >>> it = seekable('1234')
2772 |         >>> it.peek()
2773 |         '1'
2774 |         >>> list(it)
2775 |         ['1', '2', '3', '4']
2776 |         >>> it.peek(default='empty')
2777 |         'empty'
2778 | 
2779 |     Before the iterator is at its end, calling :func:`bool` on it will return
2780 |     ``True``. After it will return ``False``:
2781 | 
2782 |         >>> it = seekable('5678')
2783 |         >>> bool(it)
2784 |         True
2785 |         >>> list(it)
2786 |         ['5', '6', '7', '8']
2787 |         >>> bool(it)
2788 |         False
2789 | 
2790 |     You may view the contents of the cache with the :meth:`elements` method.
2791 |     That returns a :class:`SequenceView`, a view that updates automatically:
2792 | 
2793 |         >>> it = seekable((str(n) for n in range(10)))
2794 |         >>> next(it), next(it), next(it)
2795 |         ('0', '1', '2')
2796 |         >>> elements = it.elements()
2797 |         >>> elements
2798 |         SequenceView(['0', '1', '2'])
2799 |         >>> next(it)
2800 |         '3'
2801 |         >>> elements
2802 |         SequenceView(['0', '1', '2', '3'])
2803 | 
2804 |     By default, the cache grows as the source iterable progresses, so beware of
2805 |     wrapping very large or infinite iterables. Supply *maxlen* to limit the
2806 |     size of the cache (this of course limits how far back you can seek).
2807 | 
2808 |         >>> from itertools import count
2809 |         >>> it = seekable((str(n) for n in count()), maxlen=2)
2810 |         >>> next(it), next(it), next(it), next(it)
2811 |         ('0', '1', '2', '3')
2812 |         >>> list(it.elements())
2813 |         ['2', '3']
2814 |         >>> it.seek(0)
2815 |         >>> next(it), next(it), next(it), next(it)
2816 |         ('2', '3', '4', '5')
2817 |         >>> next(it)
2818 |         '6'
2819 | 
2820 |     """
2821 | 
2822 |     def __init__(self, iterable, maxlen=None):
2823 |         self._source = iter(iterable)
2824 |         if maxlen is None:
2825 |             self._cache = []
2826 |         else:
2827 |             self._cache = deque([], maxlen)
2828 |         self._index = None
2829 | 
2830 |     def __iter__(self):
2831 |         return self
2832 | 
2833 |     def __next__(self):
2834 |         if self._index is not None:
2835 |             try:
2836 |                 item = self._cache[self._index]
2837 |             except IndexError:
2838 |                 self._index = None
2839 |             else:
2840 |                 self._index += 1
2841 |                 return item
2842 | 
2843 |         item = next(self._source)
2844 |         self._cache.append(item)
2845 |         return item
2846 | 
2847 |     def __bool__(self):
2848 |         try:
2849 |             self.peek()
2850 |         except StopIteration:
2851 |             return False
2852 |         return True
2853 | 
2854 |     def peek(self, default=_marker):
2855 |         try:
2856 |             peeked = next(self)
2857 |         except StopIteration:
2858 |             if default is _marker:
2859 |                 raise
2860 |             return default
2861 |         if self._index is None:
2862 |             self._index = len(self._cache)
2863 |         self._index -= 1
2864 |         return peeked
2865 | 
2866 |     def elements(self):
2867 |         return SequenceView(self._cache)
2868 | 
2869 |     def seek(self, index):
2870 |         self._index = index
2871 |         remainder = index - len(self._cache)
2872 |         if remainder > 0:
2873 |             consume(self, remainder)
2874 | 
2875 |     def relative_seek(self, count):
2876 |         index = len(self._cache)
2877 |         self.seek(max(index + count, 0))
2878 | 
2879 | 
2880 | class run_length:
2881 |     """
2882 |     :func:`run_length.encode` compresses an iterable with run-length encoding.
2883 |     It yields groups of repeated items with the count of how many times they
2884 |     were repeated:
2885 | 
2886 |         >>> uncompressed = 'abbcccdddd'
2887 |         >>> list(run_length.encode(uncompressed))
2888 |         [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
2889 | 
2890 |     :func:`run_length.decode` decompresses an iterable that was previously
2891 |     compressed with run-length encoding. It yields the items of the
2892 |     decompressed iterable:
2893 | 
2894 |         >>> compressed = [('a', 1), ('b', 2), ('c', 3), ('d', 4)]
2895 |         >>> list(run_length.decode(compressed))
2896 |         ['a', 'b', 'b', 'c', 'c', 'c', 'd', 'd', 'd', 'd']
2897 | 
2898 |     """
2899 | 
2900 |     @staticmethod
2901 |     def encode(iterable):
2902 |         return ((k, ilen(g)) for k, g in groupby(iterable))
2903 | 
2904 |     @staticmethod
2905 |     def decode(iterable):
2906 |         return chain.from_iterable(repeat(k, n) for k, n in iterable)
2907 | 
2908 | 
2909 | def exactly_n(iterable, n, predicate=bool):
2910 |     """Return ``True`` if exactly ``n`` items in the iterable are ``True``
2911 |     according to the *predicate* function.
2912 | 
2913 |         >>> exactly_n([True, True, False], 2)
2914 |         True
2915 |         >>> exactly_n([True, True, False], 1)
2916 |         False
2917 |         >>> exactly_n([0, 1, 2, 3, 4, 5], 3, lambda x: x < 3)
2918 |         True
2919 | 
2920 |     The iterable will be advanced until ``n + 1`` truthy items are encountered,
2921 |     so avoid calling it on infinite iterables.
2922 | 
2923 |     """
2924 |     return len(take(n + 1, filter(predicate, iterable))) == n
2925 | 
2926 | 
2927 | def circular_shifts(iterable):
2928 |     """Return a list of circular shifts of *iterable*.
2929 | 
2930 |     >>> circular_shifts(range(4))
2931 |     [(0, 1, 2, 3), (1, 2, 3, 0), (2, 3, 0, 1), (3, 0, 1, 2)]
2932 |     """
2933 |     lst = list(iterable)
2934 |     return take(len(lst), windowed(cycle(lst), len(lst)))
2935 | 
2936 | 
2937 | def make_decorator(wrapping_func, result_index=0):
2938 |     """Return a decorator version of *wrapping_func*, which is a function that
2939 |     modifies an iterable. *result_index* is the position in that function's
2940 |     signature where the iterable goes.
2941 | 
2942 |     This lets you use itertools on the "production end," i.e. at function
2943 |     definition. This can augment what the function returns without changing the
2944 |     function's code.
2945 | 
2946 |     For example, to produce a decorator version of :func:`chunked`:
2947 | 
2948 |         >>> from more_itertools import chunked
2949 |         >>> chunker = make_decorator(chunked, result_index=0)
2950 |         >>> @chunker(3)
2951 |         ... def iter_range(n):
2952 |         ...     return iter(range(n))
2953 |         ...
2954 |         >>> list(iter_range(9))
2955 |         [[0, 1, 2], [3, 4, 5], [6, 7, 8]]
2956 | 
2957 |     To only allow truthy items to be returned:
2958 | 
2959 |         >>> truth_serum = make_decorator(filter, result_index=1)
2960 |         >>> @truth_serum(bool)
2961 |         ... def boolean_test():
2962 |         ...     return [0, 1, '', ' ', False, True]
2963 |         ...
2964 |         >>> list(boolean_test())
2965 |         [1, ' ', True]
2966 | 
2967 |     The :func:`peekable` and :func:`seekable` wrappers make for practical
2968 |     decorators:
2969 | 
2970 |         >>> from more_itertools import peekable
2971 |         >>> peekable_function = make_decorator(peekable)
2972 |         >>> @peekable_function()
2973 |         ... def str_range(*args):
2974 |         ...     return (str(x) for x in range(*args))
2975 |         ...
2976 |         >>> it = str_range(1, 20, 2)
2977 |         >>> next(it), next(it), next(it)
2978 |         ('1', '3', '5')
2979 |         >>> it.peek()
2980 |         '7'
2981 |         >>> next(it)
2982 |         '7'
2983 | 
2984 |     """
2985 | 
2986 |     # See https://sites.google.com/site/bbayles/index/decorator_factory for
2987 |     # notes on how this works.
2988 |     def decorator(*wrapping_args, **wrapping_kwargs):
2989 |         def outer_wrapper(f):
2990 |             def inner_wrapper(*args, **kwargs):
2991 |                 result = f(*args, **kwargs)
2992 |                 wrapping_args_ = list(wrapping_args)
2993 |                 wrapping_args_.insert(result_index, result)
2994 |                 return wrapping_func(*wrapping_args_, **wrapping_kwargs)
2995 | 
2996 |             return inner_wrapper
2997 | 
2998 |         return outer_wrapper
2999 | 
3000 |     return decorator
3001 | 
3002 | 
3003 | def map_reduce(iterable, keyfunc, valuefunc=None, reducefunc=None):
3004 |     """Return a dictionary that maps the items in *iterable* to categories
3005 |     defined by *keyfunc*, transforms them with *valuefunc*, and
3006 |     then summarizes them by category with *reducefunc*.
3007 | 
3008 |     *valuefunc* defaults to the identity function if it is unspecified.
3009 |     If *reducefunc* is unspecified, no summarization takes place:
3010 | 
3011 |         >>> keyfunc = lambda x: x.upper()
3012 |         >>> result = map_reduce('abbccc', keyfunc)
3013 |         >>> sorted(result.items())
3014 |         [('A', ['a']), ('B', ['b', 'b']), ('C', ['c', 'c', 'c'])]
3015 | 
3016 |     Specifying *valuefunc* transforms the categorized items:
3017 | 
3018 |         >>> keyfunc = lambda x: x.upper()
3019 |         >>> valuefunc = lambda x: 1
3020 |         >>> result = map_reduce('abbccc', keyfunc, valuefunc)
3021 |         >>> sorted(result.items())
3022 |         [('A', [1]), ('B', [1, 1]), ('C', [1, 1, 1])]
3023 | 
3024 |     Specifying *reducefunc* summarizes the categorized items:
3025 | 
3026 |         >>> keyfunc = lambda x: x.upper()
3027 |         >>> valuefunc = lambda x: 1
3028 |         >>> reducefunc = sum
3029 |         >>> result = map_reduce('abbccc', keyfunc, valuefunc, reducefunc)
3030 |         >>> sorted(result.items())
3031 |         [('A', 1), ('B', 2), ('C', 3)]
3032 | 
3033 |     You may want to filter the input iterable before applying the map/reduce
3034 |     procedure:
3035 | 
3036 |         >>> all_items = range(30)
3037 |         >>> items = [x for x in all_items if 10 <= x <= 20]  # Filter
3038 |         >>> keyfunc = lambda x: x % 2  # Evens map to 0; odds to 1
3039 |         >>> categories = map_reduce(items, keyfunc=keyfunc)
3040 |         >>> sorted(categories.items())
3041 |         [(0, [10, 12, 14, 16, 18, 20]), (1, [11, 13, 15, 17, 19])]
3042 |         >>> summaries = map_reduce(items, keyfunc=keyfunc, reducefunc=sum)
3043 |         >>> sorted(summaries.items())
3044 |         [(0, 90), (1, 75)]
3045 | 
3046 |     Note that all items in the iterable are gathered into a list before the
3047 |     summarization step, which may require significant storage.
3048 | 
3049 |     The returned object is a :obj:`collections.defaultdict` with the
3050 |     ``default_factory`` set to ``None``, such that it behaves like a normal
3051 |     dictionary.
3052 | 
3053 |     """
3054 |     valuefunc = (lambda x: x) if (valuefunc is None) else valuefunc
3055 | 
3056 |     ret = defaultdict(list)
3057 |     for item in iterable:
3058 |         key = keyfunc(item)
3059 |         value = valuefunc(item)
3060 |         ret[key].append(value)
3061 | 
3062 |     if reducefunc is not None:
3063 |         for key, value_list in ret.items():
3064 |             ret[key] = reducefunc(value_list)
3065 | 
3066 |     ret.default_factory = None
3067 |     return ret
3068 | 
3069 | 
3070 | def rlocate(iterable, pred=bool, window_size=None):
3071 |     """Yield the index of each item in *iterable* for which *pred* returns
3072 |     ``True``, starting from the right and moving left.
3073 | 
3074 |     *pred* defaults to :func:`bool`, which will select truthy items:
3075 | 
3076 |         >>> list(rlocate([0, 1, 1, 0, 1, 0, 0]))  # Truthy at 1, 2, and 4
3077 |         [4, 2, 1]
3078 | 
3079 |     Set *pred* to a custom function to, e.g., find the indexes for a particular
3080 |     item:
3081 | 
3082 |         >>> iterable = iter('abcb')
3083 |         >>> pred = lambda x: x == 'b'
3084 |         >>> list(rlocate(iterable, pred))
3085 |         [3, 1]
3086 | 
3087 |     If *window_size* is given, then the *pred* function will be called with
3088 |     that many items. This enables searching for sub-sequences:
3089 | 
3090 |         >>> iterable = [0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3]
3091 |         >>> pred = lambda *args: args == (1, 2, 3)
3092 |         >>> list(rlocate(iterable, pred=pred, window_size=3))
3093 |         [9, 5, 1]
3094 | 
3095 |     Beware, this function won't return anything for infinite iterables.
3096 |     If *iterable* is reversible, ``rlocate`` will reverse it and search from
3097 |     the right. Otherwise, it will search from the left and return the results
3098 |     in reverse order.
3099 | 
3100 |     See :func:`locate` to for other example applications.
3101 | 
3102 |     """
3103 |     if window_size is None:
3104 |         try:
3105 |             len_iter = len(iterable)
3106 |             return (len_iter - i - 1 for i in locate(reversed(iterable), pred))
3107 |         except TypeError:
3108 |             pass
3109 | 
3110 |     return reversed(list(locate(iterable, pred, window_size)))
3111 | 
3112 | 
3113 | def replace(iterable, pred, substitutes, count=None, window_size=1):
3114 |     """Yield the items from *iterable*, replacing the items for which *pred*
3115 |     returns ``True`` with the items from the iterable *substitutes*.
3116 | 
3117 |         >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1]
3118 |         >>> pred = lambda x: x == 0
3119 |         >>> substitutes = (2, 3)
3120 |         >>> list(replace(iterable, pred, substitutes))
3121 |         [1, 1, 2, 3, 1, 1, 2, 3, 1, 1]
3122 | 
3123 |     If *count* is given, the number of replacements will be limited:
3124 | 
3125 |         >>> iterable = [1, 1, 0, 1, 1, 0, 1, 1, 0]
3126 |         >>> pred = lambda x: x == 0
3127 |         >>> substitutes = [None]
3128 |         >>> list(replace(iterable, pred, substitutes, count=2))
3129 |         [1, 1, None, 1, 1, None, 1, 1, 0]
3130 | 
3131 |     Use *window_size* to control the number of items passed as arguments to
3132 |     *pred*. This allows for locating and replacing subsequences.
3133 | 
3134 |         >>> iterable = [0, 1, 2, 5, 0, 1, 2, 5]
3135 |         >>> window_size = 3
3136 |         >>> pred = lambda *args: args == (0, 1, 2)  # 3 items passed to pred
3137 |         >>> substitutes = [3, 4] # Splice in these items
3138 |         >>> list(replace(iterable, pred, substitutes, window_size=window_size))
3139 |         [3, 4, 5, 3, 4, 5]
3140 | 
3141 |     """
3142 |     if window_size < 1:
3143 |         raise ValueError('window_size must be at least 1')
3144 | 
3145 |     # Save the substitutes iterable, since it's used more than once
3146 |     substitutes = tuple(substitutes)
3147 | 
3148 |     # Add padding such that the number of windows matches the length of the
3149 |     # iterable
3150 |     it = chain(iterable, [_marker] * (window_size - 1))
3151 |     windows = windowed(it, window_size)
3152 | 
3153 |     n = 0
3154 |     for w in windows:
3155 |         # If the current window matches our predicate (and we haven't hit
3156 |         # our maximum number of replacements), splice in the substitutes
3157 |         # and then consume the following windows that overlap with this one.
3158 |         # For example, if the iterable is (0, 1, 2, 3, 4...)
3159 |         # and the window size is 2, we have (0, 1), (1, 2), (2, 3)...
3160 |         # If the predicate matches on (0, 1), we need to zap (0, 1) and (1, 2)
3161 |         if pred(*w):
3162 |             if (count is None) or (n < count):
3163 |                 n += 1
3164 |                 yield from substitutes
3165 |                 consume(windows, window_size - 1)
3166 |                 continue
3167 | 
3168 |         # If there was no match (or we've reached the replacement limit),
3169 |         # yield the first item from the window.
3170 |         if w and (w[0] is not _marker):
3171 |             yield w[0]
3172 | 
3173 | 
3174 | def partitions(iterable):
3175 |     """Yield all possible order-preserving partitions of *iterable*.
3176 | 
3177 |     >>> iterable = 'abc'
3178 |     >>> for part in partitions(iterable):
3179 |     ...     print([''.join(p) for p in part])
3180 |     ['abc']
3181 |     ['a', 'bc']
3182 |     ['ab', 'c']
3183 |     ['a', 'b', 'c']
3184 | 
3185 |     This is unrelated to :func:`partition`.
3186 | 
3187 |     """
3188 |     sequence = list(iterable)
3189 |     n = len(sequence)
3190 |     for i in powerset(range(1, n)):
3191 |         yield [sequence[i:j] for i, j in zip((0,) + i, i + (n,))]
3192 | 
3193 | 
3194 | def set_partitions(iterable, k=None):
3195 |     """
3196 |     Yield the set partitions of *iterable* into *k* parts. Set partitions are
3197 |     not order-preserving.
3198 | 
3199 |     >>> iterable = 'abc'
3200 |     >>> for part in set_partitions(iterable, 2):
3201 |     ...     print([''.join(p) for p in part])
3202 |     ['a', 'bc']
3203 |     ['ab', 'c']
3204 |     ['b', 'ac']
3205 | 
3206 | 
3207 |     If *k* is not given, every set partition is generated.
3208 | 
3209 |     >>> iterable = 'abc'
3210 |     >>> for part in set_partitions(iterable):
3211 |     ...     print([''.join(p) for p in part])
3212 |     ['abc']
3213 |     ['a', 'bc']
3214 |     ['ab', 'c']
3215 |     ['b', 'ac']
3216 |     ['a', 'b', 'c']
3217 | 
3218 |     """
3219 |     L = list(iterable)
3220 |     n = len(L)
3221 |     if k is not None:
3222 |         if k < 1:
3223 |             raise ValueError(
3224 |                 "Can't partition in a negative or zero number of groups"
3225 |             )
3226 |         elif k > n:
3227 |             return
3228 | 
3229 |     def set_partitions_helper(L, k):
3230 |         n = len(L)
3231 |         if k == 1:
3232 |             yield [L]
3233 |         elif n == k:
3234 |             yield [[s] for s in L]
3235 |         else:
3236 |             e, *M = L
3237 |             for p in set_partitions_helper(M, k - 1):
3238 |                 yield [[e], *p]
3239 |             for p in set_partitions_helper(M, k):
3240 |                 for i in range(len(p)):
3241 |                     yield p[:i] + [[e] + p[i]] + p[i + 1 :]
3242 | 
3243 |     if k is None:
3244 |         for k in range(1, n + 1):
3245 |             yield from set_partitions_helper(L, k)
3246 |     else:
3247 |         yield from set_partitions_helper(L, k)
3248 | 
3249 | 
3250 | class time_limited:
3251 |     """
3252 |     Yield items from *iterable* until *limit_seconds* have passed.
3253 |     If the time limit expires before all items have been yielded, the
3254 |     ``timed_out`` parameter will be set to ``True``.
3255 | 
3256 |     >>> from time import sleep
3257 |     >>> def generator():
3258 |     ...     yield 1
3259 |     ...     yield 2
3260 |     ...     sleep(0.2)
3261 |     ...     yield 3
3262 |     >>> iterable = time_limited(0.1, generator())
3263 |     >>> list(iterable)
3264 |     [1, 2]
3265 |     >>> iterable.timed_out
3266 |     True
3267 | 
3268 |     Note that the time is checked before each item is yielded, and iteration
3269 |     stops if  the time elapsed is greater than *limit_seconds*. If your time
3270 |     limit is 1 second, but it takes 2 seconds to generate the first item from
3271 |     the iterable, the function will run for 2 seconds and not yield anything.
3272 |     As a special case, when *limit_seconds* is zero, the iterator never
3273 |     returns anything.
3274 | 
3275 |     """
3276 | 
3277 |     def __init__(self, limit_seconds, iterable):
3278 |         if limit_seconds < 0:
3279 |             raise ValueError('limit_seconds must be positive')
3280 |         self.limit_seconds = limit_seconds
3281 |         self._iterable = iter(iterable)
3282 |         self._start_time = monotonic()
3283 |         self.timed_out = False
3284 | 
3285 |     def __iter__(self):
3286 |         return self
3287 | 
3288 |     def __next__(self):
3289 |         if self.limit_seconds == 0:
3290 |             self.timed_out = True
3291 |             raise StopIteration
3292 |         item = next(self._iterable)
3293 |         if monotonic() - self._start_time > self.limit_seconds:
3294 |             self.timed_out = True
3295 |             raise StopIteration
3296 | 
3297 |         return item
3298 | 
3299 | 
3300 | def only(iterable, default=None, too_long=None):
3301 |     """If *iterable* has only one item, return it.
3302 |     If it has zero items, return *default*.
3303 |     If it has more than one item, raise the exception given by *too_long*,
3304 |     which is ``ValueError`` by default.
3305 | 
3306 |     >>> only([], default='missing')
3307 |     'missing'
3308 |     >>> only([1])
3309 |     1
3310 |     >>> only([1, 2])  # doctest: +IGNORE_EXCEPTION_DETAIL
3311 |     Traceback (most recent call last):
3312 |     ...
3313 |     ValueError: Expected exactly one item in iterable, but got 1, 2,
3314 |      and perhaps more.'
3315 |     >>> only([1, 2], too_long=TypeError)  # doctest: +IGNORE_EXCEPTION_DETAIL
3316 |     Traceback (most recent call last):
3317 |     ...
3318 |     TypeError
3319 | 
3320 |     Note that :func:`only` attempts to advance *iterable* twice to ensure there
3321 |     is only one item.  See :func:`spy` or :func:`peekable` to check
3322 |     iterable contents less destructively.
3323 |     """
3324 |     it = iter(iterable)
3325 |     first_value = next(it, default)
3326 | 
3327 |     try:
3328 |         second_value = next(it)
3329 |     except StopIteration:
3330 |         pass
3331 |     else:
3332 |         msg = (
3333 |             'Expected exactly one item in iterable, but got {!r}, {!r}, '
3334 |             'and perhaps more.'.format(first_value, second_value)
3335 |         )
3336 |         raise too_long or ValueError(msg)
3337 | 
3338 |     return first_value
3339 | 
3340 | 
3341 | def _ichunk(iterable, n):
3342 |     cache = deque()
3343 |     chunk = islice(iterable, n)
3344 | 
3345 |     def generator():
3346 |         while True:
3347 |             if cache:
3348 |                 yield cache.popleft()
3349 |             else:
3350 |                 try:
3351 |                     item = next(chunk)
3352 |                 except StopIteration:
3353 |                     return
3354 |                 else:
3355 |                     yield item
3356 | 
3357 |     def materialize_next(n=1):
3358 |         # if n not specified materialize everything
3359 |         if n is None:
3360 |             cache.extend(chunk)
3361 |             return len(cache)
3362 | 
3363 |         to_cache = n - len(cache)
3364 | 
3365 |         # materialize up to n
3366 |         if to_cache > 0:
3367 |             cache.extend(islice(chunk, to_cache))
3368 | 
3369 |         # return number materialized up to n
3370 |         return min(n, len(cache))
3371 | 
3372 |     return (generator(), materialize_next)
3373 | 
3374 | 
3375 | def ichunked(iterable, n):
3376 |     """Break *iterable* into sub-iterables with *n* elements each.
3377 |     :func:`ichunked` is like :func:`chunked`, but it yields iterables
3378 |     instead of lists.
3379 | 
3380 |     If the sub-iterables are read in order, the elements of *iterable*
3381 |     won't be stored in memory.
3382 |     If they are read out of order, :func:`itertools.tee` is used to cache
3383 |     elements as necessary.
3384 | 
3385 |     >>> from itertools import count
3386 |     >>> all_chunks = ichunked(count(), 4)
3387 |     >>> c_1, c_2, c_3 = next(all_chunks), next(all_chunks), next(all_chunks)
3388 |     >>> list(c_2)  # c_1's elements have been cached; c_3's haven't been
3389 |     [4, 5, 6, 7]
3390 |     >>> list(c_1)
3391 |     [0, 1, 2, 3]
3392 |     >>> list(c_3)
3393 |     [8, 9, 10, 11]
3394 | 
3395 |     """
3396 |     iterable = iter(iterable)
3397 |     while True:
3398 |         # Create new chunk
3399 |         chunk, materialize_next = _ichunk(iterable, n)
3400 | 
3401 |         # Check to see whether we're at the end of the source iterable
3402 |         if not materialize_next():
3403 |             return
3404 | 
3405 |         yield chunk
3406 | 
3407 |         # Fill previous chunk's cache
3408 |         materialize_next(None)
3409 | 
3410 | 
3411 | def iequals(*iterables):
3412 |     """Return ``True`` if all given *iterables* are equal to each other,
3413 |     which means that they contain the same elements in the same order.
3414 | 
3415 |     The function is useful for comparing iterables of different data types
3416 |     or iterables that do not support equality checks.
3417 | 
3418 |     >>> iequals("abc", ['a', 'b', 'c'], ('a', 'b', 'c'), iter("abc"))
3419 |     True
3420 | 
3421 |     >>> iequals("abc", "acb")
3422 |     False
3423 | 
3424 |     Not to be confused with :func:`all_equal`, which checks whether all
3425 |     elements of iterable are equal to each other.
3426 | 
3427 |     """
3428 |     return all(map(all_equal, zip_longest(*iterables, fillvalue=object())))
3429 | 
3430 | 
3431 | def distinct_combinations(iterable, r):
3432 |     """Yield the distinct combinations of *r* items taken from *iterable*.
3433 | 
3434 |         >>> list(distinct_combinations([0, 0, 1], 2))
3435 |         [(0, 0), (0, 1)]
3436 | 
3437 |     Equivalent to ``set(combinations(iterable))``, except duplicates are not
3438 |     generated and thrown away. For larger input sequences this is much more
3439 |     efficient.
3440 | 
3441 |     """
3442 |     if r < 0:
3443 |         raise ValueError('r must be non-negative')
3444 |     elif r == 0:
3445 |         yield ()
3446 |         return
3447 |     pool = tuple(iterable)
3448 |     generators = [unique_everseen(enumerate(pool), key=itemgetter(1))]
3449 |     current_combo = [None] * r
3450 |     level = 0
3451 |     while generators:
3452 |         try:
3453 |             cur_idx, p = next(generators[-1])
3454 |         except StopIteration:
3455 |             generators.pop()
3456 |             level -= 1
3457 |             continue
3458 |         current_combo[level] = p
3459 |         if level + 1 == r:
3460 |             yield tuple(current_combo)
3461 |         else:
3462 |             generators.append(
3463 |                 unique_everseen(
3464 |                     enumerate(pool[cur_idx + 1 :], cur_idx + 1),
3465 |                     key=itemgetter(1),
3466 |                 )
3467 |             )
3468 |             level += 1
3469 | 
3470 | 
3471 | def filter_except(validator, iterable, *exceptions):
3472 |     """Yield the items from *iterable* for which the *validator* function does
3473 |     not raise one of the specified *exceptions*.
3474 | 
3475 |     *validator* is called for each item in *iterable*.
3476 |     It should be a function that accepts one argument and raises an exception
3477 |     if that item is not valid.
3478 | 
3479 |     >>> iterable = ['1', '2', 'three', '4', None]
3480 |     >>> list(filter_except(int, iterable, ValueError, TypeError))
3481 |     ['1', '2', '4']
3482 | 
3483 |     If an exception other than one given by *exceptions* is raised by
3484 |     *validator*, it is raised like normal.
3485 |     """
3486 |     for item in iterable:
3487 |         try:
3488 |             validator(item)
3489 |         except exceptions:
3490 |             pass
3491 |         else:
3492 |             yield item
3493 | 
3494 | 
3495 | def map_except(function, iterable, *exceptions):
3496 |     """Transform each item from *iterable* with *function* and yield the
3497 |     result, unless *function* raises one of the specified *exceptions*.
3498 | 
3499 |     *function* is called to transform each item in *iterable*.
3500 |     It should accept one argument.
3501 | 
3502 |     >>> iterable = ['1', '2', 'three', '4', None]
3503 |     >>> list(map_except(int, iterable, ValueError, TypeError))
3504 |     [1, 2, 4]
3505 | 
3506 |     If an exception other than one given by *exceptions* is raised by
3507 |     *function*, it is raised like normal.
3508 |     """
3509 |     for item in iterable:
3510 |         try:
3511 |             yield function(item)
3512 |         except exceptions:
3513 |             pass
3514 | 
3515 | 
3516 | def map_if(iterable, pred, func, func_else=lambda x: x):
3517 |     """Evaluate each item from *iterable* using *pred*. If the result is
3518 |     equivalent to ``True``, transform the item with *func* and yield it.
3519 |     Otherwise, transform the item with *func_else* and yield it.
3520 | 
3521 |     *pred*, *func*, and *func_else* should each be functions that accept
3522 |     one argument. By default, *func_else* is the identity function.
3523 | 
3524 |     >>> from math import sqrt
3525 |     >>> iterable = list(range(-5, 5))
3526 |     >>> iterable
3527 |     [-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]
3528 |     >>> list(map_if(iterable, lambda x: x > 3, lambda x: 'toobig'))
3529 |     [-5, -4, -3, -2, -1, 0, 1, 2, 3, 'toobig']
3530 |     >>> list(map_if(iterable, lambda x: x >= 0,
3531 |     ... lambda x: f'{sqrt(x):.2f}', lambda x: None))
3532 |     [None, None, None, None, None, '0.00', '1.00', '1.41', '1.73', '2.00']
3533 |     """
3534 |     for item in iterable:
3535 |         yield func(item) if pred(item) else func_else(item)
3536 | 
3537 | 
3538 | def _sample_unweighted(iterable, k):
3539 |     # Implementation of "Algorithm L" from the 1994 paper by Kim-Hung Li:
3540 |     # "Reservoir-Sampling Algorithms of Time Complexity O(n(1+log(N/n)))".
3541 | 
3542 |     # Fill up the reservoir (collection of samples) with the first `k` samples
3543 |     reservoir = take(k, iterable)
3544 | 
3545 |     # Generate random number that's the largest in a sample of k U(0,1) numbers
3546 |     # Largest order statistic: https://en.wikipedia.org/wiki/Order_statistic
3547 |     W = exp(log(random()) / k)
3548 | 
3549 |     # The number of elements to skip before changing the reservoir is a random
3550 |     # number with a geometric distribution. Sample it using random() and logs.
3551 |     next_index = k + floor(log(random()) / log(1 - W))
3552 | 
3553 |     for index, element in enumerate(iterable, k):
3554 |         if index == next_index:
3555 |             reservoir[randrange(k)] = element
3556 |             # The new W is the largest in a sample of k U(0, `old_W`) numbers
3557 |             W *= exp(log(random()) / k)
3558 |             next_index += floor(log(random()) / log(1 - W)) + 1
3559 | 
3560 |     return reservoir
3561 | 
3562 | 
3563 | def _sample_weighted(iterable, k, weights):
3564 |     # Implementation of "A-ExpJ" from the 2006 paper by Efraimidis et al. :
3565 |     # "Weighted random sampling with a reservoir".
3566 | 
3567 |     # Log-transform for numerical stability for weights that are small/large
3568 |     weight_keys = (log(random()) / weight for weight in weights)
3569 | 
3570 |     # Fill up the reservoir (collection of samples) with the first `k`
3571 |     # weight-keys and elements, then heapify the list.
3572 |     reservoir = take(k, zip(weight_keys, iterable))
3573 |     heapify(reservoir)
3574 | 
3575 |     # The number of jumps before changing the reservoir is a random variable
3576 |     # with an exponential distribution. Sample it using random() and logs.
3577 |     smallest_weight_key, _ = reservoir[0]
3578 |     weights_to_skip = log(random()) / smallest_weight_key
3579 | 
3580 |     for weight, element in zip(weights, iterable):
3581 |         if weight >= weights_to_skip:
3582 |             # The notation here is consistent with the paper, but we store
3583 |             # the weight-keys in log-space for better numerical stability.
3584 |             smallest_weight_key, _ = reservoir[0]
3585 |             t_w = exp(weight * smallest_weight_key)
3586 |             r_2 = uniform(t_w, 1)  # generate U(t_w, 1)
3587 |             weight_key = log(r_2) / weight
3588 |             heapreplace(reservoir, (weight_key, element))
3589 |             smallest_weight_key, _ = reservoir[0]
3590 |             weights_to_skip = log(random()) / smallest_weight_key
3591 |         else:
3592 |             weights_to_skip -= weight
3593 | 
3594 |     # Equivalent to [element for weight_key, element in sorted(reservoir)]
3595 |     return [heappop(reservoir)[1] for _ in range(k)]
3596 | 
3597 | 
3598 | def sample(iterable, k, weights=None):
3599 |     """Return a *k*-length list of elements chosen (without replacement)
3600 |     from the *iterable*. Like :func:`random.sample`, but works on iterables
3601 |     of unknown length.
3602 | 
3603 |     >>> iterable = range(100)
3604 |     >>> sample(iterable, 5)  # doctest: +SKIP
3605 |     [81, 60, 96, 16, 4]
3606 | 
3607 |     An iterable with *weights* may also be given:
3608 | 
3609 |     >>> iterable = range(100)
3610 |     >>> weights = (i * i + 1 for i in range(100))
3611 |     >>> sampled = sample(iterable, 5, weights=weights)  # doctest: +SKIP
3612 |     [79, 67, 74, 66, 78]
3613 | 
3614 |     The algorithm can also be used to generate weighted random permutations.
3615 |     The relative weight of each item determines the probability that it
3616 |     appears late in the permutation.
3617 | 
3618 |     >>> data = "abcdefgh"
3619 |     >>> weights = range(1, len(data) + 1)
3620 |     >>> sample(data, k=len(data), weights=weights)  # doctest: +SKIP
3621 |     ['c', 'a', 'b', 'e', 'g', 'd', 'h', 'f']
3622 |     """
3623 |     if k == 0:
3624 |         return []
3625 | 
3626 |     iterable = iter(iterable)
3627 |     if weights is None:
3628 |         return _sample_unweighted(iterable, k)
3629 |     else:
3630 |         weights = iter(weights)
3631 |         return _sample_weighted(iterable, k, weights)
3632 | 
3633 | 
3634 | def is_sorted(iterable, key=None, reverse=False, strict=False):
3635 |     """Returns ``True`` if the items of iterable are in sorted order, and
3636 |     ``False`` otherwise. *key* and *reverse* have the same meaning that they do
3637 |     in the built-in :func:`sorted` function.
3638 | 
3639 |     >>> is_sorted(['1', '2', '3', '4', '5'], key=int)
3640 |     True
3641 |     >>> is_sorted([5, 4, 3, 1, 2], reverse=True)
3642 |     False
3643 | 
3644 |     If *strict*, tests for strict sorting, that is, returns ``False`` if equal
3645 |     elements are found:
3646 | 
3647 |     >>> is_sorted([1, 2, 2])
3648 |     True
3649 |     >>> is_sorted([1, 2, 2], strict=True)
3650 |     False
3651 | 
3652 |     The function returns ``False`` after encountering the first out-of-order
3653 |     item. If there are no out-of-order items, the iterable is exhausted.
3654 |     """
3655 | 
3656 |     compare = (le if reverse else ge) if strict else (lt if reverse else gt)
3657 |     it = iterable if key is None else map(key, iterable)
3658 |     return not any(starmap(compare, pairwise(it)))
3659 | 
3660 | 
3661 | class AbortThread(BaseException):
3662 |     pass
3663 | 
3664 | 
3665 | class callback_iter:
3666 |     """Convert a function that uses callbacks to an iterator.
3667 | 
3668 |     Let *func* be a function that takes a `callback` keyword argument.
3669 |     For example:
3670 | 
3671 |     >>> def func(callback=None):
3672 |     ...     for i, c in [(1, 'a'), (2, 'b'), (3, 'c')]:
3673 |     ...         if callback:
3674 |     ...             callback(i, c)
3675 |     ...     return 4
3676 | 
3677 | 
3678 |     Use ``with callback_iter(func)`` to get an iterator over the parameters
3679 |     that are delivered to the callback.
3680 | 
3681 |     >>> with callback_iter(func) as it:
3682 |     ...     for args, kwargs in it:
3683 |     ...         print(args)
3684 |     (1, 'a')
3685 |     (2, 'b')
3686 |     (3, 'c')
3687 | 
3688 |     The function will be called in a background thread. The ``done`` property
3689 |     indicates whether it has completed execution.
3690 | 
3691 |     >>> it.done
3692 |     True
3693 | 
3694 |     If it completes successfully, its return value will be available
3695 |     in the ``result`` property.
3696 | 
3697 |     >>> it.result
3698 |     4
3699 | 
3700 |     Notes:
3701 | 
3702 |     * If the function uses some keyword argument besides ``callback``, supply
3703 |       *callback_kwd*.
3704 |     * If it finished executing, but raised an exception, accessing the
3705 |       ``result`` property will raise the same exception.
3706 |     * If it hasn't finished executing, accessing the ``result``
3707 |       property from within the ``with`` block will raise ``RuntimeError``.
3708 |     * If it hasn't finished executing, accessing the ``result`` property from
3709 |       outside the ``with`` block will raise a
3710 |       ``more_itertools.AbortThread`` exception.
3711 |     * Provide *wait_seconds* to adjust how frequently the it is polled for
3712 |       output.
3713 | 
3714 |     """
3715 | 
3716 |     def __init__(self, func, callback_kwd='callback', wait_seconds=0.1):
3717 |         self._func = func
3718 |         self._callback_kwd = callback_kwd
3719 |         self._aborted = False
3720 |         self._future = None
3721 |         self._wait_seconds = wait_seconds
3722 |         # Lazily import concurrent.future
3723 |         self._executor = __import__(
3724 |             'concurrent.futures'
3725 |         ).futures.ThreadPoolExecutor(max_workers=1)
3726 |         self._iterator = self._reader()
3727 | 
3728 |     def __enter__(self):
3729 |         return self
3730 | 
3731 |     def __exit__(self, exc_type, exc_value, traceback):
3732 |         self._aborted = True
3733 |         self._executor.shutdown()
3734 | 
3735 |     def __iter__(self):
3736 |         return self
3737 | 
3738 |     def __next__(self):
3739 |         return next(self._iterator)
3740 | 
3741 |     @property
3742 |     def done(self):
3743 |         if self._future is None:
3744 |             return False
3745 |         return self._future.done()
3746 | 
3747 |     @property
3748 |     def result(self):
3749 |         if not self.done:
3750 |             raise RuntimeError('Function has not yet completed')
3751 | 
3752 |         return self._future.result()
3753 | 
3754 |     def _reader(self):
3755 |         q = Queue()
3756 | 
3757 |         def callback(*args, **kwargs):
3758 |             if self._aborted:
3759 |                 raise AbortThread('canceled by user')
3760 | 
3761 |             q.put((args, kwargs))
3762 | 
3763 |         self._future = self._executor.submit(
3764 |             self._func, **{self._callback_kwd: callback}
3765 |         )
3766 | 
3767 |         while True:
3768 |             try:
3769 |                 item = q.get(timeout=self._wait_seconds)
3770 |             except Empty:
3771 |                 pass
3772 |             else:
3773 |                 q.task_done()
3774 |                 yield item
3775 | 
3776 |             if self._future.done():
3777 |                 break
3778 | 
3779 |         remaining = []
3780 |         while True:
3781 |             try:
3782 |                 item = q.get_nowait()
3783 |             except Empty:
3784 |                 break
3785 |             else:
3786 |                 q.task_done()
3787 |                 remaining.append(item)
3788 |         q.join()
3789 |         yield from remaining
3790 | 
3791 | 
3792 | def windowed_complete(iterable, n):
3793 |     """
3794 |     Yield ``(beginning, middle, end)`` tuples, where:
3795 | 
3796 |     * Each ``middle`` has *n* items from *iterable*
3797 |     * Each ``beginning`` has the items before the ones in ``middle``
3798 |     * Each ``end`` has the items after the ones in ``middle``
3799 | 
3800 |     >>> iterable = range(7)
3801 |     >>> n = 3
3802 |     >>> for beginning, middle, end in windowed_complete(iterable, n):
3803 |     ...     print(beginning, middle, end)
3804 |     () (0, 1, 2) (3, 4, 5, 6)
3805 |     (0,) (1, 2, 3) (4, 5, 6)
3806 |     (0, 1) (2, 3, 4) (5, 6)
3807 |     (0, 1, 2) (3, 4, 5) (6,)
3808 |     (0, 1, 2, 3) (4, 5, 6) ()
3809 | 
3810 |     Note that *n* must be at least 0 and most equal to the length of
3811 |     *iterable*.
3812 | 
3813 |     This function will exhaust the iterable and may require significant
3814 |     storage.
3815 |     """
3816 |     if n < 0:
3817 |         raise ValueError('n must be >= 0')
3818 | 
3819 |     seq = tuple(iterable)
3820 |     size = len(seq)
3821 | 
3822 |     if n > size:
3823 |         raise ValueError('n must be <= len(seq)')
3824 | 
3825 |     for i in range(size - n + 1):
3826 |         beginning = seq[:i]
3827 |         middle = seq[i : i + n]
3828 |         end = seq[i + n :]
3829 |         yield beginning, middle, end
3830 | 
3831 | 
3832 | def all_unique(iterable, key=None):
3833 |     """
3834 |     Returns ``True`` if all the elements of *iterable* are unique (no two
3835 |     elements are equal).
3836 | 
3837 |         >>> all_unique('ABCB')
3838 |         False
3839 | 
3840 |     If a *key* function is specified, it will be used to make comparisons.
3841 | 
3842 |         >>> all_unique('ABCb')
3843 |         True
3844 |         >>> all_unique('ABCb', str.lower)
3845 |         False
3846 | 
3847 |     The function returns as soon as the first non-unique element is
3848 |     encountered. Iterables with a mix of hashable and unhashable items can
3849 |     be used, but the function will be slower for unhashable items.
3850 |     """
3851 |     seenset = set()
3852 |     seenset_add = seenset.add
3853 |     seenlist = []
3854 |     seenlist_add = seenlist.append
3855 |     for element in map(key, iterable) if key else iterable:
3856 |         try:
3857 |             if element in seenset:
3858 |                 return False
3859 |             seenset_add(element)
3860 |         except TypeError:
3861 |             if element in seenlist:
3862 |                 return False
3863 |             seenlist_add(element)
3864 |     return True
3865 | 
3866 | 
3867 | def nth_product(index, *args):
3868 |     """Equivalent to ``list(product(*args))[index]``.
3869 | 
3870 |     The products of *args* can be ordered lexicographically.
3871 |     :func:`nth_product` computes the product at sort position *index* without
3872 |     computing the previous products.
3873 | 
3874 |         >>> nth_product(8, range(2), range(2), range(2), range(2))
3875 |         (1, 0, 0, 0)
3876 | 
3877 |     ``IndexError`` will be raised if the given *index* is invalid.
3878 |     """
3879 |     pools = list(map(tuple, reversed(args)))
3880 |     ns = list(map(len, pools))
3881 | 
3882 |     c = reduce(mul, ns)
3883 | 
3884 |     if index < 0:
3885 |         index += c
3886 | 
3887 |     if not 0 <= index < c:
3888 |         raise IndexError
3889 | 
3890 |     result = []
3891 |     for pool, n in zip(pools, ns):
3892 |         result.append(pool[index % n])
3893 |         index //= n
3894 | 
3895 |     return tuple(reversed(result))
3896 | 
3897 | 
3898 | def nth_permutation(iterable, r, index):
3899 |     """Equivalent to ``list(permutations(iterable, r))[index]```
3900 | 
3901 |     The subsequences of *iterable* that are of length *r* where order is
3902 |     important can be ordered lexicographically. :func:`nth_permutation`
3903 |     computes the subsequence at sort position *index* directly, without
3904 |     computing the previous subsequences.
3905 | 
3906 |         >>> nth_permutation('ghijk', 2, 5)
3907 |         ('h', 'i')
3908 | 
3909 |     ``ValueError`` will be raised If *r* is negative or greater than the length
3910 |     of *iterable*.
3911 |     ``IndexError`` will be raised if the given *index* is invalid.
3912 |     """
3913 |     pool = list(iterable)
3914 |     n = len(pool)
3915 | 
3916 |     if r is None or r == n:
3917 |         r, c = n, factorial(n)
3918 |     elif not 0 <= r < n:
3919 |         raise ValueError
3920 |     else:
3921 |         c = perm(n, r)
3922 |     assert c > 0  # factortial(n)>0, and r<n so perm(n,r) is never zero
3923 | 
3924 |     if index < 0:
3925 |         index += c
3926 | 
3927 |     if not 0 <= index < c:
3928 |         raise IndexError
3929 | 
3930 |     result = [0] * r
3931 |     q = index * factorial(n) // c if r < n else index
3932 |     for d in range(1, n + 1):
3933 |         q, i = divmod(q, d)
3934 |         if 0 <= n - d < r:
3935 |             result[n - d] = i
3936 |         if q == 0:
3937 |             break
3938 | 
3939 |     return tuple(map(pool.pop, result))
3940 | 
3941 | 
3942 | def nth_combination_with_replacement(iterable, r, index):
3943 |     """Equivalent to
3944 |     ``list(combinations_with_replacement(iterable, r))[index]``.
3945 | 
3946 | 
3947 |     The subsequences with repetition of *iterable* that are of length *r* can
3948 |     be ordered lexicographically. :func:`nth_combination_with_replacement`
3949 |     computes the subsequence at sort position *index* directly, without
3950 |     computing the previous subsequences with replacement.
3951 | 
3952 |         >>> nth_combination_with_replacement(range(5), 3, 5)
3953 |         (0, 1, 1)
3954 | 
3955 |     ``ValueError`` will be raised If *r* is negative or greater than the length
3956 |     of *iterable*.
3957 |     ``IndexError`` will be raised if the given *index* is invalid.
3958 |     """
3959 |     pool = tuple(iterable)
3960 |     n = len(pool)
3961 |     if (r < 0) or (r > n):
3962 |         raise ValueError
3963 | 
3964 |     c = comb(n + r - 1, r)
3965 | 
3966 |     if index < 0:
3967 |         index += c
3968 | 
3969 |     if (index < 0) or (index >= c):
3970 |         raise IndexError
3971 | 
3972 |     result = []
3973 |     i = 0
3974 |     while r:
3975 |         r -= 1
3976 |         while n >= 0:
3977 |             num_combs = comb(n + r - 1, r)
3978 |             if index < num_combs:
3979 |                 break
3980 |             n -= 1
3981 |             i += 1
3982 |             index -= num_combs
3983 |         result.append(pool[i])
3984 | 
3985 |     return tuple(result)
3986 | 
3987 | 
3988 | def value_chain(*args):
3989 |     """Yield all arguments passed to the function in the same order in which
3990 |     they were passed. If an argument itself is iterable then iterate over its
3991 |     values.
3992 | 
3993 |         >>> list(value_chain(1, 2, 3, [4, 5, 6]))
3994 |         [1, 2, 3, 4, 5, 6]
3995 | 
3996 |     Binary and text strings are not considered iterable and are emitted
3997 |     as-is:
3998 | 
3999 |         >>> list(value_chain('12', '34', ['56', '78']))
4000 |         ['12', '34', '56', '78']
4001 | 
4002 |     Pre- or postpend a single element to an iterable:
4003 | 
4004 |         >>> list(value_chain(1, [2, 3, 4, 5, 6]))
4005 |         [1, 2, 3, 4, 5, 6]
4006 |         >>> list(value_chain([1, 2, 3, 4, 5], 6))
4007 |         [1, 2, 3, 4, 5, 6]
4008 | 
4009 |     Multiple levels of nesting are not flattened.
4010 | 
4011 |     """
4012 |     for value in args:
4013 |         if isinstance(value, (str, bytes)):
4014 |             yield value
4015 |             continue
4016 |         try:
4017 |             yield from value
4018 |         except TypeError:
4019 |             yield value
4020 | 
4021 | 
4022 | def product_index(element, *args):
4023 |     """Equivalent to ``list(product(*args)).index(element)``
4024 | 
4025 |     The products of *args* can be ordered lexicographically.
4026 |     :func:`product_index` computes the first index of *element* without
4027 |     computing the previous products.
4028 | 
4029 |         >>> product_index([8, 2], range(10), range(5))
4030 |         42
4031 | 
4032 |     ``ValueError`` will be raised if the given *element* isn't in the product
4033 |     of *args*.
4034 |     """
4035 |     index = 0
4036 | 
4037 |     for x, pool in zip_longest(element, args, fillvalue=_marker):
4038 |         if x is _marker or pool is _marker:
4039 |             raise ValueError('element is not a product of args')
4040 | 
4041 |         pool = tuple(pool)
4042 |         index = index * len(pool) + pool.index(x)
4043 | 
4044 |     return index
4045 | 
4046 | 
4047 | def combination_index(element, iterable):
4048 |     """Equivalent to ``list(combinations(iterable, r)).index(element)``
4049 | 
4050 |     The subsequences of *iterable* that are of length *r* can be ordered
4051 |     lexicographically. :func:`combination_index` computes the index of the
4052 |     first *element*, without computing the previous combinations.
4053 | 
4054 |         >>> combination_index('adf', 'abcdefg')
4055 |         10
4056 | 
4057 |     ``ValueError`` will be raised if the given *element* isn't one of the
4058 |     combinations of *iterable*.
4059 |     """
4060 |     element = enumerate(element)
4061 |     k, y = next(element, (None, None))
4062 |     if k is None:
4063 |         return 0
4064 | 
4065 |     indexes = []
4066 |     pool = enumerate(iterable)
4067 |     for n, x in pool:
4068 |         if x == y:
4069 |             indexes.append(n)
4070 |             tmp, y = next(element, (None, None))
4071 |             if tmp is None:
4072 |                 break
4073 |             else:
4074 |                 k = tmp
4075 |     else:
4076 |         raise ValueError('element is not a combination of iterable')
4077 | 
4078 |     n, _ = last(pool, default=(n, None))
4079 | 
4080 |     # Python versions below 3.8 don't have math.comb
4081 |     index = 1
4082 |     for i, j in enumerate(reversed(indexes), start=1):
4083 |         j = n - j
4084 |         if i <= j:
4085 |             index += comb(j, i)
4086 | 
4087 |     return comb(n + 1, k + 1) - index
4088 | 
4089 | 
4090 | def combination_with_replacement_index(element, iterable):
4091 |     """Equivalent to
4092 |     ``list(combinations_with_replacement(iterable, r)).index(element)``
4093 | 
4094 |     The subsequences with repetition of *iterable* that are of length *r* can
4095 |     be ordered lexicographically. :func:`combination_with_replacement_index`
4096 |     computes the index of the first *element*, without computing the previous
4097 |     combinations with replacement.
4098 | 
4099 |         >>> combination_with_replacement_index('adf', 'abcdefg')
4100 |         20
4101 | 
4102 |     ``ValueError`` will be raised if the given *element* isn't one of the
4103 |     combinations with replacement of *iterable*.
4104 |     """
4105 |     element = tuple(element)
4106 |     l = len(element)
4107 |     element = enumerate(element)
4108 | 
4109 |     k, y = next(element, (None, None))
4110 |     if k is None:
4111 |         return 0
4112 | 
4113 |     indexes = []
4114 |     pool = tuple(iterable)
4115 |     for n, x in enumerate(pool):
4116 |         while x == y:
4117 |             indexes.append(n)
4118 |             tmp, y = next(element, (None, None))
4119 |             if tmp is None:
4120 |                 break
4121 |             else:
4122 |                 k = tmp
4123 |         if y is None:
4124 |             break
4125 |     else:
4126 |         raise ValueError(
4127 |             'element is not a combination with replacement of iterable'
4128 |         )
4129 | 
4130 |     n = len(pool)
4131 |     occupations = [0] * n
4132 |     for p in indexes:
4133 |         occupations[p] += 1
4134 | 
4135 |     index = 0
4136 |     cumulative_sum = 0
4137 |     for k in range(1, n):
4138 |         cumulative_sum += occupations[k - 1]
4139 |         j = l + n - 1 - k - cumulative_sum
4140 |         i = n - k
4141 |         if i <= j:
4142 |             index += comb(j, i)
4143 | 
4144 |     return index
4145 | 
4146 | 
4147 | def permutation_index(element, iterable):
4148 |     """Equivalent to ``list(permutations(iterable, r)).index(element)```
4149 | 
4150 |     The subsequences of *iterable* that are of length *r* where order is
4151 |     important can be ordered lexicographically. :func:`permutation_index`
4152 |     computes the index of the first *element* directly, without computing
4153 |     the previous permutations.
4154 | 
4155 |         >>> permutation_index([1, 3, 2], range(5))
4156 |         19
4157 | 
4158 |     ``ValueError`` will be raised if the given *element* isn't one of the
4159 |     permutations of *iterable*.
4160 |     """
4161 |     index = 0
4162 |     pool = list(iterable)
4163 |     for i, x in zip(range(len(pool), -1, -1), element):
4164 |         r = pool.index(x)
4165 |         index = index * i + r
4166 |         del pool[r]
4167 | 
4168 |     return index
4169 | 
4170 | 
4171 | class countable:
4172 |     """Wrap *iterable* and keep a count of how many items have been consumed.
4173 | 
4174 |     The ``items_seen`` attribute starts at ``0`` and increments as the iterable
4175 |     is consumed:
4176 | 
4177 |         >>> iterable = map(str, range(10))
4178 |         >>> it = countable(iterable)
4179 |         >>> it.items_seen
4180 |         0
4181 |         >>> next(it), next(it)
4182 |         ('0', '1')
4183 |         >>> list(it)
4184 |         ['2', '3', '4', '5', '6', '7', '8', '9']
4185 |         >>> it.items_seen
4186 |         10
4187 |     """
4188 | 
4189 |     def __init__(self, iterable):
4190 |         self._it = iter(iterable)
4191 |         self.items_seen = 0
4192 | 
4193 |     def __iter__(self):
4194 |         return self
4195 | 
4196 |     def __next__(self):
4197 |         item = next(self._it)
4198 |         self.items_seen += 1
4199 | 
4200 |         return item
4201 | 
4202 | 
4203 | def chunked_even(iterable, n):
4204 |     """Break *iterable* into lists of approximately length *n*.
4205 |     Items are distributed such the lengths of the lists differ by at most
4206 |     1 item.
4207 | 
4208 |     >>> iterable = [1, 2, 3, 4, 5, 6, 7]
4209 |     >>> n = 3
4210 |     >>> list(chunked_even(iterable, n))  # List lengths: 3, 2, 2
4211 |     [[1, 2, 3], [4, 5], [6, 7]]
4212 |     >>> list(chunked(iterable, n))  # List lengths: 3, 3, 1
4213 |     [[1, 2, 3], [4, 5, 6], [7]]
4214 | 
4215 |     """
4216 |     iterable = iter(iterable)
4217 | 
4218 |     # Initialize a buffer to process the chunks while keeping
4219 |     # some back to fill any underfilled chunks
4220 |     min_buffer = (n - 1) * (n - 2)
4221 |     buffer = list(islice(iterable, min_buffer))
4222 | 
4223 |     # Append items until we have a completed chunk
4224 |     for _ in islice(map(buffer.append, iterable), n, None, n):
4225 |         yield buffer[:n]
4226 |         del buffer[:n]
4227 | 
4228 |     # Check if any chunks need addition processing
4229 |     if not buffer:
4230 |         return
4231 |     length = len(buffer)
4232 | 
4233 |     # Chunks are either size `full_size <= n` or `partial_size = full_size - 1`
4234 |     q, r = divmod(length, n)
4235 |     num_lists = q + (1 if r > 0 else 0)
4236 |     q, r = divmod(length, num_lists)
4237 |     full_size = q + (1 if r > 0 else 0)
4238 |     partial_size = full_size - 1
4239 |     num_full = length - partial_size * num_lists
4240 | 
4241 |     # Yield chunks of full size
4242 |     partial_start_idx = num_full * full_size
4243 |     if full_size > 0:
4244 |         for i in range(0, partial_start_idx, full_size):
4245 |             yield buffer[i : i + full_size]
4246 | 
4247 |     # Yield chunks of partial size
4248 |     if partial_size > 0:
4249 |         for i in range(partial_start_idx, length, partial_size):
4250 |             yield buffer[i : i + partial_size]
4251 | 
4252 | 
4253 | def zip_broadcast(*objects, scalar_types=(str, bytes), strict=False):
4254 |     """A version of :func:`zip` that "broadcasts" any scalar
4255 |     (i.e., non-iterable) items into output tuples.
4256 | 
4257 |     >>> iterable_1 = [1, 2, 3]
4258 |     >>> iterable_2 = ['a', 'b', 'c']
4259 |     >>> scalar = '_'
4260 |     >>> list(zip_broadcast(iterable_1, iterable_2, scalar))
4261 |     [(1, 'a', '_'), (2, 'b', '_'), (3, 'c', '_')]
4262 | 
4263 |     The *scalar_types* keyword argument determines what types are considered
4264 |     scalar. It is set to ``(str, bytes)`` by default. Set it to ``None`` to
4265 |     treat strings and byte strings as iterable:
4266 | 
4267 |     >>> list(zip_broadcast('abc', 0, 'xyz', scalar_types=None))
4268 |     [('a', 0, 'x'), ('b', 0, 'y'), ('c', 0, 'z')]
4269 | 
4270 |     If the *strict* keyword argument is ``True``, then
4271 |     ``UnequalIterablesError`` will be raised if any of the iterables have
4272 |     different lengths.
4273 |     """
4274 | 
4275 |     def is_scalar(obj):
4276 |         if scalar_types and isinstance(obj, scalar_types):
4277 |             return True
4278 |         try:
4279 |             iter(obj)
4280 |         except TypeError:
4281 |             return True
4282 |         else:
4283 |             return False
4284 | 
4285 |     size = len(objects)
4286 |     if not size:
4287 |         return
4288 | 
4289 |     new_item = [None] * size
4290 |     iterables, iterable_positions = [], []
4291 |     for i, obj in enumerate(objects):
4292 |         if is_scalar(obj):
4293 |             new_item[i] = obj
4294 |         else:
4295 |             iterables.append(iter(obj))
4296 |             iterable_positions.append(i)
4297 | 
4298 |     if not iterables:
4299 |         yield tuple(objects)
4300 |         return
4301 | 
4302 |     zipper = _zip_equal if strict else zip
4303 |     for item in zipper(*iterables):
4304 |         for i, new_item[i] in zip(iterable_positions, item):
4305 |             pass
4306 |         yield tuple(new_item)
4307 | 
4308 | 
4309 | def unique_in_window(iterable, n, key=None):
4310 |     """Yield the items from *iterable* that haven't been seen recently.
4311 |     *n* is the size of the lookback window.
4312 | 
4313 |         >>> iterable = [0, 1, 0, 2, 3, 0]
4314 |         >>> n = 3
4315 |         >>> list(unique_in_window(iterable, n))
4316 |         [0, 1, 2, 3, 0]
4317 | 
4318 |     The *key* function, if provided, will be used to determine uniqueness:
4319 | 
4320 |         >>> list(unique_in_window('abAcda', 3, key=lambda x: x.lower()))
4321 |         ['a', 'b', 'c', 'd', 'a']
4322 | 
4323 |     The items in *iterable* must be hashable.
4324 | 
4325 |     """
4326 |     if n <= 0:
4327 |         raise ValueError('n must be greater than 0')
4328 | 
4329 |     window = deque(maxlen=n)
4330 |     counts = defaultdict(int)
4331 |     use_key = key is not None
4332 | 
4333 |     for item in iterable:
4334 |         if len(window) == n:
4335 |             to_discard = window[0]
4336 |             if counts[to_discard] == 1:
4337 |                 del counts[to_discard]
4338 |             else:
4339 |                 counts[to_discard] -= 1
4340 | 
4341 |         k = key(item) if use_key else item
4342 |         if k not in counts:
4343 |             yield item
4344 |         counts[k] += 1
4345 |         window.append(k)
4346 | 
4347 | 
4348 | def duplicates_everseen(iterable, key=None):
4349 |     """Yield duplicate elements after their first appearance.
4350 | 
4351 |     >>> list(duplicates_everseen('mississippi'))
4352 |     ['s', 'i', 's', 's', 'i', 'p', 'i']
4353 |     >>> list(duplicates_everseen('AaaBbbCccAaa', str.lower))
4354 |     ['a', 'a', 'b', 'b', 'c', 'c', 'A', 'a', 'a']
4355 | 
4356 |     This function is analogous to :func:`unique_everseen` and is subject to
4357 |     the same performance considerations.
4358 | 
4359 |     """
4360 |     seen_set = set()
4361 |     seen_list = []
4362 |     use_key = key is not None
4363 | 
4364 |     for element in iterable:
4365 |         k = key(element) if use_key else element
4366 |         try:
4367 |             if k not in seen_set:
4368 |                 seen_set.add(k)
4369 |             else:
4370 |                 yield element
4371 |         except TypeError:
4372 |             if k not in seen_list:
4373 |                 seen_list.append(k)
4374 |             else:
4375 |                 yield element
4376 | 
4377 | 
4378 | def duplicates_justseen(iterable, key=None):
4379 |     """Yields serially-duplicate elements after their first appearance.
4380 | 
4381 |     >>> list(duplicates_justseen('mississippi'))
4382 |     ['s', 's', 'p']
4383 |     >>> list(duplicates_justseen('AaaBbbCccAaa', str.lower))
4384 |     ['a', 'a', 'b', 'b', 'c', 'c', 'a', 'a']
4385 | 
4386 |     This function is analogous to :func:`unique_justseen`.
4387 | 
4388 |     """
4389 |     return flatten(g for _, g in groupby(iterable, key) for _ in g)
4390 | 
4391 | 
4392 | def classify_unique(iterable, key=None):
4393 |     """Classify each element in terms of its uniqueness.
4394 | 
4395 |     For each element in the input iterable, return a 3-tuple consisting of:
4396 | 
4397 |     1. The element itself
4398 |     2. ``False`` if the element is equal to the one preceding it in the input,
4399 |        ``True`` otherwise (i.e. the equivalent of :func:`unique_justseen`)
4400 |     3. ``False`` if this element has been seen anywhere in the input before,
4401 |        ``True`` otherwise (i.e. the equivalent of :func:`unique_everseen`)
4402 | 
4403 |     >>> list(classify_unique('otto'))    # doctest: +NORMALIZE_WHITESPACE
4404 |     [('o', True,  True),
4405 |      ('t', True,  True),
4406 |      ('t', False, False),
4407 |      ('o', True,  False)]
4408 | 
4409 |     This function is analogous to :func:`unique_everseen` and is subject to
4410 |     the same performance considerations.
4411 | 
4412 |     """
4413 |     seen_set = set()
4414 |     seen_list = []
4415 |     use_key = key is not None
4416 |     previous = None
4417 | 
4418 |     for i, element in enumerate(iterable):
4419 |         k = key(element) if use_key else element
4420 |         is_unique_justseen = not i or previous != k
4421 |         previous = k
4422 |         is_unique_everseen = False
4423 |         try:
4424 |             if k not in seen_set:
4425 |                 seen_set.add(k)
4426 |                 is_unique_everseen = True
4427 |         except TypeError:
4428 |             if k not in seen_list:
4429 |                 seen_list.append(k)
4430 |                 is_unique_everseen = True
4431 |         yield element, is_unique_justseen, is_unique_everseen
4432 | 
4433 | 
4434 | def minmax(iterable_or_value, *others, key=None, default=_marker):
4435 |     """Returns both the smallest and largest items in an iterable
4436 |     or the largest of two or more arguments.
4437 | 
4438 |         >>> minmax([3, 1, 5])
4439 |         (1, 5)
4440 | 
4441 |         >>> minmax(4, 2, 6)
4442 |         (2, 6)
4443 | 
4444 |     If a *key* function is provided, it will be used to transform the input
4445 |     items for comparison.
4446 | 
4447 |         >>> minmax([5, 30], key=str)  # '30' sorts before '5'
4448 |         (30, 5)
4449 | 
4450 |     If a *default* value is provided, it will be returned if there are no
4451 |     input items.
4452 | 
4453 |         >>> minmax([], default=(0, 0))
4454 |         (0, 0)
4455 | 
4456 |     Otherwise ``ValueError`` is raised.
4457 | 
4458 |     This function is based on the
4459 |     `recipe <http://code.activestate.com/recipes/577916/>`__ by
4460 |     Raymond Hettinger and takes care to minimize the number of comparisons
4461 |     performed.
4462 |     """
4463 |     iterable = (iterable_or_value, *others) if others else iterable_or_value
4464 | 
4465 |     it = iter(iterable)
4466 | 
4467 |     try:
4468 |         lo = hi = next(it)
4469 |     except StopIteration as exc:
4470 |         if default is _marker:
4471 |             raise ValueError(
4472 |                 '`minmax()` argument is an empty iterable. '
4473 |                 'Provide a `default` value to suppress this error.'
4474 |             ) from exc
4475 |         return default
4476 | 
4477 |     # Different branches depending on the presence of key. This saves a lot
4478 |     # of unimportant copies which would slow the "key=None" branch
4479 |     # significantly down.
4480 |     if key is None:
4481 |         for x, y in zip_longest(it, it, fillvalue=lo):
4482 |             if y < x:
4483 |                 x, y = y, x
4484 |             if x < lo:
4485 |                 lo = x
4486 |             if hi < y:
4487 |                 hi = y
4488 | 
4489 |     else:
4490 |         lo_key = hi_key = key(lo)
4491 | 
4492 |         for x, y in zip_longest(it, it, fillvalue=lo):
4493 |             x_key, y_key = key(x), key(y)
4494 | 
4495 |             if y_key < x_key:
4496 |                 x, y, x_key, y_key = y, x, y_key, x_key
4497 |             if x_key < lo_key:
4498 |                 lo, lo_key = x, x_key
4499 |             if hi_key < y_key:
4500 |                 hi, hi_key = y, y_key
4501 | 
4502 |     return lo, hi
4503 | 
4504 | 
4505 | def constrained_batches(
4506 |     iterable, max_size, max_count=None, get_len=len, strict=True
4507 | ):
4508 |     """Yield batches of items from *iterable* with a combined size limited by
4509 |     *max_size*.
4510 | 
4511 |     >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
4512 |     >>> list(constrained_batches(iterable, 10))
4513 |     [(b'12345', b'123'), (b'12345678', b'1', b'1'), (b'12', b'1')]
4514 | 
4515 |     If a *max_count* is supplied, the number of items per batch is also
4516 |     limited:
4517 | 
4518 |     >>> iterable = [b'12345', b'123', b'12345678', b'1', b'1', b'12', b'1']
4519 |     >>> list(constrained_batches(iterable, 10, max_count = 2))
4520 |     [(b'12345', b'123'), (b'12345678', b'1'), (b'1', b'12'), (b'1',)]
4521 | 
4522 |     If a *get_len* function is supplied, use that instead of :func:`len` to
4523 |     determine item size.
4524 | 
4525 |     If *strict* is ``True``, raise ``ValueError`` if any single item is bigger
4526 |     than *max_size*. Otherwise, allow single items to exceed *max_size*.
4527 |     """
4528 |     if max_size <= 0:
4529 |         raise ValueError('maximum size must be greater than zero')
4530 | 
4531 |     batch = []
4532 |     batch_size = 0
4533 |     batch_count = 0
4534 |     for item in iterable:
4535 |         item_len = get_len(item)
4536 |         if strict and item_len > max_size:
4537 |             raise ValueError('item size exceeds maximum size')
4538 | 
4539 |         reached_count = batch_count == max_count
4540 |         reached_size = item_len + batch_size > max_size
4541 |         if batch_count and (reached_size or reached_count):
4542 |             yield tuple(batch)
4543 |             batch.clear()
4544 |             batch_size = 0
4545 |             batch_count = 0
4546 | 
4547 |         batch.append(item)
4548 |         batch_size += item_len
4549 |         batch_count += 1
4550 | 
4551 |     if batch:
4552 |         yield tuple(batch)
4553 | 
4554 | 
4555 | def gray_product(*iterables):
4556 |     """Like :func:`itertools.product`, but return tuples in an order such
4557 |     that only one element in the generated tuple changes from one iteration
4558 |     to the next.
4559 | 
4560 |         >>> list(gray_product('AB','CD'))
4561 |         [('A', 'C'), ('B', 'C'), ('B', 'D'), ('A', 'D')]
4562 | 
4563 |     This function consumes all of the input iterables before producing output.
4564 |     If any of the input iterables have fewer than two items, ``ValueError``
4565 |     is raised.
4566 | 
4567 |     For information on the algorithm, see
4568 |     `this section <https://www-cs-faculty.stanford.edu/~knuth/fasc2a.ps.gz>`__
4569 |     of Donald Knuth's *The Art of Computer Programming*.
4570 |     """
4571 |     all_iterables = tuple(tuple(x) for x in iterables)
4572 |     iterable_count = len(all_iterables)
4573 |     for iterable in all_iterables:
4574 |         if len(iterable) < 2:
4575 |             raise ValueError("each iterable must have two or more items")
4576 | 
4577 |     # This is based on "Algorithm H" from section 7.2.1.1, page 20.
4578 |     # a holds the indexes of the source iterables for the n-tuple to be yielded
4579 |     # f is the array of "focus pointers"
4580 |     # o is the array of "directions"
4581 |     a = [0] * iterable_count
4582 |     f = list(range(iterable_count + 1))
4583 |     o = [1] * iterable_count
4584 |     while True:
4585 |         yield tuple(all_iterables[i][a[i]] for i in range(iterable_count))
4586 |         j = f[0]
4587 |         f[0] = 0
4588 |         if j == iterable_count:
4589 |             break
4590 |         a[j] = a[j] + o[j]
4591 |         if a[j] == 0 or a[j] == len(all_iterables[j]) - 1:
4592 |             o[j] = -o[j]
4593 |             f[j] = f[j + 1]
4594 |             f[j + 1] = j + 1
4595 | 
4596 | 
4597 | def partial_product(*iterables):
4598 |     """Yields tuples containing one item from each iterator, with subsequent
4599 |     tuples changing a single item at a time by advancing each iterator until it
4600 |     is exhausted. This sequence guarantees every value in each iterable is
4601 |     output at least once without generating all possible combinations.
4602 | 
4603 |     This may be useful, for example, when testing an expensive function.
4604 | 
4605 |         >>> list(partial_product('AB', 'C', 'DEF'))
4606 |         [('A', 'C', 'D'), ('B', 'C', 'D'), ('B', 'C', 'E'), ('B', 'C', 'F')]
4607 |     """
4608 | 
4609 |     iterators = list(map(iter, iterables))
4610 | 
4611 |     try:
4612 |         prod = [next(it) for it in iterators]
4613 |     except StopIteration:
4614 |         return
4615 |     yield tuple(prod)
4616 | 
4617 |     for i, it in enumerate(iterators):
4618 |         for prod[i] in it:
4619 |             yield tuple(prod)
4620 | 
4621 | 
4622 | def takewhile_inclusive(predicate, iterable):
4623 |     """A variant of :func:`takewhile` that yields one additional element.
4624 | 
4625 |         >>> list(takewhile_inclusive(lambda x: x < 5, [1, 4, 6, 4, 1]))
4626 |         [1, 4, 6]
4627 | 
4628 |     :func:`takewhile` would return ``[1, 4]``.
4629 |     """
4630 |     for x in iterable:
4631 |         yield x
4632 |         if not predicate(x):
4633 |             break
4634 | 
4635 | 
4636 | def outer_product(func, xs, ys, *args, **kwargs):
4637 |     """A generalized outer product that applies a binary function to all
4638 |     pairs of items. Returns a 2D matrix with ``len(xs)`` rows and ``len(ys)``
4639 |     columns.
4640 |     Also accepts ``*args`` and ``**kwargs`` that are passed to ``func``.
4641 | 
4642 |     Multiplication table:
4643 | 
4644 |     >>> list(outer_product(mul, range(1, 4), range(1, 6)))
4645 |     [(1, 2, 3, 4, 5), (2, 4, 6, 8, 10), (3, 6, 9, 12, 15)]
4646 | 
4647 |     Cross tabulation:
4648 | 
4649 |     >>> xs = ['A', 'B', 'A', 'A', 'B', 'B', 'A', 'A', 'B', 'B']
4650 |     >>> ys = ['X', 'X', 'X', 'Y', 'Z', 'Z', 'Y', 'Y', 'Z', 'Z']
4651 |     >>> rows = list(zip(xs, ys))
4652 |     >>> count_rows = lambda x, y: rows.count((x, y))
4653 |     >>> list(outer_product(count_rows, sorted(set(xs)), sorted(set(ys))))
4654 |     [(2, 3, 0), (1, 0, 4)]
4655 | 
4656 |     Usage with ``*args`` and ``**kwargs``:
4657 | 
4658 |     >>> animals = ['cat', 'wolf', 'mouse']
4659 |     >>> list(outer_product(min, animals, animals, key=len))
4660 |     [('cat', 'cat', 'cat'), ('cat', 'wolf', 'wolf'), ('cat', 'wolf', 'mouse')]
4661 |     """
4662 |     ys = tuple(ys)
4663 |     return batched(
4664 |         starmap(lambda x, y: func(x, y, *args, **kwargs), product(xs, ys)),
4665 |         n=len(ys),
4666 |     )
4667 | 
4668 | 
4669 | def iter_suppress(iterable, *exceptions):
4670 |     """Yield each of the items from *iterable*. If the iteration raises one of
4671 |     the specified *exceptions*, that exception will be suppressed and iteration
4672 |     will stop.
4673 | 
4674 |     >>> from itertools import chain
4675 |     >>> def breaks_at_five(x):
4676 |     ...     while True:
4677 |     ...         if x >= 5:
4678 |     ...             raise RuntimeError
4679 |     ...         yield x
4680 |     ...         x += 1
4681 |     >>> it_1 = iter_suppress(breaks_at_five(1), RuntimeError)
4682 |     >>> it_2 = iter_suppress(breaks_at_five(2), RuntimeError)
4683 |     >>> list(chain(it_1, it_2))
4684 |     [1, 2, 3, 4, 2, 3, 4]
4685 |     """
4686 |     try:
4687 |         yield from iterable
4688 |     except exceptions:
4689 |         return
4690 | 
4691 | 
4692 | def filter_map(func, iterable):
4693 |     """Apply *func* to every element of *iterable*, yielding only those which
4694 |     are not ``None``.
4695 | 
4696 |     >>> elems = ['1', 'a', '2', 'b', '3']
4697 |     >>> list(filter_map(lambda s: int(s) if s.isnumeric() else None, elems))
4698 |     [1, 2, 3]
4699 |     """
4700 |     for x in iterable:
4701 |         y = func(x)
4702 |         if y is not None:
4703 |             yield y
4704 | 
4705 | 
4706 | def powerset_of_sets(iterable):
4707 |     """Yields all possible subsets of the iterable.
4708 | 
4709 |         >>> list(powerset_of_sets([1, 2, 3]))  # doctest: +SKIP
4710 |         [set(), {1}, {2}, {3}, {1, 2}, {1, 3}, {2, 3}, {1, 2, 3}]
4711 |         >>> list(powerset_of_sets([1, 1, 0]))  # doctest: +SKIP
4712 |         [set(), {1}, {0}, {0, 1}]
4713 | 
4714 |     :func:`powerset_of_sets` takes care to minimize the number
4715 |     of hash operations performed.
4716 |     """
4717 |     sets = tuple(map(set, dict.fromkeys(map(frozenset, zip(iterable)))))
4718 |     for r in range(len(sets) + 1):
4719 |         yield from starmap(set().union, combinations(sets, r))
4720 | 
4721 | 
4722 | def join_mappings(**field_to_map):
4723 |     """
4724 |     Joins multiple mappings together using their common keys.
4725 | 
4726 |     >>> user_scores = {'elliot': 50, 'claris': 60}
4727 |     >>> user_times = {'elliot': 30, 'claris': 40}
4728 |     >>> join_mappings(score=user_scores, time=user_times)
4729 |     {'elliot': {'score': 50, 'time': 30}, 'claris': {'score': 60, 'time': 40}}
4730 |     """
4731 |     ret = defaultdict(dict)
4732 | 
4733 |     for field_name, mapping in field_to_map.items():
4734 |         for key, value in mapping.items():
4735 |             ret[key][field_name] = value
4736 | 
4737 |     return dict(ret)
4738 | 
4739 | 
4740 | def _complex_sumprod(v1, v2):
4741 |     """High precision sumprod() for complex numbers.
4742 |     Used by :func:`dft` and :func:`idft`.
4743 |     """
4744 | 
4745 |     r1 = chain((p.real for p in v1), (-p.imag for p in v1))
4746 |     r2 = chain((q.real for q in v2), (q.imag for q in v2))
4747 |     i1 = chain((p.real for p in v1), (p.imag for p in v1))
4748 |     i2 = chain((q.imag for q in v2), (q.real for q in v2))
4749 |     return complex(_fsumprod(r1, r2), _fsumprod(i1, i2))
4750 | 
4751 | 
4752 | def dft(xarr):
4753 |     """Discrete Fourier Tranform. *xarr* is a sequence of complex numbers.
4754 |     Yields the components of the corresponding transformed output vector.
4755 | 
4756 |     >>> import cmath
4757 |     >>> xarr = [1, 2-1j, -1j, -1+2j]
4758 |     >>> Xarr = [2, -2-2j, -2j, 4+4j]
4759 |     >>> all(map(cmath.isclose, dft(xarr), Xarr))
4760 |     True
4761 | 
4762 |     See :func:`idft` for the inverse Discrete Fourier Transform.
4763 |     """
4764 |     N = len(xarr)
4765 |     roots_of_unity = [e ** (n / N * tau * -1j) for n in range(N)]
4766 |     for k in range(N):
4767 |         coeffs = [roots_of_unity[k * n % N] for n in range(N)]
4768 |         yield _complex_sumprod(xarr, coeffs)
4769 | 
4770 | 
4771 | def idft(Xarr):
4772 |     """Inverse Discrete Fourier Tranform. *Xarr* is a sequence of
4773 |     complex numbers. Yields the components of the corresponding
4774 |     inverse-transformed output vector.
4775 | 
4776 |     >>> import cmath
4777 |     >>> xarr = [1, 2-1j, -1j, -1+2j]
4778 |     >>> Xarr = [2, -2-2j, -2j, 4+4j]
4779 |     >>> all(map(cmath.isclose, idft(Xarr), xarr))
4780 |     True
4781 | 
4782 |     See :func:`dft` for the Discrete Fourier Transform.
4783 |     """
4784 |     N = len(Xarr)
4785 |     roots_of_unity = [e ** (n / N * tau * 1j) for n in range(N)]
4786 |     for k in range(N):
4787 |         coeffs = [roots_of_unity[k * n % N] for n in range(N)]
4788 |         yield _complex_sumprod(Xarr, coeffs) / N
4789 | 
4790 | 
4791 | def doublestarmap(func, iterable):
4792 |     """Apply *func* to every item of *iterable* by dictionary unpacking
4793 |     the item into *func*.
4794 | 
4795 |     The difference between :func:`itertools.starmap` and :func:`doublestarmap`
4796 |     parallels the distinction between ``func(*a)`` and ``func(**a)``.
4797 | 
4798 |     >>> iterable = [{'a': 1, 'b': 2}, {'a': 40, 'b': 60}]
4799 |     >>> list(doublestarmap(lambda a, b: a + b, iterable))
4800 |     [3, 100]
4801 | 
4802 |     ``TypeError`` will be raised if *func*'s signature doesn't match the
4803 |     mapping contained in *iterable* or if *iterable* does not contain mappings.
4804 |     """
4805 |     for item in iterable:
4806 |         yield func(**item)
4807 | 
```
Page 234/236FirstPrevNextLast