This is page 36 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/util.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | pygments.util
3 | ~~~~~~~~~~~~~
4 |
5 | Utility functions.
6 |
7 | :copyright: Copyright 2006-2024 by the Pygments team, see AUTHORS.
8 | :license: BSD, see LICENSE for details.
9 | """
10 |
11 | import re
12 | from io import TextIOWrapper
13 |
14 |
15 | split_path_re = re.compile(r'[/\\ ]')
16 | doctype_lookup_re = re.compile(r'''
17 | <!DOCTYPE\s+(
18 | [a-zA-Z_][a-zA-Z0-9]*
19 | (?: \s+ # optional in HTML5
20 | [a-zA-Z_][a-zA-Z0-9]*\s+
21 | "[^"]*")?
22 | )
23 | [^>]*>
24 | ''', re.DOTALL | re.MULTILINE | re.VERBOSE)
25 | tag_re = re.compile(r'<(.+?)(\s.*?)?>.*?</.+?>',
26 | re.IGNORECASE | re.DOTALL | re.MULTILINE)
27 | xml_decl_re = re.compile(r'\s*<\?xml[^>]*\?>', re.I)
28 |
29 |
30 | class ClassNotFound(ValueError):
31 | """Raised if one of the lookup functions didn't find a matching class."""
32 |
33 |
34 | class OptionError(Exception):
35 | """
36 | This exception will be raised by all option processing functions if
37 | the type or value of the argument is not correct.
38 | """
39 |
40 | def get_choice_opt(options, optname, allowed, default=None, normcase=False):
41 | """
42 | If the key `optname` from the dictionary is not in the sequence
43 | `allowed`, raise an error, otherwise return it.
44 | """
45 | string = options.get(optname, default)
46 | if normcase:
47 | string = string.lower()
48 | if string not in allowed:
49 | raise OptionError('Value for option {} must be one of {}'.format(optname, ', '.join(map(str, allowed))))
50 | return string
51 |
52 |
53 | def get_bool_opt(options, optname, default=None):
54 | """
55 | Intuitively, this is `options.get(optname, default)`, but restricted to
56 | Boolean value. The Booleans can be represented as string, in order to accept
57 | Boolean value from the command line arguments. If the key `optname` is
58 | present in the dictionary `options` and is not associated with a Boolean,
59 | raise an `OptionError`. If it is absent, `default` is returned instead.
60 |
61 | The valid string values for ``True`` are ``1``, ``yes``, ``true`` and
62 | ``on``, the ones for ``False`` are ``0``, ``no``, ``false`` and ``off``
63 | (matched case-insensitively).
64 | """
65 | string = options.get(optname, default)
66 | if isinstance(string, bool):
67 | return string
68 | elif isinstance(string, int):
69 | return bool(string)
70 | elif not isinstance(string, str):
71 | raise OptionError(f'Invalid type {string!r} for option {optname}; use '
72 | '1/0, yes/no, true/false, on/off')
73 | elif string.lower() in ('1', 'yes', 'true', 'on'):
74 | return True
75 | elif string.lower() in ('0', 'no', 'false', 'off'):
76 | return False
77 | else:
78 | raise OptionError(f'Invalid value {string!r} for option {optname}; use '
79 | '1/0, yes/no, true/false, on/off')
80 |
81 |
82 | def get_int_opt(options, optname, default=None):
83 | """As :func:`get_bool_opt`, but interpret the value as an integer."""
84 | string = options.get(optname, default)
85 | try:
86 | return int(string)
87 | except TypeError:
88 | raise OptionError(f'Invalid type {string!r} for option {optname}; you '
89 | 'must give an integer value')
90 | except ValueError:
91 | raise OptionError(f'Invalid value {string!r} for option {optname}; you '
92 | 'must give an integer value')
93 |
94 | def get_list_opt(options, optname, default=None):
95 | """
96 | If the key `optname` from the dictionary `options` is a string,
97 | split it at whitespace and return it. If it is already a list
98 | or a tuple, it is returned as a list.
99 | """
100 | val = options.get(optname, default)
101 | if isinstance(val, str):
102 | return val.split()
103 | elif isinstance(val, (list, tuple)):
104 | return list(val)
105 | else:
106 | raise OptionError(f'Invalid type {val!r} for option {optname}; you '
107 | 'must give a list value')
108 |
109 |
110 | def docstring_headline(obj):
111 | if not obj.__doc__:
112 | return ''
113 | res = []
114 | for line in obj.__doc__.strip().splitlines():
115 | if line.strip():
116 | res.append(" " + line.strip())
117 | else:
118 | break
119 | return ''.join(res).lstrip()
120 |
121 |
122 | def make_analysator(f):
123 | """Return a static text analyser function that returns float values."""
124 | def text_analyse(text):
125 | try:
126 | rv = f(text)
127 | except Exception:
128 | return 0.0
129 | if not rv:
130 | return 0.0
131 | try:
132 | return min(1.0, max(0.0, float(rv)))
133 | except (ValueError, TypeError):
134 | return 0.0
135 | text_analyse.__doc__ = f.__doc__
136 | return staticmethod(text_analyse)
137 |
138 |
139 | def shebang_matches(text, regex):
140 | r"""Check if the given regular expression matches the last part of the
141 | shebang if one exists.
142 |
143 | >>> from pygments.util import shebang_matches
144 | >>> shebang_matches('#!/usr/bin/env python', r'python(2\.\d)?')
145 | True
146 | >>> shebang_matches('#!/usr/bin/python2.4', r'python(2\.\d)?')
147 | True
148 | >>> shebang_matches('#!/usr/bin/python-ruby', r'python(2\.\d)?')
149 | False
150 | >>> shebang_matches('#!/usr/bin/python/ruby', r'python(2\.\d)?')
151 | False
152 | >>> shebang_matches('#!/usr/bin/startsomethingwith python',
153 | ... r'python(2\.\d)?')
154 | True
155 |
156 | It also checks for common windows executable file extensions::
157 |
158 | >>> shebang_matches('#!C:\\Python2.4\\Python.exe', r'python(2\.\d)?')
159 | True
160 |
161 | Parameters (``'-f'`` or ``'--foo'`` are ignored so ``'perl'`` does
162 | the same as ``'perl -e'``)
163 |
164 | Note that this method automatically searches the whole string (eg:
165 | the regular expression is wrapped in ``'^$'``)
166 | """
167 | index = text.find('\n')
168 | if index >= 0:
169 | first_line = text[:index].lower()
170 | else:
171 | first_line = text.lower()
172 | if first_line.startswith('#!'):
173 | try:
174 | found = [x for x in split_path_re.split(first_line[2:].strip())
175 | if x and not x.startswith('-')][-1]
176 | except IndexError:
177 | return False
178 | regex = re.compile(rf'^{regex}(\.(exe|cmd|bat|bin))?$', re.IGNORECASE)
179 | if regex.search(found) is not None:
180 | return True
181 | return False
182 |
183 |
184 | def doctype_matches(text, regex):
185 | """Check if the doctype matches a regular expression (if present).
186 |
187 | Note that this method only checks the first part of a DOCTYPE.
188 | eg: 'html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"'
189 | """
190 | m = doctype_lookup_re.search(text)
191 | if m is None:
192 | return False
193 | doctype = m.group(1)
194 | return re.compile(regex, re.I).match(doctype.strip()) is not None
195 |
196 |
197 | def html_doctype_matches(text):
198 | """Check if the file looks like it has a html doctype."""
199 | return doctype_matches(text, r'html')
200 |
201 |
202 | _looks_like_xml_cache = {}
203 |
204 |
205 | def looks_like_xml(text):
206 | """Check if a doctype exists or if we have some tags."""
207 | if xml_decl_re.match(text):
208 | return True
209 | key = hash(text)
210 | try:
211 | return _looks_like_xml_cache[key]
212 | except KeyError:
213 | m = doctype_lookup_re.search(text)
214 | if m is not None:
215 | return True
216 | rv = tag_re.search(text[:1000]) is not None
217 | _looks_like_xml_cache[key] = rv
218 | return rv
219 |
220 |
221 | def surrogatepair(c):
222 | """Given a unicode character code with length greater than 16 bits,
223 | return the two 16 bit surrogate pair.
224 | """
225 | # From example D28 of:
226 | # http://www.unicode.org/book/ch03.pdf
227 | return (0xd7c0 + (c >> 10), (0xdc00 + (c & 0x3ff)))
228 |
229 |
230 | def format_lines(var_name, seq, raw=False, indent_level=0):
231 | """Formats a sequence of strings for output."""
232 | lines = []
233 | base_indent = ' ' * indent_level * 4
234 | inner_indent = ' ' * (indent_level + 1) * 4
235 | lines.append(base_indent + var_name + ' = (')
236 | if raw:
237 | # These should be preformatted reprs of, say, tuples.
238 | for i in seq:
239 | lines.append(inner_indent + i + ',')
240 | else:
241 | for i in seq:
242 | # Force use of single quotes
243 | r = repr(i + '"')
244 | lines.append(inner_indent + r[:-2] + r[-1] + ',')
245 | lines.append(base_indent + ')')
246 | return '\n'.join(lines)
247 |
248 |
249 | def duplicates_removed(it, already_seen=()):
250 | """
251 | Returns a list with duplicates removed from the iterable `it`.
252 |
253 | Order is preserved.
254 | """
255 | lst = []
256 | seen = set()
257 | for i in it:
258 | if i in seen or i in already_seen:
259 | continue
260 | lst.append(i)
261 | seen.add(i)
262 | return lst
263 |
264 |
265 | class Future:
266 | """Generic class to defer some work.
267 |
268 | Handled specially in RegexLexerMeta, to support regex string construction at
269 | first use.
270 | """
271 | def get(self):
272 | raise NotImplementedError
273 |
274 |
275 | def guess_decode(text):
276 | """Decode *text* with guessed encoding.
277 |
278 | First try UTF-8; this should fail for non-UTF-8 encodings.
279 | Then try the preferred locale encoding.
280 | Fall back to latin-1, which always works.
281 | """
282 | try:
283 | text = text.decode('utf-8')
284 | return text, 'utf-8'
285 | except UnicodeDecodeError:
286 | try:
287 | import locale
288 | prefencoding = locale.getpreferredencoding()
289 | text = text.decode()
290 | return text, prefencoding
291 | except (UnicodeDecodeError, LookupError):
292 | text = text.decode('latin1')
293 | return text, 'latin1'
294 |
295 |
296 | def guess_decode_from_terminal(text, term):
297 | """Decode *text* coming from terminal *term*.
298 |
299 | First try the terminal encoding, if given.
300 | Then try UTF-8. Then try the preferred locale encoding.
301 | Fall back to latin-1, which always works.
302 | """
303 | if getattr(term, 'encoding', None):
304 | try:
305 | text = text.decode(term.encoding)
306 | except UnicodeDecodeError:
307 | pass
308 | else:
309 | return text, term.encoding
310 | return guess_decode(text)
311 |
312 |
313 | def terminal_encoding(term):
314 | """Return our best guess of encoding for the given *term*."""
315 | if getattr(term, 'encoding', None):
316 | return term.encoding
317 | import locale
318 | return locale.getpreferredencoding()
319 |
320 |
321 | class UnclosingTextIOWrapper(TextIOWrapper):
322 | # Don't close underlying buffer on destruction.
323 | def close(self):
324 | self.flush()
325 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/werkzeug/debug/shared/debugger.js:
--------------------------------------------------------------------------------
```javascript
1 | docReady(() => {
2 | if (!EVALEX_TRUSTED) {
3 | initPinBox();
4 | }
5 | // if we are in console mode, show the console.
6 | if (CONSOLE_MODE && EVALEX) {
7 | createInteractiveConsole();
8 | }
9 |
10 | const frames = document.querySelectorAll("div.traceback div.frame");
11 | if (EVALEX) {
12 | addConsoleIconToFrames(frames);
13 | }
14 | addEventListenersToElements(document.querySelectorAll("div.detail"), "click", () =>
15 | document.querySelector("div.traceback").scrollIntoView(false)
16 | );
17 | addToggleFrameTraceback(frames);
18 | addToggleTraceTypesOnClick(document.querySelectorAll("h2.traceback"));
19 | addInfoPrompt(document.querySelectorAll("span.nojavascript"));
20 | wrapPlainTraceback();
21 | });
22 |
23 | function addToggleFrameTraceback(frames) {
24 | frames.forEach((frame) => {
25 | frame.addEventListener("click", () => {
26 | frame.getElementsByTagName("pre")[0].parentElement.classList.toggle("expanded");
27 | });
28 | })
29 | }
30 |
31 |
32 | function wrapPlainTraceback() {
33 | const plainTraceback = document.querySelector("div.plain textarea");
34 | const wrapper = document.createElement("pre");
35 | const textNode = document.createTextNode(plainTraceback.textContent);
36 | wrapper.appendChild(textNode);
37 | plainTraceback.replaceWith(wrapper);
38 | }
39 |
40 | function makeDebugURL(args) {
41 | const params = new URLSearchParams(args)
42 | params.set("s", SECRET)
43 | return `?__debugger__=yes&${params}`
44 | }
45 |
46 | function initPinBox() {
47 | document.querySelector(".pin-prompt form").addEventListener(
48 | "submit",
49 | function (event) {
50 | event.preventDefault();
51 | const btn = this.btn;
52 | btn.disabled = true;
53 |
54 | fetch(
55 | makeDebugURL({cmd: "pinauth", pin: this.pin.value})
56 | )
57 | .then((res) => res.json())
58 | .then(({auth, exhausted}) => {
59 | if (auth) {
60 | EVALEX_TRUSTED = true;
61 | fadeOut(document.getElementsByClassName("pin-prompt")[0]);
62 | } else {
63 | alert(
64 | `Error: ${
65 | exhausted
66 | ? "too many attempts. Restart server to retry."
67 | : "incorrect pin"
68 | }`
69 | );
70 | }
71 | })
72 | .catch((err) => {
73 | alert("Error: Could not verify PIN. Network error?");
74 | console.error(err);
75 | })
76 | .finally(() => (btn.disabled = false));
77 | },
78 | false
79 | );
80 | }
81 |
82 | function promptForPin() {
83 | if (!EVALEX_TRUSTED) {
84 | fetch(makeDebugURL({cmd: "printpin"}));
85 | const pinPrompt = document.getElementsByClassName("pin-prompt")[0];
86 | fadeIn(pinPrompt);
87 | document.querySelector('.pin-prompt input[name="pin"]').focus();
88 | }
89 | }
90 |
91 | /**
92 | * Helper function for shell initialization
93 | */
94 | function openShell(consoleNode, target, frameID) {
95 | promptForPin();
96 | if (consoleNode) {
97 | slideToggle(consoleNode);
98 | return consoleNode;
99 | }
100 | let historyPos = 0;
101 | const history = [""];
102 | const consoleElement = createConsole();
103 | const output = createConsoleOutput();
104 | const form = createConsoleInputForm();
105 | const command = createConsoleInput();
106 |
107 | target.parentNode.appendChild(consoleElement);
108 | consoleElement.append(output);
109 | consoleElement.append(form);
110 | form.append(command);
111 | command.focus();
112 | slideToggle(consoleElement);
113 |
114 | form.addEventListener("submit", (e) => {
115 | handleConsoleSubmit(e, command, frameID).then((consoleOutput) => {
116 | output.append(consoleOutput);
117 | command.focus();
118 | consoleElement.scrollTo(0, consoleElement.scrollHeight);
119 | const old = history.pop();
120 | history.push(command.value);
121 | if (typeof old !== "undefined") {
122 | history.push(old);
123 | }
124 | historyPos = history.length - 1;
125 | command.value = "";
126 | });
127 | });
128 |
129 | command.addEventListener("keydown", (e) => {
130 | if (e.key === "l" && e.ctrlKey) {
131 | output.innerText = "--- screen cleared ---";
132 | } else if (e.key === "ArrowUp" || e.key === "ArrowDown") {
133 | // Handle up arrow and down arrow.
134 | if (e.key === "ArrowUp" && historyPos > 0) {
135 | e.preventDefault();
136 | historyPos--;
137 | } else if (e.key === "ArrowDown" && historyPos < history.length - 1) {
138 | historyPos++;
139 | }
140 | command.value = history[historyPos];
141 | }
142 | return false;
143 | });
144 |
145 | return consoleElement;
146 | }
147 |
148 | function addEventListenersToElements(elements, event, listener) {
149 | elements.forEach((el) => el.addEventListener(event, listener));
150 | }
151 |
152 | /**
153 | * Add extra info
154 | */
155 | function addInfoPrompt(elements) {
156 | for (let i = 0; i < elements.length; i++) {
157 | elements[i].innerHTML =
158 | "<p>To switch between the interactive traceback and the plaintext " +
159 | 'one, you can click on the "Traceback" headline. From the text ' +
160 | "traceback you can also create a paste of it. " +
161 | (!EVALEX
162 | ? ""
163 | : "For code execution mouse-over the frame you want to debug and " +
164 | "click on the console icon on the right side." +
165 | "<p>You can execute arbitrary Python code in the stack frames and " +
166 | "there are some extra helpers available for introspection:" +
167 | "<ul><li><code>dump()</code> shows all variables in the frame" +
168 | "<li><code>dump(obj)</code> dumps all that's known about the object</ul>");
169 | elements[i].classList.remove("nojavascript");
170 | }
171 | }
172 |
173 | function addConsoleIconToFrames(frames) {
174 | for (let i = 0; i < frames.length; i++) {
175 | let consoleNode = null;
176 | const target = frames[i];
177 | const frameID = frames[i].id.substring(6);
178 |
179 | for (let j = 0; j < target.getElementsByTagName("pre").length; j++) {
180 | const img = createIconForConsole();
181 | img.addEventListener("click", (e) => {
182 | e.stopPropagation();
183 | consoleNode = openShell(consoleNode, target, frameID);
184 | return false;
185 | });
186 | target.getElementsByTagName("pre")[j].append(img);
187 | }
188 | }
189 | }
190 |
191 | function slideToggle(target) {
192 | target.classList.toggle("active");
193 | }
194 |
195 | /**
196 | * toggle traceback types on click.
197 | */
198 | function addToggleTraceTypesOnClick(elements) {
199 | for (let i = 0; i < elements.length; i++) {
200 | elements[i].addEventListener("click", () => {
201 | document.querySelector("div.traceback").classList.toggle("hidden");
202 | document.querySelector("div.plain").classList.toggle("hidden");
203 | });
204 | elements[i].style.cursor = "pointer";
205 | document.querySelector("div.plain").classList.toggle("hidden");
206 | }
207 | }
208 |
209 | function createConsole() {
210 | const consoleNode = document.createElement("pre");
211 | consoleNode.classList.add("console");
212 | consoleNode.classList.add("active");
213 | return consoleNode;
214 | }
215 |
216 | function createConsoleOutput() {
217 | const output = document.createElement("div");
218 | output.classList.add("output");
219 | output.innerHTML = "[console ready]";
220 | return output;
221 | }
222 |
223 | function createConsoleInputForm() {
224 | const form = document.createElement("form");
225 | form.innerHTML = ">>> ";
226 | return form;
227 | }
228 |
229 | function createConsoleInput() {
230 | const command = document.createElement("input");
231 | command.type = "text";
232 | command.setAttribute("autocomplete", "off");
233 | command.setAttribute("spellcheck", false);
234 | command.setAttribute("autocapitalize", "off");
235 | command.setAttribute("autocorrect", "off");
236 | return command;
237 | }
238 |
239 | function createIconForConsole() {
240 | const img = document.createElement("img");
241 | img.setAttribute("src", makeDebugURL({cmd: "resource", f: "console.png"}));
242 | img.setAttribute("title", "Open an interactive python shell in this frame");
243 | return img;
244 | }
245 |
246 | function createExpansionButtonForConsole() {
247 | const expansionButton = document.createElement("a");
248 | expansionButton.setAttribute("href", "#");
249 | expansionButton.setAttribute("class", "toggle");
250 | expansionButton.innerHTML = " ";
251 | return expansionButton;
252 | }
253 |
254 | function createInteractiveConsole() {
255 | const target = document.querySelector("div.console div.inner");
256 | while (target.firstChild) {
257 | target.removeChild(target.firstChild);
258 | }
259 | openShell(null, target, 0);
260 | }
261 |
262 | function handleConsoleSubmit(e, command, frameID) {
263 | // Prevent page from refreshing.
264 | e.preventDefault();
265 |
266 | return new Promise((resolve) => {
267 | fetch(makeDebugURL({cmd: command.value, frm: frameID}))
268 | .then((res) => {
269 | return res.text();
270 | })
271 | .then((data) => {
272 | const tmp = document.createElement("div");
273 | tmp.innerHTML = data;
274 | resolve(tmp);
275 |
276 | // Handle expandable span for long list outputs.
277 | // Example to test: list(range(13))
278 | let wrapperAdded = false;
279 | const wrapperSpan = document.createElement("span");
280 | const expansionButton = createExpansionButtonForConsole();
281 |
282 | tmp.querySelectorAll("span.extended").forEach((spanToWrap) => {
283 | const parentDiv = spanToWrap.parentNode;
284 | if (!wrapperAdded) {
285 | parentDiv.insertBefore(wrapperSpan, spanToWrap);
286 | wrapperAdded = true;
287 | }
288 | parentDiv.removeChild(spanToWrap);
289 | wrapperSpan.append(spanToWrap);
290 | spanToWrap.hidden = true;
291 |
292 | expansionButton.addEventListener("click", (event) => {
293 | event.preventDefault();
294 | spanToWrap.hidden = !spanToWrap.hidden;
295 | expansionButton.classList.toggle("open");
296 | return false;
297 | });
298 | });
299 |
300 | // Add expansion button at end of wrapper.
301 | if (wrapperAdded) {
302 | wrapperSpan.append(expansionButton);
303 | }
304 | })
305 | .catch((err) => {
306 | console.error(err);
307 | });
308 | return false;
309 | });
310 | }
311 |
312 | function fadeOut(element) {
313 | element.style.opacity = 1;
314 |
315 | (function fade() {
316 | element.style.opacity -= 0.1;
317 | if (element.style.opacity < 0) {
318 | element.style.display = "none";
319 | } else {
320 | requestAnimationFrame(fade);
321 | }
322 | })();
323 | }
324 |
325 | function fadeIn(element, display) {
326 | element.style.opacity = 0;
327 | element.style.display = display || "block";
328 |
329 | (function fade() {
330 | let val = parseFloat(element.style.opacity) + 0.1;
331 | if (val <= 1) {
332 | element.style.opacity = val;
333 | requestAnimationFrame(fade);
334 | }
335 | })();
336 | }
337 |
338 | function docReady(fn) {
339 | if (document.readyState === "complete" || document.readyState === "interactive") {
340 | setTimeout(fn, 1);
341 | } else {
342 | document.addEventListener("DOMContentLoaded", fn);
343 | }
344 | }
345 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/bs4/css.py:
--------------------------------------------------------------------------------
```python
1 | """Integration code for CSS selectors using Soup Sieve (pypi: soupsieve)."""
2 |
3 | import warnings
4 | try:
5 | import soupsieve
6 | except ImportError as e:
7 | soupsieve = None
8 | warnings.warn(
9 | 'The soupsieve package is not installed. CSS selectors cannot be used.'
10 | )
11 |
12 |
13 | class CSS(object):
14 | """A proxy object against the soupsieve library, to simplify its
15 | CSS selector API.
16 |
17 | Acquire this object through the .css attribute on the
18 | BeautifulSoup object, or on the Tag you want to use as the
19 | starting point for a CSS selector.
20 |
21 | The main advantage of doing this is that the tag to be selected
22 | against doesn't need to be explicitly specified in the function
23 | calls, since it's already scoped to a tag.
24 | """
25 |
26 | def __init__(self, tag, api=soupsieve):
27 | """Constructor.
28 |
29 | You don't need to instantiate this class yourself; instead,
30 | access the .css attribute on the BeautifulSoup object, or on
31 | the Tag you want to use as the starting point for your CSS
32 | selector.
33 |
34 | :param tag: All CSS selectors will use this as their starting
35 | point.
36 |
37 | :param api: A plug-in replacement for the soupsieve module,
38 | designed mainly for use in tests.
39 | """
40 | if api is None:
41 | raise NotImplementedError(
42 | "Cannot execute CSS selectors because the soupsieve package is not installed."
43 | )
44 | self.api = api
45 | self.tag = tag
46 |
47 | def escape(self, ident):
48 | """Escape a CSS identifier.
49 |
50 | This is a simple wrapper around soupselect.escape(). See the
51 | documentation for that function for more information.
52 | """
53 | if soupsieve is None:
54 | raise NotImplementedError(
55 | "Cannot escape CSS identifiers because the soupsieve package is not installed."
56 | )
57 | return self.api.escape(ident)
58 |
59 | def _ns(self, ns, select):
60 | """Normalize a dictionary of namespaces."""
61 | if not isinstance(select, self.api.SoupSieve) and ns is None:
62 | # If the selector is a precompiled pattern, it already has
63 | # a namespace context compiled in, which cannot be
64 | # replaced.
65 | ns = self.tag._namespaces
66 | return ns
67 |
68 | def _rs(self, results):
69 | """Normalize a list of results to a Resultset.
70 |
71 | A ResultSet is more consistent with the rest of Beautiful
72 | Soup's API, and ResultSet.__getattr__ has a helpful error
73 | message if you try to treat a list of results as a single
74 | result (a common mistake).
75 | """
76 | # Import here to avoid circular import
77 | from bs4.element import ResultSet
78 | return ResultSet(None, results)
79 |
80 | def compile(self, select, namespaces=None, flags=0, **kwargs):
81 | """Pre-compile a selector and return the compiled object.
82 |
83 | :param selector: A CSS selector.
84 |
85 | :param namespaces: A dictionary mapping namespace prefixes
86 | used in the CSS selector to namespace URIs. By default,
87 | Beautiful Soup will use the prefixes it encountered while
88 | parsing the document.
89 |
90 | :param flags: Flags to be passed into Soup Sieve's
91 | soupsieve.compile() method.
92 |
93 | :param kwargs: Keyword arguments to be passed into SoupSieve's
94 | soupsieve.compile() method.
95 |
96 | :return: A precompiled selector object.
97 | :rtype: soupsieve.SoupSieve
98 | """
99 | return self.api.compile(
100 | select, self._ns(namespaces, select), flags, **kwargs
101 | )
102 |
103 | def select_one(self, select, namespaces=None, flags=0, **kwargs):
104 | """Perform a CSS selection operation on the current Tag and return the
105 | first result.
106 |
107 | This uses the Soup Sieve library. For more information, see
108 | that library's documentation for the soupsieve.select_one()
109 | method.
110 |
111 | :param selector: A CSS selector.
112 |
113 | :param namespaces: A dictionary mapping namespace prefixes
114 | used in the CSS selector to namespace URIs. By default,
115 | Beautiful Soup will use the prefixes it encountered while
116 | parsing the document.
117 |
118 | :param flags: Flags to be passed into Soup Sieve's
119 | soupsieve.select_one() method.
120 |
121 | :param kwargs: Keyword arguments to be passed into SoupSieve's
122 | soupsieve.select_one() method.
123 |
124 | :return: A Tag, or None if the selector has no match.
125 | :rtype: bs4.element.Tag
126 |
127 | """
128 | return self.api.select_one(
129 | select, self.tag, self._ns(namespaces, select), flags, **kwargs
130 | )
131 |
132 | def select(self, select, namespaces=None, limit=0, flags=0, **kwargs):
133 | """Perform a CSS selection operation on the current Tag.
134 |
135 | This uses the Soup Sieve library. For more information, see
136 | that library's documentation for the soupsieve.select()
137 | method.
138 |
139 | :param selector: A string containing a CSS selector.
140 |
141 | :param namespaces: A dictionary mapping namespace prefixes
142 | used in the CSS selector to namespace URIs. By default,
143 | Beautiful Soup will pass in the prefixes it encountered while
144 | parsing the document.
145 |
146 | :param limit: After finding this number of results, stop looking.
147 |
148 | :param flags: Flags to be passed into Soup Sieve's
149 | soupsieve.select() method.
150 |
151 | :param kwargs: Keyword arguments to be passed into SoupSieve's
152 | soupsieve.select() method.
153 |
154 | :return: A ResultSet of Tag objects.
155 | :rtype: bs4.element.ResultSet
156 |
157 | """
158 | if limit is None:
159 | limit = 0
160 |
161 | return self._rs(
162 | self.api.select(
163 | select, self.tag, self._ns(namespaces, select), limit, flags,
164 | **kwargs
165 | )
166 | )
167 |
168 | def iselect(self, select, namespaces=None, limit=0, flags=0, **kwargs):
169 | """Perform a CSS selection operation on the current Tag.
170 |
171 | This uses the Soup Sieve library. For more information, see
172 | that library's documentation for the soupsieve.iselect()
173 | method. It is the same as select(), but it returns a generator
174 | instead of a list.
175 |
176 | :param selector: A string containing a CSS selector.
177 |
178 | :param namespaces: A dictionary mapping namespace prefixes
179 | used in the CSS selector to namespace URIs. By default,
180 | Beautiful Soup will pass in the prefixes it encountered while
181 | parsing the document.
182 |
183 | :param limit: After finding this number of results, stop looking.
184 |
185 | :param flags: Flags to be passed into Soup Sieve's
186 | soupsieve.iselect() method.
187 |
188 | :param kwargs: Keyword arguments to be passed into SoupSieve's
189 | soupsieve.iselect() method.
190 |
191 | :return: A generator
192 | :rtype: types.GeneratorType
193 | """
194 | return self.api.iselect(
195 | select, self.tag, self._ns(namespaces, select), limit, flags, **kwargs
196 | )
197 |
198 | def closest(self, select, namespaces=None, flags=0, **kwargs):
199 | """Find the Tag closest to this one that matches the given selector.
200 |
201 | This uses the Soup Sieve library. For more information, see
202 | that library's documentation for the soupsieve.closest()
203 | method.
204 |
205 | :param selector: A string containing a CSS selector.
206 |
207 | :param namespaces: A dictionary mapping namespace prefixes
208 | used in the CSS selector to namespace URIs. By default,
209 | Beautiful Soup will pass in the prefixes it encountered while
210 | parsing the document.
211 |
212 | :param flags: Flags to be passed into Soup Sieve's
213 | soupsieve.closest() method.
214 |
215 | :param kwargs: Keyword arguments to be passed into SoupSieve's
216 | soupsieve.closest() method.
217 |
218 | :return: A Tag, or None if there is no match.
219 | :rtype: bs4.Tag
220 |
221 | """
222 | return self.api.closest(
223 | select, self.tag, self._ns(namespaces, select), flags, **kwargs
224 | )
225 |
226 | def match(self, select, namespaces=None, flags=0, **kwargs):
227 | """Check whether this Tag matches the given CSS selector.
228 |
229 | This uses the Soup Sieve library. For more information, see
230 | that library's documentation for the soupsieve.match()
231 | method.
232 |
233 | :param: a CSS selector.
234 |
235 | :param namespaces: A dictionary mapping namespace prefixes
236 | used in the CSS selector to namespace URIs. By default,
237 | Beautiful Soup will pass in the prefixes it encountered while
238 | parsing the document.
239 |
240 | :param flags: Flags to be passed into Soup Sieve's
241 | soupsieve.match() method.
242 |
243 | :param kwargs: Keyword arguments to be passed into SoupSieve's
244 | soupsieve.match() method.
245 |
246 | :return: True if this Tag matches the selector; False otherwise.
247 | :rtype: bool
248 | """
249 | return self.api.match(
250 | select, self.tag, self._ns(namespaces, select), flags, **kwargs
251 | )
252 |
253 | def filter(self, select, namespaces=None, flags=0, **kwargs):
254 | """Filter this Tag's direct children based on the given CSS selector.
255 |
256 | This uses the Soup Sieve library. It works the same way as
257 | passing this Tag into that library's soupsieve.filter()
258 | method. More information, for more information see the
259 | documentation for soupsieve.filter().
260 |
261 | :param namespaces: A dictionary mapping namespace prefixes
262 | used in the CSS selector to namespace URIs. By default,
263 | Beautiful Soup will pass in the prefixes it encountered while
264 | parsing the document.
265 |
266 | :param flags: Flags to be passed into Soup Sieve's
267 | soupsieve.filter() method.
268 |
269 | :param kwargs: Keyword arguments to be passed into SoupSieve's
270 | soupsieve.filter() method.
271 |
272 | :return: A ResultSet of Tag objects.
273 | :rtype: bs4.element.ResultSet
274 |
275 | """
276 | return self._rs(
277 | self.api.filter(
278 | select, self.tag, self._ns(namespaces, select), flags, **kwargs
279 | )
280 | )
281 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/windows.py:
--------------------------------------------------------------------------------
```python
1 | """Windows."""
2 |
3 | from __future__ import annotations
4 |
5 | import os
6 | import sys
7 | from functools import lru_cache
8 | from typing import TYPE_CHECKING
9 |
10 | from .api import PlatformDirsABC
11 |
12 | if TYPE_CHECKING:
13 | from collections.abc import Callable
14 |
15 |
16 | class Windows(PlatformDirsABC):
17 | """
18 | `MSDN on where to store app data files <https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid>`_.
19 |
20 | Makes use of the `appname <platformdirs.api.PlatformDirsABC.appname>`, `appauthor
21 | <platformdirs.api.PlatformDirsABC.appauthor>`, `version <platformdirs.api.PlatformDirsABC.version>`, `roaming
22 | <platformdirs.api.PlatformDirsABC.roaming>`, `opinion <platformdirs.api.PlatformDirsABC.opinion>`, `ensure_exists
23 | <platformdirs.api.PlatformDirsABC.ensure_exists>`.
24 |
25 | """
26 |
27 | @property
28 | def user_data_dir(self) -> str:
29 | """
30 | :return: data directory tied to the user, e.g.
31 | ``%USERPROFILE%\\AppData\\Local\\$appauthor\\$appname`` (not roaming) or
32 | ``%USERPROFILE%\\AppData\\Roaming\\$appauthor\\$appname`` (roaming)
33 | """
34 | const = "CSIDL_APPDATA" if self.roaming else "CSIDL_LOCAL_APPDATA"
35 | path = os.path.normpath(get_win_folder(const))
36 | return self._append_parts(path)
37 |
38 | def _append_parts(self, path: str, *, opinion_value: str | None = None) -> str:
39 | params = []
40 | if self.appname:
41 | if self.appauthor is not False:
42 | author = self.appauthor or self.appname
43 | params.append(author)
44 | params.append(self.appname)
45 | if opinion_value is not None and self.opinion:
46 | params.append(opinion_value)
47 | if self.version:
48 | params.append(self.version)
49 | path = os.path.join(path, *params) # noqa: PTH118
50 | self._optionally_create_directory(path)
51 | return path
52 |
53 | @property
54 | def site_data_dir(self) -> str:
55 | """:return: data directory shared by users, e.g. ``C:\\ProgramData\\$appauthor\\$appname``"""
56 | path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA"))
57 | return self._append_parts(path)
58 |
59 | @property
60 | def user_config_dir(self) -> str:
61 | """:return: config directory tied to the user, same as `user_data_dir`"""
62 | return self.user_data_dir
63 |
64 | @property
65 | def site_config_dir(self) -> str:
66 | """:return: config directory shared by the users, same as `site_data_dir`"""
67 | return self.site_data_dir
68 |
69 | @property
70 | def user_cache_dir(self) -> str:
71 | """
72 | :return: cache directory tied to the user (if opinionated with ``Cache`` folder within ``$appname``) e.g.
73 | ``%USERPROFILE%\\AppData\\Local\\$appauthor\\$appname\\Cache\\$version``
74 | """
75 | path = os.path.normpath(get_win_folder("CSIDL_LOCAL_APPDATA"))
76 | return self._append_parts(path, opinion_value="Cache")
77 |
78 | @property
79 | def site_cache_dir(self) -> str:
80 | """:return: cache directory shared by users, e.g. ``C:\\ProgramData\\$appauthor\\$appname\\Cache\\$version``"""
81 | path = os.path.normpath(get_win_folder("CSIDL_COMMON_APPDATA"))
82 | return self._append_parts(path, opinion_value="Cache")
83 |
84 | @property
85 | def user_state_dir(self) -> str:
86 | """:return: state directory tied to the user, same as `user_data_dir`"""
87 | return self.user_data_dir
88 |
89 | @property
90 | def user_log_dir(self) -> str:
91 | """:return: log directory tied to the user, same as `user_data_dir` if not opinionated else ``Logs`` in it"""
92 | path = self.user_data_dir
93 | if self.opinion:
94 | path = os.path.join(path, "Logs") # noqa: PTH118
95 | self._optionally_create_directory(path)
96 | return path
97 |
98 | @property
99 | def user_documents_dir(self) -> str:
100 | """:return: documents directory tied to the user e.g. ``%USERPROFILE%\\Documents``"""
101 | return os.path.normpath(get_win_folder("CSIDL_PERSONAL"))
102 |
103 | @property
104 | def user_downloads_dir(self) -> str:
105 | """:return: downloads directory tied to the user e.g. ``%USERPROFILE%\\Downloads``"""
106 | return os.path.normpath(get_win_folder("CSIDL_DOWNLOADS"))
107 |
108 | @property
109 | def user_pictures_dir(self) -> str:
110 | """:return: pictures directory tied to the user e.g. ``%USERPROFILE%\\Pictures``"""
111 | return os.path.normpath(get_win_folder("CSIDL_MYPICTURES"))
112 |
113 | @property
114 | def user_videos_dir(self) -> str:
115 | """:return: videos directory tied to the user e.g. ``%USERPROFILE%\\Videos``"""
116 | return os.path.normpath(get_win_folder("CSIDL_MYVIDEO"))
117 |
118 | @property
119 | def user_music_dir(self) -> str:
120 | """:return: music directory tied to the user e.g. ``%USERPROFILE%\\Music``"""
121 | return os.path.normpath(get_win_folder("CSIDL_MYMUSIC"))
122 |
123 | @property
124 | def user_desktop_dir(self) -> str:
125 | """:return: desktop directory tied to the user, e.g. ``%USERPROFILE%\\Desktop``"""
126 | return os.path.normpath(get_win_folder("CSIDL_DESKTOPDIRECTORY"))
127 |
128 | @property
129 | def user_runtime_dir(self) -> str:
130 | """
131 | :return: runtime directory tied to the user, e.g.
132 | ``%USERPROFILE%\\AppData\\Local\\Temp\\$appauthor\\$appname``
133 | """
134 | path = os.path.normpath(os.path.join(get_win_folder("CSIDL_LOCAL_APPDATA"), "Temp")) # noqa: PTH118
135 | return self._append_parts(path)
136 |
137 | @property
138 | def site_runtime_dir(self) -> str:
139 | """:return: runtime directory shared by users, same as `user_runtime_dir`"""
140 | return self.user_runtime_dir
141 |
142 |
143 | def get_win_folder_from_env_vars(csidl_name: str) -> str:
144 | """Get folder from environment variables."""
145 | result = get_win_folder_if_csidl_name_not_env_var(csidl_name)
146 | if result is not None:
147 | return result
148 |
149 | env_var_name = {
150 | "CSIDL_APPDATA": "APPDATA",
151 | "CSIDL_COMMON_APPDATA": "ALLUSERSPROFILE",
152 | "CSIDL_LOCAL_APPDATA": "LOCALAPPDATA",
153 | }.get(csidl_name)
154 | if env_var_name is None:
155 | msg = f"Unknown CSIDL name: {csidl_name}"
156 | raise ValueError(msg)
157 | result = os.environ.get(env_var_name)
158 | if result is None:
159 | msg = f"Unset environment variable: {env_var_name}"
160 | raise ValueError(msg)
161 | return result
162 |
163 |
164 | def get_win_folder_if_csidl_name_not_env_var(csidl_name: str) -> str | None:
165 | """Get a folder for a CSIDL name that does not exist as an environment variable."""
166 | if csidl_name == "CSIDL_PERSONAL":
167 | return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Documents") # noqa: PTH118
168 |
169 | if csidl_name == "CSIDL_DOWNLOADS":
170 | return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Downloads") # noqa: PTH118
171 |
172 | if csidl_name == "CSIDL_MYPICTURES":
173 | return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Pictures") # noqa: PTH118
174 |
175 | if csidl_name == "CSIDL_MYVIDEO":
176 | return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Videos") # noqa: PTH118
177 |
178 | if csidl_name == "CSIDL_MYMUSIC":
179 | return os.path.join(os.path.normpath(os.environ["USERPROFILE"]), "Music") # noqa: PTH118
180 | return None
181 |
182 |
183 | def get_win_folder_from_registry(csidl_name: str) -> str:
184 | """
185 | Get folder from the registry.
186 |
187 | This is a fallback technique at best. I'm not sure if using the registry for these guarantees us the correct answer
188 | for all CSIDL_* names.
189 |
190 | """
191 | shell_folder_name = {
192 | "CSIDL_APPDATA": "AppData",
193 | "CSIDL_COMMON_APPDATA": "Common AppData",
194 | "CSIDL_LOCAL_APPDATA": "Local AppData",
195 | "CSIDL_PERSONAL": "Personal",
196 | "CSIDL_DOWNLOADS": "{374DE290-123F-4565-9164-39C4925E467B}",
197 | "CSIDL_MYPICTURES": "My Pictures",
198 | "CSIDL_MYVIDEO": "My Video",
199 | "CSIDL_MYMUSIC": "My Music",
200 | }.get(csidl_name)
201 | if shell_folder_name is None:
202 | msg = f"Unknown CSIDL name: {csidl_name}"
203 | raise ValueError(msg)
204 | if sys.platform != "win32": # only needed for mypy type checker to know that this code runs only on Windows
205 | raise NotImplementedError
206 | import winreg # noqa: PLC0415
207 |
208 | key = winreg.OpenKey(winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders")
209 | directory, _ = winreg.QueryValueEx(key, shell_folder_name)
210 | return str(directory)
211 |
212 |
213 | def get_win_folder_via_ctypes(csidl_name: str) -> str:
214 | """Get folder with ctypes."""
215 | # There is no 'CSIDL_DOWNLOADS'.
216 | # Use 'CSIDL_PROFILE' (40) and append the default folder 'Downloads' instead.
217 | # https://learn.microsoft.com/en-us/windows/win32/shell/knownfolderid
218 |
219 | import ctypes # noqa: PLC0415
220 |
221 | csidl_const = {
222 | "CSIDL_APPDATA": 26,
223 | "CSIDL_COMMON_APPDATA": 35,
224 | "CSIDL_LOCAL_APPDATA": 28,
225 | "CSIDL_PERSONAL": 5,
226 | "CSIDL_MYPICTURES": 39,
227 | "CSIDL_MYVIDEO": 14,
228 | "CSIDL_MYMUSIC": 13,
229 | "CSIDL_DOWNLOADS": 40,
230 | "CSIDL_DESKTOPDIRECTORY": 16,
231 | }.get(csidl_name)
232 | if csidl_const is None:
233 | msg = f"Unknown CSIDL name: {csidl_name}"
234 | raise ValueError(msg)
235 |
236 | buf = ctypes.create_unicode_buffer(1024)
237 | windll = getattr(ctypes, "windll") # noqa: B009 # using getattr to avoid false positive with mypy type checker
238 | windll.shell32.SHGetFolderPathW(None, csidl_const, None, 0, buf)
239 |
240 | # Downgrade to short path name if it has high-bit chars.
241 | if any(ord(c) > 255 for c in buf): # noqa: PLR2004
242 | buf2 = ctypes.create_unicode_buffer(1024)
243 | if windll.kernel32.GetShortPathNameW(buf.value, buf2, 1024):
244 | buf = buf2
245 |
246 | if csidl_name == "CSIDL_DOWNLOADS":
247 | return os.path.join(buf.value, "Downloads") # noqa: PTH118
248 |
249 | return buf.value
250 |
251 |
252 | def _pick_get_win_folder() -> Callable[[str], str]:
253 | try:
254 | import ctypes # noqa: PLC0415
255 | except ImportError:
256 | pass
257 | else:
258 | if hasattr(ctypes, "windll"):
259 | return get_win_folder_via_ctypes
260 | try:
261 | import winreg # noqa: PLC0415, F401
262 | except ImportError:
263 | return get_win_folder_from_env_vars
264 | else:
265 | return get_win_folder_from_registry
266 |
267 |
268 | get_win_folder = lru_cache(maxsize=None)(_pick_get_win_folder())
269 |
270 | __all__ = [
271 | "Windows",
272 | ]
273 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/flask/testing.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import importlib.metadata
4 | import typing as t
5 | from contextlib import contextmanager
6 | from contextlib import ExitStack
7 | from copy import copy
8 | from types import TracebackType
9 | from urllib.parse import urlsplit
10 |
11 | import werkzeug.test
12 | from click.testing import CliRunner
13 | from werkzeug.test import Client
14 | from werkzeug.wrappers import Request as BaseRequest
15 |
16 | from .cli import ScriptInfo
17 | from .sessions import SessionMixin
18 |
19 | if t.TYPE_CHECKING: # pragma: no cover
20 | from _typeshed.wsgi import WSGIEnvironment
21 | from werkzeug.test import TestResponse
22 |
23 | from .app import Flask
24 |
25 |
26 | class EnvironBuilder(werkzeug.test.EnvironBuilder):
27 | """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the
28 | application.
29 |
30 | :param app: The Flask application to configure the environment from.
31 | :param path: URL path being requested.
32 | :param base_url: Base URL where the app is being served, which
33 | ``path`` is relative to. If not given, built from
34 | :data:`PREFERRED_URL_SCHEME`, ``subdomain``,
35 | :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`.
36 | :param subdomain: Subdomain name to append to :data:`SERVER_NAME`.
37 | :param url_scheme: Scheme to use instead of
38 | :data:`PREFERRED_URL_SCHEME`.
39 | :param json: If given, this is serialized as JSON and passed as
40 | ``data``. Also defaults ``content_type`` to
41 | ``application/json``.
42 | :param args: other positional arguments passed to
43 | :class:`~werkzeug.test.EnvironBuilder`.
44 | :param kwargs: other keyword arguments passed to
45 | :class:`~werkzeug.test.EnvironBuilder`.
46 | """
47 |
48 | def __init__(
49 | self,
50 | app: Flask,
51 | path: str = "/",
52 | base_url: str | None = None,
53 | subdomain: str | None = None,
54 | url_scheme: str | None = None,
55 | *args: t.Any,
56 | **kwargs: t.Any,
57 | ) -> None:
58 | assert not (base_url or subdomain or url_scheme) or (
59 | base_url is not None
60 | ) != bool(
61 | subdomain or url_scheme
62 | ), 'Cannot pass "subdomain" or "url_scheme" with "base_url".'
63 |
64 | if base_url is None:
65 | http_host = app.config.get("SERVER_NAME") or "localhost"
66 | app_root = app.config["APPLICATION_ROOT"]
67 |
68 | if subdomain:
69 | http_host = f"{subdomain}.{http_host}"
70 |
71 | if url_scheme is None:
72 | url_scheme = app.config["PREFERRED_URL_SCHEME"]
73 |
74 | url = urlsplit(path)
75 | base_url = (
76 | f"{url.scheme or url_scheme}://{url.netloc or http_host}"
77 | f"/{app_root.lstrip('/')}"
78 | )
79 | path = url.path
80 |
81 | if url.query:
82 | sep = b"?" if isinstance(url.query, bytes) else "?"
83 | path += sep + url.query
84 |
85 | self.app = app
86 | super().__init__(path, base_url, *args, **kwargs)
87 |
88 | def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: # type: ignore
89 | """Serialize ``obj`` to a JSON-formatted string.
90 |
91 | The serialization will be configured according to the config associated
92 | with this EnvironBuilder's ``app``.
93 | """
94 | return self.app.json.dumps(obj, **kwargs)
95 |
96 |
97 | _werkzeug_version = ""
98 |
99 |
100 | def _get_werkzeug_version() -> str:
101 | global _werkzeug_version
102 |
103 | if not _werkzeug_version:
104 | _werkzeug_version = importlib.metadata.version("werkzeug")
105 |
106 | return _werkzeug_version
107 |
108 |
109 | class FlaskClient(Client):
110 | """Works like a regular Werkzeug test client but has knowledge about
111 | Flask's contexts to defer the cleanup of the request context until
112 | the end of a ``with`` block. For general information about how to
113 | use this class refer to :class:`werkzeug.test.Client`.
114 |
115 | .. versionchanged:: 0.12
116 | `app.test_client()` includes preset default environment, which can be
117 | set after instantiation of the `app.test_client()` object in
118 | `client.environ_base`.
119 |
120 | Basic usage is outlined in the :doc:`/testing` chapter.
121 | """
122 |
123 | application: Flask
124 |
125 | def __init__(self, *args: t.Any, **kwargs: t.Any) -> None:
126 | super().__init__(*args, **kwargs)
127 | self.preserve_context = False
128 | self._new_contexts: list[t.ContextManager[t.Any]] = []
129 | self._context_stack = ExitStack()
130 | self.environ_base = {
131 | "REMOTE_ADDR": "127.0.0.1",
132 | "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}",
133 | }
134 |
135 | @contextmanager
136 | def session_transaction(
137 | self, *args: t.Any, **kwargs: t.Any
138 | ) -> t.Iterator[SessionMixin]:
139 | """When used in combination with a ``with`` statement this opens a
140 | session transaction. This can be used to modify the session that
141 | the test client uses. Once the ``with`` block is left the session is
142 | stored back.
143 |
144 | ::
145 |
146 | with client.session_transaction() as session:
147 | session['value'] = 42
148 |
149 | Internally this is implemented by going through a temporary test
150 | request context and since session handling could depend on
151 | request variables this function accepts the same arguments as
152 | :meth:`~flask.Flask.test_request_context` which are directly
153 | passed through.
154 | """
155 | if self._cookies is None:
156 | raise TypeError(
157 | "Cookies are disabled. Create a client with 'use_cookies=True'."
158 | )
159 |
160 | app = self.application
161 | ctx = app.test_request_context(*args, **kwargs)
162 | self._add_cookies_to_wsgi(ctx.request.environ)
163 |
164 | with ctx:
165 | sess = app.session_interface.open_session(app, ctx.request)
166 |
167 | if sess is None:
168 | raise RuntimeError("Session backend did not open a session.")
169 |
170 | yield sess
171 | resp = app.response_class()
172 |
173 | if app.session_interface.is_null_session(sess):
174 | return
175 |
176 | with ctx:
177 | app.session_interface.save_session(app, sess, resp)
178 |
179 | self._update_cookies_from_response(
180 | ctx.request.host.partition(":")[0],
181 | ctx.request.path,
182 | resp.headers.getlist("Set-Cookie"),
183 | )
184 |
185 | def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment:
186 | out = {**self.environ_base, **other}
187 |
188 | if self.preserve_context:
189 | out["werkzeug.debug.preserve_context"] = self._new_contexts.append
190 |
191 | return out
192 |
193 | def _request_from_builder_args(
194 | self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any]
195 | ) -> BaseRequest:
196 | kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {}))
197 | builder = EnvironBuilder(self.application, *args, **kwargs)
198 |
199 | try:
200 | return builder.get_request()
201 | finally:
202 | builder.close()
203 |
204 | def open(
205 | self,
206 | *args: t.Any,
207 | buffered: bool = False,
208 | follow_redirects: bool = False,
209 | **kwargs: t.Any,
210 | ) -> TestResponse:
211 | if args and isinstance(
212 | args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest)
213 | ):
214 | if isinstance(args[0], werkzeug.test.EnvironBuilder):
215 | builder = copy(args[0])
216 | builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type]
217 | request = builder.get_request()
218 | elif isinstance(args[0], dict):
219 | request = EnvironBuilder.from_environ(
220 | args[0], app=self.application, environ_base=self._copy_environ({})
221 | ).get_request()
222 | else:
223 | # isinstance(args[0], BaseRequest)
224 | request = copy(args[0])
225 | request.environ = self._copy_environ(request.environ)
226 | else:
227 | # request is None
228 | request = self._request_from_builder_args(args, kwargs)
229 |
230 | # Pop any previously preserved contexts. This prevents contexts
231 | # from being preserved across redirects or multiple requests
232 | # within a single block.
233 | self._context_stack.close()
234 |
235 | response = super().open(
236 | request,
237 | buffered=buffered,
238 | follow_redirects=follow_redirects,
239 | )
240 | response.json_module = self.application.json # type: ignore[assignment]
241 |
242 | # Re-push contexts that were preserved during the request.
243 | while self._new_contexts:
244 | cm = self._new_contexts.pop()
245 | self._context_stack.enter_context(cm)
246 |
247 | return response
248 |
249 | def __enter__(self) -> FlaskClient:
250 | if self.preserve_context:
251 | raise RuntimeError("Cannot nest client invocations")
252 | self.preserve_context = True
253 | return self
254 |
255 | def __exit__(
256 | self,
257 | exc_type: type | None,
258 | exc_value: BaseException | None,
259 | tb: TracebackType | None,
260 | ) -> None:
261 | self.preserve_context = False
262 | self._context_stack.close()
263 |
264 |
265 | class FlaskCliRunner(CliRunner):
266 | """A :class:`~click.testing.CliRunner` for testing a Flask app's
267 | CLI commands. Typically created using
268 | :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`.
269 | """
270 |
271 | def __init__(self, app: Flask, **kwargs: t.Any) -> None:
272 | self.app = app
273 | super().__init__(**kwargs)
274 |
275 | def invoke( # type: ignore
276 | self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any
277 | ) -> t.Any:
278 | """Invokes a CLI command in an isolated environment. See
279 | :meth:`CliRunner.invoke <click.testing.CliRunner.invoke>` for
280 | full method documentation. See :ref:`testing-cli` for examples.
281 |
282 | If the ``obj`` argument is not given, passes an instance of
283 | :class:`~flask.cli.ScriptInfo` that knows how to load the Flask
284 | app being tested.
285 |
286 | :param cli: Command object to invoke. Default is the app's
287 | :attr:`~flask.app.Flask.cli` group.
288 | :param args: List of strings to invoke the command with.
289 |
290 | :return: a :class:`~click.testing.Result` object.
291 | """
292 | if cli is None:
293 | cli = self.app.cli
294 |
295 | if "obj" not in kwargs:
296 | kwargs["obj"] = ScriptInfo(create_app=lambda: self.app)
297 |
298 | return super().invoke(cli, args, **kwargs)
299 |
```