This is page 88 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/_vendor/requests/adapters.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | requests.adapters
3 | ~~~~~~~~~~~~~~~~~
4 |
5 | This module contains the transport adapters that Requests uses to define
6 | and maintain connections.
7 | """
8 |
9 | import os.path
10 | import socket # noqa: F401
11 | import typing
12 | import warnings
13 |
14 | from pip._vendor.urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
15 | from pip._vendor.urllib3.exceptions import HTTPError as _HTTPError
16 | from pip._vendor.urllib3.exceptions import InvalidHeader as _InvalidHeader
17 | from pip._vendor.urllib3.exceptions import (
18 | LocationValueError,
19 | MaxRetryError,
20 | NewConnectionError,
21 | ProtocolError,
22 | )
23 | from pip._vendor.urllib3.exceptions import ProxyError as _ProxyError
24 | from pip._vendor.urllib3.exceptions import ReadTimeoutError, ResponseError
25 | from pip._vendor.urllib3.exceptions import SSLError as _SSLError
26 | from pip._vendor.urllib3.poolmanager import PoolManager, proxy_from_url
27 | from pip._vendor.urllib3.util import Timeout as TimeoutSauce
28 | from pip._vendor.urllib3.util import parse_url
29 | from pip._vendor.urllib3.util.retry import Retry
30 | from pip._vendor.urllib3.util.ssl_ import create_urllib3_context
31 |
32 | from .auth import _basic_auth_str
33 | from .compat import basestring, urlparse
34 | from .cookies import extract_cookies_to_jar
35 | from .exceptions import (
36 | ConnectionError,
37 | ConnectTimeout,
38 | InvalidHeader,
39 | InvalidProxyURL,
40 | InvalidSchema,
41 | InvalidURL,
42 | ProxyError,
43 | ReadTimeout,
44 | RetryError,
45 | SSLError,
46 | )
47 | from .models import Response
48 | from .structures import CaseInsensitiveDict
49 | from .utils import (
50 | DEFAULT_CA_BUNDLE_PATH,
51 | extract_zipped_paths,
52 | get_auth_from_url,
53 | get_encoding_from_headers,
54 | prepend_scheme_if_needed,
55 | select_proxy,
56 | urldefragauth,
57 | )
58 |
59 | try:
60 | from pip._vendor.urllib3.contrib.socks import SOCKSProxyManager
61 | except ImportError:
62 |
63 | def SOCKSProxyManager(*args, **kwargs):
64 | raise InvalidSchema("Missing dependencies for SOCKS support.")
65 |
66 |
67 | if typing.TYPE_CHECKING:
68 | from .models import PreparedRequest
69 |
70 |
71 | DEFAULT_POOLBLOCK = False
72 | DEFAULT_POOLSIZE = 10
73 | DEFAULT_RETRIES = 0
74 | DEFAULT_POOL_TIMEOUT = None
75 |
76 |
77 | try:
78 | import ssl # noqa: F401
79 |
80 | _preloaded_ssl_context = create_urllib3_context()
81 | _preloaded_ssl_context.load_verify_locations(
82 | extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
83 | )
84 | except ImportError:
85 | # Bypass default SSLContext creation when Python
86 | # interpreter isn't built with the ssl module.
87 | _preloaded_ssl_context = None
88 |
89 |
90 | def _urllib3_request_context(
91 | request: "PreparedRequest",
92 | verify: "bool | str | None",
93 | client_cert: "typing.Tuple[str, str] | str | None",
94 | poolmanager: "PoolManager",
95 | ) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
96 | host_params = {}
97 | pool_kwargs = {}
98 | parsed_request_url = urlparse(request.url)
99 | scheme = parsed_request_url.scheme.lower()
100 | port = parsed_request_url.port
101 |
102 | # Determine if we have and should use our default SSLContext
103 | # to optimize performance on standard requests.
104 | poolmanager_kwargs = getattr(poolmanager, "connection_pool_kw", {})
105 | has_poolmanager_ssl_context = poolmanager_kwargs.get("ssl_context")
106 | should_use_default_ssl_context = (
107 | _preloaded_ssl_context is not None and not has_poolmanager_ssl_context
108 | )
109 |
110 | cert_reqs = "CERT_REQUIRED"
111 | if verify is False:
112 | cert_reqs = "CERT_NONE"
113 | elif verify is True and should_use_default_ssl_context:
114 | pool_kwargs["ssl_context"] = _preloaded_ssl_context
115 | elif isinstance(verify, str):
116 | if not os.path.isdir(verify):
117 | pool_kwargs["ca_certs"] = verify
118 | else:
119 | pool_kwargs["ca_cert_dir"] = verify
120 | pool_kwargs["cert_reqs"] = cert_reqs
121 | if client_cert is not None:
122 | if isinstance(client_cert, tuple) and len(client_cert) == 2:
123 | pool_kwargs["cert_file"] = client_cert[0]
124 | pool_kwargs["key_file"] = client_cert[1]
125 | else:
126 | # According to our docs, we allow users to specify just the client
127 | # cert path
128 | pool_kwargs["cert_file"] = client_cert
129 | host_params = {
130 | "scheme": scheme,
131 | "host": parsed_request_url.hostname,
132 | "port": port,
133 | }
134 | return host_params, pool_kwargs
135 |
136 |
137 | class BaseAdapter:
138 | """The Base Transport Adapter"""
139 |
140 | def __init__(self):
141 | super().__init__()
142 |
143 | def send(
144 | self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
145 | ):
146 | """Sends PreparedRequest object. Returns Response object.
147 |
148 | :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
149 | :param stream: (optional) Whether to stream the request content.
150 | :param timeout: (optional) How long to wait for the server to send
151 | data before giving up, as a float, or a :ref:`(connect timeout,
152 | read timeout) <timeouts>` tuple.
153 | :type timeout: float or tuple
154 | :param verify: (optional) Either a boolean, in which case it controls whether we verify
155 | the server's TLS certificate, or a string, in which case it must be a path
156 | to a CA bundle to use
157 | :param cert: (optional) Any user-provided SSL certificate to be trusted.
158 | :param proxies: (optional) The proxies dictionary to apply to the request.
159 | """
160 | raise NotImplementedError
161 |
162 | def close(self):
163 | """Cleans up adapter specific items."""
164 | raise NotImplementedError
165 |
166 |
167 | class HTTPAdapter(BaseAdapter):
168 | """The built-in HTTP Adapter for urllib3.
169 |
170 | Provides a general-case interface for Requests sessions to contact HTTP and
171 | HTTPS urls by implementing the Transport Adapter interface. This class will
172 | usually be created by the :class:`Session <Session>` class under the
173 | covers.
174 |
175 | :param pool_connections: The number of urllib3 connection pools to cache.
176 | :param pool_maxsize: The maximum number of connections to save in the pool.
177 | :param max_retries: The maximum number of retries each connection
178 | should attempt. Note, this applies only to failed DNS lookups, socket
179 | connections and connection timeouts, never to requests where data has
180 | made it to the server. By default, Requests does not retry failed
181 | connections. If you need granular control over the conditions under
182 | which we retry a request, import urllib3's ``Retry`` class and pass
183 | that instead.
184 | :param pool_block: Whether the connection pool should block for connections.
185 |
186 | Usage::
187 |
188 | >>> import requests
189 | >>> s = requests.Session()
190 | >>> a = requests.adapters.HTTPAdapter(max_retries=3)
191 | >>> s.mount('http://', a)
192 | """
193 |
194 | __attrs__ = [
195 | "max_retries",
196 | "config",
197 | "_pool_connections",
198 | "_pool_maxsize",
199 | "_pool_block",
200 | ]
201 |
202 | def __init__(
203 | self,
204 | pool_connections=DEFAULT_POOLSIZE,
205 | pool_maxsize=DEFAULT_POOLSIZE,
206 | max_retries=DEFAULT_RETRIES,
207 | pool_block=DEFAULT_POOLBLOCK,
208 | ):
209 | if max_retries == DEFAULT_RETRIES:
210 | self.max_retries = Retry(0, read=False)
211 | else:
212 | self.max_retries = Retry.from_int(max_retries)
213 | self.config = {}
214 | self.proxy_manager = {}
215 |
216 | super().__init__()
217 |
218 | self._pool_connections = pool_connections
219 | self._pool_maxsize = pool_maxsize
220 | self._pool_block = pool_block
221 |
222 | self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
223 |
224 | def __getstate__(self):
225 | return {attr: getattr(self, attr, None) for attr in self.__attrs__}
226 |
227 | def __setstate__(self, state):
228 | # Can't handle by adding 'proxy_manager' to self.__attrs__ because
229 | # self.poolmanager uses a lambda function, which isn't pickleable.
230 | self.proxy_manager = {}
231 | self.config = {}
232 |
233 | for attr, value in state.items():
234 | setattr(self, attr, value)
235 |
236 | self.init_poolmanager(
237 | self._pool_connections, self._pool_maxsize, block=self._pool_block
238 | )
239 |
240 | def init_poolmanager(
241 | self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs
242 | ):
243 | """Initializes a urllib3 PoolManager.
244 |
245 | This method should not be called from user code, and is only
246 | exposed for use when subclassing the
247 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
248 |
249 | :param connections: The number of urllib3 connection pools to cache.
250 | :param maxsize: The maximum number of connections to save in the pool.
251 | :param block: Block when no free connections are available.
252 | :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager.
253 | """
254 | # save these values for pickling
255 | self._pool_connections = connections
256 | self._pool_maxsize = maxsize
257 | self._pool_block = block
258 |
259 | self.poolmanager = PoolManager(
260 | num_pools=connections,
261 | maxsize=maxsize,
262 | block=block,
263 | **pool_kwargs,
264 | )
265 |
266 | def proxy_manager_for(self, proxy, **proxy_kwargs):
267 | """Return urllib3 ProxyManager for the given proxy.
268 |
269 | This method should not be called from user code, and is only
270 | exposed for use when subclassing the
271 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
272 |
273 | :param proxy: The proxy to return a urllib3 ProxyManager for.
274 | :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager.
275 | :returns: ProxyManager
276 | :rtype: urllib3.ProxyManager
277 | """
278 | if proxy in self.proxy_manager:
279 | manager = self.proxy_manager[proxy]
280 | elif proxy.lower().startswith("socks"):
281 | username, password = get_auth_from_url(proxy)
282 | manager = self.proxy_manager[proxy] = SOCKSProxyManager(
283 | proxy,
284 | username=username,
285 | password=password,
286 | num_pools=self._pool_connections,
287 | maxsize=self._pool_maxsize,
288 | block=self._pool_block,
289 | **proxy_kwargs,
290 | )
291 | else:
292 | proxy_headers = self.proxy_headers(proxy)
293 | manager = self.proxy_manager[proxy] = proxy_from_url(
294 | proxy,
295 | proxy_headers=proxy_headers,
296 | num_pools=self._pool_connections,
297 | maxsize=self._pool_maxsize,
298 | block=self._pool_block,
299 | **proxy_kwargs,
300 | )
301 |
302 | return manager
303 |
304 | def cert_verify(self, conn, url, verify, cert):
305 | """Verify a SSL certificate. This method should not be called from user
306 | code, and is only exposed for use when subclassing the
307 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
308 |
309 | :param conn: The urllib3 connection object associated with the cert.
310 | :param url: The requested URL.
311 | :param verify: Either a boolean, in which case it controls whether we verify
312 | the server's TLS certificate, or a string, in which case it must be a path
313 | to a CA bundle to use
314 | :param cert: The SSL certificate to verify.
315 | """
316 | if url.lower().startswith("https") and verify:
317 | conn.cert_reqs = "CERT_REQUIRED"
318 |
319 | # Only load the CA certificates if 'verify' is a string indicating the CA bundle to use.
320 | # Otherwise, if verify is a boolean, we don't load anything since
321 | # the connection will be using a context with the default certificates already loaded,
322 | # and this avoids a call to the slow load_verify_locations()
323 | if verify is not True:
324 | # `verify` must be a str with a path then
325 | cert_loc = verify
326 |
327 | if not os.path.exists(cert_loc):
328 | raise OSError(
329 | f"Could not find a suitable TLS CA certificate bundle, "
330 | f"invalid path: {cert_loc}"
331 | )
332 |
333 | if not os.path.isdir(cert_loc):
334 | conn.ca_certs = cert_loc
335 | else:
336 | conn.ca_cert_dir = cert_loc
337 | else:
338 | conn.cert_reqs = "CERT_NONE"
339 | conn.ca_certs = None
340 | conn.ca_cert_dir = None
341 |
342 | if cert:
343 | if not isinstance(cert, basestring):
344 | conn.cert_file = cert[0]
345 | conn.key_file = cert[1]
346 | else:
347 | conn.cert_file = cert
348 | conn.key_file = None
349 | if conn.cert_file and not os.path.exists(conn.cert_file):
350 | raise OSError(
351 | f"Could not find the TLS certificate file, "
352 | f"invalid path: {conn.cert_file}"
353 | )
354 | if conn.key_file and not os.path.exists(conn.key_file):
355 | raise OSError(
356 | f"Could not find the TLS key file, invalid path: {conn.key_file}"
357 | )
358 |
359 | def build_response(self, req, resp):
360 | """Builds a :class:`Response <requests.Response>` object from a urllib3
361 | response. This should not be called from user code, and is only exposed
362 | for use when subclassing the
363 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`
364 |
365 | :param req: The :class:`PreparedRequest <PreparedRequest>` used to generate the response.
366 | :param resp: The urllib3 response object.
367 | :rtype: requests.Response
368 | """
369 | response = Response()
370 |
371 | # Fallback to None if there's no status_code, for whatever reason.
372 | response.status_code = getattr(resp, "status", None)
373 |
374 | # Make headers case-insensitive.
375 | response.headers = CaseInsensitiveDict(getattr(resp, "headers", {}))
376 |
377 | # Set encoding.
378 | response.encoding = get_encoding_from_headers(response.headers)
379 | response.raw = resp
380 | response.reason = response.raw.reason
381 |
382 | if isinstance(req.url, bytes):
383 | response.url = req.url.decode("utf-8")
384 | else:
385 | response.url = req.url
386 |
387 | # Add new cookies from the server.
388 | extract_cookies_to_jar(response.cookies, req, resp)
389 |
390 | # Give the Response some context.
391 | response.request = req
392 | response.connection = self
393 |
394 | return response
395 |
396 | def build_connection_pool_key_attributes(self, request, verify, cert=None):
397 | """Build the PoolKey attributes used by urllib3 to return a connection.
398 |
399 | This looks at the PreparedRequest, the user-specified verify value,
400 | and the value of the cert parameter to determine what PoolKey values
401 | to use to select a connection from a given urllib3 Connection Pool.
402 |
403 | The SSL related pool key arguments are not consistently set. As of
404 | this writing, use the following to determine what keys may be in that
405 | dictionary:
406 |
407 | * If ``verify`` is ``True``, ``"ssl_context"`` will be set and will be the
408 | default Requests SSL Context
409 | * If ``verify`` is ``False``, ``"ssl_context"`` will not be set but
410 | ``"cert_reqs"`` will be set
411 | * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
412 | ``"ca_certs"`` will be set if the string is not a directory recognized
413 | by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
414 | set.
415 | * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
416 | ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
417 | be present
418 |
419 | To override these settings, one may subclass this class, call this
420 | method and use the above logic to change parameters as desired. For
421 | example, if one wishes to use a custom :py:class:`ssl.SSLContext` one
422 | must both set ``"ssl_context"`` and based on what else they require,
423 | alter the other keys to ensure the desired behaviour.
424 |
425 | :param request:
426 | The PreparedReqest being sent over the connection.
427 | :type request:
428 | :class:`~requests.models.PreparedRequest`
429 | :param verify:
430 | Either a boolean, in which case it controls whether
431 | we verify the server's TLS certificate, or a string, in which case it
432 | must be a path to a CA bundle to use.
433 | :param cert:
434 | (optional) Any user-provided SSL certificate for client
435 | authentication (a.k.a., mTLS). This may be a string (i.e., just
436 | the path to a file which holds both certificate and key) or a
437 | tuple of length 2 with the certificate file path and key file
438 | path.
439 | :returns:
440 | A tuple of two dictionaries. The first is the "host parameters"
441 | portion of the Pool Key including scheme, hostname, and port. The
442 | second is a dictionary of SSLContext related parameters.
443 | """
444 | return _urllib3_request_context(request, verify, cert, self.poolmanager)
445 |
446 | def get_connection_with_tls_context(self, request, verify, proxies=None, cert=None):
447 | """Returns a urllib3 connection for the given request and TLS settings.
448 | This should not be called from user code, and is only exposed for use
449 | when subclassing the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
450 |
451 | :param request:
452 | The :class:`PreparedRequest <PreparedRequest>` object to be sent
453 | over the connection.
454 | :param verify:
455 | Either a boolean, in which case it controls whether we verify the
456 | server's TLS certificate, or a string, in which case it must be a
457 | path to a CA bundle to use.
458 | :param proxies:
459 | (optional) The proxies dictionary to apply to the request.
460 | :param cert:
461 | (optional) Any user-provided SSL certificate to be used for client
462 | authentication (a.k.a., mTLS).
463 | :rtype:
464 | urllib3.ConnectionPool
465 | """
466 | proxy = select_proxy(request.url, proxies)
467 | try:
468 | host_params, pool_kwargs = self.build_connection_pool_key_attributes(
469 | request,
470 | verify,
471 | cert,
472 | )
473 | except ValueError as e:
474 | raise InvalidURL(e, request=request)
475 | if proxy:
476 | proxy = prepend_scheme_if_needed(proxy, "http")
477 | proxy_url = parse_url(proxy)
478 | if not proxy_url.host:
479 | raise InvalidProxyURL(
480 | "Please check proxy URL. It is malformed "
481 | "and could be missing the host."
482 | )
483 | proxy_manager = self.proxy_manager_for(proxy)
484 | conn = proxy_manager.connection_from_host(
485 | **host_params, pool_kwargs=pool_kwargs
486 | )
487 | else:
488 | # Only scheme should be lower case
489 | conn = self.poolmanager.connection_from_host(
490 | **host_params, pool_kwargs=pool_kwargs
491 | )
492 |
493 | return conn
494 |
495 | def get_connection(self, url, proxies=None):
496 | """DEPRECATED: Users should move to `get_connection_with_tls_context`
497 | for all subclasses of HTTPAdapter using Requests>=2.32.2.
498 |
499 | Returns a urllib3 connection for the given URL. This should not be
500 | called from user code, and is only exposed for use when subclassing the
501 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
502 |
503 | :param url: The URL to connect to.
504 | :param proxies: (optional) A Requests-style dictionary of proxies used on this request.
505 | :rtype: urllib3.ConnectionPool
506 | """
507 | warnings.warn(
508 | (
509 | "`get_connection` has been deprecated in favor of "
510 | "`get_connection_with_tls_context`. Custom HTTPAdapter subclasses "
511 | "will need to migrate for Requests>=2.32.2. Please see "
512 | "https://github.com/psf/requests/pull/6710 for more details."
513 | ),
514 | DeprecationWarning,
515 | )
516 | proxy = select_proxy(url, proxies)
517 |
518 | if proxy:
519 | proxy = prepend_scheme_if_needed(proxy, "http")
520 | proxy_url = parse_url(proxy)
521 | if not proxy_url.host:
522 | raise InvalidProxyURL(
523 | "Please check proxy URL. It is malformed "
524 | "and could be missing the host."
525 | )
526 | proxy_manager = self.proxy_manager_for(proxy)
527 | conn = proxy_manager.connection_from_url(url)
528 | else:
529 | # Only scheme should be lower case
530 | parsed = urlparse(url)
531 | url = parsed.geturl()
532 | conn = self.poolmanager.connection_from_url(url)
533 |
534 | return conn
535 |
536 | def close(self):
537 | """Disposes of any internal state.
538 |
539 | Currently, this closes the PoolManager and any active ProxyManager,
540 | which closes any pooled connections.
541 | """
542 | self.poolmanager.clear()
543 | for proxy in self.proxy_manager.values():
544 | proxy.clear()
545 |
546 | def request_url(self, request, proxies):
547 | """Obtain the url to use when making the final request.
548 |
549 | If the message is being sent through a HTTP proxy, the full URL has to
550 | be used. Otherwise, we should only use the path portion of the URL.
551 |
552 | This should not be called from user code, and is only exposed for use
553 | when subclassing the
554 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
555 |
556 | :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
557 | :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs.
558 | :rtype: str
559 | """
560 | proxy = select_proxy(request.url, proxies)
561 | scheme = urlparse(request.url).scheme
562 |
563 | is_proxied_http_request = proxy and scheme != "https"
564 | using_socks_proxy = False
565 | if proxy:
566 | proxy_scheme = urlparse(proxy).scheme.lower()
567 | using_socks_proxy = proxy_scheme.startswith("socks")
568 |
569 | url = request.path_url
570 | if url.startswith("//"): # Don't confuse urllib3
571 | url = f"/{url.lstrip('/')}"
572 |
573 | if is_proxied_http_request and not using_socks_proxy:
574 | url = urldefragauth(request.url)
575 |
576 | return url
577 |
578 | def add_headers(self, request, **kwargs):
579 | """Add any headers needed by the connection. As of v2.0 this does
580 | nothing by default, but is left for overriding by users that subclass
581 | the :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
582 |
583 | This should not be called from user code, and is only exposed for use
584 | when subclassing the
585 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
586 |
587 | :param request: The :class:`PreparedRequest <PreparedRequest>` to add headers to.
588 | :param kwargs: The keyword arguments from the call to send().
589 | """
590 | pass
591 |
592 | def proxy_headers(self, proxy):
593 | """Returns a dictionary of the headers to add to any request sent
594 | through a proxy. This works with urllib3 magic to ensure that they are
595 | correctly sent to the proxy, rather than in a tunnelled request if
596 | CONNECT is being used.
597 |
598 | This should not be called from user code, and is only exposed for use
599 | when subclassing the
600 | :class:`HTTPAdapter <requests.adapters.HTTPAdapter>`.
601 |
602 | :param proxy: The url of the proxy being used for this request.
603 | :rtype: dict
604 | """
605 | headers = {}
606 | username, password = get_auth_from_url(proxy)
607 |
608 | if username:
609 | headers["Proxy-Authorization"] = _basic_auth_str(username, password)
610 |
611 | return headers
612 |
613 | def send(
614 | self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
615 | ):
616 | """Sends PreparedRequest object. Returns Response object.
617 |
618 | :param request: The :class:`PreparedRequest <PreparedRequest>` being sent.
619 | :param stream: (optional) Whether to stream the request content.
620 | :param timeout: (optional) How long to wait for the server to send
621 | data before giving up, as a float, or a :ref:`(connect timeout,
622 | read timeout) <timeouts>` tuple.
623 | :type timeout: float or tuple or urllib3 Timeout object
624 | :param verify: (optional) Either a boolean, in which case it controls whether
625 | we verify the server's TLS certificate, or a string, in which case it
626 | must be a path to a CA bundle to use
627 | :param cert: (optional) Any user-provided SSL certificate to be trusted.
628 | :param proxies: (optional) The proxies dictionary to apply to the request.
629 | :rtype: requests.Response
630 | """
631 |
632 | try:
633 | conn = self.get_connection_with_tls_context(
634 | request, verify, proxies=proxies, cert=cert
635 | )
636 | except LocationValueError as e:
637 | raise InvalidURL(e, request=request)
638 |
639 | self.cert_verify(conn, request.url, verify, cert)
640 | url = self.request_url(request, proxies)
641 | self.add_headers(
642 | request,
643 | stream=stream,
644 | timeout=timeout,
645 | verify=verify,
646 | cert=cert,
647 | proxies=proxies,
648 | )
649 |
650 | chunked = not (request.body is None or "Content-Length" in request.headers)
651 |
652 | if isinstance(timeout, tuple):
653 | try:
654 | connect, read = timeout
655 | timeout = TimeoutSauce(connect=connect, read=read)
656 | except ValueError:
657 | raise ValueError(
658 | f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
659 | f"or a single float to set both timeouts to the same value."
660 | )
661 | elif isinstance(timeout, TimeoutSauce):
662 | pass
663 | else:
664 | timeout = TimeoutSauce(connect=timeout, read=timeout)
665 |
666 | try:
667 | resp = conn.urlopen(
668 | method=request.method,
669 | url=url,
670 | body=request.body,
671 | headers=request.headers,
672 | redirect=False,
673 | assert_same_host=False,
674 | preload_content=False,
675 | decode_content=False,
676 | retries=self.max_retries,
677 | timeout=timeout,
678 | chunked=chunked,
679 | )
680 |
681 | except (ProtocolError, OSError) as err:
682 | raise ConnectionError(err, request=request)
683 |
684 | except MaxRetryError as e:
685 | if isinstance(e.reason, ConnectTimeoutError):
686 | # TODO: Remove this in 3.0.0: see #2811
687 | if not isinstance(e.reason, NewConnectionError):
688 | raise ConnectTimeout(e, request=request)
689 |
690 | if isinstance(e.reason, ResponseError):
691 | raise RetryError(e, request=request)
692 |
693 | if isinstance(e.reason, _ProxyError):
694 | raise ProxyError(e, request=request)
695 |
696 | if isinstance(e.reason, _SSLError):
697 | # This branch is for urllib3 v1.22 and later.
698 | raise SSLError(e, request=request)
699 |
700 | raise ConnectionError(e, request=request)
701 |
702 | except ClosedPoolError as e:
703 | raise ConnectionError(e, request=request)
704 |
705 | except _ProxyError as e:
706 | raise ProxyError(e)
707 |
708 | except (_SSLError, _HTTPError) as e:
709 | if isinstance(e, _SSLError):
710 | # This branch is for urllib3 versions earlier than v1.22
711 | raise SSLError(e, request=request)
712 | elif isinstance(e, ReadTimeoutError):
713 | raise ReadTimeout(e, request=request)
714 | elif isinstance(e, _InvalidHeader):
715 | raise InvalidHeader(e, request=request)
716 | else:
717 | raise
718 |
719 | return self.build_response(request, resp)
720 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py:
--------------------------------------------------------------------------------
```python
1 | """Support for installing and building the "wheel" binary package format.
2 | """
3 |
4 | import collections
5 | import compileall
6 | import contextlib
7 | import csv
8 | import importlib
9 | import logging
10 | import os.path
11 | import re
12 | import shutil
13 | import sys
14 | import warnings
15 | from base64 import urlsafe_b64encode
16 | from email.message import Message
17 | from itertools import chain, filterfalse, starmap
18 | from typing import (
19 | IO,
20 | TYPE_CHECKING,
21 | Any,
22 | BinaryIO,
23 | Callable,
24 | Dict,
25 | Generator,
26 | Iterable,
27 | Iterator,
28 | List,
29 | NewType,
30 | Optional,
31 | Protocol,
32 | Sequence,
33 | Set,
34 | Tuple,
35 | Union,
36 | cast,
37 | )
38 | from zipfile import ZipFile, ZipInfo
39 |
40 | from pip._vendor.distlib.scripts import ScriptMaker
41 | from pip._vendor.distlib.util import get_export_entry
42 | from pip._vendor.packaging.utils import canonicalize_name
43 |
44 | from pip._internal.exceptions import InstallationError
45 | from pip._internal.locations import get_major_minor_version
46 | from pip._internal.metadata import (
47 | BaseDistribution,
48 | FilesystemWheel,
49 | get_wheel_distribution,
50 | )
51 | from pip._internal.models.direct_url import DIRECT_URL_METADATA_NAME, DirectUrl
52 | from pip._internal.models.scheme import SCHEME_KEYS, Scheme
53 | from pip._internal.utils.filesystem import adjacent_tmp_file, replace
54 | from pip._internal.utils.misc import StreamWrapper, ensure_dir, hash_file, partition
55 | from pip._internal.utils.unpacking import (
56 | current_umask,
57 | is_within_directory,
58 | set_extracted_file_to_default_mode_plus_executable,
59 | zip_item_is_executable,
60 | )
61 | from pip._internal.utils.wheel import parse_wheel
62 |
63 | if TYPE_CHECKING:
64 |
65 | class File(Protocol):
66 | src_record_path: "RecordPath"
67 | dest_path: str
68 | changed: bool
69 |
70 | def save(self) -> None:
71 | pass
72 |
73 |
74 | logger = logging.getLogger(__name__)
75 |
76 | RecordPath = NewType("RecordPath", str)
77 | InstalledCSVRow = Tuple[RecordPath, str, Union[int, str]]
78 |
79 |
80 | def rehash(path: str, blocksize: int = 1 << 20) -> Tuple[str, str]:
81 | """Return (encoded_digest, length) for path using hashlib.sha256()"""
82 | h, length = hash_file(path, blocksize)
83 | digest = "sha256=" + urlsafe_b64encode(h.digest()).decode("latin1").rstrip("=")
84 | return (digest, str(length))
85 |
86 |
87 | def csv_io_kwargs(mode: str) -> Dict[str, Any]:
88 | """Return keyword arguments to properly open a CSV file
89 | in the given mode.
90 | """
91 | return {"mode": mode, "newline": "", "encoding": "utf-8"}
92 |
93 |
94 | def fix_script(path: str) -> bool:
95 | """Replace #!python with #!/path/to/python
96 | Return True if file was changed.
97 | """
98 | # XXX RECORD hashes will need to be updated
99 | assert os.path.isfile(path)
100 |
101 | with open(path, "rb") as script:
102 | firstline = script.readline()
103 | if not firstline.startswith(b"#!python"):
104 | return False
105 | exename = sys.executable.encode(sys.getfilesystemencoding())
106 | firstline = b"#!" + exename + os.linesep.encode("ascii")
107 | rest = script.read()
108 | with open(path, "wb") as script:
109 | script.write(firstline)
110 | script.write(rest)
111 | return True
112 |
113 |
114 | def wheel_root_is_purelib(metadata: Message) -> bool:
115 | return metadata.get("Root-Is-Purelib", "").lower() == "true"
116 |
117 |
118 | def get_entrypoints(dist: BaseDistribution) -> Tuple[Dict[str, str], Dict[str, str]]:
119 | console_scripts = {}
120 | gui_scripts = {}
121 | for entry_point in dist.iter_entry_points():
122 | if entry_point.group == "console_scripts":
123 | console_scripts[entry_point.name] = entry_point.value
124 | elif entry_point.group == "gui_scripts":
125 | gui_scripts[entry_point.name] = entry_point.value
126 | return console_scripts, gui_scripts
127 |
128 |
129 | def message_about_scripts_not_on_PATH(scripts: Sequence[str]) -> Optional[str]:
130 | """Determine if any scripts are not on PATH and format a warning.
131 | Returns a warning message if one or more scripts are not on PATH,
132 | otherwise None.
133 | """
134 | if not scripts:
135 | return None
136 |
137 | # Group scripts by the path they were installed in
138 | grouped_by_dir: Dict[str, Set[str]] = collections.defaultdict(set)
139 | for destfile in scripts:
140 | parent_dir = os.path.dirname(destfile)
141 | script_name = os.path.basename(destfile)
142 | grouped_by_dir[parent_dir].add(script_name)
143 |
144 | # We don't want to warn for directories that are on PATH.
145 | not_warn_dirs = [
146 | os.path.normcase(os.path.normpath(i)).rstrip(os.sep)
147 | for i in os.environ.get("PATH", "").split(os.pathsep)
148 | ]
149 | # If an executable sits with sys.executable, we don't warn for it.
150 | # This covers the case of venv invocations without activating the venv.
151 | not_warn_dirs.append(
152 | os.path.normcase(os.path.normpath(os.path.dirname(sys.executable)))
153 | )
154 | warn_for: Dict[str, Set[str]] = {
155 | parent_dir: scripts
156 | for parent_dir, scripts in grouped_by_dir.items()
157 | if os.path.normcase(os.path.normpath(parent_dir)) not in not_warn_dirs
158 | }
159 | if not warn_for:
160 | return None
161 |
162 | # Format a message
163 | msg_lines = []
164 | for parent_dir, dir_scripts in warn_for.items():
165 | sorted_scripts: List[str] = sorted(dir_scripts)
166 | if len(sorted_scripts) == 1:
167 | start_text = f"script {sorted_scripts[0]} is"
168 | else:
169 | start_text = "scripts {} are".format(
170 | ", ".join(sorted_scripts[:-1]) + " and " + sorted_scripts[-1]
171 | )
172 |
173 | msg_lines.append(
174 | f"The {start_text} installed in '{parent_dir}' which is not on PATH."
175 | )
176 |
177 | last_line_fmt = (
178 | "Consider adding {} to PATH or, if you prefer "
179 | "to suppress this warning, use --no-warn-script-location."
180 | )
181 | if len(msg_lines) == 1:
182 | msg_lines.append(last_line_fmt.format("this directory"))
183 | else:
184 | msg_lines.append(last_line_fmt.format("these directories"))
185 |
186 | # Add a note if any directory starts with ~
187 | warn_for_tilde = any(
188 | i[0] == "~" for i in os.environ.get("PATH", "").split(os.pathsep) if i
189 | )
190 | if warn_for_tilde:
191 | tilde_warning_msg = (
192 | "NOTE: The current PATH contains path(s) starting with `~`, "
193 | "which may not be expanded by all applications."
194 | )
195 | msg_lines.append(tilde_warning_msg)
196 |
197 | # Returns the formatted multiline message
198 | return "\n".join(msg_lines)
199 |
200 |
201 | def _normalized_outrows(
202 | outrows: Iterable[InstalledCSVRow],
203 | ) -> List[Tuple[str, str, str]]:
204 | """Normalize the given rows of a RECORD file.
205 |
206 | Items in each row are converted into str. Rows are then sorted to make
207 | the value more predictable for tests.
208 |
209 | Each row is a 3-tuple (path, hash, size) and corresponds to a record of
210 | a RECORD file (see PEP 376 and PEP 427 for details). For the rows
211 | passed to this function, the size can be an integer as an int or string,
212 | or the empty string.
213 | """
214 | # Normally, there should only be one row per path, in which case the
215 | # second and third elements don't come into play when sorting.
216 | # However, in cases in the wild where a path might happen to occur twice,
217 | # we don't want the sort operation to trigger an error (but still want
218 | # determinism). Since the third element can be an int or string, we
219 | # coerce each element to a string to avoid a TypeError in this case.
220 | # For additional background, see--
221 | # https://github.com/pypa/pip/issues/5868
222 | return sorted(
223 | (record_path, hash_, str(size)) for record_path, hash_, size in outrows
224 | )
225 |
226 |
227 | def _record_to_fs_path(record_path: RecordPath, lib_dir: str) -> str:
228 | return os.path.join(lib_dir, record_path)
229 |
230 |
231 | def _fs_to_record_path(path: str, lib_dir: str) -> RecordPath:
232 | # On Windows, do not handle relative paths if they belong to different
233 | # logical disks
234 | if os.path.splitdrive(path)[0].lower() == os.path.splitdrive(lib_dir)[0].lower():
235 | path = os.path.relpath(path, lib_dir)
236 |
237 | path = path.replace(os.path.sep, "/")
238 | return cast("RecordPath", path)
239 |
240 |
241 | def get_csv_rows_for_installed(
242 | old_csv_rows: List[List[str]],
243 | installed: Dict[RecordPath, RecordPath],
244 | changed: Set[RecordPath],
245 | generated: List[str],
246 | lib_dir: str,
247 | ) -> List[InstalledCSVRow]:
248 | """
249 | :param installed: A map from archive RECORD path to installation RECORD
250 | path.
251 | """
252 | installed_rows: List[InstalledCSVRow] = []
253 | for row in old_csv_rows:
254 | if len(row) > 3:
255 | logger.warning("RECORD line has more than three elements: %s", row)
256 | old_record_path = cast("RecordPath", row[0])
257 | new_record_path = installed.pop(old_record_path, old_record_path)
258 | if new_record_path in changed:
259 | digest, length = rehash(_record_to_fs_path(new_record_path, lib_dir))
260 | else:
261 | digest = row[1] if len(row) > 1 else ""
262 | length = row[2] if len(row) > 2 else ""
263 | installed_rows.append((new_record_path, digest, length))
264 | for f in generated:
265 | path = _fs_to_record_path(f, lib_dir)
266 | digest, length = rehash(f)
267 | installed_rows.append((path, digest, length))
268 | return installed_rows + [
269 | (installed_record_path, "", "") for installed_record_path in installed.values()
270 | ]
271 |
272 |
273 | def get_console_script_specs(console: Dict[str, str]) -> List[str]:
274 | """
275 | Given the mapping from entrypoint name to callable, return the relevant
276 | console script specs.
277 | """
278 | # Don't mutate caller's version
279 | console = console.copy()
280 |
281 | scripts_to_generate = []
282 |
283 | # Special case pip and setuptools to generate versioned wrappers
284 | #
285 | # The issue is that some projects (specifically, pip and setuptools) use
286 | # code in setup.py to create "versioned" entry points - pip2.7 on Python
287 | # 2.7, pip3.3 on Python 3.3, etc. But these entry points are baked into
288 | # the wheel metadata at build time, and so if the wheel is installed with
289 | # a *different* version of Python the entry points will be wrong. The
290 | # correct fix for this is to enhance the metadata to be able to describe
291 | # such versioned entry points.
292 | # Currently, projects using versioned entry points will either have
293 | # incorrect versioned entry points, or they will not be able to distribute
294 | # "universal" wheels (i.e., they will need a wheel per Python version).
295 | #
296 | # Because setuptools and pip are bundled with _ensurepip and virtualenv,
297 | # we need to use universal wheels. As a workaround, we
298 | # override the versioned entry points in the wheel and generate the
299 | # correct ones.
300 | #
301 | # To add the level of hack in this section of code, in order to support
302 | # ensurepip this code will look for an ``ENSUREPIP_OPTIONS`` environment
303 | # variable which will control which version scripts get installed.
304 | #
305 | # ENSUREPIP_OPTIONS=altinstall
306 | # - Only pipX.Y and easy_install-X.Y will be generated and installed
307 | # ENSUREPIP_OPTIONS=install
308 | # - pipX.Y, pipX, easy_install-X.Y will be generated and installed. Note
309 | # that this option is technically if ENSUREPIP_OPTIONS is set and is
310 | # not altinstall
311 | # DEFAULT
312 | # - The default behavior is to install pip, pipX, pipX.Y, easy_install
313 | # and easy_install-X.Y.
314 | pip_script = console.pop("pip", None)
315 | if pip_script:
316 | if "ENSUREPIP_OPTIONS" not in os.environ:
317 | scripts_to_generate.append("pip = " + pip_script)
318 |
319 | if os.environ.get("ENSUREPIP_OPTIONS", "") != "altinstall":
320 | scripts_to_generate.append(f"pip{sys.version_info[0]} = {pip_script}")
321 |
322 | scripts_to_generate.append(f"pip{get_major_minor_version()} = {pip_script}")
323 | # Delete any other versioned pip entry points
324 | pip_ep = [k for k in console if re.match(r"pip(\d+(\.\d+)?)?$", k)]
325 | for k in pip_ep:
326 | del console[k]
327 | easy_install_script = console.pop("easy_install", None)
328 | if easy_install_script:
329 | if "ENSUREPIP_OPTIONS" not in os.environ:
330 | scripts_to_generate.append("easy_install = " + easy_install_script)
331 |
332 | scripts_to_generate.append(
333 | f"easy_install-{get_major_minor_version()} = {easy_install_script}"
334 | )
335 | # Delete any other versioned easy_install entry points
336 | easy_install_ep = [
337 | k for k in console if re.match(r"easy_install(-\d+\.\d+)?$", k)
338 | ]
339 | for k in easy_install_ep:
340 | del console[k]
341 |
342 | # Generate the console entry points specified in the wheel
343 | scripts_to_generate.extend(starmap("{} = {}".format, console.items()))
344 |
345 | return scripts_to_generate
346 |
347 |
348 | class ZipBackedFile:
349 | def __init__(
350 | self, src_record_path: RecordPath, dest_path: str, zip_file: ZipFile
351 | ) -> None:
352 | self.src_record_path = src_record_path
353 | self.dest_path = dest_path
354 | self._zip_file = zip_file
355 | self.changed = False
356 |
357 | def _getinfo(self) -> ZipInfo:
358 | return self._zip_file.getinfo(self.src_record_path)
359 |
360 | def save(self) -> None:
361 | # When we open the output file below, any existing file is truncated
362 | # before we start writing the new contents. This is fine in most
363 | # cases, but can cause a segfault if pip has loaded a shared
364 | # object (e.g. from pyopenssl through its vendored urllib3)
365 | # Since the shared object is mmap'd an attempt to call a
366 | # symbol in it will then cause a segfault. Unlinking the file
367 | # allows writing of new contents while allowing the process to
368 | # continue to use the old copy.
369 | if os.path.exists(self.dest_path):
370 | os.unlink(self.dest_path)
371 |
372 | zipinfo = self._getinfo()
373 |
374 | # optimization: the file is created by open(),
375 | # skip the decompression when there is 0 bytes to decompress.
376 | with open(self.dest_path, "wb") as dest:
377 | if zipinfo.file_size > 0:
378 | with self._zip_file.open(zipinfo) as f:
379 | blocksize = min(zipinfo.file_size, 1024 * 1024)
380 | shutil.copyfileobj(f, dest, blocksize)
381 |
382 | if zip_item_is_executable(zipinfo):
383 | set_extracted_file_to_default_mode_plus_executable(self.dest_path)
384 |
385 |
386 | class ScriptFile:
387 | def __init__(self, file: "File") -> None:
388 | self._file = file
389 | self.src_record_path = self._file.src_record_path
390 | self.dest_path = self._file.dest_path
391 | self.changed = False
392 |
393 | def save(self) -> None:
394 | self._file.save()
395 | self.changed = fix_script(self.dest_path)
396 |
397 |
398 | class MissingCallableSuffix(InstallationError):
399 | def __init__(self, entry_point: str) -> None:
400 | super().__init__(
401 | f"Invalid script entry point: {entry_point} - A callable "
402 | "suffix is required. Cf https://packaging.python.org/"
403 | "specifications/entry-points/#use-for-scripts for more "
404 | "information."
405 | )
406 |
407 |
408 | def _raise_for_invalid_entrypoint(specification: str) -> None:
409 | entry = get_export_entry(specification)
410 | if entry is not None and entry.suffix is None:
411 | raise MissingCallableSuffix(str(entry))
412 |
413 |
414 | class PipScriptMaker(ScriptMaker):
415 | def make(
416 | self, specification: str, options: Optional[Dict[str, Any]] = None
417 | ) -> List[str]:
418 | _raise_for_invalid_entrypoint(specification)
419 | return super().make(specification, options)
420 |
421 |
422 | def _install_wheel( # noqa: C901, PLR0915 function is too long
423 | name: str,
424 | wheel_zip: ZipFile,
425 | wheel_path: str,
426 | scheme: Scheme,
427 | pycompile: bool = True,
428 | warn_script_location: bool = True,
429 | direct_url: Optional[DirectUrl] = None,
430 | requested: bool = False,
431 | ) -> None:
432 | """Install a wheel.
433 |
434 | :param name: Name of the project to install
435 | :param wheel_zip: open ZipFile for wheel being installed
436 | :param scheme: Distutils scheme dictating the install directories
437 | :param req_description: String used in place of the requirement, for
438 | logging
439 | :param pycompile: Whether to byte-compile installed Python files
440 | :param warn_script_location: Whether to check that scripts are installed
441 | into a directory on PATH
442 | :raises UnsupportedWheel:
443 | * when the directory holds an unpacked wheel with incompatible
444 | Wheel-Version
445 | * when the .dist-info dir does not match the wheel
446 | """
447 | info_dir, metadata = parse_wheel(wheel_zip, name)
448 |
449 | if wheel_root_is_purelib(metadata):
450 | lib_dir = scheme.purelib
451 | else:
452 | lib_dir = scheme.platlib
453 |
454 | # Record details of the files moved
455 | # installed = files copied from the wheel to the destination
456 | # changed = files changed while installing (scripts #! line typically)
457 | # generated = files newly generated during the install (script wrappers)
458 | installed: Dict[RecordPath, RecordPath] = {}
459 | changed: Set[RecordPath] = set()
460 | generated: List[str] = []
461 |
462 | def record_installed(
463 | srcfile: RecordPath, destfile: str, modified: bool = False
464 | ) -> None:
465 | """Map archive RECORD paths to installation RECORD paths."""
466 | newpath = _fs_to_record_path(destfile, lib_dir)
467 | installed[srcfile] = newpath
468 | if modified:
469 | changed.add(newpath)
470 |
471 | def is_dir_path(path: RecordPath) -> bool:
472 | return path.endswith("/")
473 |
474 | def assert_no_path_traversal(dest_dir_path: str, target_path: str) -> None:
475 | if not is_within_directory(dest_dir_path, target_path):
476 | message = (
477 | "The wheel {!r} has a file {!r} trying to install"
478 | " outside the target directory {!r}"
479 | )
480 | raise InstallationError(
481 | message.format(wheel_path, target_path, dest_dir_path)
482 | )
483 |
484 | def root_scheme_file_maker(
485 | zip_file: ZipFile, dest: str
486 | ) -> Callable[[RecordPath], "File"]:
487 | def make_root_scheme_file(record_path: RecordPath) -> "File":
488 | normed_path = os.path.normpath(record_path)
489 | dest_path = os.path.join(dest, normed_path)
490 | assert_no_path_traversal(dest, dest_path)
491 | return ZipBackedFile(record_path, dest_path, zip_file)
492 |
493 | return make_root_scheme_file
494 |
495 | def data_scheme_file_maker(
496 | zip_file: ZipFile, scheme: Scheme
497 | ) -> Callable[[RecordPath], "File"]:
498 | scheme_paths = {key: getattr(scheme, key) for key in SCHEME_KEYS}
499 |
500 | def make_data_scheme_file(record_path: RecordPath) -> "File":
501 | normed_path = os.path.normpath(record_path)
502 | try:
503 | _, scheme_key, dest_subpath = normed_path.split(os.path.sep, 2)
504 | except ValueError:
505 | message = (
506 | f"Unexpected file in {wheel_path}: {record_path!r}. .data directory"
507 | " contents should be named like: '<scheme key>/<path>'."
508 | )
509 | raise InstallationError(message)
510 |
511 | try:
512 | scheme_path = scheme_paths[scheme_key]
513 | except KeyError:
514 | valid_scheme_keys = ", ".join(sorted(scheme_paths))
515 | message = (
516 | f"Unknown scheme key used in {wheel_path}: {scheme_key} "
517 | f"(for file {record_path!r}). .data directory contents "
518 | f"should be in subdirectories named with a valid scheme "
519 | f"key ({valid_scheme_keys})"
520 | )
521 | raise InstallationError(message)
522 |
523 | dest_path = os.path.join(scheme_path, dest_subpath)
524 | assert_no_path_traversal(scheme_path, dest_path)
525 | return ZipBackedFile(record_path, dest_path, zip_file)
526 |
527 | return make_data_scheme_file
528 |
529 | def is_data_scheme_path(path: RecordPath) -> bool:
530 | return path.split("/", 1)[0].endswith(".data")
531 |
532 | paths = cast(List[RecordPath], wheel_zip.namelist())
533 | file_paths = filterfalse(is_dir_path, paths)
534 | root_scheme_paths, data_scheme_paths = partition(is_data_scheme_path, file_paths)
535 |
536 | make_root_scheme_file = root_scheme_file_maker(wheel_zip, lib_dir)
537 | files: Iterator[File] = map(make_root_scheme_file, root_scheme_paths)
538 |
539 | def is_script_scheme_path(path: RecordPath) -> bool:
540 | parts = path.split("/", 2)
541 | return len(parts) > 2 and parts[0].endswith(".data") and parts[1] == "scripts"
542 |
543 | other_scheme_paths, script_scheme_paths = partition(
544 | is_script_scheme_path, data_scheme_paths
545 | )
546 |
547 | make_data_scheme_file = data_scheme_file_maker(wheel_zip, scheme)
548 | other_scheme_files = map(make_data_scheme_file, other_scheme_paths)
549 | files = chain(files, other_scheme_files)
550 |
551 | # Get the defined entry points
552 | distribution = get_wheel_distribution(
553 | FilesystemWheel(wheel_path),
554 | canonicalize_name(name),
555 | )
556 | console, gui = get_entrypoints(distribution)
557 |
558 | def is_entrypoint_wrapper(file: "File") -> bool:
559 | # EP, EP.exe and EP-script.py are scripts generated for
560 | # entry point EP by setuptools
561 | path = file.dest_path
562 | name = os.path.basename(path)
563 | if name.lower().endswith(".exe"):
564 | matchname = name[:-4]
565 | elif name.lower().endswith("-script.py"):
566 | matchname = name[:-10]
567 | elif name.lower().endswith(".pya"):
568 | matchname = name[:-4]
569 | else:
570 | matchname = name
571 | # Ignore setuptools-generated scripts
572 | return matchname in console or matchname in gui
573 |
574 | script_scheme_files: Iterator[File] = map(
575 | make_data_scheme_file, script_scheme_paths
576 | )
577 | script_scheme_files = filterfalse(is_entrypoint_wrapper, script_scheme_files)
578 | script_scheme_files = map(ScriptFile, script_scheme_files)
579 | files = chain(files, script_scheme_files)
580 |
581 | existing_parents = set()
582 | for file in files:
583 | # directory creation is lazy and after file filtering
584 | # to ensure we don't install empty dirs; empty dirs can't be
585 | # uninstalled.
586 | parent_dir = os.path.dirname(file.dest_path)
587 | if parent_dir not in existing_parents:
588 | ensure_dir(parent_dir)
589 | existing_parents.add(parent_dir)
590 | file.save()
591 | record_installed(file.src_record_path, file.dest_path, file.changed)
592 |
593 | def pyc_source_file_paths() -> Generator[str, None, None]:
594 | # We de-duplicate installation paths, since there can be overlap (e.g.
595 | # file in .data maps to same location as file in wheel root).
596 | # Sorting installation paths makes it easier to reproduce and debug
597 | # issues related to permissions on existing files.
598 | for installed_path in sorted(set(installed.values())):
599 | full_installed_path = os.path.join(lib_dir, installed_path)
600 | if not os.path.isfile(full_installed_path):
601 | continue
602 | if not full_installed_path.endswith(".py"):
603 | continue
604 | yield full_installed_path
605 |
606 | def pyc_output_path(path: str) -> str:
607 | """Return the path the pyc file would have been written to."""
608 | return importlib.util.cache_from_source(path)
609 |
610 | # Compile all of the pyc files for the installed files
611 | if pycompile:
612 | with contextlib.redirect_stdout(
613 | StreamWrapper.from_stream(sys.stdout)
614 | ) as stdout:
615 | with warnings.catch_warnings():
616 | warnings.filterwarnings("ignore")
617 | for path in pyc_source_file_paths():
618 | success = compileall.compile_file(path, force=True, quiet=True)
619 | if success:
620 | pyc_path = pyc_output_path(path)
621 | assert os.path.exists(pyc_path)
622 | pyc_record_path = cast(
623 | "RecordPath", pyc_path.replace(os.path.sep, "/")
624 | )
625 | record_installed(pyc_record_path, pyc_path)
626 | logger.debug(stdout.getvalue())
627 |
628 | maker = PipScriptMaker(None, scheme.scripts)
629 |
630 | # Ensure old scripts are overwritten.
631 | # See https://github.com/pypa/pip/issues/1800
632 | maker.clobber = True
633 |
634 | # Ensure we don't generate any variants for scripts because this is almost
635 | # never what somebody wants.
636 | # See https://bitbucket.org/pypa/distlib/issue/35/
637 | maker.variants = {""}
638 |
639 | # This is required because otherwise distlib creates scripts that are not
640 | # executable.
641 | # See https://bitbucket.org/pypa/distlib/issue/32/
642 | maker.set_mode = True
643 |
644 | # Generate the console and GUI entry points specified in the wheel
645 | scripts_to_generate = get_console_script_specs(console)
646 |
647 | gui_scripts_to_generate = list(starmap("{} = {}".format, gui.items()))
648 |
649 | generated_console_scripts = maker.make_multiple(scripts_to_generate)
650 | generated.extend(generated_console_scripts)
651 |
652 | generated.extend(maker.make_multiple(gui_scripts_to_generate, {"gui": True}))
653 |
654 | if warn_script_location:
655 | msg = message_about_scripts_not_on_PATH(generated_console_scripts)
656 | if msg is not None:
657 | logger.warning(msg)
658 |
659 | generated_file_mode = 0o666 & ~current_umask()
660 |
661 | @contextlib.contextmanager
662 | def _generate_file(path: str, **kwargs: Any) -> Generator[BinaryIO, None, None]:
663 | with adjacent_tmp_file(path, **kwargs) as f:
664 | yield f
665 | os.chmod(f.name, generated_file_mode)
666 | replace(f.name, path)
667 |
668 | dest_info_dir = os.path.join(lib_dir, info_dir)
669 |
670 | # Record pip as the installer
671 | installer_path = os.path.join(dest_info_dir, "INSTALLER")
672 | with _generate_file(installer_path) as installer_file:
673 | installer_file.write(b"pip\n")
674 | generated.append(installer_path)
675 |
676 | # Record the PEP 610 direct URL reference
677 | if direct_url is not None:
678 | direct_url_path = os.path.join(dest_info_dir, DIRECT_URL_METADATA_NAME)
679 | with _generate_file(direct_url_path) as direct_url_file:
680 | direct_url_file.write(direct_url.to_json().encode("utf-8"))
681 | generated.append(direct_url_path)
682 |
683 | # Record the REQUESTED file
684 | if requested:
685 | requested_path = os.path.join(dest_info_dir, "REQUESTED")
686 | with open(requested_path, "wb"):
687 | pass
688 | generated.append(requested_path)
689 |
690 | record_text = distribution.read_text("RECORD")
691 | record_rows = list(csv.reader(record_text.splitlines()))
692 |
693 | rows = get_csv_rows_for_installed(
694 | record_rows,
695 | installed=installed,
696 | changed=changed,
697 | generated=generated,
698 | lib_dir=lib_dir,
699 | )
700 |
701 | # Record details of all files installed
702 | record_path = os.path.join(dest_info_dir, "RECORD")
703 |
704 | with _generate_file(record_path, **csv_io_kwargs("w")) as record_file:
705 | # Explicitly cast to typing.IO[str] as a workaround for the mypy error:
706 | # "writer" has incompatible type "BinaryIO"; expected "_Writer"
707 | writer = csv.writer(cast("IO[str]", record_file))
708 | writer.writerows(_normalized_outrows(rows))
709 |
710 |
711 | @contextlib.contextmanager
712 | def req_error_context(req_description: str) -> Generator[None, None, None]:
713 | try:
714 | yield
715 | except InstallationError as e:
716 | message = f"For req: {req_description}. {e.args[0]}"
717 | raise InstallationError(message) from e
718 |
719 |
720 | def install_wheel(
721 | name: str,
722 | wheel_path: str,
723 | scheme: Scheme,
724 | req_description: str,
725 | pycompile: bool = True,
726 | warn_script_location: bool = True,
727 | direct_url: Optional[DirectUrl] = None,
728 | requested: bool = False,
729 | ) -> None:
730 | with ZipFile(wheel_path, allowZip64=True) as z:
731 | with req_error_context(req_description):
732 | _install_wheel(
733 | name=name,
734 | wheel_zip=z,
735 | wheel_path=wheel_path,
736 | scheme=scheme,
737 | pycompile=pycompile,
738 | warn_script_location=warn_script_location,
739 | direct_url=direct_url,
740 | requested=requested,
741 | )
742 |
```