This is page 89 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/pip/_internal/operations/prepare.py:
--------------------------------------------------------------------------------
```python
1 | """Prepares a distribution for installation
2 | """
3 |
4 | # The following comment should be removed at some point in the future.
5 | # mypy: strict-optional=False
6 |
7 | import mimetypes
8 | import os
9 | import shutil
10 | from dataclasses import dataclass
11 | from pathlib import Path
12 | from typing import Dict, Iterable, List, Optional
13 |
14 | from pip._vendor.packaging.utils import canonicalize_name
15 |
16 | from pip._internal.distributions import make_distribution_for_install_requirement
17 | from pip._internal.distributions.installed import InstalledDistribution
18 | from pip._internal.exceptions import (
19 | DirectoryUrlHashUnsupported,
20 | HashMismatch,
21 | HashUnpinned,
22 | InstallationError,
23 | MetadataInconsistent,
24 | NetworkConnectionError,
25 | VcsHashUnsupported,
26 | )
27 | from pip._internal.index.package_finder import PackageFinder
28 | from pip._internal.metadata import BaseDistribution, get_metadata_distribution
29 | from pip._internal.models.direct_url import ArchiveInfo
30 | from pip._internal.models.link import Link
31 | from pip._internal.models.wheel import Wheel
32 | from pip._internal.network.download import BatchDownloader, Downloader
33 | from pip._internal.network.lazy_wheel import (
34 | HTTPRangeRequestUnsupported,
35 | dist_from_wheel_url,
36 | )
37 | from pip._internal.network.session import PipSession
38 | from pip._internal.operations.build.build_tracker import BuildTracker
39 | from pip._internal.req.req_install import InstallRequirement
40 | from pip._internal.utils._log import getLogger
41 | from pip._internal.utils.direct_url_helpers import (
42 | direct_url_for_editable,
43 | direct_url_from_link,
44 | )
45 | from pip._internal.utils.hashes import Hashes, MissingHashes
46 | from pip._internal.utils.logging import indent_log
47 | from pip._internal.utils.misc import (
48 | display_path,
49 | hash_file,
50 | hide_url,
51 | redact_auth_from_requirement,
52 | )
53 | from pip._internal.utils.temp_dir import TempDirectory
54 | from pip._internal.utils.unpacking import unpack_file
55 | from pip._internal.vcs import vcs
56 |
57 | logger = getLogger(__name__)
58 |
59 |
60 | def _get_prepared_distribution(
61 | req: InstallRequirement,
62 | build_tracker: BuildTracker,
63 | finder: PackageFinder,
64 | build_isolation: bool,
65 | check_build_deps: bool,
66 | ) -> BaseDistribution:
67 | """Prepare a distribution for installation."""
68 | abstract_dist = make_distribution_for_install_requirement(req)
69 | tracker_id = abstract_dist.build_tracker_id
70 | if tracker_id is not None:
71 | with build_tracker.track(req, tracker_id):
72 | abstract_dist.prepare_distribution_metadata(
73 | finder, build_isolation, check_build_deps
74 | )
75 | return abstract_dist.get_metadata_distribution()
76 |
77 |
78 | def unpack_vcs_link(link: Link, location: str, verbosity: int) -> None:
79 | vcs_backend = vcs.get_backend_for_scheme(link.scheme)
80 | assert vcs_backend is not None
81 | vcs_backend.unpack(location, url=hide_url(link.url), verbosity=verbosity)
82 |
83 |
84 | @dataclass
85 | class File:
86 | path: str
87 | content_type: Optional[str] = None
88 |
89 | def __post_init__(self) -> None:
90 | if self.content_type is None:
91 | self.content_type = mimetypes.guess_type(self.path)[0]
92 |
93 |
94 | def get_http_url(
95 | link: Link,
96 | download: Downloader,
97 | download_dir: Optional[str] = None,
98 | hashes: Optional[Hashes] = None,
99 | ) -> File:
100 | temp_dir = TempDirectory(kind="unpack", globally_managed=True)
101 | # If a download dir is specified, is the file already downloaded there?
102 | already_downloaded_path = None
103 | if download_dir:
104 | already_downloaded_path = _check_download_dir(link, download_dir, hashes)
105 |
106 | if already_downloaded_path:
107 | from_path = already_downloaded_path
108 | content_type = None
109 | else:
110 | # let's download to a tmp dir
111 | from_path, content_type = download(link, temp_dir.path)
112 | if hashes:
113 | hashes.check_against_path(from_path)
114 |
115 | return File(from_path, content_type)
116 |
117 |
118 | def get_file_url(
119 | link: Link, download_dir: Optional[str] = None, hashes: Optional[Hashes] = None
120 | ) -> File:
121 | """Get file and optionally check its hash."""
122 | # If a download dir is specified, is the file already there and valid?
123 | already_downloaded_path = None
124 | if download_dir:
125 | already_downloaded_path = _check_download_dir(link, download_dir, hashes)
126 |
127 | if already_downloaded_path:
128 | from_path = already_downloaded_path
129 | else:
130 | from_path = link.file_path
131 |
132 | # If --require-hashes is off, `hashes` is either empty, the
133 | # link's embedded hash, or MissingHashes; it is required to
134 | # match. If --require-hashes is on, we are satisfied by any
135 | # hash in `hashes` matching: a URL-based or an option-based
136 | # one; no internet-sourced hash will be in `hashes`.
137 | if hashes:
138 | hashes.check_against_path(from_path)
139 | return File(from_path, None)
140 |
141 |
142 | def unpack_url(
143 | link: Link,
144 | location: str,
145 | download: Downloader,
146 | verbosity: int,
147 | download_dir: Optional[str] = None,
148 | hashes: Optional[Hashes] = None,
149 | ) -> Optional[File]:
150 | """Unpack link into location, downloading if required.
151 |
152 | :param hashes: A Hashes object, one of whose embedded hashes must match,
153 | or HashMismatch will be raised. If the Hashes is empty, no matches are
154 | required, and unhashable types of requirements (like VCS ones, which
155 | would ordinarily raise HashUnsupported) are allowed.
156 | """
157 | # non-editable vcs urls
158 | if link.is_vcs:
159 | unpack_vcs_link(link, location, verbosity=verbosity)
160 | return None
161 |
162 | assert not link.is_existing_dir()
163 |
164 | # file urls
165 | if link.is_file:
166 | file = get_file_url(link, download_dir, hashes=hashes)
167 |
168 | # http urls
169 | else:
170 | file = get_http_url(
171 | link,
172 | download,
173 | download_dir,
174 | hashes=hashes,
175 | )
176 |
177 | # unpack the archive to the build dir location. even when only downloading
178 | # archives, they have to be unpacked to parse dependencies, except wheels
179 | if not link.is_wheel:
180 | unpack_file(file.path, location, file.content_type)
181 |
182 | return file
183 |
184 |
185 | def _check_download_dir(
186 | link: Link,
187 | download_dir: str,
188 | hashes: Optional[Hashes],
189 | warn_on_hash_mismatch: bool = True,
190 | ) -> Optional[str]:
191 | """Check download_dir for previously downloaded file with correct hash
192 | If a correct file is found return its path else None
193 | """
194 | download_path = os.path.join(download_dir, link.filename)
195 |
196 | if not os.path.exists(download_path):
197 | return None
198 |
199 | # If already downloaded, does its hash match?
200 | logger.info("File was already downloaded %s", download_path)
201 | if hashes:
202 | try:
203 | hashes.check_against_path(download_path)
204 | except HashMismatch:
205 | if warn_on_hash_mismatch:
206 | logger.warning(
207 | "Previously-downloaded file %s has bad hash. Re-downloading.",
208 | download_path,
209 | )
210 | os.unlink(download_path)
211 | return None
212 | return download_path
213 |
214 |
215 | class RequirementPreparer:
216 | """Prepares a Requirement"""
217 |
218 | def __init__(
219 | self,
220 | build_dir: str,
221 | download_dir: Optional[str],
222 | src_dir: str,
223 | build_isolation: bool,
224 | check_build_deps: bool,
225 | build_tracker: BuildTracker,
226 | session: PipSession,
227 | progress_bar: str,
228 | finder: PackageFinder,
229 | require_hashes: bool,
230 | use_user_site: bool,
231 | lazy_wheel: bool,
232 | verbosity: int,
233 | legacy_resolver: bool,
234 | ) -> None:
235 | super().__init__()
236 |
237 | self.src_dir = src_dir
238 | self.build_dir = build_dir
239 | self.build_tracker = build_tracker
240 | self._session = session
241 | self._download = Downloader(session, progress_bar)
242 | self._batch_download = BatchDownloader(session, progress_bar)
243 | self.finder = finder
244 |
245 | # Where still-packed archives should be written to. If None, they are
246 | # not saved, and are deleted immediately after unpacking.
247 | self.download_dir = download_dir
248 |
249 | # Is build isolation allowed?
250 | self.build_isolation = build_isolation
251 |
252 | # Should check build dependencies?
253 | self.check_build_deps = check_build_deps
254 |
255 | # Should hash-checking be required?
256 | self.require_hashes = require_hashes
257 |
258 | # Should install in user site-packages?
259 | self.use_user_site = use_user_site
260 |
261 | # Should wheels be downloaded lazily?
262 | self.use_lazy_wheel = lazy_wheel
263 |
264 | # How verbose should underlying tooling be?
265 | self.verbosity = verbosity
266 |
267 | # Are we using the legacy resolver?
268 | self.legacy_resolver = legacy_resolver
269 |
270 | # Memoized downloaded files, as mapping of url: path.
271 | self._downloaded: Dict[str, str] = {}
272 |
273 | # Previous "header" printed for a link-based InstallRequirement
274 | self._previous_requirement_header = ("", "")
275 |
276 | def _log_preparing_link(self, req: InstallRequirement) -> None:
277 | """Provide context for the requirement being prepared."""
278 | if req.link.is_file and not req.is_wheel_from_cache:
279 | message = "Processing %s"
280 | information = str(display_path(req.link.file_path))
281 | else:
282 | message = "Collecting %s"
283 | information = redact_auth_from_requirement(req.req) if req.req else str(req)
284 |
285 | # If we used req.req, inject requirement source if available (this
286 | # would already be included if we used req directly)
287 | if req.req and req.comes_from:
288 | if isinstance(req.comes_from, str):
289 | comes_from: Optional[str] = req.comes_from
290 | else:
291 | comes_from = req.comes_from.from_path()
292 | if comes_from:
293 | information += f" (from {comes_from})"
294 |
295 | if (message, information) != self._previous_requirement_header:
296 | self._previous_requirement_header = (message, information)
297 | logger.info(message, information)
298 |
299 | if req.is_wheel_from_cache:
300 | with indent_log():
301 | logger.info("Using cached %s", req.link.filename)
302 |
303 | def _ensure_link_req_src_dir(
304 | self, req: InstallRequirement, parallel_builds: bool
305 | ) -> None:
306 | """Ensure source_dir of a linked InstallRequirement."""
307 | # Since source_dir is only set for editable requirements.
308 | if req.link.is_wheel:
309 | # We don't need to unpack wheels, so no need for a source
310 | # directory.
311 | return
312 | assert req.source_dir is None
313 | if req.link.is_existing_dir():
314 | # build local directories in-tree
315 | req.source_dir = req.link.file_path
316 | return
317 |
318 | # We always delete unpacked sdists after pip runs.
319 | req.ensure_has_source_dir(
320 | self.build_dir,
321 | autodelete=True,
322 | parallel_builds=parallel_builds,
323 | )
324 | req.ensure_pristine_source_checkout()
325 |
326 | def _get_linked_req_hashes(self, req: InstallRequirement) -> Hashes:
327 | # By the time this is called, the requirement's link should have
328 | # been checked so we can tell what kind of requirements req is
329 | # and raise some more informative errors than otherwise.
330 | # (For example, we can raise VcsHashUnsupported for a VCS URL
331 | # rather than HashMissing.)
332 | if not self.require_hashes:
333 | return req.hashes(trust_internet=True)
334 |
335 | # We could check these first 2 conditions inside unpack_url
336 | # and save repetition of conditions, but then we would
337 | # report less-useful error messages for unhashable
338 | # requirements, complaining that there's no hash provided.
339 | if req.link.is_vcs:
340 | raise VcsHashUnsupported()
341 | if req.link.is_existing_dir():
342 | raise DirectoryUrlHashUnsupported()
343 |
344 | # Unpinned packages are asking for trouble when a new version
345 | # is uploaded. This isn't a security check, but it saves users
346 | # a surprising hash mismatch in the future.
347 | # file:/// URLs aren't pinnable, so don't complain about them
348 | # not being pinned.
349 | if not req.is_direct and not req.is_pinned:
350 | raise HashUnpinned()
351 |
352 | # If known-good hashes are missing for this requirement,
353 | # shim it with a facade object that will provoke hash
354 | # computation and then raise a HashMissing exception
355 | # showing the user what the hash should be.
356 | return req.hashes(trust_internet=False) or MissingHashes()
357 |
358 | def _fetch_metadata_only(
359 | self,
360 | req: InstallRequirement,
361 | ) -> Optional[BaseDistribution]:
362 | if self.legacy_resolver:
363 | logger.debug(
364 | "Metadata-only fetching is not used in the legacy resolver",
365 | )
366 | return None
367 | if self.require_hashes:
368 | logger.debug(
369 | "Metadata-only fetching is not used as hash checking is required",
370 | )
371 | return None
372 | # Try PEP 658 metadata first, then fall back to lazy wheel if unavailable.
373 | return self._fetch_metadata_using_link_data_attr(
374 | req
375 | ) or self._fetch_metadata_using_lazy_wheel(req.link)
376 |
377 | def _fetch_metadata_using_link_data_attr(
378 | self,
379 | req: InstallRequirement,
380 | ) -> Optional[BaseDistribution]:
381 | """Fetch metadata from the data-dist-info-metadata attribute, if possible."""
382 | # (1) Get the link to the metadata file, if provided by the backend.
383 | metadata_link = req.link.metadata_link()
384 | if metadata_link is None:
385 | return None
386 | assert req.req is not None
387 | logger.verbose(
388 | "Obtaining dependency information for %s from %s",
389 | req.req,
390 | metadata_link,
391 | )
392 | # (2) Download the contents of the METADATA file, separate from the dist itself.
393 | metadata_file = get_http_url(
394 | metadata_link,
395 | self._download,
396 | hashes=metadata_link.as_hashes(),
397 | )
398 | with open(metadata_file.path, "rb") as f:
399 | metadata_contents = f.read()
400 | # (3) Generate a dist just from those file contents.
401 | metadata_dist = get_metadata_distribution(
402 | metadata_contents,
403 | req.link.filename,
404 | req.req.name,
405 | )
406 | # (4) Ensure the Name: field from the METADATA file matches the name from the
407 | # install requirement.
408 | #
409 | # NB: raw_name will fall back to the name from the install requirement if
410 | # the Name: field is not present, but it's noted in the raw_name docstring
411 | # that that should NEVER happen anyway.
412 | if canonicalize_name(metadata_dist.raw_name) != canonicalize_name(req.req.name):
413 | raise MetadataInconsistent(
414 | req, "Name", req.req.name, metadata_dist.raw_name
415 | )
416 | return metadata_dist
417 |
418 | def _fetch_metadata_using_lazy_wheel(
419 | self,
420 | link: Link,
421 | ) -> Optional[BaseDistribution]:
422 | """Fetch metadata using lazy wheel, if possible."""
423 | # --use-feature=fast-deps must be provided.
424 | if not self.use_lazy_wheel:
425 | return None
426 | if link.is_file or not link.is_wheel:
427 | logger.debug(
428 | "Lazy wheel is not used as %r does not point to a remote wheel",
429 | link,
430 | )
431 | return None
432 |
433 | wheel = Wheel(link.filename)
434 | name = canonicalize_name(wheel.name)
435 | logger.info(
436 | "Obtaining dependency information from %s %s",
437 | name,
438 | wheel.version,
439 | )
440 | url = link.url.split("#", 1)[0]
441 | try:
442 | return dist_from_wheel_url(name, url, self._session)
443 | except HTTPRangeRequestUnsupported:
444 | logger.debug("%s does not support range requests", url)
445 | return None
446 |
447 | def _complete_partial_requirements(
448 | self,
449 | partially_downloaded_reqs: Iterable[InstallRequirement],
450 | parallel_builds: bool = False,
451 | ) -> None:
452 | """Download any requirements which were only fetched by metadata."""
453 | # Download to a temporary directory. These will be copied over as
454 | # needed for downstream 'download', 'wheel', and 'install' commands.
455 | temp_dir = TempDirectory(kind="unpack", globally_managed=True).path
456 |
457 | # Map each link to the requirement that owns it. This allows us to set
458 | # `req.local_file_path` on the appropriate requirement after passing
459 | # all the links at once into BatchDownloader.
460 | links_to_fully_download: Dict[Link, InstallRequirement] = {}
461 | for req in partially_downloaded_reqs:
462 | assert req.link
463 | links_to_fully_download[req.link] = req
464 |
465 | batch_download = self._batch_download(
466 | links_to_fully_download.keys(),
467 | temp_dir,
468 | )
469 | for link, (filepath, _) in batch_download:
470 | logger.debug("Downloading link %s to %s", link, filepath)
471 | req = links_to_fully_download[link]
472 | # Record the downloaded file path so wheel reqs can extract a Distribution
473 | # in .get_dist().
474 | req.local_file_path = filepath
475 | # Record that the file is downloaded so we don't do it again in
476 | # _prepare_linked_requirement().
477 | self._downloaded[req.link.url] = filepath
478 |
479 | # If this is an sdist, we need to unpack it after downloading, but the
480 | # .source_dir won't be set up until we are in _prepare_linked_requirement().
481 | # Add the downloaded archive to the install requirement to unpack after
482 | # preparing the source dir.
483 | if not req.is_wheel:
484 | req.needs_unpacked_archive(Path(filepath))
485 |
486 | # This step is necessary to ensure all lazy wheels are processed
487 | # successfully by the 'download', 'wheel', and 'install' commands.
488 | for req in partially_downloaded_reqs:
489 | self._prepare_linked_requirement(req, parallel_builds)
490 |
491 | def prepare_linked_requirement(
492 | self, req: InstallRequirement, parallel_builds: bool = False
493 | ) -> BaseDistribution:
494 | """Prepare a requirement to be obtained from req.link."""
495 | assert req.link
496 | self._log_preparing_link(req)
497 | with indent_log():
498 | # Check if the relevant file is already available
499 | # in the download directory
500 | file_path = None
501 | if self.download_dir is not None and req.link.is_wheel:
502 | hashes = self._get_linked_req_hashes(req)
503 | file_path = _check_download_dir(
504 | req.link,
505 | self.download_dir,
506 | hashes,
507 | # When a locally built wheel has been found in cache, we don't warn
508 | # about re-downloading when the already downloaded wheel hash does
509 | # not match. This is because the hash must be checked against the
510 | # original link, not the cached link. It that case the already
511 | # downloaded file will be removed and re-fetched from cache (which
512 | # implies a hash check against the cache entry's origin.json).
513 | warn_on_hash_mismatch=not req.is_wheel_from_cache,
514 | )
515 |
516 | if file_path is not None:
517 | # The file is already available, so mark it as downloaded
518 | self._downloaded[req.link.url] = file_path
519 | else:
520 | # The file is not available, attempt to fetch only metadata
521 | metadata_dist = self._fetch_metadata_only(req)
522 | if metadata_dist is not None:
523 | req.needs_more_preparation = True
524 | return metadata_dist
525 |
526 | # None of the optimizations worked, fully prepare the requirement
527 | return self._prepare_linked_requirement(req, parallel_builds)
528 |
529 | def prepare_linked_requirements_more(
530 | self, reqs: Iterable[InstallRequirement], parallel_builds: bool = False
531 | ) -> None:
532 | """Prepare linked requirements more, if needed."""
533 | reqs = [req for req in reqs if req.needs_more_preparation]
534 | for req in reqs:
535 | # Determine if any of these requirements were already downloaded.
536 | if self.download_dir is not None and req.link.is_wheel:
537 | hashes = self._get_linked_req_hashes(req)
538 | file_path = _check_download_dir(req.link, self.download_dir, hashes)
539 | if file_path is not None:
540 | self._downloaded[req.link.url] = file_path
541 | req.needs_more_preparation = False
542 |
543 | # Prepare requirements we found were already downloaded for some
544 | # reason. The other downloads will be completed separately.
545 | partially_downloaded_reqs: List[InstallRequirement] = []
546 | for req in reqs:
547 | if req.needs_more_preparation:
548 | partially_downloaded_reqs.append(req)
549 | else:
550 | self._prepare_linked_requirement(req, parallel_builds)
551 |
552 | # TODO: separate this part out from RequirementPreparer when the v1
553 | # resolver can be removed!
554 | self._complete_partial_requirements(
555 | partially_downloaded_reqs,
556 | parallel_builds=parallel_builds,
557 | )
558 |
559 | def _prepare_linked_requirement(
560 | self, req: InstallRequirement, parallel_builds: bool
561 | ) -> BaseDistribution:
562 | assert req.link
563 | link = req.link
564 |
565 | hashes = self._get_linked_req_hashes(req)
566 |
567 | if hashes and req.is_wheel_from_cache:
568 | assert req.download_info is not None
569 | assert link.is_wheel
570 | assert link.is_file
571 | # We need to verify hashes, and we have found the requirement in the cache
572 | # of locally built wheels.
573 | if (
574 | isinstance(req.download_info.info, ArchiveInfo)
575 | and req.download_info.info.hashes
576 | and hashes.has_one_of(req.download_info.info.hashes)
577 | ):
578 | # At this point we know the requirement was built from a hashable source
579 | # artifact, and we verified that the cache entry's hash of the original
580 | # artifact matches one of the hashes we expect. We don't verify hashes
581 | # against the cached wheel, because the wheel is not the original.
582 | hashes = None
583 | else:
584 | logger.warning(
585 | "The hashes of the source archive found in cache entry "
586 | "don't match, ignoring cached built wheel "
587 | "and re-downloading source."
588 | )
589 | req.link = req.cached_wheel_source_link
590 | link = req.link
591 |
592 | self._ensure_link_req_src_dir(req, parallel_builds)
593 |
594 | if link.is_existing_dir():
595 | local_file = None
596 | elif link.url not in self._downloaded:
597 | try:
598 | local_file = unpack_url(
599 | link,
600 | req.source_dir,
601 | self._download,
602 | self.verbosity,
603 | self.download_dir,
604 | hashes,
605 | )
606 | except NetworkConnectionError as exc:
607 | raise InstallationError(
608 | f"Could not install requirement {req} because of HTTP "
609 | f"error {exc} for URL {link}"
610 | )
611 | else:
612 | file_path = self._downloaded[link.url]
613 | if hashes:
614 | hashes.check_against_path(file_path)
615 | local_file = File(file_path, content_type=None)
616 |
617 | # If download_info is set, we got it from the wheel cache.
618 | if req.download_info is None:
619 | # Editables don't go through this function (see
620 | # prepare_editable_requirement).
621 | assert not req.editable
622 | req.download_info = direct_url_from_link(link, req.source_dir)
623 | # Make sure we have a hash in download_info. If we got it as part of the
624 | # URL, it will have been verified and we can rely on it. Otherwise we
625 | # compute it from the downloaded file.
626 | # FIXME: https://github.com/pypa/pip/issues/11943
627 | if (
628 | isinstance(req.download_info.info, ArchiveInfo)
629 | and not req.download_info.info.hashes
630 | and local_file
631 | ):
632 | hash = hash_file(local_file.path)[0].hexdigest()
633 | # We populate info.hash for backward compatibility.
634 | # This will automatically populate info.hashes.
635 | req.download_info.info.hash = f"sha256={hash}"
636 |
637 | # For use in later processing,
638 | # preserve the file path on the requirement.
639 | if local_file:
640 | req.local_file_path = local_file.path
641 |
642 | dist = _get_prepared_distribution(
643 | req,
644 | self.build_tracker,
645 | self.finder,
646 | self.build_isolation,
647 | self.check_build_deps,
648 | )
649 | return dist
650 |
651 | def save_linked_requirement(self, req: InstallRequirement) -> None:
652 | assert self.download_dir is not None
653 | assert req.link is not None
654 | link = req.link
655 | if link.is_vcs or (link.is_existing_dir() and req.editable):
656 | # Make a .zip of the source_dir we already created.
657 | req.archive(self.download_dir)
658 | return
659 |
660 | if link.is_existing_dir():
661 | logger.debug(
662 | "Not copying link to destination directory "
663 | "since it is a directory: %s",
664 | link,
665 | )
666 | return
667 | if req.local_file_path is None:
668 | # No distribution was downloaded for this requirement.
669 | return
670 |
671 | download_location = os.path.join(self.download_dir, link.filename)
672 | if not os.path.exists(download_location):
673 | shutil.copy(req.local_file_path, download_location)
674 | download_path = display_path(download_location)
675 | logger.info("Saved %s", download_path)
676 |
677 | def prepare_editable_requirement(
678 | self,
679 | req: InstallRequirement,
680 | ) -> BaseDistribution:
681 | """Prepare an editable requirement."""
682 | assert req.editable, "cannot prepare a non-editable req as editable"
683 |
684 | logger.info("Obtaining %s", req)
685 |
686 | with indent_log():
687 | if self.require_hashes:
688 | raise InstallationError(
689 | f"The editable requirement {req} cannot be installed when "
690 | "requiring hashes, because there is no single file to "
691 | "hash."
692 | )
693 | req.ensure_has_source_dir(self.src_dir)
694 | req.update_editable()
695 | assert req.source_dir
696 | req.download_info = direct_url_for_editable(req.unpacked_source_directory)
697 |
698 | dist = _get_prepared_distribution(
699 | req,
700 | self.build_tracker,
701 | self.finder,
702 | self.build_isolation,
703 | self.check_build_deps,
704 | )
705 |
706 | req.check_if_exists(self.use_user_site)
707 |
708 | return dist
709 |
710 | def prepare_installed_requirement(
711 | self,
712 | req: InstallRequirement,
713 | skip_reason: str,
714 | ) -> BaseDistribution:
715 | """Prepare an already-installed requirement."""
716 | assert req.satisfied_by, "req should have been satisfied but isn't"
717 | assert skip_reason is not None, (
718 | "did not get skip reason skipped but req.satisfied_by "
719 | f"is set to {req.satisfied_by}"
720 | )
721 | logger.info(
722 | "Requirement %s: %s (%s)", skip_reason, req, req.satisfied_by.version
723 | )
724 | with indent_log():
725 | if self.require_hashes:
726 | logger.debug(
727 | "Since it is already installed, we are trusting this "
728 | "package without checking its hash. To ensure a "
729 | "completely repeatable environment, install into an "
730 | "empty virtualenv."
731 | )
732 | return InstalledDistribution(req).get_metadata_distribution()
733 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/click/termui.py:
--------------------------------------------------------------------------------
```python
1 | import inspect
2 | import io
3 | import itertools
4 | import sys
5 | import typing as t
6 | from gettext import gettext as _
7 |
8 | from ._compat import isatty
9 | from ._compat import strip_ansi
10 | from .exceptions import Abort
11 | from .exceptions import UsageError
12 | from .globals import resolve_color_default
13 | from .types import Choice
14 | from .types import convert_type
15 | from .types import ParamType
16 | from .utils import echo
17 | from .utils import LazyFile
18 |
19 | if t.TYPE_CHECKING:
20 | from ._termui_impl import ProgressBar
21 |
22 | V = t.TypeVar("V")
23 |
24 | # The prompt functions to use. The doc tools currently override these
25 | # functions to customize how they work.
26 | visible_prompt_func: t.Callable[[str], str] = input
27 |
28 | _ansi_colors = {
29 | "black": 30,
30 | "red": 31,
31 | "green": 32,
32 | "yellow": 33,
33 | "blue": 34,
34 | "magenta": 35,
35 | "cyan": 36,
36 | "white": 37,
37 | "reset": 39,
38 | "bright_black": 90,
39 | "bright_red": 91,
40 | "bright_green": 92,
41 | "bright_yellow": 93,
42 | "bright_blue": 94,
43 | "bright_magenta": 95,
44 | "bright_cyan": 96,
45 | "bright_white": 97,
46 | }
47 | _ansi_reset_all = "\033[0m"
48 |
49 |
50 | def hidden_prompt_func(prompt: str) -> str:
51 | import getpass
52 |
53 | return getpass.getpass(prompt)
54 |
55 |
56 | def _build_prompt(
57 | text: str,
58 | suffix: str,
59 | show_default: bool = False,
60 | default: t.Optional[t.Any] = None,
61 | show_choices: bool = True,
62 | type: t.Optional[ParamType] = None,
63 | ) -> str:
64 | prompt = text
65 | if type is not None and show_choices and isinstance(type, Choice):
66 | prompt += f" ({', '.join(map(str, type.choices))})"
67 | if default is not None and show_default:
68 | prompt = f"{prompt} [{_format_default(default)}]"
69 | return f"{prompt}{suffix}"
70 |
71 |
72 | def _format_default(default: t.Any) -> t.Any:
73 | if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"):
74 | return default.name
75 |
76 | return default
77 |
78 |
79 | def prompt(
80 | text: str,
81 | default: t.Optional[t.Any] = None,
82 | hide_input: bool = False,
83 | confirmation_prompt: t.Union[bool, str] = False,
84 | type: t.Optional[t.Union[ParamType, t.Any]] = None,
85 | value_proc: t.Optional[t.Callable[[str], t.Any]] = None,
86 | prompt_suffix: str = ": ",
87 | show_default: bool = True,
88 | err: bool = False,
89 | show_choices: bool = True,
90 | ) -> t.Any:
91 | """Prompts a user for input. This is a convenience function that can
92 | be used to prompt a user for input later.
93 |
94 | If the user aborts the input by sending an interrupt signal, this
95 | function will catch it and raise a :exc:`Abort` exception.
96 |
97 | :param text: the text to show for the prompt.
98 | :param default: the default value to use if no input happens. If this
99 | is not given it will prompt until it's aborted.
100 | :param hide_input: if this is set to true then the input value will
101 | be hidden.
102 | :param confirmation_prompt: Prompt a second time to confirm the
103 | value. Can be set to a string instead of ``True`` to customize
104 | the message.
105 | :param type: the type to use to check the value against.
106 | :param value_proc: if this parameter is provided it's a function that
107 | is invoked instead of the type conversion to
108 | convert a value.
109 | :param prompt_suffix: a suffix that should be added to the prompt.
110 | :param show_default: shows or hides the default value in the prompt.
111 | :param err: if set to true the file defaults to ``stderr`` instead of
112 | ``stdout``, the same as with echo.
113 | :param show_choices: Show or hide choices if the passed type is a Choice.
114 | For example if type is a Choice of either day or week,
115 | show_choices is true and text is "Group by" then the
116 | prompt will be "Group by (day, week): ".
117 |
118 | .. versionadded:: 8.0
119 | ``confirmation_prompt`` can be a custom string.
120 |
121 | .. versionadded:: 7.0
122 | Added the ``show_choices`` parameter.
123 |
124 | .. versionadded:: 6.0
125 | Added unicode support for cmd.exe on Windows.
126 |
127 | .. versionadded:: 4.0
128 | Added the `err` parameter.
129 |
130 | """
131 |
132 | def prompt_func(text: str) -> str:
133 | f = hidden_prompt_func if hide_input else visible_prompt_func
134 | try:
135 | # Write the prompt separately so that we get nice
136 | # coloring through colorama on Windows
137 | echo(text.rstrip(" "), nl=False, err=err)
138 | # Echo a space to stdout to work around an issue where
139 | # readline causes backspace to clear the whole line.
140 | return f(" ")
141 | except (KeyboardInterrupt, EOFError):
142 | # getpass doesn't print a newline if the user aborts input with ^C.
143 | # Allegedly this behavior is inherited from getpass(3).
144 | # A doc bug has been filed at https://bugs.python.org/issue24711
145 | if hide_input:
146 | echo(None, err=err)
147 | raise Abort() from None
148 |
149 | if value_proc is None:
150 | value_proc = convert_type(type, default)
151 |
152 | prompt = _build_prompt(
153 | text, prompt_suffix, show_default, default, show_choices, type
154 | )
155 |
156 | if confirmation_prompt:
157 | if confirmation_prompt is True:
158 | confirmation_prompt = _("Repeat for confirmation")
159 |
160 | confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix)
161 |
162 | while True:
163 | while True:
164 | value = prompt_func(prompt)
165 | if value:
166 | break
167 | elif default is not None:
168 | value = default
169 | break
170 | try:
171 | result = value_proc(value)
172 | except UsageError as e:
173 | if hide_input:
174 | echo(_("Error: The value you entered was invalid."), err=err)
175 | else:
176 | echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306
177 | continue
178 | if not confirmation_prompt:
179 | return result
180 | while True:
181 | value2 = prompt_func(confirmation_prompt)
182 | is_empty = not value and not value2
183 | if value2 or is_empty:
184 | break
185 | if value == value2:
186 | return result
187 | echo(_("Error: The two entered values do not match."), err=err)
188 |
189 |
190 | def confirm(
191 | text: str,
192 | default: t.Optional[bool] = False,
193 | abort: bool = False,
194 | prompt_suffix: str = ": ",
195 | show_default: bool = True,
196 | err: bool = False,
197 | ) -> bool:
198 | """Prompts for confirmation (yes/no question).
199 |
200 | If the user aborts the input by sending a interrupt signal this
201 | function will catch it and raise a :exc:`Abort` exception.
202 |
203 | :param text: the question to ask.
204 | :param default: The default value to use when no input is given. If
205 | ``None``, repeat until input is given.
206 | :param abort: if this is set to `True` a negative answer aborts the
207 | exception by raising :exc:`Abort`.
208 | :param prompt_suffix: a suffix that should be added to the prompt.
209 | :param show_default: shows or hides the default value in the prompt.
210 | :param err: if set to true the file defaults to ``stderr`` instead of
211 | ``stdout``, the same as with echo.
212 |
213 | .. versionchanged:: 8.0
214 | Repeat until input is given if ``default`` is ``None``.
215 |
216 | .. versionadded:: 4.0
217 | Added the ``err`` parameter.
218 | """
219 | prompt = _build_prompt(
220 | text,
221 | prompt_suffix,
222 | show_default,
223 | "y/n" if default is None else ("Y/n" if default else "y/N"),
224 | )
225 |
226 | while True:
227 | try:
228 | # Write the prompt separately so that we get nice
229 | # coloring through colorama on Windows
230 | echo(prompt.rstrip(" "), nl=False, err=err)
231 | # Echo a space to stdout to work around an issue where
232 | # readline causes backspace to clear the whole line.
233 | value = visible_prompt_func(" ").lower().strip()
234 | except (KeyboardInterrupt, EOFError):
235 | raise Abort() from None
236 | if value in ("y", "yes"):
237 | rv = True
238 | elif value in ("n", "no"):
239 | rv = False
240 | elif default is not None and value == "":
241 | rv = default
242 | else:
243 | echo(_("Error: invalid input"), err=err)
244 | continue
245 | break
246 | if abort and not rv:
247 | raise Abort()
248 | return rv
249 |
250 |
251 | def echo_via_pager(
252 | text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str],
253 | color: t.Optional[bool] = None,
254 | ) -> None:
255 | """This function takes a text and shows it via an environment specific
256 | pager on stdout.
257 |
258 | .. versionchanged:: 3.0
259 | Added the `color` flag.
260 |
261 | :param text_or_generator: the text to page, or alternatively, a
262 | generator emitting the text to page.
263 | :param color: controls if the pager supports ANSI colors or not. The
264 | default is autodetection.
265 | """
266 | color = resolve_color_default(color)
267 |
268 | if inspect.isgeneratorfunction(text_or_generator):
269 | i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)()
270 | elif isinstance(text_or_generator, str):
271 | i = [text_or_generator]
272 | else:
273 | i = iter(t.cast(t.Iterable[str], text_or_generator))
274 |
275 | # convert every element of i to a text type if necessary
276 | text_generator = (el if isinstance(el, str) else str(el) for el in i)
277 |
278 | from ._termui_impl import pager
279 |
280 | return pager(itertools.chain(text_generator, "\n"), color)
281 |
282 |
283 | def progressbar(
284 | iterable: t.Optional[t.Iterable[V]] = None,
285 | length: t.Optional[int] = None,
286 | label: t.Optional[str] = None,
287 | show_eta: bool = True,
288 | show_percent: t.Optional[bool] = None,
289 | show_pos: bool = False,
290 | item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None,
291 | fill_char: str = "#",
292 | empty_char: str = "-",
293 | bar_template: str = "%(label)s [%(bar)s] %(info)s",
294 | info_sep: str = " ",
295 | width: int = 36,
296 | file: t.Optional[t.TextIO] = None,
297 | color: t.Optional[bool] = None,
298 | update_min_steps: int = 1,
299 | ) -> "ProgressBar[V]":
300 | """This function creates an iterable context manager that can be used
301 | to iterate over something while showing a progress bar. It will
302 | either iterate over the `iterable` or `length` items (that are counted
303 | up). While iteration happens, this function will print a rendered
304 | progress bar to the given `file` (defaults to stdout) and will attempt
305 | to calculate remaining time and more. By default, this progress bar
306 | will not be rendered if the file is not a terminal.
307 |
308 | The context manager creates the progress bar. When the context
309 | manager is entered the progress bar is already created. With every
310 | iteration over the progress bar, the iterable passed to the bar is
311 | advanced and the bar is updated. When the context manager exits,
312 | a newline is printed and the progress bar is finalized on screen.
313 |
314 | Note: The progress bar is currently designed for use cases where the
315 | total progress can be expected to take at least several seconds.
316 | Because of this, the ProgressBar class object won't display
317 | progress that is considered too fast, and progress where the time
318 | between steps is less than a second.
319 |
320 | No printing must happen or the progress bar will be unintentionally
321 | destroyed.
322 |
323 | Example usage::
324 |
325 | with progressbar(items) as bar:
326 | for item in bar:
327 | do_something_with(item)
328 |
329 | Alternatively, if no iterable is specified, one can manually update the
330 | progress bar through the `update()` method instead of directly
331 | iterating over the progress bar. The update method accepts the number
332 | of steps to increment the bar with::
333 |
334 | with progressbar(length=chunks.total_bytes) as bar:
335 | for chunk in chunks:
336 | process_chunk(chunk)
337 | bar.update(chunks.bytes)
338 |
339 | The ``update()`` method also takes an optional value specifying the
340 | ``current_item`` at the new position. This is useful when used
341 | together with ``item_show_func`` to customize the output for each
342 | manual step::
343 |
344 | with click.progressbar(
345 | length=total_size,
346 | label='Unzipping archive',
347 | item_show_func=lambda a: a.filename
348 | ) as bar:
349 | for archive in zip_file:
350 | archive.extract()
351 | bar.update(archive.size, archive)
352 |
353 | :param iterable: an iterable to iterate over. If not provided the length
354 | is required.
355 | :param length: the number of items to iterate over. By default the
356 | progressbar will attempt to ask the iterator about its
357 | length, which might or might not work. If an iterable is
358 | also provided this parameter can be used to override the
359 | length. If an iterable is not provided the progress bar
360 | will iterate over a range of that length.
361 | :param label: the label to show next to the progress bar.
362 | :param show_eta: enables or disables the estimated time display. This is
363 | automatically disabled if the length cannot be
364 | determined.
365 | :param show_percent: enables or disables the percentage display. The
366 | default is `True` if the iterable has a length or
367 | `False` if not.
368 | :param show_pos: enables or disables the absolute position display. The
369 | default is `False`.
370 | :param item_show_func: A function called with the current item which
371 | can return a string to show next to the progress bar. If the
372 | function returns ``None`` nothing is shown. The current item can
373 | be ``None``, such as when entering and exiting the bar.
374 | :param fill_char: the character to use to show the filled part of the
375 | progress bar.
376 | :param empty_char: the character to use to show the non-filled part of
377 | the progress bar.
378 | :param bar_template: the format string to use as template for the bar.
379 | The parameters in it are ``label`` for the label,
380 | ``bar`` for the progress bar and ``info`` for the
381 | info section.
382 | :param info_sep: the separator between multiple info items (eta etc.)
383 | :param width: the width of the progress bar in characters, 0 means full
384 | terminal width
385 | :param file: The file to write to. If this is not a terminal then
386 | only the label is printed.
387 | :param color: controls if the terminal supports ANSI colors or not. The
388 | default is autodetection. This is only needed if ANSI
389 | codes are included anywhere in the progress bar output
390 | which is not the case by default.
391 | :param update_min_steps: Render only when this many updates have
392 | completed. This allows tuning for very fast iterators.
393 |
394 | .. versionchanged:: 8.0
395 | Output is shown even if execution time is less than 0.5 seconds.
396 |
397 | .. versionchanged:: 8.0
398 | ``item_show_func`` shows the current item, not the previous one.
399 |
400 | .. versionchanged:: 8.0
401 | Labels are echoed if the output is not a TTY. Reverts a change
402 | in 7.0 that removed all output.
403 |
404 | .. versionadded:: 8.0
405 | Added the ``update_min_steps`` parameter.
406 |
407 | .. versionchanged:: 4.0
408 | Added the ``color`` parameter. Added the ``update`` method to
409 | the object.
410 |
411 | .. versionadded:: 2.0
412 | """
413 | from ._termui_impl import ProgressBar
414 |
415 | color = resolve_color_default(color)
416 | return ProgressBar(
417 | iterable=iterable,
418 | length=length,
419 | show_eta=show_eta,
420 | show_percent=show_percent,
421 | show_pos=show_pos,
422 | item_show_func=item_show_func,
423 | fill_char=fill_char,
424 | empty_char=empty_char,
425 | bar_template=bar_template,
426 | info_sep=info_sep,
427 | file=file,
428 | label=label,
429 | width=width,
430 | color=color,
431 | update_min_steps=update_min_steps,
432 | )
433 |
434 |
435 | def clear() -> None:
436 | """Clears the terminal screen. This will have the effect of clearing
437 | the whole visible space of the terminal and moving the cursor to the
438 | top left. This does not do anything if not connected to a terminal.
439 |
440 | .. versionadded:: 2.0
441 | """
442 | if not isatty(sys.stdout):
443 | return
444 |
445 | # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor
446 | echo("\033[2J\033[1;1H", nl=False)
447 |
448 |
449 | def _interpret_color(
450 | color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0
451 | ) -> str:
452 | if isinstance(color, int):
453 | return f"{38 + offset};5;{color:d}"
454 |
455 | if isinstance(color, (tuple, list)):
456 | r, g, b = color
457 | return f"{38 + offset};2;{r:d};{g:d};{b:d}"
458 |
459 | return str(_ansi_colors[color] + offset)
460 |
461 |
462 | def style(
463 | text: t.Any,
464 | fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
465 | bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None,
466 | bold: t.Optional[bool] = None,
467 | dim: t.Optional[bool] = None,
468 | underline: t.Optional[bool] = None,
469 | overline: t.Optional[bool] = None,
470 | italic: t.Optional[bool] = None,
471 | blink: t.Optional[bool] = None,
472 | reverse: t.Optional[bool] = None,
473 | strikethrough: t.Optional[bool] = None,
474 | reset: bool = True,
475 | ) -> str:
476 | """Styles a text with ANSI styles and returns the new string. By
477 | default the styling is self contained which means that at the end
478 | of the string a reset code is issued. This can be prevented by
479 | passing ``reset=False``.
480 |
481 | Examples::
482 |
483 | click.echo(click.style('Hello World!', fg='green'))
484 | click.echo(click.style('ATTENTION!', blink=True))
485 | click.echo(click.style('Some things', reverse=True, fg='cyan'))
486 | click.echo(click.style('More colors', fg=(255, 12, 128), bg=117))
487 |
488 | Supported color names:
489 |
490 | * ``black`` (might be a gray)
491 | * ``red``
492 | * ``green``
493 | * ``yellow`` (might be an orange)
494 | * ``blue``
495 | * ``magenta``
496 | * ``cyan``
497 | * ``white`` (might be light gray)
498 | * ``bright_black``
499 | * ``bright_red``
500 | * ``bright_green``
501 | * ``bright_yellow``
502 | * ``bright_blue``
503 | * ``bright_magenta``
504 | * ``bright_cyan``
505 | * ``bright_white``
506 | * ``reset`` (reset the color code only)
507 |
508 | If the terminal supports it, color may also be specified as:
509 |
510 | - An integer in the interval [0, 255]. The terminal must support
511 | 8-bit/256-color mode.
512 | - An RGB tuple of three integers in [0, 255]. The terminal must
513 | support 24-bit/true-color mode.
514 |
515 | See https://en.wikipedia.org/wiki/ANSI_color and
516 | https://gist.github.com/XVilka/8346728 for more information.
517 |
518 | :param text: the string to style with ansi codes.
519 | :param fg: if provided this will become the foreground color.
520 | :param bg: if provided this will become the background color.
521 | :param bold: if provided this will enable or disable bold mode.
522 | :param dim: if provided this will enable or disable dim mode. This is
523 | badly supported.
524 | :param underline: if provided this will enable or disable underline.
525 | :param overline: if provided this will enable or disable overline.
526 | :param italic: if provided this will enable or disable italic.
527 | :param blink: if provided this will enable or disable blinking.
528 | :param reverse: if provided this will enable or disable inverse
529 | rendering (foreground becomes background and the
530 | other way round).
531 | :param strikethrough: if provided this will enable or disable
532 | striking through text.
533 | :param reset: by default a reset-all code is added at the end of the
534 | string which means that styles do not carry over. This
535 | can be disabled to compose styles.
536 |
537 | .. versionchanged:: 8.0
538 | A non-string ``message`` is converted to a string.
539 |
540 | .. versionchanged:: 8.0
541 | Added support for 256 and RGB color codes.
542 |
543 | .. versionchanged:: 8.0
544 | Added the ``strikethrough``, ``italic``, and ``overline``
545 | parameters.
546 |
547 | .. versionchanged:: 7.0
548 | Added support for bright colors.
549 |
550 | .. versionadded:: 2.0
551 | """
552 | if not isinstance(text, str):
553 | text = str(text)
554 |
555 | bits = []
556 |
557 | if fg:
558 | try:
559 | bits.append(f"\033[{_interpret_color(fg)}m")
560 | except KeyError:
561 | raise TypeError(f"Unknown color {fg!r}") from None
562 |
563 | if bg:
564 | try:
565 | bits.append(f"\033[{_interpret_color(bg, 10)}m")
566 | except KeyError:
567 | raise TypeError(f"Unknown color {bg!r}") from None
568 |
569 | if bold is not None:
570 | bits.append(f"\033[{1 if bold else 22}m")
571 | if dim is not None:
572 | bits.append(f"\033[{2 if dim else 22}m")
573 | if underline is not None:
574 | bits.append(f"\033[{4 if underline else 24}m")
575 | if overline is not None:
576 | bits.append(f"\033[{53 if overline else 55}m")
577 | if italic is not None:
578 | bits.append(f"\033[{3 if italic else 23}m")
579 | if blink is not None:
580 | bits.append(f"\033[{5 if blink else 25}m")
581 | if reverse is not None:
582 | bits.append(f"\033[{7 if reverse else 27}m")
583 | if strikethrough is not None:
584 | bits.append(f"\033[{9 if strikethrough else 29}m")
585 | bits.append(text)
586 | if reset:
587 | bits.append(_ansi_reset_all)
588 | return "".join(bits)
589 |
590 |
591 | def unstyle(text: str) -> str:
592 | """Removes ANSI styling information from a string. Usually it's not
593 | necessary to use this function as Click's echo function will
594 | automatically remove styling if necessary.
595 |
596 | .. versionadded:: 2.0
597 |
598 | :param text: the text to remove style information from.
599 | """
600 | return strip_ansi(text)
601 |
602 |
603 | def secho(
604 | message: t.Optional[t.Any] = None,
605 | file: t.Optional[t.IO[t.AnyStr]] = None,
606 | nl: bool = True,
607 | err: bool = False,
608 | color: t.Optional[bool] = None,
609 | **styles: t.Any,
610 | ) -> None:
611 | """This function combines :func:`echo` and :func:`style` into one
612 | call. As such the following two calls are the same::
613 |
614 | click.secho('Hello World!', fg='green')
615 | click.echo(click.style('Hello World!', fg='green'))
616 |
617 | All keyword arguments are forwarded to the underlying functions
618 | depending on which one they go with.
619 |
620 | Non-string types will be converted to :class:`str`. However,
621 | :class:`bytes` are passed directly to :meth:`echo` without applying
622 | style. If you want to style bytes that represent text, call
623 | :meth:`bytes.decode` first.
624 |
625 | .. versionchanged:: 8.0
626 | A non-string ``message`` is converted to a string. Bytes are
627 | passed through without style applied.
628 |
629 | .. versionadded:: 2.0
630 | """
631 | if message is not None and not isinstance(message, (bytes, bytearray)):
632 | message = style(message, **styles)
633 |
634 | return echo(message, file=file, nl=nl, err=err, color=color)
635 |
636 |
637 | def edit(
638 | text: t.Optional[t.AnyStr] = None,
639 | editor: t.Optional[str] = None,
640 | env: t.Optional[t.Mapping[str, str]] = None,
641 | require_save: bool = True,
642 | extension: str = ".txt",
643 | filename: t.Optional[str] = None,
644 | ) -> t.Optional[t.AnyStr]:
645 | r"""Edits the given text in the defined editor. If an editor is given
646 | (should be the full path to the executable but the regular operating
647 | system search path is used for finding the executable) it overrides
648 | the detected editor. Optionally, some environment variables can be
649 | used. If the editor is closed without changes, `None` is returned. In
650 | case a file is edited directly the return value is always `None` and
651 | `require_save` and `extension` are ignored.
652 |
653 | If the editor cannot be opened a :exc:`UsageError` is raised.
654 |
655 | Note for Windows: to simplify cross-platform usage, the newlines are
656 | automatically converted from POSIX to Windows and vice versa. As such,
657 | the message here will have ``\n`` as newline markers.
658 |
659 | :param text: the text to edit.
660 | :param editor: optionally the editor to use. Defaults to automatic
661 | detection.
662 | :param env: environment variables to forward to the editor.
663 | :param require_save: if this is true, then not saving in the editor
664 | will make the return value become `None`.
665 | :param extension: the extension to tell the editor about. This defaults
666 | to `.txt` but changing this might change syntax
667 | highlighting.
668 | :param filename: if provided it will edit this file instead of the
669 | provided text contents. It will not use a temporary
670 | file as an indirection in that case.
671 | """
672 | from ._termui_impl import Editor
673 |
674 | ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension)
675 |
676 | if filename is None:
677 | return ed.edit(text)
678 |
679 | ed.edit_file(filename)
680 | return None
681 |
682 |
683 | def launch(url: str, wait: bool = False, locate: bool = False) -> int:
684 | """This function launches the given URL (or filename) in the default
685 | viewer application for this file type. If this is an executable, it
686 | might launch the executable in a new session. The return value is
687 | the exit code of the launched application. Usually, ``0`` indicates
688 | success.
689 |
690 | Examples::
691 |
692 | click.launch('https://click.palletsprojects.com/')
693 | click.launch('/my/downloaded/file', locate=True)
694 |
695 | .. versionadded:: 2.0
696 |
697 | :param url: URL or filename of the thing to launch.
698 | :param wait: Wait for the program to exit before returning. This
699 | only works if the launched program blocks. In particular,
700 | ``xdg-open`` on Linux does not block.
701 | :param locate: if this is set to `True` then instead of launching the
702 | application associated with the URL it will attempt to
703 | launch a file manager with the file located. This
704 | might have weird effects if the URL does not point to
705 | the filesystem.
706 | """
707 | from ._termui_impl import open_url
708 |
709 | return open_url(url, wait=wait, locate=locate)
710 |
711 |
712 | # If this is provided, getchar() calls into this instead. This is used
713 | # for unittesting purposes.
714 | _getchar: t.Optional[t.Callable[[bool], str]] = None
715 |
716 |
717 | def getchar(echo: bool = False) -> str:
718 | """Fetches a single character from the terminal and returns it. This
719 | will always return a unicode character and under certain rare
720 | circumstances this might return more than one character. The
721 | situations which more than one character is returned is when for
722 | whatever reason multiple characters end up in the terminal buffer or
723 | standard input was not actually a terminal.
724 |
725 | Note that this will always read from the terminal, even if something
726 | is piped into the standard input.
727 |
728 | Note for Windows: in rare cases when typing non-ASCII characters, this
729 | function might wait for a second character and then return both at once.
730 | This is because certain Unicode characters look like special-key markers.
731 |
732 | .. versionadded:: 2.0
733 |
734 | :param echo: if set to `True`, the character read will also show up on
735 | the terminal. The default is to not show it.
736 | """
737 | global _getchar
738 |
739 | if _getchar is None:
740 | from ._termui_impl import getchar as f
741 |
742 | _getchar = f
743 |
744 | return _getchar(echo)
745 |
746 |
747 | def raw_terminal() -> t.ContextManager[int]:
748 | from ._termui_impl import raw_terminal as f
749 |
750 | return f()
751 |
752 |
753 | def pause(info: t.Optional[str] = None, err: bool = False) -> None:
754 | """This command stops execution and waits for the user to press any
755 | key to continue. This is similar to the Windows batch "pause"
756 | command. If the program is not run through a terminal, this command
757 | will instead do nothing.
758 |
759 | .. versionadded:: 2.0
760 |
761 | .. versionadded:: 4.0
762 | Added the `err` parameter.
763 |
764 | :param info: The message to print before pausing. Defaults to
765 | ``"Press any key to continue..."``.
766 | :param err: if set to message goes to ``stderr`` instead of
767 | ``stdout``, the same as with echo.
768 | """
769 | if not isatty(sys.stdin) or not isatty(sys.stdout):
770 | return
771 |
772 | if info is None:
773 | info = _("Press any key to continue...")
774 |
775 | try:
776 | if info:
777 | echo(info, nl=False, err=err)
778 | try:
779 | getchar()
780 | except (KeyboardInterrupt, EOFError):
781 | pass
782 | finally:
783 | if info:
784 | echo(err=err)
785 |
```