#
tokens: 49573/50000 3/808 files (page 71/168)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 71 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/network/auth.py:
--------------------------------------------------------------------------------

```python
  1 | """Network Authentication Helpers
  2 | 
  3 | Contains interface (MultiDomainBasicAuth) and associated glue code for
  4 | providing credentials in the context of network requests.
  5 | """
  6 | 
  7 | import logging
  8 | import os
  9 | import shutil
 10 | import subprocess
 11 | import sysconfig
 12 | import typing
 13 | import urllib.parse
 14 | from abc import ABC, abstractmethod
 15 | from functools import lru_cache
 16 | from os.path import commonprefix
 17 | from pathlib import Path
 18 | from typing import Any, Dict, List, NamedTuple, Optional, Tuple
 19 | 
 20 | from pip._vendor.requests.auth import AuthBase, HTTPBasicAuth
 21 | from pip._vendor.requests.models import Request, Response
 22 | from pip._vendor.requests.utils import get_netrc_auth
 23 | 
 24 | from pip._internal.utils.logging import getLogger
 25 | from pip._internal.utils.misc import (
 26 |     ask,
 27 |     ask_input,
 28 |     ask_password,
 29 |     remove_auth_from_url,
 30 |     split_auth_netloc_from_url,
 31 | )
 32 | from pip._internal.vcs.versioncontrol import AuthInfo
 33 | 
 34 | logger = getLogger(__name__)
 35 | 
 36 | KEYRING_DISABLED = False
 37 | 
 38 | 
 39 | class Credentials(NamedTuple):
 40 |     url: str
 41 |     username: str
 42 |     password: str
 43 | 
 44 | 
 45 | class KeyRingBaseProvider(ABC):
 46 |     """Keyring base provider interface"""
 47 | 
 48 |     has_keyring: bool
 49 | 
 50 |     @abstractmethod
 51 |     def get_auth_info(
 52 |         self, url: str, username: Optional[str]
 53 |     ) -> Optional[AuthInfo]: ...
 54 | 
 55 |     @abstractmethod
 56 |     def save_auth_info(self, url: str, username: str, password: str) -> None: ...
 57 | 
 58 | 
 59 | class KeyRingNullProvider(KeyRingBaseProvider):
 60 |     """Keyring null provider"""
 61 | 
 62 |     has_keyring = False
 63 | 
 64 |     def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]:
 65 |         return None
 66 | 
 67 |     def save_auth_info(self, url: str, username: str, password: str) -> None:
 68 |         return None
 69 | 
 70 | 
 71 | class KeyRingPythonProvider(KeyRingBaseProvider):
 72 |     """Keyring interface which uses locally imported `keyring`"""
 73 | 
 74 |     has_keyring = True
 75 | 
 76 |     def __init__(self) -> None:
 77 |         import keyring
 78 | 
 79 |         self.keyring = keyring
 80 | 
 81 |     def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]:
 82 |         # Support keyring's get_credential interface which supports getting
 83 |         # credentials without a username. This is only available for
 84 |         # keyring>=15.2.0.
 85 |         if hasattr(self.keyring, "get_credential"):
 86 |             logger.debug("Getting credentials from keyring for %s", url)
 87 |             cred = self.keyring.get_credential(url, username)
 88 |             if cred is not None:
 89 |                 return cred.username, cred.password
 90 |             return None
 91 | 
 92 |         if username is not None:
 93 |             logger.debug("Getting password from keyring for %s", url)
 94 |             password = self.keyring.get_password(url, username)
 95 |             if password:
 96 |                 return username, password
 97 |         return None
 98 | 
 99 |     def save_auth_info(self, url: str, username: str, password: str) -> None:
100 |         self.keyring.set_password(url, username, password)
101 | 
102 | 
103 | class KeyRingCliProvider(KeyRingBaseProvider):
104 |     """Provider which uses `keyring` cli
105 | 
106 |     Instead of calling the keyring package installed alongside pip
107 |     we call keyring on the command line which will enable pip to
108 |     use which ever installation of keyring is available first in
109 |     PATH.
110 |     """
111 | 
112 |     has_keyring = True
113 | 
114 |     def __init__(self, cmd: str) -> None:
115 |         self.keyring = cmd
116 | 
117 |     def get_auth_info(self, url: str, username: Optional[str]) -> Optional[AuthInfo]:
118 |         # This is the default implementation of keyring.get_credential
119 |         # https://github.com/jaraco/keyring/blob/97689324abcf01bd1793d49063e7ca01e03d7d07/keyring/backend.py#L134-L139
120 |         if username is not None:
121 |             password = self._get_password(url, username)
122 |             if password is not None:
123 |                 return username, password
124 |         return None
125 | 
126 |     def save_auth_info(self, url: str, username: str, password: str) -> None:
127 |         return self._set_password(url, username, password)
128 | 
129 |     def _get_password(self, service_name: str, username: str) -> Optional[str]:
130 |         """Mirror the implementation of keyring.get_password using cli"""
131 |         if self.keyring is None:
132 |             return None
133 | 
134 |         cmd = [self.keyring, "get", service_name, username]
135 |         env = os.environ.copy()
136 |         env["PYTHONIOENCODING"] = "utf-8"
137 |         res = subprocess.run(
138 |             cmd,
139 |             stdin=subprocess.DEVNULL,
140 |             stdout=subprocess.PIPE,
141 |             env=env,
142 |         )
143 |         if res.returncode:
144 |             return None
145 |         return res.stdout.decode("utf-8").strip(os.linesep)
146 | 
147 |     def _set_password(self, service_name: str, username: str, password: str) -> None:
148 |         """Mirror the implementation of keyring.set_password using cli"""
149 |         if self.keyring is None:
150 |             return None
151 |         env = os.environ.copy()
152 |         env["PYTHONIOENCODING"] = "utf-8"
153 |         subprocess.run(
154 |             [self.keyring, "set", service_name, username],
155 |             input=f"{password}{os.linesep}".encode(),
156 |             env=env,
157 |             check=True,
158 |         )
159 |         return None
160 | 
161 | 
162 | @lru_cache(maxsize=None)
163 | def get_keyring_provider(provider: str) -> KeyRingBaseProvider:
164 |     logger.verbose("Keyring provider requested: %s", provider)
165 | 
166 |     # keyring has previously failed and been disabled
167 |     if KEYRING_DISABLED:
168 |         provider = "disabled"
169 |     if provider in ["import", "auto"]:
170 |         try:
171 |             impl = KeyRingPythonProvider()
172 |             logger.verbose("Keyring provider set: import")
173 |             return impl
174 |         except ImportError:
175 |             pass
176 |         except Exception as exc:
177 |             # In the event of an unexpected exception
178 |             # we should warn the user
179 |             msg = "Installed copy of keyring fails with exception %s"
180 |             if provider == "auto":
181 |                 msg = msg + ", trying to find a keyring executable as a fallback"
182 |             logger.warning(msg, exc, exc_info=logger.isEnabledFor(logging.DEBUG))
183 |     if provider in ["subprocess", "auto"]:
184 |         cli = shutil.which("keyring")
185 |         if cli and cli.startswith(sysconfig.get_path("scripts")):
186 |             # all code within this function is stolen from shutil.which implementation
187 |             @typing.no_type_check
188 |             def PATH_as_shutil_which_determines_it() -> str:
189 |                 path = os.environ.get("PATH", None)
190 |                 if path is None:
191 |                     try:
192 |                         path = os.confstr("CS_PATH")
193 |                     except (AttributeError, ValueError):
194 |                         # os.confstr() or CS_PATH is not available
195 |                         path = os.defpath
196 |                 # bpo-35755: Don't use os.defpath if the PATH environment variable is
197 |                 # set to an empty string
198 | 
199 |                 return path
200 | 
201 |             scripts = Path(sysconfig.get_path("scripts"))
202 | 
203 |             paths = []
204 |             for path in PATH_as_shutil_which_determines_it().split(os.pathsep):
205 |                 p = Path(path)
206 |                 try:
207 |                     if not p.samefile(scripts):
208 |                         paths.append(path)
209 |                 except FileNotFoundError:
210 |                     pass
211 | 
212 |             path = os.pathsep.join(paths)
213 | 
214 |             cli = shutil.which("keyring", path=path)
215 | 
216 |         if cli:
217 |             logger.verbose("Keyring provider set: subprocess with executable %s", cli)
218 |             return KeyRingCliProvider(cli)
219 | 
220 |     logger.verbose("Keyring provider set: disabled")
221 |     return KeyRingNullProvider()
222 | 
223 | 
224 | class MultiDomainBasicAuth(AuthBase):
225 |     def __init__(
226 |         self,
227 |         prompting: bool = True,
228 |         index_urls: Optional[List[str]] = None,
229 |         keyring_provider: str = "auto",
230 |     ) -> None:
231 |         self.prompting = prompting
232 |         self.index_urls = index_urls
233 |         self.keyring_provider = keyring_provider  # type: ignore[assignment]
234 |         self.passwords: Dict[str, AuthInfo] = {}
235 |         # When the user is prompted to enter credentials and keyring is
236 |         # available, we will offer to save them. If the user accepts,
237 |         # this value is set to the credentials they entered. After the
238 |         # request authenticates, the caller should call
239 |         # ``save_credentials`` to save these.
240 |         self._credentials_to_save: Optional[Credentials] = None
241 | 
242 |     @property
243 |     def keyring_provider(self) -> KeyRingBaseProvider:
244 |         return get_keyring_provider(self._keyring_provider)
245 | 
246 |     @keyring_provider.setter
247 |     def keyring_provider(self, provider: str) -> None:
248 |         # The free function get_keyring_provider has been decorated with
249 |         # functools.cache. If an exception occurs in get_keyring_auth that
250 |         # cache will be cleared and keyring disabled, take that into account
251 |         # if you want to remove this indirection.
252 |         self._keyring_provider = provider
253 | 
254 |     @property
255 |     def use_keyring(self) -> bool:
256 |         # We won't use keyring when --no-input is passed unless
257 |         # a specific provider is requested because it might require
258 |         # user interaction
259 |         return self.prompting or self._keyring_provider not in ["auto", "disabled"]
260 | 
261 |     def _get_keyring_auth(
262 |         self,
263 |         url: Optional[str],
264 |         username: Optional[str],
265 |     ) -> Optional[AuthInfo]:
266 |         """Return the tuple auth for a given url from keyring."""
267 |         # Do nothing if no url was provided
268 |         if not url:
269 |             return None
270 | 
271 |         try:
272 |             return self.keyring_provider.get_auth_info(url, username)
273 |         except Exception as exc:
274 |             # Log the full exception (with stacktrace) at debug, so it'll only
275 |             # show up when running in verbose mode.
276 |             logger.debug("Keyring is skipped due to an exception", exc_info=True)
277 |             # Always log a shortened version of the exception.
278 |             logger.warning(
279 |                 "Keyring is skipped due to an exception: %s",
280 |                 str(exc),
281 |             )
282 |             global KEYRING_DISABLED
283 |             KEYRING_DISABLED = True
284 |             get_keyring_provider.cache_clear()
285 |             return None
286 | 
287 |     def _get_index_url(self, url: str) -> Optional[str]:
288 |         """Return the original index URL matching the requested URL.
289 | 
290 |         Cached or dynamically generated credentials may work against
291 |         the original index URL rather than just the netloc.
292 | 
293 |         The provided url should have had its username and password
294 |         removed already. If the original index url had credentials then
295 |         they will be included in the return value.
296 | 
297 |         Returns None if no matching index was found, or if --no-index
298 |         was specified by the user.
299 |         """
300 |         if not url or not self.index_urls:
301 |             return None
302 | 
303 |         url = remove_auth_from_url(url).rstrip("/") + "/"
304 |         parsed_url = urllib.parse.urlsplit(url)
305 | 
306 |         candidates = []
307 | 
308 |         for index in self.index_urls:
309 |             index = index.rstrip("/") + "/"
310 |             parsed_index = urllib.parse.urlsplit(remove_auth_from_url(index))
311 |             if parsed_url == parsed_index:
312 |                 return index
313 | 
314 |             if parsed_url.netloc != parsed_index.netloc:
315 |                 continue
316 | 
317 |             candidate = urllib.parse.urlsplit(index)
318 |             candidates.append(candidate)
319 | 
320 |         if not candidates:
321 |             return None
322 | 
323 |         candidates.sort(
324 |             reverse=True,
325 |             key=lambda candidate: commonprefix(
326 |                 [
327 |                     parsed_url.path,
328 |                     candidate.path,
329 |                 ]
330 |             ).rfind("/"),
331 |         )
332 | 
333 |         return urllib.parse.urlunsplit(candidates[0])
334 | 
335 |     def _get_new_credentials(
336 |         self,
337 |         original_url: str,
338 |         *,
339 |         allow_netrc: bool = True,
340 |         allow_keyring: bool = False,
341 |     ) -> AuthInfo:
342 |         """Find and return credentials for the specified URL."""
343 |         # Split the credentials and netloc from the url.
344 |         url, netloc, url_user_password = split_auth_netloc_from_url(
345 |             original_url,
346 |         )
347 | 
348 |         # Start with the credentials embedded in the url
349 |         username, password = url_user_password
350 |         if username is not None and password is not None:
351 |             logger.debug("Found credentials in url for %s", netloc)
352 |             return url_user_password
353 | 
354 |         # Find a matching index url for this request
355 |         index_url = self._get_index_url(url)
356 |         if index_url:
357 |             # Split the credentials from the url.
358 |             index_info = split_auth_netloc_from_url(index_url)
359 |             if index_info:
360 |                 index_url, _, index_url_user_password = index_info
361 |                 logger.debug("Found index url %s", index_url)
362 | 
363 |         # If an index URL was found, try its embedded credentials
364 |         if index_url and index_url_user_password[0] is not None:
365 |             username, password = index_url_user_password
366 |             if username is not None and password is not None:
367 |                 logger.debug("Found credentials in index url for %s", netloc)
368 |                 return index_url_user_password
369 | 
370 |         # Get creds from netrc if we still don't have them
371 |         if allow_netrc:
372 |             netrc_auth = get_netrc_auth(original_url)
373 |             if netrc_auth:
374 |                 logger.debug("Found credentials in netrc for %s", netloc)
375 |                 return netrc_auth
376 | 
377 |         # If we don't have a password and keyring is available, use it.
378 |         if allow_keyring:
379 |             # The index url is more specific than the netloc, so try it first
380 |             # fmt: off
381 |             kr_auth = (
382 |                 self._get_keyring_auth(index_url, username) or
383 |                 self._get_keyring_auth(netloc, username)
384 |             )
385 |             # fmt: on
386 |             if kr_auth:
387 |                 logger.debug("Found credentials in keyring for %s", netloc)
388 |                 return kr_auth
389 | 
390 |         return username, password
391 | 
392 |     def _get_url_and_credentials(
393 |         self, original_url: str
394 |     ) -> Tuple[str, Optional[str], Optional[str]]:
395 |         """Return the credentials to use for the provided URL.
396 | 
397 |         If allowed, netrc and keyring may be used to obtain the
398 |         correct credentials.
399 | 
400 |         Returns (url_without_credentials, username, password). Note
401 |         that even if the original URL contains credentials, this
402 |         function may return a different username and password.
403 |         """
404 |         url, netloc, _ = split_auth_netloc_from_url(original_url)
405 | 
406 |         # Try to get credentials from original url
407 |         username, password = self._get_new_credentials(original_url)
408 | 
409 |         # If credentials not found, use any stored credentials for this netloc.
410 |         # Do this if either the username or the password is missing.
411 |         # This accounts for the situation in which the user has specified
412 |         # the username in the index url, but the password comes from keyring.
413 |         if (username is None or password is None) and netloc in self.passwords:
414 |             un, pw = self.passwords[netloc]
415 |             # It is possible that the cached credentials are for a different username,
416 |             # in which case the cache should be ignored.
417 |             if username is None or username == un:
418 |                 username, password = un, pw
419 | 
420 |         if username is not None or password is not None:
421 |             # Convert the username and password if they're None, so that
422 |             # this netloc will show up as "cached" in the conditional above.
423 |             # Further, HTTPBasicAuth doesn't accept None, so it makes sense to
424 |             # cache the value that is going to be used.
425 |             username = username or ""
426 |             password = password or ""
427 | 
428 |             # Store any acquired credentials.
429 |             self.passwords[netloc] = (username, password)
430 | 
431 |         assert (
432 |             # Credentials were found
433 |             (username is not None and password is not None)
434 |             # Credentials were not found
435 |             or (username is None and password is None)
436 |         ), f"Could not load credentials from url: {original_url}"
437 | 
438 |         return url, username, password
439 | 
440 |     def __call__(self, req: Request) -> Request:
441 |         # Get credentials for this request
442 |         url, username, password = self._get_url_and_credentials(req.url)
443 | 
444 |         # Set the url of the request to the url without any credentials
445 |         req.url = url
446 | 
447 |         if username is not None and password is not None:
448 |             # Send the basic auth with this request
449 |             req = HTTPBasicAuth(username, password)(req)
450 | 
451 |         # Attach a hook to handle 401 responses
452 |         req.register_hook("response", self.handle_401)
453 | 
454 |         return req
455 | 
456 |     # Factored out to allow for easy patching in tests
457 |     def _prompt_for_password(
458 |         self, netloc: str
459 |     ) -> Tuple[Optional[str], Optional[str], bool]:
460 |         username = ask_input(f"User for {netloc}: ") if self.prompting else None
461 |         if not username:
462 |             return None, None, False
463 |         if self.use_keyring:
464 |             auth = self._get_keyring_auth(netloc, username)
465 |             if auth and auth[0] is not None and auth[1] is not None:
466 |                 return auth[0], auth[1], False
467 |         password = ask_password("Password: ")
468 |         return username, password, True
469 | 
470 |     # Factored out to allow for easy patching in tests
471 |     def _should_save_password_to_keyring(self) -> bool:
472 |         if (
473 |             not self.prompting
474 |             or not self.use_keyring
475 |             or not self.keyring_provider.has_keyring
476 |         ):
477 |             return False
478 |         return ask("Save credentials to keyring [y/N]: ", ["y", "n"]) == "y"
479 | 
480 |     def handle_401(self, resp: Response, **kwargs: Any) -> Response:
481 |         # We only care about 401 responses, anything else we want to just
482 |         #   pass through the actual response
483 |         if resp.status_code != 401:
484 |             return resp
485 | 
486 |         username, password = None, None
487 | 
488 |         # Query the keyring for credentials:
489 |         if self.use_keyring:
490 |             username, password = self._get_new_credentials(
491 |                 resp.url,
492 |                 allow_netrc=False,
493 |                 allow_keyring=True,
494 |             )
495 | 
496 |         # We are not able to prompt the user so simply return the response
497 |         if not self.prompting and not username and not password:
498 |             return resp
499 | 
500 |         parsed = urllib.parse.urlparse(resp.url)
501 | 
502 |         # Prompt the user for a new username and password
503 |         save = False
504 |         if not username and not password:
505 |             username, password, save = self._prompt_for_password(parsed.netloc)
506 | 
507 |         # Store the new username and password to use for future requests
508 |         self._credentials_to_save = None
509 |         if username is not None and password is not None:
510 |             self.passwords[parsed.netloc] = (username, password)
511 | 
512 |             # Prompt to save the password to keyring
513 |             if save and self._should_save_password_to_keyring():
514 |                 self._credentials_to_save = Credentials(
515 |                     url=parsed.netloc,
516 |                     username=username,
517 |                     password=password,
518 |                 )
519 | 
520 |         # Consume content and release the original connection to allow our new
521 |         #   request to reuse the same one.
522 |         # The result of the assignment isn't used, it's just needed to consume
523 |         # the content.
524 |         _ = resp.content
525 |         resp.raw.release_conn()
526 | 
527 |         # Add our new username and password to the request
528 |         req = HTTPBasicAuth(username or "", password or "")(resp.request)
529 |         req.register_hook("response", self.warn_on_401)
530 | 
531 |         # On successful request, save the credentials that were used to
532 |         # keyring. (Note that if the user responded "no" above, this member
533 |         # is not set and nothing will be saved.)
534 |         if self._credentials_to_save:
535 |             req.register_hook("response", self.save_credentials)
536 | 
537 |         # Send our new request
538 |         new_resp = resp.connection.send(req, **kwargs)
539 |         new_resp.history.append(resp)
540 | 
541 |         return new_resp
542 | 
543 |     def warn_on_401(self, resp: Response, **kwargs: Any) -> None:
544 |         """Response callback to warn about incorrect credentials."""
545 |         if resp.status_code == 401:
546 |             logger.warning(
547 |                 "401 Error, Credentials not correct for %s",
548 |                 resp.request.url,
549 |             )
550 | 
551 |     def save_credentials(self, resp: Response, **kwargs: Any) -> None:
552 |         """Response callback to save credentials on success."""
553 |         assert (
554 |             self.keyring_provider.has_keyring
555 |         ), "should never reach here without keyring"
556 | 
557 |         creds = self._credentials_to_save
558 |         self._credentials_to_save = None
559 |         if creds and resp.status_code < 400:
560 |             try:
561 |                 logger.info("Saving credentials to keyring")
562 |                 self.keyring_provider.save_auth_info(
563 |                     creds.url, creds.username, creds.password
564 |                 )
565 |             except Exception:
566 |                 logger.exception("Failed to save credentials")
567 | 
```

