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

```python
   1 | # -*- coding: utf-8 -*-
   2 | #
   3 | # Copyright (C) 2012-2023 The Python Software Foundation.
   4 | # See LICENSE.txt and CONTRIBUTORS.txt.
   5 | #
   6 | """PEP 376 implementation."""
   7 | 
   8 | from __future__ import unicode_literals
   9 | 
  10 | import base64
  11 | import codecs
  12 | import contextlib
  13 | import hashlib
  14 | import logging
  15 | import os
  16 | import posixpath
  17 | import sys
  18 | import zipimport
  19 | 
  20 | from . import DistlibException, resources
  21 | from .compat import StringIO
  22 | from .version import get_scheme, UnsupportedVersionError
  23 | from .metadata import (Metadata, METADATA_FILENAME, WHEEL_METADATA_FILENAME,
  24 |                        LEGACY_METADATA_FILENAME)
  25 | from .util import (parse_requirement, cached_property, parse_name_and_version,
  26 |                    read_exports, write_exports, CSVReader, CSVWriter)
  27 | 
  28 | __all__ = [
  29 |     'Distribution', 'BaseInstalledDistribution', 'InstalledDistribution',
  30 |     'EggInfoDistribution', 'DistributionPath'
  31 | ]
  32 | 
  33 | logger = logging.getLogger(__name__)
  34 | 
  35 | EXPORTS_FILENAME = 'pydist-exports.json'
  36 | COMMANDS_FILENAME = 'pydist-commands.json'
  37 | 
  38 | DIST_FILES = ('INSTALLER', METADATA_FILENAME, 'RECORD', 'REQUESTED',
  39 |               'RESOURCES', EXPORTS_FILENAME, 'SHARED')
  40 | 
  41 | DISTINFO_EXT = '.dist-info'
  42 | 
  43 | 
  44 | class _Cache(object):
  45 |     """
  46 |     A simple cache mapping names and .dist-info paths to distributions
  47 |     """
  48 | 
  49 |     def __init__(self):
  50 |         """
  51 |         Initialise an instance. There is normally one for each DistributionPath.
  52 |         """
  53 |         self.name = {}
  54 |         self.path = {}
  55 |         self.generated = False
  56 | 
  57 |     def clear(self):
  58 |         """
  59 |         Clear the cache, setting it to its initial state.
  60 |         """
  61 |         self.name.clear()
  62 |         self.path.clear()
  63 |         self.generated = False
  64 | 
  65 |     def add(self, dist):
  66 |         """
  67 |         Add a distribution to the cache.
  68 |         :param dist: The distribution to add.
  69 |         """
  70 |         if dist.path not in self.path:
  71 |             self.path[dist.path] = dist
  72 |             self.name.setdefault(dist.key, []).append(dist)
  73 | 
  74 | 
  75 | class DistributionPath(object):
  76 |     """
  77 |     Represents a set of distributions installed on a path (typically sys.path).
  78 |     """
  79 | 
  80 |     def __init__(self, path=None, include_egg=False):
  81 |         """
  82 |         Create an instance from a path, optionally including legacy (distutils/
  83 |         setuptools/distribute) distributions.
  84 |         :param path: The path to use, as a list of directories. If not specified,
  85 |                      sys.path is used.
  86 |         :param include_egg: If True, this instance will look for and return legacy
  87 |                             distributions as well as those based on PEP 376.
  88 |         """
  89 |         if path is None:
  90 |             path = sys.path
  91 |         self.path = path
  92 |         self._include_dist = True
  93 |         self._include_egg = include_egg
  94 | 
  95 |         self._cache = _Cache()
  96 |         self._cache_egg = _Cache()
  97 |         self._cache_enabled = True
  98 |         self._scheme = get_scheme('default')
  99 | 
 100 |     def _get_cache_enabled(self):
 101 |         return self._cache_enabled
 102 | 
 103 |     def _set_cache_enabled(self, value):
 104 |         self._cache_enabled = value
 105 | 
 106 |     cache_enabled = property(_get_cache_enabled, _set_cache_enabled)
 107 | 
 108 |     def clear_cache(self):
 109 |         """
 110 |         Clears the internal cache.
 111 |         """
 112 |         self._cache.clear()
 113 |         self._cache_egg.clear()
 114 | 
 115 |     def _yield_distributions(self):
 116 |         """
 117 |         Yield .dist-info and/or .egg(-info) distributions.
 118 |         """
 119 |         # We need to check if we've seen some resources already, because on
 120 |         # some Linux systems (e.g. some Debian/Ubuntu variants) there are
 121 |         # symlinks which alias other files in the environment.
 122 |         seen = set()
 123 |         for path in self.path:
 124 |             finder = resources.finder_for_path(path)
 125 |             if finder is None:
 126 |                 continue
 127 |             r = finder.find('')
 128 |             if not r or not r.is_container:
 129 |                 continue
 130 |             rset = sorted(r.resources)
 131 |             for entry in rset:
 132 |                 r = finder.find(entry)
 133 |                 if not r or r.path in seen:
 134 |                     continue
 135 |                 try:
 136 |                     if self._include_dist and entry.endswith(DISTINFO_EXT):
 137 |                         possible_filenames = [
 138 |                             METADATA_FILENAME, WHEEL_METADATA_FILENAME,
 139 |                             LEGACY_METADATA_FILENAME
 140 |                         ]
 141 |                         for metadata_filename in possible_filenames:
 142 |                             metadata_path = posixpath.join(
 143 |                                 entry, metadata_filename)
 144 |                             pydist = finder.find(metadata_path)
 145 |                             if pydist:
 146 |                                 break
 147 |                         else:
 148 |                             continue
 149 | 
 150 |                         with contextlib.closing(pydist.as_stream()) as stream:
 151 |                             metadata = Metadata(fileobj=stream,
 152 |                                                 scheme='legacy')
 153 |                         logger.debug('Found %s', r.path)
 154 |                         seen.add(r.path)
 155 |                         yield new_dist_class(r.path,
 156 |                                              metadata=metadata,
 157 |                                              env=self)
 158 |                     elif self._include_egg and entry.endswith(
 159 |                             ('.egg-info', '.egg')):
 160 |                         logger.debug('Found %s', r.path)
 161 |                         seen.add(r.path)
 162 |                         yield old_dist_class(r.path, self)
 163 |                 except Exception as e:
 164 |                     msg = 'Unable to read distribution at %s, perhaps due to bad metadata: %s'
 165 |                     logger.warning(msg, r.path, e)
 166 |                     import warnings
 167 |                     warnings.warn(msg % (r.path, e), stacklevel=2)
 168 | 
 169 |     def _generate_cache(self):
 170 |         """
 171 |         Scan the path for distributions and populate the cache with
 172 |         those that are found.
 173 |         """
 174 |         gen_dist = not self._cache.generated
 175 |         gen_egg = self._include_egg and not self._cache_egg.generated
 176 |         if gen_dist or gen_egg:
 177 |             for dist in self._yield_distributions():
 178 |                 if isinstance(dist, InstalledDistribution):
 179 |                     self._cache.add(dist)
 180 |                 else:
 181 |                     self._cache_egg.add(dist)
 182 | 
 183 |             if gen_dist:
 184 |                 self._cache.generated = True
 185 |             if gen_egg:
 186 |                 self._cache_egg.generated = True
 187 | 
 188 |     @classmethod
 189 |     def distinfo_dirname(cls, name, version):
 190 |         """
 191 |         The *name* and *version* parameters are converted into their
 192 |         filename-escaped form, i.e. any ``'-'`` characters are replaced
 193 |         with ``'_'`` other than the one in ``'dist-info'`` and the one
 194 |         separating the name from the version number.
 195 | 
 196 |         :parameter name: is converted to a standard distribution name by replacing
 197 |                          any runs of non- alphanumeric characters with a single
 198 |                          ``'-'``.
 199 |         :type name: string
 200 |         :parameter version: is converted to a standard version string. Spaces
 201 |                             become dots, and all other non-alphanumeric characters
 202 |                             (except dots) become dashes, with runs of multiple
 203 |                             dashes condensed to a single dash.
 204 |         :type version: string
 205 |         :returns: directory name
 206 |         :rtype: string"""
 207 |         name = name.replace('-', '_')
 208 |         return '-'.join([name, version]) + DISTINFO_EXT
 209 | 
 210 |     def get_distributions(self):
 211 |         """
 212 |         Provides an iterator that looks for distributions and returns
 213 |         :class:`InstalledDistribution` or
 214 |         :class:`EggInfoDistribution` instances for each one of them.
 215 | 
 216 |         :rtype: iterator of :class:`InstalledDistribution` and
 217 |                 :class:`EggInfoDistribution` instances
 218 |         """
 219 |         if not self._cache_enabled:
 220 |             for dist in self._yield_distributions():
 221 |                 yield dist
 222 |         else:
 223 |             self._generate_cache()
 224 | 
 225 |             for dist in self._cache.path.values():
 226 |                 yield dist
 227 | 
 228 |             if self._include_egg:
 229 |                 for dist in self._cache_egg.path.values():
 230 |                     yield dist
 231 | 
 232 |     def get_distribution(self, name):
 233 |         """
 234 |         Looks for a named distribution on the path.
 235 | 
 236 |         This function only returns the first result found, as no more than one
 237 |         value is expected. If nothing is found, ``None`` is returned.
 238 | 
 239 |         :rtype: :class:`InstalledDistribution`, :class:`EggInfoDistribution`
 240 |                 or ``None``
 241 |         """
 242 |         result = None
 243 |         name = name.lower()
 244 |         if not self._cache_enabled:
 245 |             for dist in self._yield_distributions():
 246 |                 if dist.key == name:
 247 |                     result = dist
 248 |                     break
 249 |         else:
 250 |             self._generate_cache()
 251 | 
 252 |             if name in self._cache.name:
 253 |                 result = self._cache.name[name][0]
 254 |             elif self._include_egg and name in self._cache_egg.name:
 255 |                 result = self._cache_egg.name[name][0]
 256 |         return result
 257 | 
 258 |     def provides_distribution(self, name, version=None):
 259 |         """
 260 |         Iterates over all distributions to find which distributions provide *name*.
 261 |         If a *version* is provided, it will be used to filter the results.
 262 | 
 263 |         This function only returns the first result found, since no more than
 264 |         one values are expected. If the directory is not found, returns ``None``.
 265 | 
 266 |         :parameter version: a version specifier that indicates the version
 267 |                             required, conforming to the format in ``PEP-345``
 268 | 
 269 |         :type name: string
 270 |         :type version: string
 271 |         """
 272 |         matcher = None
 273 |         if version is not None:
 274 |             try:
 275 |                 matcher = self._scheme.matcher('%s (%s)' % (name, version))
 276 |             except ValueError:
 277 |                 raise DistlibException('invalid name or version: %r, %r' %
 278 |                                        (name, version))
 279 | 
 280 |         for dist in self.get_distributions():
 281 |             # We hit a problem on Travis where enum34 was installed and doesn't
 282 |             # have a provides attribute ...
 283 |             if not hasattr(dist, 'provides'):
 284 |                 logger.debug('No "provides": %s', dist)
 285 |             else:
 286 |                 provided = dist.provides
 287 | 
 288 |                 for p in provided:
 289 |                     p_name, p_ver = parse_name_and_version(p)
 290 |                     if matcher is None:
 291 |                         if p_name == name:
 292 |                             yield dist
 293 |                             break
 294 |                     else:
 295 |                         if p_name == name and matcher.match(p_ver):
 296 |                             yield dist
 297 |                             break
 298 | 
 299 |     def get_file_path(self, name, relative_path):
 300 |         """
 301 |         Return the path to a resource file.
 302 |         """
 303 |         dist = self.get_distribution(name)
 304 |         if dist is None:
 305 |             raise LookupError('no distribution named %r found' % name)
 306 |         return dist.get_resource_path(relative_path)
 307 | 
 308 |     def get_exported_entries(self, category, name=None):
 309 |         """
 310 |         Return all of the exported entries in a particular category.
 311 | 
 312 |         :param category: The category to search for entries.
 313 |         :param name: If specified, only entries with that name are returned.
 314 |         """
 315 |         for dist in self.get_distributions():
 316 |             r = dist.exports
 317 |             if category in r:
 318 |                 d = r[category]
 319 |                 if name is not None:
 320 |                     if name in d:
 321 |                         yield d[name]
 322 |                 else:
 323 |                     for v in d.values():
 324 |                         yield v
 325 | 
 326 | 
 327 | class Distribution(object):
 328 |     """
 329 |     A base class for distributions, whether installed or from indexes.
 330 |     Either way, it must have some metadata, so that's all that's needed
 331 |     for construction.
 332 |     """
 333 | 
 334 |     build_time_dependency = False
 335 |     """
 336 |     Set to True if it's known to be only a build-time dependency (i.e.
 337 |     not needed after installation).
 338 |     """
 339 | 
 340 |     requested = False
 341 |     """A boolean that indicates whether the ``REQUESTED`` metadata file is
 342 |     present (in other words, whether the package was installed by user
 343 |     request or it was installed as a dependency)."""
 344 | 
 345 |     def __init__(self, metadata):
 346 |         """
 347 |         Initialise an instance.
 348 |         :param metadata: The instance of :class:`Metadata` describing this
 349 |         distribution.
 350 |         """
 351 |         self.metadata = metadata
 352 |         self.name = metadata.name
 353 |         self.key = self.name.lower()  # for case-insensitive comparisons
 354 |         self.version = metadata.version
 355 |         self.locator = None
 356 |         self.digest = None
 357 |         self.extras = None  # additional features requested
 358 |         self.context = None  # environment marker overrides
 359 |         self.download_urls = set()
 360 |         self.digests = {}
 361 | 
 362 |     @property
 363 |     def source_url(self):
 364 |         """
 365 |         The source archive download URL for this distribution.
 366 |         """
 367 |         return self.metadata.source_url
 368 | 
 369 |     download_url = source_url  # Backward compatibility
 370 | 
 371 |     @property
 372 |     def name_and_version(self):
 373 |         """
 374 |         A utility property which displays the name and version in parentheses.
 375 |         """
 376 |         return '%s (%s)' % (self.name, self.version)
 377 | 
 378 |     @property
 379 |     def provides(self):
 380 |         """
 381 |         A set of distribution names and versions provided by this distribution.
 382 |         :return: A set of "name (version)" strings.
 383 |         """
 384 |         plist = self.metadata.provides
 385 |         s = '%s (%s)' % (self.name, self.version)
 386 |         if s not in plist:
 387 |             plist.append(s)
 388 |         return plist
 389 | 
 390 |     def _get_requirements(self, req_attr):
 391 |         md = self.metadata
 392 |         reqts = getattr(md, req_attr)
 393 |         logger.debug('%s: got requirements %r from metadata: %r', self.name,
 394 |                      req_attr, reqts)
 395 |         return set(
 396 |             md.get_requirements(reqts, extras=self.extras, env=self.context))
 397 | 
 398 |     @property
 399 |     def run_requires(self):
 400 |         return self._get_requirements('run_requires')
 401 | 
 402 |     @property
 403 |     def meta_requires(self):
 404 |         return self._get_requirements('meta_requires')
 405 | 
 406 |     @property
 407 |     def build_requires(self):
 408 |         return self._get_requirements('build_requires')
 409 | 
 410 |     @property
 411 |     def test_requires(self):
 412 |         return self._get_requirements('test_requires')
 413 | 
 414 |     @property
 415 |     def dev_requires(self):
 416 |         return self._get_requirements('dev_requires')
 417 | 
 418 |     def matches_requirement(self, req):
 419 |         """
 420 |         Say if this instance matches (fulfills) a requirement.
 421 |         :param req: The requirement to match.
 422 |         :rtype req: str
 423 |         :return: True if it matches, else False.
 424 |         """
 425 |         # Requirement may contain extras - parse to lose those
 426 |         # from what's passed to the matcher
 427 |         r = parse_requirement(req)
 428 |         scheme = get_scheme(self.metadata.scheme)
 429 |         try:
 430 |             matcher = scheme.matcher(r.requirement)
 431 |         except UnsupportedVersionError:
 432 |             # XXX compat-mode if cannot read the version
 433 |             logger.warning('could not read version %r - using name only', req)
 434 |             name = req.split()[0]
 435 |             matcher = scheme.matcher(name)
 436 | 
 437 |         name = matcher.key  # case-insensitive
 438 | 
 439 |         result = False
 440 |         for p in self.provides:
 441 |             p_name, p_ver = parse_name_and_version(p)
 442 |             if p_name != name:
 443 |                 continue
 444 |             try:
 445 |                 result = matcher.match(p_ver)
 446 |                 break
 447 |             except UnsupportedVersionError:
 448 |                 pass
 449 |         return result
 450 | 
 451 |     def __repr__(self):
 452 |         """
 453 |         Return a textual representation of this instance,
 454 |         """
 455 |         if self.source_url:
 456 |             suffix = ' [%s]' % self.source_url
 457 |         else:
 458 |             suffix = ''
 459 |         return '<Distribution %s (%s)%s>' % (self.name, self.version, suffix)
 460 | 
 461 |     def __eq__(self, other):
 462 |         """
 463 |         See if this distribution is the same as another.
 464 |         :param other: The distribution to compare with. To be equal to one
 465 |                       another. distributions must have the same type, name,
 466 |                       version and source_url.
 467 |         :return: True if it is the same, else False.
 468 |         """
 469 |         if type(other) is not type(self):
 470 |             result = False
 471 |         else:
 472 |             result = (self.name == other.name and self.version == other.version
 473 |                       and self.source_url == other.source_url)
 474 |         return result
 475 | 
 476 |     def __hash__(self):
 477 |         """
 478 |         Compute hash in a way which matches the equality test.
 479 |         """
 480 |         return hash(self.name) + hash(self.version) + hash(self.source_url)
 481 | 
 482 | 
 483 | class BaseInstalledDistribution(Distribution):
 484 |     """
 485 |     This is the base class for installed distributions (whether PEP 376 or
 486 |     legacy).
 487 |     """
 488 | 
 489 |     hasher = None
 490 | 
 491 |     def __init__(self, metadata, path, env=None):
 492 |         """
 493 |         Initialise an instance.
 494 |         :param metadata: An instance of :class:`Metadata` which describes the
 495 |                          distribution. This will normally have been initialised
 496 |                          from a metadata file in the ``path``.
 497 |         :param path:     The path of the ``.dist-info`` or ``.egg-info``
 498 |                          directory for the distribution.
 499 |         :param env:      This is normally the :class:`DistributionPath`
 500 |                          instance where this distribution was found.
 501 |         """
 502 |         super(BaseInstalledDistribution, self).__init__(metadata)
 503 |         self.path = path
 504 |         self.dist_path = env
 505 | 
 506 |     def get_hash(self, data, hasher=None):
 507 |         """
 508 |         Get the hash of some data, using a particular hash algorithm, if
 509 |         specified.
 510 | 
 511 |         :param data: The data to be hashed.
 512 |         :type data: bytes
 513 |         :param hasher: The name of a hash implementation, supported by hashlib,
 514 |                        or ``None``. Examples of valid values are ``'sha1'``,
 515 |                        ``'sha224'``, ``'sha384'``, '``sha256'``, ``'md5'`` and
 516 |                        ``'sha512'``. If no hasher is specified, the ``hasher``
 517 |                        attribute of the :class:`InstalledDistribution` instance
 518 |                        is used. If the hasher is determined to be ``None``, MD5
 519 |                        is used as the hashing algorithm.
 520 |         :returns: The hash of the data. If a hasher was explicitly specified,
 521 |                   the returned hash will be prefixed with the specified hasher
 522 |                   followed by '='.
 523 |         :rtype: str
 524 |         """
 525 |         if hasher is None:
 526 |             hasher = self.hasher
 527 |         if hasher is None:
 528 |             hasher = hashlib.md5
 529 |             prefix = ''
 530 |         else:
 531 |             hasher = getattr(hashlib, hasher)
 532 |             prefix = '%s=' % self.hasher
 533 |         digest = hasher(data).digest()
 534 |         digest = base64.urlsafe_b64encode(digest).rstrip(b'=').decode('ascii')
 535 |         return '%s%s' % (prefix, digest)
 536 | 
 537 | 
 538 | class InstalledDistribution(BaseInstalledDistribution):
 539 |     """
 540 |     Created with the *path* of the ``.dist-info`` directory provided to the
 541 |     constructor. It reads the metadata contained in ``pydist.json`` when it is
 542 |     instantiated., or uses a passed in Metadata instance (useful for when
 543 |     dry-run mode is being used).
 544 |     """
 545 | 
 546 |     hasher = 'sha256'
 547 | 
 548 |     def __init__(self, path, metadata=None, env=None):
 549 |         self.modules = []
 550 |         self.finder = finder = resources.finder_for_path(path)
 551 |         if finder is None:
 552 |             raise ValueError('finder unavailable for %s' % path)
 553 |         if env and env._cache_enabled and path in env._cache.path:
 554 |             metadata = env._cache.path[path].metadata
 555 |         elif metadata is None:
 556 |             r = finder.find(METADATA_FILENAME)
 557 |             # Temporary - for Wheel 0.23 support
 558 |             if r is None:
 559 |                 r = finder.find(WHEEL_METADATA_FILENAME)
 560 |             # Temporary - for legacy support
 561 |             if r is None:
 562 |                 r = finder.find(LEGACY_METADATA_FILENAME)
 563 |             if r is None:
 564 |                 raise ValueError('no %s found in %s' %
 565 |                                  (METADATA_FILENAME, path))
 566 |             with contextlib.closing(r.as_stream()) as stream:
 567 |                 metadata = Metadata(fileobj=stream, scheme='legacy')
 568 | 
 569 |         super(InstalledDistribution, self).__init__(metadata, path, env)
 570 | 
 571 |         if env and env._cache_enabled:
 572 |             env._cache.add(self)
 573 | 
 574 |         r = finder.find('REQUESTED')
 575 |         self.requested = r is not None
 576 |         p = os.path.join(path, 'top_level.txt')
 577 |         if os.path.exists(p):
 578 |             with open(p, 'rb') as f:
 579 |                 data = f.read().decode('utf-8')
 580 |             self.modules = data.splitlines()
 581 | 
 582 |     def __repr__(self):
 583 |         return '<InstalledDistribution %r %s at %r>' % (
 584 |             self.name, self.version, self.path)
 585 | 
 586 |     def __str__(self):
 587 |         return "%s %s" % (self.name, self.version)
 588 | 
 589 |     def _get_records(self):
 590 |         """
 591 |         Get the list of installed files for the distribution
 592 |         :return: A list of tuples of path, hash and size. Note that hash and
 593 |                  size might be ``None`` for some entries. The path is exactly
 594 |                  as stored in the file (which is as in PEP 376).
 595 |         """
 596 |         results = []
 597 |         r = self.get_distinfo_resource('RECORD')
 598 |         with contextlib.closing(r.as_stream()) as stream:
 599 |             with CSVReader(stream=stream) as record_reader:
 600 |                 # Base location is parent dir of .dist-info dir
 601 |                 # base_location = os.path.dirname(self.path)
 602 |                 # base_location = os.path.abspath(base_location)
 603 |                 for row in record_reader:
 604 |                     missing = [None for i in range(len(row), 3)]
 605 |                     path, checksum, size = row + missing
 606 |                     # if not os.path.isabs(path):
 607 |                     #     path = path.replace('/', os.sep)
 608 |                     #     path = os.path.join(base_location, path)
 609 |                     results.append((path, checksum, size))
 610 |         return results
 611 | 
 612 |     @cached_property
 613 |     def exports(self):
 614 |         """
 615 |         Return the information exported by this distribution.
 616 |         :return: A dictionary of exports, mapping an export category to a dict
 617 |                  of :class:`ExportEntry` instances describing the individual
 618 |                  export entries, and keyed by name.
 619 |         """
 620 |         result = {}
 621 |         r = self.get_distinfo_resource(EXPORTS_FILENAME)
 622 |         if r:
 623 |             result = self.read_exports()
 624 |         return result
 625 | 
 626 |     def read_exports(self):
 627 |         """
 628 |         Read exports data from a file in .ini format.
 629 | 
 630 |         :return: A dictionary of exports, mapping an export category to a list
 631 |                  of :class:`ExportEntry` instances describing the individual
 632 |                  export entries.
 633 |         """
 634 |         result = {}
 635 |         r = self.get_distinfo_resource(EXPORTS_FILENAME)
 636 |         if r:
 637 |             with contextlib.closing(r.as_stream()) as stream:
 638 |                 result = read_exports(stream)
 639 |         return result
 640 | 
 641 |     def write_exports(self, exports):
 642 |         """
 643 |         Write a dictionary of exports to a file in .ini format.
 644 |         :param exports: A dictionary of exports, mapping an export category to
 645 |                         a list of :class:`ExportEntry` instances describing the
 646 |                         individual export entries.
 647 |         """
 648 |         rf = self.get_distinfo_file(EXPORTS_FILENAME)
 649 |         with open(rf, 'w') as f:
 650 |             write_exports(exports, f)
 651 | 
 652 |     def get_resource_path(self, relative_path):
 653 |         """
 654 |         NOTE: This API may change in the future.
 655 | 
 656 |         Return the absolute path to a resource file with the given relative
 657 |         path.
 658 | 
 659 |         :param relative_path: The path, relative to .dist-info, of the resource
 660 |                               of interest.
 661 |         :return: The absolute path where the resource is to be found.
 662 |         """
 663 |         r = self.get_distinfo_resource('RESOURCES')
 664 |         with contextlib.closing(r.as_stream()) as stream:
 665 |             with CSVReader(stream=stream) as resources_reader:
 666 |                 for relative, destination in resources_reader:
 667 |                     if relative == relative_path:
 668 |                         return destination
 669 |         raise KeyError('no resource file with relative path %r '
 670 |                        'is installed' % relative_path)
 671 | 
 672 |     def list_installed_files(self):
 673 |         """
 674 |         Iterates over the ``RECORD`` entries and returns a tuple
 675 |         ``(path, hash, size)`` for each line.
 676 | 
 677 |         :returns: iterator of (path, hash, size)
 678 |         """
 679 |         for result in self._get_records():
 680 |             yield result
 681 | 
 682 |     def write_installed_files(self, paths, prefix, dry_run=False):
 683 |         """
 684 |         Writes the ``RECORD`` file, using the ``paths`` iterable passed in. Any
 685 |         existing ``RECORD`` file is silently overwritten.
 686 | 
 687 |         prefix is used to determine when to write absolute paths.
 688 |         """
 689 |         prefix = os.path.join(prefix, '')
 690 |         base = os.path.dirname(self.path)
 691 |         base_under_prefix = base.startswith(prefix)
 692 |         base = os.path.join(base, '')
 693 |         record_path = self.get_distinfo_file('RECORD')
 694 |         logger.info('creating %s', record_path)
 695 |         if dry_run:
 696 |             return None
 697 |         with CSVWriter(record_path) as writer:
 698 |             for path in paths:
 699 |                 if os.path.isdir(path) or path.endswith(('.pyc', '.pyo')):
 700 |                     # do not put size and hash, as in PEP-376
 701 |                     hash_value = size = ''
 702 |                 else:
 703 |                     size = '%d' % os.path.getsize(path)
 704 |                     with open(path, 'rb') as fp:
 705 |                         hash_value = self.get_hash(fp.read())
 706 |                 if path.startswith(base) or (base_under_prefix
 707 |                                              and path.startswith(prefix)):
 708 |                     path = os.path.relpath(path, base)
 709 |                 writer.writerow((path, hash_value, size))
 710 | 
 711 |             # add the RECORD file itself
 712 |             if record_path.startswith(base):
 713 |                 record_path = os.path.relpath(record_path, base)
 714 |             writer.writerow((record_path, '', ''))
 715 |         return record_path
 716 | 
 717 |     def check_installed_files(self):
 718 |         """
 719 |         Checks that the hashes and sizes of the files in ``RECORD`` are
 720 |         matched by the files themselves. Returns a (possibly empty) list of
 721 |         mismatches. Each entry in the mismatch list will be a tuple consisting
 722 |         of the path, 'exists', 'size' or 'hash' according to what didn't match
 723 |         (existence is checked first, then size, then hash), the expected
 724 |         value and the actual value.
 725 |         """
 726 |         mismatches = []
 727 |         base = os.path.dirname(self.path)
 728 |         record_path = self.get_distinfo_file('RECORD')
 729 |         for path, hash_value, size in self.list_installed_files():
 730 |             if not os.path.isabs(path):
 731 |                 path = os.path.join(base, path)
 732 |             if path == record_path:
 733 |                 continue
 734 |             if not os.path.exists(path):
 735 |                 mismatches.append((path, 'exists', True, False))
 736 |             elif os.path.isfile(path):
 737 |                 actual_size = str(os.path.getsize(path))
 738 |                 if size and actual_size != size:
 739 |                     mismatches.append((path, 'size', size, actual_size))
 740 |                 elif hash_value:
 741 |                     if '=' in hash_value:
 742 |                         hasher = hash_value.split('=', 1)[0]
 743 |                     else:
 744 |                         hasher = None
 745 | 
 746 |                     with open(path, 'rb') as f:
 747 |                         actual_hash = self.get_hash(f.read(), hasher)
 748 |                         if actual_hash != hash_value:
 749 |                             mismatches.append(
 750 |                                 (path, 'hash', hash_value, actual_hash))
 751 |         return mismatches
 752 | 
 753 |     @cached_property
 754 |     def shared_locations(self):
 755 |         """
 756 |         A dictionary of shared locations whose keys are in the set 'prefix',
 757 |         'purelib', 'platlib', 'scripts', 'headers', 'data' and 'namespace'.
 758 |         The corresponding value is the absolute path of that category for
 759 |         this distribution, and takes into account any paths selected by the
 760 |         user at installation time (e.g. via command-line arguments). In the
 761 |         case of the 'namespace' key, this would be a list of absolute paths
 762 |         for the roots of namespace packages in this distribution.
 763 | 
 764 |         The first time this property is accessed, the relevant information is
 765 |         read from the SHARED file in the .dist-info directory.
 766 |         """
 767 |         result = {}
 768 |         shared_path = os.path.join(self.path, 'SHARED')
 769 |         if os.path.isfile(shared_path):
 770 |             with codecs.open(shared_path, 'r', encoding='utf-8') as f:
 771 |                 lines = f.read().splitlines()
 772 |             for line in lines:
 773 |                 key, value = line.split('=', 1)
 774 |                 if key == 'namespace':
 775 |                     result.setdefault(key, []).append(value)
 776 |                 else:
 777 |                     result[key] = value
 778 |         return result
 779 | 
 780 |     def write_shared_locations(self, paths, dry_run=False):
 781 |         """
 782 |         Write shared location information to the SHARED file in .dist-info.
 783 |         :param paths: A dictionary as described in the documentation for
 784 |         :meth:`shared_locations`.
 785 |         :param dry_run: If True, the action is logged but no file is actually
 786 |                         written.
 787 |         :return: The path of the file written to.
 788 |         """
 789 |         shared_path = os.path.join(self.path, 'SHARED')
 790 |         logger.info('creating %s', shared_path)
 791 |         if dry_run:
 792 |             return None
 793 |         lines = []
 794 |         for key in ('prefix', 'lib', 'headers', 'scripts', 'data'):
 795 |             path = paths[key]
 796 |             if os.path.isdir(paths[key]):
 797 |                 lines.append('%s=%s' % (key, path))
 798 |         for ns in paths.get('namespace', ()):
 799 |             lines.append('namespace=%s' % ns)
 800 | 
 801 |         with codecs.open(shared_path, 'w', encoding='utf-8') as f:
 802 |             f.write('\n'.join(lines))
 803 |         return shared_path
 804 | 
 805 |     def get_distinfo_resource(self, path):
 806 |         if path not in DIST_FILES:
 807 |             raise DistlibException('invalid path for a dist-info file: '
 808 |                                    '%r at %r' % (path, self.path))
 809 |         finder = resources.finder_for_path(self.path)
 810 |         if finder is None:
 811 |             raise DistlibException('Unable to get a finder for %s' % self.path)
 812 |         return finder.find(path)
 813 | 
 814 |     def get_distinfo_file(self, path):
 815 |         """
 816 |         Returns a path located under the ``.dist-info`` directory. Returns a
 817 |         string representing the path.
 818 | 
 819 |         :parameter path: a ``'/'``-separated path relative to the
 820 |                          ``.dist-info`` directory or an absolute path;
 821 |                          If *path* is an absolute path and doesn't start
 822 |                          with the ``.dist-info`` directory path,
 823 |                          a :class:`DistlibException` is raised
 824 |         :type path: str
 825 |         :rtype: str
 826 |         """
 827 |         # Check if it is an absolute path  # XXX use relpath, add tests
 828 |         if path.find(os.sep) >= 0:
 829 |             # it's an absolute path?
 830 |             distinfo_dirname, path = path.split(os.sep)[-2:]
 831 |             if distinfo_dirname != self.path.split(os.sep)[-1]:
 832 |                 raise DistlibException(
 833 |                     'dist-info file %r does not belong to the %r %s '
 834 |                     'distribution' % (path, self.name, self.version))
 835 | 
 836 |         # The file must be relative
 837 |         if path not in DIST_FILES:
 838 |             raise DistlibException('invalid path for a dist-info file: '
 839 |                                    '%r at %r' % (path, self.path))
 840 | 
 841 |         return os.path.join(self.path, path)
 842 | 
 843 |     def list_distinfo_files(self):
 844 |         """
 845 |         Iterates over the ``RECORD`` entries and returns paths for each line if
 846 |         the path is pointing to a file located in the ``.dist-info`` directory
 847 |         or one of its subdirectories.
 848 | 
 849 |         :returns: iterator of paths
 850 |         """
 851 |         base = os.path.dirname(self.path)
 852 |         for path, checksum, size in self._get_records():
 853 |             # XXX add separator or use real relpath algo
 854 |             if not os.path.isabs(path):
 855 |                 path = os.path.join(base, path)
 856 |             if path.startswith(self.path):
 857 |                 yield path
 858 | 
 859 |     def __eq__(self, other):
 860 |         return (isinstance(other, InstalledDistribution)
 861 |                 and self.path == other.path)
 862 | 
 863 |     # See http://docs.python.org/reference/datamodel#object.__hash__
 864 |     __hash__ = object.__hash__
 865 | 
 866 | 
 867 | class EggInfoDistribution(BaseInstalledDistribution):
 868 |     """Created with the *path* of the ``.egg-info`` directory or file provided
 869 |     to the constructor. It reads the metadata contained in the file itself, or
 870 |     if the given path happens to be a directory, the metadata is read from the
 871 |     file ``PKG-INFO`` under that directory."""
 872 | 
 873 |     requested = True  # as we have no way of knowing, assume it was
 874 |     shared_locations = {}
 875 | 
 876 |     def __init__(self, path, env=None):
 877 | 
 878 |         def set_name_and_version(s, n, v):
 879 |             s.name = n
 880 |             s.key = n.lower()  # for case-insensitive comparisons
 881 |             s.version = v
 882 | 
 883 |         self.path = path
 884 |         self.dist_path = env
 885 |         if env and env._cache_enabled and path in env._cache_egg.path:
 886 |             metadata = env._cache_egg.path[path].metadata
 887 |             set_name_and_version(self, metadata.name, metadata.version)
 888 |         else:
 889 |             metadata = self._get_metadata(path)
 890 | 
 891 |             # Need to be set before caching
 892 |             set_name_and_version(self, metadata.name, metadata.version)
 893 | 
 894 |             if env and env._cache_enabled:
 895 |                 env._cache_egg.add(self)
 896 |         super(EggInfoDistribution, self).__init__(metadata, path, env)
 897 | 
 898 |     def _get_metadata(self, path):
 899 |         requires = None
 900 | 
 901 |         def parse_requires_data(data):
 902 |             """Create a list of dependencies from a requires.txt file.
 903 | 
 904 |             *data*: the contents of a setuptools-produced requires.txt file.
 905 |             """
 906 |             reqs = []
 907 |             lines = data.splitlines()
 908 |             for line in lines:
 909 |                 line = line.strip()
 910 |                 # sectioned files have bare newlines (separating sections)
 911 |                 if not line:  # pragma: no cover
 912 |                     continue
 913 |                 if line.startswith('['):  # pragma: no cover
 914 |                     logger.warning(
 915 |                         'Unexpected line: quitting requirement scan: %r', line)
 916 |                     break
 917 |                 r = parse_requirement(line)
 918 |                 if not r:  # pragma: no cover
 919 |                     logger.warning('Not recognised as a requirement: %r', line)
 920 |                     continue
 921 |                 if r.extras:  # pragma: no cover
 922 |                     logger.warning('extra requirements in requires.txt are '
 923 |                                    'not supported')
 924 |                 if not r.constraints:
 925 |                     reqs.append(r.name)
 926 |                 else:
 927 |                     cons = ', '.join('%s%s' % c for c in r.constraints)
 928 |                     reqs.append('%s (%s)' % (r.name, cons))
 929 |             return reqs
 930 | 
 931 |         def parse_requires_path(req_path):
 932 |             """Create a list of dependencies from a requires.txt file.
 933 | 
 934 |             *req_path*: the path to a setuptools-produced requires.txt file.
 935 |             """
 936 | 
 937 |             reqs = []
 938 |             try:
 939 |                 with codecs.open(req_path, 'r', 'utf-8') as fp:
 940 |                     reqs = parse_requires_data(fp.read())
 941 |             except IOError:
 942 |                 pass
 943 |             return reqs
 944 | 
 945 |         tl_path = tl_data = None
 946 |         if path.endswith('.egg'):
 947 |             if os.path.isdir(path):
 948 |                 p = os.path.join(path, 'EGG-INFO')
 949 |                 meta_path = os.path.join(p, 'PKG-INFO')
 950 |                 metadata = Metadata(path=meta_path, scheme='legacy')
 951 |                 req_path = os.path.join(p, 'requires.txt')
 952 |                 tl_path = os.path.join(p, 'top_level.txt')
 953 |                 requires = parse_requires_path(req_path)
 954 |             else:
 955 |                 # FIXME handle the case where zipfile is not available
 956 |                 zipf = zipimport.zipimporter(path)
 957 |                 fileobj = StringIO(
 958 |                     zipf.get_data('EGG-INFO/PKG-INFO').decode('utf8'))
 959 |                 metadata = Metadata(fileobj=fileobj, scheme='legacy')
 960 |                 try:
 961 |                     data = zipf.get_data('EGG-INFO/requires.txt')
 962 |                     tl_data = zipf.get_data('EGG-INFO/top_level.txt').decode(
 963 |                         'utf-8')
 964 |                     requires = parse_requires_data(data.decode('utf-8'))
 965 |                 except IOError:
 966 |                     requires = None
 967 |         elif path.endswith('.egg-info'):
 968 |             if os.path.isdir(path):
 969 |                 req_path = os.path.join(path, 'requires.txt')
 970 |                 requires = parse_requires_path(req_path)
 971 |                 path = os.path.join(path, 'PKG-INFO')
 972 |                 tl_path = os.path.join(path, 'top_level.txt')
 973 |             metadata = Metadata(path=path, scheme='legacy')
 974 |         else:
 975 |             raise DistlibException('path must end with .egg-info or .egg, '
 976 |                                    'got %r' % path)
 977 | 
 978 |         if requires:
 979 |             metadata.add_requirements(requires)
 980 |         # look for top-level modules in top_level.txt, if present
 981 |         if tl_data is None:
 982 |             if tl_path is not None and os.path.exists(tl_path):
 983 |                 with open(tl_path, 'rb') as f:
 984 |                     tl_data = f.read().decode('utf-8')
 985 |         if not tl_data:
 986 |             tl_data = []
 987 |         else:
 988 |             tl_data = tl_data.splitlines()
 989 |         self.modules = tl_data
 990 |         return metadata
 991 | 
 992 |     def __repr__(self):
 993 |         return '<EggInfoDistribution %r %s at %r>' % (self.name, self.version,
 994 |                                                       self.path)
 995 | 
 996 |     def __str__(self):
 997 |         return "%s %s" % (self.name, self.version)
 998 | 
 999 |     def check_installed_files(self):
1000 |         """
1001 |         Checks that the hashes and sizes of the files in ``RECORD`` are
1002 |         matched by the files themselves. Returns a (possibly empty) list of
1003 |         mismatches. Each entry in the mismatch list will be a tuple consisting
1004 |         of the path, 'exists', 'size' or 'hash' according to what didn't match
1005 |         (existence is checked first, then size, then hash), the expected
1006 |         value and the actual value.
1007 |         """
1008 |         mismatches = []
1009 |         record_path = os.path.join(self.path, 'installed-files.txt')
1010 |         if os.path.exists(record_path):
1011 |             for path, _, _ in self.list_installed_files():
1012 |                 if path == record_path:
1013 |                     continue
1014 |                 if not os.path.exists(path):
1015 |                     mismatches.append((path, 'exists', True, False))
1016 |         return mismatches
1017 | 
1018 |     def list_installed_files(self):
1019 |         """
1020 |         Iterates over the ``installed-files.txt`` entries and returns a tuple
1021 |         ``(path, hash, size)`` for each line.
1022 | 
1023 |         :returns: a list of (path, hash, size)
1024 |         """
1025 | 
1026 |         def _md5(path):
1027 |             f = open(path, 'rb')
1028 |             try:
1029 |                 content = f.read()
1030 |             finally:
1031 |                 f.close()
1032 |             return hashlib.md5(content).hexdigest()
1033 | 
1034 |         def _size(path):
1035 |             return os.stat(path).st_size
1036 | 
1037 |         record_path = os.path.join(self.path, 'installed-files.txt')
1038 |         result = []
1039 |         if os.path.exists(record_path):
1040 |             with codecs.open(record_path, 'r', encoding='utf-8') as f:
1041 |                 for line in f:
1042 |                     line = line.strip()
1043 |                     p = os.path.normpath(os.path.join(self.path, line))
1044 |                     # "./" is present as a marker between installed files
1045 |                     # and installation metadata files
1046 |                     if not os.path.exists(p):
1047 |                         logger.warning('Non-existent file: %s', p)
1048 |                         if p.endswith(('.pyc', '.pyo')):
1049 |                             continue
1050 |                         # otherwise fall through and fail
1051 |                     if not os.path.isdir(p):
1052 |                         result.append((p, _md5(p), _size(p)))
1053 |             result.append((record_path, None, None))
1054 |         return result
1055 | 
1056 |     def list_distinfo_files(self, absolute=False):
1057 |         """
1058 |         Iterates over the ``installed-files.txt`` entries and returns paths for
1059 |         each line if the path is pointing to a file located in the
1060 |         ``.egg-info`` directory or one of its subdirectories.
1061 | 
1062 |         :parameter absolute: If *absolute* is ``True``, each returned path is
1063 |                           transformed into a local absolute path. Otherwise the
1064 |                           raw value from ``installed-files.txt`` is returned.
1065 |         :type absolute: boolean
1066 |         :returns: iterator of paths
1067 |         """
1068 |         record_path = os.path.join(self.path, 'installed-files.txt')
1069 |         if os.path.exists(record_path):
1070 |             skip = True
1071 |             with codecs.open(record_path, 'r', encoding='utf-8') as f:
1072 |                 for line in f:
1073 |                     line = line.strip()
1074 |                     if line == './':
1075 |                         skip = False
1076 |                         continue
1077 |                     if not skip:
1078 |                         p = os.path.normpath(os.path.join(self.path, line))
1079 |                         if p.startswith(self.path):
1080 |                             if absolute:
1081 |                                 yield p
1082 |                             else:
1083 |                                 yield line
1084 | 
1085 |     def __eq__(self, other):
1086 |         return (isinstance(other, EggInfoDistribution)
1087 |                 and self.path == other.path)
1088 | 
1089 |     # See http://docs.python.org/reference/datamodel#object.__hash__
1090 |     __hash__ = object.__hash__
1091 | 
1092 | 
1093 | new_dist_class = InstalledDistribution
1094 | old_dist_class = EggInfoDistribution
1095 | 
1096 | 
1097 | class DependencyGraph(object):
1098 |     """
1099 |     Represents a dependency graph between distributions.
1100 | 
1101 |     The dependency relationships are stored in an ``adjacency_list`` that maps
1102 |     distributions to a list of ``(other, label)`` tuples where  ``other``
1103 |     is a distribution and the edge is labeled with ``label`` (i.e. the version
1104 |     specifier, if such was provided). Also, for more efficient traversal, for
1105 |     every distribution ``x``, a list of predecessors is kept in
1106 |     ``reverse_list[x]``. An edge from distribution ``a`` to
1107 |     distribution ``b`` means that ``a`` depends on ``b``. If any missing
1108 |     dependencies are found, they are stored in ``missing``, which is a
1109 |     dictionary that maps distributions to a list of requirements that were not
1110 |     provided by any other distributions.
1111 |     """
1112 | 
1113 |     def __init__(self):
1114 |         self.adjacency_list = {}
1115 |         self.reverse_list = {}
1116 |         self.missing = {}
1117 | 
1118 |     def add_distribution(self, distribution):
1119 |         """Add the *distribution* to the graph.
1120 | 
1121 |         :type distribution: :class:`distutils2.database.InstalledDistribution`
1122 |                             or :class:`distutils2.database.EggInfoDistribution`
1123 |         """
1124 |         self.adjacency_list[distribution] = []
1125 |         self.reverse_list[distribution] = []
1126 |         # self.missing[distribution] = []
1127 | 
1128 |     def add_edge(self, x, y, label=None):
1129 |         """Add an edge from distribution *x* to distribution *y* with the given
1130 |         *label*.
1131 | 
1132 |         :type x: :class:`distutils2.database.InstalledDistribution` or
1133 |                  :class:`distutils2.database.EggInfoDistribution`
1134 |         :type y: :class:`distutils2.database.InstalledDistribution` or
1135 |                  :class:`distutils2.database.EggInfoDistribution`
1136 |         :type label: ``str`` or ``None``
1137 |         """
1138 |         self.adjacency_list[x].append((y, label))
1139 |         # multiple edges are allowed, so be careful
1140 |         if x not in self.reverse_list[y]:
1141 |             self.reverse_list[y].append(x)
1142 | 
1143 |     def add_missing(self, distribution, requirement):
1144 |         """
1145 |         Add a missing *requirement* for the given *distribution*.
1146 | 
1147 |         :type distribution: :class:`distutils2.database.InstalledDistribution`
1148 |                             or :class:`distutils2.database.EggInfoDistribution`
1149 |         :type requirement: ``str``
1150 |         """
1151 |         logger.debug('%s missing %r', distribution, requirement)
1152 |         self.missing.setdefault(distribution, []).append(requirement)
1153 | 
1154 |     def _repr_dist(self, dist):
1155 |         return '%s %s' % (dist.name, dist.version)
1156 | 
1157 |     def repr_node(self, dist, level=1):
1158 |         """Prints only a subgraph"""
1159 |         output = [self._repr_dist(dist)]
1160 |         for other, label in self.adjacency_list[dist]:
1161 |             dist = self._repr_dist(other)
1162 |             if label is not None:
1163 |                 dist = '%s [%s]' % (dist, label)
1164 |             output.append('    ' * level + str(dist))
1165 |             suboutput = self.repr_node(other, level + 1)
1166 |             subs = suboutput.split('\n')
1167 |             output.extend(subs[1:])
1168 |         return '\n'.join(output)
1169 | 
1170 |     def to_dot(self, f, skip_disconnected=True):
1171 |         """Writes a DOT output for the graph to the provided file *f*.
1172 | 
1173 |         If *skip_disconnected* is set to ``True``, then all distributions
1174 |         that are not dependent on any other distribution are skipped.
1175 | 
1176 |         :type f: has to support ``file``-like operations
1177 |         :type skip_disconnected: ``bool``
1178 |         """
1179 |         disconnected = []
1180 | 
1181 |         f.write("digraph dependencies {\n")
1182 |         for dist, adjs in self.adjacency_list.items():
1183 |             if len(adjs) == 0 and not skip_disconnected:
1184 |                 disconnected.append(dist)
1185 |             for other, label in adjs:
1186 |                 if label is not None:
1187 |                     f.write('"%s" -> "%s" [label="%s"]\n' %
1188 |                             (dist.name, other.name, label))
1189 |                 else:
1190 |                     f.write('"%s" -> "%s"\n' % (dist.name, other.name))
1191 |         if not skip_disconnected and len(disconnected) > 0:
1192 |             f.write('subgraph disconnected {\n')
1193 |             f.write('label = "Disconnected"\n')
1194 |             f.write('bgcolor = red\n')
1195 | 
1196 |             for dist in disconnected:
1197 |                 f.write('"%s"' % dist.name)
1198 |                 f.write('\n')
1199 |             f.write('}\n')
1200 |         f.write('}\n')
1201 | 
1202 |     def topological_sort(self):
1203 |         """
1204 |         Perform a topological sort of the graph.
1205 |         :return: A tuple, the first element of which is a topologically sorted
1206 |                  list of distributions, and the second element of which is a
1207 |                  list of distributions that cannot be sorted because they have
1208 |                  circular dependencies and so form a cycle.
1209 |         """
1210 |         result = []
1211 |         # Make a shallow copy of the adjacency list
1212 |         alist = {}
1213 |         for k, v in self.adjacency_list.items():
1214 |             alist[k] = v[:]
1215 |         while True:
1216 |             # See what we can remove in this run
1217 |             to_remove = []
1218 |             for k, v in list(alist.items())[:]:
1219 |                 if not v:
1220 |                     to_remove.append(k)
1221 |                     del alist[k]
1222 |             if not to_remove:
1223 |                 # What's left in alist (if anything) is a cycle.
1224 |                 break
1225 |             # Remove from the adjacency list of others
1226 |             for k, v in alist.items():
1227 |                 alist[k] = [(d, r) for d, r in v if d not in to_remove]
1228 |             logger.debug('Moving to result: %s',
1229 |                          ['%s (%s)' % (d.name, d.version) for d in to_remove])
1230 |             result.extend(to_remove)
1231 |         return result, list(alist.keys())
1232 | 
1233 |     def __repr__(self):
1234 |         """Representation of the graph"""
1235 |         output = []
1236 |         for dist, adjs in self.adjacency_list.items():
1237 |             output.append(self.repr_node(dist))
1238 |         return '\n'.join(output)
1239 | 
1240 | 
1241 | def make_graph(dists, scheme='default'):
1242 |     """Makes a dependency graph from the given distributions.
1243 | 
1244 |     :parameter dists: a list of distributions
1245 |     :type dists: list of :class:`distutils2.database.InstalledDistribution` and
1246 |                  :class:`distutils2.database.EggInfoDistribution` instances
1247 |     :rtype: a :class:`DependencyGraph` instance
1248 |     """
1249 |     scheme = get_scheme(scheme)
1250 |     graph = DependencyGraph()
1251 |     provided = {}  # maps names to lists of (version, dist) tuples
1252 | 
1253 |     # first, build the graph and find out what's provided
1254 |     for dist in dists:
1255 |         graph.add_distribution(dist)
1256 | 
1257 |         for p in dist.provides:
1258 |             name, version = parse_name_and_version(p)
1259 |             logger.debug('Add to provided: %s, %s, %s', name, version, dist)
1260 |             provided.setdefault(name, []).append((version, dist))
1261 | 
1262 |     # now make the edges
1263 |     for dist in dists:
1264 |         requires = (dist.run_requires | dist.meta_requires
1265 |                     | dist.build_requires | dist.dev_requires)
1266 |         for req in requires:
1267 |             try:
1268 |                 matcher = scheme.matcher(req)
1269 |             except UnsupportedVersionError:
1270 |                 # XXX compat-mode if cannot read the version
1271 |                 logger.warning('could not read version %r - using name only',
1272 |                                req)
1273 |                 name = req.split()[0]
1274 |                 matcher = scheme.matcher(name)
1275 | 
1276 |             name = matcher.key  # case-insensitive
1277 | 
1278 |             matched = False
1279 |             if name in provided:
1280 |                 for version, provider in provided[name]:
1281 |                     try:
1282 |                         match = matcher.match(version)
1283 |                     except UnsupportedVersionError:
1284 |                         match = False
1285 | 
1286 |                     if match:
1287 |                         graph.add_edge(dist, provider, req)
1288 |                         matched = True
1289 |                         break
1290 |             if not matched:
1291 |                 graph.add_missing(dist, req)
1292 |     return graph
1293 | 
1294 | 
1295 | def get_dependent_dists(dists, dist):
1296 |     """Recursively generate a list of distributions from *dists* that are
1297 |     dependent on *dist*.
1298 | 
1299 |     :param dists: a list of distributions
1300 |     :param dist: a distribution, member of *dists* for which we are interested
1301 |     """
1302 |     if dist not in dists:
1303 |         raise DistlibException('given distribution %r is not a member '
1304 |                                'of the list' % dist.name)
1305 |     graph = make_graph(dists)
1306 | 
1307 |     dep = [dist]  # dependent distributions
1308 |     todo = graph.reverse_list[dist]  # list of nodes we should inspect
1309 | 
1310 |     while todo:
1311 |         d = todo.pop()
1312 |         dep.append(d)
1313 |         for succ in graph.reverse_list[d]:
1314 |             if succ not in dep:
1315 |                 todo.append(succ)
1316 | 
1317 |     dep.pop(0)  # remove dist from dep, was there to prevent infinite loops
1318 |     return dep
1319 | 
1320 | 
1321 | def get_required_dists(dists, dist):
1322 |     """Recursively generate a list of distributions from *dists* that are
1323 |     required by *dist*.
1324 | 
1325 |     :param dists: a list of distributions
1326 |     :param dist: a distribution, member of *dists* for which we are interested
1327 |                  in finding the dependencies.
1328 |     """
1329 |     if dist not in dists:
1330 |         raise DistlibException('given distribution %r is not a member '
1331 |                                'of the list' % dist.name)
1332 |     graph = make_graph(dists)
1333 | 
1334 |     req = set()  # required distributions
1335 |     todo = graph.adjacency_list[dist]  # list of nodes we should inspect
1336 |     seen = set(t[0] for t in todo)  # already added to todo
1337 | 
1338 |     while todo:
1339 |         d = todo.pop()[0]
1340 |         req.add(d)
1341 |         pred_list = graph.adjacency_list[d]
1342 |         for pred in pred_list:
1343 |             d = pred[0]
1344 |             if d not in req and d not in seen:
1345 |                 seen.add(d)
1346 |                 todo.append(pred)
1347 |     return req
1348 | 
1349 | 
1350 | def make_dist(name, version, **kwargs):
1351 |     """
1352 |     A convenience method for making a dist given just a name and version.
1353 |     """
1354 |     summary = kwargs.pop('summary', 'Placeholder for summary')
1355 |     md = Metadata(**kwargs)
1356 |     md.name = name
1357 |     md.version = version
1358 |     md.summary = summary or 'Placeholder for summary'
1359 |     return Distribution(md)
1360 | 
```
Page 145/168FirstPrevNextLast