This is page 164 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.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-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.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-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.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-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.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-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.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.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.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
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/click/core.py:
--------------------------------------------------------------------------------
```python
1 | import enum
2 | import errno
3 | import inspect
4 | import os
5 | import sys
6 | import typing as t
7 | from collections import abc
8 | from contextlib import contextmanager
9 | from contextlib import ExitStack
10 | from functools import update_wrapper
11 | from gettext import gettext as _
12 | from gettext import ngettext
13 | from itertools import repeat
14 | from types import TracebackType
15 |
16 | from . import types
17 | from .exceptions import Abort
18 | from .exceptions import BadParameter
19 | from .exceptions import ClickException
20 | from .exceptions import Exit
21 | from .exceptions import MissingParameter
22 | from .exceptions import UsageError
23 | from .formatting import HelpFormatter
24 | from .formatting import join_options
25 | from .globals import pop_context
26 | from .globals import push_context
27 | from .parser import _flag_needs_value
28 | from .parser import OptionParser
29 | from .parser import split_opt
30 | from .termui import confirm
31 | from .termui import prompt
32 | from .termui import style
33 | from .utils import _detect_program_name
34 | from .utils import _expand_args
35 | from .utils import echo
36 | from .utils import make_default_short_help
37 | from .utils import make_str
38 | from .utils import PacifyFlushWrapper
39 |
40 | if t.TYPE_CHECKING:
41 | import typing_extensions as te
42 | from .shell_completion import CompletionItem
43 |
44 | F = t.TypeVar("F", bound=t.Callable[..., t.Any])
45 | V = t.TypeVar("V")
46 |
47 |
48 | def _complete_visible_commands(
49 | ctx: "Context", incomplete: str
50 | ) -> t.Iterator[t.Tuple[str, "Command"]]:
51 | """List all the subcommands of a group that start with the
52 | incomplete value and aren't hidden.
53 |
54 | :param ctx: Invocation context for the group.
55 | :param incomplete: Value being completed. May be empty.
56 | """
57 | multi = t.cast(MultiCommand, ctx.command)
58 |
59 | for name in multi.list_commands(ctx):
60 | if name.startswith(incomplete):
61 | command = multi.get_command(ctx, name)
62 |
63 | if command is not None and not command.hidden:
64 | yield name, command
65 |
66 |
67 | def _check_multicommand(
68 | base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False
69 | ) -> None:
70 | if not base_command.chain or not isinstance(cmd, MultiCommand):
71 | return
72 | if register:
73 | hint = (
74 | "It is not possible to add multi commands as children to"
75 | " another multi command that is in chain mode."
76 | )
77 | else:
78 | hint = (
79 | "Found a multi command as subcommand to a multi command"
80 | " that is in chain mode. This is not supported."
81 | )
82 | raise RuntimeError(
83 | f"{hint}. Command {base_command.name!r} is set to chain and"
84 | f" {cmd_name!r} was added as a subcommand but it in itself is a"
85 | f" multi command. ({cmd_name!r} is a {type(cmd).__name__}"
86 | f" within a chained {type(base_command).__name__} named"
87 | f" {base_command.name!r})."
88 | )
89 |
90 |
91 | def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]:
92 | return list(zip(*repeat(iter(iterable), batch_size)))
93 |
94 |
95 | @contextmanager
96 | def augment_usage_errors(
97 | ctx: "Context", param: t.Optional["Parameter"] = None
98 | ) -> t.Iterator[None]:
99 | """Context manager that attaches extra information to exceptions."""
100 | try:
101 | yield
102 | except BadParameter as e:
103 | if e.ctx is None:
104 | e.ctx = ctx
105 | if param is not None and e.param is None:
106 | e.param = param
107 | raise
108 | except UsageError as e:
109 | if e.ctx is None:
110 | e.ctx = ctx
111 | raise
112 |
113 |
114 | def iter_params_for_processing(
115 | invocation_order: t.Sequence["Parameter"],
116 | declaration_order: t.Sequence["Parameter"],
117 | ) -> t.List["Parameter"]:
118 | """Given a sequence of parameters in the order as should be considered
119 | for processing and an iterable of parameters that exist, this returns
120 | a list in the correct order as they should be processed.
121 | """
122 |
123 | def sort_key(item: "Parameter") -> t.Tuple[bool, float]:
124 | try:
125 | idx: float = invocation_order.index(item)
126 | except ValueError:
127 | idx = float("inf")
128 |
129 | return not item.is_eager, idx
130 |
131 | return sorted(declaration_order, key=sort_key)
132 |
133 |
134 | class ParameterSource(enum.Enum):
135 | """This is an :class:`~enum.Enum` that indicates the source of a
136 | parameter's value.
137 |
138 | Use :meth:`click.Context.get_parameter_source` to get the
139 | source for a parameter by name.
140 |
141 | .. versionchanged:: 8.0
142 | Use :class:`~enum.Enum` and drop the ``validate`` method.
143 |
144 | .. versionchanged:: 8.0
145 | Added the ``PROMPT`` value.
146 | """
147 |
148 | COMMANDLINE = enum.auto()
149 | """The value was provided by the command line args."""
150 | ENVIRONMENT = enum.auto()
151 | """The value was provided with an environment variable."""
152 | DEFAULT = enum.auto()
153 | """Used the default specified by the parameter."""
154 | DEFAULT_MAP = enum.auto()
155 | """Used a default provided by :attr:`Context.default_map`."""
156 | PROMPT = enum.auto()
157 | """Used a prompt to confirm a default or provide a value."""
158 |
159 |
160 | class Context:
161 | """The context is a special internal object that holds state relevant
162 | for the script execution at every single level. It's normally invisible
163 | to commands unless they opt-in to getting access to it.
164 |
165 | The context is useful as it can pass internal objects around and can
166 | control special execution features such as reading data from
167 | environment variables.
168 |
169 | A context can be used as context manager in which case it will call
170 | :meth:`close` on teardown.
171 |
172 | :param command: the command class for this context.
173 | :param parent: the parent context.
174 | :param info_name: the info name for this invocation. Generally this
175 | is the most descriptive name for the script or
176 | command. For the toplevel script it is usually
177 | the name of the script, for commands below it it's
178 | the name of the script.
179 | :param obj: an arbitrary object of user data.
180 | :param auto_envvar_prefix: the prefix to use for automatic environment
181 | variables. If this is `None` then reading
182 | from environment variables is disabled. This
183 | does not affect manually set environment
184 | variables which are always read.
185 | :param default_map: a dictionary (like object) with default values
186 | for parameters.
187 | :param terminal_width: the width of the terminal. The default is
188 | inherit from parent context. If no context
189 | defines the terminal width then auto
190 | detection will be applied.
191 | :param max_content_width: the maximum width for content rendered by
192 | Click (this currently only affects help
193 | pages). This defaults to 80 characters if
194 | not overridden. In other words: even if the
195 | terminal is larger than that, Click will not
196 | format things wider than 80 characters by
197 | default. In addition to that, formatters might
198 | add some safety mapping on the right.
199 | :param resilient_parsing: if this flag is enabled then Click will
200 | parse without any interactivity or callback
201 | invocation. Default values will also be
202 | ignored. This is useful for implementing
203 | things such as completion support.
204 | :param allow_extra_args: if this is set to `True` then extra arguments
205 | at the end will not raise an error and will be
206 | kept on the context. The default is to inherit
207 | from the command.
208 | :param allow_interspersed_args: if this is set to `False` then options
209 | and arguments cannot be mixed. The
210 | default is to inherit from the command.
211 | :param ignore_unknown_options: instructs click to ignore options it does
212 | not know and keeps them for later
213 | processing.
214 | :param help_option_names: optionally a list of strings that define how
215 | the default help parameter is named. The
216 | default is ``['--help']``.
217 | :param token_normalize_func: an optional function that is used to
218 | normalize tokens (options, choices,
219 | etc.). This for instance can be used to
220 | implement case insensitive behavior.
221 | :param color: controls if the terminal supports ANSI colors or not. The
222 | default is autodetection. This is only needed if ANSI
223 | codes are used in texts that Click prints which is by
224 | default not the case. This for instance would affect
225 | help output.
226 | :param show_default: Show the default value for commands. If this
227 | value is not set, it defaults to the value from the parent
228 | context. ``Command.show_default`` overrides this default for the
229 | specific command.
230 |
231 | .. versionchanged:: 8.1
232 | The ``show_default`` parameter is overridden by
233 | ``Command.show_default``, instead of the other way around.
234 |
235 | .. versionchanged:: 8.0
236 | The ``show_default`` parameter defaults to the value from the
237 | parent context.
238 |
239 | .. versionchanged:: 7.1
240 | Added the ``show_default`` parameter.
241 |
242 | .. versionchanged:: 4.0
243 | Added the ``color``, ``ignore_unknown_options``, and
244 | ``max_content_width`` parameters.
245 |
246 | .. versionchanged:: 3.0
247 | Added the ``allow_extra_args`` and ``allow_interspersed_args``
248 | parameters.
249 |
250 | .. versionchanged:: 2.0
251 | Added the ``resilient_parsing``, ``help_option_names``, and
252 | ``token_normalize_func`` parameters.
253 | """
254 |
255 | #: The formatter class to create with :meth:`make_formatter`.
256 | #:
257 | #: .. versionadded:: 8.0
258 | formatter_class: t.Type["HelpFormatter"] = HelpFormatter
259 |
260 | def __init__(
261 | self,
262 | command: "Command",
263 | parent: t.Optional["Context"] = None,
264 | info_name: t.Optional[str] = None,
265 | obj: t.Optional[t.Any] = None,
266 | auto_envvar_prefix: t.Optional[str] = None,
267 | default_map: t.Optional[t.MutableMapping[str, t.Any]] = None,
268 | terminal_width: t.Optional[int] = None,
269 | max_content_width: t.Optional[int] = None,
270 | resilient_parsing: bool = False,
271 | allow_extra_args: t.Optional[bool] = None,
272 | allow_interspersed_args: t.Optional[bool] = None,
273 | ignore_unknown_options: t.Optional[bool] = None,
274 | help_option_names: t.Optional[t.List[str]] = None,
275 | token_normalize_func: t.Optional[t.Callable[[str], str]] = None,
276 | color: t.Optional[bool] = None,
277 | show_default: t.Optional[bool] = None,
278 | ) -> None:
279 | #: the parent context or `None` if none exists.
280 | self.parent = parent
281 | #: the :class:`Command` for this context.
282 | self.command = command
283 | #: the descriptive information name
284 | self.info_name = info_name
285 | #: Map of parameter names to their parsed values. Parameters
286 | #: with ``expose_value=False`` are not stored.
287 | self.params: t.Dict[str, t.Any] = {}
288 | #: the leftover arguments.
289 | self.args: t.List[str] = []
290 | #: protected arguments. These are arguments that are prepended
291 | #: to `args` when certain parsing scenarios are encountered but
292 | #: must be never propagated to another arguments. This is used
293 | #: to implement nested parsing.
294 | self.protected_args: t.List[str] = []
295 | #: the collected prefixes of the command's options.
296 | self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set()
297 |
298 | if obj is None and parent is not None:
299 | obj = parent.obj
300 |
301 | #: the user object stored.
302 | self.obj: t.Any = obj
303 | self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {})
304 |
305 | #: A dictionary (-like object) with defaults for parameters.
306 | if (
307 | default_map is None
308 | and info_name is not None
309 | and parent is not None
310 | and parent.default_map is not None
311 | ):
312 | default_map = parent.default_map.get(info_name)
313 |
314 | self.default_map: t.Optional[t.MutableMapping[str, t.Any]] = default_map
315 |
316 | #: This flag indicates if a subcommand is going to be executed. A
317 | #: group callback can use this information to figure out if it's
318 | #: being executed directly or because the execution flow passes
319 | #: onwards to a subcommand. By default it's None, but it can be
320 | #: the name of the subcommand to execute.
321 | #:
322 | #: If chaining is enabled this will be set to ``'*'`` in case
323 | #: any commands are executed. It is however not possible to
324 | #: figure out which ones. If you require this knowledge you
325 | #: should use a :func:`result_callback`.
326 | self.invoked_subcommand: t.Optional[str] = None
327 |
328 | if terminal_width is None and parent is not None:
329 | terminal_width = parent.terminal_width
330 |
331 | #: The width of the terminal (None is autodetection).
332 | self.terminal_width: t.Optional[int] = terminal_width
333 |
334 | if max_content_width is None and parent is not None:
335 | max_content_width = parent.max_content_width
336 |
337 | #: The maximum width of formatted content (None implies a sensible
338 | #: default which is 80 for most things).
339 | self.max_content_width: t.Optional[int] = max_content_width
340 |
341 | if allow_extra_args is None:
342 | allow_extra_args = command.allow_extra_args
343 |
344 | #: Indicates if the context allows extra args or if it should
345 | #: fail on parsing.
346 | #:
347 | #: .. versionadded:: 3.0
348 | self.allow_extra_args = allow_extra_args
349 |
350 | if allow_interspersed_args is None:
351 | allow_interspersed_args = command.allow_interspersed_args
352 |
353 | #: Indicates if the context allows mixing of arguments and
354 | #: options or not.
355 | #:
356 | #: .. versionadded:: 3.0
357 | self.allow_interspersed_args: bool = allow_interspersed_args
358 |
359 | if ignore_unknown_options is None:
360 | ignore_unknown_options = command.ignore_unknown_options
361 |
362 | #: Instructs click to ignore options that a command does not
363 | #: understand and will store it on the context for later
364 | #: processing. This is primarily useful for situations where you
365 | #: want to call into external programs. Generally this pattern is
366 | #: strongly discouraged because it's not possibly to losslessly
367 | #: forward all arguments.
368 | #:
369 | #: .. versionadded:: 4.0
370 | self.ignore_unknown_options: bool = ignore_unknown_options
371 |
372 | if help_option_names is None:
373 | if parent is not None:
374 | help_option_names = parent.help_option_names
375 | else:
376 | help_option_names = ["--help"]
377 |
378 | #: The names for the help options.
379 | self.help_option_names: t.List[str] = help_option_names
380 |
381 | if token_normalize_func is None and parent is not None:
382 | token_normalize_func = parent.token_normalize_func
383 |
384 | #: An optional normalization function for tokens. This is
385 | #: options, choices, commands etc.
386 | self.token_normalize_func: t.Optional[
387 | t.Callable[[str], str]
388 | ] = token_normalize_func
389 |
390 | #: Indicates if resilient parsing is enabled. In that case Click
391 | #: will do its best to not cause any failures and default values
392 | #: will be ignored. Useful for completion.
393 | self.resilient_parsing: bool = resilient_parsing
394 |
395 | # If there is no envvar prefix yet, but the parent has one and
396 | # the command on this level has a name, we can expand the envvar
397 | # prefix automatically.
398 | if auto_envvar_prefix is None:
399 | if (
400 | parent is not None
401 | and parent.auto_envvar_prefix is not None
402 | and self.info_name is not None
403 | ):
404 | auto_envvar_prefix = (
405 | f"{parent.auto_envvar_prefix}_{self.info_name.upper()}"
406 | )
407 | else:
408 | auto_envvar_prefix = auto_envvar_prefix.upper()
409 |
410 | if auto_envvar_prefix is not None:
411 | auto_envvar_prefix = auto_envvar_prefix.replace("-", "_")
412 |
413 | self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix
414 |
415 | if color is None and parent is not None:
416 | color = parent.color
417 |
418 | #: Controls if styling output is wanted or not.
419 | self.color: t.Optional[bool] = color
420 |
421 | if show_default is None and parent is not None:
422 | show_default = parent.show_default
423 |
424 | #: Show option default values when formatting help text.
425 | self.show_default: t.Optional[bool] = show_default
426 |
427 | self._close_callbacks: t.List[t.Callable[[], t.Any]] = []
428 | self._depth = 0
429 | self._parameter_source: t.Dict[str, ParameterSource] = {}
430 | self._exit_stack = ExitStack()
431 |
432 | def to_info_dict(self) -> t.Dict[str, t.Any]:
433 | """Gather information that could be useful for a tool generating
434 | user-facing documentation. This traverses the entire CLI
435 | structure.
436 |
437 | .. code-block:: python
438 |
439 | with Context(cli) as ctx:
440 | info = ctx.to_info_dict()
441 |
442 | .. versionadded:: 8.0
443 | """
444 | return {
445 | "command": self.command.to_info_dict(self),
446 | "info_name": self.info_name,
447 | "allow_extra_args": self.allow_extra_args,
448 | "allow_interspersed_args": self.allow_interspersed_args,
449 | "ignore_unknown_options": self.ignore_unknown_options,
450 | "auto_envvar_prefix": self.auto_envvar_prefix,
451 | }
452 |
453 | def __enter__(self) -> "Context":
454 | self._depth += 1
455 | push_context(self)
456 | return self
457 |
458 | def __exit__(
459 | self,
460 | exc_type: t.Optional[t.Type[BaseException]],
461 | exc_value: t.Optional[BaseException],
462 | tb: t.Optional[TracebackType],
463 | ) -> None:
464 | self._depth -= 1
465 | if self._depth == 0:
466 | self.close()
467 | pop_context()
468 |
469 | @contextmanager
470 | def scope(self, cleanup: bool = True) -> t.Iterator["Context"]:
471 | """This helper method can be used with the context object to promote
472 | it to the current thread local (see :func:`get_current_context`).
473 | The default behavior of this is to invoke the cleanup functions which
474 | can be disabled by setting `cleanup` to `False`. The cleanup
475 | functions are typically used for things such as closing file handles.
476 |
477 | If the cleanup is intended the context object can also be directly
478 | used as a context manager.
479 |
480 | Example usage::
481 |
482 | with ctx.scope():
483 | assert get_current_context() is ctx
484 |
485 | This is equivalent::
486 |
487 | with ctx:
488 | assert get_current_context() is ctx
489 |
490 | .. versionadded:: 5.0
491 |
492 | :param cleanup: controls if the cleanup functions should be run or
493 | not. The default is to run these functions. In
494 | some situations the context only wants to be
495 | temporarily pushed in which case this can be disabled.
496 | Nested pushes automatically defer the cleanup.
497 | """
498 | if not cleanup:
499 | self._depth += 1
500 | try:
501 | with self as rv:
502 | yield rv
503 | finally:
504 | if not cleanup:
505 | self._depth -= 1
506 |
507 | @property
508 | def meta(self) -> t.Dict[str, t.Any]:
509 | """This is a dictionary which is shared with all the contexts
510 | that are nested. It exists so that click utilities can store some
511 | state here if they need to. It is however the responsibility of
512 | that code to manage this dictionary well.
513 |
514 | The keys are supposed to be unique dotted strings. For instance
515 | module paths are a good choice for it. What is stored in there is
516 | irrelevant for the operation of click. However what is important is
517 | that code that places data here adheres to the general semantics of
518 | the system.
519 |
520 | Example usage::
521 |
522 | LANG_KEY = f'{__name__}.lang'
523 |
524 | def set_language(value):
525 | ctx = get_current_context()
526 | ctx.meta[LANG_KEY] = value
527 |
528 | def get_language():
529 | return get_current_context().meta.get(LANG_KEY, 'en_US')
530 |
531 | .. versionadded:: 5.0
532 | """
533 | return self._meta
534 |
535 | def make_formatter(self) -> HelpFormatter:
536 | """Creates the :class:`~click.HelpFormatter` for the help and
537 | usage output.
538 |
539 | To quickly customize the formatter class used without overriding
540 | this method, set the :attr:`formatter_class` attribute.
541 |
542 | .. versionchanged:: 8.0
543 | Added the :attr:`formatter_class` attribute.
544 | """
545 | return self.formatter_class(
546 | width=self.terminal_width, max_width=self.max_content_width
547 | )
548 |
549 | def with_resource(self, context_manager: t.ContextManager[V]) -> V:
550 | """Register a resource as if it were used in a ``with``
551 | statement. The resource will be cleaned up when the context is
552 | popped.
553 |
554 | Uses :meth:`contextlib.ExitStack.enter_context`. It calls the
555 | resource's ``__enter__()`` method and returns the result. When
556 | the context is popped, it closes the stack, which calls the
557 | resource's ``__exit__()`` method.
558 |
559 | To register a cleanup function for something that isn't a
560 | context manager, use :meth:`call_on_close`. Or use something
561 | from :mod:`contextlib` to turn it into a context manager first.
562 |
563 | .. code-block:: python
564 |
565 | @click.group()
566 | @click.option("--name")
567 | @click.pass_context
568 | def cli(ctx):
569 | ctx.obj = ctx.with_resource(connect_db(name))
570 |
571 | :param context_manager: The context manager to enter.
572 | :return: Whatever ``context_manager.__enter__()`` returns.
573 |
574 | .. versionadded:: 8.0
575 | """
576 | return self._exit_stack.enter_context(context_manager)
577 |
578 | def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]:
579 | """Register a function to be called when the context tears down.
580 |
581 | This can be used to close resources opened during the script
582 | execution. Resources that support Python's context manager
583 | protocol which would be used in a ``with`` statement should be
584 | registered with :meth:`with_resource` instead.
585 |
586 | :param f: The function to execute on teardown.
587 | """
588 | return self._exit_stack.callback(f)
589 |
590 | def close(self) -> None:
591 | """Invoke all close callbacks registered with
592 | :meth:`call_on_close`, and exit all context managers entered
593 | with :meth:`with_resource`.
594 | """
595 | self._exit_stack.close()
596 | # In case the context is reused, create a new exit stack.
597 | self._exit_stack = ExitStack()
598 |
599 | @property
600 | def command_path(self) -> str:
601 | """The computed command path. This is used for the ``usage``
602 | information on the help page. It's automatically created by
603 | combining the info names of the chain of contexts to the root.
604 | """
605 | rv = ""
606 | if self.info_name is not None:
607 | rv = self.info_name
608 | if self.parent is not None:
609 | parent_command_path = [self.parent.command_path]
610 |
611 | if isinstance(self.parent.command, Command):
612 | for param in self.parent.command.get_params(self):
613 | parent_command_path.extend(param.get_usage_pieces(self))
614 |
615 | rv = f"{' '.join(parent_command_path)} {rv}"
616 | return rv.lstrip()
617 |
618 | def find_root(self) -> "Context":
619 | """Finds the outermost context."""
620 | node = self
621 | while node.parent is not None:
622 | node = node.parent
623 | return node
624 |
625 | def find_object(self, object_type: t.Type[V]) -> t.Optional[V]:
626 | """Finds the closest object of a given type."""
627 | node: t.Optional["Context"] = self
628 |
629 | while node is not None:
630 | if isinstance(node.obj, object_type):
631 | return node.obj
632 |
633 | node = node.parent
634 |
635 | return None
636 |
637 | def ensure_object(self, object_type: t.Type[V]) -> V:
638 | """Like :meth:`find_object` but sets the innermost object to a
639 | new instance of `object_type` if it does not exist.
640 | """
641 | rv = self.find_object(object_type)
642 | if rv is None:
643 | self.obj = rv = object_type()
644 | return rv
645 |
646 | @t.overload
647 | def lookup_default(
648 | self, name: str, call: "te.Literal[True]" = True
649 | ) -> t.Optional[t.Any]:
650 | ...
651 |
652 | @t.overload
653 | def lookup_default(
654 | self, name: str, call: "te.Literal[False]" = ...
655 | ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
656 | ...
657 |
658 | def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]:
659 | """Get the default for a parameter from :attr:`default_map`.
660 |
661 | :param name: Name of the parameter.
662 | :param call: If the default is a callable, call it. Disable to
663 | return the callable instead.
664 |
665 | .. versionchanged:: 8.0
666 | Added the ``call`` parameter.
667 | """
668 | if self.default_map is not None:
669 | value = self.default_map.get(name)
670 |
671 | if call and callable(value):
672 | return value()
673 |
674 | return value
675 |
676 | return None
677 |
678 | def fail(self, message: str) -> "te.NoReturn":
679 | """Aborts the execution of the program with a specific error
680 | message.
681 |
682 | :param message: the error message to fail with.
683 | """
684 | raise UsageError(message, self)
685 |
686 | def abort(self) -> "te.NoReturn":
687 | """Aborts the script."""
688 | raise Abort()
689 |
690 | def exit(self, code: int = 0) -> "te.NoReturn":
691 | """Exits the application with a given exit code."""
692 | raise Exit(code)
693 |
694 | def get_usage(self) -> str:
695 | """Helper method to get formatted usage string for the current
696 | context and command.
697 | """
698 | return self.command.get_usage(self)
699 |
700 | def get_help(self) -> str:
701 | """Helper method to get formatted help page for the current
702 | context and command.
703 | """
704 | return self.command.get_help(self)
705 |
706 | def _make_sub_context(self, command: "Command") -> "Context":
707 | """Create a new context of the same type as this context, but
708 | for a new command.
709 |
710 | :meta private:
711 | """
712 | return type(self)(command, info_name=command.name, parent=self)
713 |
714 | @t.overload
715 | def invoke(
716 | __self, # noqa: B902
717 | __callback: "t.Callable[..., V]",
718 | *args: t.Any,
719 | **kwargs: t.Any,
720 | ) -> V:
721 | ...
722 |
723 | @t.overload
724 | def invoke(
725 | __self, # noqa: B902
726 | __callback: "Command",
727 | *args: t.Any,
728 | **kwargs: t.Any,
729 | ) -> t.Any:
730 | ...
731 |
732 | def invoke(
733 | __self, # noqa: B902
734 | __callback: t.Union["Command", "t.Callable[..., V]"],
735 | *args: t.Any,
736 | **kwargs: t.Any,
737 | ) -> t.Union[t.Any, V]:
738 | """Invokes a command callback in exactly the way it expects. There
739 | are two ways to invoke this method:
740 |
741 | 1. the first argument can be a callback and all other arguments and
742 | keyword arguments are forwarded directly to the function.
743 | 2. the first argument is a click command object. In that case all
744 | arguments are forwarded as well but proper click parameters
745 | (options and click arguments) must be keyword arguments and Click
746 | will fill in defaults.
747 |
748 | Note that before Click 3.2 keyword arguments were not properly filled
749 | in against the intention of this code and no context was created. For
750 | more information about this change and why it was done in a bugfix
751 | release see :ref:`upgrade-to-3.2`.
752 |
753 | .. versionchanged:: 8.0
754 | All ``kwargs`` are tracked in :attr:`params` so they will be
755 | passed if :meth:`forward` is called at multiple levels.
756 | """
757 | if isinstance(__callback, Command):
758 | other_cmd = __callback
759 |
760 | if other_cmd.callback is None:
761 | raise TypeError(
762 | "The given command does not have a callback that can be invoked."
763 | )
764 | else:
765 | __callback = t.cast("t.Callable[..., V]", other_cmd.callback)
766 |
767 | ctx = __self._make_sub_context(other_cmd)
768 |
769 | for param in other_cmd.params:
770 | if param.name not in kwargs and param.expose_value:
771 | kwargs[param.name] = param.type_cast_value( # type: ignore
772 | ctx, param.get_default(ctx)
773 | )
774 |
775 | # Track all kwargs as params, so that forward() will pass
776 | # them on in subsequent calls.
777 | ctx.params.update(kwargs)
778 | else:
779 | ctx = __self
780 |
781 | with augment_usage_errors(__self):
782 | with ctx:
783 | return __callback(*args, **kwargs)
784 |
785 | def forward(
786 | __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902
787 | ) -> t.Any:
788 | """Similar to :meth:`invoke` but fills in default keyword
789 | arguments from the current context if the other command expects
790 | it. This cannot invoke callbacks directly, only other commands.
791 |
792 | .. versionchanged:: 8.0
793 | All ``kwargs`` are tracked in :attr:`params` so they will be
794 | passed if ``forward`` is called at multiple levels.
795 | """
796 | # Can only forward to other commands, not direct callbacks.
797 | if not isinstance(__cmd, Command):
798 | raise TypeError("Callback is not a command.")
799 |
800 | for param in __self.params:
801 | if param not in kwargs:
802 | kwargs[param] = __self.params[param]
803 |
804 | return __self.invoke(__cmd, *args, **kwargs)
805 |
806 | def set_parameter_source(self, name: str, source: ParameterSource) -> None:
807 | """Set the source of a parameter. This indicates the location
808 | from which the value of the parameter was obtained.
809 |
810 | :param name: The name of the parameter.
811 | :param source: A member of :class:`~click.core.ParameterSource`.
812 | """
813 | self._parameter_source[name] = source
814 |
815 | def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]:
816 | """Get the source of a parameter. This indicates the location
817 | from which the value of the parameter was obtained.
818 |
819 | This can be useful for determining when a user specified a value
820 | on the command line that is the same as the default value. It
821 | will be :attr:`~click.core.ParameterSource.DEFAULT` only if the
822 | value was actually taken from the default.
823 |
824 | :param name: The name of the parameter.
825 | :rtype: ParameterSource
826 |
827 | .. versionchanged:: 8.0
828 | Returns ``None`` if the parameter was not provided from any
829 | source.
830 | """
831 | return self._parameter_source.get(name)
832 |
833 |
834 | class BaseCommand:
835 | """The base command implements the minimal API contract of commands.
836 | Most code will never use this as it does not implement a lot of useful
837 | functionality but it can act as the direct subclass of alternative
838 | parsing methods that do not depend on the Click parser.
839 |
840 | For instance, this can be used to bridge Click and other systems like
841 | argparse or docopt.
842 |
843 | Because base commands do not implement a lot of the API that other
844 | parts of Click take for granted, they are not supported for all
845 | operations. For instance, they cannot be used with the decorators
846 | usually and they have no built-in callback system.
847 |
848 | .. versionchanged:: 2.0
849 | Added the `context_settings` parameter.
850 |
851 | :param name: the name of the command to use unless a group overrides it.
852 | :param context_settings: an optional dictionary with defaults that are
853 | passed to the context object.
854 | """
855 |
856 | #: The context class to create with :meth:`make_context`.
857 | #:
858 | #: .. versionadded:: 8.0
859 | context_class: t.Type[Context] = Context
860 | #: the default for the :attr:`Context.allow_extra_args` flag.
861 | allow_extra_args = False
862 | #: the default for the :attr:`Context.allow_interspersed_args` flag.
863 | allow_interspersed_args = True
864 | #: the default for the :attr:`Context.ignore_unknown_options` flag.
865 | ignore_unknown_options = False
866 |
867 | def __init__(
868 | self,
869 | name: t.Optional[str],
870 | context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None,
871 | ) -> None:
872 | #: the name the command thinks it has. Upon registering a command
873 | #: on a :class:`Group` the group will default the command name
874 | #: with this information. You should instead use the
875 | #: :class:`Context`\'s :attr:`~Context.info_name` attribute.
876 | self.name = name
877 |
878 | if context_settings is None:
879 | context_settings = {}
880 |
881 | #: an optional dictionary with defaults passed to the context.
882 | self.context_settings: t.MutableMapping[str, t.Any] = context_settings
883 |
884 | def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
885 | """Gather information that could be useful for a tool generating
886 | user-facing documentation. This traverses the entire structure
887 | below this command.
888 |
889 | Use :meth:`click.Context.to_info_dict` to traverse the entire
890 | CLI structure.
891 |
892 | :param ctx: A :class:`Context` representing this command.
893 |
894 | .. versionadded:: 8.0
895 | """
896 | return {"name": self.name}
897 |
898 | def __repr__(self) -> str:
899 | return f"<{self.__class__.__name__} {self.name}>"
900 |
901 | def get_usage(self, ctx: Context) -> str:
902 | raise NotImplementedError("Base commands cannot get usage")
903 |
904 | def get_help(self, ctx: Context) -> str:
905 | raise NotImplementedError("Base commands cannot get help")
906 |
907 | def make_context(
908 | self,
909 | info_name: t.Optional[str],
910 | args: t.List[str],
911 | parent: t.Optional[Context] = None,
912 | **extra: t.Any,
913 | ) -> Context:
914 | """This function when given an info name and arguments will kick
915 | off the parsing and create a new :class:`Context`. It does not
916 | invoke the actual command callback though.
917 |
918 | To quickly customize the context class used without overriding
919 | this method, set the :attr:`context_class` attribute.
920 |
921 | :param info_name: the info name for this invocation. Generally this
922 | is the most descriptive name for the script or
923 | command. For the toplevel script it's usually
924 | the name of the script, for commands below it's
925 | the name of the command.
926 | :param args: the arguments to parse as list of strings.
927 | :param parent: the parent context if available.
928 | :param extra: extra keyword arguments forwarded to the context
929 | constructor.
930 |
931 | .. versionchanged:: 8.0
932 | Added the :attr:`context_class` attribute.
933 | """
934 | for key, value in self.context_settings.items():
935 | if key not in extra:
936 | extra[key] = value
937 |
938 | ctx = self.context_class(
939 | self, info_name=info_name, parent=parent, **extra # type: ignore
940 | )
941 |
942 | with ctx.scope(cleanup=False):
943 | self.parse_args(ctx, args)
944 | return ctx
945 |
946 | def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
947 | """Given a context and a list of arguments this creates the parser
948 | and parses the arguments, then modifies the context as necessary.
949 | This is automatically invoked by :meth:`make_context`.
950 | """
951 | raise NotImplementedError("Base commands do not know how to parse arguments.")
952 |
953 | def invoke(self, ctx: Context) -> t.Any:
954 | """Given a context, this invokes the command. The default
955 | implementation is raising a not implemented error.
956 | """
957 | raise NotImplementedError("Base commands are not invocable by default")
958 |
959 | def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
960 | """Return a list of completions for the incomplete value. Looks
961 | at the names of chained multi-commands.
962 |
963 | Any command could be part of a chained multi-command, so sibling
964 | commands are valid at any point during command completion. Other
965 | command classes will return more completions.
966 |
967 | :param ctx: Invocation context for this command.
968 | :param incomplete: Value being completed. May be empty.
969 |
970 | .. versionadded:: 8.0
971 | """
972 | from click.shell_completion import CompletionItem
973 |
974 | results: t.List["CompletionItem"] = []
975 |
976 | while ctx.parent is not None:
977 | ctx = ctx.parent
978 |
979 | if isinstance(ctx.command, MultiCommand) and ctx.command.chain:
980 | results.extend(
981 | CompletionItem(name, help=command.get_short_help_str())
982 | for name, command in _complete_visible_commands(ctx, incomplete)
983 | if name not in ctx.protected_args
984 | )
985 |
986 | return results
987 |
988 | @t.overload
989 | def main(
990 | self,
991 | args: t.Optional[t.Sequence[str]] = None,
992 | prog_name: t.Optional[str] = None,
993 | complete_var: t.Optional[str] = None,
994 | standalone_mode: "te.Literal[True]" = True,
995 | **extra: t.Any,
996 | ) -> "te.NoReturn":
997 | ...
998 |
999 | @t.overload
1000 | def main(
1001 | self,
1002 | args: t.Optional[t.Sequence[str]] = None,
1003 | prog_name: t.Optional[str] = None,
1004 | complete_var: t.Optional[str] = None,
1005 | standalone_mode: bool = ...,
1006 | **extra: t.Any,
1007 | ) -> t.Any:
1008 | ...
1009 |
1010 | def main(
1011 | self,
1012 | args: t.Optional[t.Sequence[str]] = None,
1013 | prog_name: t.Optional[str] = None,
1014 | complete_var: t.Optional[str] = None,
1015 | standalone_mode: bool = True,
1016 | windows_expand_args: bool = True,
1017 | **extra: t.Any,
1018 | ) -> t.Any:
1019 | """This is the way to invoke a script with all the bells and
1020 | whistles as a command line application. This will always terminate
1021 | the application after a call. If this is not wanted, ``SystemExit``
1022 | needs to be caught.
1023 |
1024 | This method is also available by directly calling the instance of
1025 | a :class:`Command`.
1026 |
1027 | :param args: the arguments that should be used for parsing. If not
1028 | provided, ``sys.argv[1:]`` is used.
1029 | :param prog_name: the program name that should be used. By default
1030 | the program name is constructed by taking the file
1031 | name from ``sys.argv[0]``.
1032 | :param complete_var: the environment variable that controls the
1033 | bash completion support. The default is
1034 | ``"_<prog_name>_COMPLETE"`` with prog_name in
1035 | uppercase.
1036 | :param standalone_mode: the default behavior is to invoke the script
1037 | in standalone mode. Click will then
1038 | handle exceptions and convert them into
1039 | error messages and the function will never
1040 | return but shut down the interpreter. If
1041 | this is set to `False` they will be
1042 | propagated to the caller and the return
1043 | value of this function is the return value
1044 | of :meth:`invoke`.
1045 | :param windows_expand_args: Expand glob patterns, user dir, and
1046 | env vars in command line args on Windows.
1047 | :param extra: extra keyword arguments are forwarded to the context
1048 | constructor. See :class:`Context` for more information.
1049 |
1050 | .. versionchanged:: 8.0.1
1051 | Added the ``windows_expand_args`` parameter to allow
1052 | disabling command line arg expansion on Windows.
1053 |
1054 | .. versionchanged:: 8.0
1055 | When taking arguments from ``sys.argv`` on Windows, glob
1056 | patterns, user dir, and env vars are expanded.
1057 |
1058 | .. versionchanged:: 3.0
1059 | Added the ``standalone_mode`` parameter.
1060 | """
1061 | if args is None:
1062 | args = sys.argv[1:]
1063 |
1064 | if os.name == "nt" and windows_expand_args:
1065 | args = _expand_args(args)
1066 | else:
1067 | args = list(args)
1068 |
1069 | if prog_name is None:
1070 | prog_name = _detect_program_name()
1071 |
1072 | # Process shell completion requests and exit early.
1073 | self._main_shell_completion(extra, prog_name, complete_var)
1074 |
1075 | try:
1076 | try:
1077 | with self.make_context(prog_name, args, **extra) as ctx:
1078 | rv = self.invoke(ctx)
1079 | if not standalone_mode:
1080 | return rv
1081 | # it's not safe to `ctx.exit(rv)` here!
1082 | # note that `rv` may actually contain data like "1" which
1083 | # has obvious effects
1084 | # more subtle case: `rv=[None, None]` can come out of
1085 | # chained commands which all returned `None` -- so it's not
1086 | # even always obvious that `rv` indicates success/failure
1087 | # by its truthiness/falsiness
1088 | ctx.exit()
1089 | except (EOFError, KeyboardInterrupt) as e:
1090 | echo(file=sys.stderr)
1091 | raise Abort() from e
1092 | except ClickException as e:
1093 | if not standalone_mode:
1094 | raise
1095 | e.show()
1096 | sys.exit(e.exit_code)
1097 | except OSError as e:
1098 | if e.errno == errno.EPIPE:
1099 | sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout))
1100 | sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr))
1101 | sys.exit(1)
1102 | else:
1103 | raise
1104 | except Exit as e:
1105 | if standalone_mode:
1106 | sys.exit(e.exit_code)
1107 | else:
1108 | # in non-standalone mode, return the exit code
1109 | # note that this is only reached if `self.invoke` above raises
1110 | # an Exit explicitly -- thus bypassing the check there which
1111 | # would return its result
1112 | # the results of non-standalone execution may therefore be
1113 | # somewhat ambiguous: if there are codepaths which lead to
1114 | # `ctx.exit(1)` and to `return 1`, the caller won't be able to
1115 | # tell the difference between the two
1116 | return e.exit_code
1117 | except Abort:
1118 | if not standalone_mode:
1119 | raise
1120 | echo(_("Aborted!"), file=sys.stderr)
1121 | sys.exit(1)
1122 |
1123 | def _main_shell_completion(
1124 | self,
1125 | ctx_args: t.MutableMapping[str, t.Any],
1126 | prog_name: str,
1127 | complete_var: t.Optional[str] = None,
1128 | ) -> None:
1129 | """Check if the shell is asking for tab completion, process
1130 | that, then exit early. Called from :meth:`main` before the
1131 | program is invoked.
1132 |
1133 | :param prog_name: Name of the executable in the shell.
1134 | :param complete_var: Name of the environment variable that holds
1135 | the completion instruction. Defaults to
1136 | ``_{PROG_NAME}_COMPLETE``.
1137 |
1138 | .. versionchanged:: 8.2.0
1139 | Dots (``.``) in ``prog_name`` are replaced with underscores (``_``).
1140 | """
1141 | if complete_var is None:
1142 | complete_name = prog_name.replace("-", "_").replace(".", "_")
1143 | complete_var = f"_{complete_name}_COMPLETE".upper()
1144 |
1145 | instruction = os.environ.get(complete_var)
1146 |
1147 | if not instruction:
1148 | return
1149 |
1150 | from .shell_completion import shell_complete
1151 |
1152 | rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction)
1153 | sys.exit(rv)
1154 |
1155 | def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any:
1156 | """Alias for :meth:`main`."""
1157 | return self.main(*args, **kwargs)
1158 |
1159 |
1160 | class Command(BaseCommand):
1161 | """Commands are the basic building block of command line interfaces in
1162 | Click. A basic command handles command line parsing and might dispatch
1163 | more parsing to commands nested below it.
1164 |
1165 | :param name: the name of the command to use unless a group overrides it.
1166 | :param context_settings: an optional dictionary with defaults that are
1167 | passed to the context object.
1168 | :param callback: the callback to invoke. This is optional.
1169 | :param params: the parameters to register with this command. This can
1170 | be either :class:`Option` or :class:`Argument` objects.
1171 | :param help: the help string to use for this command.
1172 | :param epilog: like the help string but it's printed at the end of the
1173 | help page after everything else.
1174 | :param short_help: the short help to use for this command. This is
1175 | shown on the command listing of the parent command.
1176 | :param add_help_option: by default each command registers a ``--help``
1177 | option. This can be disabled by this parameter.
1178 | :param no_args_is_help: this controls what happens if no arguments are
1179 | provided. This option is disabled by default.
1180 | If enabled this will add ``--help`` as argument
1181 | if no arguments are passed
1182 | :param hidden: hide this command from help outputs.
1183 |
1184 | :param deprecated: issues a message indicating that
1185 | the command is deprecated.
1186 |
1187 | .. versionchanged:: 8.1
1188 | ``help``, ``epilog``, and ``short_help`` are stored unprocessed,
1189 | all formatting is done when outputting help text, not at init,
1190 | and is done even if not using the ``@command`` decorator.
1191 |
1192 | .. versionchanged:: 8.0
1193 | Added a ``repr`` showing the command name.
1194 |
1195 | .. versionchanged:: 7.1
1196 | Added the ``no_args_is_help`` parameter.
1197 |
1198 | .. versionchanged:: 2.0
1199 | Added the ``context_settings`` parameter.
1200 | """
1201 |
1202 | def __init__(
1203 | self,
1204 | name: t.Optional[str],
1205 | context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None,
1206 | callback: t.Optional[t.Callable[..., t.Any]] = None,
1207 | params: t.Optional[t.List["Parameter"]] = None,
1208 | help: t.Optional[str] = None,
1209 | epilog: t.Optional[str] = None,
1210 | short_help: t.Optional[str] = None,
1211 | options_metavar: t.Optional[str] = "[OPTIONS]",
1212 | add_help_option: bool = True,
1213 | no_args_is_help: bool = False,
1214 | hidden: bool = False,
1215 | deprecated: bool = False,
1216 | ) -> None:
1217 | super().__init__(name, context_settings)
1218 | #: the callback to execute when the command fires. This might be
1219 | #: `None` in which case nothing happens.
1220 | self.callback = callback
1221 | #: the list of parameters for this command in the order they
1222 | #: should show up in the help page and execute. Eager parameters
1223 | #: will automatically be handled before non eager ones.
1224 | self.params: t.List["Parameter"] = params or []
1225 | self.help = help
1226 | self.epilog = epilog
1227 | self.options_metavar = options_metavar
1228 | self.short_help = short_help
1229 | self.add_help_option = add_help_option
1230 | self.no_args_is_help = no_args_is_help
1231 | self.hidden = hidden
1232 | self.deprecated = deprecated
1233 |
1234 | def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
1235 | info_dict = super().to_info_dict(ctx)
1236 | info_dict.update(
1237 | params=[param.to_info_dict() for param in self.get_params(ctx)],
1238 | help=self.help,
1239 | epilog=self.epilog,
1240 | short_help=self.short_help,
1241 | hidden=self.hidden,
1242 | deprecated=self.deprecated,
1243 | )
1244 | return info_dict
1245 |
1246 | def get_usage(self, ctx: Context) -> str:
1247 | """Formats the usage line into a string and returns it.
1248 |
1249 | Calls :meth:`format_usage` internally.
1250 | """
1251 | formatter = ctx.make_formatter()
1252 | self.format_usage(ctx, formatter)
1253 | return formatter.getvalue().rstrip("\n")
1254 |
1255 | def get_params(self, ctx: Context) -> t.List["Parameter"]:
1256 | rv = self.params
1257 | help_option = self.get_help_option(ctx)
1258 |
1259 | if help_option is not None:
1260 | rv = [*rv, help_option]
1261 |
1262 | return rv
1263 |
1264 | def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None:
1265 | """Writes the usage line into the formatter.
1266 |
1267 | This is a low-level method called by :meth:`get_usage`.
1268 | """
1269 | pieces = self.collect_usage_pieces(ctx)
1270 | formatter.write_usage(ctx.command_path, " ".join(pieces))
1271 |
1272 | def collect_usage_pieces(self, ctx: Context) -> t.List[str]:
1273 | """Returns all the pieces that go into the usage line and returns
1274 | it as a list of strings.
1275 | """
1276 | rv = [self.options_metavar] if self.options_metavar else []
1277 |
1278 | for param in self.get_params(ctx):
1279 | rv.extend(param.get_usage_pieces(ctx))
1280 |
1281 | return rv
1282 |
1283 | def get_help_option_names(self, ctx: Context) -> t.List[str]:
1284 | """Returns the names for the help option."""
1285 | all_names = set(ctx.help_option_names)
1286 | for param in self.params:
1287 | all_names.difference_update(param.opts)
1288 | all_names.difference_update(param.secondary_opts)
1289 | return list(all_names)
1290 |
1291 | def get_help_option(self, ctx: Context) -> t.Optional["Option"]:
1292 | """Returns the help option object."""
1293 | help_options = self.get_help_option_names(ctx)
1294 |
1295 | if not help_options or not self.add_help_option:
1296 | return None
1297 |
1298 | def show_help(ctx: Context, param: "Parameter", value: str) -> None:
1299 | if value and not ctx.resilient_parsing:
1300 | echo(ctx.get_help(), color=ctx.color)
1301 | ctx.exit()
1302 |
1303 | return Option(
1304 | help_options,
1305 | is_flag=True,
1306 | is_eager=True,
1307 | expose_value=False,
1308 | callback=show_help,
1309 | help=_("Show this message and exit."),
1310 | )
1311 |
1312 | def make_parser(self, ctx: Context) -> OptionParser:
1313 | """Creates the underlying option parser for this command."""
1314 | parser = OptionParser(ctx)
1315 | for param in self.get_params(ctx):
1316 | param.add_to_parser(parser, ctx)
1317 | return parser
1318 |
1319 | def get_help(self, ctx: Context) -> str:
1320 | """Formats the help into a string and returns it.
1321 |
1322 | Calls :meth:`format_help` internally.
1323 | """
1324 | formatter = ctx.make_formatter()
1325 | self.format_help(ctx, formatter)
1326 | return formatter.getvalue().rstrip("\n")
1327 |
1328 | def get_short_help_str(self, limit: int = 45) -> str:
1329 | """Gets short help for the command or makes it by shortening the
1330 | long help string.
1331 | """
1332 | if self.short_help:
1333 | text = inspect.cleandoc(self.short_help)
1334 | elif self.help:
1335 | text = make_default_short_help(self.help, limit)
1336 | else:
1337 | text = ""
1338 |
1339 | if self.deprecated:
1340 | text = _("(Deprecated) {text}").format(text=text)
1341 |
1342 | return text.strip()
1343 |
1344 | def format_help(self, ctx: Context, formatter: HelpFormatter) -> None:
1345 | """Writes the help into the formatter if it exists.
1346 |
1347 | This is a low-level method called by :meth:`get_help`.
1348 |
1349 | This calls the following methods:
1350 |
1351 | - :meth:`format_usage`
1352 | - :meth:`format_help_text`
1353 | - :meth:`format_options`
1354 | - :meth:`format_epilog`
1355 | """
1356 | self.format_usage(ctx, formatter)
1357 | self.format_help_text(ctx, formatter)
1358 | self.format_options(ctx, formatter)
1359 | self.format_epilog(ctx, formatter)
1360 |
1361 | def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None:
1362 | """Writes the help text to the formatter if it exists."""
1363 | if self.help is not None:
1364 | # truncate the help text to the first form feed
1365 | text = inspect.cleandoc(self.help).partition("\f")[0]
1366 | else:
1367 | text = ""
1368 |
1369 | if self.deprecated:
1370 | text = _("(Deprecated) {text}").format(text=text)
1371 |
1372 | if text:
1373 | formatter.write_paragraph()
1374 |
1375 | with formatter.indentation():
1376 | formatter.write_text(text)
1377 |
1378 | def format_options(self, ctx: Context, formatter: HelpFormatter) -> None:
1379 | """Writes all the options into the formatter if they exist."""
1380 | opts = []
1381 | for param in self.get_params(ctx):
1382 | rv = param.get_help_record(ctx)
1383 | if rv is not None:
1384 | opts.append(rv)
1385 |
1386 | if opts:
1387 | with formatter.section(_("Options")):
1388 | formatter.write_dl(opts)
1389 |
1390 | def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None:
1391 | """Writes the epilog into the formatter if it exists."""
1392 | if self.epilog:
1393 | epilog = inspect.cleandoc(self.epilog)
1394 | formatter.write_paragraph()
1395 |
1396 | with formatter.indentation():
1397 | formatter.write_text(epilog)
1398 |
1399 | def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
1400 | if not args and self.no_args_is_help and not ctx.resilient_parsing:
1401 | echo(ctx.get_help(), color=ctx.color)
1402 | ctx.exit()
1403 |
1404 | parser = self.make_parser(ctx)
1405 | opts, args, param_order = parser.parse_args(args=args)
1406 |
1407 | for param in iter_params_for_processing(param_order, self.get_params(ctx)):
1408 | value, args = param.handle_parse_result(ctx, opts, args)
1409 |
1410 | if args and not ctx.allow_extra_args and not ctx.resilient_parsing:
1411 | ctx.fail(
1412 | ngettext(
1413 | "Got unexpected extra argument ({args})",
1414 | "Got unexpected extra arguments ({args})",
1415 | len(args),
1416 | ).format(args=" ".join(map(str, args)))
1417 | )
1418 |
1419 | ctx.args = args
1420 | ctx._opt_prefixes.update(parser._opt_prefixes)
1421 | return args
1422 |
1423 | def invoke(self, ctx: Context) -> t.Any:
1424 | """Given a context, this invokes the attached callback (if it exists)
1425 | in the right way.
1426 | """
1427 | if self.deprecated:
1428 | message = _(
1429 | "DeprecationWarning: The command {name!r} is deprecated."
1430 | ).format(name=self.name)
1431 | echo(style(message, fg="red"), err=True)
1432 |
1433 | if self.callback is not None:
1434 | return ctx.invoke(self.callback, **ctx.params)
1435 |
1436 | def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
1437 | """Return a list of completions for the incomplete value. Looks
1438 | at the names of options and chained multi-commands.
1439 |
1440 | :param ctx: Invocation context for this command.
1441 | :param incomplete: Value being completed. May be empty.
1442 |
1443 | .. versionadded:: 8.0
1444 | """
1445 | from click.shell_completion import CompletionItem
1446 |
1447 | results: t.List["CompletionItem"] = []
1448 |
1449 | if incomplete and not incomplete[0].isalnum():
1450 | for param in self.get_params(ctx):
1451 | if (
1452 | not isinstance(param, Option)
1453 | or param.hidden
1454 | or (
1455 | not param.multiple
1456 | and ctx.get_parameter_source(param.name) # type: ignore
1457 | is ParameterSource.COMMANDLINE
1458 | )
1459 | ):
1460 | continue
1461 |
1462 | results.extend(
1463 | CompletionItem(name, help=param.help)
1464 | for name in [*param.opts, *param.secondary_opts]
1465 | if name.startswith(incomplete)
1466 | )
1467 |
1468 | results.extend(super().shell_complete(ctx, incomplete))
1469 | return results
1470 |
1471 |
1472 | class MultiCommand(Command):
1473 | """A multi command is the basic implementation of a command that
1474 | dispatches to subcommands. The most common version is the
1475 | :class:`Group`.
1476 |
1477 | :param invoke_without_command: this controls how the multi command itself
1478 | is invoked. By default it's only invoked
1479 | if a subcommand is provided.
1480 | :param no_args_is_help: this controls what happens if no arguments are
1481 | provided. This option is enabled by default if
1482 | `invoke_without_command` is disabled or disabled
1483 | if it's enabled. If enabled this will add
1484 | ``--help`` as argument if no arguments are
1485 | passed.
1486 | :param subcommand_metavar: the string that is used in the documentation
1487 | to indicate the subcommand place.
1488 | :param chain: if this is set to `True` chaining of multiple subcommands
1489 | is enabled. This restricts the form of commands in that
1490 | they cannot have optional arguments but it allows
1491 | multiple commands to be chained together.
1492 | :param result_callback: The result callback to attach to this multi
1493 | command. This can be set or changed later with the
1494 | :meth:`result_callback` decorator.
1495 | :param attrs: Other command arguments described in :class:`Command`.
1496 | """
1497 |
1498 | allow_extra_args = True
1499 | allow_interspersed_args = False
1500 |
1501 | def __init__(
1502 | self,
1503 | name: t.Optional[str] = None,
1504 | invoke_without_command: bool = False,
1505 | no_args_is_help: t.Optional[bool] = None,
1506 | subcommand_metavar: t.Optional[str] = None,
1507 | chain: bool = False,
1508 | result_callback: t.Optional[t.Callable[..., t.Any]] = None,
1509 | **attrs: t.Any,
1510 | ) -> None:
1511 | super().__init__(name, **attrs)
1512 |
1513 | if no_args_is_help is None:
1514 | no_args_is_help = not invoke_without_command
1515 |
1516 | self.no_args_is_help = no_args_is_help
1517 | self.invoke_without_command = invoke_without_command
1518 |
1519 | if subcommand_metavar is None:
1520 | if chain:
1521 | subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..."
1522 | else:
1523 | subcommand_metavar = "COMMAND [ARGS]..."
1524 |
1525 | self.subcommand_metavar = subcommand_metavar
1526 | self.chain = chain
1527 | # The result callback that is stored. This can be set or
1528 | # overridden with the :func:`result_callback` decorator.
1529 | self._result_callback = result_callback
1530 |
1531 | if self.chain:
1532 | for param in self.params:
1533 | if isinstance(param, Argument) and not param.required:
1534 | raise RuntimeError(
1535 | "Multi commands in chain mode cannot have"
1536 | " optional arguments."
1537 | )
1538 |
1539 | def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]:
1540 | info_dict = super().to_info_dict(ctx)
1541 | commands = {}
1542 |
1543 | for name in self.list_commands(ctx):
1544 | command = self.get_command(ctx, name)
1545 |
1546 | if command is None:
1547 | continue
1548 |
1549 | sub_ctx = ctx._make_sub_context(command)
1550 |
1551 | with sub_ctx.scope(cleanup=False):
1552 | commands[name] = command.to_info_dict(sub_ctx)
1553 |
1554 | info_dict.update(commands=commands, chain=self.chain)
1555 | return info_dict
1556 |
1557 | def collect_usage_pieces(self, ctx: Context) -> t.List[str]:
1558 | rv = super().collect_usage_pieces(ctx)
1559 | rv.append(self.subcommand_metavar)
1560 | return rv
1561 |
1562 | def format_options(self, ctx: Context, formatter: HelpFormatter) -> None:
1563 | super().format_options(ctx, formatter)
1564 | self.format_commands(ctx, formatter)
1565 |
1566 | def result_callback(self, replace: bool = False) -> t.Callable[[F], F]:
1567 | """Adds a result callback to the command. By default if a
1568 | result callback is already registered this will chain them but
1569 | this can be disabled with the `replace` parameter. The result
1570 | callback is invoked with the return value of the subcommand
1571 | (or the list of return values from all subcommands if chaining
1572 | is enabled) as well as the parameters as they would be passed
1573 | to the main callback.
1574 |
1575 | Example::
1576 |
1577 | @click.group()
1578 | @click.option('-i', '--input', default=23)
1579 | def cli(input):
1580 | return 42
1581 |
1582 | @cli.result_callback()
1583 | def process_result(result, input):
1584 | return result + input
1585 |
1586 | :param replace: if set to `True` an already existing result
1587 | callback will be removed.
1588 |
1589 | .. versionchanged:: 8.0
1590 | Renamed from ``resultcallback``.
1591 |
1592 | .. versionadded:: 3.0
1593 | """
1594 |
1595 | def decorator(f: F) -> F:
1596 | old_callback = self._result_callback
1597 |
1598 | if old_callback is None or replace:
1599 | self._result_callback = f
1600 | return f
1601 |
1602 | def function(__value, *args, **kwargs): # type: ignore
1603 | inner = old_callback(__value, *args, **kwargs)
1604 | return f(inner, *args, **kwargs)
1605 |
1606 | self._result_callback = rv = update_wrapper(t.cast(F, function), f)
1607 | return rv
1608 |
1609 | return decorator
1610 |
1611 | def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None:
1612 | """Extra format methods for multi methods that adds all the commands
1613 | after the options.
1614 | """
1615 | commands = []
1616 | for subcommand in self.list_commands(ctx):
1617 | cmd = self.get_command(ctx, subcommand)
1618 | # What is this, the tool lied about a command. Ignore it
1619 | if cmd is None:
1620 | continue
1621 | if cmd.hidden:
1622 | continue
1623 |
1624 | commands.append((subcommand, cmd))
1625 |
1626 | # allow for 3 times the default spacing
1627 | if len(commands):
1628 | limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands)
1629 |
1630 | rows = []
1631 | for subcommand, cmd in commands:
1632 | help = cmd.get_short_help_str(limit)
1633 | rows.append((subcommand, help))
1634 |
1635 | if rows:
1636 | with formatter.section(_("Commands")):
1637 | formatter.write_dl(rows)
1638 |
1639 | def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]:
1640 | if not args and self.no_args_is_help and not ctx.resilient_parsing:
1641 | echo(ctx.get_help(), color=ctx.color)
1642 | ctx.exit()
1643 |
1644 | rest = super().parse_args(ctx, args)
1645 |
1646 | if self.chain:
1647 | ctx.protected_args = rest
1648 | ctx.args = []
1649 | elif rest:
1650 | ctx.protected_args, ctx.args = rest[:1], rest[1:]
1651 |
1652 | return ctx.args
1653 |
1654 | def invoke(self, ctx: Context) -> t.Any:
1655 | def _process_result(value: t.Any) -> t.Any:
1656 | if self._result_callback is not None:
1657 | value = ctx.invoke(self._result_callback, value, **ctx.params)
1658 | return value
1659 |
1660 | if not ctx.protected_args:
1661 | if self.invoke_without_command:
1662 | # No subcommand was invoked, so the result callback is
1663 | # invoked with the group return value for regular
1664 | # groups, or an empty list for chained groups.
1665 | with ctx:
1666 | rv = super().invoke(ctx)
1667 | return _process_result([] if self.chain else rv)
1668 | ctx.fail(_("Missing command."))
1669 |
1670 | # Fetch args back out
1671 | args = [*ctx.protected_args, *ctx.args]
1672 | ctx.args = []
1673 | ctx.protected_args = []
1674 |
1675 | # If we're not in chain mode, we only allow the invocation of a
1676 | # single command but we also inform the current context about the
1677 | # name of the command to invoke.
1678 | if not self.chain:
1679 | # Make sure the context is entered so we do not clean up
1680 | # resources until the result processor has worked.
1681 | with ctx:
1682 | cmd_name, cmd, args = self.resolve_command(ctx, args)
1683 | assert cmd is not None
1684 | ctx.invoked_subcommand = cmd_name
1685 | super().invoke(ctx)
1686 | sub_ctx = cmd.make_context(cmd_name, args, parent=ctx)
1687 | with sub_ctx:
1688 | return _process_result(sub_ctx.command.invoke(sub_ctx))
1689 |
1690 | # In chain mode we create the contexts step by step, but after the
1691 | # base command has been invoked. Because at that point we do not
1692 | # know the subcommands yet, the invoked subcommand attribute is
1693 | # set to ``*`` to inform the command that subcommands are executed
1694 | # but nothing else.
1695 | with ctx:
1696 | ctx.invoked_subcommand = "*" if args else None
1697 | super().invoke(ctx)
1698 |
1699 | # Otherwise we make every single context and invoke them in a
1700 | # chain. In that case the return value to the result processor
1701 | # is the list of all invoked subcommand's results.
1702 | contexts = []
1703 | while args:
1704 | cmd_name, cmd, args = self.resolve_command(ctx, args)
1705 | assert cmd is not None
1706 | sub_ctx = cmd.make_context(
1707 | cmd_name,
1708 | args,
1709 | parent=ctx,
1710 | allow_extra_args=True,
1711 | allow_interspersed_args=False,
1712 | )
1713 | contexts.append(sub_ctx)
1714 | args, sub_ctx.args = sub_ctx.args, []
1715 |
1716 | rv = []
1717 | for sub_ctx in contexts:
1718 | with sub_ctx:
1719 | rv.append(sub_ctx.command.invoke(sub_ctx))
1720 | return _process_result(rv)
1721 |
1722 | def resolve_command(
1723 | self, ctx: Context, args: t.List[str]
1724 | ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]:
1725 | cmd_name = make_str(args[0])
1726 | original_cmd_name = cmd_name
1727 |
1728 | # Get the command
1729 | cmd = self.get_command(ctx, cmd_name)
1730 |
1731 | # If we can't find the command but there is a normalization
1732 | # function available, we try with that one.
1733 | if cmd is None and ctx.token_normalize_func is not None:
1734 | cmd_name = ctx.token_normalize_func(cmd_name)
1735 | cmd = self.get_command(ctx, cmd_name)
1736 |
1737 | # If we don't find the command we want to show an error message
1738 | # to the user that it was not provided. However, there is
1739 | # something else we should do: if the first argument looks like
1740 | # an option we want to kick off parsing again for arguments to
1741 | # resolve things like --help which now should go to the main
1742 | # place.
1743 | if cmd is None and not ctx.resilient_parsing:
1744 | if split_opt(cmd_name)[0]:
1745 | self.parse_args(ctx, ctx.args)
1746 | ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name))
1747 | return cmd_name if cmd else None, cmd, args[1:]
1748 |
1749 | def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
1750 | """Given a context and a command name, this returns a
1751 | :class:`Command` object if it exists or returns `None`.
1752 | """
1753 | raise NotImplementedError
1754 |
1755 | def list_commands(self, ctx: Context) -> t.List[str]:
1756 | """Returns a list of subcommand names in the order they should
1757 | appear.
1758 | """
1759 | return []
1760 |
1761 | def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
1762 | """Return a list of completions for the incomplete value. Looks
1763 | at the names of options, subcommands, and chained
1764 | multi-commands.
1765 |
1766 | :param ctx: Invocation context for this command.
1767 | :param incomplete: Value being completed. May be empty.
1768 |
1769 | .. versionadded:: 8.0
1770 | """
1771 | from click.shell_completion import CompletionItem
1772 |
1773 | results = [
1774 | CompletionItem(name, help=command.get_short_help_str())
1775 | for name, command in _complete_visible_commands(ctx, incomplete)
1776 | ]
1777 | results.extend(super().shell_complete(ctx, incomplete))
1778 | return results
1779 |
1780 |
1781 | class Group(MultiCommand):
1782 | """A group allows a command to have subcommands attached. This is
1783 | the most common way to implement nesting in Click.
1784 |
1785 | :param name: The name of the group command.
1786 | :param commands: A dict mapping names to :class:`Command` objects.
1787 | Can also be a list of :class:`Command`, which will use
1788 | :attr:`Command.name` to create the dict.
1789 | :param attrs: Other command arguments described in
1790 | :class:`MultiCommand`, :class:`Command`, and
1791 | :class:`BaseCommand`.
1792 |
1793 | .. versionchanged:: 8.0
1794 | The ``commands`` argument can be a list of command objects.
1795 | """
1796 |
1797 | #: If set, this is used by the group's :meth:`command` decorator
1798 | #: as the default :class:`Command` class. This is useful to make all
1799 | #: subcommands use a custom command class.
1800 | #:
1801 | #: .. versionadded:: 8.0
1802 | command_class: t.Optional[t.Type[Command]] = None
1803 |
1804 | #: If set, this is used by the group's :meth:`group` decorator
1805 | #: as the default :class:`Group` class. This is useful to make all
1806 | #: subgroups use a custom group class.
1807 | #:
1808 | #: If set to the special value :class:`type` (literally
1809 | #: ``group_class = type``), this group's class will be used as the
1810 | #: default class. This makes a custom group class continue to make
1811 | #: custom groups.
1812 | #:
1813 | #: .. versionadded:: 8.0
1814 | group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None
1815 | # Literal[type] isn't valid, so use Type[type]
1816 |
1817 | def __init__(
1818 | self,
1819 | name: t.Optional[str] = None,
1820 | commands: t.Optional[
1821 | t.Union[t.MutableMapping[str, Command], t.Sequence[Command]]
1822 | ] = None,
1823 | **attrs: t.Any,
1824 | ) -> None:
1825 | super().__init__(name, **attrs)
1826 |
1827 | if commands is None:
1828 | commands = {}
1829 | elif isinstance(commands, abc.Sequence):
1830 | commands = {c.name: c for c in commands if c.name is not None}
1831 |
1832 | #: The registered subcommands by their exported names.
1833 | self.commands: t.MutableMapping[str, Command] = commands
1834 |
1835 | def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None:
1836 | """Registers another :class:`Command` with this group. If the name
1837 | is not provided, the name of the command is used.
1838 | """
1839 | name = name or cmd.name
1840 | if name is None:
1841 | raise TypeError("Command has no name.")
1842 | _check_multicommand(self, name, cmd, register=True)
1843 | self.commands[name] = cmd
1844 |
1845 | @t.overload
1846 | def command(self, __func: t.Callable[..., t.Any]) -> Command:
1847 | ...
1848 |
1849 | @t.overload
1850 | def command(
1851 | self, *args: t.Any, **kwargs: t.Any
1852 | ) -> t.Callable[[t.Callable[..., t.Any]], Command]:
1853 | ...
1854 |
1855 | def command(
1856 | self, *args: t.Any, **kwargs: t.Any
1857 | ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]:
1858 | """A shortcut decorator for declaring and attaching a command to
1859 | the group. This takes the same arguments as :func:`command` and
1860 | immediately registers the created command with this group by
1861 | calling :meth:`add_command`.
1862 |
1863 | To customize the command class used, set the
1864 | :attr:`command_class` attribute.
1865 |
1866 | .. versionchanged:: 8.1
1867 | This decorator can be applied without parentheses.
1868 |
1869 | .. versionchanged:: 8.0
1870 | Added the :attr:`command_class` attribute.
1871 | """
1872 | from .decorators import command
1873 |
1874 | func: t.Optional[t.Callable[..., t.Any]] = None
1875 |
1876 | if args and callable(args[0]):
1877 | assert (
1878 | len(args) == 1 and not kwargs
1879 | ), "Use 'command(**kwargs)(callable)' to provide arguments."
1880 | (func,) = args
1881 | args = ()
1882 |
1883 | if self.command_class and kwargs.get("cls") is None:
1884 | kwargs["cls"] = self.command_class
1885 |
1886 | def decorator(f: t.Callable[..., t.Any]) -> Command:
1887 | cmd: Command = command(*args, **kwargs)(f)
1888 | self.add_command(cmd)
1889 | return cmd
1890 |
1891 | if func is not None:
1892 | return decorator(func)
1893 |
1894 | return decorator
1895 |
1896 | @t.overload
1897 | def group(self, __func: t.Callable[..., t.Any]) -> "Group":
1898 | ...
1899 |
1900 | @t.overload
1901 | def group(
1902 | self, *args: t.Any, **kwargs: t.Any
1903 | ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]:
1904 | ...
1905 |
1906 | def group(
1907 | self, *args: t.Any, **kwargs: t.Any
1908 | ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]:
1909 | """A shortcut decorator for declaring and attaching a group to
1910 | the group. This takes the same arguments as :func:`group` and
1911 | immediately registers the created group with this group by
1912 | calling :meth:`add_command`.
1913 |
1914 | To customize the group class used, set the :attr:`group_class`
1915 | attribute.
1916 |
1917 | .. versionchanged:: 8.1
1918 | This decorator can be applied without parentheses.
1919 |
1920 | .. versionchanged:: 8.0
1921 | Added the :attr:`group_class` attribute.
1922 | """
1923 | from .decorators import group
1924 |
1925 | func: t.Optional[t.Callable[..., t.Any]] = None
1926 |
1927 | if args and callable(args[0]):
1928 | assert (
1929 | len(args) == 1 and not kwargs
1930 | ), "Use 'group(**kwargs)(callable)' to provide arguments."
1931 | (func,) = args
1932 | args = ()
1933 |
1934 | if self.group_class is not None and kwargs.get("cls") is None:
1935 | if self.group_class is type:
1936 | kwargs["cls"] = type(self)
1937 | else:
1938 | kwargs["cls"] = self.group_class
1939 |
1940 | def decorator(f: t.Callable[..., t.Any]) -> "Group":
1941 | cmd: Group = group(*args, **kwargs)(f)
1942 | self.add_command(cmd)
1943 | return cmd
1944 |
1945 | if func is not None:
1946 | return decorator(func)
1947 |
1948 | return decorator
1949 |
1950 | def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
1951 | return self.commands.get(cmd_name)
1952 |
1953 | def list_commands(self, ctx: Context) -> t.List[str]:
1954 | return sorted(self.commands)
1955 |
1956 |
1957 | class CommandCollection(MultiCommand):
1958 | """A command collection is a multi command that merges multiple multi
1959 | commands together into one. This is a straightforward implementation
1960 | that accepts a list of different multi commands as sources and
1961 | provides all the commands for each of them.
1962 |
1963 | See :class:`MultiCommand` and :class:`Command` for the description of
1964 | ``name`` and ``attrs``.
1965 | """
1966 |
1967 | def __init__(
1968 | self,
1969 | name: t.Optional[str] = None,
1970 | sources: t.Optional[t.List[MultiCommand]] = None,
1971 | **attrs: t.Any,
1972 | ) -> None:
1973 | super().__init__(name, **attrs)
1974 | #: The list of registered multi commands.
1975 | self.sources: t.List[MultiCommand] = sources or []
1976 |
1977 | def add_source(self, multi_cmd: MultiCommand) -> None:
1978 | """Adds a new multi command to the chain dispatcher."""
1979 | self.sources.append(multi_cmd)
1980 |
1981 | def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]:
1982 | for source in self.sources:
1983 | rv = source.get_command(ctx, cmd_name)
1984 |
1985 | if rv is not None:
1986 | if self.chain:
1987 | _check_multicommand(self, cmd_name, rv)
1988 |
1989 | return rv
1990 |
1991 | return None
1992 |
1993 | def list_commands(self, ctx: Context) -> t.List[str]:
1994 | rv: t.Set[str] = set()
1995 |
1996 | for source in self.sources:
1997 | rv.update(source.list_commands(ctx))
1998 |
1999 | return sorted(rv)
2000 |
2001 |
2002 | def _check_iter(value: t.Any) -> t.Iterator[t.Any]:
2003 | """Check if the value is iterable but not a string. Raises a type
2004 | error, or return an iterator over the value.
2005 | """
2006 | if isinstance(value, str):
2007 | raise TypeError
2008 |
2009 | return iter(value)
2010 |
2011 |
2012 | class Parameter:
2013 | r"""A parameter to a command comes in two versions: they are either
2014 | :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently
2015 | not supported by design as some of the internals for parsing are
2016 | intentionally not finalized.
2017 |
2018 | Some settings are supported by both options and arguments.
2019 |
2020 | :param param_decls: the parameter declarations for this option or
2021 | argument. This is a list of flags or argument
2022 | names.
2023 | :param type: the type that should be used. Either a :class:`ParamType`
2024 | or a Python type. The latter is converted into the former
2025 | automatically if supported.
2026 | :param required: controls if this is optional or not.
2027 | :param default: the default value if omitted. This can also be a callable,
2028 | in which case it's invoked when the default is needed
2029 | without any arguments.
2030 | :param callback: A function to further process or validate the value
2031 | after type conversion. It is called as ``f(ctx, param, value)``
2032 | and must return the value. It is called for all sources,
2033 | including prompts.
2034 | :param nargs: the number of arguments to match. If not ``1`` the return
2035 | value is a tuple instead of single value. The default for
2036 | nargs is ``1`` (except if the type is a tuple, then it's
2037 | the arity of the tuple). If ``nargs=-1``, all remaining
2038 | parameters are collected.
2039 | :param metavar: how the value is represented in the help page.
2040 | :param expose_value: if this is `True` then the value is passed onwards
2041 | to the command callback and stored on the context,
2042 | otherwise it's skipped.
2043 | :param is_eager: eager values are processed before non eager ones. This
2044 | should not be set for arguments or it will inverse the
2045 | order of processing.
2046 | :param envvar: a string or list of strings that are environment variables
2047 | that should be checked.
2048 | :param shell_complete: A function that returns custom shell
2049 | completions. Used instead of the param's type completion if
2050 | given. Takes ``ctx, param, incomplete`` and must return a list
2051 | of :class:`~click.shell_completion.CompletionItem` or a list of
2052 | strings.
2053 |
2054 | .. versionchanged:: 8.0
2055 | ``process_value`` validates required parameters and bounded
2056 | ``nargs``, and invokes the parameter callback before returning
2057 | the value. This allows the callback to validate prompts.
2058 | ``full_process_value`` is removed.
2059 |
2060 | .. versionchanged:: 8.0
2061 | ``autocompletion`` is renamed to ``shell_complete`` and has new
2062 | semantics described above. The old name is deprecated and will
2063 | be removed in 8.1, until then it will be wrapped to match the
2064 | new requirements.
2065 |
2066 | .. versionchanged:: 8.0
2067 | For ``multiple=True, nargs>1``, the default must be a list of
2068 | tuples.
2069 |
2070 | .. versionchanged:: 8.0
2071 | Setting a default is no longer required for ``nargs>1``, it will
2072 | default to ``None``. ``multiple=True`` or ``nargs=-1`` will
2073 | default to ``()``.
2074 |
2075 | .. versionchanged:: 7.1
2076 | Empty environment variables are ignored rather than taking the
2077 | empty string value. This makes it possible for scripts to clear
2078 | variables if they can't unset them.
2079 |
2080 | .. versionchanged:: 2.0
2081 | Changed signature for parameter callback to also be passed the
2082 | parameter. The old callback format will still work, but it will
2083 | raise a warning to give you a chance to migrate the code easier.
2084 | """
2085 |
2086 | param_type_name = "parameter"
2087 |
2088 | def __init__(
2089 | self,
2090 | param_decls: t.Optional[t.Sequence[str]] = None,
2091 | type: t.Optional[t.Union[types.ParamType, t.Any]] = None,
2092 | required: bool = False,
2093 | default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None,
2094 | callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None,
2095 | nargs: t.Optional[int] = None,
2096 | multiple: bool = False,
2097 | metavar: t.Optional[str] = None,
2098 | expose_value: bool = True,
2099 | is_eager: bool = False,
2100 | envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None,
2101 | shell_complete: t.Optional[
2102 | t.Callable[
2103 | [Context, "Parameter", str],
2104 | t.Union[t.List["CompletionItem"], t.List[str]],
2105 | ]
2106 | ] = None,
2107 | ) -> None:
2108 | self.name: t.Optional[str]
2109 | self.opts: t.List[str]
2110 | self.secondary_opts: t.List[str]
2111 | self.name, self.opts, self.secondary_opts = self._parse_decls(
2112 | param_decls or (), expose_value
2113 | )
2114 | self.type: types.ParamType = types.convert_type(type, default)
2115 |
2116 | # Default nargs to what the type tells us if we have that
2117 | # information available.
2118 | if nargs is None:
2119 | if self.type.is_composite:
2120 | nargs = self.type.arity
2121 | else:
2122 | nargs = 1
2123 |
2124 | self.required = required
2125 | self.callback = callback
2126 | self.nargs = nargs
2127 | self.multiple = multiple
2128 | self.expose_value = expose_value
2129 | self.default = default
2130 | self.is_eager = is_eager
2131 | self.metavar = metavar
2132 | self.envvar = envvar
2133 | self._custom_shell_complete = shell_complete
2134 |
2135 | if __debug__:
2136 | if self.type.is_composite and nargs != self.type.arity:
2137 | raise ValueError(
2138 | f"'nargs' must be {self.type.arity} (or None) for"
2139 | f" type {self.type!r}, but it was {nargs}."
2140 | )
2141 |
2142 | # Skip no default or callable default.
2143 | check_default = default if not callable(default) else None
2144 |
2145 | if check_default is not None:
2146 | if multiple:
2147 | try:
2148 | # Only check the first value against nargs.
2149 | check_default = next(_check_iter(check_default), None)
2150 | except TypeError:
2151 | raise ValueError(
2152 | "'default' must be a list when 'multiple' is true."
2153 | ) from None
2154 |
2155 | # Can be None for multiple with empty default.
2156 | if nargs != 1 and check_default is not None:
2157 | try:
2158 | _check_iter(check_default)
2159 | except TypeError:
2160 | if multiple:
2161 | message = (
2162 | "'default' must be a list of lists when 'multiple' is"
2163 | " true and 'nargs' != 1."
2164 | )
2165 | else:
2166 | message = "'default' must be a list when 'nargs' != 1."
2167 |
2168 | raise ValueError(message) from None
2169 |
2170 | if nargs > 1 and len(check_default) != nargs:
2171 | subject = "item length" if multiple else "length"
2172 | raise ValueError(
2173 | f"'default' {subject} must match nargs={nargs}."
2174 | )
2175 |
2176 | def to_info_dict(self) -> t.Dict[str, t.Any]:
2177 | """Gather information that could be useful for a tool generating
2178 | user-facing documentation.
2179 |
2180 | Use :meth:`click.Context.to_info_dict` to traverse the entire
2181 | CLI structure.
2182 |
2183 | .. versionadded:: 8.0
2184 | """
2185 | return {
2186 | "name": self.name,
2187 | "param_type_name": self.param_type_name,
2188 | "opts": self.opts,
2189 | "secondary_opts": self.secondary_opts,
2190 | "type": self.type.to_info_dict(),
2191 | "required": self.required,
2192 | "nargs": self.nargs,
2193 | "multiple": self.multiple,
2194 | "default": self.default,
2195 | "envvar": self.envvar,
2196 | }
2197 |
2198 | def __repr__(self) -> str:
2199 | return f"<{self.__class__.__name__} {self.name}>"
2200 |
2201 | def _parse_decls(
2202 | self, decls: t.Sequence[str], expose_value: bool
2203 | ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
2204 | raise NotImplementedError()
2205 |
2206 | @property
2207 | def human_readable_name(self) -> str:
2208 | """Returns the human readable name of this parameter. This is the
2209 | same as the name for options, but the metavar for arguments.
2210 | """
2211 | return self.name # type: ignore
2212 |
2213 | def make_metavar(self) -> str:
2214 | if self.metavar is not None:
2215 | return self.metavar
2216 |
2217 | metavar = self.type.get_metavar(self)
2218 |
2219 | if metavar is None:
2220 | metavar = self.type.name.upper()
2221 |
2222 | if self.nargs != 1:
2223 | metavar += "..."
2224 |
2225 | return metavar
2226 |
2227 | @t.overload
2228 | def get_default(
2229 | self, ctx: Context, call: "te.Literal[True]" = True
2230 | ) -> t.Optional[t.Any]:
2231 | ...
2232 |
2233 | @t.overload
2234 | def get_default(
2235 | self, ctx: Context, call: bool = ...
2236 | ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
2237 | ...
2238 |
2239 | def get_default(
2240 | self, ctx: Context, call: bool = True
2241 | ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
2242 | """Get the default for the parameter. Tries
2243 | :meth:`Context.lookup_default` first, then the local default.
2244 |
2245 | :param ctx: Current context.
2246 | :param call: If the default is a callable, call it. Disable to
2247 | return the callable instead.
2248 |
2249 | .. versionchanged:: 8.0.2
2250 | Type casting is no longer performed when getting a default.
2251 |
2252 | .. versionchanged:: 8.0.1
2253 | Type casting can fail in resilient parsing mode. Invalid
2254 | defaults will not prevent showing help text.
2255 |
2256 | .. versionchanged:: 8.0
2257 | Looks at ``ctx.default_map`` first.
2258 |
2259 | .. versionchanged:: 8.0
2260 | Added the ``call`` parameter.
2261 | """
2262 | value = ctx.lookup_default(self.name, call=False) # type: ignore
2263 |
2264 | if value is None:
2265 | value = self.default
2266 |
2267 | if call and callable(value):
2268 | value = value()
2269 |
2270 | return value
2271 |
2272 | def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
2273 | raise NotImplementedError()
2274 |
2275 | def consume_value(
2276 | self, ctx: Context, opts: t.Mapping[str, t.Any]
2277 | ) -> t.Tuple[t.Any, ParameterSource]:
2278 | value = opts.get(self.name) # type: ignore
2279 | source = ParameterSource.COMMANDLINE
2280 |
2281 | if value is None:
2282 | value = self.value_from_envvar(ctx)
2283 | source = ParameterSource.ENVIRONMENT
2284 |
2285 | if value is None:
2286 | value = ctx.lookup_default(self.name) # type: ignore
2287 | source = ParameterSource.DEFAULT_MAP
2288 |
2289 | if value is None:
2290 | value = self.get_default(ctx)
2291 | source = ParameterSource.DEFAULT
2292 |
2293 | return value, source
2294 |
2295 | def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any:
2296 | """Convert and validate a value against the option's
2297 | :attr:`type`, :attr:`multiple`, and :attr:`nargs`.
2298 | """
2299 | if value is None:
2300 | return () if self.multiple or self.nargs == -1 else None
2301 |
2302 | def check_iter(value: t.Any) -> t.Iterator[t.Any]:
2303 | try:
2304 | return _check_iter(value)
2305 | except TypeError:
2306 | # This should only happen when passing in args manually,
2307 | # the parser should construct an iterable when parsing
2308 | # the command line.
2309 | raise BadParameter(
2310 | _("Value must be an iterable."), ctx=ctx, param=self
2311 | ) from None
2312 |
2313 | if self.nargs == 1 or self.type.is_composite:
2314 |
2315 | def convert(value: t.Any) -> t.Any:
2316 | return self.type(value, param=self, ctx=ctx)
2317 |
2318 | elif self.nargs == -1:
2319 |
2320 | def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...]
2321 | return tuple(self.type(x, self, ctx) for x in check_iter(value))
2322 |
2323 | else: # nargs > 1
2324 |
2325 | def convert(value: t.Any) -> t.Any: # t.Tuple[t.Any, ...]
2326 | value = tuple(check_iter(value))
2327 |
2328 | if len(value) != self.nargs:
2329 | raise BadParameter(
2330 | ngettext(
2331 | "Takes {nargs} values but 1 was given.",
2332 | "Takes {nargs} values but {len} were given.",
2333 | len(value),
2334 | ).format(nargs=self.nargs, len=len(value)),
2335 | ctx=ctx,
2336 | param=self,
2337 | )
2338 |
2339 | return tuple(self.type(x, self, ctx) for x in value)
2340 |
2341 | if self.multiple:
2342 | return tuple(convert(x) for x in check_iter(value))
2343 |
2344 | return convert(value)
2345 |
2346 | def value_is_missing(self, value: t.Any) -> bool:
2347 | if value is None:
2348 | return True
2349 |
2350 | if (self.nargs != 1 or self.multiple) and value == ():
2351 | return True
2352 |
2353 | return False
2354 |
2355 | def process_value(self, ctx: Context, value: t.Any) -> t.Any:
2356 | value = self.type_cast_value(ctx, value)
2357 |
2358 | if self.required and self.value_is_missing(value):
2359 | raise MissingParameter(ctx=ctx, param=self)
2360 |
2361 | if self.callback is not None:
2362 | value = self.callback(ctx, self, value)
2363 |
2364 | return value
2365 |
2366 | def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]:
2367 | if self.envvar is None:
2368 | return None
2369 |
2370 | if isinstance(self.envvar, str):
2371 | rv = os.environ.get(self.envvar)
2372 |
2373 | if rv:
2374 | return rv
2375 | else:
2376 | for envvar in self.envvar:
2377 | rv = os.environ.get(envvar)
2378 |
2379 | if rv:
2380 | return rv
2381 |
2382 | return None
2383 |
2384 | def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]:
2385 | rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx)
2386 |
2387 | if rv is not None and self.nargs != 1:
2388 | rv = self.type.split_envvar_value(rv)
2389 |
2390 | return rv
2391 |
2392 | def handle_parse_result(
2393 | self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str]
2394 | ) -> t.Tuple[t.Any, t.List[str]]:
2395 | with augment_usage_errors(ctx, param=self):
2396 | value, source = self.consume_value(ctx, opts)
2397 | ctx.set_parameter_source(self.name, source) # type: ignore
2398 |
2399 | try:
2400 | value = self.process_value(ctx, value)
2401 | except Exception:
2402 | if not ctx.resilient_parsing:
2403 | raise
2404 |
2405 | value = None
2406 |
2407 | if self.expose_value:
2408 | ctx.params[self.name] = value # type: ignore
2409 |
2410 | return value, args
2411 |
2412 | def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]:
2413 | pass
2414 |
2415 | def get_usage_pieces(self, ctx: Context) -> t.List[str]:
2416 | return []
2417 |
2418 | def get_error_hint(self, ctx: Context) -> str:
2419 | """Get a stringified version of the param for use in error messages to
2420 | indicate which param caused the error.
2421 | """
2422 | hint_list = self.opts or [self.human_readable_name]
2423 | return " / ".join(f"'{x}'" for x in hint_list)
2424 |
2425 | def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]:
2426 | """Return a list of completions for the incomplete value. If a
2427 | ``shell_complete`` function was given during init, it is used.
2428 | Otherwise, the :attr:`type`
2429 | :meth:`~click.types.ParamType.shell_complete` function is used.
2430 |
2431 | :param ctx: Invocation context for this command.
2432 | :param incomplete: Value being completed. May be empty.
2433 |
2434 | .. versionadded:: 8.0
2435 | """
2436 | if self._custom_shell_complete is not None:
2437 | results = self._custom_shell_complete(ctx, self, incomplete)
2438 |
2439 | if results and isinstance(results[0], str):
2440 | from click.shell_completion import CompletionItem
2441 |
2442 | results = [CompletionItem(c) for c in results]
2443 |
2444 | return t.cast(t.List["CompletionItem"], results)
2445 |
2446 | return self.type.shell_complete(ctx, self, incomplete)
2447 |
2448 |
2449 | class Option(Parameter):
2450 | """Options are usually optional values on the command line and
2451 | have some extra features that arguments don't have.
2452 |
2453 | All other parameters are passed onwards to the parameter constructor.
2454 |
2455 | :param show_default: Show the default value for this option in its
2456 | help text. Values are not shown by default, unless
2457 | :attr:`Context.show_default` is ``True``. If this value is a
2458 | string, it shows that string in parentheses instead of the
2459 | actual value. This is particularly useful for dynamic options.
2460 | For single option boolean flags, the default remains hidden if
2461 | its value is ``False``.
2462 | :param show_envvar: Controls if an environment variable should be
2463 | shown on the help page. Normally, environment variables are not
2464 | shown.
2465 | :param prompt: If set to ``True`` or a non empty string then the
2466 | user will be prompted for input. If set to ``True`` the prompt
2467 | will be the option name capitalized.
2468 | :param confirmation_prompt: Prompt a second time to confirm the
2469 | value if it was prompted for. Can be set to a string instead of
2470 | ``True`` to customize the message.
2471 | :param prompt_required: If set to ``False``, the user will be
2472 | prompted for input only when the option was specified as a flag
2473 | without a value.
2474 | :param hide_input: If this is ``True`` then the input on the prompt
2475 | will be hidden from the user. This is useful for password input.
2476 | :param is_flag: forces this option to act as a flag. The default is
2477 | auto detection.
2478 | :param flag_value: which value should be used for this flag if it's
2479 | enabled. This is set to a boolean automatically if
2480 | the option string contains a slash to mark two options.
2481 | :param multiple: if this is set to `True` then the argument is accepted
2482 | multiple times and recorded. This is similar to ``nargs``
2483 | in how it works but supports arbitrary number of
2484 | arguments.
2485 | :param count: this flag makes an option increment an integer.
2486 | :param allow_from_autoenv: if this is enabled then the value of this
2487 | parameter will be pulled from an environment
2488 | variable in case a prefix is defined on the
2489 | context.
2490 | :param help: the help string.
2491 | :param hidden: hide this option from help outputs.
2492 | :param attrs: Other command arguments described in :class:`Parameter`.
2493 |
2494 | .. versionchanged:: 8.1.0
2495 | Help text indentation is cleaned here instead of only in the
2496 | ``@option`` decorator.
2497 |
2498 | .. versionchanged:: 8.1.0
2499 | The ``show_default`` parameter overrides
2500 | ``Context.show_default``.
2501 |
2502 | .. versionchanged:: 8.1.0
2503 | The default of a single option boolean flag is not shown if the
2504 | default value is ``False``.
2505 |
2506 | .. versionchanged:: 8.0.1
2507 | ``type`` is detected from ``flag_value`` if given.
2508 | """
2509 |
2510 | param_type_name = "option"
2511 |
2512 | def __init__(
2513 | self,
2514 | param_decls: t.Optional[t.Sequence[str]] = None,
2515 | show_default: t.Union[bool, str, None] = None,
2516 | prompt: t.Union[bool, str] = False,
2517 | confirmation_prompt: t.Union[bool, str] = False,
2518 | prompt_required: bool = True,
2519 | hide_input: bool = False,
2520 | is_flag: t.Optional[bool] = None,
2521 | flag_value: t.Optional[t.Any] = None,
2522 | multiple: bool = False,
2523 | count: bool = False,
2524 | allow_from_autoenv: bool = True,
2525 | type: t.Optional[t.Union[types.ParamType, t.Any]] = None,
2526 | help: t.Optional[str] = None,
2527 | hidden: bool = False,
2528 | show_choices: bool = True,
2529 | show_envvar: bool = False,
2530 | **attrs: t.Any,
2531 | ) -> None:
2532 | if help:
2533 | help = inspect.cleandoc(help)
2534 |
2535 | default_is_missing = "default" not in attrs
2536 | super().__init__(param_decls, type=type, multiple=multiple, **attrs)
2537 |
2538 | if prompt is True:
2539 | if self.name is None:
2540 | raise TypeError("'name' is required with 'prompt=True'.")
2541 |
2542 | prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize()
2543 | elif prompt is False:
2544 | prompt_text = None
2545 | else:
2546 | prompt_text = prompt
2547 |
2548 | self.prompt = prompt_text
2549 | self.confirmation_prompt = confirmation_prompt
2550 | self.prompt_required = prompt_required
2551 | self.hide_input = hide_input
2552 | self.hidden = hidden
2553 |
2554 | # If prompt is enabled but not required, then the option can be
2555 | # used as a flag to indicate using prompt or flag_value.
2556 | self._flag_needs_value = self.prompt is not None and not self.prompt_required
2557 |
2558 | if is_flag is None:
2559 | if flag_value is not None:
2560 | # Implicitly a flag because flag_value was set.
2561 | is_flag = True
2562 | elif self._flag_needs_value:
2563 | # Not a flag, but when used as a flag it shows a prompt.
2564 | is_flag = False
2565 | else:
2566 | # Implicitly a flag because flag options were given.
2567 | is_flag = bool(self.secondary_opts)
2568 | elif is_flag is False and not self._flag_needs_value:
2569 | # Not a flag, and prompt is not enabled, can be used as a
2570 | # flag if flag_value is set.
2571 | self._flag_needs_value = flag_value is not None
2572 |
2573 | self.default: t.Union[t.Any, t.Callable[[], t.Any]]
2574 |
2575 | if is_flag and default_is_missing and not self.required:
2576 | if multiple:
2577 | self.default = ()
2578 | else:
2579 | self.default = False
2580 |
2581 | if flag_value is None:
2582 | flag_value = not self.default
2583 |
2584 | self.type: types.ParamType
2585 | if is_flag and type is None:
2586 | # Re-guess the type from the flag value instead of the
2587 | # default.
2588 | self.type = types.convert_type(None, flag_value)
2589 |
2590 | self.is_flag: bool = is_flag
2591 | self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType)
2592 | self.flag_value: t.Any = flag_value
2593 |
2594 | # Counting
2595 | self.count = count
2596 | if count:
2597 | if type is None:
2598 | self.type = types.IntRange(min=0)
2599 | if default_is_missing:
2600 | self.default = 0
2601 |
2602 | self.allow_from_autoenv = allow_from_autoenv
2603 | self.help = help
2604 | self.show_default = show_default
2605 | self.show_choices = show_choices
2606 | self.show_envvar = show_envvar
2607 |
2608 | if __debug__:
2609 | if self.nargs == -1:
2610 | raise TypeError("nargs=-1 is not supported for options.")
2611 |
2612 | if self.prompt and self.is_flag and not self.is_bool_flag:
2613 | raise TypeError("'prompt' is not valid for non-boolean flag.")
2614 |
2615 | if not self.is_bool_flag and self.secondary_opts:
2616 | raise TypeError("Secondary flag is not valid for non-boolean flag.")
2617 |
2618 | if self.is_bool_flag and self.hide_input and self.prompt is not None:
2619 | raise TypeError(
2620 | "'prompt' with 'hide_input' is not valid for boolean flag."
2621 | )
2622 |
2623 | if self.count:
2624 | if self.multiple:
2625 | raise TypeError("'count' is not valid with 'multiple'.")
2626 |
2627 | if self.is_flag:
2628 | raise TypeError("'count' is not valid with 'is_flag'.")
2629 |
2630 | def to_info_dict(self) -> t.Dict[str, t.Any]:
2631 | info_dict = super().to_info_dict()
2632 | info_dict.update(
2633 | help=self.help,
2634 | prompt=self.prompt,
2635 | is_flag=self.is_flag,
2636 | flag_value=self.flag_value,
2637 | count=self.count,
2638 | hidden=self.hidden,
2639 | )
2640 | return info_dict
2641 |
2642 | def _parse_decls(
2643 | self, decls: t.Sequence[str], expose_value: bool
2644 | ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
2645 | opts = []
2646 | secondary_opts = []
2647 | name = None
2648 | possible_names = []
2649 |
2650 | for decl in decls:
2651 | if decl.isidentifier():
2652 | if name is not None:
2653 | raise TypeError(f"Name '{name}' defined twice")
2654 | name = decl
2655 | else:
2656 | split_char = ";" if decl[:1] == "/" else "/"
2657 | if split_char in decl:
2658 | first, second = decl.split(split_char, 1)
2659 | first = first.rstrip()
2660 | if first:
2661 | possible_names.append(split_opt(first))
2662 | opts.append(first)
2663 | second = second.lstrip()
2664 | if second:
2665 | secondary_opts.append(second.lstrip())
2666 | if first == second:
2667 | raise ValueError(
2668 | f"Boolean option {decl!r} cannot use the"
2669 | " same flag for true/false."
2670 | )
2671 | else:
2672 | possible_names.append(split_opt(decl))
2673 | opts.append(decl)
2674 |
2675 | if name is None and possible_names:
2676 | possible_names.sort(key=lambda x: -len(x[0])) # group long options first
2677 | name = possible_names[0][1].replace("-", "_").lower()
2678 | if not name.isidentifier():
2679 | name = None
2680 |
2681 | if name is None:
2682 | if not expose_value:
2683 | return None, opts, secondary_opts
2684 | raise TypeError("Could not determine name for option")
2685 |
2686 | if not opts and not secondary_opts:
2687 | raise TypeError(
2688 | f"No options defined but a name was passed ({name})."
2689 | " Did you mean to declare an argument instead? Did"
2690 | f" you mean to pass '--{name}'?"
2691 | )
2692 |
2693 | return name, opts, secondary_opts
2694 |
2695 | def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
2696 | if self.multiple:
2697 | action = "append"
2698 | elif self.count:
2699 | action = "count"
2700 | else:
2701 | action = "store"
2702 |
2703 | if self.is_flag:
2704 | action = f"{action}_const"
2705 |
2706 | if self.is_bool_flag and self.secondary_opts:
2707 | parser.add_option(
2708 | obj=self, opts=self.opts, dest=self.name, action=action, const=True
2709 | )
2710 | parser.add_option(
2711 | obj=self,
2712 | opts=self.secondary_opts,
2713 | dest=self.name,
2714 | action=action,
2715 | const=False,
2716 | )
2717 | else:
2718 | parser.add_option(
2719 | obj=self,
2720 | opts=self.opts,
2721 | dest=self.name,
2722 | action=action,
2723 | const=self.flag_value,
2724 | )
2725 | else:
2726 | parser.add_option(
2727 | obj=self,
2728 | opts=self.opts,
2729 | dest=self.name,
2730 | action=action,
2731 | nargs=self.nargs,
2732 | )
2733 |
2734 | def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]:
2735 | if self.hidden:
2736 | return None
2737 |
2738 | any_prefix_is_slash = False
2739 |
2740 | def _write_opts(opts: t.Sequence[str]) -> str:
2741 | nonlocal any_prefix_is_slash
2742 |
2743 | rv, any_slashes = join_options(opts)
2744 |
2745 | if any_slashes:
2746 | any_prefix_is_slash = True
2747 |
2748 | if not self.is_flag and not self.count:
2749 | rv += f" {self.make_metavar()}"
2750 |
2751 | return rv
2752 |
2753 | rv = [_write_opts(self.opts)]
2754 |
2755 | if self.secondary_opts:
2756 | rv.append(_write_opts(self.secondary_opts))
2757 |
2758 | help = self.help or ""
2759 | extra = []
2760 |
2761 | if self.show_envvar:
2762 | envvar = self.envvar
2763 |
2764 | if envvar is None:
2765 | if (
2766 | self.allow_from_autoenv
2767 | and ctx.auto_envvar_prefix is not None
2768 | and self.name is not None
2769 | ):
2770 | envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}"
2771 |
2772 | if envvar is not None:
2773 | var_str = (
2774 | envvar
2775 | if isinstance(envvar, str)
2776 | else ", ".join(str(d) for d in envvar)
2777 | )
2778 | extra.append(_("env var: {var}").format(var=var_str))
2779 |
2780 | # Temporarily enable resilient parsing to avoid type casting
2781 | # failing for the default. Might be possible to extend this to
2782 | # help formatting in general.
2783 | resilient = ctx.resilient_parsing
2784 | ctx.resilient_parsing = True
2785 |
2786 | try:
2787 | default_value = self.get_default(ctx, call=False)
2788 | finally:
2789 | ctx.resilient_parsing = resilient
2790 |
2791 | show_default = False
2792 | show_default_is_str = False
2793 |
2794 | if self.show_default is not None:
2795 | if isinstance(self.show_default, str):
2796 | show_default_is_str = show_default = True
2797 | else:
2798 | show_default = self.show_default
2799 | elif ctx.show_default is not None:
2800 | show_default = ctx.show_default
2801 |
2802 | if show_default_is_str or (show_default and (default_value is not None)):
2803 | if show_default_is_str:
2804 | default_string = f"({self.show_default})"
2805 | elif isinstance(default_value, (list, tuple)):
2806 | default_string = ", ".join(str(d) for d in default_value)
2807 | elif inspect.isfunction(default_value):
2808 | default_string = _("(dynamic)")
2809 | elif self.is_bool_flag and self.secondary_opts:
2810 | # For boolean flags that have distinct True/False opts,
2811 | # use the opt without prefix instead of the value.
2812 | default_string = split_opt(
2813 | (self.opts if self.default else self.secondary_opts)[0]
2814 | )[1]
2815 | elif self.is_bool_flag and not self.secondary_opts and not default_value:
2816 | default_string = ""
2817 | else:
2818 | default_string = str(default_value)
2819 |
2820 | if default_string:
2821 | extra.append(_("default: {default}").format(default=default_string))
2822 |
2823 | if (
2824 | isinstance(self.type, types._NumberRangeBase)
2825 | # skip count with default range type
2826 | and not (self.count and self.type.min == 0 and self.type.max is None)
2827 | ):
2828 | range_str = self.type._describe_range()
2829 |
2830 | if range_str:
2831 | extra.append(range_str)
2832 |
2833 | if self.required:
2834 | extra.append(_("required"))
2835 |
2836 | if extra:
2837 | extra_str = "; ".join(extra)
2838 | help = f"{help} [{extra_str}]" if help else f"[{extra_str}]"
2839 |
2840 | return ("; " if any_prefix_is_slash else " / ").join(rv), help
2841 |
2842 | @t.overload
2843 | def get_default(
2844 | self, ctx: Context, call: "te.Literal[True]" = True
2845 | ) -> t.Optional[t.Any]:
2846 | ...
2847 |
2848 | @t.overload
2849 | def get_default(
2850 | self, ctx: Context, call: bool = ...
2851 | ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
2852 | ...
2853 |
2854 | def get_default(
2855 | self, ctx: Context, call: bool = True
2856 | ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]:
2857 | # If we're a non boolean flag our default is more complex because
2858 | # we need to look at all flags in the same group to figure out
2859 | # if we're the default one in which case we return the flag
2860 | # value as default.
2861 | if self.is_flag and not self.is_bool_flag:
2862 | for param in ctx.command.params:
2863 | if param.name == self.name and param.default:
2864 | return t.cast(Option, param).flag_value
2865 |
2866 | return None
2867 |
2868 | return super().get_default(ctx, call=call)
2869 |
2870 | def prompt_for_value(self, ctx: Context) -> t.Any:
2871 | """This is an alternative flow that can be activated in the full
2872 | value processing if a value does not exist. It will prompt the
2873 | user until a valid value exists and then returns the processed
2874 | value as result.
2875 | """
2876 | assert self.prompt is not None
2877 |
2878 | # Calculate the default before prompting anything to be stable.
2879 | default = self.get_default(ctx)
2880 |
2881 | # If this is a prompt for a flag we need to handle this
2882 | # differently.
2883 | if self.is_bool_flag:
2884 | return confirm(self.prompt, default)
2885 |
2886 | return prompt(
2887 | self.prompt,
2888 | default=default,
2889 | type=self.type,
2890 | hide_input=self.hide_input,
2891 | show_choices=self.show_choices,
2892 | confirmation_prompt=self.confirmation_prompt,
2893 | value_proc=lambda x: self.process_value(ctx, x),
2894 | )
2895 |
2896 | def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]:
2897 | rv = super().resolve_envvar_value(ctx)
2898 |
2899 | if rv is not None:
2900 | return rv
2901 |
2902 | if (
2903 | self.allow_from_autoenv
2904 | and ctx.auto_envvar_prefix is not None
2905 | and self.name is not None
2906 | ):
2907 | envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}"
2908 | rv = os.environ.get(envvar)
2909 |
2910 | if rv:
2911 | return rv
2912 |
2913 | return None
2914 |
2915 | def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]:
2916 | rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx)
2917 |
2918 | if rv is None:
2919 | return None
2920 |
2921 | value_depth = (self.nargs != 1) + bool(self.multiple)
2922 |
2923 | if value_depth > 0:
2924 | rv = self.type.split_envvar_value(rv)
2925 |
2926 | if self.multiple and self.nargs != 1:
2927 | rv = batch(rv, self.nargs)
2928 |
2929 | return rv
2930 |
2931 | def consume_value(
2932 | self, ctx: Context, opts: t.Mapping[str, "Parameter"]
2933 | ) -> t.Tuple[t.Any, ParameterSource]:
2934 | value, source = super().consume_value(ctx, opts)
2935 |
2936 | # The parser will emit a sentinel value if the option can be
2937 | # given as a flag without a value. This is different from None
2938 | # to distinguish from the flag not being given at all.
2939 | if value is _flag_needs_value:
2940 | if self.prompt is not None and not ctx.resilient_parsing:
2941 | value = self.prompt_for_value(ctx)
2942 | source = ParameterSource.PROMPT
2943 | else:
2944 | value = self.flag_value
2945 | source = ParameterSource.COMMANDLINE
2946 |
2947 | elif (
2948 | self.multiple
2949 | and value is not None
2950 | and any(v is _flag_needs_value for v in value)
2951 | ):
2952 | value = [self.flag_value if v is _flag_needs_value else v for v in value]
2953 | source = ParameterSource.COMMANDLINE
2954 |
2955 | # The value wasn't set, or used the param's default, prompt if
2956 | # prompting is enabled.
2957 | elif (
2958 | source in {None, ParameterSource.DEFAULT}
2959 | and self.prompt is not None
2960 | and (self.required or self.prompt_required)
2961 | and not ctx.resilient_parsing
2962 | ):
2963 | value = self.prompt_for_value(ctx)
2964 | source = ParameterSource.PROMPT
2965 |
2966 | return value, source
2967 |
2968 |
2969 | class Argument(Parameter):
2970 | """Arguments are positional parameters to a command. They generally
2971 | provide fewer features than options but can have infinite ``nargs``
2972 | and are required by default.
2973 |
2974 | All parameters are passed onwards to the constructor of :class:`Parameter`.
2975 | """
2976 |
2977 | param_type_name = "argument"
2978 |
2979 | def __init__(
2980 | self,
2981 | param_decls: t.Sequence[str],
2982 | required: t.Optional[bool] = None,
2983 | **attrs: t.Any,
2984 | ) -> None:
2985 | if required is None:
2986 | if attrs.get("default") is not None:
2987 | required = False
2988 | else:
2989 | required = attrs.get("nargs", 1) > 0
2990 |
2991 | if "multiple" in attrs:
2992 | raise TypeError("__init__() got an unexpected keyword argument 'multiple'.")
2993 |
2994 | super().__init__(param_decls, required=required, **attrs)
2995 |
2996 | if __debug__:
2997 | if self.default is not None and self.nargs == -1:
2998 | raise TypeError("'default' is not supported for nargs=-1.")
2999 |
3000 | @property
3001 | def human_readable_name(self) -> str:
3002 | if self.metavar is not None:
3003 | return self.metavar
3004 | return self.name.upper() # type: ignore
3005 |
3006 | def make_metavar(self) -> str:
3007 | if self.metavar is not None:
3008 | return self.metavar
3009 | var = self.type.get_metavar(self)
3010 | if not var:
3011 | var = self.name.upper() # type: ignore
3012 | if not self.required:
3013 | var = f"[{var}]"
3014 | if self.nargs != 1:
3015 | var += "..."
3016 | return var
3017 |
3018 | def _parse_decls(
3019 | self, decls: t.Sequence[str], expose_value: bool
3020 | ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]:
3021 | if not decls:
3022 | if not expose_value:
3023 | return None, [], []
3024 | raise TypeError("Could not determine name for argument")
3025 | if len(decls) == 1:
3026 | name = arg = decls[0]
3027 | name = name.replace("-", "_").lower()
3028 | else:
3029 | raise TypeError(
3030 | "Arguments take exactly one parameter declaration, got"
3031 | f" {len(decls)}."
3032 | )
3033 | return name, [arg], []
3034 |
3035 | def get_usage_pieces(self, ctx: Context) -> t.List[str]:
3036 | return [self.make_metavar()]
3037 |
3038 | def get_error_hint(self, ctx: Context) -> str:
3039 | return f"'{self.make_metavar()}'"
3040 |
3041 | def add_to_parser(self, parser: OptionParser, ctx: Context) -> None:
3042 | parser.add_argument(dest=self.name, nargs=self.nargs, obj=self)
3043 |
```