This is page 79 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/utils/misc.py:
--------------------------------------------------------------------------------
```python
1 | import errno
2 | import getpass
3 | import hashlib
4 | import logging
5 | import os
6 | import posixpath
7 | import shutil
8 | import stat
9 | import sys
10 | import sysconfig
11 | import urllib.parse
12 | from dataclasses import dataclass
13 | from functools import partial
14 | from io import StringIO
15 | from itertools import filterfalse, tee, zip_longest
16 | from pathlib import Path
17 | from types import FunctionType, TracebackType
18 | from typing import (
19 | Any,
20 | BinaryIO,
21 | Callable,
22 | Dict,
23 | Generator,
24 | Iterable,
25 | Iterator,
26 | List,
27 | Optional,
28 | TextIO,
29 | Tuple,
30 | Type,
31 | TypeVar,
32 | Union,
33 | cast,
34 | )
35 |
36 | from pip._vendor.packaging.requirements import Requirement
37 | from pip._vendor.pyproject_hooks import BuildBackendHookCaller
38 |
39 | from pip import __version__
40 | from pip._internal.exceptions import CommandError, ExternallyManagedEnvironment
41 | from pip._internal.locations import get_major_minor_version
42 | from pip._internal.utils.compat import WINDOWS
43 | from pip._internal.utils.retry import retry
44 | from pip._internal.utils.virtualenv import running_under_virtualenv
45 |
46 | __all__ = [
47 | "rmtree",
48 | "display_path",
49 | "backup_dir",
50 | "ask",
51 | "splitext",
52 | "format_size",
53 | "is_installable_dir",
54 | "normalize_path",
55 | "renames",
56 | "get_prog",
57 | "ensure_dir",
58 | "remove_auth_from_url",
59 | "check_externally_managed",
60 | "ConfiguredBuildBackendHookCaller",
61 | ]
62 |
63 | logger = logging.getLogger(__name__)
64 |
65 | T = TypeVar("T")
66 | ExcInfo = Tuple[Type[BaseException], BaseException, TracebackType]
67 | VersionInfo = Tuple[int, int, int]
68 | NetlocTuple = Tuple[str, Tuple[Optional[str], Optional[str]]]
69 | OnExc = Callable[[FunctionType, Path, BaseException], Any]
70 | OnErr = Callable[[FunctionType, Path, ExcInfo], Any]
71 |
72 | FILE_CHUNK_SIZE = 1024 * 1024
73 |
74 |
75 | def get_pip_version() -> str:
76 | pip_pkg_dir = os.path.join(os.path.dirname(__file__), "..", "..")
77 | pip_pkg_dir = os.path.abspath(pip_pkg_dir)
78 |
79 | return f"pip {__version__} from {pip_pkg_dir} (python {get_major_minor_version()})"
80 |
81 |
82 | def normalize_version_info(py_version_info: Tuple[int, ...]) -> Tuple[int, int, int]:
83 | """
84 | Convert a tuple of ints representing a Python version to one of length
85 | three.
86 |
87 | :param py_version_info: a tuple of ints representing a Python version,
88 | or None to specify no version. The tuple can have any length.
89 |
90 | :return: a tuple of length three if `py_version_info` is non-None.
91 | Otherwise, return `py_version_info` unchanged (i.e. None).
92 | """
93 | if len(py_version_info) < 3:
94 | py_version_info += (3 - len(py_version_info)) * (0,)
95 | elif len(py_version_info) > 3:
96 | py_version_info = py_version_info[:3]
97 |
98 | return cast("VersionInfo", py_version_info)
99 |
100 |
101 | def ensure_dir(path: str) -> None:
102 | """os.path.makedirs without EEXIST."""
103 | try:
104 | os.makedirs(path)
105 | except OSError as e:
106 | # Windows can raise spurious ENOTEMPTY errors. See #6426.
107 | if e.errno != errno.EEXIST and e.errno != errno.ENOTEMPTY:
108 | raise
109 |
110 |
111 | def get_prog() -> str:
112 | try:
113 | prog = os.path.basename(sys.argv[0])
114 | if prog in ("__main__.py", "-c"):
115 | return f"{sys.executable} -m pip"
116 | else:
117 | return prog
118 | except (AttributeError, TypeError, IndexError):
119 | pass
120 | return "pip"
121 |
122 |
123 | # Retry every half second for up to 3 seconds
124 | @retry(stop_after_delay=3, wait=0.5)
125 | def rmtree(
126 | dir: str, ignore_errors: bool = False, onexc: Optional[OnExc] = None
127 | ) -> None:
128 | if ignore_errors:
129 | onexc = _onerror_ignore
130 | if onexc is None:
131 | onexc = _onerror_reraise
132 | handler: OnErr = partial(
133 | # `[func, path, Union[ExcInfo, BaseException]] -> Any` is equivalent to
134 | # `Union[([func, path, ExcInfo] -> Any), ([func, path, BaseException] -> Any)]`.
135 | cast(Union[OnExc, OnErr], rmtree_errorhandler),
136 | onexc=onexc,
137 | )
138 | if sys.version_info >= (3, 12):
139 | # See https://docs.python.org/3.12/whatsnew/3.12.html#shutil.
140 | shutil.rmtree(dir, onexc=handler) # type: ignore
141 | else:
142 | shutil.rmtree(dir, onerror=handler) # type: ignore
143 |
144 |
145 | def _onerror_ignore(*_args: Any) -> None:
146 | pass
147 |
148 |
149 | def _onerror_reraise(*_args: Any) -> None:
150 | raise # noqa: PLE0704 - Bare exception used to reraise existing exception
151 |
152 |
153 | def rmtree_errorhandler(
154 | func: FunctionType,
155 | path: Path,
156 | exc_info: Union[ExcInfo, BaseException],
157 | *,
158 | onexc: OnExc = _onerror_reraise,
159 | ) -> None:
160 | """
161 | `rmtree` error handler to 'force' a file remove (i.e. like `rm -f`).
162 |
163 | * If a file is readonly then it's write flag is set and operation is
164 | retried.
165 |
166 | * `onerror` is the original callback from `rmtree(... onerror=onerror)`
167 | that is chained at the end if the "rm -f" still fails.
168 | """
169 | try:
170 | st_mode = os.stat(path).st_mode
171 | except OSError:
172 | # it's equivalent to os.path.exists
173 | return
174 |
175 | if not st_mode & stat.S_IWRITE:
176 | # convert to read/write
177 | try:
178 | os.chmod(path, st_mode | stat.S_IWRITE)
179 | except OSError:
180 | pass
181 | else:
182 | # use the original function to repeat the operation
183 | try:
184 | func(path)
185 | return
186 | except OSError:
187 | pass
188 |
189 | if not isinstance(exc_info, BaseException):
190 | _, exc_info, _ = exc_info
191 | onexc(func, path, exc_info)
192 |
193 |
194 | def display_path(path: str) -> str:
195 | """Gives the display value for a given path, making it relative to cwd
196 | if possible."""
197 | path = os.path.normcase(os.path.abspath(path))
198 | if path.startswith(os.getcwd() + os.path.sep):
199 | path = "." + path[len(os.getcwd()) :]
200 | return path
201 |
202 |
203 | def backup_dir(dir: str, ext: str = ".bak") -> str:
204 | """Figure out the name of a directory to back up the given dir to
205 | (adding .bak, .bak2, etc)"""
206 | n = 1
207 | extension = ext
208 | while os.path.exists(dir + extension):
209 | n += 1
210 | extension = ext + str(n)
211 | return dir + extension
212 |
213 |
214 | def ask_path_exists(message: str, options: Iterable[str]) -> str:
215 | for action in os.environ.get("PIP_EXISTS_ACTION", "").split():
216 | if action in options:
217 | return action
218 | return ask(message, options)
219 |
220 |
221 | def _check_no_input(message: str) -> None:
222 | """Raise an error if no input is allowed."""
223 | if os.environ.get("PIP_NO_INPUT"):
224 | raise Exception(
225 | f"No input was expected ($PIP_NO_INPUT set); question: {message}"
226 | )
227 |
228 |
229 | def ask(message: str, options: Iterable[str]) -> str:
230 | """Ask the message interactively, with the given possible responses"""
231 | while 1:
232 | _check_no_input(message)
233 | response = input(message)
234 | response = response.strip().lower()
235 | if response not in options:
236 | print(
237 | "Your response ({!r}) was not one of the expected responses: "
238 | "{}".format(response, ", ".join(options))
239 | )
240 | else:
241 | return response
242 |
243 |
244 | def ask_input(message: str) -> str:
245 | """Ask for input interactively."""
246 | _check_no_input(message)
247 | return input(message)
248 |
249 |
250 | def ask_password(message: str) -> str:
251 | """Ask for a password interactively."""
252 | _check_no_input(message)
253 | return getpass.getpass(message)
254 |
255 |
256 | def strtobool(val: str) -> int:
257 | """Convert a string representation of truth to true (1) or false (0).
258 |
259 | True values are 'y', 'yes', 't', 'true', 'on', and '1'; false values
260 | are 'n', 'no', 'f', 'false', 'off', and '0'. Raises ValueError if
261 | 'val' is anything else.
262 | """
263 | val = val.lower()
264 | if val in ("y", "yes", "t", "true", "on", "1"):
265 | return 1
266 | elif val in ("n", "no", "f", "false", "off", "0"):
267 | return 0
268 | else:
269 | raise ValueError(f"invalid truth value {val!r}")
270 |
271 |
272 | def format_size(bytes: float) -> str:
273 | if bytes > 1000 * 1000:
274 | return f"{bytes / 1000.0 / 1000:.1f} MB"
275 | elif bytes > 10 * 1000:
276 | return f"{int(bytes / 1000)} kB"
277 | elif bytes > 1000:
278 | return f"{bytes / 1000.0:.1f} kB"
279 | else:
280 | return f"{int(bytes)} bytes"
281 |
282 |
283 | def tabulate(rows: Iterable[Iterable[Any]]) -> Tuple[List[str], List[int]]:
284 | """Return a list of formatted rows and a list of column sizes.
285 |
286 | For example::
287 |
288 | >>> tabulate([['foobar', 2000], [0xdeadbeef]])
289 | (['foobar 2000', '3735928559'], [10, 4])
290 | """
291 | rows = [tuple(map(str, row)) for row in rows]
292 | sizes = [max(map(len, col)) for col in zip_longest(*rows, fillvalue="")]
293 | table = [" ".join(map(str.ljust, row, sizes)).rstrip() for row in rows]
294 | return table, sizes
295 |
296 |
297 | def is_installable_dir(path: str) -> bool:
298 | """Is path is a directory containing pyproject.toml or setup.py?
299 |
300 | If pyproject.toml exists, this is a PEP 517 project. Otherwise we look for
301 | a legacy setuptools layout by identifying setup.py. We don't check for the
302 | setup.cfg because using it without setup.py is only available for PEP 517
303 | projects, which are already covered by the pyproject.toml check.
304 | """
305 | if not os.path.isdir(path):
306 | return False
307 | if os.path.isfile(os.path.join(path, "pyproject.toml")):
308 | return True
309 | if os.path.isfile(os.path.join(path, "setup.py")):
310 | return True
311 | return False
312 |
313 |
314 | def read_chunks(
315 | file: BinaryIO, size: int = FILE_CHUNK_SIZE
316 | ) -> Generator[bytes, None, None]:
317 | """Yield pieces of data from a file-like object until EOF."""
318 | while True:
319 | chunk = file.read(size)
320 | if not chunk:
321 | break
322 | yield chunk
323 |
324 |
325 | def normalize_path(path: str, resolve_symlinks: bool = True) -> str:
326 | """
327 | Convert a path to its canonical, case-normalized, absolute version.
328 |
329 | """
330 | path = os.path.expanduser(path)
331 | if resolve_symlinks:
332 | path = os.path.realpath(path)
333 | else:
334 | path = os.path.abspath(path)
335 | return os.path.normcase(path)
336 |
337 |
338 | def splitext(path: str) -> Tuple[str, str]:
339 | """Like os.path.splitext, but take off .tar too"""
340 | base, ext = posixpath.splitext(path)
341 | if base.lower().endswith(".tar"):
342 | ext = base[-4:] + ext
343 | base = base[:-4]
344 | return base, ext
345 |
346 |
347 | def renames(old: str, new: str) -> None:
348 | """Like os.renames(), but handles renaming across devices."""
349 | # Implementation borrowed from os.renames().
350 | head, tail = os.path.split(new)
351 | if head and tail and not os.path.exists(head):
352 | os.makedirs(head)
353 |
354 | shutil.move(old, new)
355 |
356 | head, tail = os.path.split(old)
357 | if head and tail:
358 | try:
359 | os.removedirs(head)
360 | except OSError:
361 | pass
362 |
363 |
364 | def is_local(path: str) -> bool:
365 | """
366 | Return True if path is within sys.prefix, if we're running in a virtualenv.
367 |
368 | If we're not in a virtualenv, all paths are considered "local."
369 |
370 | Caution: this function assumes the head of path has been normalized
371 | with normalize_path.
372 | """
373 | if not running_under_virtualenv():
374 | return True
375 | return path.startswith(normalize_path(sys.prefix))
376 |
377 |
378 | def write_output(msg: Any, *args: Any) -> None:
379 | logger.info(msg, *args)
380 |
381 |
382 | class StreamWrapper(StringIO):
383 | orig_stream: TextIO
384 |
385 | @classmethod
386 | def from_stream(cls, orig_stream: TextIO) -> "StreamWrapper":
387 | ret = cls()
388 | ret.orig_stream = orig_stream
389 | return ret
390 |
391 | # compileall.compile_dir() needs stdout.encoding to print to stdout
392 | # type ignore is because TextIOBase.encoding is writeable
393 | @property
394 | def encoding(self) -> str: # type: ignore
395 | return self.orig_stream.encoding
396 |
397 |
398 | # Simulates an enum
399 | def enum(*sequential: Any, **named: Any) -> Type[Any]:
400 | enums = dict(zip(sequential, range(len(sequential))), **named)
401 | reverse = {value: key for key, value in enums.items()}
402 | enums["reverse_mapping"] = reverse
403 | return type("Enum", (), enums)
404 |
405 |
406 | def build_netloc(host: str, port: Optional[int]) -> str:
407 | """
408 | Build a netloc from a host-port pair
409 | """
410 | if port is None:
411 | return host
412 | if ":" in host:
413 | # Only wrap host with square brackets when it is IPv6
414 | host = f"[{host}]"
415 | return f"{host}:{port}"
416 |
417 |
418 | def build_url_from_netloc(netloc: str, scheme: str = "https") -> str:
419 | """
420 | Build a full URL from a netloc.
421 | """
422 | if netloc.count(":") >= 2 and "@" not in netloc and "[" not in netloc:
423 | # It must be a bare IPv6 address, so wrap it with brackets.
424 | netloc = f"[{netloc}]"
425 | return f"{scheme}://{netloc}"
426 |
427 |
428 | def parse_netloc(netloc: str) -> Tuple[Optional[str], Optional[int]]:
429 | """
430 | Return the host-port pair from a netloc.
431 | """
432 | url = build_url_from_netloc(netloc)
433 | parsed = urllib.parse.urlparse(url)
434 | return parsed.hostname, parsed.port
435 |
436 |
437 | def split_auth_from_netloc(netloc: str) -> NetlocTuple:
438 | """
439 | Parse out and remove the auth information from a netloc.
440 |
441 | Returns: (netloc, (username, password)).
442 | """
443 | if "@" not in netloc:
444 | return netloc, (None, None)
445 |
446 | # Split from the right because that's how urllib.parse.urlsplit()
447 | # behaves if more than one @ is present (which can be checked using
448 | # the password attribute of urlsplit()'s return value).
449 | auth, netloc = netloc.rsplit("@", 1)
450 | pw: Optional[str] = None
451 | if ":" in auth:
452 | # Split from the left because that's how urllib.parse.urlsplit()
453 | # behaves if more than one : is present (which again can be checked
454 | # using the password attribute of the return value)
455 | user, pw = auth.split(":", 1)
456 | else:
457 | user, pw = auth, None
458 |
459 | user = urllib.parse.unquote(user)
460 | if pw is not None:
461 | pw = urllib.parse.unquote(pw)
462 |
463 | return netloc, (user, pw)
464 |
465 |
466 | def redact_netloc(netloc: str) -> str:
467 | """
468 | Replace the sensitive data in a netloc with "****", if it exists.
469 |
470 | For example:
471 | - "user:[email protected]" returns "user:****@example.com"
472 | - "[email protected]" returns "****@example.com"
473 | """
474 | netloc, (user, password) = split_auth_from_netloc(netloc)
475 | if user is None:
476 | return netloc
477 | if password is None:
478 | user = "****"
479 | password = ""
480 | else:
481 | user = urllib.parse.quote(user)
482 | password = ":****"
483 | return f"{user}{password}@{netloc}"
484 |
485 |
486 | def _transform_url(
487 | url: str, transform_netloc: Callable[[str], Tuple[Any, ...]]
488 | ) -> Tuple[str, NetlocTuple]:
489 | """Transform and replace netloc in a url.
490 |
491 | transform_netloc is a function taking the netloc and returning a
492 | tuple. The first element of this tuple is the new netloc. The
493 | entire tuple is returned.
494 |
495 | Returns a tuple containing the transformed url as item 0 and the
496 | original tuple returned by transform_netloc as item 1.
497 | """
498 | purl = urllib.parse.urlsplit(url)
499 | netloc_tuple = transform_netloc(purl.netloc)
500 | # stripped url
501 | url_pieces = (purl.scheme, netloc_tuple[0], purl.path, purl.query, purl.fragment)
502 | surl = urllib.parse.urlunsplit(url_pieces)
503 | return surl, cast("NetlocTuple", netloc_tuple)
504 |
505 |
506 | def _get_netloc(netloc: str) -> NetlocTuple:
507 | return split_auth_from_netloc(netloc)
508 |
509 |
510 | def _redact_netloc(netloc: str) -> Tuple[str]:
511 | return (redact_netloc(netloc),)
512 |
513 |
514 | def split_auth_netloc_from_url(
515 | url: str,
516 | ) -> Tuple[str, str, Tuple[Optional[str], Optional[str]]]:
517 | """
518 | Parse a url into separate netloc, auth, and url with no auth.
519 |
520 | Returns: (url_without_auth, netloc, (username, password))
521 | """
522 | url_without_auth, (netloc, auth) = _transform_url(url, _get_netloc)
523 | return url_without_auth, netloc, auth
524 |
525 |
526 | def remove_auth_from_url(url: str) -> str:
527 | """Return a copy of url with 'username:password@' removed."""
528 | # username/pass params are passed to subversion through flags
529 | # and are not recognized in the url.
530 | return _transform_url(url, _get_netloc)[0]
531 |
532 |
533 | def redact_auth_from_url(url: str) -> str:
534 | """Replace the password in a given url with ****."""
535 | return _transform_url(url, _redact_netloc)[0]
536 |
537 |
538 | def redact_auth_from_requirement(req: Requirement) -> str:
539 | """Replace the password in a given requirement url with ****."""
540 | if not req.url:
541 | return str(req)
542 | return str(req).replace(req.url, redact_auth_from_url(req.url))
543 |
544 |
545 | @dataclass(frozen=True)
546 | class HiddenText:
547 | secret: str
548 | redacted: str
549 |
550 | def __repr__(self) -> str:
551 | return f"<HiddenText {str(self)!r}>"
552 |
553 | def __str__(self) -> str:
554 | return self.redacted
555 |
556 | # This is useful for testing.
557 | def __eq__(self, other: Any) -> bool:
558 | if type(self) != type(other):
559 | return False
560 |
561 | # The string being used for redaction doesn't also have to match,
562 | # just the raw, original string.
563 | return self.secret == other.secret
564 |
565 |
566 | def hide_value(value: str) -> HiddenText:
567 | return HiddenText(value, redacted="****")
568 |
569 |
570 | def hide_url(url: str) -> HiddenText:
571 | redacted = redact_auth_from_url(url)
572 | return HiddenText(url, redacted=redacted)
573 |
574 |
575 | def protect_pip_from_modification_on_windows(modifying_pip: bool) -> None:
576 | """Protection of pip.exe from modification on Windows
577 |
578 | On Windows, any operation modifying pip should be run as:
579 | python -m pip ...
580 | """
581 | pip_names = [
582 | "pip",
583 | f"pip{sys.version_info.major}",
584 | f"pip{sys.version_info.major}.{sys.version_info.minor}",
585 | ]
586 |
587 | # See https://github.com/pypa/pip/issues/1299 for more discussion
588 | should_show_use_python_msg = (
589 | modifying_pip and WINDOWS and os.path.basename(sys.argv[0]) in pip_names
590 | )
591 |
592 | if should_show_use_python_msg:
593 | new_command = [sys.executable, "-m", "pip"] + sys.argv[1:]
594 | raise CommandError(
595 | "To modify pip, please run the following command:\n{}".format(
596 | " ".join(new_command)
597 | )
598 | )
599 |
600 |
601 | def check_externally_managed() -> None:
602 | """Check whether the current environment is externally managed.
603 |
604 | If the ``EXTERNALLY-MANAGED`` config file is found, the current environment
605 | is considered externally managed, and an ExternallyManagedEnvironment is
606 | raised.
607 | """
608 | if running_under_virtualenv():
609 | return
610 | marker = os.path.join(sysconfig.get_path("stdlib"), "EXTERNALLY-MANAGED")
611 | if not os.path.isfile(marker):
612 | return
613 | raise ExternallyManagedEnvironment.from_config(marker)
614 |
615 |
616 | def is_console_interactive() -> bool:
617 | """Is this console interactive?"""
618 | return sys.stdin is not None and sys.stdin.isatty()
619 |
620 |
621 | def hash_file(path: str, blocksize: int = 1 << 20) -> Tuple[Any, int]:
622 | """Return (hash, length) for path using hashlib.sha256()"""
623 |
624 | h = hashlib.sha256()
625 | length = 0
626 | with open(path, "rb") as f:
627 | for block in read_chunks(f, size=blocksize):
628 | length += len(block)
629 | h.update(block)
630 | return h, length
631 |
632 |
633 | def pairwise(iterable: Iterable[Any]) -> Iterator[Tuple[Any, Any]]:
634 | """
635 | Return paired elements.
636 |
637 | For example:
638 | s -> (s0, s1), (s2, s3), (s4, s5), ...
639 | """
640 | iterable = iter(iterable)
641 | return zip_longest(iterable, iterable)
642 |
643 |
644 | def partition(
645 | pred: Callable[[T], bool], iterable: Iterable[T]
646 | ) -> Tuple[Iterable[T], Iterable[T]]:
647 | """
648 | Use a predicate to partition entries into false entries and true entries,
649 | like
650 |
651 | partition(is_odd, range(10)) --> 0 2 4 6 8 and 1 3 5 7 9
652 | """
653 | t1, t2 = tee(iterable)
654 | return filterfalse(pred, t1), filter(pred, t2)
655 |
656 |
657 | class ConfiguredBuildBackendHookCaller(BuildBackendHookCaller):
658 | def __init__(
659 | self,
660 | config_holder: Any,
661 | source_dir: str,
662 | build_backend: str,
663 | backend_path: Optional[str] = None,
664 | runner: Optional[Callable[..., None]] = None,
665 | python_executable: Optional[str] = None,
666 | ):
667 | super().__init__(
668 | source_dir, build_backend, backend_path, runner, python_executable
669 | )
670 | self.config_holder = config_holder
671 |
672 | def build_wheel(
673 | self,
674 | wheel_directory: str,
675 | config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
676 | metadata_directory: Optional[str] = None,
677 | ) -> str:
678 | cs = self.config_holder.config_settings
679 | return super().build_wheel(
680 | wheel_directory, config_settings=cs, metadata_directory=metadata_directory
681 | )
682 |
683 | def build_sdist(
684 | self,
685 | sdist_directory: str,
686 | config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
687 | ) -> str:
688 | cs = self.config_holder.config_settings
689 | return super().build_sdist(sdist_directory, config_settings=cs)
690 |
691 | def build_editable(
692 | self,
693 | wheel_directory: str,
694 | config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
695 | metadata_directory: Optional[str] = None,
696 | ) -> str:
697 | cs = self.config_holder.config_settings
698 | return super().build_editable(
699 | wheel_directory, config_settings=cs, metadata_directory=metadata_directory
700 | )
701 |
702 | def get_requires_for_build_wheel(
703 | self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
704 | ) -> List[str]:
705 | cs = self.config_holder.config_settings
706 | return super().get_requires_for_build_wheel(config_settings=cs)
707 |
708 | def get_requires_for_build_sdist(
709 | self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
710 | ) -> List[str]:
711 | cs = self.config_holder.config_settings
712 | return super().get_requires_for_build_sdist(config_settings=cs)
713 |
714 | def get_requires_for_build_editable(
715 | self, config_settings: Optional[Dict[str, Union[str, List[str]]]] = None
716 | ) -> List[str]:
717 | cs = self.config_holder.config_settings
718 | return super().get_requires_for_build_editable(config_settings=cs)
719 |
720 | def prepare_metadata_for_build_wheel(
721 | self,
722 | metadata_directory: str,
723 | config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
724 | _allow_fallback: bool = True,
725 | ) -> str:
726 | cs = self.config_holder.config_settings
727 | return super().prepare_metadata_for_build_wheel(
728 | metadata_directory=metadata_directory,
729 | config_settings=cs,
730 | _allow_fallback=_allow_fallback,
731 | )
732 |
733 | def prepare_metadata_for_build_editable(
734 | self,
735 | metadata_directory: str,
736 | config_settings: Optional[Dict[str, Union[str, List[str]]]] = None,
737 | _allow_fallback: bool = True,
738 | ) -> str:
739 | cs = self.config_holder.config_settings
740 | return super().prepare_metadata_for_build_editable(
741 | metadata_directory=metadata_directory,
742 | config_settings=cs,
743 | _allow_fallback=_allow_fallback,
744 | )
745 |
746 |
747 | def warn_if_run_as_root() -> None:
748 | """Output a warning for sudo users on Unix.
749 |
750 | In a virtual environment, sudo pip still writes to virtualenv.
751 | On Windows, users may run pip as Administrator without issues.
752 | This warning only applies to Unix root users outside of virtualenv.
753 | """
754 | if running_under_virtualenv():
755 | return
756 | if not hasattr(os, "getuid"):
757 | return
758 | # On Windows, there are no "system managed" Python packages. Installing as
759 | # Administrator via pip is the correct way of updating system environments.
760 | #
761 | # We choose sys.platform over utils.compat.WINDOWS here to enable Mypy platform
762 | # checks: https://mypy.readthedocs.io/en/stable/common_issues.html
763 | if sys.platform == "win32" or sys.platform == "cygwin":
764 | return
765 |
766 | if os.getuid() != 0:
767 | return
768 |
769 | logger.warning(
770 | "Running pip as the 'root' user can result in broken permissions and "
771 | "conflicting behaviour with the system package manager, possibly "
772 | "rendering your system unusable."
773 | "It is recommended to use a virtual environment instead: "
774 | "https://pip.pypa.io/warnings/venv. "
775 | "Use the --root-user-action option if you know what you are doing and "
776 | "want to suppress this warning."
777 | )
778 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/version.py:
--------------------------------------------------------------------------------
```python
1 | # -*- coding: utf-8 -*-
2 | #
3 | # Copyright (C) 2012-2023 The Python Software Foundation.
4 | # See LICENSE.txt and CONTRIBUTORS.txt.
5 | #
6 | """
7 | Implementation of a flexible versioning scheme providing support for PEP-440,
8 | setuptools-compatible and semantic versioning.
9 | """
10 |
11 | import logging
12 | import re
13 |
14 | from .compat import string_types
15 | from .util import parse_requirement
16 |
17 | __all__ = ['NormalizedVersion', 'NormalizedMatcher',
18 | 'LegacyVersion', 'LegacyMatcher',
19 | 'SemanticVersion', 'SemanticMatcher',
20 | 'UnsupportedVersionError', 'get_scheme']
21 |
22 | logger = logging.getLogger(__name__)
23 |
24 |
25 | class UnsupportedVersionError(ValueError):
26 | """This is an unsupported version."""
27 | pass
28 |
29 |
30 | class Version(object):
31 | def __init__(self, s):
32 | self._string = s = s.strip()
33 | self._parts = parts = self.parse(s)
34 | assert isinstance(parts, tuple)
35 | assert len(parts) > 0
36 |
37 | def parse(self, s):
38 | raise NotImplementedError('please implement in a subclass')
39 |
40 | def _check_compatible(self, other):
41 | if type(self) != type(other):
42 | raise TypeError('cannot compare %r and %r' % (self, other))
43 |
44 | def __eq__(self, other):
45 | self._check_compatible(other)
46 | return self._parts == other._parts
47 |
48 | def __ne__(self, other):
49 | return not self.__eq__(other)
50 |
51 | def __lt__(self, other):
52 | self._check_compatible(other)
53 | return self._parts < other._parts
54 |
55 | def __gt__(self, other):
56 | return not (self.__lt__(other) or self.__eq__(other))
57 |
58 | def __le__(self, other):
59 | return self.__lt__(other) or self.__eq__(other)
60 |
61 | def __ge__(self, other):
62 | return self.__gt__(other) or self.__eq__(other)
63 |
64 | # See http://docs.python.org/reference/datamodel#object.__hash__
65 | def __hash__(self):
66 | return hash(self._parts)
67 |
68 | def __repr__(self):
69 | return "%s('%s')" % (self.__class__.__name__, self._string)
70 |
71 | def __str__(self):
72 | return self._string
73 |
74 | @property
75 | def is_prerelease(self):
76 | raise NotImplementedError('Please implement in subclasses.')
77 |
78 |
79 | class Matcher(object):
80 | version_class = None
81 |
82 | # value is either a callable or the name of a method
83 | _operators = {
84 | '<': lambda v, c, p: v < c,
85 | '>': lambda v, c, p: v > c,
86 | '<=': lambda v, c, p: v == c or v < c,
87 | '>=': lambda v, c, p: v == c or v > c,
88 | '==': lambda v, c, p: v == c,
89 | '===': lambda v, c, p: v == c,
90 | # by default, compatible => >=.
91 | '~=': lambda v, c, p: v == c or v > c,
92 | '!=': lambda v, c, p: v != c,
93 | }
94 |
95 | # this is a method only to support alternative implementations
96 | # via overriding
97 | def parse_requirement(self, s):
98 | return parse_requirement(s)
99 |
100 | def __init__(self, s):
101 | if self.version_class is None:
102 | raise ValueError('Please specify a version class')
103 | self._string = s = s.strip()
104 | r = self.parse_requirement(s)
105 | if not r:
106 | raise ValueError('Not valid: %r' % s)
107 | self.name = r.name
108 | self.key = self.name.lower() # for case-insensitive comparisons
109 | clist = []
110 | if r.constraints:
111 | # import pdb; pdb.set_trace()
112 | for op, s in r.constraints:
113 | if s.endswith('.*'):
114 | if op not in ('==', '!='):
115 | raise ValueError('\'.*\' not allowed for '
116 | '%r constraints' % op)
117 | # Could be a partial version (e.g. for '2.*') which
118 | # won't parse as a version, so keep it as a string
119 | vn, prefix = s[:-2], True
120 | # Just to check that vn is a valid version
121 | self.version_class(vn)
122 | else:
123 | # Should parse as a version, so we can create an
124 | # instance for the comparison
125 | vn, prefix = self.version_class(s), False
126 | clist.append((op, vn, prefix))
127 | self._parts = tuple(clist)
128 |
129 | def match(self, version):
130 | """
131 | Check if the provided version matches the constraints.
132 |
133 | :param version: The version to match against this instance.
134 | :type version: String or :class:`Version` instance.
135 | """
136 | if isinstance(version, string_types):
137 | version = self.version_class(version)
138 | for operator, constraint, prefix in self._parts:
139 | f = self._operators.get(operator)
140 | if isinstance(f, string_types):
141 | f = getattr(self, f)
142 | if not f:
143 | msg = ('%r not implemented '
144 | 'for %s' % (operator, self.__class__.__name__))
145 | raise NotImplementedError(msg)
146 | if not f(version, constraint, prefix):
147 | return False
148 | return True
149 |
150 | @property
151 | def exact_version(self):
152 | result = None
153 | if len(self._parts) == 1 and self._parts[0][0] in ('==', '==='):
154 | result = self._parts[0][1]
155 | return result
156 |
157 | def _check_compatible(self, other):
158 | if type(self) != type(other) or self.name != other.name:
159 | raise TypeError('cannot compare %s and %s' % (self, other))
160 |
161 | def __eq__(self, other):
162 | self._check_compatible(other)
163 | return self.key == other.key and self._parts == other._parts
164 |
165 | def __ne__(self, other):
166 | return not self.__eq__(other)
167 |
168 | # See http://docs.python.org/reference/datamodel#object.__hash__
169 | def __hash__(self):
170 | return hash(self.key) + hash(self._parts)
171 |
172 | def __repr__(self):
173 | return "%s(%r)" % (self.__class__.__name__, self._string)
174 |
175 | def __str__(self):
176 | return self._string
177 |
178 |
179 | PEP440_VERSION_RE = re.compile(r'^v?(\d+!)?(\d+(\.\d+)*)((a|alpha|b|beta|c|rc|pre|preview)(\d+)?)?'
180 | r'(\.(post|r|rev)(\d+)?)?([._-]?(dev)(\d+)?)?'
181 | r'(\+([a-zA-Z\d]+(\.[a-zA-Z\d]+)?))?$', re.I)
182 |
183 |
184 | def _pep_440_key(s):
185 | s = s.strip()
186 | m = PEP440_VERSION_RE.match(s)
187 | if not m:
188 | raise UnsupportedVersionError('Not a valid version: %s' % s)
189 | groups = m.groups()
190 | nums = tuple(int(v) for v in groups[1].split('.'))
191 | while len(nums) > 1 and nums[-1] == 0:
192 | nums = nums[:-1]
193 |
194 | if not groups[0]:
195 | epoch = 0
196 | else:
197 | epoch = int(groups[0][:-1])
198 | pre = groups[4:6]
199 | post = groups[7:9]
200 | dev = groups[10:12]
201 | local = groups[13]
202 | if pre == (None, None):
203 | pre = ()
204 | else:
205 | if pre[1] is None:
206 | pre = pre[0], 0
207 | else:
208 | pre = pre[0], int(pre[1])
209 | if post == (None, None):
210 | post = ()
211 | else:
212 | if post[1] is None:
213 | post = post[0], 0
214 | else:
215 | post = post[0], int(post[1])
216 | if dev == (None, None):
217 | dev = ()
218 | else:
219 | if dev[1] is None:
220 | dev = dev[0], 0
221 | else:
222 | dev = dev[0], int(dev[1])
223 | if local is None:
224 | local = ()
225 | else:
226 | parts = []
227 | for part in local.split('.'):
228 | # to ensure that numeric compares as > lexicographic, avoid
229 | # comparing them directly, but encode a tuple which ensures
230 | # correct sorting
231 | if part.isdigit():
232 | part = (1, int(part))
233 | else:
234 | part = (0, part)
235 | parts.append(part)
236 | local = tuple(parts)
237 | if not pre:
238 | # either before pre-release, or final release and after
239 | if not post and dev:
240 | # before pre-release
241 | pre = ('a', -1) # to sort before a0
242 | else:
243 | pre = ('z',) # to sort after all pre-releases
244 | # now look at the state of post and dev.
245 | if not post:
246 | post = ('_',) # sort before 'a'
247 | if not dev:
248 | dev = ('final',)
249 |
250 | return epoch, nums, pre, post, dev, local
251 |
252 |
253 | _normalized_key = _pep_440_key
254 |
255 |
256 | class NormalizedVersion(Version):
257 | """A rational version.
258 |
259 | Good:
260 | 1.2 # equivalent to "1.2.0"
261 | 1.2.0
262 | 1.2a1
263 | 1.2.3a2
264 | 1.2.3b1
265 | 1.2.3c1
266 | 1.2.3.4
267 | TODO: fill this out
268 |
269 | Bad:
270 | 1 # minimum two numbers
271 | 1.2a # release level must have a release serial
272 | 1.2.3b
273 | """
274 | def parse(self, s):
275 | result = _normalized_key(s)
276 | # _normalized_key loses trailing zeroes in the release
277 | # clause, since that's needed to ensure that X.Y == X.Y.0 == X.Y.0.0
278 | # However, PEP 440 prefix matching needs it: for example,
279 | # (~= 1.4.5.0) matches differently to (~= 1.4.5.0.0).
280 | m = PEP440_VERSION_RE.match(s) # must succeed
281 | groups = m.groups()
282 | self._release_clause = tuple(int(v) for v in groups[1].split('.'))
283 | return result
284 |
285 | PREREL_TAGS = set(['a', 'b', 'c', 'rc', 'dev'])
286 |
287 | @property
288 | def is_prerelease(self):
289 | return any(t[0] in self.PREREL_TAGS for t in self._parts if t)
290 |
291 |
292 | def _match_prefix(x, y):
293 | x = str(x)
294 | y = str(y)
295 | if x == y:
296 | return True
297 | if not x.startswith(y):
298 | return False
299 | n = len(y)
300 | return x[n] == '.'
301 |
302 |
303 | class NormalizedMatcher(Matcher):
304 | version_class = NormalizedVersion
305 |
306 | # value is either a callable or the name of a method
307 | _operators = {
308 | '~=': '_match_compatible',
309 | '<': '_match_lt',
310 | '>': '_match_gt',
311 | '<=': '_match_le',
312 | '>=': '_match_ge',
313 | '==': '_match_eq',
314 | '===': '_match_arbitrary',
315 | '!=': '_match_ne',
316 | }
317 |
318 | def _adjust_local(self, version, constraint, prefix):
319 | if prefix:
320 | strip_local = '+' not in constraint and version._parts[-1]
321 | else:
322 | # both constraint and version are
323 | # NormalizedVersion instances.
324 | # If constraint does not have a local component,
325 | # ensure the version doesn't, either.
326 | strip_local = not constraint._parts[-1] and version._parts[-1]
327 | if strip_local:
328 | s = version._string.split('+', 1)[0]
329 | version = self.version_class(s)
330 | return version, constraint
331 |
332 | def _match_lt(self, version, constraint, prefix):
333 | version, constraint = self._adjust_local(version, constraint, prefix)
334 | if version >= constraint:
335 | return False
336 | release_clause = constraint._release_clause
337 | pfx = '.'.join([str(i) for i in release_clause])
338 | return not _match_prefix(version, pfx)
339 |
340 | def _match_gt(self, version, constraint, prefix):
341 | version, constraint = self._adjust_local(version, constraint, prefix)
342 | if version <= constraint:
343 | return False
344 | release_clause = constraint._release_clause
345 | pfx = '.'.join([str(i) for i in release_clause])
346 | return not _match_prefix(version, pfx)
347 |
348 | def _match_le(self, version, constraint, prefix):
349 | version, constraint = self._adjust_local(version, constraint, prefix)
350 | return version <= constraint
351 |
352 | def _match_ge(self, version, constraint, prefix):
353 | version, constraint = self._adjust_local(version, constraint, prefix)
354 | return version >= constraint
355 |
356 | def _match_eq(self, version, constraint, prefix):
357 | version, constraint = self._adjust_local(version, constraint, prefix)
358 | if not prefix:
359 | result = (version == constraint)
360 | else:
361 | result = _match_prefix(version, constraint)
362 | return result
363 |
364 | def _match_arbitrary(self, version, constraint, prefix):
365 | return str(version) == str(constraint)
366 |
367 | def _match_ne(self, version, constraint, prefix):
368 | version, constraint = self._adjust_local(version, constraint, prefix)
369 | if not prefix:
370 | result = (version != constraint)
371 | else:
372 | result = not _match_prefix(version, constraint)
373 | return result
374 |
375 | def _match_compatible(self, version, constraint, prefix):
376 | version, constraint = self._adjust_local(version, constraint, prefix)
377 | if version == constraint:
378 | return True
379 | if version < constraint:
380 | return False
381 | # if not prefix:
382 | # return True
383 | release_clause = constraint._release_clause
384 | if len(release_clause) > 1:
385 | release_clause = release_clause[:-1]
386 | pfx = '.'.join([str(i) for i in release_clause])
387 | return _match_prefix(version, pfx)
388 |
389 |
390 | _REPLACEMENTS = (
391 | (re.compile('[.+-]$'), ''), # remove trailing puncts
392 | (re.compile(r'^[.](\d)'), r'0.\1'), # .N -> 0.N at start
393 | (re.compile('^[.-]'), ''), # remove leading puncts
394 | (re.compile(r'^\((.*)\)$'), r'\1'), # remove parentheses
395 | (re.compile(r'^v(ersion)?\s*(\d+)'), r'\2'), # remove leading v(ersion)
396 | (re.compile(r'^r(ev)?\s*(\d+)'), r'\2'), # remove leading v(ersion)
397 | (re.compile('[.]{2,}'), '.'), # multiple runs of '.'
398 | (re.compile(r'\b(alfa|apha)\b'), 'alpha'), # misspelt alpha
399 | (re.compile(r'\b(pre-alpha|prealpha)\b'),
400 | 'pre.alpha'), # standardise
401 | (re.compile(r'\(beta\)$'), 'beta'), # remove parentheses
402 | )
403 |
404 | _SUFFIX_REPLACEMENTS = (
405 | (re.compile('^[:~._+-]+'), ''), # remove leading puncts
406 | (re.compile('[,*")([\\]]'), ''), # remove unwanted chars
407 | (re.compile('[~:+_ -]'), '.'), # replace illegal chars
408 | (re.compile('[.]{2,}'), '.'), # multiple runs of '.'
409 | (re.compile(r'\.$'), ''), # trailing '.'
410 | )
411 |
412 | _NUMERIC_PREFIX = re.compile(r'(\d+(\.\d+)*)')
413 |
414 |
415 | def _suggest_semantic_version(s):
416 | """
417 | Try to suggest a semantic form for a version for which
418 | _suggest_normalized_version couldn't come up with anything.
419 | """
420 | result = s.strip().lower()
421 | for pat, repl in _REPLACEMENTS:
422 | result = pat.sub(repl, result)
423 | if not result:
424 | result = '0.0.0'
425 |
426 | # Now look for numeric prefix, and separate it out from
427 | # the rest.
428 | # import pdb; pdb.set_trace()
429 | m = _NUMERIC_PREFIX.match(result)
430 | if not m:
431 | prefix = '0.0.0'
432 | suffix = result
433 | else:
434 | prefix = m.groups()[0].split('.')
435 | prefix = [int(i) for i in prefix]
436 | while len(prefix) < 3:
437 | prefix.append(0)
438 | if len(prefix) == 3:
439 | suffix = result[m.end():]
440 | else:
441 | suffix = '.'.join([str(i) for i in prefix[3:]]) + result[m.end():]
442 | prefix = prefix[:3]
443 | prefix = '.'.join([str(i) for i in prefix])
444 | suffix = suffix.strip()
445 | if suffix:
446 | # import pdb; pdb.set_trace()
447 | # massage the suffix.
448 | for pat, repl in _SUFFIX_REPLACEMENTS:
449 | suffix = pat.sub(repl, suffix)
450 |
451 | if not suffix:
452 | result = prefix
453 | else:
454 | sep = '-' if 'dev' in suffix else '+'
455 | result = prefix + sep + suffix
456 | if not is_semver(result):
457 | result = None
458 | return result
459 |
460 |
461 | def _suggest_normalized_version(s):
462 | """Suggest a normalized version close to the given version string.
463 |
464 | If you have a version string that isn't rational (i.e. NormalizedVersion
465 | doesn't like it) then you might be able to get an equivalent (or close)
466 | rational version from this function.
467 |
468 | This does a number of simple normalizations to the given string, based
469 | on observation of versions currently in use on PyPI. Given a dump of
470 | those version during PyCon 2009, 4287 of them:
471 | - 2312 (53.93%) match NormalizedVersion without change
472 | with the automatic suggestion
473 | - 3474 (81.04%) match when using this suggestion method
474 |
475 | @param s {str} An irrational version string.
476 | @returns A rational version string, or None, if couldn't determine one.
477 | """
478 | try:
479 | _normalized_key(s)
480 | return s # already rational
481 | except UnsupportedVersionError:
482 | pass
483 |
484 | rs = s.lower()
485 |
486 | # part of this could use maketrans
487 | for orig, repl in (('-alpha', 'a'), ('-beta', 'b'), ('alpha', 'a'),
488 | ('beta', 'b'), ('rc', 'c'), ('-final', ''),
489 | ('-pre', 'c'),
490 | ('-release', ''), ('.release', ''), ('-stable', ''),
491 | ('+', '.'), ('_', '.'), (' ', ''), ('.final', ''),
492 | ('final', '')):
493 | rs = rs.replace(orig, repl)
494 |
495 | # if something ends with dev or pre, we add a 0
496 | rs = re.sub(r"pre$", r"pre0", rs)
497 | rs = re.sub(r"dev$", r"dev0", rs)
498 |
499 | # if we have something like "b-2" or "a.2" at the end of the
500 | # version, that is probably beta, alpha, etc
501 | # let's remove the dash or dot
502 | rs = re.sub(r"([abc]|rc)[\-\.](\d+)$", r"\1\2", rs)
503 |
504 | # 1.0-dev-r371 -> 1.0.dev371
505 | # 0.1-dev-r79 -> 0.1.dev79
506 | rs = re.sub(r"[\-\.](dev)[\-\.]?r?(\d+)$", r".\1\2", rs)
507 |
508 | # Clean: 2.0.a.3, 2.0.b1, 0.9.0~c1
509 | rs = re.sub(r"[.~]?([abc])\.?", r"\1", rs)
510 |
511 | # Clean: v0.3, v1.0
512 | if rs.startswith('v'):
513 | rs = rs[1:]
514 |
515 | # Clean leading '0's on numbers.
516 | # TODO: unintended side-effect on, e.g., "2003.05.09"
517 | # PyPI stats: 77 (~2%) better
518 | rs = re.sub(r"\b0+(\d+)(?!\d)", r"\1", rs)
519 |
520 | # Clean a/b/c with no version. E.g. "1.0a" -> "1.0a0". Setuptools infers
521 | # zero.
522 | # PyPI stats: 245 (7.56%) better
523 | rs = re.sub(r"(\d+[abc])$", r"\g<1>0", rs)
524 |
525 | # the 'dev-rNNN' tag is a dev tag
526 | rs = re.sub(r"\.?(dev-r|dev\.r)\.?(\d+)$", r".dev\2", rs)
527 |
528 | # clean the - when used as a pre delimiter
529 | rs = re.sub(r"-(a|b|c)(\d+)$", r"\1\2", rs)
530 |
531 | # a terminal "dev" or "devel" can be changed into ".dev0"
532 | rs = re.sub(r"[\.\-](dev|devel)$", r".dev0", rs)
533 |
534 | # a terminal "dev" can be changed into ".dev0"
535 | rs = re.sub(r"(?![\.\-])dev$", r".dev0", rs)
536 |
537 | # a terminal "final" or "stable" can be removed
538 | rs = re.sub(r"(final|stable)$", "", rs)
539 |
540 | # The 'r' and the '-' tags are post release tags
541 | # 0.4a1.r10 -> 0.4a1.post10
542 | # 0.9.33-17222 -> 0.9.33.post17222
543 | # 0.9.33-r17222 -> 0.9.33.post17222
544 | rs = re.sub(r"\.?(r|-|-r)\.?(\d+)$", r".post\2", rs)
545 |
546 | # Clean 'r' instead of 'dev' usage:
547 | # 0.9.33+r17222 -> 0.9.33.dev17222
548 | # 1.0dev123 -> 1.0.dev123
549 | # 1.0.git123 -> 1.0.dev123
550 | # 1.0.bzr123 -> 1.0.dev123
551 | # 0.1a0dev.123 -> 0.1a0.dev123
552 | # PyPI stats: ~150 (~4%) better
553 | rs = re.sub(r"\.?(dev|git|bzr)\.?(\d+)$", r".dev\2", rs)
554 |
555 | # Clean '.pre' (normalized from '-pre' above) instead of 'c' usage:
556 | # 0.2.pre1 -> 0.2c1
557 | # 0.2-c1 -> 0.2c1
558 | # 1.0preview123 -> 1.0c123
559 | # PyPI stats: ~21 (0.62%) better
560 | rs = re.sub(r"\.?(pre|preview|-c)(\d+)$", r"c\g<2>", rs)
561 |
562 | # Tcl/Tk uses "px" for their post release markers
563 | rs = re.sub(r"p(\d+)$", r".post\1", rs)
564 |
565 | try:
566 | _normalized_key(rs)
567 | except UnsupportedVersionError:
568 | rs = None
569 | return rs
570 |
571 | #
572 | # Legacy version processing (distribute-compatible)
573 | #
574 |
575 |
576 | _VERSION_PART = re.compile(r'([a-z]+|\d+|[\.-])', re.I)
577 | _VERSION_REPLACE = {
578 | 'pre': 'c',
579 | 'preview': 'c',
580 | '-': 'final-',
581 | 'rc': 'c',
582 | 'dev': '@',
583 | '': None,
584 | '.': None,
585 | }
586 |
587 |
588 | def _legacy_key(s):
589 | def get_parts(s):
590 | result = []
591 | for p in _VERSION_PART.split(s.lower()):
592 | p = _VERSION_REPLACE.get(p, p)
593 | if p:
594 | if '0' <= p[:1] <= '9':
595 | p = p.zfill(8)
596 | else:
597 | p = '*' + p
598 | result.append(p)
599 | result.append('*final')
600 | return result
601 |
602 | result = []
603 | for p in get_parts(s):
604 | if p.startswith('*'):
605 | if p < '*final':
606 | while result and result[-1] == '*final-':
607 | result.pop()
608 | while result and result[-1] == '00000000':
609 | result.pop()
610 | result.append(p)
611 | return tuple(result)
612 |
613 |
614 | class LegacyVersion(Version):
615 | def parse(self, s):
616 | return _legacy_key(s)
617 |
618 | @property
619 | def is_prerelease(self):
620 | result = False
621 | for x in self._parts:
622 | if (isinstance(x, string_types) and x.startswith('*') and
623 | x < '*final'):
624 | result = True
625 | break
626 | return result
627 |
628 |
629 | class LegacyMatcher(Matcher):
630 | version_class = LegacyVersion
631 |
632 | _operators = dict(Matcher._operators)
633 | _operators['~='] = '_match_compatible'
634 |
635 | numeric_re = re.compile(r'^(\d+(\.\d+)*)')
636 |
637 | def _match_compatible(self, version, constraint, prefix):
638 | if version < constraint:
639 | return False
640 | m = self.numeric_re.match(str(constraint))
641 | if not m:
642 | logger.warning('Cannot compute compatible match for version %s '
643 | ' and constraint %s', version, constraint)
644 | return True
645 | s = m.groups()[0]
646 | if '.' in s:
647 | s = s.rsplit('.', 1)[0]
648 | return _match_prefix(version, s)
649 |
650 | #
651 | # Semantic versioning
652 | #
653 |
654 |
655 | _SEMVER_RE = re.compile(r'^(\d+)\.(\d+)\.(\d+)'
656 | r'(-[a-z0-9]+(\.[a-z0-9-]+)*)?'
657 | r'(\+[a-z0-9]+(\.[a-z0-9-]+)*)?$', re.I)
658 |
659 |
660 | def is_semver(s):
661 | return _SEMVER_RE.match(s)
662 |
663 |
664 | def _semantic_key(s):
665 | def make_tuple(s, absent):
666 | if s is None:
667 | result = (absent,)
668 | else:
669 | parts = s[1:].split('.')
670 | # We can't compare ints and strings on Python 3, so fudge it
671 | # by zero-filling numeric values so simulate a numeric comparison
672 | result = tuple([p.zfill(8) if p.isdigit() else p for p in parts])
673 | return result
674 |
675 | m = is_semver(s)
676 | if not m:
677 | raise UnsupportedVersionError(s)
678 | groups = m.groups()
679 | major, minor, patch = [int(i) for i in groups[:3]]
680 | # choose the '|' and '*' so that versions sort correctly
681 | pre, build = make_tuple(groups[3], '|'), make_tuple(groups[5], '*')
682 | return (major, minor, patch), pre, build
683 |
684 |
685 | class SemanticVersion(Version):
686 | def parse(self, s):
687 | return _semantic_key(s)
688 |
689 | @property
690 | def is_prerelease(self):
691 | return self._parts[1][0] != '|'
692 |
693 |
694 | class SemanticMatcher(Matcher):
695 | version_class = SemanticVersion
696 |
697 |
698 | class VersionScheme(object):
699 | def __init__(self, key, matcher, suggester=None):
700 | self.key = key
701 | self.matcher = matcher
702 | self.suggester = suggester
703 |
704 | def is_valid_version(self, s):
705 | try:
706 | self.matcher.version_class(s)
707 | result = True
708 | except UnsupportedVersionError:
709 | result = False
710 | return result
711 |
712 | def is_valid_matcher(self, s):
713 | try:
714 | self.matcher(s)
715 | result = True
716 | except UnsupportedVersionError:
717 | result = False
718 | return result
719 |
720 | def is_valid_constraint_list(self, s):
721 | """
722 | Used for processing some metadata fields
723 | """
724 | # See issue #140. Be tolerant of a single trailing comma.
725 | if s.endswith(','):
726 | s = s[:-1]
727 | return self.is_valid_matcher('dummy_name (%s)' % s)
728 |
729 | def suggest(self, s):
730 | if self.suggester is None:
731 | result = None
732 | else:
733 | result = self.suggester(s)
734 | return result
735 |
736 |
737 | _SCHEMES = {
738 | 'normalized': VersionScheme(_normalized_key, NormalizedMatcher,
739 | _suggest_normalized_version),
740 | 'legacy': VersionScheme(_legacy_key, LegacyMatcher, lambda self, s: s),
741 | 'semantic': VersionScheme(_semantic_key, SemanticMatcher,
742 | _suggest_semantic_version),
743 | }
744 |
745 | _SCHEMES['default'] = _SCHEMES['normalized']
746 |
747 |
748 | def get_scheme(name):
749 | if name not in _SCHEMES:
750 | raise ValueError('unknown scheme name: %r' % name)
751 | return _SCHEMES[name]
752 |
```