This is page 84 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/werkzeug/utils.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import io
4 | import mimetypes
5 | import os
6 | import pkgutil
7 | import re
8 | import sys
9 | import typing as t
10 | import unicodedata
11 | from datetime import datetime
12 | from time import time
13 | from urllib.parse import quote
14 | from zlib import adler32
15 |
16 | from markupsafe import escape
17 |
18 | from ._internal import _DictAccessorProperty
19 | from ._internal import _missing
20 | from ._internal import _TAccessorValue
21 | from .datastructures import Headers
22 | from .exceptions import NotFound
23 | from .exceptions import RequestedRangeNotSatisfiable
24 | from .security import safe_join
25 | from .wsgi import wrap_file
26 |
27 | if t.TYPE_CHECKING:
28 | from _typeshed.wsgi import WSGIEnvironment
29 |
30 | from .wrappers.request import Request
31 | from .wrappers.response import Response
32 |
33 | _T = t.TypeVar("_T")
34 |
35 | _entity_re = re.compile(r"&([^;]+);")
36 | _filename_ascii_strip_re = re.compile(r"[^A-Za-z0-9_.-]")
37 | _windows_device_files = {
38 | "CON",
39 | "PRN",
40 | "AUX",
41 | "NUL",
42 | *(f"COM{i}" for i in range(10)),
43 | *(f"LPT{i}" for i in range(10)),
44 | }
45 |
46 |
47 | class cached_property(property, t.Generic[_T]):
48 | """A :func:`property` that is only evaluated once. Subsequent access
49 | returns the cached value. Setting the property sets the cached
50 | value. Deleting the property clears the cached value, accessing it
51 | again will evaluate it again.
52 |
53 | .. code-block:: python
54 |
55 | class Example:
56 | @cached_property
57 | def value(self):
58 | # calculate something important here
59 | return 42
60 |
61 | e = Example()
62 | e.value # evaluates
63 | e.value # uses cache
64 | e.value = 16 # sets cache
65 | del e.value # clears cache
66 |
67 | If the class defines ``__slots__``, it must add ``_cache_{name}`` as
68 | a slot. Alternatively, it can add ``__dict__``, but that's usually
69 | not desirable.
70 |
71 | .. versionchanged:: 2.1
72 | Works with ``__slots__``.
73 |
74 | .. versionchanged:: 2.0
75 | ``del obj.name`` clears the cached value.
76 | """
77 |
78 | def __init__(
79 | self,
80 | fget: t.Callable[[t.Any], _T],
81 | name: str | None = None,
82 | doc: str | None = None,
83 | ) -> None:
84 | super().__init__(fget, doc=doc)
85 | self.__name__ = name or fget.__name__
86 | self.slot_name = f"_cache_{self.__name__}"
87 | self.__module__ = fget.__module__
88 |
89 | def __set__(self, obj: object, value: _T) -> None:
90 | if hasattr(obj, "__dict__"):
91 | obj.__dict__[self.__name__] = value
92 | else:
93 | setattr(obj, self.slot_name, value)
94 |
95 | def __get__(self, obj: object, type: type = None) -> _T: # type: ignore
96 | if obj is None:
97 | return self # type: ignore
98 |
99 | obj_dict = getattr(obj, "__dict__", None)
100 |
101 | if obj_dict is not None:
102 | value: _T = obj_dict.get(self.__name__, _missing)
103 | else:
104 | value = getattr(obj, self.slot_name, _missing) # type: ignore[arg-type]
105 |
106 | if value is _missing:
107 | value = self.fget(obj) # type: ignore
108 |
109 | if obj_dict is not None:
110 | obj.__dict__[self.__name__] = value
111 | else:
112 | setattr(obj, self.slot_name, value)
113 |
114 | return value
115 |
116 | def __delete__(self, obj: object) -> None:
117 | if hasattr(obj, "__dict__"):
118 | del obj.__dict__[self.__name__]
119 | else:
120 | setattr(obj, self.slot_name, _missing)
121 |
122 |
123 | class environ_property(_DictAccessorProperty[_TAccessorValue]):
124 | """Maps request attributes to environment variables. This works not only
125 | for the Werkzeug request object, but also any other class with an
126 | environ attribute:
127 |
128 | >>> class Test(object):
129 | ... environ = {'key': 'value'}
130 | ... test = environ_property('key')
131 | >>> var = Test()
132 | >>> var.test
133 | 'value'
134 |
135 | If you pass it a second value it's used as default if the key does not
136 | exist, the third one can be a converter that takes a value and converts
137 | it. If it raises :exc:`ValueError` or :exc:`TypeError` the default value
138 | is used. If no default value is provided `None` is used.
139 |
140 | Per default the property is read only. You have to explicitly enable it
141 | by passing ``read_only=False`` to the constructor.
142 | """
143 |
144 | read_only = True
145 |
146 | def lookup(self, obj: Request) -> WSGIEnvironment:
147 | return obj.environ
148 |
149 |
150 | class header_property(_DictAccessorProperty[_TAccessorValue]):
151 | """Like `environ_property` but for headers."""
152 |
153 | def lookup(self, obj: Request | Response) -> Headers:
154 | return obj.headers
155 |
156 |
157 | # https://cgit.freedesktop.org/xdg/shared-mime-info/tree/freedesktop.org.xml.in
158 | # https://www.iana.org/assignments/media-types/media-types.xhtml
159 | # Types listed in the XDG mime info that have a charset in the IANA registration.
160 | _charset_mimetypes = {
161 | "application/ecmascript",
162 | "application/javascript",
163 | "application/sql",
164 | "application/xml",
165 | "application/xml-dtd",
166 | "application/xml-external-parsed-entity",
167 | }
168 |
169 |
170 | def get_content_type(mimetype: str, charset: str) -> str:
171 | """Returns the full content type string with charset for a mimetype.
172 |
173 | If the mimetype represents text, the charset parameter will be
174 | appended, otherwise the mimetype is returned unchanged.
175 |
176 | :param mimetype: The mimetype to be used as content type.
177 | :param charset: The charset to be appended for text mimetypes.
178 | :return: The content type.
179 |
180 | .. versionchanged:: 0.15
181 | Any type that ends with ``+xml`` gets a charset, not just those
182 | that start with ``application/``. Known text types such as
183 | ``application/javascript`` are also given charsets.
184 | """
185 | if (
186 | mimetype.startswith("text/")
187 | or mimetype in _charset_mimetypes
188 | or mimetype.endswith("+xml")
189 | ):
190 | mimetype += f"; charset={charset}"
191 |
192 | return mimetype
193 |
194 |
195 | def secure_filename(filename: str) -> str:
196 | r"""Pass it a filename and it will return a secure version of it. This
197 | filename can then safely be stored on a regular file system and passed
198 | to :func:`os.path.join`. The filename returned is an ASCII only string
199 | for maximum portability.
200 |
201 | On windows systems the function also makes sure that the file is not
202 | named after one of the special device files.
203 |
204 | >>> secure_filename("My cool movie.mov")
205 | 'My_cool_movie.mov'
206 | >>> secure_filename("../../../etc/passwd")
207 | 'etc_passwd'
208 | >>> secure_filename('i contain cool \xfcml\xe4uts.txt')
209 | 'i_contain_cool_umlauts.txt'
210 |
211 | The function might return an empty filename. It's your responsibility
212 | to ensure that the filename is unique and that you abort or
213 | generate a random filename if the function returned an empty one.
214 |
215 | .. versionadded:: 0.5
216 |
217 | :param filename: the filename to secure
218 | """
219 | filename = unicodedata.normalize("NFKD", filename)
220 | filename = filename.encode("ascii", "ignore").decode("ascii")
221 |
222 | for sep in os.sep, os.path.altsep:
223 | if sep:
224 | filename = filename.replace(sep, " ")
225 | filename = str(_filename_ascii_strip_re.sub("", "_".join(filename.split()))).strip(
226 | "._"
227 | )
228 |
229 | # on nt a couple of special files are present in each folder. We
230 | # have to ensure that the target file is not such a filename. In
231 | # this case we prepend an underline
232 | if (
233 | os.name == "nt"
234 | and filename
235 | and filename.split(".")[0].upper() in _windows_device_files
236 | ):
237 | filename = f"_{filename}"
238 |
239 | return filename
240 |
241 |
242 | def redirect(
243 | location: str, code: int = 302, Response: type[Response] | None = None
244 | ) -> Response:
245 | """Returns a response object (a WSGI application) that, if called,
246 | redirects the client to the target location. Supported codes are
247 | 301, 302, 303, 305, 307, and 308. 300 is not supported because
248 | it's not a real redirect and 304 because it's the answer for a
249 | request with a request with defined If-Modified-Since headers.
250 |
251 | .. versionadded:: 0.6
252 | The location can now be a unicode string that is encoded using
253 | the :func:`iri_to_uri` function.
254 |
255 | .. versionadded:: 0.10
256 | The class used for the Response object can now be passed in.
257 |
258 | :param location: the location the response should redirect to.
259 | :param code: the redirect status code. defaults to 302.
260 | :param class Response: a Response class to use when instantiating a
261 | response. The default is :class:`werkzeug.wrappers.Response` if
262 | unspecified.
263 | """
264 | if Response is None:
265 | from .wrappers import Response
266 |
267 | html_location = escape(location)
268 | response = Response( # type: ignore[misc]
269 | "<!doctype html>\n"
270 | "<html lang=en>\n"
271 | "<title>Redirecting...</title>\n"
272 | "<h1>Redirecting...</h1>\n"
273 | "<p>You should be redirected automatically to the target URL: "
274 | f'<a href="{html_location}">{html_location}</a>. If not, click the link.\n',
275 | code,
276 | mimetype="text/html",
277 | )
278 | response.headers["Location"] = location
279 | return response
280 |
281 |
282 | def append_slash_redirect(environ: WSGIEnvironment, code: int = 308) -> Response:
283 | """Redirect to the current URL with a slash appended.
284 |
285 | If the current URL is ``/user/42``, the redirect URL will be
286 | ``42/``. When joined to the current URL during response
287 | processing or by the browser, this will produce ``/user/42/``.
288 |
289 | The behavior is undefined if the path ends with a slash already. If
290 | called unconditionally on a URL, it may produce a redirect loop.
291 |
292 | :param environ: Use the path and query from this WSGI environment
293 | to produce the redirect URL.
294 | :param code: the status code for the redirect.
295 |
296 | .. versionchanged:: 2.1
297 | Produce a relative URL that only modifies the last segment.
298 | Relevant when the current path has multiple segments.
299 |
300 | .. versionchanged:: 2.1
301 | The default status code is 308 instead of 301. This preserves
302 | the request method and body.
303 | """
304 | tail = environ["PATH_INFO"].rpartition("/")[2]
305 |
306 | if not tail:
307 | new_path = "./"
308 | else:
309 | new_path = f"{tail}/"
310 |
311 | query_string = environ.get("QUERY_STRING")
312 |
313 | if query_string:
314 | new_path = f"{new_path}?{query_string}"
315 |
316 | return redirect(new_path, code)
317 |
318 |
319 | def send_file(
320 | path_or_file: os.PathLike[str] | str | t.IO[bytes],
321 | environ: WSGIEnvironment,
322 | mimetype: str | None = None,
323 | as_attachment: bool = False,
324 | download_name: str | None = None,
325 | conditional: bool = True,
326 | etag: bool | str = True,
327 | last_modified: datetime | int | float | None = None,
328 | max_age: None | (int | t.Callable[[str | None], int | None]) = None,
329 | use_x_sendfile: bool = False,
330 | response_class: type[Response] | None = None,
331 | _root_path: os.PathLike[str] | str | None = None,
332 | ) -> Response:
333 | """Send the contents of a file to the client.
334 |
335 | The first argument can be a file path or a file-like object. Paths
336 | are preferred in most cases because Werkzeug can manage the file and
337 | get extra information from the path. Passing a file-like object
338 | requires that the file is opened in binary mode, and is mostly
339 | useful when building a file in memory with :class:`io.BytesIO`.
340 |
341 | Never pass file paths provided by a user. The path is assumed to be
342 | trusted, so a user could craft a path to access a file you didn't
343 | intend. Use :func:`send_from_directory` to safely serve user-provided paths.
344 |
345 | If the WSGI server sets a ``file_wrapper`` in ``environ``, it is
346 | used, otherwise Werkzeug's built-in wrapper is used. Alternatively,
347 | if the HTTP server supports ``X-Sendfile``, ``use_x_sendfile=True``
348 | will tell the server to send the given path, which is much more
349 | efficient than reading it in Python.
350 |
351 | :param path_or_file: The path to the file to send, relative to the
352 | current working directory if a relative path is given.
353 | Alternatively, a file-like object opened in binary mode. Make
354 | sure the file pointer is seeked to the start of the data.
355 | :param environ: The WSGI environ for the current request.
356 | :param mimetype: The MIME type to send for the file. If not
357 | provided, it will try to detect it from the file name.
358 | :param as_attachment: Indicate to a browser that it should offer to
359 | save the file instead of displaying it.
360 | :param download_name: The default name browsers will use when saving
361 | the file. Defaults to the passed file name.
362 | :param conditional: Enable conditional and range responses based on
363 | request headers. Requires passing a file path and ``environ``.
364 | :param etag: Calculate an ETag for the file, which requires passing
365 | a file path. Can also be a string to use instead.
366 | :param last_modified: The last modified time to send for the file,
367 | in seconds. If not provided, it will try to detect it from the
368 | file path.
369 | :param max_age: How long the client should cache the file, in
370 | seconds. If set, ``Cache-Control`` will be ``public``, otherwise
371 | it will be ``no-cache`` to prefer conditional caching.
372 | :param use_x_sendfile: Set the ``X-Sendfile`` header to let the
373 | server to efficiently send the file. Requires support from the
374 | HTTP server. Requires passing a file path.
375 | :param response_class: Build the response using this class. Defaults
376 | to :class:`~werkzeug.wrappers.Response`.
377 | :param _root_path: Do not use. For internal use only. Use
378 | :func:`send_from_directory` to safely send files under a path.
379 |
380 | .. versionchanged:: 2.0.2
381 | ``send_file`` only sets a detected ``Content-Encoding`` if
382 | ``as_attachment`` is disabled.
383 |
384 | .. versionadded:: 2.0
385 | Adapted from Flask's implementation.
386 |
387 | .. versionchanged:: 2.0
388 | ``download_name`` replaces Flask's ``attachment_filename``
389 | parameter. If ``as_attachment=False``, it is passed with
390 | ``Content-Disposition: inline`` instead.
391 |
392 | .. versionchanged:: 2.0
393 | ``max_age`` replaces Flask's ``cache_timeout`` parameter.
394 | ``conditional`` is enabled and ``max_age`` is not set by
395 | default.
396 |
397 | .. versionchanged:: 2.0
398 | ``etag`` replaces Flask's ``add_etags`` parameter. It can be a
399 | string to use instead of generating one.
400 |
401 | .. versionchanged:: 2.0
402 | If an encoding is returned when guessing ``mimetype`` from
403 | ``download_name``, set the ``Content-Encoding`` header.
404 | """
405 | if response_class is None:
406 | from .wrappers import Response
407 |
408 | response_class = Response
409 |
410 | path: str | None = None
411 | file: t.IO[bytes] | None = None
412 | size: int | None = None
413 | mtime: float | None = None
414 | headers = Headers()
415 |
416 | if isinstance(path_or_file, (os.PathLike, str)) or hasattr(
417 | path_or_file, "__fspath__"
418 | ):
419 | path_or_file = t.cast("t.Union[os.PathLike[str], str]", path_or_file)
420 |
421 | # Flask will pass app.root_path, allowing its send_file wrapper
422 | # to not have to deal with paths.
423 | if _root_path is not None:
424 | path = os.path.join(_root_path, path_or_file)
425 | else:
426 | path = os.path.abspath(path_or_file)
427 |
428 | stat = os.stat(path)
429 | size = stat.st_size
430 | mtime = stat.st_mtime
431 | else:
432 | file = path_or_file
433 |
434 | if download_name is None and path is not None:
435 | download_name = os.path.basename(path)
436 |
437 | if mimetype is None:
438 | if download_name is None:
439 | raise TypeError(
440 | "Unable to detect the MIME type because a file name is"
441 | " not available. Either set 'download_name', pass a"
442 | " path instead of a file, or set 'mimetype'."
443 | )
444 |
445 | mimetype, encoding = mimetypes.guess_type(download_name)
446 |
447 | if mimetype is None:
448 | mimetype = "application/octet-stream"
449 |
450 | # Don't send encoding for attachments, it causes browsers to
451 | # save decompress tar.gz files.
452 | if encoding is not None and not as_attachment:
453 | headers.set("Content-Encoding", encoding)
454 |
455 | if download_name is not None:
456 | try:
457 | download_name.encode("ascii")
458 | except UnicodeEncodeError:
459 | simple = unicodedata.normalize("NFKD", download_name)
460 | simple = simple.encode("ascii", "ignore").decode("ascii")
461 | # safe = RFC 5987 attr-char
462 | quoted = quote(download_name, safe="!#$&+-.^_`|~")
463 | names = {"filename": simple, "filename*": f"UTF-8''{quoted}"}
464 | else:
465 | names = {"filename": download_name}
466 |
467 | value = "attachment" if as_attachment else "inline"
468 | headers.set("Content-Disposition", value, **names)
469 | elif as_attachment:
470 | raise TypeError(
471 | "No name provided for attachment. Either set"
472 | " 'download_name' or pass a path instead of a file."
473 | )
474 |
475 | if use_x_sendfile and path is not None:
476 | headers["X-Sendfile"] = path
477 | data = None
478 | else:
479 | if file is None:
480 | file = open(path, "rb") # type: ignore
481 | elif isinstance(file, io.BytesIO):
482 | size = file.getbuffer().nbytes
483 | elif isinstance(file, io.TextIOBase):
484 | raise ValueError("Files must be opened in binary mode or use BytesIO.")
485 |
486 | data = wrap_file(environ, file)
487 |
488 | rv = response_class(
489 | data, mimetype=mimetype, headers=headers, direct_passthrough=True
490 | )
491 |
492 | if size is not None:
493 | rv.content_length = size
494 |
495 | if last_modified is not None:
496 | rv.last_modified = last_modified # type: ignore
497 | elif mtime is not None:
498 | rv.last_modified = mtime # type: ignore
499 |
500 | rv.cache_control.no_cache = True
501 |
502 | # Flask will pass app.get_send_file_max_age, allowing its send_file
503 | # wrapper to not have to deal with paths.
504 | if callable(max_age):
505 | max_age = max_age(path)
506 |
507 | if max_age is not None:
508 | if max_age > 0:
509 | rv.cache_control.no_cache = None
510 | rv.cache_control.public = True
511 |
512 | rv.cache_control.max_age = max_age
513 | rv.expires = int(time() + max_age) # type: ignore
514 |
515 | if isinstance(etag, str):
516 | rv.set_etag(etag)
517 | elif etag and path is not None:
518 | check = adler32(path.encode()) & 0xFFFFFFFF
519 | rv.set_etag(f"{mtime}-{size}-{check}")
520 |
521 | if conditional:
522 | try:
523 | rv = rv.make_conditional(environ, accept_ranges=True, complete_length=size)
524 | except RequestedRangeNotSatisfiable:
525 | if file is not None:
526 | file.close()
527 |
528 | raise
529 |
530 | # Some x-sendfile implementations incorrectly ignore the 304
531 | # status code and send the file anyway.
532 | if rv.status_code == 304:
533 | rv.headers.pop("x-sendfile", None)
534 |
535 | return rv
536 |
537 |
538 | def send_from_directory(
539 | directory: os.PathLike[str] | str,
540 | path: os.PathLike[str] | str,
541 | environ: WSGIEnvironment,
542 | **kwargs: t.Any,
543 | ) -> Response:
544 | """Send a file from within a directory using :func:`send_file`.
545 |
546 | This is a secure way to serve files from a folder, such as static
547 | files or uploads. Uses :func:`~werkzeug.security.safe_join` to
548 | ensure the path coming from the client is not maliciously crafted to
549 | point outside the specified directory.
550 |
551 | If the final path does not point to an existing regular file,
552 | returns a 404 :exc:`~werkzeug.exceptions.NotFound` error.
553 |
554 | :param directory: The directory that ``path`` must be located under. This *must not*
555 | be a value provided by the client, otherwise it becomes insecure.
556 | :param path: The path to the file to send, relative to ``directory``. This is the
557 | part of the path provided by the client, which is checked for security.
558 | :param environ: The WSGI environ for the current request.
559 | :param kwargs: Arguments to pass to :func:`send_file`.
560 |
561 | .. versionadded:: 2.0
562 | Adapted from Flask's implementation.
563 | """
564 | path_str = safe_join(os.fspath(directory), os.fspath(path))
565 |
566 | if path_str is None:
567 | raise NotFound()
568 |
569 | # Flask will pass app.root_path, allowing its send_from_directory
570 | # wrapper to not have to deal with paths.
571 | if "_root_path" in kwargs:
572 | path_str = os.path.join(kwargs["_root_path"], path_str)
573 |
574 | if not os.path.isfile(path_str):
575 | raise NotFound()
576 |
577 | return send_file(path_str, environ, **kwargs)
578 |
579 |
580 | def import_string(import_name: str, silent: bool = False) -> t.Any:
581 | """Imports an object based on a string. This is useful if you want to
582 | use import paths as endpoints or something similar. An import path can
583 | be specified either in dotted notation (``xml.sax.saxutils.escape``)
584 | or with a colon as object delimiter (``xml.sax.saxutils:escape``).
585 |
586 | If `silent` is True the return value will be `None` if the import fails.
587 |
588 | :param import_name: the dotted name for the object to import.
589 | :param silent: if set to `True` import errors are ignored and
590 | `None` is returned instead.
591 | :return: imported object
592 | """
593 | import_name = import_name.replace(":", ".")
594 | try:
595 | try:
596 | __import__(import_name)
597 | except ImportError:
598 | if "." not in import_name:
599 | raise
600 | else:
601 | return sys.modules[import_name]
602 |
603 | module_name, obj_name = import_name.rsplit(".", 1)
604 | module = __import__(module_name, globals(), locals(), [obj_name])
605 | try:
606 | return getattr(module, obj_name)
607 | except AttributeError as e:
608 | raise ImportError(e) from None
609 |
610 | except ImportError as e:
611 | if not silent:
612 | raise ImportStringError(import_name, e).with_traceback(
613 | sys.exc_info()[2]
614 | ) from None
615 |
616 | return None
617 |
618 |
619 | def find_modules(
620 | import_path: str, include_packages: bool = False, recursive: bool = False
621 | ) -> t.Iterator[str]:
622 | """Finds all the modules below a package. This can be useful to
623 | automatically import all views / controllers so that their metaclasses /
624 | function decorators have a chance to register themselves on the
625 | application.
626 |
627 | Packages are not returned unless `include_packages` is `True`. This can
628 | also recursively list modules but in that case it will import all the
629 | packages to get the correct load path of that module.
630 |
631 | :param import_path: the dotted name for the package to find child modules.
632 | :param include_packages: set to `True` if packages should be returned, too.
633 | :param recursive: set to `True` if recursion should happen.
634 | :return: generator
635 | """
636 | module = import_string(import_path)
637 | path = getattr(module, "__path__", None)
638 | if path is None:
639 | raise ValueError(f"{import_path!r} is not a package")
640 | basename = f"{module.__name__}."
641 | for _importer, modname, ispkg in pkgutil.iter_modules(path):
642 | modname = basename + modname
643 | if ispkg:
644 | if include_packages:
645 | yield modname
646 | if recursive:
647 | yield from find_modules(modname, include_packages, True)
648 | else:
649 | yield modname
650 |
651 |
652 | class ImportStringError(ImportError):
653 | """Provides information about a failed :func:`import_string` attempt."""
654 |
655 | #: String in dotted notation that failed to be imported.
656 | import_name: str
657 | #: Wrapped exception.
658 | exception: BaseException
659 |
660 | def __init__(self, import_name: str, exception: BaseException) -> None:
661 | self.import_name = import_name
662 | self.exception = exception
663 | msg = import_name
664 | name = ""
665 | tracked = []
666 | for part in import_name.replace(":", ".").split("."):
667 | name = f"{name}.{part}" if name else part
668 | imported = import_string(name, silent=True)
669 | if imported:
670 | tracked.append((name, getattr(imported, "__file__", None)))
671 | else:
672 | track = [f"- {n!r} found in {i!r}." for n, i in tracked]
673 | track.append(f"- {name!r} not found.")
674 | track_str = "\n".join(track)
675 | msg = (
676 | f"import_string() failed for {import_name!r}. Possible reasons"
677 | f" are:\n\n"
678 | "- missing __init__.py in a package;\n"
679 | "- package or module path not included in sys.path;\n"
680 | "- duplicated package or module name taking precedence in"
681 | " sys.path;\n"
682 | "- missing module, class, function or variable;\n\n"
683 | f"Debugged import:\n\n{track_str}\n\n"
684 | f"Original exception:\n\n{type(exception).__name__}: {exception}"
685 | )
686 | break
687 |
688 | super().__init__(msg)
689 |
690 | def __repr__(self) -> str:
691 | return f"<{type(self).__name__}({self.import_name!r}, {self.exception!r})>"
692 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/metadata/base.py:
--------------------------------------------------------------------------------
```python
1 | import csv
2 | import email.message
3 | import functools
4 | import json
5 | import logging
6 | import pathlib
7 | import re
8 | import zipfile
9 | from typing import (
10 | IO,
11 | Any,
12 | Collection,
13 | Container,
14 | Dict,
15 | Iterable,
16 | Iterator,
17 | List,
18 | NamedTuple,
19 | Optional,
20 | Protocol,
21 | Tuple,
22 | Union,
23 | )
24 |
25 | from pip._vendor.packaging.requirements import Requirement
26 | from pip._vendor.packaging.specifiers import InvalidSpecifier, SpecifierSet
27 | from pip._vendor.packaging.utils import NormalizedName, canonicalize_name
28 | from pip._vendor.packaging.version import Version
29 |
30 | from pip._internal.exceptions import NoneMetadataError
31 | from pip._internal.locations import site_packages, user_site
32 | from pip._internal.models.direct_url import (
33 | DIRECT_URL_METADATA_NAME,
34 | DirectUrl,
35 | DirectUrlValidationError,
36 | )
37 | from pip._internal.utils.compat import stdlib_pkgs # TODO: Move definition here.
38 | from pip._internal.utils.egg_link import egg_link_path_from_sys_path
39 | from pip._internal.utils.misc import is_local, normalize_path
40 | from pip._internal.utils.urls import url_to_path
41 |
42 | from ._json import msg_to_json
43 |
44 | InfoPath = Union[str, pathlib.PurePath]
45 |
46 | logger = logging.getLogger(__name__)
47 |
48 |
49 | class BaseEntryPoint(Protocol):
50 | @property
51 | def name(self) -> str:
52 | raise NotImplementedError()
53 |
54 | @property
55 | def value(self) -> str:
56 | raise NotImplementedError()
57 |
58 | @property
59 | def group(self) -> str:
60 | raise NotImplementedError()
61 |
62 |
63 | def _convert_installed_files_path(
64 | entry: Tuple[str, ...],
65 | info: Tuple[str, ...],
66 | ) -> str:
67 | """Convert a legacy installed-files.txt path into modern RECORD path.
68 |
69 | The legacy format stores paths relative to the info directory, while the
70 | modern format stores paths relative to the package root, e.g. the
71 | site-packages directory.
72 |
73 | :param entry: Path parts of the installed-files.txt entry.
74 | :param info: Path parts of the egg-info directory relative to package root.
75 | :returns: The converted entry.
76 |
77 | For best compatibility with symlinks, this does not use ``abspath()`` or
78 | ``Path.resolve()``, but tries to work with path parts:
79 |
80 | 1. While ``entry`` starts with ``..``, remove the equal amounts of parts
81 | from ``info``; if ``info`` is empty, start appending ``..`` instead.
82 | 2. Join the two directly.
83 | """
84 | while entry and entry[0] == "..":
85 | if not info or info[-1] == "..":
86 | info += ("..",)
87 | else:
88 | info = info[:-1]
89 | entry = entry[1:]
90 | return str(pathlib.Path(*info, *entry))
91 |
92 |
93 | class RequiresEntry(NamedTuple):
94 | requirement: str
95 | extra: str
96 | marker: str
97 |
98 |
99 | class BaseDistribution(Protocol):
100 | @classmethod
101 | def from_directory(cls, directory: str) -> "BaseDistribution":
102 | """Load the distribution from a metadata directory.
103 |
104 | :param directory: Path to a metadata directory, e.g. ``.dist-info``.
105 | """
106 | raise NotImplementedError()
107 |
108 | @classmethod
109 | def from_metadata_file_contents(
110 | cls,
111 | metadata_contents: bytes,
112 | filename: str,
113 | project_name: str,
114 | ) -> "BaseDistribution":
115 | """Load the distribution from the contents of a METADATA file.
116 |
117 | This is used to implement PEP 658 by generating a "shallow" dist object that can
118 | be used for resolution without downloading or building the actual dist yet.
119 |
120 | :param metadata_contents: The contents of a METADATA file.
121 | :param filename: File name for the dist with this metadata.
122 | :param project_name: Name of the project this dist represents.
123 | """
124 | raise NotImplementedError()
125 |
126 | @classmethod
127 | def from_wheel(cls, wheel: "Wheel", name: str) -> "BaseDistribution":
128 | """Load the distribution from a given wheel.
129 |
130 | :param wheel: A concrete wheel definition.
131 | :param name: File name of the wheel.
132 |
133 | :raises InvalidWheel: Whenever loading of the wheel causes a
134 | :py:exc:`zipfile.BadZipFile` exception to be thrown.
135 | :raises UnsupportedWheel: If the wheel is a valid zip, but malformed
136 | internally.
137 | """
138 | raise NotImplementedError()
139 |
140 | def __repr__(self) -> str:
141 | return f"{self.raw_name} {self.raw_version} ({self.location})"
142 |
143 | def __str__(self) -> str:
144 | return f"{self.raw_name} {self.raw_version}"
145 |
146 | @property
147 | def location(self) -> Optional[str]:
148 | """Where the distribution is loaded from.
149 |
150 | A string value is not necessarily a filesystem path, since distributions
151 | can be loaded from other sources, e.g. arbitrary zip archives. ``None``
152 | means the distribution is created in-memory.
153 |
154 | Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If
155 | this is a symbolic link, we want to preserve the relative path between
156 | it and files in the distribution.
157 | """
158 | raise NotImplementedError()
159 |
160 | @property
161 | def editable_project_location(self) -> Optional[str]:
162 | """The project location for editable distributions.
163 |
164 | This is the directory where pyproject.toml or setup.py is located.
165 | None if the distribution is not installed in editable mode.
166 | """
167 | # TODO: this property is relatively costly to compute, memoize it ?
168 | direct_url = self.direct_url
169 | if direct_url:
170 | if direct_url.is_local_editable():
171 | return url_to_path(direct_url.url)
172 | else:
173 | # Search for an .egg-link file by walking sys.path, as it was
174 | # done before by dist_is_editable().
175 | egg_link_path = egg_link_path_from_sys_path(self.raw_name)
176 | if egg_link_path:
177 | # TODO: get project location from second line of egg_link file
178 | # (https://github.com/pypa/pip/issues/10243)
179 | return self.location
180 | return None
181 |
182 | @property
183 | def installed_location(self) -> Optional[str]:
184 | """The distribution's "installed" location.
185 |
186 | This should generally be a ``site-packages`` directory. This is
187 | usually ``dist.location``, except for legacy develop-installed packages,
188 | where ``dist.location`` is the source code location, and this is where
189 | the ``.egg-link`` file is.
190 |
191 | The returned location is normalized (in particular, with symlinks removed).
192 | """
193 | raise NotImplementedError()
194 |
195 | @property
196 | def info_location(self) -> Optional[str]:
197 | """Location of the .[egg|dist]-info directory or file.
198 |
199 | Similarly to ``location``, a string value is not necessarily a
200 | filesystem path. ``None`` means the distribution is created in-memory.
201 |
202 | For a modern .dist-info installation on disk, this should be something
203 | like ``{location}/{raw_name}-{version}.dist-info``.
204 |
205 | Do not canonicalize this value with e.g. ``pathlib.Path.resolve()``. If
206 | this is a symbolic link, we want to preserve the relative path between
207 | it and other files in the distribution.
208 | """
209 | raise NotImplementedError()
210 |
211 | @property
212 | def installed_by_distutils(self) -> bool:
213 | """Whether this distribution is installed with legacy distutils format.
214 |
215 | A distribution installed with "raw" distutils not patched by setuptools
216 | uses one single file at ``info_location`` to store metadata. We need to
217 | treat this specially on uninstallation.
218 | """
219 | info_location = self.info_location
220 | if not info_location:
221 | return False
222 | return pathlib.Path(info_location).is_file()
223 |
224 | @property
225 | def installed_as_egg(self) -> bool:
226 | """Whether this distribution is installed as an egg.
227 |
228 | This usually indicates the distribution was installed by (older versions
229 | of) easy_install.
230 | """
231 | location = self.location
232 | if not location:
233 | return False
234 | return location.endswith(".egg")
235 |
236 | @property
237 | def installed_with_setuptools_egg_info(self) -> bool:
238 | """Whether this distribution is installed with the ``.egg-info`` format.
239 |
240 | This usually indicates the distribution was installed with setuptools
241 | with an old pip version or with ``single-version-externally-managed``.
242 |
243 | Note that this ensure the metadata store is a directory. distutils can
244 | also installs an ``.egg-info``, but as a file, not a directory. This
245 | property is *False* for that case. Also see ``installed_by_distutils``.
246 | """
247 | info_location = self.info_location
248 | if not info_location:
249 | return False
250 | if not info_location.endswith(".egg-info"):
251 | return False
252 | return pathlib.Path(info_location).is_dir()
253 |
254 | @property
255 | def installed_with_dist_info(self) -> bool:
256 | """Whether this distribution is installed with the "modern format".
257 |
258 | This indicates a "modern" installation, e.g. storing metadata in the
259 | ``.dist-info`` directory. This applies to installations made by
260 | setuptools (but through pip, not directly), or anything using the
261 | standardized build backend interface (PEP 517).
262 | """
263 | info_location = self.info_location
264 | if not info_location:
265 | return False
266 | if not info_location.endswith(".dist-info"):
267 | return False
268 | return pathlib.Path(info_location).is_dir()
269 |
270 | @property
271 | def canonical_name(self) -> NormalizedName:
272 | raise NotImplementedError()
273 |
274 | @property
275 | def version(self) -> Version:
276 | raise NotImplementedError()
277 |
278 | @property
279 | def raw_version(self) -> str:
280 | raise NotImplementedError()
281 |
282 | @property
283 | def setuptools_filename(self) -> str:
284 | """Convert a project name to its setuptools-compatible filename.
285 |
286 | This is a copy of ``pkg_resources.to_filename()`` for compatibility.
287 | """
288 | return self.raw_name.replace("-", "_")
289 |
290 | @property
291 | def direct_url(self) -> Optional[DirectUrl]:
292 | """Obtain a DirectUrl from this distribution.
293 |
294 | Returns None if the distribution has no `direct_url.json` metadata,
295 | or if `direct_url.json` is invalid.
296 | """
297 | try:
298 | content = self.read_text(DIRECT_URL_METADATA_NAME)
299 | except FileNotFoundError:
300 | return None
301 | try:
302 | return DirectUrl.from_json(content)
303 | except (
304 | UnicodeDecodeError,
305 | json.JSONDecodeError,
306 | DirectUrlValidationError,
307 | ) as e:
308 | logger.warning(
309 | "Error parsing %s for %s: %s",
310 | DIRECT_URL_METADATA_NAME,
311 | self.canonical_name,
312 | e,
313 | )
314 | return None
315 |
316 | @property
317 | def installer(self) -> str:
318 | try:
319 | installer_text = self.read_text("INSTALLER")
320 | except (OSError, ValueError, NoneMetadataError):
321 | return "" # Fail silently if the installer file cannot be read.
322 | for line in installer_text.splitlines():
323 | cleaned_line = line.strip()
324 | if cleaned_line:
325 | return cleaned_line
326 | return ""
327 |
328 | @property
329 | def requested(self) -> bool:
330 | return self.is_file("REQUESTED")
331 |
332 | @property
333 | def editable(self) -> bool:
334 | return bool(self.editable_project_location)
335 |
336 | @property
337 | def local(self) -> bool:
338 | """If distribution is installed in the current virtual environment.
339 |
340 | Always True if we're not in a virtualenv.
341 | """
342 | if self.installed_location is None:
343 | return False
344 | return is_local(self.installed_location)
345 |
346 | @property
347 | def in_usersite(self) -> bool:
348 | if self.installed_location is None or user_site is None:
349 | return False
350 | return self.installed_location.startswith(normalize_path(user_site))
351 |
352 | @property
353 | def in_site_packages(self) -> bool:
354 | if self.installed_location is None or site_packages is None:
355 | return False
356 | return self.installed_location.startswith(normalize_path(site_packages))
357 |
358 | def is_file(self, path: InfoPath) -> bool:
359 | """Check whether an entry in the info directory is a file."""
360 | raise NotImplementedError()
361 |
362 | def iter_distutils_script_names(self) -> Iterator[str]:
363 | """Find distutils 'scripts' entries metadata.
364 |
365 | If 'scripts' is supplied in ``setup.py``, distutils records those in the
366 | installed distribution's ``scripts`` directory, a file for each script.
367 | """
368 | raise NotImplementedError()
369 |
370 | def read_text(self, path: InfoPath) -> str:
371 | """Read a file in the info directory.
372 |
373 | :raise FileNotFoundError: If ``path`` does not exist in the directory.
374 | :raise NoneMetadataError: If ``path`` exists in the info directory, but
375 | cannot be read.
376 | """
377 | raise NotImplementedError()
378 |
379 | def iter_entry_points(self) -> Iterable[BaseEntryPoint]:
380 | raise NotImplementedError()
381 |
382 | def _metadata_impl(self) -> email.message.Message:
383 | raise NotImplementedError()
384 |
385 | @functools.cached_property
386 | def metadata(self) -> email.message.Message:
387 | """Metadata of distribution parsed from e.g. METADATA or PKG-INFO.
388 |
389 | This should return an empty message if the metadata file is unavailable.
390 |
391 | :raises NoneMetadataError: If the metadata file is available, but does
392 | not contain valid metadata.
393 | """
394 | metadata = self._metadata_impl()
395 | self._add_egg_info_requires(metadata)
396 | return metadata
397 |
398 | @property
399 | def metadata_dict(self) -> Dict[str, Any]:
400 | """PEP 566 compliant JSON-serializable representation of METADATA or PKG-INFO.
401 |
402 | This should return an empty dict if the metadata file is unavailable.
403 |
404 | :raises NoneMetadataError: If the metadata file is available, but does
405 | not contain valid metadata.
406 | """
407 | return msg_to_json(self.metadata)
408 |
409 | @property
410 | def metadata_version(self) -> Optional[str]:
411 | """Value of "Metadata-Version:" in distribution metadata, if available."""
412 | return self.metadata.get("Metadata-Version")
413 |
414 | @property
415 | def raw_name(self) -> str:
416 | """Value of "Name:" in distribution metadata."""
417 | # The metadata should NEVER be missing the Name: key, but if it somehow
418 | # does, fall back to the known canonical name.
419 | return self.metadata.get("Name", self.canonical_name)
420 |
421 | @property
422 | def requires_python(self) -> SpecifierSet:
423 | """Value of "Requires-Python:" in distribution metadata.
424 |
425 | If the key does not exist or contains an invalid value, an empty
426 | SpecifierSet should be returned.
427 | """
428 | value = self.metadata.get("Requires-Python")
429 | if value is None:
430 | return SpecifierSet()
431 | try:
432 | # Convert to str to satisfy the type checker; this can be a Header object.
433 | spec = SpecifierSet(str(value))
434 | except InvalidSpecifier as e:
435 | message = "Package %r has an invalid Requires-Python: %s"
436 | logger.warning(message, self.raw_name, e)
437 | return SpecifierSet()
438 | return spec
439 |
440 | def iter_dependencies(self, extras: Collection[str] = ()) -> Iterable[Requirement]:
441 | """Dependencies of this distribution.
442 |
443 | For modern .dist-info distributions, this is the collection of
444 | "Requires-Dist:" entries in distribution metadata.
445 | """
446 | raise NotImplementedError()
447 |
448 | def iter_raw_dependencies(self) -> Iterable[str]:
449 | """Raw Requires-Dist metadata."""
450 | return self.metadata.get_all("Requires-Dist", [])
451 |
452 | def iter_provided_extras(self) -> Iterable[NormalizedName]:
453 | """Extras provided by this distribution.
454 |
455 | For modern .dist-info distributions, this is the collection of
456 | "Provides-Extra:" entries in distribution metadata.
457 |
458 | The return value of this function is expected to be normalised names,
459 | per PEP 685, with the returned value being handled appropriately by
460 | `iter_dependencies`.
461 | """
462 | raise NotImplementedError()
463 |
464 | def _iter_declared_entries_from_record(self) -> Optional[Iterator[str]]:
465 | try:
466 | text = self.read_text("RECORD")
467 | except FileNotFoundError:
468 | return None
469 | # This extra Path-str cast normalizes entries.
470 | return (str(pathlib.Path(row[0])) for row in csv.reader(text.splitlines()))
471 |
472 | def _iter_declared_entries_from_legacy(self) -> Optional[Iterator[str]]:
473 | try:
474 | text = self.read_text("installed-files.txt")
475 | except FileNotFoundError:
476 | return None
477 | paths = (p for p in text.splitlines(keepends=False) if p)
478 | root = self.location
479 | info = self.info_location
480 | if root is None or info is None:
481 | return paths
482 | try:
483 | info_rel = pathlib.Path(info).relative_to(root)
484 | except ValueError: # info is not relative to root.
485 | return paths
486 | if not info_rel.parts: # info *is* root.
487 | return paths
488 | return (
489 | _convert_installed_files_path(pathlib.Path(p).parts, info_rel.parts)
490 | for p in paths
491 | )
492 |
493 | def iter_declared_entries(self) -> Optional[Iterator[str]]:
494 | """Iterate through file entries declared in this distribution.
495 |
496 | For modern .dist-info distributions, this is the files listed in the
497 | ``RECORD`` metadata file. For legacy setuptools distributions, this
498 | comes from ``installed-files.txt``, with entries normalized to be
499 | compatible with the format used by ``RECORD``.
500 |
501 | :return: An iterator for listed entries, or None if the distribution
502 | contains neither ``RECORD`` nor ``installed-files.txt``.
503 | """
504 | return (
505 | self._iter_declared_entries_from_record()
506 | or self._iter_declared_entries_from_legacy()
507 | )
508 |
509 | def _iter_requires_txt_entries(self) -> Iterator[RequiresEntry]:
510 | """Parse a ``requires.txt`` in an egg-info directory.
511 |
512 | This is an INI-ish format where an egg-info stores dependencies. A
513 | section name describes extra other environment markers, while each entry
514 | is an arbitrary string (not a key-value pair) representing a dependency
515 | as a requirement string (no markers).
516 |
517 | There is a construct in ``importlib.metadata`` called ``Sectioned`` that
518 | does mostly the same, but the format is currently considered private.
519 | """
520 | try:
521 | content = self.read_text("requires.txt")
522 | except FileNotFoundError:
523 | return
524 | extra = marker = "" # Section-less entries don't have markers.
525 | for line in content.splitlines():
526 | line = line.strip()
527 | if not line or line.startswith("#"): # Comment; ignored.
528 | continue
529 | if line.startswith("[") and line.endswith("]"): # A section header.
530 | extra, _, marker = line.strip("[]").partition(":")
531 | continue
532 | yield RequiresEntry(requirement=line, extra=extra, marker=marker)
533 |
534 | def _iter_egg_info_extras(self) -> Iterable[str]:
535 | """Get extras from the egg-info directory."""
536 | known_extras = {""}
537 | for entry in self._iter_requires_txt_entries():
538 | extra = canonicalize_name(entry.extra)
539 | if extra in known_extras:
540 | continue
541 | known_extras.add(extra)
542 | yield extra
543 |
544 | def _iter_egg_info_dependencies(self) -> Iterable[str]:
545 | """Get distribution dependencies from the egg-info directory.
546 |
547 | To ease parsing, this converts a legacy dependency entry into a PEP 508
548 | requirement string. Like ``_iter_requires_txt_entries()``, there is code
549 | in ``importlib.metadata`` that does mostly the same, but not do exactly
550 | what we need.
551 |
552 | Namely, ``importlib.metadata`` does not normalize the extra name before
553 | putting it into the requirement string, which causes marker comparison
554 | to fail because the dist-info format do normalize. This is consistent in
555 | all currently available PEP 517 backends, although not standardized.
556 | """
557 | for entry in self._iter_requires_txt_entries():
558 | extra = canonicalize_name(entry.extra)
559 | if extra and entry.marker:
560 | marker = f'({entry.marker}) and extra == "{extra}"'
561 | elif extra:
562 | marker = f'extra == "{extra}"'
563 | elif entry.marker:
564 | marker = entry.marker
565 | else:
566 | marker = ""
567 | if marker:
568 | yield f"{entry.requirement} ; {marker}"
569 | else:
570 | yield entry.requirement
571 |
572 | def _add_egg_info_requires(self, metadata: email.message.Message) -> None:
573 | """Add egg-info requires.txt information to the metadata."""
574 | if not metadata.get_all("Requires-Dist"):
575 | for dep in self._iter_egg_info_dependencies():
576 | metadata["Requires-Dist"] = dep
577 | if not metadata.get_all("Provides-Extra"):
578 | for extra in self._iter_egg_info_extras():
579 | metadata["Provides-Extra"] = extra
580 |
581 |
582 | class BaseEnvironment:
583 | """An environment containing distributions to introspect."""
584 |
585 | @classmethod
586 | def default(cls) -> "BaseEnvironment":
587 | raise NotImplementedError()
588 |
589 | @classmethod
590 | def from_paths(cls, paths: Optional[List[str]]) -> "BaseEnvironment":
591 | raise NotImplementedError()
592 |
593 | def get_distribution(self, name: str) -> Optional["BaseDistribution"]:
594 | """Given a requirement name, return the installed distributions.
595 |
596 | The name may not be normalized. The implementation must canonicalize
597 | it for lookup.
598 | """
599 | raise NotImplementedError()
600 |
601 | def _iter_distributions(self) -> Iterator["BaseDistribution"]:
602 | """Iterate through installed distributions.
603 |
604 | This function should be implemented by subclass, but never called
605 | directly. Use the public ``iter_distribution()`` instead, which
606 | implements additional logic to make sure the distributions are valid.
607 | """
608 | raise NotImplementedError()
609 |
610 | def iter_all_distributions(self) -> Iterator[BaseDistribution]:
611 | """Iterate through all installed distributions without any filtering."""
612 | for dist in self._iter_distributions():
613 | # Make sure the distribution actually comes from a valid Python
614 | # packaging distribution. Pip's AdjacentTempDirectory leaves folders
615 | # e.g. ``~atplotlib.dist-info`` if cleanup was interrupted. The
616 | # valid project name pattern is taken from PEP 508.
617 | project_name_valid = re.match(
618 | r"^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$",
619 | dist.canonical_name,
620 | flags=re.IGNORECASE,
621 | )
622 | if not project_name_valid:
623 | logger.warning(
624 | "Ignoring invalid distribution %s (%s)",
625 | dist.canonical_name,
626 | dist.location,
627 | )
628 | continue
629 | yield dist
630 |
631 | def iter_installed_distributions(
632 | self,
633 | local_only: bool = True,
634 | skip: Container[str] = stdlib_pkgs,
635 | include_editables: bool = True,
636 | editables_only: bool = False,
637 | user_only: bool = False,
638 | ) -> Iterator[BaseDistribution]:
639 | """Return a list of installed distributions.
640 |
641 | This is based on ``iter_all_distributions()`` with additional filtering
642 | options. Note that ``iter_installed_distributions()`` without arguments
643 | is *not* equal to ``iter_all_distributions()``, since some of the
644 | configurations exclude packages by default.
645 |
646 | :param local_only: If True (default), only return installations
647 | local to the current virtualenv, if in a virtualenv.
648 | :param skip: An iterable of canonicalized project names to ignore;
649 | defaults to ``stdlib_pkgs``.
650 | :param include_editables: If False, don't report editables.
651 | :param editables_only: If True, only report editables.
652 | :param user_only: If True, only report installations in the user
653 | site directory.
654 | """
655 | it = self.iter_all_distributions()
656 | if local_only:
657 | it = (d for d in it if d.local)
658 | if not include_editables:
659 | it = (d for d in it if not d.editable)
660 | if editables_only:
661 | it = (d for d in it if d.editable)
662 | if user_only:
663 | it = (d for d in it if d.in_usersite)
664 | return (d for d in it if d.canonical_name not in skip)
665 |
666 |
667 | class Wheel(Protocol):
668 | location: str
669 |
670 | def as_zipfile(self) -> zipfile.ZipFile:
671 | raise NotImplementedError()
672 |
673 |
674 | class FilesystemWheel(Wheel):
675 | def __init__(self, location: str) -> None:
676 | self.location = location
677 |
678 | def as_zipfile(self) -> zipfile.ZipFile:
679 | return zipfile.ZipFile(self.location, allowZip64=True)
680 |
681 |
682 | class MemoryWheel(Wheel):
683 | def __init__(self, location: str, stream: IO[bytes]) -> None:
684 | self.location = location
685 | self.stream = stream
686 |
687 | def as_zipfile(self) -> zipfile.ZipFile:
688 | return zipfile.ZipFile(self.stream, allowZip64=True)
689 |
```