--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/werkzeug/wsgi.py:
--------------------------------------------------------------------------------

```python
  1 | from __future__ import annotations
  2 | 
  3 | import io
  4 | import typing as t
  5 | from functools import partial
  6 | from functools import update_wrapper
  7 | 
  8 | from .exceptions import ClientDisconnected
  9 | from .exceptions import RequestEntityTooLarge
 10 | from .sansio import utils as _sansio_utils
 11 | from .sansio.utils import host_is_trusted  # noqa: F401 # Imported as part of API
 12 | 
 13 | if t.TYPE_CHECKING:
 14 |     from _typeshed.wsgi import WSGIApplication
 15 |     from _typeshed.wsgi import WSGIEnvironment
 16 | 
 17 | 
 18 | def responder(f: t.Callable[..., WSGIApplication]) -> WSGIApplication:
 19 |     """Marks a function as responder.  Decorate a function with it and it
 20 |     will automatically call the return value as WSGI application.
 21 | 
 22 |     Example::
 23 | 
 24 |         @responder
 25 |         def application(environ, start_response):
 26 |             return Response('Hello World!')
 27 |     """
 28 |     return update_wrapper(lambda *a: f(*a)(*a[-2:]), f)
 29 | 
 30 | 
 31 | def get_current_url(
 32 |     environ: WSGIEnvironment,
 33 |     root_only: bool = False,
 34 |     strip_querystring: bool = False,
 35 |     host_only: bool = False,
 36 |     trusted_hosts: t.Iterable[str] | None = None,
 37 | ) -> str:
 38 |     """Recreate the URL for a request from the parts in a WSGI
 39 |     environment.
 40 | 
 41 |     The URL is an IRI, not a URI, so it may contain Unicode characters.
 42 |     Use :func:`~werkzeug.urls.iri_to_uri` to convert it to ASCII.
 43 | 
 44 |     :param environ: The WSGI environment to get the URL parts from.
 45 |     :param root_only: Only build the root path, don't include the
 46 |         remaining path or query string.
 47 |     :param strip_querystring: Don't include the query string.
 48 |     :param host_only: Only build the scheme and host.
 49 |     :param trusted_hosts: A list of trusted host names to validate the
 50 |         host against.
 51 |     """
 52 |     parts = {
 53 |         "scheme": environ["wsgi.url_scheme"],
 54 |         "host": get_host(environ, trusted_hosts),
 55 |     }
 56 | 
 57 |     if not host_only:
 58 |         parts["root_path"] = environ.get("SCRIPT_NAME", "")
 59 | 
 60 |         if not root_only:
 61 |             parts["path"] = environ.get("PATH_INFO", "")
 62 | 
 63 |             if not strip_querystring:
 64 |                 parts["query_string"] = environ.get("QUERY_STRING", "").encode("latin1")
 65 | 
 66 |     return _sansio_utils.get_current_url(**parts)
 67 | 
 68 | 
 69 | def _get_server(
 70 |     environ: WSGIEnvironment,
 71 | ) -> tuple[str, int | None] | None:
 72 |     name = environ.get("SERVER_NAME")
 73 | 
 74 |     if name is None:
 75 |         return None
 76 | 
 77 |     try:
 78 |         port: int | None = int(environ.get("SERVER_PORT", None))
 79 |     except (TypeError, ValueError):
 80 |         # unix socket
 81 |         port = None
 82 | 
 83 |     return name, port
 84 | 
 85 | 
 86 | def get_host(
 87 |     environ: WSGIEnvironment, trusted_hosts: t.Iterable[str] | None = None
 88 | ) -> str:
 89 |     """Return the host for the given WSGI environment.
 90 | 
 91 |     The ``Host`` header is preferred, then ``SERVER_NAME`` if it's not
 92 |     set. The returned host will only contain the port if it is different
 93 |     than the standard port for the protocol.
 94 | 
 95 |     Optionally, verify that the host is trusted using
 96 |     :func:`host_is_trusted` and raise a
 97 |     :exc:`~werkzeug.exceptions.SecurityError` if it is not.
 98 | 
 99 |     :param environ: A WSGI environment dict.
100 |     :param trusted_hosts: A list of trusted host names.
101 | 
102 |     :return: Host, with port if necessary.
103 |     :raise ~werkzeug.exceptions.SecurityError: If the host is not
104 |         trusted.
105 |     """
106 |     return _sansio_utils.get_host(
107 |         environ["wsgi.url_scheme"],
108 |         environ.get("HTTP_HOST"),
109 |         _get_server(environ),
110 |         trusted_hosts,
111 |     )
112 | 
113 | 
114 | def get_content_length(environ: WSGIEnvironment) -> int | None:
115 |     """Return the ``Content-Length`` header value as an int. If the header is not given
116 |     or the ``Transfer-Encoding`` header is ``chunked``, ``None`` is returned to indicate
117 |     a streaming request. If the value is not an integer, or negative, 0 is returned.
118 | 
119 |     :param environ: The WSGI environ to get the content length from.
120 | 
121 |     .. versionadded:: 0.9
122 |     """
123 |     return _sansio_utils.get_content_length(
124 |         http_content_length=environ.get("CONTENT_LENGTH"),
125 |         http_transfer_encoding=environ.get("HTTP_TRANSFER_ENCODING"),
126 |     )
127 | 
128 | 
129 | def get_input_stream(
130 |     environ: WSGIEnvironment,
131 |     safe_fallback: bool = True,
132 |     max_content_length: int | None = None,
133 | ) -> t.IO[bytes]:
134 |     """Return the WSGI input stream, wrapped so that it may be read safely without going
135 |     past the ``Content-Length`` header value or ``max_content_length``.
136 | 
137 |     If ``Content-Length`` exceeds ``max_content_length``, a
138 |     :exc:`RequestEntityTooLarge`` ``413 Content Too Large`` error is raised.
139 | 
140 |     If the WSGI server sets ``environ["wsgi.input_terminated"]``, it indicates that the
141 |     server handles terminating the stream, so it is safe to read directly. For example,
142 |     a server that knows how to handle chunked requests safely would set this.
143 | 
144 |     If ``max_content_length`` is set, it can be enforced on streams if
145 |     ``wsgi.input_terminated`` is set. Otherwise, an empty stream is returned unless the
146 |     user explicitly disables this safe fallback.
147 | 
148 |     If the limit is reached before the underlying stream is exhausted (such as a file
149 |     that is too large, or an infinite stream), the remaining contents of the stream
150 |     cannot be read safely. Depending on how the server handles this, clients may show a
151 |     "connection reset" failure instead of seeing the 413 response.
152 | 
153 |     :param environ: The WSGI environ containing the stream.
154 |     :param safe_fallback: Return an empty stream when ``Content-Length`` is not set.
155 |         Disabling this allows infinite streams, which can be a denial-of-service risk.
156 |     :param max_content_length: The maximum length that content-length or streaming
157 |         requests may not exceed.
158 | 
159 |     .. versionchanged:: 2.3.2
160 |         ``max_content_length`` is only applied to streaming requests if the server sets
161 |         ``wsgi.input_terminated``.
162 | 
163 |     .. versionchanged:: 2.3
164 |         Check ``max_content_length`` and raise an error if it is exceeded.
165 | 
166 |     .. versionadded:: 0.9
167 |     """
168 |     stream = t.cast(t.IO[bytes], environ["wsgi.input"])
169 |     content_length = get_content_length(environ)
170 | 
171 |     if content_length is not None and max_content_length is not None:
172 |         if content_length > max_content_length:
173 |             raise RequestEntityTooLarge()
174 | 
175 |     # A WSGI server can set this to indicate that it terminates the input stream. In
176 |     # that case the stream is safe without wrapping, or can enforce a max length.
177 |     if "wsgi.input_terminated" in environ:
178 |         if max_content_length is not None:
179 |             # If this is moved above, it can cause the stream to hang if a read attempt
180 |             # is made when the client sends no data. For example, the development server
181 |             # does not handle buffering except for chunked encoding.
182 |             return t.cast(
183 |                 t.IO[bytes], LimitedStream(stream, max_content_length, is_max=True)
184 |             )
185 | 
186 |         return stream
187 | 
188 |     # No limit given, return an empty stream unless the user explicitly allows the
189 |     # potentially infinite stream. An infinite stream is dangerous if it's not expected,
190 |     # as it can tie up a worker indefinitely.
191 |     if content_length is None:
192 |         return io.BytesIO() if safe_fallback else stream
193 | 
194 |     return t.cast(t.IO[bytes], LimitedStream(stream, content_length))
195 | 
196 | 
197 | def get_path_info(environ: WSGIEnvironment) -> str:
198 |     """Return ``PATH_INFO`` from  the WSGI environment.
199 | 
200 |     :param environ: WSGI environment to get the path from.
201 | 
202 |     .. versionchanged:: 3.0
203 |         The ``charset`` and ``errors`` parameters were removed.
204 | 
205 |     .. versionadded:: 0.9
206 |     """
207 |     path: bytes = environ.get("PATH_INFO", "").encode("latin1")
208 |     return path.decode(errors="replace")
209 | 
210 | 
211 | class ClosingIterator:
212 |     """The WSGI specification requires that all middlewares and gateways
213 |     respect the `close` callback of the iterable returned by the application.
214 |     Because it is useful to add another close action to a returned iterable
215 |     and adding a custom iterable is a boring task this class can be used for
216 |     that::
217 | 
218 |         return ClosingIterator(app(environ, start_response), [cleanup_session,
219 |                                                               cleanup_locals])
220 | 
221 |     If there is just one close function it can be passed instead of the list.
222 | 
223 |     A closing iterator is not needed if the application uses response objects
224 |     and finishes the processing if the response is started::
225 | 
226 |         try:
227 |             return response(environ, start_response)
228 |         finally:
229 |             cleanup_session()
230 |             cleanup_locals()
231 |     """
232 | 
233 |     def __init__(
234 |         self,
235 |         iterable: t.Iterable[bytes],
236 |         callbacks: None
237 |         | (t.Callable[[], None] | t.Iterable[t.Callable[[], None]]) = None,
238 |     ) -> None:
239 |         iterator = iter(iterable)
240 |         self._next = t.cast(t.Callable[[], bytes], partial(next, iterator))
241 |         if callbacks is None:
242 |             callbacks = []
243 |         elif callable(callbacks):
244 |             callbacks = [callbacks]
245 |         else:
246 |             callbacks = list(callbacks)
247 |         iterable_close = getattr(iterable, "close", None)
248 |         if iterable_close:
249 |             callbacks.insert(0, iterable_close)
250 |         self._callbacks = callbacks
251 | 
252 |     def __iter__(self) -> ClosingIterator:
253 |         return self
254 | 
255 |     def __next__(self) -> bytes:
256 |         return self._next()
257 | 
258 |     def close(self) -> None:
259 |         for callback in self._callbacks:
260 |             callback()
261 | 
262 | 
263 | def wrap_file(
264 |     environ: WSGIEnvironment, file: t.IO[bytes], buffer_size: int = 8192
265 | ) -> t.Iterable[bytes]:
266 |     """Wraps a file.  This uses the WSGI server's file wrapper if available
267 |     or otherwise the generic :class:`FileWrapper`.
268 | 
269 |     .. versionadded:: 0.5
270 | 
271 |     If the file wrapper from the WSGI server is used it's important to not
272 |     iterate over it from inside the application but to pass it through
273 |     unchanged.  If you want to pass out a file wrapper inside a response
274 |     object you have to set :attr:`Response.direct_passthrough` to `True`.
275 | 
276 |     More information about file wrappers are available in :pep:`333`.
277 | 
278 |     :param file: a :class:`file`-like object with a :meth:`~file.read` method.
279 |     :param buffer_size: number of bytes for one iteration.
280 |     """
281 |     return environ.get("wsgi.file_wrapper", FileWrapper)(  # type: ignore
282 |         file, buffer_size
283 |     )
284 | 
285 | 
286 | class FileWrapper:
287 |     """This class can be used to convert a :class:`file`-like object into
288 |     an iterable.  It yields `buffer_size` blocks until the file is fully
289 |     read.
290 | 
291 |     You should not use this class directly but rather use the
292 |     :func:`wrap_file` function that uses the WSGI server's file wrapper
293 |     support if it's available.
294 | 
295 |     .. versionadded:: 0.5
296 | 
297 |     If you're using this object together with a :class:`Response` you have
298 |     to use the `direct_passthrough` mode.
299 | 
300 |     :param file: a :class:`file`-like object with a :meth:`~file.read` method.
301 |     :param buffer_size: number of bytes for one iteration.
302 |     """
303 | 
304 |     def __init__(self, file: t.IO[bytes], buffer_size: int = 8192) -> None:
305 |         self.file = file
306 |         self.buffer_size = buffer_size
307 | 
308 |     def close(self) -> None:
309 |         if hasattr(self.file, "close"):
310 |             self.file.close()
311 | 
312 |     def seekable(self) -> bool:
313 |         if hasattr(self.file, "seekable"):
314 |             return self.file.seekable()
315 |         if hasattr(self.file, "seek"):
316 |             return True
317 |         return False
318 | 
319 |     def seek(self, *args: t.Any) -> None:
320 |         if hasattr(self.file, "seek"):
321 |             self.file.seek(*args)
322 | 
323 |     def tell(self) -> int | None:
324 |         if hasattr(self.file, "tell"):
325 |             return self.file.tell()
326 |         return None
327 | 
328 |     def __iter__(self) -> FileWrapper:
329 |         return self
330 | 
331 |     def __next__(self) -> bytes:
332 |         data = self.file.read(self.buffer_size)
333 |         if data:
334 |             return data
335 |         raise StopIteration()
336 | 
337 | 
338 | class _RangeWrapper:
339 |     # private for now, but should we make it public in the future ?
340 | 
341 |     """This class can be used to convert an iterable object into
342 |     an iterable that will only yield a piece of the underlying content.
343 |     It yields blocks until the underlying stream range is fully read.
344 |     The yielded blocks will have a size that can't exceed the original
345 |     iterator defined block size, but that can be smaller.
346 | 
347 |     If you're using this object together with a :class:`Response` you have
348 |     to use the `direct_passthrough` mode.
349 | 
350 |     :param iterable: an iterable object with a :meth:`__next__` method.
351 |     :param start_byte: byte from which read will start.
352 |     :param byte_range: how many bytes to read.
353 |     """
354 | 
355 |     def __init__(
356 |         self,
357 |         iterable: t.Iterable[bytes] | t.IO[bytes],
358 |         start_byte: int = 0,
359 |         byte_range: int | None = None,
360 |     ):
361 |         self.iterable = iter(iterable)
362 |         self.byte_range = byte_range
363 |         self.start_byte = start_byte
364 |         self.end_byte = None
365 | 
366 |         if byte_range is not None:
367 |             self.end_byte = start_byte + byte_range
368 | 
369 |         self.read_length = 0
370 |         self.seekable = hasattr(iterable, "seekable") and iterable.seekable()
371 |         self.end_reached = False
372 | 
373 |     def __iter__(self) -> _RangeWrapper:
374 |         return self
375 | 
376 |     def _next_chunk(self) -> bytes:
377 |         try:
378 |             chunk = next(self.iterable)
379 |             self.read_length += len(chunk)
380 |             return chunk
381 |         except StopIteration:
382 |             self.end_reached = True
383 |             raise
384 | 
385 |     def _first_iteration(self) -> tuple[bytes | None, int]:
386 |         chunk = None
387 |         if self.seekable:
388 |             self.iterable.seek(self.start_byte)  # type: ignore
389 |             self.read_length = self.iterable.tell()  # type: ignore
390 |             contextual_read_length = self.read_length
391 |         else:
392 |             while self.read_length <= self.start_byte:
393 |                 chunk = self._next_chunk()
394 |             if chunk is not None:
395 |                 chunk = chunk[self.start_byte - self.read_length :]
396 |             contextual_read_length = self.start_byte
397 |         return chunk, contextual_read_length
398 | 
399 |     def _next(self) -> bytes:
400 |         if self.end_reached:
401 |             raise StopIteration()
402 |         chunk = None
403 |         contextual_read_length = self.read_length
404 |         if self.read_length == 0:
405 |             chunk, contextual_read_length = self._first_iteration()
406 |         if chunk is None:
407 |             chunk = self._next_chunk()
408 |         if self.end_byte is not None and self.read_length >= self.end_byte:
409 |             self.end_reached = True
410 |             return chunk[: self.end_byte - contextual_read_length]
411 |         return chunk
412 | 
413 |     def __next__(self) -> bytes:
414 |         chunk = self._next()
415 |         if chunk:
416 |             return chunk
417 |         self.end_reached = True
418 |         raise StopIteration()
419 | 
420 |     def close(self) -> None:
421 |         if hasattr(self.iterable, "close"):
422 |             self.iterable.close()
423 | 
424 | 
425 | class LimitedStream(io.RawIOBase):
426 |     """Wrap a stream so that it doesn't read more than a given limit. This is used to
427 |     limit ``wsgi.input`` to the ``Content-Length`` header value or
428 |     :attr:`.Request.max_content_length`.
429 | 
430 |     When attempting to read after the limit has been reached, :meth:`on_exhausted` is
431 |     called. When the limit is a maximum, this raises :exc:`.RequestEntityTooLarge`.
432 | 
433 |     If reading from the stream returns zero bytes or raises an error,
434 |     :meth:`on_disconnect` is called, which raises :exc:`.ClientDisconnected`. When the
435 |     limit is a maximum and zero bytes were read, no error is raised, since it may be the
436 |     end of the stream.
437 | 
438 |     If the limit is reached before the underlying stream is exhausted (such as a file
439 |     that is too large, or an infinite stream), the remaining contents of the stream
440 |     cannot be read safely. Depending on how the server handles this, clients may show a
441 |     "connection reset" failure instead of seeing the 413 response.
442 | 
443 |     :param stream: The stream to read from. Must be a readable binary IO object.
444 |     :param limit: The limit in bytes to not read past. Should be either the
445 |         ``Content-Length`` header value or ``request.max_content_length``.
446 |     :param is_max: Whether the given ``limit`` is ``request.max_content_length`` instead
447 |         of the ``Content-Length`` header value. This changes how exhausted and
448 |         disconnect events are handled.
449 | 
450 |     .. versionchanged:: 2.3
451 |         Handle ``max_content_length`` differently than ``Content-Length``.
452 | 
453 |     .. versionchanged:: 2.3
454 |         Implements ``io.RawIOBase`` rather than ``io.IOBase``.
455 |     """
456 | 
457 |     def __init__(self, stream: t.IO[bytes], limit: int, is_max: bool = False) -> None:
458 |         self._stream = stream
459 |         self._pos = 0
460 |         self.limit = limit
461 |         self._limit_is_max = is_max
462 | 
463 |     @property
464 |     def is_exhausted(self) -> bool:
465 |         """Whether the current stream position has reached the limit."""
466 |         return self._pos >= self.limit
467 | 
468 |     def on_exhausted(self) -> None:
469 |         """Called when attempting to read after the limit has been reached.
470 | 
471 |         The default behavior is to do nothing, unless the limit is a maximum, in which
472 |         case it raises :exc:`.RequestEntityTooLarge`.
473 | 
474 |         .. versionchanged:: 2.3
475 |             Raises ``RequestEntityTooLarge`` if the limit is a maximum.
476 | 
477 |         .. versionchanged:: 2.3
478 |             Any return value is ignored.
479 |         """
480 |         if self._limit_is_max:
481 |             raise RequestEntityTooLarge()
482 | 
483 |     def on_disconnect(self, error: Exception | None = None) -> None:
484 |         """Called when an attempted read receives zero bytes before the limit was
485 |         reached. This indicates that the client disconnected before sending the full
486 |         request body.
487 | 
488 |         The default behavior is to raise :exc:`.ClientDisconnected`, unless the limit is
489 |         a maximum and no error was raised.
490 | 
491 |         .. versionchanged:: 2.3
492 |             Added the ``error`` parameter. Do nothing if the limit is a maximum and no
493 |             error was raised.
494 | 
495 |         .. versionchanged:: 2.3
496 |             Any return value is ignored.
497 |         """
498 |         if not self._limit_is_max or error is not None:
499 |             raise ClientDisconnected()
500 | 
501 |         # If the limit is a maximum, then we may have read zero bytes because the
502 |         # streaming body is complete. There's no way to distinguish that from the
503 |         # client disconnecting early.
504 | 
505 |     def exhaust(self) -> bytes:
506 |         """Exhaust the stream by reading until the limit is reached or the client
507 |         disconnects, returning the remaining data.
508 | 
509 |         .. versionchanged:: 2.3
510 |             Return the remaining data.
511 | 
512 |         .. versionchanged:: 2.2.3
513 |             Handle case where wrapped stream returns fewer bytes than requested.
514 |         """
515 |         if not self.is_exhausted:
516 |             return self.readall()
517 | 
518 |         return b""
519 | 
520 |     def readinto(self, b: bytearray) -> int | None:  # type: ignore[override]
521 |         size = len(b)
522 |         remaining = self.limit - self._pos
523 | 
524 |         if remaining <= 0:
525 |             self.on_exhausted()
526 |             return 0
527 | 
528 |         if hasattr(self._stream, "readinto"):
529 |             # Use stream.readinto if it's available.
530 |             if size <= remaining:
531 |                 # The size fits in the remaining limit, use the buffer directly.
532 |                 try:
533 |                     out_size: int | None = self._stream.readinto(b)
534 |                 except (OSError, ValueError) as e:
535 |                     self.on_disconnect(error=e)
536 |                     return 0
537 |             else:
538 |                 # Use a temp buffer with the remaining limit as the size.
539 |                 temp_b = bytearray(remaining)
540 | 
541 |                 try:
542 |                     out_size = self._stream.readinto(temp_b)
543 |                 except (OSError, ValueError) as e:
544 |                     self.on_disconnect(error=e)
545 |                     return 0
546 | 
547 |                 if out_size:
548 |                     b[:out_size] = temp_b
549 |         else:
550 |             # WSGI requires that stream.read is available.
551 |             try:
552 |                 data = self._stream.read(min(size, remaining))
553 |             except (OSError, ValueError) as e:
554 |                 self.on_disconnect(error=e)
555 |                 return 0
556 | 
557 |             out_size = len(data)
558 |             b[:out_size] = data
559 | 
560 |         if not out_size:
561 |             # Read zero bytes from the stream.
562 |             self.on_disconnect()
563 |             return 0
564 | 
565 |         self._pos += out_size
566 |         return out_size
567 | 
568 |     def readall(self) -> bytes:
569 |         if self.is_exhausted:
570 |             self.on_exhausted()
571 |             return b""
572 | 
573 |         out = bytearray()
574 | 
575 |         # The parent implementation uses "while True", which results in an extra read.
576 |         while not self.is_exhausted:
577 |             data = self.read(1024 * 64)
578 | 
579 |             # Stream may return empty before a max limit is reached.
580 |             if not data:
581 |                 break
582 | 
583 |             out.extend(data)
584 | 
585 |         return bytes(out)
586 | 
587 |     def tell(self) -> int:
588 |         """Return the current stream position.
589 | 
590 |         .. versionadded:: 0.9
591 |         """
592 |         return self._pos
593 | 
594 |     def readable(self) -> bool:
595 |         return True
596 | 
```

--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/models/link.py:
--------------------------------------------------------------------------------

```python
  1 | import functools
  2 | import itertools
  3 | import logging
  4 | import os
  5 | import posixpath
  6 | import re
  7 | import urllib.parse
  8 | from dataclasses import dataclass
  9 | from typing import (
 10 |     TYPE_CHECKING,
 11 |     Any,
 12 |     Dict,
 13 |     List,
 14 |     Mapping,
 15 |     NamedTuple,
 16 |     Optional,
 17 |     Tuple,
 18 |     Union,
 19 | )
 20 | 
 21 | from pip._internal.utils.deprecation import deprecated
 22 | from pip._internal.utils.filetypes import WHEEL_EXTENSION
 23 | from pip._internal.utils.hashes import Hashes
 24 | from pip._internal.utils.misc import (
 25 |     pairwise,
 26 |     redact_auth_from_url,
 27 |     split_auth_from_netloc,
 28 |     splitext,
 29 | )
 30 | from pip._internal.utils.urls import path_to_url, url_to_path
 31 | 
 32 | if TYPE_CHECKING:
 33 |     from pip._internal.index.collector import IndexContent
 34 | 
 35 | logger = logging.getLogger(__name__)
 36 | 
 37 | 
 38 | # Order matters, earlier hashes have a precedence over later hashes for what
 39 | # we will pick to use.
 40 | _SUPPORTED_HASHES = ("sha512", "sha384", "sha256", "sha224", "sha1", "md5")
 41 | 
 42 | 
 43 | @dataclass(frozen=True)
 44 | class LinkHash:
 45 |     """Links to content may have embedded hash values. This class parses those.
 46 | 
 47 |     `name` must be any member of `_SUPPORTED_HASHES`.
 48 | 
 49 |     This class can be converted to and from `ArchiveInfo`. While ArchiveInfo intends to
 50 |     be JSON-serializable to conform to PEP 610, this class contains the logic for
 51 |     parsing a hash name and value for correctness, and then checking whether that hash
 52 |     conforms to a schema with `.is_hash_allowed()`."""
 53 | 
 54 |     name: str
 55 |     value: str
 56 | 
 57 |     _hash_url_fragment_re = re.compile(
 58 |         # NB: we do not validate that the second group (.*) is a valid hex
 59 |         # digest. Instead, we simply keep that string in this class, and then check it
 60 |         # against Hashes when hash-checking is needed. This is easier to debug than
 61 |         # proactively discarding an invalid hex digest, as we handle incorrect hashes
 62 |         # and malformed hashes in the same place.
 63 |         r"[#&]({choices})=([^&]*)".format(
 64 |             choices="|".join(re.escape(hash_name) for hash_name in _SUPPORTED_HASHES)
 65 |         ),
 66 |     )
 67 | 
 68 |     def __post_init__(self) -> None:
 69 |         assert self.name in _SUPPORTED_HASHES
 70 | 
 71 |     @classmethod
 72 |     @functools.lru_cache(maxsize=None)
 73 |     def find_hash_url_fragment(cls, url: str) -> Optional["LinkHash"]:
 74 |         """Search a string for a checksum algorithm name and encoded output value."""
 75 |         match = cls._hash_url_fragment_re.search(url)
 76 |         if match is None:
 77 |             return None
 78 |         name, value = match.groups()
 79 |         return cls(name=name, value=value)
 80 | 
 81 |     def as_dict(self) -> Dict[str, str]:
 82 |         return {self.name: self.value}
 83 | 
 84 |     def as_hashes(self) -> Hashes:
 85 |         """Return a Hashes instance which checks only for the current hash."""
 86 |         return Hashes({self.name: [self.value]})
 87 | 
 88 |     def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool:
 89 |         """
 90 |         Return True if the current hash is allowed by `hashes`.
 91 |         """
 92 |         if hashes is None:
 93 |             return False
 94 |         return hashes.is_hash_allowed(self.name, hex_digest=self.value)
 95 | 
 96 | 
 97 | @dataclass(frozen=True)
 98 | class MetadataFile:
 99 |     """Information about a core metadata file associated with a distribution."""
100 | 
101 |     hashes: Optional[Dict[str, str]]
102 | 
103 |     def __post_init__(self) -> None:
104 |         if self.hashes is not None:
105 |             assert all(name in _SUPPORTED_HASHES for name in self.hashes)
106 | 
107 | 
108 | def supported_hashes(hashes: Optional[Dict[str, str]]) -> Optional[Dict[str, str]]:
109 |     # Remove any unsupported hash types from the mapping. If this leaves no
110 |     # supported hashes, return None
111 |     if hashes is None:
112 |         return None
113 |     hashes = {n: v for n, v in hashes.items() if n in _SUPPORTED_HASHES}
114 |     if not hashes:
115 |         return None
116 |     return hashes
117 | 
118 | 
119 | def _clean_url_path_part(part: str) -> str:
120 |     """
121 |     Clean a "part" of a URL path (i.e. after splitting on "@" characters).
122 |     """
123 |     # We unquote prior to quoting to make sure nothing is double quoted.
124 |     return urllib.parse.quote(urllib.parse.unquote(part))
125 | 
126 | 
127 | def _clean_file_url_path(part: str) -> str:
128 |     """
129 |     Clean the first part of a URL path that corresponds to a local
130 |     filesystem path (i.e. the first part after splitting on "@" characters).
131 |     """
132 |     # We unquote prior to quoting to make sure nothing is double quoted.
133 |     # Also, on Windows the path part might contain a drive letter which
134 |     # should not be quoted. On Linux where drive letters do not
135 |     # exist, the colon should be quoted. We rely on urllib.request
136 |     # to do the right thing here.
137 |     return urllib.request.pathname2url(urllib.request.url2pathname(part))
138 | 
139 | 
140 | # percent-encoded:                   /
141 | _reserved_chars_re = re.compile("(@|%2F)", re.IGNORECASE)
142 | 
143 | 
144 | def _clean_url_path(path: str, is_local_path: bool) -> str:
145 |     """
146 |     Clean the path portion of a URL.
147 |     """
148 |     if is_local_path:
149 |         clean_func = _clean_file_url_path
150 |     else:
151 |         clean_func = _clean_url_path_part
152 | 
153 |     # Split on the reserved characters prior to cleaning so that
154 |     # revision strings in VCS URLs are properly preserved.
155 |     parts = _reserved_chars_re.split(path)
156 | 
157 |     cleaned_parts = []
158 |     for to_clean, reserved in pairwise(itertools.chain(parts, [""])):
159 |         cleaned_parts.append(clean_func(to_clean))
160 |         # Normalize %xx escapes (e.g. %2f -> %2F)
161 |         cleaned_parts.append(reserved.upper())
162 | 
163 |     return "".join(cleaned_parts)
164 | 
165 | 
166 | def _ensure_quoted_url(url: str) -> str:
167 |     """
168 |     Make sure a link is fully quoted.
169 |     For example, if ' ' occurs in the URL, it will be replaced with "%20",
170 |     and without double-quoting other characters.
171 |     """
172 |     # Split the URL into parts according to the general structure
173 |     # `scheme://netloc/path;parameters?query#fragment`.
174 |     result = urllib.parse.urlparse(url)
175 |     # If the netloc is empty, then the URL refers to a local filesystem path.
176 |     is_local_path = not result.netloc
177 |     path = _clean_url_path(result.path, is_local_path=is_local_path)
178 |     return urllib.parse.urlunparse(result._replace(path=path))
179 | 
180 | 
181 | @functools.total_ordering
182 | class Link:
183 |     """Represents a parsed link from a Package Index's simple URL"""
184 | 
185 |     __slots__ = [
186 |         "_parsed_url",
187 |         "_url",
188 |         "_hashes",
189 |         "comes_from",
190 |         "requires_python",
191 |         "yanked_reason",
192 |         "metadata_file_data",
193 |         "cache_link_parsing",
194 |         "egg_fragment",
195 |     ]
196 | 
197 |     def __init__(
198 |         self,
199 |         url: str,
200 |         comes_from: Optional[Union[str, "IndexContent"]] = None,
201 |         requires_python: Optional[str] = None,
202 |         yanked_reason: Optional[str] = None,
203 |         metadata_file_data: Optional[MetadataFile] = None,
204 |         cache_link_parsing: bool = True,
205 |         hashes: Optional[Mapping[str, str]] = None,
206 |     ) -> None:
207 |         """
208 |         :param url: url of the resource pointed to (href of the link)
209 |         :param comes_from: instance of IndexContent where the link was found,
210 |             or string.
211 |         :param requires_python: String containing the `Requires-Python`
212 |             metadata field, specified in PEP 345. This may be specified by
213 |             a data-requires-python attribute in the HTML link tag, as
214 |             described in PEP 503.
215 |         :param yanked_reason: the reason the file has been yanked, if the
216 |             file has been yanked, or None if the file hasn't been yanked.
217 |             This is the value of the "data-yanked" attribute, if present, in
218 |             a simple repository HTML link. If the file has been yanked but
219 |             no reason was provided, this should be the empty string. See
220 |             PEP 592 for more information and the specification.
221 |         :param metadata_file_data: the metadata attached to the file, or None if
222 |             no such metadata is provided. This argument, if not None, indicates
223 |             that a separate metadata file exists, and also optionally supplies
224 |             hashes for that file.
225 |         :param cache_link_parsing: A flag that is used elsewhere to determine
226 |             whether resources retrieved from this link should be cached. PyPI
227 |             URLs should generally have this set to False, for example.
228 |         :param hashes: A mapping of hash names to digests to allow us to
229 |             determine the validity of a download.
230 |         """
231 | 
232 |         # The comes_from, requires_python, and metadata_file_data arguments are
233 |         # only used by classmethods of this class, and are not used in client
234 |         # code directly.
235 | 
236 |         # url can be a UNC windows share
237 |         if url.startswith("\\\\"):
238 |             url = path_to_url(url)
239 | 
240 |         self._parsed_url = urllib.parse.urlsplit(url)
241 |         # Store the url as a private attribute to prevent accidentally
242 |         # trying to set a new value.
243 |         self._url = url
244 | 
245 |         link_hash = LinkHash.find_hash_url_fragment(url)
246 |         hashes_from_link = {} if link_hash is None else link_hash.as_dict()
247 |         if hashes is None:
248 |             self._hashes = hashes_from_link
249 |         else:
250 |             self._hashes = {**hashes, **hashes_from_link}
251 | 
252 |         self.comes_from = comes_from
253 |         self.requires_python = requires_python if requires_python else None
254 |         self.yanked_reason = yanked_reason
255 |         self.metadata_file_data = metadata_file_data
256 | 
257 |         self.cache_link_parsing = cache_link_parsing
258 |         self.egg_fragment = self._egg_fragment()
259 | 
260 |     @classmethod
261 |     def from_json(
262 |         cls,
263 |         file_data: Dict[str, Any],
264 |         page_url: str,
265 |     ) -> Optional["Link"]:
266 |         """
267 |         Convert an pypi json document from a simple repository page into a Link.
268 |         """
269 |         file_url = file_data.get("url")
270 |         if file_url is None:
271 |             return None
272 | 
273 |         url = _ensure_quoted_url(urllib.parse.urljoin(page_url, file_url))
274 |         pyrequire = file_data.get("requires-python")
275 |         yanked_reason = file_data.get("yanked")
276 |         hashes = file_data.get("hashes", {})
277 | 
278 |         # PEP 714: Indexes must use the name core-metadata, but
279 |         # clients should support the old name as a fallback for compatibility.
280 |         metadata_info = file_data.get("core-metadata")
281 |         if metadata_info is None:
282 |             metadata_info = file_data.get("dist-info-metadata")
283 | 
284 |         # The metadata info value may be a boolean, or a dict of hashes.
285 |         if isinstance(metadata_info, dict):
286 |             # The file exists, and hashes have been supplied
287 |             metadata_file_data = MetadataFile(supported_hashes(metadata_info))
288 |         elif metadata_info:
289 |             # The file exists, but there are no hashes
290 |             metadata_file_data = MetadataFile(None)
291 |         else:
292 |             # False or not present: the file does not exist
293 |             metadata_file_data = None
294 | 
295 |         # The Link.yanked_reason expects an empty string instead of a boolean.
296 |         if yanked_reason and not isinstance(yanked_reason, str):
297 |             yanked_reason = ""
298 |         # The Link.yanked_reason expects None instead of False.
299 |         elif not yanked_reason:
300 |             yanked_reason = None
301 | 
302 |         return cls(
303 |             url,
304 |             comes_from=page_url,
305 |             requires_python=pyrequire,
306 |             yanked_reason=yanked_reason,
307 |             hashes=hashes,
308 |             metadata_file_data=metadata_file_data,
309 |         )
310 | 
311 |     @classmethod
312 |     def from_element(
313 |         cls,
314 |         anchor_attribs: Dict[str, Optional[str]],
315 |         page_url: str,
316 |         base_url: str,
317 |     ) -> Optional["Link"]:
318 |         """
319 |         Convert an anchor element's attributes in a simple repository page to a Link.
320 |         """
321 |         href = anchor_attribs.get("href")
322 |         if not href:
323 |             return None
324 | 
325 |         url = _ensure_quoted_url(urllib.parse.urljoin(base_url, href))
326 |         pyrequire = anchor_attribs.get("data-requires-python")
327 |         yanked_reason = anchor_attribs.get("data-yanked")
328 | 
329 |         # PEP 714: Indexes must use the name data-core-metadata, but
330 |         # clients should support the old name as a fallback for compatibility.
331 |         metadata_info = anchor_attribs.get("data-core-metadata")
332 |         if metadata_info is None:
333 |             metadata_info = anchor_attribs.get("data-dist-info-metadata")
334 |         # The metadata info value may be the string "true", or a string of
335 |         # the form "hashname=hashval"
336 |         if metadata_info == "true":
337 |             # The file exists, but there are no hashes
338 |             metadata_file_data = MetadataFile(None)
339 |         elif metadata_info is None:
340 |             # The file does not exist
341 |             metadata_file_data = None
342 |         else:
343 |             # The file exists, and hashes have been supplied
344 |             hashname, sep, hashval = metadata_info.partition("=")
345 |             if sep == "=":
346 |                 metadata_file_data = MetadataFile(supported_hashes({hashname: hashval}))
347 |             else:
348 |                 # Error - data is wrong. Treat as no hashes supplied.
349 |                 logger.debug(
350 |                     "Index returned invalid data-dist-info-metadata value: %s",
351 |                     metadata_info,
352 |                 )
353 |                 metadata_file_data = MetadataFile(None)
354 | 
355 |         return cls(
356 |             url,
357 |             comes_from=page_url,
358 |             requires_python=pyrequire,
359 |             yanked_reason=yanked_reason,
360 |             metadata_file_data=metadata_file_data,
361 |         )
362 | 
363 |     def __str__(self) -> str:
364 |         if self.requires_python:
365 |             rp = f" (requires-python:{self.requires_python})"
366 |         else:
367 |             rp = ""
368 |         if self.comes_from:
369 |             return f"{redact_auth_from_url(self._url)} (from {self.comes_from}){rp}"
370 |         else:
371 |             return redact_auth_from_url(str(self._url))
372 | 
373 |     def __repr__(self) -> str:
374 |         return f"<Link {self}>"
375 | 
376 |     def __hash__(self) -> int:
377 |         return hash(self.url)
378 | 
379 |     def __eq__(self, other: Any) -> bool:
380 |         if not isinstance(other, Link):
381 |             return NotImplemented
382 |         return self.url == other.url
383 | 
384 |     def __lt__(self, other: Any) -> bool:
385 |         if not isinstance(other, Link):
386 |             return NotImplemented
387 |         return self.url < other.url
388 | 
389 |     @property
390 |     def url(self) -> str:
391 |         return self._url
392 | 
393 |     @property
394 |     def filename(self) -> str:
395 |         path = self.path.rstrip("/")
396 |         name = posixpath.basename(path)
397 |         if not name:
398 |             # Make sure we don't leak auth information if the netloc
399 |             # includes a username and password.
400 |             netloc, user_pass = split_auth_from_netloc(self.netloc)
401 |             return netloc
402 | 
403 |         name = urllib.parse.unquote(name)
404 |         assert name, f"URL {self._url!r} produced no filename"
405 |         return name
406 | 
407 |     @property
408 |     def file_path(self) -> str:
409 |         return url_to_path(self.url)
410 | 
411 |     @property
412 |     def scheme(self) -> str:
413 |         return self._parsed_url.scheme
414 | 
415 |     @property
416 |     def netloc(self) -> str:
417 |         """
418 |         This can contain auth information.
419 |         """
420 |         return self._parsed_url.netloc
421 | 
422 |     @property
423 |     def path(self) -> str:
424 |         return urllib.parse.unquote(self._parsed_url.path)
425 | 
426 |     def splitext(self) -> Tuple[str, str]:
427 |         return splitext(posixpath.basename(self.path.rstrip("/")))
428 | 
429 |     @property
430 |     def ext(self) -> str:
431 |         return self.splitext()[1]
432 | 
433 |     @property
434 |     def url_without_fragment(self) -> str:
435 |         scheme, netloc, path, query, fragment = self._parsed_url
436 |         return urllib.parse.urlunsplit((scheme, netloc, path, query, ""))
437 | 
438 |     _egg_fragment_re = re.compile(r"[#&]egg=([^&]*)")
439 | 
440 |     # Per PEP 508.
441 |     _project_name_re = re.compile(
442 |         r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$", re.IGNORECASE
443 |     )
444 | 
445 |     def _egg_fragment(self) -> Optional[str]:
446 |         match = self._egg_fragment_re.search(self._url)
447 |         if not match:
448 |             return None
449 | 
450 |         # An egg fragment looks like a PEP 508 project name, along with
451 |         # an optional extras specifier. Anything else is invalid.
452 |         project_name = match.group(1)
453 |         if not self._project_name_re.match(project_name):
454 |             deprecated(
455 |                 reason=f"{self} contains an egg fragment with a non-PEP 508 name",
456 |                 replacement="to use the req @ url syntax, and remove the egg fragment",
457 |                 gone_in="25.0",
458 |                 issue=11617,
459 |             )
460 | 
461 |         return project_name
462 | 
463 |     _subdirectory_fragment_re = re.compile(r"[#&]subdirectory=([^&]*)")
464 | 
465 |     @property
466 |     def subdirectory_fragment(self) -> Optional[str]:
467 |         match = self._subdirectory_fragment_re.search(self._url)
468 |         if not match:
469 |             return None
470 |         return match.group(1)
471 | 
472 |     def metadata_link(self) -> Optional["Link"]:
473 |         """Return a link to the associated core metadata file (if any)."""
474 |         if self.metadata_file_data is None:
475 |             return None
476 |         metadata_url = f"{self.url_without_fragment}.metadata"
477 |         if self.metadata_file_data.hashes is None:
478 |             return Link(metadata_url)
479 |         return Link(metadata_url, hashes=self.metadata_file_data.hashes)
480 | 
481 |     def as_hashes(self) -> Hashes:
482 |         return Hashes({k: [v] for k, v in self._hashes.items()})
483 | 
484 |     @property
485 |     def hash(self) -> Optional[str]:
486 |         return next(iter(self._hashes.values()), None)
487 | 
488 |     @property
489 |     def hash_name(self) -> Optional[str]:
490 |         return next(iter(self._hashes), None)
491 | 
492 |     @property
493 |     def show_url(self) -> str:
494 |         return posixpath.basename(self._url.split("#", 1)[0].split("?", 1)[0])
495 | 
496 |     @property
497 |     def is_file(self) -> bool:
498 |         return self.scheme == "file"
499 | 
500 |     def is_existing_dir(self) -> bool:
501 |         return self.is_file and os.path.isdir(self.file_path)
502 | 
503 |     @property
504 |     def is_wheel(self) -> bool:
505 |         return self.ext == WHEEL_EXTENSION
506 | 
507 |     @property
508 |     def is_vcs(self) -> bool:
509 |         from pip._internal.vcs import vcs
510 | 
511 |         return self.scheme in vcs.all_schemes
512 | 
513 |     @property
514 |     def is_yanked(self) -> bool:
515 |         return self.yanked_reason is not None
516 | 
517 |     @property
518 |     def has_hash(self) -> bool:
519 |         return bool(self._hashes)
520 | 
521 |     def is_hash_allowed(self, hashes: Optional[Hashes]) -> bool:
522 |         """
523 |         Return True if the link has a hash and it is allowed by `hashes`.
524 |         """
525 |         if hashes is None:
526 |             return False
527 |         return any(hashes.is_hash_allowed(k, v) for k, v in self._hashes.items())
528 | 
529 | 
530 | class _CleanResult(NamedTuple):
531 |     """Convert link for equivalency check.
532 | 
533 |     This is used in the resolver to check whether two URL-specified requirements
534 |     likely point to the same distribution and can be considered equivalent. This
535 |     equivalency logic avoids comparing URLs literally, which can be too strict
536 |     (e.g. "a=1&b=2" vs "b=2&a=1") and produce conflicts unexpecting to users.
537 | 
538 |     Currently this does three things:
539 | 
540 |     1. Drop the basic auth part. This is technically wrong since a server can
541 |        serve different content based on auth, but if it does that, it is even
542 |        impossible to guarantee two URLs without auth are equivalent, since
543 |        the user can input different auth information when prompted. So the
544 |        practical solution is to assume the auth doesn't affect the response.
545 |     2. Parse the query to avoid the ordering issue. Note that ordering under the
546 |        same key in the query are NOT cleaned; i.e. "a=1&a=2" and "a=2&a=1" are
547 |        still considered different.
548 |     3. Explicitly drop most of the fragment part, except ``subdirectory=`` and
549 |        hash values, since it should have no impact the downloaded content. Note
550 |        that this drops the "egg=" part historically used to denote the requested
551 |        project (and extras), which is wrong in the strictest sense, but too many
552 |        people are supplying it inconsistently to cause superfluous resolution
553 |        conflicts, so we choose to also ignore them.
554 |     """
555 | 
556 |     parsed: urllib.parse.SplitResult
557 |     query: Dict[str, List[str]]
558 |     subdirectory: str
559 |     hashes: Dict[str, str]
560 | 
561 | 
562 | def _clean_link(link: Link) -> _CleanResult:
563 |     parsed = link._parsed_url
564 |     netloc = parsed.netloc.rsplit("@", 1)[-1]
565 |     # According to RFC 8089, an empty host in file: means localhost.
566 |     if parsed.scheme == "file" and not netloc:
567 |         netloc = "localhost"
568 |     fragment = urllib.parse.parse_qs(parsed.fragment)
569 |     if "egg" in fragment:
570 |         logger.debug("Ignoring egg= fragment in %s", link)
571 |     try:
572 |         # If there are multiple subdirectory values, use the first one.
573 |         # This matches the behavior of Link.subdirectory_fragment.
574 |         subdirectory = fragment["subdirectory"][0]
575 |     except (IndexError, KeyError):
576 |         subdirectory = ""
577 |     # If there are multiple hash values under the same algorithm, use the
578 |     # first one. This matches the behavior of Link.hash_value.
579 |     hashes = {k: fragment[k][0] for k in _SUPPORTED_HASHES if k in fragment}
580 |     return _CleanResult(
581 |         parsed=parsed._replace(netloc=netloc, query="", fragment=""),
582 |         query=urllib.parse.parse_qs(parsed.query),
583 |         subdirectory=subdirectory,
584 |         hashes=hashes,
585 |     )
586 | 
587 | 
588 | @functools.lru_cache(maxsize=None)
589 | def links_equivalent(link1: Link, link2: Link) -> bool:
590 |     return _clean_link(link1) == _clean_link(link2)
591 | 
```
Page 71/168FirstPrevNextLast