#
tokens: 46296/50000 1/808 files (page 144/168)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 144 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/distlib/locators.py:
--------------------------------------------------------------------------------

```python
   1 | # -*- coding: utf-8 -*-
   2 | #
   3 | # Copyright (C) 2012-2023 Vinay Sajip.
   4 | # Licensed to the Python Software Foundation under a contributor agreement.
   5 | # See LICENSE.txt and CONTRIBUTORS.txt.
   6 | #
   7 | 
   8 | import gzip
   9 | from io import BytesIO
  10 | import json
  11 | import logging
  12 | import os
  13 | import posixpath
  14 | import re
  15 | try:
  16 |     import threading
  17 | except ImportError:  # pragma: no cover
  18 |     import dummy_threading as threading
  19 | import zlib
  20 | 
  21 | from . import DistlibException
  22 | from .compat import (urljoin, urlparse, urlunparse, url2pathname, pathname2url,
  23 |                      queue, quote, unescape, build_opener,
  24 |                      HTTPRedirectHandler as BaseRedirectHandler, text_type,
  25 |                      Request, HTTPError, URLError)
  26 | from .database import Distribution, DistributionPath, make_dist
  27 | from .metadata import Metadata, MetadataInvalidError
  28 | from .util import (cached_property, ensure_slash, split_filename, get_project_data,
  29 |                    parse_requirement, parse_name_and_version, ServerProxy,
  30 |                    normalize_name)
  31 | from .version import get_scheme, UnsupportedVersionError
  32 | from .wheel import Wheel, is_compatible
  33 | 
  34 | logger = logging.getLogger(__name__)
  35 | 
  36 | HASHER_HASH = re.compile(r'^(\w+)=([a-f0-9]+)')
  37 | CHARSET = re.compile(r';\s*charset\s*=\s*(.*)\s*$', re.I)
  38 | HTML_CONTENT_TYPE = re.compile('text/html|application/x(ht)?ml')
  39 | DEFAULT_INDEX = 'https://pypi.org/pypi'
  40 | 
  41 | 
  42 | def get_all_distribution_names(url=None):
  43 |     """
  44 |     Return all distribution names known by an index.
  45 |     :param url: The URL of the index.
  46 |     :return: A list of all known distribution names.
  47 |     """
  48 |     if url is None:
  49 |         url = DEFAULT_INDEX
  50 |     client = ServerProxy(url, timeout=3.0)
  51 |     try:
  52 |         return client.list_packages()
  53 |     finally:
  54 |         client('close')()
  55 | 
  56 | 
  57 | class RedirectHandler(BaseRedirectHandler):
  58 |     """
  59 |     A class to work around a bug in some Python 3.2.x releases.
  60 |     """
  61 |     # There's a bug in the base version for some 3.2.x
  62 |     # (e.g. 3.2.2 on Ubuntu Oneiric). If a Location header
  63 |     # returns e.g. /abc, it bails because it says the scheme ''
  64 |     # is bogus, when actually it should use the request's
  65 |     # URL for the scheme. See Python issue #13696.
  66 |     def http_error_302(self, req, fp, code, msg, headers):
  67 |         # Some servers (incorrectly) return multiple Location headers
  68 |         # (so probably same goes for URI).  Use first header.
  69 |         newurl = None
  70 |         for key in ('location', 'uri'):
  71 |             if key in headers:
  72 |                 newurl = headers[key]
  73 |                 break
  74 |         if newurl is None:  # pragma: no cover
  75 |             return
  76 |         urlparts = urlparse(newurl)
  77 |         if urlparts.scheme == '':
  78 |             newurl = urljoin(req.get_full_url(), newurl)
  79 |             if hasattr(headers, 'replace_header'):
  80 |                 headers.replace_header(key, newurl)
  81 |             else:
  82 |                 headers[key] = newurl
  83 |         return BaseRedirectHandler.http_error_302(self, req, fp, code, msg,
  84 |                                                   headers)
  85 | 
  86 |     http_error_301 = http_error_303 = http_error_307 = http_error_302
  87 | 
  88 | 
  89 | class Locator(object):
  90 |     """
  91 |     A base class for locators - things that locate distributions.
  92 |     """
  93 |     source_extensions = ('.tar.gz', '.tar.bz2', '.tar', '.zip', '.tgz', '.tbz')
  94 |     binary_extensions = ('.egg', '.exe', '.whl')
  95 |     excluded_extensions = ('.pdf',)
  96 | 
  97 |     # A list of tags indicating which wheels you want to match. The default
  98 |     # value of None matches against the tags compatible with the running
  99 |     # Python. If you want to match other values, set wheel_tags on a locator
 100 |     # instance to a list of tuples (pyver, abi, arch) which you want to match.
 101 |     wheel_tags = None
 102 | 
 103 |     downloadable_extensions = source_extensions + ('.whl',)
 104 | 
 105 |     def __init__(self, scheme='default'):
 106 |         """
 107 |         Initialise an instance.
 108 |         :param scheme: Because locators look for most recent versions, they
 109 |                        need to know the version scheme to use. This specifies
 110 |                        the current PEP-recommended scheme - use ``'legacy'``
 111 |                        if you need to support existing distributions on PyPI.
 112 |         """
 113 |         self._cache = {}
 114 |         self.scheme = scheme
 115 |         # Because of bugs in some of the handlers on some of the platforms,
 116 |         # we use our own opener rather than just using urlopen.
 117 |         self.opener = build_opener(RedirectHandler())
 118 |         # If get_project() is called from locate(), the matcher instance
 119 |         # is set from the requirement passed to locate(). See issue #18 for
 120 |         # why this can be useful to know.
 121 |         self.matcher = None
 122 |         self.errors = queue.Queue()
 123 | 
 124 |     def get_errors(self):
 125 |         """
 126 |         Return any errors which have occurred.
 127 |         """
 128 |         result = []
 129 |         while not self.errors.empty():  # pragma: no cover
 130 |             try:
 131 |                 e = self.errors.get(False)
 132 |                 result.append(e)
 133 |             except self.errors.Empty:
 134 |                 continue
 135 |             self.errors.task_done()
 136 |         return result
 137 | 
 138 |     def clear_errors(self):
 139 |         """
 140 |         Clear any errors which may have been logged.
 141 |         """
 142 |         # Just get the errors and throw them away
 143 |         self.get_errors()
 144 | 
 145 |     def clear_cache(self):
 146 |         self._cache.clear()
 147 | 
 148 |     def _get_scheme(self):
 149 |         return self._scheme
 150 | 
 151 |     def _set_scheme(self, value):
 152 |         self._scheme = value
 153 | 
 154 |     scheme = property(_get_scheme, _set_scheme)
 155 | 
 156 |     def _get_project(self, name):
 157 |         """
 158 |         For a given project, get a dictionary mapping available versions to Distribution
 159 |         instances.
 160 | 
 161 |         This should be implemented in subclasses.
 162 | 
 163 |         If called from a locate() request, self.matcher will be set to a
 164 |         matcher for the requirement to satisfy, otherwise it will be None.
 165 |         """
 166 |         raise NotImplementedError('Please implement in the subclass')
 167 | 
 168 |     def get_distribution_names(self):
 169 |         """
 170 |         Return all the distribution names known to this locator.
 171 |         """
 172 |         raise NotImplementedError('Please implement in the subclass')
 173 | 
 174 |     def get_project(self, name):
 175 |         """
 176 |         For a given project, get a dictionary mapping available versions to Distribution
 177 |         instances.
 178 | 
 179 |         This calls _get_project to do all the work, and just implements a caching layer on top.
 180 |         """
 181 |         if self._cache is None:  # pragma: no cover
 182 |             result = self._get_project(name)
 183 |         elif name in self._cache:
 184 |             result = self._cache[name]
 185 |         else:
 186 |             self.clear_errors()
 187 |             result = self._get_project(name)
 188 |             self._cache[name] = result
 189 |         return result
 190 | 
 191 |     def score_url(self, url):
 192 |         """
 193 |         Give an url a score which can be used to choose preferred URLs
 194 |         for a given project release.
 195 |         """
 196 |         t = urlparse(url)
 197 |         basename = posixpath.basename(t.path)
 198 |         compatible = True
 199 |         is_wheel = basename.endswith('.whl')
 200 |         is_downloadable = basename.endswith(self.downloadable_extensions)
 201 |         if is_wheel:
 202 |             compatible = is_compatible(Wheel(basename), self.wheel_tags)
 203 |         return (t.scheme == 'https', 'pypi.org' in t.netloc,
 204 |                 is_downloadable, is_wheel, compatible, basename)
 205 | 
 206 |     def prefer_url(self, url1, url2):
 207 |         """
 208 |         Choose one of two URLs where both are candidates for distribution
 209 |         archives for the same version of a distribution (for example,
 210 |         .tar.gz vs. zip).
 211 | 
 212 |         The current implementation favours https:// URLs over http://, archives
 213 |         from PyPI over those from other locations, wheel compatibility (if a
 214 |         wheel) and then the archive name.
 215 |         """
 216 |         result = url2
 217 |         if url1:
 218 |             s1 = self.score_url(url1)
 219 |             s2 = self.score_url(url2)
 220 |             if s1 > s2:
 221 |                 result = url1
 222 |             if result != url2:
 223 |                 logger.debug('Not replacing %r with %r', url1, url2)
 224 |             else:
 225 |                 logger.debug('Replacing %r with %r', url1, url2)
 226 |         return result
 227 | 
 228 |     def split_filename(self, filename, project_name):
 229 |         """
 230 |         Attempt to split a filename in project name, version and Python version.
 231 |         """
 232 |         return split_filename(filename, project_name)
 233 | 
 234 |     def convert_url_to_download_info(self, url, project_name):
 235 |         """
 236 |         See if a URL is a candidate for a download URL for a project (the URL
 237 |         has typically been scraped from an HTML page).
 238 | 
 239 |         If it is, a dictionary is returned with keys "name", "version",
 240 |         "filename" and "url"; otherwise, None is returned.
 241 |         """
 242 |         def same_project(name1, name2):
 243 |             return normalize_name(name1) == normalize_name(name2)
 244 | 
 245 |         result = None
 246 |         scheme, netloc, path, params, query, frag = urlparse(url)
 247 |         if frag.lower().startswith('egg='):  # pragma: no cover
 248 |             logger.debug('%s: version hint in fragment: %r',
 249 |                          project_name, frag)
 250 |         m = HASHER_HASH.match(frag)
 251 |         if m:
 252 |             algo, digest = m.groups()
 253 |         else:
 254 |             algo, digest = None, None
 255 |         origpath = path
 256 |         if path and path[-1] == '/':  # pragma: no cover
 257 |             path = path[:-1]
 258 |         if path.endswith('.whl'):
 259 |             try:
 260 |                 wheel = Wheel(path)
 261 |                 if not is_compatible(wheel, self.wheel_tags):
 262 |                     logger.debug('Wheel not compatible: %s', path)
 263 |                 else:
 264 |                     if project_name is None:
 265 |                         include = True
 266 |                     else:
 267 |                         include = same_project(wheel.name, project_name)
 268 |                     if include:
 269 |                         result = {
 270 |                             'name': wheel.name,
 271 |                             'version': wheel.version,
 272 |                             'filename': wheel.filename,
 273 |                             'url': urlunparse((scheme, netloc, origpath,
 274 |                                                params, query, '')),
 275 |                             'python-version': ', '.join(
 276 |                                 ['.'.join(list(v[2:])) for v in wheel.pyver]),
 277 |                         }
 278 |             except Exception:  # pragma: no cover
 279 |                 logger.warning('invalid path for wheel: %s', path)
 280 |         elif not path.endswith(self.downloadable_extensions):  # pragma: no cover
 281 |             logger.debug('Not downloadable: %s', path)
 282 |         else:  # downloadable extension
 283 |             path = filename = posixpath.basename(path)
 284 |             for ext in self.downloadable_extensions:
 285 |                 if path.endswith(ext):
 286 |                     path = path[:-len(ext)]
 287 |                     t = self.split_filename(path, project_name)
 288 |                     if not t:  # pragma: no cover
 289 |                         logger.debug('No match for project/version: %s', path)
 290 |                     else:
 291 |                         name, version, pyver = t
 292 |                         if not project_name or same_project(project_name, name):
 293 |                             result = {
 294 |                                 'name': name,
 295 |                                 'version': version,
 296 |                                 'filename': filename,
 297 |                                 'url': urlunparse((scheme, netloc, origpath,
 298 |                                                    params, query, '')),
 299 |                             }
 300 |                             if pyver:  # pragma: no cover
 301 |                                 result['python-version'] = pyver
 302 |                     break
 303 |         if result and algo:
 304 |             result['%s_digest' % algo] = digest
 305 |         return result
 306 | 
 307 |     def _get_digest(self, info):
 308 |         """
 309 |         Get a digest from a dictionary by looking at a "digests" dictionary
 310 |         or keys of the form 'algo_digest'.
 311 | 
 312 |         Returns a 2-tuple (algo, digest) if found, else None. Currently
 313 |         looks only for SHA256, then MD5.
 314 |         """
 315 |         result = None
 316 |         if 'digests' in info:
 317 |             digests = info['digests']
 318 |             for algo in ('sha256', 'md5'):
 319 |                 if algo in digests:
 320 |                     result = (algo, digests[algo])
 321 |                     break
 322 |         if not result:
 323 |             for algo in ('sha256', 'md5'):
 324 |                 key = '%s_digest' % algo
 325 |                 if key in info:
 326 |                     result = (algo, info[key])
 327 |                     break
 328 |         return result
 329 | 
 330 |     def _update_version_data(self, result, info):
 331 |         """
 332 |         Update a result dictionary (the final result from _get_project) with a
 333 |         dictionary for a specific version, which typically holds information
 334 |         gleaned from a filename or URL for an archive for the distribution.
 335 |         """
 336 |         name = info.pop('name')
 337 |         version = info.pop('version')
 338 |         if version in result:
 339 |             dist = result[version]
 340 |             md = dist.metadata
 341 |         else:
 342 |             dist = make_dist(name, version, scheme=self.scheme)
 343 |             md = dist.metadata
 344 |         dist.digest = digest = self._get_digest(info)
 345 |         url = info['url']
 346 |         result['digests'][url] = digest
 347 |         if md.source_url != info['url']:
 348 |             md.source_url = self.prefer_url(md.source_url, url)
 349 |             result['urls'].setdefault(version, set()).add(url)
 350 |         dist.locator = self
 351 |         result[version] = dist
 352 | 
 353 |     def locate(self, requirement, prereleases=False):
 354 |         """
 355 |         Find the most recent distribution which matches the given
 356 |         requirement.
 357 | 
 358 |         :param requirement: A requirement of the form 'foo (1.0)' or perhaps
 359 |                             'foo (>= 1.0, < 2.0, != 1.3)'
 360 |         :param prereleases: If ``True``, allow pre-release versions
 361 |                             to be located. Otherwise, pre-release versions
 362 |                             are not returned.
 363 |         :return: A :class:`Distribution` instance, or ``None`` if no such
 364 |                  distribution could be located.
 365 |         """
 366 |         result = None
 367 |         r = parse_requirement(requirement)
 368 |         if r is None:  # pragma: no cover
 369 |             raise DistlibException('Not a valid requirement: %r' % requirement)
 370 |         scheme = get_scheme(self.scheme)
 371 |         self.matcher = matcher = scheme.matcher(r.requirement)
 372 |         logger.debug('matcher: %s (%s)', matcher, type(matcher).__name__)
 373 |         versions = self.get_project(r.name)
 374 |         if len(versions) > 2:   # urls and digests keys are present
 375 |             # sometimes, versions are invalid
 376 |             slist = []
 377 |             vcls = matcher.version_class
 378 |             for k in versions:
 379 |                 if k in ('urls', 'digests'):
 380 |                     continue
 381 |                 try:
 382 |                     if not matcher.match(k):
 383 |                         pass  # logger.debug('%s did not match %r', matcher, k)
 384 |                     else:
 385 |                         if prereleases or not vcls(k).is_prerelease:
 386 |                             slist.append(k)
 387 |                 except Exception:  # pragma: no cover
 388 |                     logger.warning('error matching %s with %r', matcher, k)
 389 |                     pass  # slist.append(k)
 390 |             if len(slist) > 1:
 391 |                 slist = sorted(slist, key=scheme.key)
 392 |             if slist:
 393 |                 logger.debug('sorted list: %s', slist)
 394 |                 version = slist[-1]
 395 |                 result = versions[version]
 396 |         if result:
 397 |             if r.extras:
 398 |                 result.extras = r.extras
 399 |             result.download_urls = versions.get('urls', {}).get(version, set())
 400 |             d = {}
 401 |             sd = versions.get('digests', {})
 402 |             for url in result.download_urls:
 403 |                 if url in sd:  # pragma: no cover
 404 |                     d[url] = sd[url]
 405 |             result.digests = d
 406 |         self.matcher = None
 407 |         return result
 408 | 
 409 | 
 410 | class PyPIRPCLocator(Locator):
 411 |     """
 412 |     This locator uses XML-RPC to locate distributions. It therefore
 413 |     cannot be used with simple mirrors (that only mirror file content).
 414 |     """
 415 |     def __init__(self, url, **kwargs):
 416 |         """
 417 |         Initialise an instance.
 418 | 
 419 |         :param url: The URL to use for XML-RPC.
 420 |         :param kwargs: Passed to the superclass constructor.
 421 |         """
 422 |         super(PyPIRPCLocator, self).__init__(**kwargs)
 423 |         self.base_url = url
 424 |         self.client = ServerProxy(url, timeout=3.0)
 425 | 
 426 |     def get_distribution_names(self):
 427 |         """
 428 |         Return all the distribution names known to this locator.
 429 |         """
 430 |         return set(self.client.list_packages())
 431 | 
 432 |     def _get_project(self, name):
 433 |         result = {'urls': {}, 'digests': {}}
 434 |         versions = self.client.package_releases(name, True)
 435 |         for v in versions:
 436 |             urls = self.client.release_urls(name, v)
 437 |             data = self.client.release_data(name, v)
 438 |             metadata = Metadata(scheme=self.scheme)
 439 |             metadata.name = data['name']
 440 |             metadata.version = data['version']
 441 |             metadata.license = data.get('license')
 442 |             metadata.keywords = data.get('keywords', [])
 443 |             metadata.summary = data.get('summary')
 444 |             dist = Distribution(metadata)
 445 |             if urls:
 446 |                 info = urls[0]
 447 |                 metadata.source_url = info['url']
 448 |                 dist.digest = self._get_digest(info)
 449 |                 dist.locator = self
 450 |                 result[v] = dist
 451 |                 for info in urls:
 452 |                     url = info['url']
 453 |                     digest = self._get_digest(info)
 454 |                     result['urls'].setdefault(v, set()).add(url)
 455 |                     result['digests'][url] = digest
 456 |         return result
 457 | 
 458 | 
 459 | class PyPIJSONLocator(Locator):
 460 |     """
 461 |     This locator uses PyPI's JSON interface. It's very limited in functionality
 462 |     and probably not worth using.
 463 |     """
 464 |     def __init__(self, url, **kwargs):
 465 |         super(PyPIJSONLocator, self).__init__(**kwargs)
 466 |         self.base_url = ensure_slash(url)
 467 | 
 468 |     def get_distribution_names(self):
 469 |         """
 470 |         Return all the distribution names known to this locator.
 471 |         """
 472 |         raise NotImplementedError('Not available from this locator')
 473 | 
 474 |     def _get_project(self, name):
 475 |         result = {'urls': {}, 'digests': {}}
 476 |         url = urljoin(self.base_url, '%s/json' % quote(name))
 477 |         try:
 478 |             resp = self.opener.open(url)
 479 |             data = resp.read().decode()  # for now
 480 |             d = json.loads(data)
 481 |             md = Metadata(scheme=self.scheme)
 482 |             data = d['info']
 483 |             md.name = data['name']
 484 |             md.version = data['version']
 485 |             md.license = data.get('license')
 486 |             md.keywords = data.get('keywords', [])
 487 |             md.summary = data.get('summary')
 488 |             dist = Distribution(md)
 489 |             dist.locator = self
 490 |             # urls = d['urls']
 491 |             result[md.version] = dist
 492 |             for info in d['urls']:
 493 |                 url = info['url']
 494 |                 dist.download_urls.add(url)
 495 |                 dist.digests[url] = self._get_digest(info)
 496 |                 result['urls'].setdefault(md.version, set()).add(url)
 497 |                 result['digests'][url] = self._get_digest(info)
 498 |             # Now get other releases
 499 |             for version, infos in d['releases'].items():
 500 |                 if version == md.version:
 501 |                     continue    # already done
 502 |                 omd = Metadata(scheme=self.scheme)
 503 |                 omd.name = md.name
 504 |                 omd.version = version
 505 |                 odist = Distribution(omd)
 506 |                 odist.locator = self
 507 |                 result[version] = odist
 508 |                 for info in infos:
 509 |                     url = info['url']
 510 |                     odist.download_urls.add(url)
 511 |                     odist.digests[url] = self._get_digest(info)
 512 |                     result['urls'].setdefault(version, set()).add(url)
 513 |                     result['digests'][url] = self._get_digest(info)
 514 | #            for info in urls:
 515 | #                md.source_url = info['url']
 516 | #                dist.digest = self._get_digest(info)
 517 | #                dist.locator = self
 518 | #                for info in urls:
 519 | #                    url = info['url']
 520 | #                    result['urls'].setdefault(md.version, set()).add(url)
 521 | #                    result['digests'][url] = self._get_digest(info)
 522 |         except Exception as e:
 523 |             self.errors.put(text_type(e))
 524 |             logger.exception('JSON fetch failed: %s', e)
 525 |         return result
 526 | 
 527 | 
 528 | class Page(object):
 529 |     """
 530 |     This class represents a scraped HTML page.
 531 |     """
 532 |     # The following slightly hairy-looking regex just looks for the contents of
 533 |     # an anchor link, which has an attribute "href" either immediately preceded
 534 |     # or immediately followed by a "rel" attribute. The attribute values can be
 535 |     # declared with double quotes, single quotes or no quotes - which leads to
 536 |     # the length of the expression.
 537 |     _href = re.compile("""
 538 | (rel\\s*=\\s*(?:"(?P<rel1>[^"]*)"|'(?P<rel2>[^']*)'|(?P<rel3>[^>\\s\n]*))\\s+)?
 539 | href\\s*=\\s*(?:"(?P<url1>[^"]*)"|'(?P<url2>[^']*)'|(?P<url3>[^>\\s\n]*))
 540 | (\\s+rel\\s*=\\s*(?:"(?P<rel4>[^"]*)"|'(?P<rel5>[^']*)'|(?P<rel6>[^>\\s\n]*)))?
 541 | """, re.I | re.S | re.X)
 542 |     _base = re.compile(r"""<base\s+href\s*=\s*['"]?([^'">]+)""", re.I | re.S)
 543 | 
 544 |     def __init__(self, data, url):
 545 |         """
 546 |         Initialise an instance with the Unicode page contents and the URL they
 547 |         came from.
 548 |         """
 549 |         self.data = data
 550 |         self.base_url = self.url = url
 551 |         m = self._base.search(self.data)
 552 |         if m:
 553 |             self.base_url = m.group(1)
 554 | 
 555 |     _clean_re = re.compile(r'[^a-z0-9$&+,/:;=?@.#%_\\|-]', re.I)
 556 | 
 557 |     @cached_property
 558 |     def links(self):
 559 |         """
 560 |         Return the URLs of all the links on a page together with information
 561 |         about their "rel" attribute, for determining which ones to treat as
 562 |         downloads and which ones to queue for further scraping.
 563 |         """
 564 |         def clean(url):
 565 |             "Tidy up an URL."
 566 |             scheme, netloc, path, params, query, frag = urlparse(url)
 567 |             return urlunparse((scheme, netloc, quote(path),
 568 |                                params, query, frag))
 569 | 
 570 |         result = set()
 571 |         for match in self._href.finditer(self.data):
 572 |             d = match.groupdict('')
 573 |             rel = (d['rel1'] or d['rel2'] or d['rel3'] or
 574 |                    d['rel4'] or d['rel5'] or d['rel6'])
 575 |             url = d['url1'] or d['url2'] or d['url3']
 576 |             url = urljoin(self.base_url, url)
 577 |             url = unescape(url)
 578 |             url = self._clean_re.sub(lambda m: '%%%2x' % ord(m.group(0)), url)
 579 |             result.add((url, rel))
 580 |         # We sort the result, hoping to bring the most recent versions
 581 |         # to the front
 582 |         result = sorted(result, key=lambda t: t[0], reverse=True)
 583 |         return result
 584 | 
 585 | 
 586 | class SimpleScrapingLocator(Locator):
 587 |     """
 588 |     A locator which scrapes HTML pages to locate downloads for a distribution.
 589 |     This runs multiple threads to do the I/O; performance is at least as good
 590 |     as pip's PackageFinder, which works in an analogous fashion.
 591 |     """
 592 | 
 593 |     # These are used to deal with various Content-Encoding schemes.
 594 |     decoders = {
 595 |         'deflate': zlib.decompress,
 596 |         'gzip': lambda b: gzip.GzipFile(fileobj=BytesIO(b)).read(),
 597 |         'none': lambda b: b,
 598 |     }
 599 | 
 600 |     def __init__(self, url, timeout=None, num_workers=10, **kwargs):
 601 |         """
 602 |         Initialise an instance.
 603 |         :param url: The root URL to use for scraping.
 604 |         :param timeout: The timeout, in seconds, to be applied to requests.
 605 |                         This defaults to ``None`` (no timeout specified).
 606 |         :param num_workers: The number of worker threads you want to do I/O,
 607 |                             This defaults to 10.
 608 |         :param kwargs: Passed to the superclass.
 609 |         """
 610 |         super(SimpleScrapingLocator, self).__init__(**kwargs)
 611 |         self.base_url = ensure_slash(url)
 612 |         self.timeout = timeout
 613 |         self._page_cache = {}
 614 |         self._seen = set()
 615 |         self._to_fetch = queue.Queue()
 616 |         self._bad_hosts = set()
 617 |         self.skip_externals = False
 618 |         self.num_workers = num_workers
 619 |         self._lock = threading.RLock()
 620 |         # See issue #45: we need to be resilient when the locator is used
 621 |         # in a thread, e.g. with concurrent.futures. We can't use self._lock
 622 |         # as it is for coordinating our internal threads - the ones created
 623 |         # in _prepare_threads.
 624 |         self._gplock = threading.RLock()
 625 |         self.platform_check = False  # See issue #112
 626 | 
 627 |     def _prepare_threads(self):
 628 |         """
 629 |         Threads are created only when get_project is called, and terminate
 630 |         before it returns. They are there primarily to parallelise I/O (i.e.
 631 |         fetching web pages).
 632 |         """
 633 |         self._threads = []
 634 |         for i in range(self.num_workers):
 635 |             t = threading.Thread(target=self._fetch)
 636 |             t.daemon = True
 637 |             t.start()
 638 |             self._threads.append(t)
 639 | 
 640 |     def _wait_threads(self):
 641 |         """
 642 |         Tell all the threads to terminate (by sending a sentinel value) and
 643 |         wait for them to do so.
 644 |         """
 645 |         # Note that you need two loops, since you can't say which
 646 |         # thread will get each sentinel
 647 |         for t in self._threads:
 648 |             self._to_fetch.put(None)    # sentinel
 649 |         for t in self._threads:
 650 |             t.join()
 651 |         self._threads = []
 652 | 
 653 |     def _get_project(self, name):
 654 |         result = {'urls': {}, 'digests': {}}
 655 |         with self._gplock:
 656 |             self.result = result
 657 |             self.project_name = name
 658 |             url = urljoin(self.base_url, '%s/' % quote(name))
 659 |             self._seen.clear()
 660 |             self._page_cache.clear()
 661 |             self._prepare_threads()
 662 |             try:
 663 |                 logger.debug('Queueing %s', url)
 664 |                 self._to_fetch.put(url)
 665 |                 self._to_fetch.join()
 666 |             finally:
 667 |                 self._wait_threads()
 668 |             del self.result
 669 |         return result
 670 | 
 671 |     platform_dependent = re.compile(r'\b(linux_(i\d86|x86_64|arm\w+)|'
 672 |                                     r'win(32|_amd64)|macosx_?\d+)\b', re.I)
 673 | 
 674 |     def _is_platform_dependent(self, url):
 675 |         """
 676 |         Does an URL refer to a platform-specific download?
 677 |         """
 678 |         return self.platform_dependent.search(url)
 679 | 
 680 |     def _process_download(self, url):
 681 |         """
 682 |         See if an URL is a suitable download for a project.
 683 | 
 684 |         If it is, register information in the result dictionary (for
 685 |         _get_project) about the specific version it's for.
 686 | 
 687 |         Note that the return value isn't actually used other than as a boolean
 688 |         value.
 689 |         """
 690 |         if self.platform_check and self._is_platform_dependent(url):
 691 |             info = None
 692 |         else:
 693 |             info = self.convert_url_to_download_info(url, self.project_name)
 694 |         logger.debug('process_download: %s -> %s', url, info)
 695 |         if info:
 696 |             with self._lock:    # needed because self.result is shared
 697 |                 self._update_version_data(self.result, info)
 698 |         return info
 699 | 
 700 |     def _should_queue(self, link, referrer, rel):
 701 |         """
 702 |         Determine whether a link URL from a referring page and with a
 703 |         particular "rel" attribute should be queued for scraping.
 704 |         """
 705 |         scheme, netloc, path, _, _, _ = urlparse(link)
 706 |         if path.endswith(self.source_extensions + self.binary_extensions +
 707 |                          self.excluded_extensions):
 708 |             result = False
 709 |         elif self.skip_externals and not link.startswith(self.base_url):
 710 |             result = False
 711 |         elif not referrer.startswith(self.base_url):
 712 |             result = False
 713 |         elif rel not in ('homepage', 'download'):
 714 |             result = False
 715 |         elif scheme not in ('http', 'https', 'ftp'):
 716 |             result = False
 717 |         elif self._is_platform_dependent(link):
 718 |             result = False
 719 |         else:
 720 |             host = netloc.split(':', 1)[0]
 721 |             if host.lower() == 'localhost':
 722 |                 result = False
 723 |             else:
 724 |                 result = True
 725 |         logger.debug('should_queue: %s (%s) from %s -> %s', link, rel,
 726 |                      referrer, result)
 727 |         return result
 728 | 
 729 |     def _fetch(self):
 730 |         """
 731 |         Get a URL to fetch from the work queue, get the HTML page, examine its
 732 |         links for download candidates and candidates for further scraping.
 733 | 
 734 |         This is a handy method to run in a thread.
 735 |         """
 736 |         while True:
 737 |             url = self._to_fetch.get()
 738 |             try:
 739 |                 if url:
 740 |                     page = self.get_page(url)
 741 |                     if page is None:    # e.g. after an error
 742 |                         continue
 743 |                     for link, rel in page.links:
 744 |                         if link not in self._seen:
 745 |                             try:
 746 |                                 self._seen.add(link)
 747 |                                 if (not self._process_download(link) and
 748 |                                         self._should_queue(link, url, rel)):
 749 |                                     logger.debug('Queueing %s from %s', link, url)
 750 |                                     self._to_fetch.put(link)
 751 |                             except MetadataInvalidError:  # e.g. invalid versions
 752 |                                 pass
 753 |             except Exception as e:  # pragma: no cover
 754 |                 self.errors.put(text_type(e))
 755 |             finally:
 756 |                 # always do this, to avoid hangs :-)
 757 |                 self._to_fetch.task_done()
 758 |             if not url:
 759 |                 # logger.debug('Sentinel seen, quitting.')
 760 |                 break
 761 | 
 762 |     def get_page(self, url):
 763 |         """
 764 |         Get the HTML for an URL, possibly from an in-memory cache.
 765 | 
 766 |         XXX TODO Note: this cache is never actually cleared. It's assumed that
 767 |         the data won't get stale over the lifetime of a locator instance (not
 768 |         necessarily true for the default_locator).
 769 |         """
 770 |         # http://peak.telecommunity.com/DevCenter/EasyInstall#package-index-api
 771 |         scheme, netloc, path, _, _, _ = urlparse(url)
 772 |         if scheme == 'file' and os.path.isdir(url2pathname(path)):
 773 |             url = urljoin(ensure_slash(url), 'index.html')
 774 | 
 775 |         if url in self._page_cache:
 776 |             result = self._page_cache[url]
 777 |             logger.debug('Returning %s from cache: %s', url, result)
 778 |         else:
 779 |             host = netloc.split(':', 1)[0]
 780 |             result = None
 781 |             if host in self._bad_hosts:
 782 |                 logger.debug('Skipping %s due to bad host %s', url, host)
 783 |             else:
 784 |                 req = Request(url, headers={'Accept-encoding': 'identity'})
 785 |                 try:
 786 |                     logger.debug('Fetching %s', url)
 787 |                     resp = self.opener.open(req, timeout=self.timeout)
 788 |                     logger.debug('Fetched %s', url)
 789 |                     headers = resp.info()
 790 |                     content_type = headers.get('Content-Type', '')
 791 |                     if HTML_CONTENT_TYPE.match(content_type):
 792 |                         final_url = resp.geturl()
 793 |                         data = resp.read()
 794 |                         encoding = headers.get('Content-Encoding')
 795 |                         if encoding:
 796 |                             decoder = self.decoders[encoding]   # fail if not found
 797 |                             data = decoder(data)
 798 |                         encoding = 'utf-8'
 799 |                         m = CHARSET.search(content_type)
 800 |                         if m:
 801 |                             encoding = m.group(1)
 802 |                         try:
 803 |                             data = data.decode(encoding)
 804 |                         except UnicodeError:  # pragma: no cover
 805 |                             data = data.decode('latin-1')    # fallback
 806 |                         result = Page(data, final_url)
 807 |                         self._page_cache[final_url] = result
 808 |                 except HTTPError as e:
 809 |                     if e.code != 404:
 810 |                         logger.exception('Fetch failed: %s: %s', url, e)
 811 |                 except URLError as e:  # pragma: no cover
 812 |                     logger.exception('Fetch failed: %s: %s', url, e)
 813 |                     with self._lock:
 814 |                         self._bad_hosts.add(host)
 815 |                 except Exception as e:  # pragma: no cover
 816 |                     logger.exception('Fetch failed: %s: %s', url, e)
 817 |                 finally:
 818 |                     self._page_cache[url] = result   # even if None (failure)
 819 |         return result
 820 | 
 821 |     _distname_re = re.compile('<a href=[^>]*>([^<]+)<')
 822 | 
 823 |     def get_distribution_names(self):
 824 |         """
 825 |         Return all the distribution names known to this locator.
 826 |         """
 827 |         result = set()
 828 |         page = self.get_page(self.base_url)
 829 |         if not page:
 830 |             raise DistlibException('Unable to get %s' % self.base_url)
 831 |         for match in self._distname_re.finditer(page.data):
 832 |             result.add(match.group(1))
 833 |         return result
 834 | 
 835 | 
 836 | class DirectoryLocator(Locator):
 837 |     """
 838 |     This class locates distributions in a directory tree.
 839 |     """
 840 | 
 841 |     def __init__(self, path, **kwargs):
 842 |         """
 843 |         Initialise an instance.
 844 |         :param path: The root of the directory tree to search.
 845 |         :param kwargs: Passed to the superclass constructor,
 846 |                        except for:
 847 |                        * recursive - if True (the default), subdirectories are
 848 |                          recursed into. If False, only the top-level directory
 849 |                          is searched,
 850 |         """
 851 |         self.recursive = kwargs.pop('recursive', True)
 852 |         super(DirectoryLocator, self).__init__(**kwargs)
 853 |         path = os.path.abspath(path)
 854 |         if not os.path.isdir(path):  # pragma: no cover
 855 |             raise DistlibException('Not a directory: %r' % path)
 856 |         self.base_dir = path
 857 | 
 858 |     def should_include(self, filename, parent):
 859 |         """
 860 |         Should a filename be considered as a candidate for a distribution
 861 |         archive? As well as the filename, the directory which contains it
 862 |         is provided, though not used by the current implementation.
 863 |         """
 864 |         return filename.endswith(self.downloadable_extensions)
 865 | 
 866 |     def _get_project(self, name):
 867 |         result = {'urls': {}, 'digests': {}}
 868 |         for root, dirs, files in os.walk(self.base_dir):
 869 |             for fn in files:
 870 |                 if self.should_include(fn, root):
 871 |                     fn = os.path.join(root, fn)
 872 |                     url = urlunparse(('file', '',
 873 |                                       pathname2url(os.path.abspath(fn)),
 874 |                                       '', '', ''))
 875 |                     info = self.convert_url_to_download_info(url, name)
 876 |                     if info:
 877 |                         self._update_version_data(result, info)
 878 |             if not self.recursive:
 879 |                 break
 880 |         return result
 881 | 
 882 |     def get_distribution_names(self):
 883 |         """
 884 |         Return all the distribution names known to this locator.
 885 |         """
 886 |         result = set()
 887 |         for root, dirs, files in os.walk(self.base_dir):
 888 |             for fn in files:
 889 |                 if self.should_include(fn, root):
 890 |                     fn = os.path.join(root, fn)
 891 |                     url = urlunparse(('file', '',
 892 |                                       pathname2url(os.path.abspath(fn)),
 893 |                                       '', '', ''))
 894 |                     info = self.convert_url_to_download_info(url, None)
 895 |                     if info:
 896 |                         result.add(info['name'])
 897 |             if not self.recursive:
 898 |                 break
 899 |         return result
 900 | 
 901 | 
 902 | class JSONLocator(Locator):
 903 |     """
 904 |     This locator uses special extended metadata (not available on PyPI) and is
 905 |     the basis of performant dependency resolution in distlib. Other locators
 906 |     require archive downloads before dependencies can be determined! As you
 907 |     might imagine, that can be slow.
 908 |     """
 909 |     def get_distribution_names(self):
 910 |         """
 911 |         Return all the distribution names known to this locator.
 912 |         """
 913 |         raise NotImplementedError('Not available from this locator')
 914 | 
 915 |     def _get_project(self, name):
 916 |         result = {'urls': {}, 'digests': {}}
 917 |         data = get_project_data(name)
 918 |         if data:
 919 |             for info in data.get('files', []):
 920 |                 if info['ptype'] != 'sdist' or info['pyversion'] != 'source':
 921 |                     continue
 922 |                 # We don't store summary in project metadata as it makes
 923 |                 # the data bigger for no benefit during dependency
 924 |                 # resolution
 925 |                 dist = make_dist(data['name'], info['version'],
 926 |                                  summary=data.get('summary',
 927 |                                                   'Placeholder for summary'),
 928 |                                  scheme=self.scheme)
 929 |                 md = dist.metadata
 930 |                 md.source_url = info['url']
 931 |                 # TODO SHA256 digest
 932 |                 if 'digest' in info and info['digest']:
 933 |                     dist.digest = ('md5', info['digest'])
 934 |                 md.dependencies = info.get('requirements', {})
 935 |                 dist.exports = info.get('exports', {})
 936 |                 result[dist.version] = dist
 937 |                 result['urls'].setdefault(dist.version, set()).add(info['url'])
 938 |         return result
 939 | 
 940 | 
 941 | class DistPathLocator(Locator):
 942 |     """
 943 |     This locator finds installed distributions in a path. It can be useful for
 944 |     adding to an :class:`AggregatingLocator`.
 945 |     """
 946 |     def __init__(self, distpath, **kwargs):
 947 |         """
 948 |         Initialise an instance.
 949 | 
 950 |         :param distpath: A :class:`DistributionPath` instance to search.
 951 |         """
 952 |         super(DistPathLocator, self).__init__(**kwargs)
 953 |         assert isinstance(distpath, DistributionPath)
 954 |         self.distpath = distpath
 955 | 
 956 |     def _get_project(self, name):
 957 |         dist = self.distpath.get_distribution(name)
 958 |         if dist is None:
 959 |             result = {'urls': {}, 'digests': {}}
 960 |         else:
 961 |             result = {
 962 |                 dist.version: dist,
 963 |                 'urls': {dist.version: set([dist.source_url])},
 964 |                 'digests': {dist.version: set([None])}
 965 |             }
 966 |         return result
 967 | 
 968 | 
 969 | class AggregatingLocator(Locator):
 970 |     """
 971 |     This class allows you to chain and/or merge a list of locators.
 972 |     """
 973 |     def __init__(self, *locators, **kwargs):
 974 |         """
 975 |         Initialise an instance.
 976 | 
 977 |         :param locators: The list of locators to search.
 978 |         :param kwargs: Passed to the superclass constructor,
 979 |                        except for:
 980 |                        * merge - if False (the default), the first successful
 981 |                          search from any of the locators is returned. If True,
 982 |                          the results from all locators are merged (this can be
 983 |                          slow).
 984 |         """
 985 |         self.merge = kwargs.pop('merge', False)
 986 |         self.locators = locators
 987 |         super(AggregatingLocator, self).__init__(**kwargs)
 988 | 
 989 |     def clear_cache(self):
 990 |         super(AggregatingLocator, self).clear_cache()
 991 |         for locator in self.locators:
 992 |             locator.clear_cache()
 993 | 
 994 |     def _set_scheme(self, value):
 995 |         self._scheme = value
 996 |         for locator in self.locators:
 997 |             locator.scheme = value
 998 | 
 999 |     scheme = property(Locator.scheme.fget, _set_scheme)
1000 | 
1001 |     def _get_project(self, name):
1002 |         result = {}
1003 |         for locator in self.locators:
1004 |             d = locator.get_project(name)
1005 |             if d:
1006 |                 if self.merge:
1007 |                     files = result.get('urls', {})
1008 |                     digests = result.get('digests', {})
1009 |                     # next line could overwrite result['urls'], result['digests']
1010 |                     result.update(d)
1011 |                     df = result.get('urls')
1012 |                     if files and df:
1013 |                         for k, v in files.items():
1014 |                             if k in df:
1015 |                                 df[k] |= v
1016 |                             else:
1017 |                                 df[k] = v
1018 |                     dd = result.get('digests')
1019 |                     if digests and dd:
1020 |                         dd.update(digests)
1021 |                 else:
1022 |                     # See issue #18. If any dists are found and we're looking
1023 |                     # for specific constraints, we only return something if
1024 |                     # a match is found. For example, if a DirectoryLocator
1025 |                     # returns just foo (1.0) while we're looking for
1026 |                     # foo (>= 2.0), we'll pretend there was nothing there so
1027 |                     # that subsequent locators can be queried. Otherwise we
1028 |                     # would just return foo (1.0) which would then lead to a
1029 |                     # failure to find foo (>= 2.0), because other locators
1030 |                     # weren't searched. Note that this only matters when
1031 |                     # merge=False.
1032 |                     if self.matcher is None:
1033 |                         found = True
1034 |                     else:
1035 |                         found = False
1036 |                         for k in d:
1037 |                             if self.matcher.match(k):
1038 |                                 found = True
1039 |                                 break
1040 |                     if found:
1041 |                         result = d
1042 |                         break
1043 |         return result
1044 | 
1045 |     def get_distribution_names(self):
1046 |         """
1047 |         Return all the distribution names known to this locator.
1048 |         """
1049 |         result = set()
1050 |         for locator in self.locators:
1051 |             try:
1052 |                 result |= locator.get_distribution_names()
1053 |             except NotImplementedError:
1054 |                 pass
1055 |         return result
1056 | 
1057 | 
1058 | # We use a legacy scheme simply because most of the dists on PyPI use legacy
1059 | # versions which don't conform to PEP 440.
1060 | default_locator = AggregatingLocator(
1061 |                     # JSONLocator(), # don't use as PEP 426 is withdrawn
1062 |                     SimpleScrapingLocator('https://pypi.org/simple/',
1063 |                                           timeout=3.0),
1064 |                     scheme='legacy')
1065 | 
1066 | locate = default_locator.locate
1067 | 
1068 | 
1069 | class DependencyFinder(object):
1070 |     """
1071 |     Locate dependencies for distributions.
1072 |     """
1073 | 
1074 |     def __init__(self, locator=None):
1075 |         """
1076 |         Initialise an instance, using the specified locator
1077 |         to locate distributions.
1078 |         """
1079 |         self.locator = locator or default_locator
1080 |         self.scheme = get_scheme(self.locator.scheme)
1081 | 
1082 |     def add_distribution(self, dist):
1083 |         """
1084 |         Add a distribution to the finder. This will update internal information
1085 |         about who provides what.
1086 |         :param dist: The distribution to add.
1087 |         """
1088 |         logger.debug('adding distribution %s', dist)
1089 |         name = dist.key
1090 |         self.dists_by_name[name] = dist
1091 |         self.dists[(name, dist.version)] = dist
1092 |         for p in dist.provides:
1093 |             name, version = parse_name_and_version(p)
1094 |             logger.debug('Add to provided: %s, %s, %s', name, version, dist)
1095 |             self.provided.setdefault(name, set()).add((version, dist))
1096 | 
1097 |     def remove_distribution(self, dist):
1098 |         """
1099 |         Remove a distribution from the finder. This will update internal
1100 |         information about who provides what.
1101 |         :param dist: The distribution to remove.
1102 |         """
1103 |         logger.debug('removing distribution %s', dist)
1104 |         name = dist.key
1105 |         del self.dists_by_name[name]
1106 |         del self.dists[(name, dist.version)]
1107 |         for p in dist.provides:
1108 |             name, version = parse_name_and_version(p)
1109 |             logger.debug('Remove from provided: %s, %s, %s', name, version, dist)
1110 |             s = self.provided[name]
1111 |             s.remove((version, dist))
1112 |             if not s:
1113 |                 del self.provided[name]
1114 | 
1115 |     def get_matcher(self, reqt):
1116 |         """
1117 |         Get a version matcher for a requirement.
1118 |         :param reqt: The requirement
1119 |         :type reqt: str
1120 |         :return: A version matcher (an instance of
1121 |                  :class:`distlib.version.Matcher`).
1122 |         """
1123 |         try:
1124 |             matcher = self.scheme.matcher(reqt)
1125 |         except UnsupportedVersionError:  # pragma: no cover
1126 |             # XXX compat-mode if cannot read the version
1127 |             name = reqt.split()[0]
1128 |             matcher = self.scheme.matcher(name)
1129 |         return matcher
1130 | 
1131 |     def find_providers(self, reqt):
1132 |         """
1133 |         Find the distributions which can fulfill a requirement.
1134 | 
1135 |         :param reqt: The requirement.
1136 |          :type reqt: str
1137 |         :return: A set of distribution which can fulfill the requirement.
1138 |         """
1139 |         matcher = self.get_matcher(reqt)
1140 |         name = matcher.key   # case-insensitive
1141 |         result = set()
1142 |         provided = self.provided
1143 |         if name in provided:
1144 |             for version, provider in provided[name]:
1145 |                 try:
1146 |                     match = matcher.match(version)
1147 |                 except UnsupportedVersionError:
1148 |                     match = False
1149 | 
1150 |                 if match:
1151 |                     result.add(provider)
1152 |                     break
1153 |         return result
1154 | 
1155 |     def try_to_replace(self, provider, other, problems):
1156 |         """
1157 |         Attempt to replace one provider with another. This is typically used
1158 |         when resolving dependencies from multiple sources, e.g. A requires
1159 |         (B >= 1.0) while C requires (B >= 1.1).
1160 | 
1161 |         For successful replacement, ``provider`` must meet all the requirements
1162 |         which ``other`` fulfills.
1163 | 
1164 |         :param provider: The provider we are trying to replace with.
1165 |         :param other: The provider we're trying to replace.
1166 |         :param problems: If False is returned, this will contain what
1167 |                          problems prevented replacement. This is currently
1168 |                          a tuple of the literal string 'cantreplace',
1169 |                          ``provider``, ``other``  and the set of requirements
1170 |                          that ``provider`` couldn't fulfill.
1171 |         :return: True if we can replace ``other`` with ``provider``, else
1172 |                  False.
1173 |         """
1174 |         rlist = self.reqts[other]
1175 |         unmatched = set()
1176 |         for s in rlist:
1177 |             matcher = self.get_matcher(s)
1178 |             if not matcher.match(provider.version):
1179 |                 unmatched.add(s)
1180 |         if unmatched:
1181 |             # can't replace other with provider
1182 |             problems.add(('cantreplace', provider, other,
1183 |                           frozenset(unmatched)))
1184 |             result = False
1185 |         else:
1186 |             # can replace other with provider
1187 |             self.remove_distribution(other)
1188 |             del self.reqts[other]
1189 |             for s in rlist:
1190 |                 self.reqts.setdefault(provider, set()).add(s)
1191 |             self.add_distribution(provider)
1192 |             result = True
1193 |         return result
1194 | 
1195 |     def find(self, requirement, meta_extras=None, prereleases=False):
1196 |         """
1197 |         Find a distribution and all distributions it depends on.
1198 | 
1199 |         :param requirement: The requirement specifying the distribution to
1200 |                             find, or a Distribution instance.
1201 |         :param meta_extras: A list of meta extras such as :test:, :build: and
1202 |                             so on.
1203 |         :param prereleases: If ``True``, allow pre-release versions to be
1204 |                             returned - otherwise, don't return prereleases
1205 |                             unless they're all that's available.
1206 | 
1207 |         Return a set of :class:`Distribution` instances and a set of
1208 |         problems.
1209 | 
1210 |         The distributions returned should be such that they have the
1211 |         :attr:`required` attribute set to ``True`` if they were
1212 |         from the ``requirement`` passed to ``find()``, and they have the
1213 |         :attr:`build_time_dependency` attribute set to ``True`` unless they
1214 |         are post-installation dependencies of the ``requirement``.
1215 | 
1216 |         The problems should be a tuple consisting of the string
1217 |         ``'unsatisfied'`` and the requirement which couldn't be satisfied
1218 |         by any distribution known to the locator.
1219 |         """
1220 | 
1221 |         self.provided = {}
1222 |         self.dists = {}
1223 |         self.dists_by_name = {}
1224 |         self.reqts = {}
1225 | 
1226 |         meta_extras = set(meta_extras or [])
1227 |         if ':*:' in meta_extras:
1228 |             meta_extras.remove(':*:')
1229 |             # :meta: and :run: are implicitly included
1230 |             meta_extras |= set([':test:', ':build:', ':dev:'])
1231 | 
1232 |         if isinstance(requirement, Distribution):
1233 |             dist = odist = requirement
1234 |             logger.debug('passed %s as requirement', odist)
1235 |         else:
1236 |             dist = odist = self.locator.locate(requirement,
1237 |                                                prereleases=prereleases)
1238 |             if dist is None:
1239 |                 raise DistlibException('Unable to locate %r' % requirement)
1240 |             logger.debug('located %s', odist)
1241 |         dist.requested = True
1242 |         problems = set()
1243 |         todo = set([dist])
1244 |         install_dists = set([odist])
1245 |         while todo:
1246 |             dist = todo.pop()
1247 |             name = dist.key     # case-insensitive
1248 |             if name not in self.dists_by_name:
1249 |                 self.add_distribution(dist)
1250 |             else:
1251 |                 # import pdb; pdb.set_trace()
1252 |                 other = self.dists_by_name[name]
1253 |                 if other != dist:
1254 |                     self.try_to_replace(dist, other, problems)
1255 | 
1256 |             ireqts = dist.run_requires | dist.meta_requires
1257 |             sreqts = dist.build_requires
1258 |             ereqts = set()
1259 |             if meta_extras and dist in install_dists:
1260 |                 for key in ('test', 'build', 'dev'):
1261 |                     e = ':%s:' % key
1262 |                     if e in meta_extras:
1263 |                         ereqts |= getattr(dist, '%s_requires' % key)
1264 |             all_reqts = ireqts | sreqts | ereqts
1265 |             for r in all_reqts:
1266 |                 providers = self.find_providers(r)
1267 |                 if not providers:
1268 |                     logger.debug('No providers found for %r', r)
1269 |                     provider = self.locator.locate(r, prereleases=prereleases)
1270 |                     # If no provider is found and we didn't consider
1271 |                     # prereleases, consider them now.
1272 |                     if provider is None and not prereleases:
1273 |                         provider = self.locator.locate(r, prereleases=True)
1274 |                     if provider is None:
1275 |                         logger.debug('Cannot satisfy %r', r)
1276 |                         problems.add(('unsatisfied', r))
1277 |                     else:
1278 |                         n, v = provider.key, provider.version
1279 |                         if (n, v) not in self.dists:
1280 |                             todo.add(provider)
1281 |                         providers.add(provider)
1282 |                         if r in ireqts and dist in install_dists:
1283 |                             install_dists.add(provider)
1284 |                             logger.debug('Adding %s to install_dists',
1285 |                                          provider.name_and_version)
1286 |                 for p in providers:
1287 |                     name = p.key
1288 |                     if name not in self.dists_by_name:
1289 |                         self.reqts.setdefault(p, set()).add(r)
1290 |                     else:
1291 |                         other = self.dists_by_name[name]
1292 |                         if other != p:
1293 |                             # see if other can be replaced by p
1294 |                             self.try_to_replace(p, other, problems)
1295 | 
1296 |         dists = set(self.dists.values())
1297 |         for dist in dists:
1298 |             dist.build_time_dependency = dist not in install_dists
1299 |             if dist.build_time_dependency:
1300 |                 logger.debug('%s is a build-time dependency only.',
1301 |                              dist.name_and_version)
1302 |         logger.debug('find done for %s', odist)
1303 |         return dists, problems
1304 | 
```
Page 144/168FirstPrevNextLast