This is page 49 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/werkzeug/debug/tbtools.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import itertools
4 | import linecache
5 | import os
6 | import re
7 | import sys
8 | import sysconfig
9 | import traceback
10 | import typing as t
11 |
12 | from markupsafe import escape
13 |
14 | from ..utils import cached_property
15 | from .console import Console
16 |
17 | HEADER = """\
18 | <!doctype html>
19 | <html lang=en>
20 | <head>
21 | <title>%(title)s // Werkzeug Debugger</title>
22 | <link rel="stylesheet" href="?__debugger__=yes&cmd=resource&f=style.css">
23 | <link rel="shortcut icon"
24 | href="?__debugger__=yes&cmd=resource&f=console.png">
25 | <script src="?__debugger__=yes&cmd=resource&f=debugger.js"></script>
26 | <script>
27 | var CONSOLE_MODE = %(console)s,
28 | EVALEX = %(evalex)s,
29 | EVALEX_TRUSTED = %(evalex_trusted)s,
30 | SECRET = "%(secret)s";
31 | </script>
32 | </head>
33 | <body style="background-color: #fff">
34 | <div class="debugger">
35 | """
36 |
37 | FOOTER = """\
38 | <div class="footer">
39 | Brought to you by <strong class="arthur">DON'T PANIC</strong>, your
40 | friendly Werkzeug powered traceback interpreter.
41 | </div>
42 | </div>
43 |
44 | <div class="pin-prompt">
45 | <div class="inner">
46 | <h3>Console Locked</h3>
47 | <p>
48 | The console is locked and needs to be unlocked by entering the PIN.
49 | You can find the PIN printed out on the standard output of your
50 | shell that runs the server.
51 | <form>
52 | <p>PIN:
53 | <input type=text name=pin size=14>
54 | <input type=submit name=btn value="Confirm Pin">
55 | </form>
56 | </div>
57 | </div>
58 | </body>
59 | </html>
60 | """
61 |
62 | PAGE_HTML = (
63 | HEADER
64 | + """\
65 | <h1>%(exception_type)s</h1>
66 | <div class="detail">
67 | <p class="errormsg">%(exception)s</p>
68 | </div>
69 | <h2 class="traceback">Traceback <em>(most recent call last)</em></h2>
70 | %(summary)s
71 | <div class="plain">
72 | <p>
73 | This is the Copy/Paste friendly version of the traceback.
74 | </p>
75 | <textarea cols="50" rows="10" name="code" readonly>%(plaintext)s</textarea>
76 | </div>
77 | <div class="explanation">
78 | The debugger caught an exception in your WSGI application. You can now
79 | look at the traceback which led to the error. <span class="nojavascript">
80 | If you enable JavaScript you can also use additional features such as code
81 | execution (if the evalex feature is enabled), automatic pasting of the
82 | exceptions and much more.</span>
83 | </div>
84 | """
85 | + FOOTER
86 | + """
87 | <!--
88 |
89 | %(plaintext_cs)s
90 |
91 | -->
92 | """
93 | )
94 |
95 | CONSOLE_HTML = (
96 | HEADER
97 | + """\
98 | <h1>Interactive Console</h1>
99 | <div class="explanation">
100 | In this console you can execute Python expressions in the context of the
101 | application. The initial namespace was created by the debugger automatically.
102 | </div>
103 | <div class="console"><div class="inner">The Console requires JavaScript.</div></div>
104 | """
105 | + FOOTER
106 | )
107 |
108 | SUMMARY_HTML = """\
109 | <div class="%(classes)s">
110 | %(title)s
111 | <ul>%(frames)s</ul>
112 | %(description)s
113 | </div>
114 | """
115 |
116 | FRAME_HTML = """\
117 | <div class="frame" id="frame-%(id)d">
118 | <h4>File <cite class="filename">"%(filename)s"</cite>,
119 | line <em class="line">%(lineno)s</em>,
120 | in <code class="function">%(function_name)s</code></h4>
121 | <div class="source %(library)s">%(lines)s</div>
122 | </div>
123 | """
124 |
125 |
126 | def _process_traceback(
127 | exc: BaseException,
128 | te: traceback.TracebackException | None = None,
129 | *,
130 | skip: int = 0,
131 | hide: bool = True,
132 | ) -> traceback.TracebackException:
133 | if te is None:
134 | te = traceback.TracebackException.from_exception(exc, lookup_lines=False)
135 |
136 | # Get the frames the same way StackSummary.extract did, in order
137 | # to match each frame with the FrameSummary to augment.
138 | frame_gen = traceback.walk_tb(exc.__traceback__)
139 | limit = getattr(sys, "tracebacklimit", None)
140 |
141 | if limit is not None:
142 | if limit < 0:
143 | limit = 0
144 |
145 | frame_gen = itertools.islice(frame_gen, limit)
146 |
147 | if skip:
148 | frame_gen = itertools.islice(frame_gen, skip, None)
149 | del te.stack[:skip]
150 |
151 | new_stack: list[DebugFrameSummary] = []
152 | hidden = False
153 |
154 | # Match each frame with the FrameSummary that was generated.
155 | # Hide frames using Paste's __traceback_hide__ rules. Replace
156 | # all visible FrameSummary with DebugFrameSummary.
157 | for (f, _), fs in zip(frame_gen, te.stack):
158 | if hide:
159 | hide_value = f.f_locals.get("__traceback_hide__", False)
160 |
161 | if hide_value in {"before", "before_and_this"}:
162 | new_stack = []
163 | hidden = False
164 |
165 | if hide_value == "before_and_this":
166 | continue
167 | elif hide_value in {"reset", "reset_and_this"}:
168 | hidden = False
169 |
170 | if hide_value == "reset_and_this":
171 | continue
172 | elif hide_value in {"after", "after_and_this"}:
173 | hidden = True
174 |
175 | if hide_value == "after_and_this":
176 | continue
177 | elif hide_value or hidden:
178 | continue
179 |
180 | frame_args: dict[str, t.Any] = {
181 | "filename": fs.filename,
182 | "lineno": fs.lineno,
183 | "name": fs.name,
184 | "locals": f.f_locals,
185 | "globals": f.f_globals,
186 | }
187 |
188 | if hasattr(fs, "colno"):
189 | frame_args["colno"] = fs.colno
190 | frame_args["end_colno"] = fs.end_colno
191 |
192 | new_stack.append(DebugFrameSummary(**frame_args))
193 |
194 | # The codeop module is used to compile code from the interactive
195 | # debugger. Hide any codeop frames from the bottom of the traceback.
196 | while new_stack:
197 | module = new_stack[0].global_ns.get("__name__")
198 |
199 | if module is None:
200 | module = new_stack[0].local_ns.get("__name__")
201 |
202 | if module == "codeop":
203 | del new_stack[0]
204 | else:
205 | break
206 |
207 | te.stack[:] = new_stack
208 |
209 | if te.__context__:
210 | context_exc = t.cast(BaseException, exc.__context__)
211 | te.__context__ = _process_traceback(context_exc, te.__context__, hide=hide)
212 |
213 | if te.__cause__:
214 | cause_exc = t.cast(BaseException, exc.__cause__)
215 | te.__cause__ = _process_traceback(cause_exc, te.__cause__, hide=hide)
216 |
217 | return te
218 |
219 |
220 | class DebugTraceback:
221 | __slots__ = ("_te", "_cache_all_tracebacks", "_cache_all_frames")
222 |
223 | def __init__(
224 | self,
225 | exc: BaseException,
226 | te: traceback.TracebackException | None = None,
227 | *,
228 | skip: int = 0,
229 | hide: bool = True,
230 | ) -> None:
231 | self._te = _process_traceback(exc, te, skip=skip, hide=hide)
232 |
233 | def __str__(self) -> str:
234 | return f"<{type(self).__name__} {self._te}>"
235 |
236 | @cached_property
237 | def all_tracebacks(
238 | self,
239 | ) -> list[tuple[str | None, traceback.TracebackException]]:
240 | out = []
241 | current = self._te
242 |
243 | while current is not None:
244 | if current.__cause__ is not None:
245 | chained_msg = (
246 | "The above exception was the direct cause of the"
247 | " following exception"
248 | )
249 | chained_exc = current.__cause__
250 | elif current.__context__ is not None and not current.__suppress_context__:
251 | chained_msg = (
252 | "During handling of the above exception, another"
253 | " exception occurred"
254 | )
255 | chained_exc = current.__context__
256 | else:
257 | chained_msg = None
258 | chained_exc = None
259 |
260 | out.append((chained_msg, current))
261 | current = chained_exc
262 |
263 | return out
264 |
265 | @cached_property
266 | def all_frames(self) -> list[DebugFrameSummary]:
267 | return [
268 | f # type: ignore[misc]
269 | for _, te in self.all_tracebacks
270 | for f in te.stack
271 | ]
272 |
273 | def render_traceback_text(self) -> str:
274 | return "".join(self._te.format())
275 |
276 | def render_traceback_html(self, include_title: bool = True) -> str:
277 | library_frames = [f.is_library for f in self.all_frames]
278 | mark_library = 0 < sum(library_frames) < len(library_frames)
279 | rows = []
280 |
281 | if not library_frames:
282 | classes = "traceback noframe-traceback"
283 | else:
284 | classes = "traceback"
285 |
286 | for msg, current in reversed(self.all_tracebacks):
287 | row_parts = []
288 |
289 | if msg is not None:
290 | row_parts.append(f'<li><div class="exc-divider">{msg}:</div>')
291 |
292 | for frame in current.stack:
293 | frame = t.cast(DebugFrameSummary, frame)
294 | info = f' title="{escape(frame.info)}"' if frame.info else ""
295 | row_parts.append(f"<li{info}>{frame.render_html(mark_library)}")
296 |
297 | rows.append("\n".join(row_parts))
298 |
299 | if sys.version_info < (3, 13):
300 | exc_type_str = self._te.exc_type.__name__
301 | else:
302 | exc_type_str = self._te.exc_type_str
303 |
304 | is_syntax_error = exc_type_str == "SyntaxError"
305 |
306 | if include_title:
307 | if is_syntax_error:
308 | title = "Syntax Error"
309 | else:
310 | title = "Traceback <em>(most recent call last)</em>:"
311 | else:
312 | title = ""
313 |
314 | exc_full = escape("".join(self._te.format_exception_only()))
315 |
316 | if is_syntax_error:
317 | description = f"<pre class=syntaxerror>{exc_full}</pre>"
318 | else:
319 | description = f"<blockquote>{exc_full}</blockquote>"
320 |
321 | return SUMMARY_HTML % {
322 | "classes": classes,
323 | "title": f"<h3>{title}</h3>",
324 | "frames": "\n".join(rows),
325 | "description": description,
326 | }
327 |
328 | def render_debugger_html(
329 | self, evalex: bool, secret: str, evalex_trusted: bool
330 | ) -> str:
331 | exc_lines = list(self._te.format_exception_only())
332 | plaintext = "".join(self._te.format())
333 |
334 | if sys.version_info < (3, 13):
335 | exc_type_str = self._te.exc_type.__name__
336 | else:
337 | exc_type_str = self._te.exc_type_str
338 |
339 | return PAGE_HTML % {
340 | "evalex": "true" if evalex else "false",
341 | "evalex_trusted": "true" if evalex_trusted else "false",
342 | "console": "false",
343 | "title": escape(exc_lines[0]),
344 | "exception": escape("".join(exc_lines)),
345 | "exception_type": escape(exc_type_str),
346 | "summary": self.render_traceback_html(include_title=False),
347 | "plaintext": escape(plaintext),
348 | "plaintext_cs": re.sub("-{2,}", "-", plaintext),
349 | "secret": secret,
350 | }
351 |
352 |
353 | class DebugFrameSummary(traceback.FrameSummary):
354 | """A :class:`traceback.FrameSummary` that can evaluate code in the
355 | frame's namespace.
356 | """
357 |
358 | __slots__ = (
359 | "local_ns",
360 | "global_ns",
361 | "_cache_info",
362 | "_cache_is_library",
363 | "_cache_console",
364 | )
365 |
366 | def __init__(
367 | self,
368 | *,
369 | locals: dict[str, t.Any],
370 | globals: dict[str, t.Any],
371 | **kwargs: t.Any,
372 | ) -> None:
373 | super().__init__(locals=None, **kwargs)
374 | self.local_ns = locals
375 | self.global_ns = globals
376 |
377 | @cached_property
378 | def info(self) -> str | None:
379 | return self.local_ns.get("__traceback_info__")
380 |
381 | @cached_property
382 | def is_library(self) -> bool:
383 | return any(
384 | self.filename.startswith((path, os.path.realpath(path)))
385 | for path in sysconfig.get_paths().values()
386 | )
387 |
388 | @cached_property
389 | def console(self) -> Console:
390 | return Console(self.global_ns, self.local_ns)
391 |
392 | def eval(self, code: str) -> t.Any:
393 | return self.console.eval(code)
394 |
395 | def render_html(self, mark_library: bool) -> str:
396 | context = 5
397 | lines = linecache.getlines(self.filename)
398 | line_idx = self.lineno - 1 # type: ignore[operator]
399 | start_idx = max(0, line_idx - context)
400 | stop_idx = min(len(lines), line_idx + context + 1)
401 | rendered_lines = []
402 |
403 | def render_line(line: str, cls: str) -> None:
404 | line = line.expandtabs().rstrip()
405 | stripped_line = line.strip()
406 | prefix = len(line) - len(stripped_line)
407 | colno = getattr(self, "colno", 0)
408 | end_colno = getattr(self, "end_colno", 0)
409 |
410 | if cls == "current" and colno and end_colno:
411 | arrow = (
412 | f'\n<span class="ws">{" " * prefix}</span>'
413 | f'{" " * (colno - prefix)}{"^" * (end_colno - colno)}'
414 | )
415 | else:
416 | arrow = ""
417 |
418 | rendered_lines.append(
419 | f'<pre class="line {cls}"><span class="ws">{" " * prefix}</span>'
420 | f"{escape(stripped_line) if stripped_line else ' '}"
421 | f"{arrow if arrow else ''}</pre>"
422 | )
423 |
424 | if lines:
425 | for line in lines[start_idx:line_idx]:
426 | render_line(line, "before")
427 |
428 | render_line(lines[line_idx], "current")
429 |
430 | for line in lines[line_idx + 1 : stop_idx]:
431 | render_line(line, "after")
432 |
433 | return FRAME_HTML % {
434 | "id": id(self),
435 | "filename": escape(self.filename),
436 | "lineno": self.lineno,
437 | "function_name": escape(self.name),
438 | "lines": "\n".join(rendered_lines),
439 | "library": "library" if mark_library and self.is_library else "",
440 | }
441 |
442 |
443 | def render_console_html(secret: str, evalex_trusted: bool) -> str:
444 | return CONSOLE_HTML % {
445 | "evalex": "true",
446 | "evalex_trusted": "true" if evalex_trusted else "false",
447 | "console": "true",
448 | "title": "Console",
449 | "secret": secret,
450 | }
451 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | Low-level helpers for the SecureTransport bindings.
3 |
4 | These are Python functions that are not directly related to the high-level APIs
5 | but are necessary to get them to work. They include a whole bunch of low-level
6 | CoreFoundation messing about and memory management. The concerns in this module
7 | are almost entirely about trying to avoid memory leaks and providing
8 | appropriate and useful assistance to the higher-level code.
9 | """
10 | import base64
11 | import ctypes
12 | import itertools
13 | import os
14 | import re
15 | import ssl
16 | import struct
17 | import tempfile
18 |
19 | from .bindings import CFConst, CoreFoundation, Security
20 |
21 | # This regular expression is used to grab PEM data out of a PEM bundle.
22 | _PEM_CERTS_RE = re.compile(
23 | b"-----BEGIN CERTIFICATE-----\n(.*?)\n-----END CERTIFICATE-----", re.DOTALL
24 | )
25 |
26 |
27 | def _cf_data_from_bytes(bytestring):
28 | """
29 | Given a bytestring, create a CFData object from it. This CFData object must
30 | be CFReleased by the caller.
31 | """
32 | return CoreFoundation.CFDataCreate(
33 | CoreFoundation.kCFAllocatorDefault, bytestring, len(bytestring)
34 | )
35 |
36 |
37 | def _cf_dictionary_from_tuples(tuples):
38 | """
39 | Given a list of Python tuples, create an associated CFDictionary.
40 | """
41 | dictionary_size = len(tuples)
42 |
43 | # We need to get the dictionary keys and values out in the same order.
44 | keys = (t[0] for t in tuples)
45 | values = (t[1] for t in tuples)
46 | cf_keys = (CoreFoundation.CFTypeRef * dictionary_size)(*keys)
47 | cf_values = (CoreFoundation.CFTypeRef * dictionary_size)(*values)
48 |
49 | return CoreFoundation.CFDictionaryCreate(
50 | CoreFoundation.kCFAllocatorDefault,
51 | cf_keys,
52 | cf_values,
53 | dictionary_size,
54 | CoreFoundation.kCFTypeDictionaryKeyCallBacks,
55 | CoreFoundation.kCFTypeDictionaryValueCallBacks,
56 | )
57 |
58 |
59 | def _cfstr(py_bstr):
60 | """
61 | Given a Python binary data, create a CFString.
62 | The string must be CFReleased by the caller.
63 | """
64 | c_str = ctypes.c_char_p(py_bstr)
65 | cf_str = CoreFoundation.CFStringCreateWithCString(
66 | CoreFoundation.kCFAllocatorDefault,
67 | c_str,
68 | CFConst.kCFStringEncodingUTF8,
69 | )
70 | return cf_str
71 |
72 |
73 | def _create_cfstring_array(lst):
74 | """
75 | Given a list of Python binary data, create an associated CFMutableArray.
76 | The array must be CFReleased by the caller.
77 |
78 | Raises an ssl.SSLError on failure.
79 | """
80 | cf_arr = None
81 | try:
82 | cf_arr = CoreFoundation.CFArrayCreateMutable(
83 | CoreFoundation.kCFAllocatorDefault,
84 | 0,
85 | ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
86 | )
87 | if not cf_arr:
88 | raise MemoryError("Unable to allocate memory!")
89 | for item in lst:
90 | cf_str = _cfstr(item)
91 | if not cf_str:
92 | raise MemoryError("Unable to allocate memory!")
93 | try:
94 | CoreFoundation.CFArrayAppendValue(cf_arr, cf_str)
95 | finally:
96 | CoreFoundation.CFRelease(cf_str)
97 | except BaseException as e:
98 | if cf_arr:
99 | CoreFoundation.CFRelease(cf_arr)
100 | raise ssl.SSLError("Unable to allocate array: %s" % (e,))
101 | return cf_arr
102 |
103 |
104 | def _cf_string_to_unicode(value):
105 | """
106 | Creates a Unicode string from a CFString object. Used entirely for error
107 | reporting.
108 |
109 | Yes, it annoys me quite a lot that this function is this complex.
110 | """
111 | value_as_void_p = ctypes.cast(value, ctypes.POINTER(ctypes.c_void_p))
112 |
113 | string = CoreFoundation.CFStringGetCStringPtr(
114 | value_as_void_p, CFConst.kCFStringEncodingUTF8
115 | )
116 | if string is None:
117 | buffer = ctypes.create_string_buffer(1024)
118 | result = CoreFoundation.CFStringGetCString(
119 | value_as_void_p, buffer, 1024, CFConst.kCFStringEncodingUTF8
120 | )
121 | if not result:
122 | raise OSError("Error copying C string from CFStringRef")
123 | string = buffer.value
124 | if string is not None:
125 | string = string.decode("utf-8")
126 | return string
127 |
128 |
129 | def _assert_no_error(error, exception_class=None):
130 | """
131 | Checks the return code and throws an exception if there is an error to
132 | report
133 | """
134 | if error == 0:
135 | return
136 |
137 | cf_error_string = Security.SecCopyErrorMessageString(error, None)
138 | output = _cf_string_to_unicode(cf_error_string)
139 | CoreFoundation.CFRelease(cf_error_string)
140 |
141 | if output is None or output == u"":
142 | output = u"OSStatus %s" % error
143 |
144 | if exception_class is None:
145 | exception_class = ssl.SSLError
146 |
147 | raise exception_class(output)
148 |
149 |
150 | def _cert_array_from_pem(pem_bundle):
151 | """
152 | Given a bundle of certs in PEM format, turns them into a CFArray of certs
153 | that can be used to validate a cert chain.
154 | """
155 | # Normalize the PEM bundle's line endings.
156 | pem_bundle = pem_bundle.replace(b"\r\n", b"\n")
157 |
158 | der_certs = [
159 | base64.b64decode(match.group(1)) for match in _PEM_CERTS_RE.finditer(pem_bundle)
160 | ]
161 | if not der_certs:
162 | raise ssl.SSLError("No root certificates specified")
163 |
164 | cert_array = CoreFoundation.CFArrayCreateMutable(
165 | CoreFoundation.kCFAllocatorDefault,
166 | 0,
167 | ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
168 | )
169 | if not cert_array:
170 | raise ssl.SSLError("Unable to allocate memory!")
171 |
172 | try:
173 | for der_bytes in der_certs:
174 | certdata = _cf_data_from_bytes(der_bytes)
175 | if not certdata:
176 | raise ssl.SSLError("Unable to allocate memory!")
177 | cert = Security.SecCertificateCreateWithData(
178 | CoreFoundation.kCFAllocatorDefault, certdata
179 | )
180 | CoreFoundation.CFRelease(certdata)
181 | if not cert:
182 | raise ssl.SSLError("Unable to build cert object!")
183 |
184 | CoreFoundation.CFArrayAppendValue(cert_array, cert)
185 | CoreFoundation.CFRelease(cert)
186 | except Exception:
187 | # We need to free the array before the exception bubbles further.
188 | # We only want to do that if an error occurs: otherwise, the caller
189 | # should free.
190 | CoreFoundation.CFRelease(cert_array)
191 | raise
192 |
193 | return cert_array
194 |
195 |
196 | def _is_cert(item):
197 | """
198 | Returns True if a given CFTypeRef is a certificate.
199 | """
200 | expected = Security.SecCertificateGetTypeID()
201 | return CoreFoundation.CFGetTypeID(item) == expected
202 |
203 |
204 | def _is_identity(item):
205 | """
206 | Returns True if a given CFTypeRef is an identity.
207 | """
208 | expected = Security.SecIdentityGetTypeID()
209 | return CoreFoundation.CFGetTypeID(item) == expected
210 |
211 |
212 | def _temporary_keychain():
213 | """
214 | This function creates a temporary Mac keychain that we can use to work with
215 | credentials. This keychain uses a one-time password and a temporary file to
216 | store the data. We expect to have one keychain per socket. The returned
217 | SecKeychainRef must be freed by the caller, including calling
218 | SecKeychainDelete.
219 |
220 | Returns a tuple of the SecKeychainRef and the path to the temporary
221 | directory that contains it.
222 | """
223 | # Unfortunately, SecKeychainCreate requires a path to a keychain. This
224 | # means we cannot use mkstemp to use a generic temporary file. Instead,
225 | # we're going to create a temporary directory and a filename to use there.
226 | # This filename will be 8 random bytes expanded into base64. We also need
227 | # some random bytes to password-protect the keychain we're creating, so we
228 | # ask for 40 random bytes.
229 | random_bytes = os.urandom(40)
230 | filename = base64.b16encode(random_bytes[:8]).decode("utf-8")
231 | password = base64.b16encode(random_bytes[8:]) # Must be valid UTF-8
232 | tempdirectory = tempfile.mkdtemp()
233 |
234 | keychain_path = os.path.join(tempdirectory, filename).encode("utf-8")
235 |
236 | # We now want to create the keychain itself.
237 | keychain = Security.SecKeychainRef()
238 | status = Security.SecKeychainCreate(
239 | keychain_path, len(password), password, False, None, ctypes.byref(keychain)
240 | )
241 | _assert_no_error(status)
242 |
243 | # Having created the keychain, we want to pass it off to the caller.
244 | return keychain, tempdirectory
245 |
246 |
247 | def _load_items_from_file(keychain, path):
248 | """
249 | Given a single file, loads all the trust objects from it into arrays and
250 | the keychain.
251 | Returns a tuple of lists: the first list is a list of identities, the
252 | second a list of certs.
253 | """
254 | certificates = []
255 | identities = []
256 | result_array = None
257 |
258 | with open(path, "rb") as f:
259 | raw_filedata = f.read()
260 |
261 | try:
262 | filedata = CoreFoundation.CFDataCreate(
263 | CoreFoundation.kCFAllocatorDefault, raw_filedata, len(raw_filedata)
264 | )
265 | result_array = CoreFoundation.CFArrayRef()
266 | result = Security.SecItemImport(
267 | filedata, # cert data
268 | None, # Filename, leaving it out for now
269 | None, # What the type of the file is, we don't care
270 | None, # what's in the file, we don't care
271 | 0, # import flags
272 | None, # key params, can include passphrase in the future
273 | keychain, # The keychain to insert into
274 | ctypes.byref(result_array), # Results
275 | )
276 | _assert_no_error(result)
277 |
278 | # A CFArray is not very useful to us as an intermediary
279 | # representation, so we are going to extract the objects we want
280 | # and then free the array. We don't need to keep hold of keys: the
281 | # keychain already has them!
282 | result_count = CoreFoundation.CFArrayGetCount(result_array)
283 | for index in range(result_count):
284 | item = CoreFoundation.CFArrayGetValueAtIndex(result_array, index)
285 | item = ctypes.cast(item, CoreFoundation.CFTypeRef)
286 |
287 | if _is_cert(item):
288 | CoreFoundation.CFRetain(item)
289 | certificates.append(item)
290 | elif _is_identity(item):
291 | CoreFoundation.CFRetain(item)
292 | identities.append(item)
293 | finally:
294 | if result_array:
295 | CoreFoundation.CFRelease(result_array)
296 |
297 | CoreFoundation.CFRelease(filedata)
298 |
299 | return (identities, certificates)
300 |
301 |
302 | def _load_client_cert_chain(keychain, *paths):
303 | """
304 | Load certificates and maybe keys from a number of files. Has the end goal
305 | of returning a CFArray containing one SecIdentityRef, and then zero or more
306 | SecCertificateRef objects, suitable for use as a client certificate trust
307 | chain.
308 | """
309 | # Ok, the strategy.
310 | #
311 | # This relies on knowing that macOS will not give you a SecIdentityRef
312 | # unless you have imported a key into a keychain. This is a somewhat
313 | # artificial limitation of macOS (for example, it doesn't necessarily
314 | # affect iOS), but there is nothing inside Security.framework that lets you
315 | # get a SecIdentityRef without having a key in a keychain.
316 | #
317 | # So the policy here is we take all the files and iterate them in order.
318 | # Each one will use SecItemImport to have one or more objects loaded from
319 | # it. We will also point at a keychain that macOS can use to work with the
320 | # private key.
321 | #
322 | # Once we have all the objects, we'll check what we actually have. If we
323 | # already have a SecIdentityRef in hand, fab: we'll use that. Otherwise,
324 | # we'll take the first certificate (which we assume to be our leaf) and
325 | # ask the keychain to give us a SecIdentityRef with that cert's associated
326 | # key.
327 | #
328 | # We'll then return a CFArray containing the trust chain: one
329 | # SecIdentityRef and then zero-or-more SecCertificateRef objects. The
330 | # responsibility for freeing this CFArray will be with the caller. This
331 | # CFArray must remain alive for the entire connection, so in practice it
332 | # will be stored with a single SSLSocket, along with the reference to the
333 | # keychain.
334 | certificates = []
335 | identities = []
336 |
337 | # Filter out bad paths.
338 | paths = (path for path in paths if path)
339 |
340 | try:
341 | for file_path in paths:
342 | new_identities, new_certs = _load_items_from_file(keychain, file_path)
343 | identities.extend(new_identities)
344 | certificates.extend(new_certs)
345 |
346 | # Ok, we have everything. The question is: do we have an identity? If
347 | # not, we want to grab one from the first cert we have.
348 | if not identities:
349 | new_identity = Security.SecIdentityRef()
350 | status = Security.SecIdentityCreateWithCertificate(
351 | keychain, certificates[0], ctypes.byref(new_identity)
352 | )
353 | _assert_no_error(status)
354 | identities.append(new_identity)
355 |
356 | # We now want to release the original certificate, as we no longer
357 | # need it.
358 | CoreFoundation.CFRelease(certificates.pop(0))
359 |
360 | # We now need to build a new CFArray that holds the trust chain.
361 | trust_chain = CoreFoundation.CFArrayCreateMutable(
362 | CoreFoundation.kCFAllocatorDefault,
363 | 0,
364 | ctypes.byref(CoreFoundation.kCFTypeArrayCallBacks),
365 | )
366 | for item in itertools.chain(identities, certificates):
367 | # ArrayAppendValue does a CFRetain on the item. That's fine,
368 | # because the finally block will release our other refs to them.
369 | CoreFoundation.CFArrayAppendValue(trust_chain, item)
370 |
371 | return trust_chain
372 | finally:
373 | for obj in itertools.chain(identities, certificates):
374 | CoreFoundation.CFRelease(obj)
375 |
376 |
377 | TLS_PROTOCOL_VERSIONS = {
378 | "SSLv2": (0, 2),
379 | "SSLv3": (3, 0),
380 | "TLSv1": (3, 1),
381 | "TLSv1.1": (3, 2),
382 | "TLSv1.2": (3, 3),
383 | }
384 |
385 |
386 | def _build_tls_unknown_ca_alert(version):
387 | """
388 | Builds a TLS alert record for an unknown CA.
389 | """
390 | ver_maj, ver_min = TLS_PROTOCOL_VERSIONS[version]
391 | severity_fatal = 0x02
392 | description_unknown_ca = 0x30
393 | msg = struct.pack(">BB", severity_fatal, description_unknown_ca)
394 | msg_len = len(msg)
395 | record_type_alert = 0x15
396 | record = struct.pack(">BBBH", record_type_alert, ver_maj, ver_min, msg_len) + msg
397 | return record
398 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/rich/layout.py:
--------------------------------------------------------------------------------
```python
1 | from abc import ABC, abstractmethod
2 | from itertools import islice
3 | from operator import itemgetter
4 | from threading import RLock
5 | from typing import (
6 | TYPE_CHECKING,
7 | Dict,
8 | Iterable,
9 | List,
10 | NamedTuple,
11 | Optional,
12 | Sequence,
13 | Tuple,
14 | Union,
15 | )
16 |
17 | from ._ratio import ratio_resolve
18 | from .align import Align
19 | from .console import Console, ConsoleOptions, RenderableType, RenderResult
20 | from .highlighter import ReprHighlighter
21 | from .panel import Panel
22 | from .pretty import Pretty
23 | from .region import Region
24 | from .repr import Result, rich_repr
25 | from .segment import Segment
26 | from .style import StyleType
27 |
28 | if TYPE_CHECKING:
29 | from pip._vendor.rich.tree import Tree
30 |
31 |
32 | class LayoutRender(NamedTuple):
33 | """An individual layout render."""
34 |
35 | region: Region
36 | render: List[List[Segment]]
37 |
38 |
39 | RegionMap = Dict["Layout", Region]
40 | RenderMap = Dict["Layout", LayoutRender]
41 |
42 |
43 | class LayoutError(Exception):
44 | """Layout related error."""
45 |
46 |
47 | class NoSplitter(LayoutError):
48 | """Requested splitter does not exist."""
49 |
50 |
51 | class _Placeholder:
52 | """An internal renderable used as a Layout placeholder."""
53 |
54 | highlighter = ReprHighlighter()
55 |
56 | def __init__(self, layout: "Layout", style: StyleType = "") -> None:
57 | self.layout = layout
58 | self.style = style
59 |
60 | def __rich_console__(
61 | self, console: Console, options: ConsoleOptions
62 | ) -> RenderResult:
63 | width = options.max_width
64 | height = options.height or options.size.height
65 | layout = self.layout
66 | title = (
67 | f"{layout.name!r} ({width} x {height})"
68 | if layout.name
69 | else f"({width} x {height})"
70 | )
71 | yield Panel(
72 | Align.center(Pretty(layout), vertical="middle"),
73 | style=self.style,
74 | title=self.highlighter(title),
75 | border_style="blue",
76 | height=height,
77 | )
78 |
79 |
80 | class Splitter(ABC):
81 | """Base class for a splitter."""
82 |
83 | name: str = ""
84 |
85 | @abstractmethod
86 | def get_tree_icon(self) -> str:
87 | """Get the icon (emoji) used in layout.tree"""
88 |
89 | @abstractmethod
90 | def divide(
91 | self, children: Sequence["Layout"], region: Region
92 | ) -> Iterable[Tuple["Layout", Region]]:
93 | """Divide a region amongst several child layouts.
94 |
95 | Args:
96 | children (Sequence(Layout)): A number of child layouts.
97 | region (Region): A rectangular region to divide.
98 | """
99 |
100 |
101 | class RowSplitter(Splitter):
102 | """Split a layout region in to rows."""
103 |
104 | name = "row"
105 |
106 | def get_tree_icon(self) -> str:
107 | return "[layout.tree.row]⬌"
108 |
109 | def divide(
110 | self, children: Sequence["Layout"], region: Region
111 | ) -> Iterable[Tuple["Layout", Region]]:
112 | x, y, width, height = region
113 | render_widths = ratio_resolve(width, children)
114 | offset = 0
115 | _Region = Region
116 | for child, child_width in zip(children, render_widths):
117 | yield child, _Region(x + offset, y, child_width, height)
118 | offset += child_width
119 |
120 |
121 | class ColumnSplitter(Splitter):
122 | """Split a layout region in to columns."""
123 |
124 | name = "column"
125 |
126 | def get_tree_icon(self) -> str:
127 | return "[layout.tree.column]⬍"
128 |
129 | def divide(
130 | self, children: Sequence["Layout"], region: Region
131 | ) -> Iterable[Tuple["Layout", Region]]:
132 | x, y, width, height = region
133 | render_heights = ratio_resolve(height, children)
134 | offset = 0
135 | _Region = Region
136 | for child, child_height in zip(children, render_heights):
137 | yield child, _Region(x, y + offset, width, child_height)
138 | offset += child_height
139 |
140 |
141 | @rich_repr
142 | class Layout:
143 | """A renderable to divide a fixed height in to rows or columns.
144 |
145 | Args:
146 | renderable (RenderableType, optional): Renderable content, or None for placeholder. Defaults to None.
147 | name (str, optional): Optional identifier for Layout. Defaults to None.
148 | size (int, optional): Optional fixed size of layout. Defaults to None.
149 | minimum_size (int, optional): Minimum size of layout. Defaults to 1.
150 | ratio (int, optional): Optional ratio for flexible layout. Defaults to 1.
151 | visible (bool, optional): Visibility of layout. Defaults to True.
152 | """
153 |
154 | splitters = {"row": RowSplitter, "column": ColumnSplitter}
155 |
156 | def __init__(
157 | self,
158 | renderable: Optional[RenderableType] = None,
159 | *,
160 | name: Optional[str] = None,
161 | size: Optional[int] = None,
162 | minimum_size: int = 1,
163 | ratio: int = 1,
164 | visible: bool = True,
165 | ) -> None:
166 | self._renderable = renderable or _Placeholder(self)
167 | self.size = size
168 | self.minimum_size = minimum_size
169 | self.ratio = ratio
170 | self.name = name
171 | self.visible = visible
172 | self.splitter: Splitter = self.splitters["column"]()
173 | self._children: List[Layout] = []
174 | self._render_map: RenderMap = {}
175 | self._lock = RLock()
176 |
177 | def __rich_repr__(self) -> Result:
178 | yield "name", self.name, None
179 | yield "size", self.size, None
180 | yield "minimum_size", self.minimum_size, 1
181 | yield "ratio", self.ratio, 1
182 |
183 | @property
184 | def renderable(self) -> RenderableType:
185 | """Layout renderable."""
186 | return self if self._children else self._renderable
187 |
188 | @property
189 | def children(self) -> List["Layout"]:
190 | """Gets (visible) layout children."""
191 | return [child for child in self._children if child.visible]
192 |
193 | @property
194 | def map(self) -> RenderMap:
195 | """Get a map of the last render."""
196 | return self._render_map
197 |
198 | def get(self, name: str) -> Optional["Layout"]:
199 | """Get a named layout, or None if it doesn't exist.
200 |
201 | Args:
202 | name (str): Name of layout.
203 |
204 | Returns:
205 | Optional[Layout]: Layout instance or None if no layout was found.
206 | """
207 | if self.name == name:
208 | return self
209 | else:
210 | for child in self._children:
211 | named_layout = child.get(name)
212 | if named_layout is not None:
213 | return named_layout
214 | return None
215 |
216 | def __getitem__(self, name: str) -> "Layout":
217 | layout = self.get(name)
218 | if layout is None:
219 | raise KeyError(f"No layout with name {name!r}")
220 | return layout
221 |
222 | @property
223 | def tree(self) -> "Tree":
224 | """Get a tree renderable to show layout structure."""
225 | from pip._vendor.rich.styled import Styled
226 | from pip._vendor.rich.table import Table
227 | from pip._vendor.rich.tree import Tree
228 |
229 | def summary(layout: "Layout") -> Table:
230 | icon = layout.splitter.get_tree_icon()
231 |
232 | table = Table.grid(padding=(0, 1, 0, 0))
233 |
234 | text: RenderableType = (
235 | Pretty(layout) if layout.visible else Styled(Pretty(layout), "dim")
236 | )
237 | table.add_row(icon, text)
238 | _summary = table
239 | return _summary
240 |
241 | layout = self
242 | tree = Tree(
243 | summary(layout),
244 | guide_style=f"layout.tree.{layout.splitter.name}",
245 | highlight=True,
246 | )
247 |
248 | def recurse(tree: "Tree", layout: "Layout") -> None:
249 | for child in layout._children:
250 | recurse(
251 | tree.add(
252 | summary(child),
253 | guide_style=f"layout.tree.{child.splitter.name}",
254 | ),
255 | child,
256 | )
257 |
258 | recurse(tree, self)
259 | return tree
260 |
261 | def split(
262 | self,
263 | *layouts: Union["Layout", RenderableType],
264 | splitter: Union[Splitter, str] = "column",
265 | ) -> None:
266 | """Split the layout in to multiple sub-layouts.
267 |
268 | Args:
269 | *layouts (Layout): Positional arguments should be (sub) Layout instances.
270 | splitter (Union[Splitter, str]): Splitter instance or name of splitter.
271 | """
272 | _layouts = [
273 | layout if isinstance(layout, Layout) else Layout(layout)
274 | for layout in layouts
275 | ]
276 | try:
277 | self.splitter = (
278 | splitter
279 | if isinstance(splitter, Splitter)
280 | else self.splitters[splitter]()
281 | )
282 | except KeyError:
283 | raise NoSplitter(f"No splitter called {splitter!r}")
284 | self._children[:] = _layouts
285 |
286 | def add_split(self, *layouts: Union["Layout", RenderableType]) -> None:
287 | """Add a new layout(s) to existing split.
288 |
289 | Args:
290 | *layouts (Union[Layout, RenderableType]): Positional arguments should be renderables or (sub) Layout instances.
291 |
292 | """
293 | _layouts = (
294 | layout if isinstance(layout, Layout) else Layout(layout)
295 | for layout in layouts
296 | )
297 | self._children.extend(_layouts)
298 |
299 | def split_row(self, *layouts: Union["Layout", RenderableType]) -> None:
300 | """Split the layout in to a row (layouts side by side).
301 |
302 | Args:
303 | *layouts (Layout): Positional arguments should be (sub) Layout instances.
304 | """
305 | self.split(*layouts, splitter="row")
306 |
307 | def split_column(self, *layouts: Union["Layout", RenderableType]) -> None:
308 | """Split the layout in to a column (layouts stacked on top of each other).
309 |
310 | Args:
311 | *layouts (Layout): Positional arguments should be (sub) Layout instances.
312 | """
313 | self.split(*layouts, splitter="column")
314 |
315 | def unsplit(self) -> None:
316 | """Reset splits to initial state."""
317 | del self._children[:]
318 |
319 | def update(self, renderable: RenderableType) -> None:
320 | """Update renderable.
321 |
322 | Args:
323 | renderable (RenderableType): New renderable object.
324 | """
325 | with self._lock:
326 | self._renderable = renderable
327 |
328 | def refresh_screen(self, console: "Console", layout_name: str) -> None:
329 | """Refresh a sub-layout.
330 |
331 | Args:
332 | console (Console): Console instance where Layout is to be rendered.
333 | layout_name (str): Name of layout.
334 | """
335 | with self._lock:
336 | layout = self[layout_name]
337 | region, _lines = self._render_map[layout]
338 | (x, y, width, height) = region
339 | lines = console.render_lines(
340 | layout, console.options.update_dimensions(width, height)
341 | )
342 | self._render_map[layout] = LayoutRender(region, lines)
343 | console.update_screen_lines(lines, x, y)
344 |
345 | def _make_region_map(self, width: int, height: int) -> RegionMap:
346 | """Create a dict that maps layout on to Region."""
347 | stack: List[Tuple[Layout, Region]] = [(self, Region(0, 0, width, height))]
348 | push = stack.append
349 | pop = stack.pop
350 | layout_regions: List[Tuple[Layout, Region]] = []
351 | append_layout_region = layout_regions.append
352 | while stack:
353 | append_layout_region(pop())
354 | layout, region = layout_regions[-1]
355 | children = layout.children
356 | if children:
357 | for child_and_region in layout.splitter.divide(children, region):
358 | push(child_and_region)
359 |
360 | region_map = {
361 | layout: region
362 | for layout, region in sorted(layout_regions, key=itemgetter(1))
363 | }
364 | return region_map
365 |
366 | def render(self, console: Console, options: ConsoleOptions) -> RenderMap:
367 | """Render the sub_layouts.
368 |
369 | Args:
370 | console (Console): Console instance.
371 | options (ConsoleOptions): Console options.
372 |
373 | Returns:
374 | RenderMap: A dict that maps Layout on to a tuple of Region, lines
375 | """
376 | render_width = options.max_width
377 | render_height = options.height or console.height
378 | region_map = self._make_region_map(render_width, render_height)
379 | layout_regions = [
380 | (layout, region)
381 | for layout, region in region_map.items()
382 | if not layout.children
383 | ]
384 | render_map: Dict["Layout", "LayoutRender"] = {}
385 | render_lines = console.render_lines
386 | update_dimensions = options.update_dimensions
387 |
388 | for layout, region in layout_regions:
389 | lines = render_lines(
390 | layout.renderable, update_dimensions(region.width, region.height)
391 | )
392 | render_map[layout] = LayoutRender(region, lines)
393 | return render_map
394 |
395 | def __rich_console__(
396 | self, console: Console, options: ConsoleOptions
397 | ) -> RenderResult:
398 | with self._lock:
399 | width = options.max_width or console.width
400 | height = options.height or console.height
401 | render_map = self.render(console, options.update_dimensions(width, height))
402 | self._render_map = render_map
403 | layout_lines: List[List[Segment]] = [[] for _ in range(height)]
404 | _islice = islice
405 | for region, lines in render_map.values():
406 | _x, y, _layout_width, layout_height = region
407 | for row, line in zip(
408 | _islice(layout_lines, y, y + layout_height), lines
409 | ):
410 | row.extend(line)
411 |
412 | new_line = Segment.line()
413 | for layout_row in layout_lines:
414 | yield from layout_row
415 | yield new_line
416 |
417 |
418 | if __name__ == "__main__":
419 | from pip._vendor.rich.console import Console
420 |
421 | console = Console()
422 | layout = Layout()
423 |
424 | layout.split_column(
425 | Layout(name="header", size=3),
426 | Layout(ratio=1, name="main"),
427 | Layout(size=10, name="footer"),
428 | )
429 |
430 | layout["main"].split_row(Layout(name="side"), Layout(name="body", ratio=2))
431 |
432 | layout["body"].split_row(Layout(name="content", ratio=2), Layout(name="s2"))
433 |
434 | layout["s2"].split_column(
435 | Layout(name="top"), Layout(name="middle"), Layout(name="bottom")
436 | )
437 |
438 | layout["side"].split_column(Layout(layout.tree, name="left1"), Layout(name="left2"))
439 |
440 | layout["content"].update("foo")
441 |
442 | console.print(layout)
443 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/configuration.py:
--------------------------------------------------------------------------------
```python
1 | """Configuration management setup
2 |
3 | Some terminology:
4 | - name
5 | As written in config files.
6 | - value
7 | Value associated with a name
8 | - key
9 | Name combined with it's section (section.name)
10 | - variant
11 | A single word describing where the configuration key-value pair came from
12 | """
13 |
14 | import configparser
15 | import locale
16 | import os
17 | import sys
18 | from typing import Any, Dict, Iterable, List, NewType, Optional, Tuple
19 |
20 | from pip._internal.exceptions import (
21 | ConfigurationError,
22 | ConfigurationFileCouldNotBeLoaded,
23 | )
24 | from pip._internal.utils import appdirs
25 | from pip._internal.utils.compat import WINDOWS
26 | from pip._internal.utils.logging import getLogger
27 | from pip._internal.utils.misc import ensure_dir, enum
28 |
29 | RawConfigParser = configparser.RawConfigParser # Shorthand
30 | Kind = NewType("Kind", str)
31 |
32 | CONFIG_BASENAME = "pip.ini" if WINDOWS else "pip.conf"
33 | ENV_NAMES_IGNORED = "version", "help"
34 |
35 | # The kinds of configurations there are.
36 | kinds = enum(
37 | USER="user", # User Specific
38 | GLOBAL="global", # System Wide
39 | SITE="site", # [Virtual] Environment Specific
40 | ENV="env", # from PIP_CONFIG_FILE
41 | ENV_VAR="env-var", # from Environment Variables
42 | )
43 | OVERRIDE_ORDER = kinds.GLOBAL, kinds.USER, kinds.SITE, kinds.ENV, kinds.ENV_VAR
44 | VALID_LOAD_ONLY = kinds.USER, kinds.GLOBAL, kinds.SITE
45 |
46 | logger = getLogger(__name__)
47 |
48 |
49 | # NOTE: Maybe use the optionx attribute to normalize keynames.
50 | def _normalize_name(name: str) -> str:
51 | """Make a name consistent regardless of source (environment or file)"""
52 | name = name.lower().replace("_", "-")
53 | if name.startswith("--"):
54 | name = name[2:] # only prefer long opts
55 | return name
56 |
57 |
58 | def _disassemble_key(name: str) -> List[str]:
59 | if "." not in name:
60 | error_message = (
61 | "Key does not contain dot separated section and key. "
62 | f"Perhaps you wanted to use 'global.{name}' instead?"
63 | )
64 | raise ConfigurationError(error_message)
65 | return name.split(".", 1)
66 |
67 |
68 | def get_configuration_files() -> Dict[Kind, List[str]]:
69 | global_config_files = [
70 | os.path.join(path, CONFIG_BASENAME) for path in appdirs.site_config_dirs("pip")
71 | ]
72 |
73 | site_config_file = os.path.join(sys.prefix, CONFIG_BASENAME)
74 | legacy_config_file = os.path.join(
75 | os.path.expanduser("~"),
76 | "pip" if WINDOWS else ".pip",
77 | CONFIG_BASENAME,
78 | )
79 | new_config_file = os.path.join(appdirs.user_config_dir("pip"), CONFIG_BASENAME)
80 | return {
81 | kinds.GLOBAL: global_config_files,
82 | kinds.SITE: [site_config_file],
83 | kinds.USER: [legacy_config_file, new_config_file],
84 | }
85 |
86 |
87 | class Configuration:
88 | """Handles management of configuration.
89 |
90 | Provides an interface to accessing and managing configuration files.
91 |
92 | This class converts provides an API that takes "section.key-name" style
93 | keys and stores the value associated with it as "key-name" under the
94 | section "section".
95 |
96 | This allows for a clean interface wherein the both the section and the
97 | key-name are preserved in an easy to manage form in the configuration files
98 | and the data stored is also nice.
99 | """
100 |
101 | def __init__(self, isolated: bool, load_only: Optional[Kind] = None) -> None:
102 | super().__init__()
103 |
104 | if load_only is not None and load_only not in VALID_LOAD_ONLY:
105 | raise ConfigurationError(
106 | "Got invalid value for load_only - should be one of {}".format(
107 | ", ".join(map(repr, VALID_LOAD_ONLY))
108 | )
109 | )
110 | self.isolated = isolated
111 | self.load_only = load_only
112 |
113 | # Because we keep track of where we got the data from
114 | self._parsers: Dict[Kind, List[Tuple[str, RawConfigParser]]] = {
115 | variant: [] for variant in OVERRIDE_ORDER
116 | }
117 | self._config: Dict[Kind, Dict[str, Any]] = {
118 | variant: {} for variant in OVERRIDE_ORDER
119 | }
120 | self._modified_parsers: List[Tuple[str, RawConfigParser]] = []
121 |
122 | def load(self) -> None:
123 | """Loads configuration from configuration files and environment"""
124 | self._load_config_files()
125 | if not self.isolated:
126 | self._load_environment_vars()
127 |
128 | def get_file_to_edit(self) -> Optional[str]:
129 | """Returns the file with highest priority in configuration"""
130 | assert self.load_only is not None, "Need to be specified a file to be editing"
131 |
132 | try:
133 | return self._get_parser_to_modify()[0]
134 | except IndexError:
135 | return None
136 |
137 | def items(self) -> Iterable[Tuple[str, Any]]:
138 | """Returns key-value pairs like dict.items() representing the loaded
139 | configuration
140 | """
141 | return self._dictionary.items()
142 |
143 | def get_value(self, key: str) -> Any:
144 | """Get a value from the configuration."""
145 | orig_key = key
146 | key = _normalize_name(key)
147 | try:
148 | return self._dictionary[key]
149 | except KeyError:
150 | # disassembling triggers a more useful error message than simply
151 | # "No such key" in the case that the key isn't in the form command.option
152 | _disassemble_key(key)
153 | raise ConfigurationError(f"No such key - {orig_key}")
154 |
155 | def set_value(self, key: str, value: Any) -> None:
156 | """Modify a value in the configuration."""
157 | key = _normalize_name(key)
158 | self._ensure_have_load_only()
159 |
160 | assert self.load_only
161 | fname, parser = self._get_parser_to_modify()
162 |
163 | if parser is not None:
164 | section, name = _disassemble_key(key)
165 |
166 | # Modify the parser and the configuration
167 | if not parser.has_section(section):
168 | parser.add_section(section)
169 | parser.set(section, name, value)
170 |
171 | self._config[self.load_only][key] = value
172 | self._mark_as_modified(fname, parser)
173 |
174 | def unset_value(self, key: str) -> None:
175 | """Unset a value in the configuration."""
176 | orig_key = key
177 | key = _normalize_name(key)
178 | self._ensure_have_load_only()
179 |
180 | assert self.load_only
181 | if key not in self._config[self.load_only]:
182 | raise ConfigurationError(f"No such key - {orig_key}")
183 |
184 | fname, parser = self._get_parser_to_modify()
185 |
186 | if parser is not None:
187 | section, name = _disassemble_key(key)
188 | if not (
189 | parser.has_section(section) and parser.remove_option(section, name)
190 | ):
191 | # The option was not removed.
192 | raise ConfigurationError(
193 | "Fatal Internal error [id=1]. Please report as a bug."
194 | )
195 |
196 | # The section may be empty after the option was removed.
197 | if not parser.items(section):
198 | parser.remove_section(section)
199 | self._mark_as_modified(fname, parser)
200 |
201 | del self._config[self.load_only][key]
202 |
203 | def save(self) -> None:
204 | """Save the current in-memory state."""
205 | self._ensure_have_load_only()
206 |
207 | for fname, parser in self._modified_parsers:
208 | logger.info("Writing to %s", fname)
209 |
210 | # Ensure directory exists.
211 | ensure_dir(os.path.dirname(fname))
212 |
213 | # Ensure directory's permission(need to be writeable)
214 | try:
215 | with open(fname, "w") as f:
216 | parser.write(f)
217 | except OSError as error:
218 | raise ConfigurationError(
219 | f"An error occurred while writing to the configuration file "
220 | f"{fname}: {error}"
221 | )
222 |
223 | #
224 | # Private routines
225 | #
226 |
227 | def _ensure_have_load_only(self) -> None:
228 | if self.load_only is None:
229 | raise ConfigurationError("Needed a specific file to be modifying.")
230 | logger.debug("Will be working with %s variant only", self.load_only)
231 |
232 | @property
233 | def _dictionary(self) -> Dict[str, Any]:
234 | """A dictionary representing the loaded configuration."""
235 | # NOTE: Dictionaries are not populated if not loaded. So, conditionals
236 | # are not needed here.
237 | retval = {}
238 |
239 | for variant in OVERRIDE_ORDER:
240 | retval.update(self._config[variant])
241 |
242 | return retval
243 |
244 | def _load_config_files(self) -> None:
245 | """Loads configuration from configuration files"""
246 | config_files = dict(self.iter_config_files())
247 | if config_files[kinds.ENV][0:1] == [os.devnull]:
248 | logger.debug(
249 | "Skipping loading configuration files due to "
250 | "environment's PIP_CONFIG_FILE being os.devnull"
251 | )
252 | return
253 |
254 | for variant, files in config_files.items():
255 | for fname in files:
256 | # If there's specific variant set in `load_only`, load only
257 | # that variant, not the others.
258 | if self.load_only is not None and variant != self.load_only:
259 | logger.debug("Skipping file '%s' (variant: %s)", fname, variant)
260 | continue
261 |
262 | parser = self._load_file(variant, fname)
263 |
264 | # Keeping track of the parsers used
265 | self._parsers[variant].append((fname, parser))
266 |
267 | def _load_file(self, variant: Kind, fname: str) -> RawConfigParser:
268 | logger.verbose("For variant '%s', will try loading '%s'", variant, fname)
269 | parser = self._construct_parser(fname)
270 |
271 | for section in parser.sections():
272 | items = parser.items(section)
273 | self._config[variant].update(self._normalized_keys(section, items))
274 |
275 | return parser
276 |
277 | def _construct_parser(self, fname: str) -> RawConfigParser:
278 | parser = configparser.RawConfigParser()
279 | # If there is no such file, don't bother reading it but create the
280 | # parser anyway, to hold the data.
281 | # Doing this is useful when modifying and saving files, where we don't
282 | # need to construct a parser.
283 | if os.path.exists(fname):
284 | locale_encoding = locale.getpreferredencoding(False)
285 | try:
286 | parser.read(fname, encoding=locale_encoding)
287 | except UnicodeDecodeError:
288 | # See https://github.com/pypa/pip/issues/4963
289 | raise ConfigurationFileCouldNotBeLoaded(
290 | reason=f"contains invalid {locale_encoding} characters",
291 | fname=fname,
292 | )
293 | except configparser.Error as error:
294 | # See https://github.com/pypa/pip/issues/4893
295 | raise ConfigurationFileCouldNotBeLoaded(error=error)
296 | return parser
297 |
298 | def _load_environment_vars(self) -> None:
299 | """Loads configuration from environment variables"""
300 | self._config[kinds.ENV_VAR].update(
301 | self._normalized_keys(":env:", self.get_environ_vars())
302 | )
303 |
304 | def _normalized_keys(
305 | self, section: str, items: Iterable[Tuple[str, Any]]
306 | ) -> Dict[str, Any]:
307 | """Normalizes items to construct a dictionary with normalized keys.
308 |
309 | This routine is where the names become keys and are made the same
310 | regardless of source - configuration files or environment.
311 | """
312 | normalized = {}
313 | for name, val in items:
314 | key = section + "." + _normalize_name(name)
315 | normalized[key] = val
316 | return normalized
317 |
318 | def get_environ_vars(self) -> Iterable[Tuple[str, str]]:
319 | """Returns a generator with all environmental vars with prefix PIP_"""
320 | for key, val in os.environ.items():
321 | if key.startswith("PIP_"):
322 | name = key[4:].lower()
323 | if name not in ENV_NAMES_IGNORED:
324 | yield name, val
325 |
326 | # XXX: This is patched in the tests.
327 | def iter_config_files(self) -> Iterable[Tuple[Kind, List[str]]]:
328 | """Yields variant and configuration files associated with it.
329 |
330 | This should be treated like items of a dictionary. The order
331 | here doesn't affect what gets overridden. That is controlled
332 | by OVERRIDE_ORDER. However this does control the order they are
333 | displayed to the user. It's probably most ergononmic to display
334 | things in the same order as OVERRIDE_ORDER
335 | """
336 | # SMELL: Move the conditions out of this function
337 |
338 | env_config_file = os.environ.get("PIP_CONFIG_FILE", None)
339 | config_files = get_configuration_files()
340 |
341 | yield kinds.GLOBAL, config_files[kinds.GLOBAL]
342 |
343 | # per-user config is not loaded when env_config_file exists
344 | should_load_user_config = not self.isolated and not (
345 | env_config_file and os.path.exists(env_config_file)
346 | )
347 | if should_load_user_config:
348 | # The legacy config file is overridden by the new config file
349 | yield kinds.USER, config_files[kinds.USER]
350 |
351 | # virtualenv config
352 | yield kinds.SITE, config_files[kinds.SITE]
353 |
354 | if env_config_file is not None:
355 | yield kinds.ENV, [env_config_file]
356 | else:
357 | yield kinds.ENV, []
358 |
359 | def get_values_in_config(self, variant: Kind) -> Dict[str, Any]:
360 | """Get values present in a config file"""
361 | return self._config[variant]
362 |
363 | def _get_parser_to_modify(self) -> Tuple[str, RawConfigParser]:
364 | # Determine which parser to modify
365 | assert self.load_only
366 | parsers = self._parsers[self.load_only]
367 | if not parsers:
368 | # This should not happen if everything works correctly.
369 | raise ConfigurationError(
370 | "Fatal Internal error [id=2]. Please report as a bug."
371 | )
372 |
373 | # Use the highest priority parser.
374 | return parsers[-1]
375 |
376 | # XXX: This is patched in the tests.
377 | def _mark_as_modified(self, fname: str, parser: RawConfigParser) -> None:
378 | file_parser_tuple = (fname, parser)
379 | if file_parser_tuple not in self._modified_parsers:
380 | self._modified_parsers.append(file_parser_tuple)
381 |
382 | def __repr__(self) -> str:
383 | return f"{self.__class__.__name__}({self._dictionary!r})"
384 |
```