This is page 66 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/bs4/builder/_html5lib.py:
--------------------------------------------------------------------------------
```python
1 | # Use of this source code is governed by the MIT license.
2 | __license__ = "MIT"
3 |
4 | __all__ = [
5 | 'HTML5TreeBuilder',
6 | ]
7 |
8 | import warnings
9 | import re
10 | from bs4.builder import (
11 | DetectsXMLParsedAsHTML,
12 | PERMISSIVE,
13 | HTML,
14 | HTML_5,
15 | HTMLTreeBuilder,
16 | )
17 | from bs4.element import (
18 | NamespacedAttribute,
19 | nonwhitespace_re,
20 | )
21 | import html5lib
22 | from html5lib.constants import (
23 | namespaces,
24 | prefixes,
25 | )
26 | from bs4.element import (
27 | Comment,
28 | Doctype,
29 | NavigableString,
30 | Tag,
31 | )
32 |
33 | try:
34 | # Pre-0.99999999
35 | from html5lib.treebuilders import _base as treebuilder_base
36 | new_html5lib = False
37 | except ImportError as e:
38 | # 0.99999999 and up
39 | from html5lib.treebuilders import base as treebuilder_base
40 | new_html5lib = True
41 |
42 | class HTML5TreeBuilder(HTMLTreeBuilder):
43 | """Use html5lib to build a tree.
44 |
45 | Note that this TreeBuilder does not support some features common
46 | to HTML TreeBuilders. Some of these features could theoretically
47 | be implemented, but at the very least it's quite difficult,
48 | because html5lib moves the parse tree around as it's being built.
49 |
50 | * This TreeBuilder doesn't use different subclasses of NavigableString
51 | based on the name of the tag in which the string was found.
52 |
53 | * You can't use a SoupStrainer to parse only part of a document.
54 | """
55 |
56 | NAME = "html5lib"
57 |
58 | features = [NAME, PERMISSIVE, HTML_5, HTML]
59 |
60 | # html5lib can tell us which line number and position in the
61 | # original file is the source of an element.
62 | TRACKS_LINE_NUMBERS = True
63 |
64 | def prepare_markup(self, markup, user_specified_encoding,
65 | document_declared_encoding=None, exclude_encodings=None):
66 | # Store the user-specified encoding for use later on.
67 | self.user_specified_encoding = user_specified_encoding
68 |
69 | # document_declared_encoding and exclude_encodings aren't used
70 | # ATM because the html5lib TreeBuilder doesn't use
71 | # UnicodeDammit.
72 | if exclude_encodings:
73 | warnings.warn(
74 | "You provided a value for exclude_encoding, but the html5lib tree builder doesn't support exclude_encoding.",
75 | stacklevel=3
76 | )
77 |
78 | # html5lib only parses HTML, so if it's given XML that's worth
79 | # noting.
80 | DetectsXMLParsedAsHTML.warn_if_markup_looks_like_xml(
81 | markup, stacklevel=3
82 | )
83 |
84 | yield (markup, None, None, False)
85 |
86 | # These methods are defined by Beautiful Soup.
87 | def feed(self, markup):
88 | if self.soup.parse_only is not None:
89 | warnings.warn(
90 | "You provided a value for parse_only, but the html5lib tree builder doesn't support parse_only. The entire document will be parsed.",
91 | stacklevel=4
92 | )
93 | parser = html5lib.HTMLParser(tree=self.create_treebuilder)
94 | self.underlying_builder.parser = parser
95 | extra_kwargs = dict()
96 | if not isinstance(markup, str):
97 | if new_html5lib:
98 | extra_kwargs['override_encoding'] = self.user_specified_encoding
99 | else:
100 | extra_kwargs['encoding'] = self.user_specified_encoding
101 | doc = parser.parse(markup, **extra_kwargs)
102 |
103 | # Set the character encoding detected by the tokenizer.
104 | if isinstance(markup, str):
105 | # We need to special-case this because html5lib sets
106 | # charEncoding to UTF-8 if it gets Unicode input.
107 | doc.original_encoding = None
108 | else:
109 | original_encoding = parser.tokenizer.stream.charEncoding[0]
110 | if not isinstance(original_encoding, str):
111 | # In 0.99999999 and up, the encoding is an html5lib
112 | # Encoding object. We want to use a string for compatibility
113 | # with other tree builders.
114 | original_encoding = original_encoding.name
115 | doc.original_encoding = original_encoding
116 | self.underlying_builder.parser = None
117 |
118 | def create_treebuilder(self, namespaceHTMLElements):
119 | self.underlying_builder = TreeBuilderForHtml5lib(
120 | namespaceHTMLElements, self.soup,
121 | store_line_numbers=self.store_line_numbers
122 | )
123 | return self.underlying_builder
124 |
125 | def test_fragment_to_document(self, fragment):
126 | """See `TreeBuilder`."""
127 | return '<html><head></head><body>%s</body></html>' % fragment
128 |
129 |
130 | class TreeBuilderForHtml5lib(treebuilder_base.TreeBuilder):
131 |
132 | def __init__(self, namespaceHTMLElements, soup=None,
133 | store_line_numbers=True, **kwargs):
134 | if soup:
135 | self.soup = soup
136 | else:
137 | from bs4 import BeautifulSoup
138 | # TODO: Why is the parser 'html.parser' here? To avoid an
139 | # infinite loop?
140 | self.soup = BeautifulSoup(
141 | "", "html.parser", store_line_numbers=store_line_numbers,
142 | **kwargs
143 | )
144 | # TODO: What are **kwargs exactly? Should they be passed in
145 | # here in addition to/instead of being passed to the BeautifulSoup
146 | # constructor?
147 | super(TreeBuilderForHtml5lib, self).__init__(namespaceHTMLElements)
148 |
149 | # This will be set later to an html5lib.html5parser.HTMLParser
150 | # object, which we can use to track the current line number.
151 | self.parser = None
152 | self.store_line_numbers = store_line_numbers
153 |
154 | def documentClass(self):
155 | self.soup.reset()
156 | return Element(self.soup, self.soup, None)
157 |
158 | def insertDoctype(self, token):
159 | name = token["name"]
160 | publicId = token["publicId"]
161 | systemId = token["systemId"]
162 |
163 | doctype = Doctype.for_name_and_ids(name, publicId, systemId)
164 | self.soup.object_was_parsed(doctype)
165 |
166 | def elementClass(self, name, namespace):
167 | kwargs = {}
168 | if self.parser and self.store_line_numbers:
169 | # This represents the point immediately after the end of the
170 | # tag. We don't know when the tag started, but we do know
171 | # where it ended -- the character just before this one.
172 | sourceline, sourcepos = self.parser.tokenizer.stream.position()
173 | kwargs['sourceline'] = sourceline
174 | kwargs['sourcepos'] = sourcepos-1
175 | tag = self.soup.new_tag(name, namespace, **kwargs)
176 |
177 | return Element(tag, self.soup, namespace)
178 |
179 | def commentClass(self, data):
180 | return TextNode(Comment(data), self.soup)
181 |
182 | def fragmentClass(self):
183 | from bs4 import BeautifulSoup
184 | # TODO: Why is the parser 'html.parser' here? To avoid an
185 | # infinite loop?
186 | self.soup = BeautifulSoup("", "html.parser")
187 | self.soup.name = "[document_fragment]"
188 | return Element(self.soup, self.soup, None)
189 |
190 | def appendChild(self, node):
191 | # XXX This code is not covered by the BS4 tests.
192 | self.soup.append(node.element)
193 |
194 | def getDocument(self):
195 | return self.soup
196 |
197 | def getFragment(self):
198 | return treebuilder_base.TreeBuilder.getFragment(self).element
199 |
200 | def testSerializer(self, element):
201 | from bs4 import BeautifulSoup
202 | rv = []
203 | doctype_re = re.compile(r'^(.*?)(?: PUBLIC "(.*?)"(?: "(.*?)")?| SYSTEM "(.*?)")?$')
204 |
205 | def serializeElement(element, indent=0):
206 | if isinstance(element, BeautifulSoup):
207 | pass
208 | if isinstance(element, Doctype):
209 | m = doctype_re.match(element)
210 | if m:
211 | name = m.group(1)
212 | if m.lastindex > 1:
213 | publicId = m.group(2) or ""
214 | systemId = m.group(3) or m.group(4) or ""
215 | rv.append("""|%s<!DOCTYPE %s "%s" "%s">""" %
216 | (' ' * indent, name, publicId, systemId))
217 | else:
218 | rv.append("|%s<!DOCTYPE %s>" % (' ' * indent, name))
219 | else:
220 | rv.append("|%s<!DOCTYPE >" % (' ' * indent,))
221 | elif isinstance(element, Comment):
222 | rv.append("|%s<!-- %s -->" % (' ' * indent, element))
223 | elif isinstance(element, NavigableString):
224 | rv.append("|%s\"%s\"" % (' ' * indent, element))
225 | else:
226 | if element.namespace:
227 | name = "%s %s" % (prefixes[element.namespace],
228 | element.name)
229 | else:
230 | name = element.name
231 | rv.append("|%s<%s>" % (' ' * indent, name))
232 | if element.attrs:
233 | attributes = []
234 | for name, value in list(element.attrs.items()):
235 | if isinstance(name, NamespacedAttribute):
236 | name = "%s %s" % (prefixes[name.namespace], name.name)
237 | if isinstance(value, list):
238 | value = " ".join(value)
239 | attributes.append((name, value))
240 |
241 | for name, value in sorted(attributes):
242 | rv.append('|%s%s="%s"' % (' ' * (indent + 2), name, value))
243 | indent += 2
244 | for child in element.children:
245 | serializeElement(child, indent)
246 | serializeElement(element, 0)
247 |
248 | return "\n".join(rv)
249 |
250 | class AttrList(object):
251 | def __init__(self, element):
252 | self.element = element
253 | self.attrs = dict(self.element.attrs)
254 | def __iter__(self):
255 | return list(self.attrs.items()).__iter__()
256 | def __setitem__(self, name, value):
257 | # If this attribute is a multi-valued attribute for this element,
258 | # turn its value into a list.
259 | list_attr = self.element.cdata_list_attributes or {}
260 | if (name in list_attr.get('*', [])
261 | or (self.element.name in list_attr
262 | and name in list_attr.get(self.element.name, []))):
263 | # A node that is being cloned may have already undergone
264 | # this procedure.
265 | if not isinstance(value, list):
266 | value = nonwhitespace_re.findall(value)
267 | self.element[name] = value
268 | def items(self):
269 | return list(self.attrs.items())
270 | def keys(self):
271 | return list(self.attrs.keys())
272 | def __len__(self):
273 | return len(self.attrs)
274 | def __getitem__(self, name):
275 | return self.attrs[name]
276 | def __contains__(self, name):
277 | return name in list(self.attrs.keys())
278 |
279 |
280 | class Element(treebuilder_base.Node):
281 | def __init__(self, element, soup, namespace):
282 | treebuilder_base.Node.__init__(self, element.name)
283 | self.element = element
284 | self.soup = soup
285 | self.namespace = namespace
286 |
287 | def appendChild(self, node):
288 | string_child = child = None
289 | if isinstance(node, str):
290 | # Some other piece of code decided to pass in a string
291 | # instead of creating a TextElement object to contain the
292 | # string.
293 | string_child = child = node
294 | elif isinstance(node, Tag):
295 | # Some other piece of code decided to pass in a Tag
296 | # instead of creating an Element object to contain the
297 | # Tag.
298 | child = node
299 | elif node.element.__class__ == NavigableString:
300 | string_child = child = node.element
301 | node.parent = self
302 | else:
303 | child = node.element
304 | node.parent = self
305 |
306 | if not isinstance(child, str) and child.parent is not None:
307 | node.element.extract()
308 |
309 | if (string_child is not None and self.element.contents
310 | and self.element.contents[-1].__class__ == NavigableString):
311 | # We are appending a string onto another string.
312 | # TODO This has O(n^2) performance, for input like
313 | # "a</a>a</a>a</a>..."
314 | old_element = self.element.contents[-1]
315 | new_element = self.soup.new_string(old_element + string_child)
316 | old_element.replace_with(new_element)
317 | self.soup._most_recent_element = new_element
318 | else:
319 | if isinstance(node, str):
320 | # Create a brand new NavigableString from this string.
321 | child = self.soup.new_string(node)
322 |
323 | # Tell Beautiful Soup to act as if it parsed this element
324 | # immediately after the parent's last descendant. (Or
325 | # immediately after the parent, if it has no children.)
326 | if self.element.contents:
327 | most_recent_element = self.element._last_descendant(False)
328 | elif self.element.next_element is not None:
329 | # Something from further ahead in the parse tree is
330 | # being inserted into this earlier element. This is
331 | # very annoying because it means an expensive search
332 | # for the last element in the tree.
333 | most_recent_element = self.soup._last_descendant()
334 | else:
335 | most_recent_element = self.element
336 |
337 | self.soup.object_was_parsed(
338 | child, parent=self.element,
339 | most_recent_element=most_recent_element)
340 |
341 | def getAttributes(self):
342 | if isinstance(self.element, Comment):
343 | return {}
344 | return AttrList(self.element)
345 |
346 | def setAttributes(self, attributes):
347 | if attributes is not None and len(attributes) > 0:
348 | converted_attributes = []
349 | for name, value in list(attributes.items()):
350 | if isinstance(name, tuple):
351 | new_name = NamespacedAttribute(*name)
352 | del attributes[name]
353 | attributes[new_name] = value
354 |
355 | self.soup.builder._replace_cdata_list_attribute_values(
356 | self.name, attributes)
357 | for name, value in list(attributes.items()):
358 | self.element[name] = value
359 |
360 | # The attributes may contain variables that need substitution.
361 | # Call set_up_substitutions manually.
362 | #
363 | # The Tag constructor called this method when the Tag was created,
364 | # but we just set/changed the attributes, so call it again.
365 | self.soup.builder.set_up_substitutions(self.element)
366 | attributes = property(getAttributes, setAttributes)
367 |
368 | def insertText(self, data, insertBefore=None):
369 | text = TextNode(self.soup.new_string(data), self.soup)
370 | if insertBefore:
371 | self.insertBefore(text, insertBefore)
372 | else:
373 | self.appendChild(text)
374 |
375 | def insertBefore(self, node, refNode):
376 | index = self.element.index(refNode.element)
377 | if (node.element.__class__ == NavigableString and self.element.contents
378 | and self.element.contents[index-1].__class__ == NavigableString):
379 | # (See comments in appendChild)
380 | old_node = self.element.contents[index-1]
381 | new_str = self.soup.new_string(old_node + node.element)
382 | old_node.replace_with(new_str)
383 | else:
384 | self.element.insert(index, node.element)
385 | node.parent = self
386 |
387 | def removeChild(self, node):
388 | node.element.extract()
389 |
390 | def reparentChildren(self, new_parent):
391 | """Move all of this tag's children into another tag."""
392 | # print("MOVE", self.element.contents)
393 | # print("FROM", self.element)
394 | # print("TO", new_parent.element)
395 |
396 | element = self.element
397 | new_parent_element = new_parent.element
398 | # Determine what this tag's next_element will be once all the children
399 | # are removed.
400 | final_next_element = element.next_sibling
401 |
402 | new_parents_last_descendant = new_parent_element._last_descendant(False, False)
403 | if len(new_parent_element.contents) > 0:
404 | # The new parent already contains children. We will be
405 | # appending this tag's children to the end.
406 | new_parents_last_child = new_parent_element.contents[-1]
407 | new_parents_last_descendant_next_element = new_parents_last_descendant.next_element
408 | else:
409 | # The new parent contains no children.
410 | new_parents_last_child = None
411 | new_parents_last_descendant_next_element = new_parent_element.next_element
412 |
413 | to_append = element.contents
414 | if len(to_append) > 0:
415 | # Set the first child's previous_element and previous_sibling
416 | # to elements within the new parent
417 | first_child = to_append[0]
418 | if new_parents_last_descendant is not None:
419 | first_child.previous_element = new_parents_last_descendant
420 | else:
421 | first_child.previous_element = new_parent_element
422 | first_child.previous_sibling = new_parents_last_child
423 | if new_parents_last_descendant is not None:
424 | new_parents_last_descendant.next_element = first_child
425 | else:
426 | new_parent_element.next_element = first_child
427 | if new_parents_last_child is not None:
428 | new_parents_last_child.next_sibling = first_child
429 |
430 | # Find the very last element being moved. It is now the
431 | # parent's last descendant. It has no .next_sibling and
432 | # its .next_element is whatever the previous last
433 | # descendant had.
434 | last_childs_last_descendant = to_append[-1]._last_descendant(False, True)
435 |
436 | last_childs_last_descendant.next_element = new_parents_last_descendant_next_element
437 | if new_parents_last_descendant_next_element is not None:
438 | # TODO: This code has no test coverage and I'm not sure
439 | # how to get html5lib to go through this path, but it's
440 | # just the other side of the previous line.
441 | new_parents_last_descendant_next_element.previous_element = last_childs_last_descendant
442 | last_childs_last_descendant.next_sibling = None
443 |
444 | for child in to_append:
445 | child.parent = new_parent_element
446 | new_parent_element.contents.append(child)
447 |
448 | # Now that this element has no children, change its .next_element.
449 | element.contents = []
450 | element.next_element = final_next_element
451 |
452 | # print("DONE WITH MOVE")
453 | # print("FROM", self.element)
454 | # print("TO", new_parent_element)
455 |
456 | def cloneNode(self):
457 | tag = self.soup.new_tag(self.element.name, self.namespace)
458 | node = Element(tag, self.soup, self.namespace)
459 | for key,value in self.attributes:
460 | node.attributes[key] = value
461 | return node
462 |
463 | def hasContent(self):
464 | return self.element.contents
465 |
466 | def getNameTuple(self):
467 | if self.namespace == None:
468 | return namespaces["html"], self.name
469 | else:
470 | return self.namespace, self.name
471 |
472 | nameTuple = property(getNameTuple)
473 |
474 | class TextNode(Element):
475 | def __init__(self, element, soup):
476 | treebuilder_base.Node.__init__(self, None)
477 | self.element = element
478 | self.soup = soup
479 |
480 | def cloneNode(self):
481 | raise NotImplementedError
482 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/urllib3/util/ssl_.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import hashlib
4 | import hmac
5 | import os
6 | import socket
7 | import sys
8 | import typing
9 | import warnings
10 | from binascii import unhexlify
11 |
12 | from ..exceptions import ProxySchemeUnsupported, SSLError
13 | from .url import _BRACELESS_IPV6_ADDRZ_RE, _IPV4_RE
14 |
15 | SSLContext = None
16 | SSLTransport = None
17 | HAS_NEVER_CHECK_COMMON_NAME = False
18 | IS_PYOPENSSL = False
19 | ALPN_PROTOCOLS = ["http/1.1"]
20 |
21 | _TYPE_VERSION_INFO = typing.Tuple[int, int, int, str, int]
22 |
23 | # Maps the length of a digest to a possible hash function producing this digest
24 | HASHFUNC_MAP = {
25 | length: getattr(hashlib, algorithm, None)
26 | for length, algorithm in ((32, "md5"), (40, "sha1"), (64, "sha256"))
27 | }
28 |
29 |
30 | def _is_bpo_43522_fixed(
31 | implementation_name: str,
32 | version_info: _TYPE_VERSION_INFO,
33 | pypy_version_info: _TYPE_VERSION_INFO | None,
34 | ) -> bool:
35 | """Return True for CPython 3.8.9+, 3.9.3+ or 3.10+ and PyPy 7.3.8+ where
36 | setting SSLContext.hostname_checks_common_name to False works.
37 |
38 | Outside of CPython and PyPy we don't know which implementations work
39 | or not so we conservatively use our hostname matching as we know that works
40 | on all implementations.
41 |
42 | https://github.com/urllib3/urllib3/issues/2192#issuecomment-821832963
43 | https://foss.heptapod.net/pypy/pypy/-/issues/3539
44 | """
45 | if implementation_name == "pypy":
46 | # https://foss.heptapod.net/pypy/pypy/-/issues/3129
47 | return pypy_version_info >= (7, 3, 8) # type: ignore[operator]
48 | elif implementation_name == "cpython":
49 | major_minor = version_info[:2]
50 | micro = version_info[2]
51 | return (
52 | (major_minor == (3, 8) and micro >= 9)
53 | or (major_minor == (3, 9) and micro >= 3)
54 | or major_minor >= (3, 10)
55 | )
56 | else: # Defensive:
57 | return False
58 |
59 |
60 | def _is_has_never_check_common_name_reliable(
61 | openssl_version: str,
62 | openssl_version_number: int,
63 | implementation_name: str,
64 | version_info: _TYPE_VERSION_INFO,
65 | pypy_version_info: _TYPE_VERSION_INFO | None,
66 | ) -> bool:
67 | # As of May 2023, all released versions of LibreSSL fail to reject certificates with
68 | # only common names, see https://github.com/urllib3/urllib3/pull/3024
69 | is_openssl = openssl_version.startswith("OpenSSL ")
70 | # Before fixing OpenSSL issue #14579, the SSL_new() API was not copying hostflags
71 | # like X509_CHECK_FLAG_NEVER_CHECK_SUBJECT, which tripped up CPython.
72 | # https://github.com/openssl/openssl/issues/14579
73 | # This was released in OpenSSL 1.1.1l+ (>=0x101010cf)
74 | is_openssl_issue_14579_fixed = openssl_version_number >= 0x101010CF
75 |
76 | return is_openssl and (
77 | is_openssl_issue_14579_fixed
78 | or _is_bpo_43522_fixed(implementation_name, version_info, pypy_version_info)
79 | )
80 |
81 |
82 | if typing.TYPE_CHECKING:
83 | from ssl import VerifyMode
84 | from typing import TypedDict
85 |
86 | from .ssltransport import SSLTransport as SSLTransportType
87 |
88 | class _TYPE_PEER_CERT_RET_DICT(TypedDict, total=False):
89 | subjectAltName: tuple[tuple[str, str], ...]
90 | subject: tuple[tuple[tuple[str, str], ...], ...]
91 | serialNumber: str
92 |
93 |
94 | # Mapping from 'ssl.PROTOCOL_TLSX' to 'TLSVersion.X'
95 | _SSL_VERSION_TO_TLS_VERSION: dict[int, int] = {}
96 |
97 | try: # Do we have ssl at all?
98 | import ssl
99 | from ssl import ( # type: ignore[assignment]
100 | CERT_REQUIRED,
101 | HAS_NEVER_CHECK_COMMON_NAME,
102 | OP_NO_COMPRESSION,
103 | OP_NO_TICKET,
104 | OPENSSL_VERSION,
105 | OPENSSL_VERSION_NUMBER,
106 | PROTOCOL_TLS,
107 | PROTOCOL_TLS_CLIENT,
108 | OP_NO_SSLv2,
109 | OP_NO_SSLv3,
110 | SSLContext,
111 | TLSVersion,
112 | )
113 |
114 | PROTOCOL_SSLv23 = PROTOCOL_TLS
115 |
116 | # Setting SSLContext.hostname_checks_common_name = False didn't work before CPython
117 | # 3.8.9, 3.9.3, and 3.10 (but OK on PyPy) or OpenSSL 1.1.1l+
118 | if HAS_NEVER_CHECK_COMMON_NAME and not _is_has_never_check_common_name_reliable(
119 | OPENSSL_VERSION,
120 | OPENSSL_VERSION_NUMBER,
121 | sys.implementation.name,
122 | sys.version_info,
123 | sys.pypy_version_info if sys.implementation.name == "pypy" else None, # type: ignore[attr-defined]
124 | ):
125 | HAS_NEVER_CHECK_COMMON_NAME = False
126 |
127 | # Need to be careful here in case old TLS versions get
128 | # removed in future 'ssl' module implementations.
129 | for attr in ("TLSv1", "TLSv1_1", "TLSv1_2"):
130 | try:
131 | _SSL_VERSION_TO_TLS_VERSION[getattr(ssl, f"PROTOCOL_{attr}")] = getattr(
132 | TLSVersion, attr
133 | )
134 | except AttributeError: # Defensive:
135 | continue
136 |
137 | from .ssltransport import SSLTransport # type: ignore[assignment]
138 | except ImportError:
139 | OP_NO_COMPRESSION = 0x20000 # type: ignore[assignment]
140 | OP_NO_TICKET = 0x4000 # type: ignore[assignment]
141 | OP_NO_SSLv2 = 0x1000000 # type: ignore[assignment]
142 | OP_NO_SSLv3 = 0x2000000 # type: ignore[assignment]
143 | PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 # type: ignore[assignment]
144 | PROTOCOL_TLS_CLIENT = 16 # type: ignore[assignment]
145 |
146 |
147 | _TYPE_PEER_CERT_RET = typing.Union["_TYPE_PEER_CERT_RET_DICT", bytes, None]
148 |
149 |
150 | def assert_fingerprint(cert: bytes | None, fingerprint: str) -> None:
151 | """
152 | Checks if given fingerprint matches the supplied certificate.
153 |
154 | :param cert:
155 | Certificate as bytes object.
156 | :param fingerprint:
157 | Fingerprint as string of hexdigits, can be interspersed by colons.
158 | """
159 |
160 | if cert is None:
161 | raise SSLError("No certificate for the peer.")
162 |
163 | fingerprint = fingerprint.replace(":", "").lower()
164 | digest_length = len(fingerprint)
165 | if digest_length not in HASHFUNC_MAP:
166 | raise SSLError(f"Fingerprint of invalid length: {fingerprint}")
167 | hashfunc = HASHFUNC_MAP.get(digest_length)
168 | if hashfunc is None:
169 | raise SSLError(
170 | f"Hash function implementation unavailable for fingerprint length: {digest_length}"
171 | )
172 |
173 | # We need encode() here for py32; works on py2 and p33.
174 | fingerprint_bytes = unhexlify(fingerprint.encode())
175 |
176 | cert_digest = hashfunc(cert).digest()
177 |
178 | if not hmac.compare_digest(cert_digest, fingerprint_bytes):
179 | raise SSLError(
180 | f'Fingerprints did not match. Expected "{fingerprint}", got "{cert_digest.hex()}"'
181 | )
182 |
183 |
184 | def resolve_cert_reqs(candidate: None | int | str) -> VerifyMode:
185 | """
186 | Resolves the argument to a numeric constant, which can be passed to
187 | the wrap_socket function/method from the ssl module.
188 | Defaults to :data:`ssl.CERT_REQUIRED`.
189 | If given a string it is assumed to be the name of the constant in the
190 | :mod:`ssl` module or its abbreviation.
191 | (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
192 | If it's neither `None` nor a string we assume it is already the numeric
193 | constant which can directly be passed to wrap_socket.
194 | """
195 | if candidate is None:
196 | return CERT_REQUIRED
197 |
198 | if isinstance(candidate, str):
199 | res = getattr(ssl, candidate, None)
200 | if res is None:
201 | res = getattr(ssl, "CERT_" + candidate)
202 | return res # type: ignore[no-any-return]
203 |
204 | return candidate # type: ignore[return-value]
205 |
206 |
207 | def resolve_ssl_version(candidate: None | int | str) -> int:
208 | """
209 | like resolve_cert_reqs
210 | """
211 | if candidate is None:
212 | return PROTOCOL_TLS
213 |
214 | if isinstance(candidate, str):
215 | res = getattr(ssl, candidate, None)
216 | if res is None:
217 | res = getattr(ssl, "PROTOCOL_" + candidate)
218 | return typing.cast(int, res)
219 |
220 | return candidate
221 |
222 |
223 | def create_urllib3_context(
224 | ssl_version: int | None = None,
225 | cert_reqs: int | None = None,
226 | options: int | None = None,
227 | ciphers: str | None = None,
228 | ssl_minimum_version: int | None = None,
229 | ssl_maximum_version: int | None = None,
230 | ) -> ssl.SSLContext:
231 | """Creates and configures an :class:`ssl.SSLContext` instance for use with urllib3.
232 |
233 | :param ssl_version:
234 | The desired protocol version to use. This will default to
235 | PROTOCOL_SSLv23 which will negotiate the highest protocol that both
236 | the server and your installation of OpenSSL support.
237 |
238 | This parameter is deprecated instead use 'ssl_minimum_version'.
239 | :param ssl_minimum_version:
240 | The minimum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value.
241 | :param ssl_maximum_version:
242 | The maximum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value.
243 | Not recommended to set to anything other than 'ssl.TLSVersion.MAXIMUM_SUPPORTED' which is the
244 | default value.
245 | :param cert_reqs:
246 | Whether to require the certificate verification. This defaults to
247 | ``ssl.CERT_REQUIRED``.
248 | :param options:
249 | Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,
250 | ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``.
251 | :param ciphers:
252 | Which cipher suites to allow the server to select. Defaults to either system configured
253 | ciphers if OpenSSL 1.1.1+, otherwise uses a secure default set of ciphers.
254 | :returns:
255 | Constructed SSLContext object with specified options
256 | :rtype: SSLContext
257 | """
258 | if SSLContext is None:
259 | raise TypeError("Can't create an SSLContext object without an ssl module")
260 |
261 | # This means 'ssl_version' was specified as an exact value.
262 | if ssl_version not in (None, PROTOCOL_TLS, PROTOCOL_TLS_CLIENT):
263 | # Disallow setting 'ssl_version' and 'ssl_minimum|maximum_version'
264 | # to avoid conflicts.
265 | if ssl_minimum_version is not None or ssl_maximum_version is not None:
266 | raise ValueError(
267 | "Can't specify both 'ssl_version' and either "
268 | "'ssl_minimum_version' or 'ssl_maximum_version'"
269 | )
270 |
271 | # 'ssl_version' is deprecated and will be removed in the future.
272 | else:
273 | # Use 'ssl_minimum_version' and 'ssl_maximum_version' instead.
274 | ssl_minimum_version = _SSL_VERSION_TO_TLS_VERSION.get(
275 | ssl_version, TLSVersion.MINIMUM_SUPPORTED
276 | )
277 | ssl_maximum_version = _SSL_VERSION_TO_TLS_VERSION.get(
278 | ssl_version, TLSVersion.MAXIMUM_SUPPORTED
279 | )
280 |
281 | # This warning message is pushing users to use 'ssl_minimum_version'
282 | # instead of both min/max. Best practice is to only set the minimum version and
283 | # keep the maximum version to be it's default value: 'TLSVersion.MAXIMUM_SUPPORTED'
284 | warnings.warn(
285 | "'ssl_version' option is deprecated and will be "
286 | "removed in urllib3 v2.1.0. Instead use 'ssl_minimum_version'",
287 | category=DeprecationWarning,
288 | stacklevel=2,
289 | )
290 |
291 | # PROTOCOL_TLS is deprecated in Python 3.10 so we always use PROTOCOL_TLS_CLIENT
292 | context = SSLContext(PROTOCOL_TLS_CLIENT)
293 |
294 | if ssl_minimum_version is not None:
295 | context.minimum_version = ssl_minimum_version
296 | else: # Python <3.10 defaults to 'MINIMUM_SUPPORTED' so explicitly set TLSv1.2 here
297 | context.minimum_version = TLSVersion.TLSv1_2
298 |
299 | if ssl_maximum_version is not None:
300 | context.maximum_version = ssl_maximum_version
301 |
302 | # Unless we're given ciphers defer to either system ciphers in
303 | # the case of OpenSSL 1.1.1+ or use our own secure default ciphers.
304 | if ciphers:
305 | context.set_ciphers(ciphers)
306 |
307 | # Setting the default here, as we may have no ssl module on import
308 | cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs
309 |
310 | if options is None:
311 | options = 0
312 | # SSLv2 is easily broken and is considered harmful and dangerous
313 | options |= OP_NO_SSLv2
314 | # SSLv3 has several problems and is now dangerous
315 | options |= OP_NO_SSLv3
316 | # Disable compression to prevent CRIME attacks for OpenSSL 1.0+
317 | # (issue #309)
318 | options |= OP_NO_COMPRESSION
319 | # TLSv1.2 only. Unless set explicitly, do not request tickets.
320 | # This may save some bandwidth on wire, and although the ticket is encrypted,
321 | # there is a risk associated with it being on wire,
322 | # if the server is not rotating its ticketing keys properly.
323 | options |= OP_NO_TICKET
324 |
325 | context.options |= options
326 |
327 | # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
328 | # necessary for conditional client cert authentication with TLS 1.3.
329 | # The attribute is None for OpenSSL <= 1.1.0 or does not exist when using
330 | # an SSLContext created by pyOpenSSL.
331 | if getattr(context, "post_handshake_auth", None) is not None:
332 | context.post_handshake_auth = True
333 |
334 | # The order of the below lines setting verify_mode and check_hostname
335 | # matter due to safe-guards SSLContext has to prevent an SSLContext with
336 | # check_hostname=True, verify_mode=NONE/OPTIONAL.
337 | # We always set 'check_hostname=False' for pyOpenSSL so we rely on our own
338 | # 'ssl.match_hostname()' implementation.
339 | if cert_reqs == ssl.CERT_REQUIRED and not IS_PYOPENSSL:
340 | context.verify_mode = cert_reqs
341 | context.check_hostname = True
342 | else:
343 | context.check_hostname = False
344 | context.verify_mode = cert_reqs
345 |
346 | try:
347 | context.hostname_checks_common_name = False
348 | except AttributeError: # Defensive: for CPython < 3.8.9 and 3.9.3; for PyPy < 7.3.8
349 | pass
350 |
351 | # Enable logging of TLS session keys via defacto standard environment variable
352 | # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values.
353 | if hasattr(context, "keylog_filename"):
354 | sslkeylogfile = os.environ.get("SSLKEYLOGFILE")
355 | if sslkeylogfile:
356 | context.keylog_filename = sslkeylogfile
357 |
358 | return context
359 |
360 |
361 | @typing.overload
362 | def ssl_wrap_socket(
363 | sock: socket.socket,
364 | keyfile: str | None = ...,
365 | certfile: str | None = ...,
366 | cert_reqs: int | None = ...,
367 | ca_certs: str | None = ...,
368 | server_hostname: str | None = ...,
369 | ssl_version: int | None = ...,
370 | ciphers: str | None = ...,
371 | ssl_context: ssl.SSLContext | None = ...,
372 | ca_cert_dir: str | None = ...,
373 | key_password: str | None = ...,
374 | ca_cert_data: None | str | bytes = ...,
375 | tls_in_tls: typing.Literal[False] = ...,
376 | ) -> ssl.SSLSocket:
377 | ...
378 |
379 |
380 | @typing.overload
381 | def ssl_wrap_socket(
382 | sock: socket.socket,
383 | keyfile: str | None = ...,
384 | certfile: str | None = ...,
385 | cert_reqs: int | None = ...,
386 | ca_certs: str | None = ...,
387 | server_hostname: str | None = ...,
388 | ssl_version: int | None = ...,
389 | ciphers: str | None = ...,
390 | ssl_context: ssl.SSLContext | None = ...,
391 | ca_cert_dir: str | None = ...,
392 | key_password: str | None = ...,
393 | ca_cert_data: None | str | bytes = ...,
394 | tls_in_tls: bool = ...,
395 | ) -> ssl.SSLSocket | SSLTransportType:
396 | ...
397 |
398 |
399 | def ssl_wrap_socket(
400 | sock: socket.socket,
401 | keyfile: str | None = None,
402 | certfile: str | None = None,
403 | cert_reqs: int | None = None,
404 | ca_certs: str | None = None,
405 | server_hostname: str | None = None,
406 | ssl_version: int | None = None,
407 | ciphers: str | None = None,
408 | ssl_context: ssl.SSLContext | None = None,
409 | ca_cert_dir: str | None = None,
410 | key_password: str | None = None,
411 | ca_cert_data: None | str | bytes = None,
412 | tls_in_tls: bool = False,
413 | ) -> ssl.SSLSocket | SSLTransportType:
414 | """
415 | All arguments except for server_hostname, ssl_context, tls_in_tls, ca_cert_data and
416 | ca_cert_dir have the same meaning as they do when using
417 | :func:`ssl.create_default_context`, :meth:`ssl.SSLContext.load_cert_chain`,
418 | :meth:`ssl.SSLContext.set_ciphers` and :meth:`ssl.SSLContext.wrap_socket`.
419 |
420 | :param server_hostname:
421 | When SNI is supported, the expected hostname of the certificate
422 | :param ssl_context:
423 | A pre-made :class:`SSLContext` object. If none is provided, one will
424 | be created using :func:`create_urllib3_context`.
425 | :param ciphers:
426 | A string of ciphers we wish the client to support.
427 | :param ca_cert_dir:
428 | A directory containing CA certificates in multiple separate files, as
429 | supported by OpenSSL's -CApath flag or the capath argument to
430 | SSLContext.load_verify_locations().
431 | :param key_password:
432 | Optional password if the keyfile is encrypted.
433 | :param ca_cert_data:
434 | Optional string containing CA certificates in PEM format suitable for
435 | passing as the cadata parameter to SSLContext.load_verify_locations()
436 | :param tls_in_tls:
437 | Use SSLTransport to wrap the existing socket.
438 | """
439 | context = ssl_context
440 | if context is None:
441 | # Note: This branch of code and all the variables in it are only used in tests.
442 | # We should consider deprecating and removing this code.
443 | context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers)
444 |
445 | if ca_certs or ca_cert_dir or ca_cert_data:
446 | try:
447 | context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data)
448 | except OSError as e:
449 | raise SSLError(e) from e
450 |
451 | elif ssl_context is None and hasattr(context, "load_default_certs"):
452 | # try to load OS default certs; works well on Windows.
453 | context.load_default_certs()
454 |
455 | # Attempt to detect if we get the goofy behavior of the
456 | # keyfile being encrypted and OpenSSL asking for the
457 | # passphrase via the terminal and instead error out.
458 | if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
459 | raise SSLError("Client private key is encrypted, password is required")
460 |
461 | if certfile:
462 | if key_password is None:
463 | context.load_cert_chain(certfile, keyfile)
464 | else:
465 | context.load_cert_chain(certfile, keyfile, key_password)
466 |
467 | context.set_alpn_protocols(ALPN_PROTOCOLS)
468 |
469 | ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
470 | return ssl_sock
471 |
472 |
473 | def is_ipaddress(hostname: str | bytes) -> bool:
474 | """Detects whether the hostname given is an IPv4 or IPv6 address.
475 | Also detects IPv6 addresses with Zone IDs.
476 |
477 | :param str hostname: Hostname to examine.
478 | :return: True if the hostname is an IP address, False otherwise.
479 | """
480 | if isinstance(hostname, bytes):
481 | # IDN A-label bytes are ASCII compatible.
482 | hostname = hostname.decode("ascii")
483 | return bool(_IPV4_RE.match(hostname) or _BRACELESS_IPV6_ADDRZ_RE.match(hostname))
484 |
485 |
486 | def _is_key_file_encrypted(key_file: str) -> bool:
487 | """Detects if a key file is encrypted or not."""
488 | with open(key_file) as f:
489 | for line in f:
490 | # Look for Proc-Type: 4,ENCRYPTED
491 | if "ENCRYPTED" in line:
492 | return True
493 |
494 | return False
495 |
496 |
497 | def _ssl_wrap_socket_impl(
498 | sock: socket.socket,
499 | ssl_context: ssl.SSLContext,
500 | tls_in_tls: bool,
501 | server_hostname: str | None = None,
502 | ) -> ssl.SSLSocket | SSLTransportType:
503 | if tls_in_tls:
504 | if not SSLTransport:
505 | # Import error, ssl is not available.
506 | raise ProxySchemeUnsupported(
507 | "TLS in TLS requires support for the 'ssl' module"
508 | )
509 |
510 | SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context)
511 | return SSLTransport(sock, ssl_context, server_hostname)
512 |
513 | return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
514 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | pygments.formatters.latex
3 | ~~~~~~~~~~~~~~~~~~~~~~~~~
4 |
5 | Formatter for LaTeX fancyvrb output.
6 |
7 | :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS.
8 | :license: BSD, see LICENSE for details.
9 | """
10 |
11 | from io import StringIO
12 |
13 | from pip._vendor.pygments.formatter import Formatter
14 | from pip._vendor.pygments.lexer import Lexer, do_insertions
15 | from pip._vendor.pygments.token import Token, STANDARD_TYPES
16 | from pip._vendor.pygments.util import get_bool_opt, get_int_opt
17 |
18 |
19 | __all__ = ['LatexFormatter']
20 |
21 |
22 | def escape_tex(text, commandprefix):
23 | return text.replace('\\', '\x00'). \
24 | replace('{', '\x01'). \
25 | replace('}', '\x02'). \
26 | replace('\x00', rf'\{commandprefix}Zbs{{}}'). \
27 | replace('\x01', rf'\{commandprefix}Zob{{}}'). \
28 | replace('\x02', rf'\{commandprefix}Zcb{{}}'). \
29 | replace('^', rf'\{commandprefix}Zca{{}}'). \
30 | replace('_', rf'\{commandprefix}Zus{{}}'). \
31 | replace('&', rf'\{commandprefix}Zam{{}}'). \
32 | replace('<', rf'\{commandprefix}Zlt{{}}'). \
33 | replace('>', rf'\{commandprefix}Zgt{{}}'). \
34 | replace('#', rf'\{commandprefix}Zsh{{}}'). \
35 | replace('%', rf'\{commandprefix}Zpc{{}}'). \
36 | replace('$', rf'\{commandprefix}Zdl{{}}'). \
37 | replace('-', rf'\{commandprefix}Zhy{{}}'). \
38 | replace("'", rf'\{commandprefix}Zsq{{}}'). \
39 | replace('"', rf'\{commandprefix}Zdq{{}}'). \
40 | replace('~', rf'\{commandprefix}Zti{{}}')
41 |
42 |
43 | DOC_TEMPLATE = r'''
44 | \documentclass{%(docclass)s}
45 | \usepackage{fancyvrb}
46 | \usepackage{color}
47 | \usepackage[%(encoding)s]{inputenc}
48 | %(preamble)s
49 |
50 | %(styledefs)s
51 |
52 | \begin{document}
53 |
54 | \section*{%(title)s}
55 |
56 | %(code)s
57 | \end{document}
58 | '''
59 |
60 | ## Small explanation of the mess below :)
61 | #
62 | # The previous version of the LaTeX formatter just assigned a command to
63 | # each token type defined in the current style. That obviously is
64 | # problematic if the highlighted code is produced for a different style
65 | # than the style commands themselves.
66 | #
67 | # This version works much like the HTML formatter which assigns multiple
68 | # CSS classes to each <span> tag, from the most specific to the least
69 | # specific token type, thus falling back to the parent token type if one
70 | # is not defined. Here, the classes are there too and use the same short
71 | # forms given in token.STANDARD_TYPES.
72 | #
73 | # Highlighted code now only uses one custom command, which by default is
74 | # \PY and selectable by the commandprefix option (and in addition the
75 | # escapes \PYZat, \PYZlb and \PYZrb which haven't been renamed for
76 | # backwards compatibility purposes).
77 | #
78 | # \PY has two arguments: the classes, separated by +, and the text to
79 | # render in that style. The classes are resolved into the respective
80 | # style commands by magic, which serves to ignore unknown classes.
81 | #
82 | # The magic macros are:
83 | # * \PY@it, \PY@bf, etc. are unconditionally wrapped around the text
84 | # to render in \PY@do. Their definition determines the style.
85 | # * \PY@reset resets \PY@it etc. to do nothing.
86 | # * \PY@toks parses the list of classes, using magic inspired by the
87 | # keyval package (but modified to use plusses instead of commas
88 | # because fancyvrb redefines commas inside its environments).
89 | # * \PY@tok processes one class, calling the \PY@tok@classname command
90 | # if it exists.
91 | # * \PY@tok@classname sets the \PY@it etc. to reflect the chosen style
92 | # for its class.
93 | # * \PY resets the style, parses the classnames and then calls \PY@do.
94 | #
95 | # Tip: to read this code, print it out in substituted form using e.g.
96 | # >>> print STYLE_TEMPLATE % {'cp': 'PY'}
97 |
98 | STYLE_TEMPLATE = r'''
99 | \makeatletter
100 | \def\%(cp)s@reset{\let\%(cp)s@it=\relax \let\%(cp)s@bf=\relax%%
101 | \let\%(cp)s@ul=\relax \let\%(cp)s@tc=\relax%%
102 | \let\%(cp)s@bc=\relax \let\%(cp)s@ff=\relax}
103 | \def\%(cp)s@tok#1{\csname %(cp)s@tok@#1\endcsname}
104 | \def\%(cp)s@toks#1+{\ifx\relax#1\empty\else%%
105 | \%(cp)s@tok{#1}\expandafter\%(cp)s@toks\fi}
106 | \def\%(cp)s@do#1{\%(cp)s@bc{\%(cp)s@tc{\%(cp)s@ul{%%
107 | \%(cp)s@it{\%(cp)s@bf{\%(cp)s@ff{#1}}}}}}}
108 | \def\%(cp)s#1#2{\%(cp)s@reset\%(cp)s@toks#1+\relax+\%(cp)s@do{#2}}
109 |
110 | %(styles)s
111 |
112 | \def\%(cp)sZbs{\char`\\}
113 | \def\%(cp)sZus{\char`\_}
114 | \def\%(cp)sZob{\char`\{}
115 | \def\%(cp)sZcb{\char`\}}
116 | \def\%(cp)sZca{\char`\^}
117 | \def\%(cp)sZam{\char`\&}
118 | \def\%(cp)sZlt{\char`\<}
119 | \def\%(cp)sZgt{\char`\>}
120 | \def\%(cp)sZsh{\char`\#}
121 | \def\%(cp)sZpc{\char`\%%}
122 | \def\%(cp)sZdl{\char`\$}
123 | \def\%(cp)sZhy{\char`\-}
124 | \def\%(cp)sZsq{\char`\'}
125 | \def\%(cp)sZdq{\char`\"}
126 | \def\%(cp)sZti{\char`\~}
127 | %% for compatibility with earlier versions
128 | \def\%(cp)sZat{@}
129 | \def\%(cp)sZlb{[}
130 | \def\%(cp)sZrb{]}
131 | \makeatother
132 | '''
133 |
134 |
135 | def _get_ttype_name(ttype):
136 | fname = STANDARD_TYPES.get(ttype)
137 | if fname:
138 | return fname
139 | aname = ''
140 | while fname is None:
141 | aname = ttype[-1] + aname
142 | ttype = ttype.parent
143 | fname = STANDARD_TYPES.get(ttype)
144 | return fname + aname
145 |
146 |
147 | class LatexFormatter(Formatter):
148 | r"""
149 | Format tokens as LaTeX code. This needs the `fancyvrb` and `color`
150 | standard packages.
151 |
152 | Without the `full` option, code is formatted as one ``Verbatim``
153 | environment, like this:
154 |
155 | .. sourcecode:: latex
156 |
157 | \begin{Verbatim}[commandchars=\\\{\}]
158 | \PY{k}{def }\PY{n+nf}{foo}(\PY{n}{bar}):
159 | \PY{k}{pass}
160 | \end{Verbatim}
161 |
162 | Wrapping can be disabled using the `nowrap` option.
163 |
164 | The special command used here (``\PY``) and all the other macros it needs
165 | are output by the `get_style_defs` method.
166 |
167 | With the `full` option, a complete LaTeX document is output, including
168 | the command definitions in the preamble.
169 |
170 | The `get_style_defs()` method of a `LatexFormatter` returns a string
171 | containing ``\def`` commands defining the macros needed inside the
172 | ``Verbatim`` environments.
173 |
174 | Additional options accepted:
175 |
176 | `nowrap`
177 | If set to ``True``, don't wrap the tokens at all, not even inside a
178 | ``\begin{Verbatim}`` environment. This disables most other options
179 | (default: ``False``).
180 |
181 | `style`
182 | The style to use, can be a string or a Style subclass (default:
183 | ``'default'``).
184 |
185 | `full`
186 | Tells the formatter to output a "full" document, i.e. a complete
187 | self-contained document (default: ``False``).
188 |
189 | `title`
190 | If `full` is true, the title that should be used to caption the
191 | document (default: ``''``).
192 |
193 | `docclass`
194 | If the `full` option is enabled, this is the document class to use
195 | (default: ``'article'``).
196 |
197 | `preamble`
198 | If the `full` option is enabled, this can be further preamble commands,
199 | e.g. ``\usepackage`` (default: ``''``).
200 |
201 | `linenos`
202 | If set to ``True``, output line numbers (default: ``False``).
203 |
204 | `linenostart`
205 | The line number for the first line (default: ``1``).
206 |
207 | `linenostep`
208 | If set to a number n > 1, only every nth line number is printed.
209 |
210 | `verboptions`
211 | Additional options given to the Verbatim environment (see the *fancyvrb*
212 | docs for possible values) (default: ``''``).
213 |
214 | `commandprefix`
215 | The LaTeX commands used to produce colored output are constructed
216 | using this prefix and some letters (default: ``'PY'``).
217 |
218 | .. versionadded:: 0.7
219 | .. versionchanged:: 0.10
220 | The default is now ``'PY'`` instead of ``'C'``.
221 |
222 | `texcomments`
223 | If set to ``True``, enables LaTeX comment lines. That is, LaTex markup
224 | in comment tokens is not escaped so that LaTeX can render it (default:
225 | ``False``).
226 |
227 | .. versionadded:: 1.2
228 |
229 | `mathescape`
230 | If set to ``True``, enables LaTeX math mode escape in comments. That
231 | is, ``'$...$'`` inside a comment will trigger math mode (default:
232 | ``False``).
233 |
234 | .. versionadded:: 1.2
235 |
236 | `escapeinside`
237 | If set to a string of length 2, enables escaping to LaTeX. Text
238 | delimited by these 2 characters is read as LaTeX code and
239 | typeset accordingly. It has no effect in string literals. It has
240 | no effect in comments if `texcomments` or `mathescape` is
241 | set. (default: ``''``).
242 |
243 | .. versionadded:: 2.0
244 |
245 | `envname`
246 | Allows you to pick an alternative environment name replacing Verbatim.
247 | The alternate environment still has to support Verbatim's option syntax.
248 | (default: ``'Verbatim'``).
249 |
250 | .. versionadded:: 2.0
251 | """
252 | name = 'LaTeX'
253 | aliases = ['latex', 'tex']
254 | filenames = ['*.tex']
255 |
256 | def __init__(self, **options):
257 | Formatter.__init__(self, **options)
258 | self.nowrap = get_bool_opt(options, 'nowrap', False)
259 | self.docclass = options.get('docclass', 'article')
260 | self.preamble = options.get('preamble', '')
261 | self.linenos = get_bool_opt(options, 'linenos', False)
262 | self.linenostart = abs(get_int_opt(options, 'linenostart', 1))
263 | self.linenostep = abs(get_int_opt(options, 'linenostep', 1))
264 | self.verboptions = options.get('verboptions', '')
265 | self.nobackground = get_bool_opt(options, 'nobackground', False)
266 | self.commandprefix = options.get('commandprefix', 'PY')
267 | self.texcomments = get_bool_opt(options, 'texcomments', False)
268 | self.mathescape = get_bool_opt(options, 'mathescape', False)
269 | self.escapeinside = options.get('escapeinside', '')
270 | if len(self.escapeinside) == 2:
271 | self.left = self.escapeinside[0]
272 | self.right = self.escapeinside[1]
273 | else:
274 | self.escapeinside = ''
275 | self.envname = options.get('envname', 'Verbatim')
276 |
277 | self._create_stylesheet()
278 |
279 | def _create_stylesheet(self):
280 | t2n = self.ttype2name = {Token: ''}
281 | c2d = self.cmd2def = {}
282 | cp = self.commandprefix
283 |
284 | def rgbcolor(col):
285 | if col:
286 | return ','.join(['%.2f' % (int(col[i] + col[i + 1], 16) / 255.0)
287 | for i in (0, 2, 4)])
288 | else:
289 | return '1,1,1'
290 |
291 | for ttype, ndef in self.style:
292 | name = _get_ttype_name(ttype)
293 | cmndef = ''
294 | if ndef['bold']:
295 | cmndef += r'\let\$$@bf=\textbf'
296 | if ndef['italic']:
297 | cmndef += r'\let\$$@it=\textit'
298 | if ndef['underline']:
299 | cmndef += r'\let\$$@ul=\underline'
300 | if ndef['roman']:
301 | cmndef += r'\let\$$@ff=\textrm'
302 | if ndef['sans']:
303 | cmndef += r'\let\$$@ff=\textsf'
304 | if ndef['mono']:
305 | cmndef += r'\let\$$@ff=\textsf'
306 | if ndef['color']:
307 | cmndef += (r'\def\$$@tc##1{{\textcolor[rgb]{{{}}}{{##1}}}}'.format(rgbcolor(ndef['color'])))
308 | if ndef['border']:
309 | cmndef += (r'\def\$$@bc##1{{{{\setlength{{\fboxsep}}{{\string -\fboxrule}}'
310 | r'\fcolorbox[rgb]{{{}}}{{{}}}{{\strut ##1}}}}}}'.format(rgbcolor(ndef['border']),
311 | rgbcolor(ndef['bgcolor'])))
312 | elif ndef['bgcolor']:
313 | cmndef += (r'\def\$$@bc##1{{{{\setlength{{\fboxsep}}{{0pt}}'
314 | r'\colorbox[rgb]{{{}}}{{\strut ##1}}}}}}'.format(rgbcolor(ndef['bgcolor'])))
315 | if cmndef == '':
316 | continue
317 | cmndef = cmndef.replace('$$', cp)
318 | t2n[ttype] = name
319 | c2d[name] = cmndef
320 |
321 | def get_style_defs(self, arg=''):
322 | """
323 | Return the command sequences needed to define the commands
324 | used to format text in the verbatim environment. ``arg`` is ignored.
325 | """
326 | cp = self.commandprefix
327 | styles = []
328 | for name, definition in self.cmd2def.items():
329 | styles.append(rf'\@namedef{{{cp}@tok@{name}}}{{{definition}}}')
330 | return STYLE_TEMPLATE % {'cp': self.commandprefix,
331 | 'styles': '\n'.join(styles)}
332 |
333 | def format_unencoded(self, tokensource, outfile):
334 | # TODO: add support for background colors
335 | t2n = self.ttype2name
336 | cp = self.commandprefix
337 |
338 | if self.full:
339 | realoutfile = outfile
340 | outfile = StringIO()
341 |
342 | if not self.nowrap:
343 | outfile.write('\\begin{' + self.envname + '}[commandchars=\\\\\\{\\}')
344 | if self.linenos:
345 | start, step = self.linenostart, self.linenostep
346 | outfile.write(',numbers=left' +
347 | (start and ',firstnumber=%d' % start or '') +
348 | (step and ',stepnumber=%d' % step or ''))
349 | if self.mathescape or self.texcomments or self.escapeinside:
350 | outfile.write(',codes={\\catcode`\\$=3\\catcode`\\^=7'
351 | '\\catcode`\\_=8\\relax}')
352 | if self.verboptions:
353 | outfile.write(',' + self.verboptions)
354 | outfile.write(']\n')
355 |
356 | for ttype, value in tokensource:
357 | if ttype in Token.Comment:
358 | if self.texcomments:
359 | # Try to guess comment starting lexeme and escape it ...
360 | start = value[0:1]
361 | for i in range(1, len(value)):
362 | if start[0] != value[i]:
363 | break
364 | start += value[i]
365 |
366 | value = value[len(start):]
367 | start = escape_tex(start, cp)
368 |
369 | # ... but do not escape inside comment.
370 | value = start + value
371 | elif self.mathescape:
372 | # Only escape parts not inside a math environment.
373 | parts = value.split('$')
374 | in_math = False
375 | for i, part in enumerate(parts):
376 | if not in_math:
377 | parts[i] = escape_tex(part, cp)
378 | in_math = not in_math
379 | value = '$'.join(parts)
380 | elif self.escapeinside:
381 | text = value
382 | value = ''
383 | while text:
384 | a, sep1, text = text.partition(self.left)
385 | if sep1:
386 | b, sep2, text = text.partition(self.right)
387 | if sep2:
388 | value += escape_tex(a, cp) + b
389 | else:
390 | value += escape_tex(a + sep1 + b, cp)
391 | else:
392 | value += escape_tex(a, cp)
393 | else:
394 | value = escape_tex(value, cp)
395 | elif ttype not in Token.Escape:
396 | value = escape_tex(value, cp)
397 | styles = []
398 | while ttype is not Token:
399 | try:
400 | styles.append(t2n[ttype])
401 | except KeyError:
402 | # not in current style
403 | styles.append(_get_ttype_name(ttype))
404 | ttype = ttype.parent
405 | styleval = '+'.join(reversed(styles))
406 | if styleval:
407 | spl = value.split('\n')
408 | for line in spl[:-1]:
409 | if line:
410 | outfile.write(f"\\{cp}{{{styleval}}}{{{line}}}")
411 | outfile.write('\n')
412 | if spl[-1]:
413 | outfile.write(f"\\{cp}{{{styleval}}}{{{spl[-1]}}}")
414 | else:
415 | outfile.write(value)
416 |
417 | if not self.nowrap:
418 | outfile.write('\\end{' + self.envname + '}\n')
419 |
420 | if self.full:
421 | encoding = self.encoding or 'utf8'
422 | # map known existings encodings from LaTeX distribution
423 | encoding = {
424 | 'utf_8': 'utf8',
425 | 'latin_1': 'latin1',
426 | 'iso_8859_1': 'latin1',
427 | }.get(encoding.replace('-', '_'), encoding)
428 | realoutfile.write(DOC_TEMPLATE %
429 | dict(docclass = self.docclass,
430 | preamble = self.preamble,
431 | title = self.title,
432 | encoding = encoding,
433 | styledefs = self.get_style_defs(),
434 | code = outfile.getvalue()))
435 |
436 |
437 | class LatexEmbeddedLexer(Lexer):
438 | """
439 | This lexer takes one lexer as argument, the lexer for the language
440 | being formatted, and the left and right delimiters for escaped text.
441 |
442 | First everything is scanned using the language lexer to obtain
443 | strings and comments. All other consecutive tokens are merged and
444 | the resulting text is scanned for escaped segments, which are given
445 | the Token.Escape type. Finally text that is not escaped is scanned
446 | again with the language lexer.
447 | """
448 | def __init__(self, left, right, lang, **options):
449 | self.left = left
450 | self.right = right
451 | self.lang = lang
452 | Lexer.__init__(self, **options)
453 |
454 | def get_tokens_unprocessed(self, text):
455 | # find and remove all the escape tokens (replace with an empty string)
456 | # this is very similar to DelegatingLexer.get_tokens_unprocessed.
457 | buffered = ''
458 | insertions = []
459 | insertion_buf = []
460 | for i, t, v in self._find_safe_escape_tokens(text):
461 | if t is None:
462 | if insertion_buf:
463 | insertions.append((len(buffered), insertion_buf))
464 | insertion_buf = []
465 | buffered += v
466 | else:
467 | insertion_buf.append((i, t, v))
468 | if insertion_buf:
469 | insertions.append((len(buffered), insertion_buf))
470 | return do_insertions(insertions,
471 | self.lang.get_tokens_unprocessed(buffered))
472 |
473 | def _find_safe_escape_tokens(self, text):
474 | """ find escape tokens that are not in strings or comments """
475 | for i, t, v in self._filter_to(
476 | self.lang.get_tokens_unprocessed(text),
477 | lambda t: t in Token.Comment or t in Token.String
478 | ):
479 | if t is None:
480 | for i2, t2, v2 in self._find_escape_tokens(v):
481 | yield i + i2, t2, v2
482 | else:
483 | yield i, None, v
484 |
485 | def _filter_to(self, it, pred):
486 | """ Keep only the tokens that match `pred`, merge the others together """
487 | buf = ''
488 | idx = 0
489 | for i, t, v in it:
490 | if pred(t):
491 | if buf:
492 | yield idx, None, buf
493 | buf = ''
494 | yield i, t, v
495 | else:
496 | if not buf:
497 | idx = i
498 | buf += v
499 | if buf:
500 | yield idx, None, buf
501 |
502 | def _find_escape_tokens(self, text):
503 | """ Find escape tokens within text, give token=None otherwise """
504 | index = 0
505 | while text:
506 | a, sep1, text = text.partition(self.left)
507 | if a:
508 | yield index, None, a
509 | index += len(a)
510 | if sep1:
511 | b, sep2, text = text.partition(self.right)
512 | if sep2:
513 | yield index + len(sep1), Token.Escape, b
514 | index += len(sep1) + len(b) + len(sep2)
515 | else:
516 | yield index, Token.Error, sep1
517 | index += len(sep1)
518 | text = b
519 |
```