This is page 80 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py:
--------------------------------------------------------------------------------
```python
1 | import functools
2 | import os
3 | import sys
4 | import sysconfig
5 | from importlib.util import cache_from_source
6 | from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Set, Tuple
7 |
8 | from pip._internal.exceptions import LegacyDistutilsInstall, UninstallMissingRecord
9 | from pip._internal.locations import get_bin_prefix, get_bin_user
10 | from pip._internal.metadata import BaseDistribution
11 | from pip._internal.utils.compat import WINDOWS
12 | from pip._internal.utils.egg_link import egg_link_path_from_location
13 | from pip._internal.utils.logging import getLogger, indent_log
14 | from pip._internal.utils.misc import ask, normalize_path, renames, rmtree
15 | from pip._internal.utils.temp_dir import AdjacentTempDirectory, TempDirectory
16 | from pip._internal.utils.virtualenv import running_under_virtualenv
17 |
18 | logger = getLogger(__name__)
19 |
20 |
21 | def _script_names(
22 | bin_dir: str, script_name: str, is_gui: bool
23 | ) -> Generator[str, None, None]:
24 | """Create the fully qualified name of the files created by
25 | {console,gui}_scripts for the given ``dist``.
26 | Returns the list of file names
27 | """
28 | exe_name = os.path.join(bin_dir, script_name)
29 | yield exe_name
30 | if not WINDOWS:
31 | return
32 | yield f"{exe_name}.exe"
33 | yield f"{exe_name}.exe.manifest"
34 | if is_gui:
35 | yield f"{exe_name}-script.pyw"
36 | else:
37 | yield f"{exe_name}-script.py"
38 |
39 |
40 | def _unique(
41 | fn: Callable[..., Generator[Any, None, None]]
42 | ) -> Callable[..., Generator[Any, None, None]]:
43 | @functools.wraps(fn)
44 | def unique(*args: Any, **kw: Any) -> Generator[Any, None, None]:
45 | seen: Set[Any] = set()
46 | for item in fn(*args, **kw):
47 | if item not in seen:
48 | seen.add(item)
49 | yield item
50 |
51 | return unique
52 |
53 |
54 | @_unique
55 | def uninstallation_paths(dist: BaseDistribution) -> Generator[str, None, None]:
56 | """
57 | Yield all the uninstallation paths for dist based on RECORD-without-.py[co]
58 |
59 | Yield paths to all the files in RECORD. For each .py file in RECORD, add
60 | the .pyc and .pyo in the same directory.
61 |
62 | UninstallPathSet.add() takes care of the __pycache__ .py[co].
63 |
64 | If RECORD is not found, raises an error,
65 | with possible information from the INSTALLER file.
66 |
67 | https://packaging.python.org/specifications/recording-installed-packages/
68 | """
69 | location = dist.location
70 | assert location is not None, "not installed"
71 |
72 | entries = dist.iter_declared_entries()
73 | if entries is None:
74 | raise UninstallMissingRecord(distribution=dist)
75 |
76 | for entry in entries:
77 | path = os.path.join(location, entry)
78 | yield path
79 | if path.endswith(".py"):
80 | dn, fn = os.path.split(path)
81 | base = fn[:-3]
82 | path = os.path.join(dn, base + ".pyc")
83 | yield path
84 | path = os.path.join(dn, base + ".pyo")
85 | yield path
86 |
87 |
88 | def compact(paths: Iterable[str]) -> Set[str]:
89 | """Compact a path set to contain the minimal number of paths
90 | necessary to contain all paths in the set. If /a/path/ and
91 | /a/path/to/a/file.txt are both in the set, leave only the
92 | shorter path."""
93 |
94 | sep = os.path.sep
95 | short_paths: Set[str] = set()
96 | for path in sorted(paths, key=len):
97 | should_skip = any(
98 | path.startswith(shortpath.rstrip("*"))
99 | and path[len(shortpath.rstrip("*").rstrip(sep))] == sep
100 | for shortpath in short_paths
101 | )
102 | if not should_skip:
103 | short_paths.add(path)
104 | return short_paths
105 |
106 |
107 | def compress_for_rename(paths: Iterable[str]) -> Set[str]:
108 | """Returns a set containing the paths that need to be renamed.
109 |
110 | This set may include directories when the original sequence of paths
111 | included every file on disk.
112 | """
113 | case_map = {os.path.normcase(p): p for p in paths}
114 | remaining = set(case_map)
115 | unchecked = sorted({os.path.split(p)[0] for p in case_map.values()}, key=len)
116 | wildcards: Set[str] = set()
117 |
118 | def norm_join(*a: str) -> str:
119 | return os.path.normcase(os.path.join(*a))
120 |
121 | for root in unchecked:
122 | if any(os.path.normcase(root).startswith(w) for w in wildcards):
123 | # This directory has already been handled.
124 | continue
125 |
126 | all_files: Set[str] = set()
127 | all_subdirs: Set[str] = set()
128 | for dirname, subdirs, files in os.walk(root):
129 | all_subdirs.update(norm_join(root, dirname, d) for d in subdirs)
130 | all_files.update(norm_join(root, dirname, f) for f in files)
131 | # If all the files we found are in our remaining set of files to
132 | # remove, then remove them from the latter set and add a wildcard
133 | # for the directory.
134 | if not (all_files - remaining):
135 | remaining.difference_update(all_files)
136 | wildcards.add(root + os.sep)
137 |
138 | return set(map(case_map.__getitem__, remaining)) | wildcards
139 |
140 |
141 | def compress_for_output_listing(paths: Iterable[str]) -> Tuple[Set[str], Set[str]]:
142 | """Returns a tuple of 2 sets of which paths to display to user
143 |
144 | The first set contains paths that would be deleted. Files of a package
145 | are not added and the top-level directory of the package has a '*' added
146 | at the end - to signify that all it's contents are removed.
147 |
148 | The second set contains files that would have been skipped in the above
149 | folders.
150 | """
151 |
152 | will_remove = set(paths)
153 | will_skip = set()
154 |
155 | # Determine folders and files
156 | folders = set()
157 | files = set()
158 | for path in will_remove:
159 | if path.endswith(".pyc"):
160 | continue
161 | if path.endswith("__init__.py") or ".dist-info" in path:
162 | folders.add(os.path.dirname(path))
163 | files.add(path)
164 |
165 | _normcased_files = set(map(os.path.normcase, files))
166 |
167 | folders = compact(folders)
168 |
169 | # This walks the tree using os.walk to not miss extra folders
170 | # that might get added.
171 | for folder in folders:
172 | for dirpath, _, dirfiles in os.walk(folder):
173 | for fname in dirfiles:
174 | if fname.endswith(".pyc"):
175 | continue
176 |
177 | file_ = os.path.join(dirpath, fname)
178 | if (
179 | os.path.isfile(file_)
180 | and os.path.normcase(file_) not in _normcased_files
181 | ):
182 | # We are skipping this file. Add it to the set.
183 | will_skip.add(file_)
184 |
185 | will_remove = files | {os.path.join(folder, "*") for folder in folders}
186 |
187 | return will_remove, will_skip
188 |
189 |
190 | class StashedUninstallPathSet:
191 | """A set of file rename operations to stash files while
192 | tentatively uninstalling them."""
193 |
194 | def __init__(self) -> None:
195 | # Mapping from source file root to [Adjacent]TempDirectory
196 | # for files under that directory.
197 | self._save_dirs: Dict[str, TempDirectory] = {}
198 | # (old path, new path) tuples for each move that may need
199 | # to be undone.
200 | self._moves: List[Tuple[str, str]] = []
201 |
202 | def _get_directory_stash(self, path: str) -> str:
203 | """Stashes a directory.
204 |
205 | Directories are stashed adjacent to their original location if
206 | possible, or else moved/copied into the user's temp dir."""
207 |
208 | try:
209 | save_dir: TempDirectory = AdjacentTempDirectory(path)
210 | except OSError:
211 | save_dir = TempDirectory(kind="uninstall")
212 | self._save_dirs[os.path.normcase(path)] = save_dir
213 |
214 | return save_dir.path
215 |
216 | def _get_file_stash(self, path: str) -> str:
217 | """Stashes a file.
218 |
219 | If no root has been provided, one will be created for the directory
220 | in the user's temp directory."""
221 | path = os.path.normcase(path)
222 | head, old_head = os.path.dirname(path), None
223 | save_dir = None
224 |
225 | while head != old_head:
226 | try:
227 | save_dir = self._save_dirs[head]
228 | break
229 | except KeyError:
230 | pass
231 | head, old_head = os.path.dirname(head), head
232 | else:
233 | # Did not find any suitable root
234 | head = os.path.dirname(path)
235 | save_dir = TempDirectory(kind="uninstall")
236 | self._save_dirs[head] = save_dir
237 |
238 | relpath = os.path.relpath(path, head)
239 | if relpath and relpath != os.path.curdir:
240 | return os.path.join(save_dir.path, relpath)
241 | return save_dir.path
242 |
243 | def stash(self, path: str) -> str:
244 | """Stashes the directory or file and returns its new location.
245 | Handle symlinks as files to avoid modifying the symlink targets.
246 | """
247 | path_is_dir = os.path.isdir(path) and not os.path.islink(path)
248 | if path_is_dir:
249 | new_path = self._get_directory_stash(path)
250 | else:
251 | new_path = self._get_file_stash(path)
252 |
253 | self._moves.append((path, new_path))
254 | if path_is_dir and os.path.isdir(new_path):
255 | # If we're moving a directory, we need to
256 | # remove the destination first or else it will be
257 | # moved to inside the existing directory.
258 | # We just created new_path ourselves, so it will
259 | # be removable.
260 | os.rmdir(new_path)
261 | renames(path, new_path)
262 | return new_path
263 |
264 | def commit(self) -> None:
265 | """Commits the uninstall by removing stashed files."""
266 | for save_dir in self._save_dirs.values():
267 | save_dir.cleanup()
268 | self._moves = []
269 | self._save_dirs = {}
270 |
271 | def rollback(self) -> None:
272 | """Undoes the uninstall by moving stashed files back."""
273 | for p in self._moves:
274 | logger.info("Moving to %s\n from %s", *p)
275 |
276 | for new_path, path in self._moves:
277 | try:
278 | logger.debug("Replacing %s from %s", new_path, path)
279 | if os.path.isfile(new_path) or os.path.islink(new_path):
280 | os.unlink(new_path)
281 | elif os.path.isdir(new_path):
282 | rmtree(new_path)
283 | renames(path, new_path)
284 | except OSError as ex:
285 | logger.error("Failed to restore %s", new_path)
286 | logger.debug("Exception: %s", ex)
287 |
288 | self.commit()
289 |
290 | @property
291 | def can_rollback(self) -> bool:
292 | return bool(self._moves)
293 |
294 |
295 | class UninstallPathSet:
296 | """A set of file paths to be removed in the uninstallation of a
297 | requirement."""
298 |
299 | def __init__(self, dist: BaseDistribution) -> None:
300 | self._paths: Set[str] = set()
301 | self._refuse: Set[str] = set()
302 | self._pth: Dict[str, UninstallPthEntries] = {}
303 | self._dist = dist
304 | self._moved_paths = StashedUninstallPathSet()
305 | # Create local cache of normalize_path results. Creating an UninstallPathSet
306 | # can result in hundreds/thousands of redundant calls to normalize_path with
307 | # the same args, which hurts performance.
308 | self._normalize_path_cached = functools.lru_cache(normalize_path)
309 |
310 | def _permitted(self, path: str) -> bool:
311 | """
312 | Return True if the given path is one we are permitted to
313 | remove/modify, False otherwise.
314 |
315 | """
316 | # aka is_local, but caching normalized sys.prefix
317 | if not running_under_virtualenv():
318 | return True
319 | return path.startswith(self._normalize_path_cached(sys.prefix))
320 |
321 | def add(self, path: str) -> None:
322 | head, tail = os.path.split(path)
323 |
324 | # we normalize the head to resolve parent directory symlinks, but not
325 | # the tail, since we only want to uninstall symlinks, not their targets
326 | path = os.path.join(self._normalize_path_cached(head), os.path.normcase(tail))
327 |
328 | if not os.path.exists(path):
329 | return
330 | if self._permitted(path):
331 | self._paths.add(path)
332 | else:
333 | self._refuse.add(path)
334 |
335 | # __pycache__ files can show up after 'installed-files.txt' is created,
336 | # due to imports
337 | if os.path.splitext(path)[1] == ".py":
338 | self.add(cache_from_source(path))
339 |
340 | def add_pth(self, pth_file: str, entry: str) -> None:
341 | pth_file = self._normalize_path_cached(pth_file)
342 | if self._permitted(pth_file):
343 | if pth_file not in self._pth:
344 | self._pth[pth_file] = UninstallPthEntries(pth_file)
345 | self._pth[pth_file].add(entry)
346 | else:
347 | self._refuse.add(pth_file)
348 |
349 | def remove(self, auto_confirm: bool = False, verbose: bool = False) -> None:
350 | """Remove paths in ``self._paths`` with confirmation (unless
351 | ``auto_confirm`` is True)."""
352 |
353 | if not self._paths:
354 | logger.info(
355 | "Can't uninstall '%s'. No files were found to uninstall.",
356 | self._dist.raw_name,
357 | )
358 | return
359 |
360 | dist_name_version = f"{self._dist.raw_name}-{self._dist.raw_version}"
361 | logger.info("Uninstalling %s:", dist_name_version)
362 |
363 | with indent_log():
364 | if auto_confirm or self._allowed_to_proceed(verbose):
365 | moved = self._moved_paths
366 |
367 | for_rename = compress_for_rename(self._paths)
368 |
369 | for path in sorted(compact(for_rename)):
370 | moved.stash(path)
371 | logger.verbose("Removing file or directory %s", path)
372 |
373 | for pth in self._pth.values():
374 | pth.remove()
375 |
376 | logger.info("Successfully uninstalled %s", dist_name_version)
377 |
378 | def _allowed_to_proceed(self, verbose: bool) -> bool:
379 | """Display which files would be deleted and prompt for confirmation"""
380 |
381 | def _display(msg: str, paths: Iterable[str]) -> None:
382 | if not paths:
383 | return
384 |
385 | logger.info(msg)
386 | with indent_log():
387 | for path in sorted(compact(paths)):
388 | logger.info(path)
389 |
390 | if not verbose:
391 | will_remove, will_skip = compress_for_output_listing(self._paths)
392 | else:
393 | # In verbose mode, display all the files that are going to be
394 | # deleted.
395 | will_remove = set(self._paths)
396 | will_skip = set()
397 |
398 | _display("Would remove:", will_remove)
399 | _display("Would not remove (might be manually added):", will_skip)
400 | _display("Would not remove (outside of prefix):", self._refuse)
401 | if verbose:
402 | _display("Will actually move:", compress_for_rename(self._paths))
403 |
404 | return ask("Proceed (Y/n)? ", ("y", "n", "")) != "n"
405 |
406 | def rollback(self) -> None:
407 | """Rollback the changes previously made by remove()."""
408 | if not self._moved_paths.can_rollback:
409 | logger.error(
410 | "Can't roll back %s; was not uninstalled",
411 | self._dist.raw_name,
412 | )
413 | return
414 | logger.info("Rolling back uninstall of %s", self._dist.raw_name)
415 | self._moved_paths.rollback()
416 | for pth in self._pth.values():
417 | pth.rollback()
418 |
419 | def commit(self) -> None:
420 | """Remove temporary save dir: rollback will no longer be possible."""
421 | self._moved_paths.commit()
422 |
423 | @classmethod
424 | def from_dist(cls, dist: BaseDistribution) -> "UninstallPathSet":
425 | dist_location = dist.location
426 | info_location = dist.info_location
427 | if dist_location is None:
428 | logger.info(
429 | "Not uninstalling %s since it is not installed",
430 | dist.canonical_name,
431 | )
432 | return cls(dist)
433 |
434 | normalized_dist_location = normalize_path(dist_location)
435 | if not dist.local:
436 | logger.info(
437 | "Not uninstalling %s at %s, outside environment %s",
438 | dist.canonical_name,
439 | normalized_dist_location,
440 | sys.prefix,
441 | )
442 | return cls(dist)
443 |
444 | if normalized_dist_location in {
445 | p
446 | for p in {sysconfig.get_path("stdlib"), sysconfig.get_path("platstdlib")}
447 | if p
448 | }:
449 | logger.info(
450 | "Not uninstalling %s at %s, as it is in the standard library.",
451 | dist.canonical_name,
452 | normalized_dist_location,
453 | )
454 | return cls(dist)
455 |
456 | paths_to_remove = cls(dist)
457 | develop_egg_link = egg_link_path_from_location(dist.raw_name)
458 |
459 | # Distribution is installed with metadata in a "flat" .egg-info
460 | # directory. This means it is not a modern .dist-info installation, an
461 | # egg, or legacy editable.
462 | setuptools_flat_installation = (
463 | dist.installed_with_setuptools_egg_info
464 | and info_location is not None
465 | and os.path.exists(info_location)
466 | # If dist is editable and the location points to a ``.egg-info``,
467 | # we are in fact in the legacy editable case.
468 | and not info_location.endswith(f"{dist.setuptools_filename}.egg-info")
469 | )
470 |
471 | # Uninstall cases order do matter as in the case of 2 installs of the
472 | # same package, pip needs to uninstall the currently detected version
473 | if setuptools_flat_installation:
474 | if info_location is not None:
475 | paths_to_remove.add(info_location)
476 | installed_files = dist.iter_declared_entries()
477 | if installed_files is not None:
478 | for installed_file in installed_files:
479 | paths_to_remove.add(os.path.join(dist_location, installed_file))
480 | # FIXME: need a test for this elif block
481 | # occurs with --single-version-externally-managed/--record outside
482 | # of pip
483 | elif dist.is_file("top_level.txt"):
484 | try:
485 | namespace_packages = dist.read_text("namespace_packages.txt")
486 | except FileNotFoundError:
487 | namespaces = []
488 | else:
489 | namespaces = namespace_packages.splitlines(keepends=False)
490 | for top_level_pkg in [
491 | p
492 | for p in dist.read_text("top_level.txt").splitlines()
493 | if p and p not in namespaces
494 | ]:
495 | path = os.path.join(dist_location, top_level_pkg)
496 | paths_to_remove.add(path)
497 | paths_to_remove.add(f"{path}.py")
498 | paths_to_remove.add(f"{path}.pyc")
499 | paths_to_remove.add(f"{path}.pyo")
500 |
501 | elif dist.installed_by_distutils:
502 | raise LegacyDistutilsInstall(distribution=dist)
503 |
504 | elif dist.installed_as_egg:
505 | # package installed by easy_install
506 | # We cannot match on dist.egg_name because it can slightly vary
507 | # i.e. setuptools-0.6c11-py2.6.egg vs setuptools-0.6rc11-py2.6.egg
508 | paths_to_remove.add(dist_location)
509 | easy_install_egg = os.path.split(dist_location)[1]
510 | easy_install_pth = os.path.join(
511 | os.path.dirname(dist_location),
512 | "easy-install.pth",
513 | )
514 | paths_to_remove.add_pth(easy_install_pth, "./" + easy_install_egg)
515 |
516 | elif dist.installed_with_dist_info:
517 | for path in uninstallation_paths(dist):
518 | paths_to_remove.add(path)
519 |
520 | elif develop_egg_link:
521 | # PEP 660 modern editable is handled in the ``.dist-info`` case
522 | # above, so this only covers the setuptools-style editable.
523 | with open(develop_egg_link) as fh:
524 | link_pointer = os.path.normcase(fh.readline().strip())
525 | normalized_link_pointer = paths_to_remove._normalize_path_cached(
526 | link_pointer
527 | )
528 | assert os.path.samefile(
529 | normalized_link_pointer, normalized_dist_location
530 | ), (
531 | f"Egg-link {develop_egg_link} (to {link_pointer}) does not match "
532 | f"installed location of {dist.raw_name} (at {dist_location})"
533 | )
534 | paths_to_remove.add(develop_egg_link)
535 | easy_install_pth = os.path.join(
536 | os.path.dirname(develop_egg_link), "easy-install.pth"
537 | )
538 | paths_to_remove.add_pth(easy_install_pth, dist_location)
539 |
540 | else:
541 | logger.debug(
542 | "Not sure how to uninstall: %s - Check: %s",
543 | dist,
544 | dist_location,
545 | )
546 |
547 | if dist.in_usersite:
548 | bin_dir = get_bin_user()
549 | else:
550 | bin_dir = get_bin_prefix()
551 |
552 | # find distutils scripts= scripts
553 | try:
554 | for script in dist.iter_distutils_script_names():
555 | paths_to_remove.add(os.path.join(bin_dir, script))
556 | if WINDOWS:
557 | paths_to_remove.add(os.path.join(bin_dir, f"{script}.bat"))
558 | except (FileNotFoundError, NotADirectoryError):
559 | pass
560 |
561 | # find console_scripts and gui_scripts
562 | def iter_scripts_to_remove(
563 | dist: BaseDistribution,
564 | bin_dir: str,
565 | ) -> Generator[str, None, None]:
566 | for entry_point in dist.iter_entry_points():
567 | if entry_point.group == "console_scripts":
568 | yield from _script_names(bin_dir, entry_point.name, False)
569 | elif entry_point.group == "gui_scripts":
570 | yield from _script_names(bin_dir, entry_point.name, True)
571 |
572 | for s in iter_scripts_to_remove(dist, bin_dir):
573 | paths_to_remove.add(s)
574 |
575 | return paths_to_remove
576 |
577 |
578 | class UninstallPthEntries:
579 | def __init__(self, pth_file: str) -> None:
580 | self.file = pth_file
581 | self.entries: Set[str] = set()
582 | self._saved_lines: Optional[List[bytes]] = None
583 |
584 | def add(self, entry: str) -> None:
585 | entry = os.path.normcase(entry)
586 | # On Windows, os.path.normcase converts the entry to use
587 | # backslashes. This is correct for entries that describe absolute
588 | # paths outside of site-packages, but all the others use forward
589 | # slashes.
590 | # os.path.splitdrive is used instead of os.path.isabs because isabs
591 | # treats non-absolute paths with drive letter markings like c:foo\bar
592 | # as absolute paths. It also does not recognize UNC paths if they don't
593 | # have more than "\\sever\share". Valid examples: "\\server\share\" or
594 | # "\\server\share\folder".
595 | if WINDOWS and not os.path.splitdrive(entry)[0]:
596 | entry = entry.replace("\\", "/")
597 | self.entries.add(entry)
598 |
599 | def remove(self) -> None:
600 | logger.verbose("Removing pth entries from %s:", self.file)
601 |
602 | # If the file doesn't exist, log a warning and return
603 | if not os.path.isfile(self.file):
604 | logger.warning("Cannot remove entries from nonexistent file %s", self.file)
605 | return
606 | with open(self.file, "rb") as fh:
607 | # windows uses '\r\n' with py3k, but uses '\n' with py2.x
608 | lines = fh.readlines()
609 | self._saved_lines = lines
610 | if any(b"\r\n" in line for line in lines):
611 | endline = "\r\n"
612 | else:
613 | endline = "\n"
614 | # handle missing trailing newline
615 | if lines and not lines[-1].endswith(endline.encode("utf-8")):
616 | lines[-1] = lines[-1] + endline.encode("utf-8")
617 | for entry in self.entries:
618 | try:
619 | logger.verbose("Removing entry: %s", entry)
620 | lines.remove((entry + endline).encode("utf-8"))
621 | except ValueError:
622 | pass
623 | with open(self.file, "wb") as fh:
624 | fh.writelines(lines)
625 |
626 | def rollback(self) -> bool:
627 | if self._saved_lines is None:
628 | logger.error("Cannot roll back changes to %s, none were made", self.file)
629 | return False
630 | logger.debug("Rolling %s back to previous state", self.file)
631 | with open(self.file, "wb") as fh:
632 | fh.writelines(self._saved_lines)
633 | return True
634 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/jinja2/utils.py:
--------------------------------------------------------------------------------
```python
1 | import enum
2 | import json
3 | import os
4 | import re
5 | import typing as t
6 | from collections import abc
7 | from collections import deque
8 | from random import choice
9 | from random import randrange
10 | from threading import Lock
11 | from types import CodeType
12 | from urllib.parse import quote_from_bytes
13 |
14 | import markupsafe
15 |
16 | if t.TYPE_CHECKING:
17 | import typing_extensions as te
18 |
19 | F = t.TypeVar("F", bound=t.Callable[..., t.Any])
20 |
21 | # special singleton representing missing values for the runtime
22 | missing: t.Any = type("MissingType", (), {"__repr__": lambda x: "missing"})()
23 |
24 | internal_code: t.MutableSet[CodeType] = set()
25 |
26 | concat = "".join
27 |
28 |
29 | def pass_context(f: F) -> F:
30 | """Pass the :class:`~jinja2.runtime.Context` as the first argument
31 | to the decorated function when called while rendering a template.
32 |
33 | Can be used on functions, filters, and tests.
34 |
35 | If only ``Context.eval_context`` is needed, use
36 | :func:`pass_eval_context`. If only ``Context.environment`` is
37 | needed, use :func:`pass_environment`.
38 |
39 | .. versionadded:: 3.0.0
40 | Replaces ``contextfunction`` and ``contextfilter``.
41 | """
42 | f.jinja_pass_arg = _PassArg.context # type: ignore
43 | return f
44 |
45 |
46 | def pass_eval_context(f: F) -> F:
47 | """Pass the :class:`~jinja2.nodes.EvalContext` as the first argument
48 | to the decorated function when called while rendering a template.
49 | See :ref:`eval-context`.
50 |
51 | Can be used on functions, filters, and tests.
52 |
53 | If only ``EvalContext.environment`` is needed, use
54 | :func:`pass_environment`.
55 |
56 | .. versionadded:: 3.0.0
57 | Replaces ``evalcontextfunction`` and ``evalcontextfilter``.
58 | """
59 | f.jinja_pass_arg = _PassArg.eval_context # type: ignore
60 | return f
61 |
62 |
63 | def pass_environment(f: F) -> F:
64 | """Pass the :class:`~jinja2.Environment` as the first argument to
65 | the decorated function when called while rendering a template.
66 |
67 | Can be used on functions, filters, and tests.
68 |
69 | .. versionadded:: 3.0.0
70 | Replaces ``environmentfunction`` and ``environmentfilter``.
71 | """
72 | f.jinja_pass_arg = _PassArg.environment # type: ignore
73 | return f
74 |
75 |
76 | class _PassArg(enum.Enum):
77 | context = enum.auto()
78 | eval_context = enum.auto()
79 | environment = enum.auto()
80 |
81 | @classmethod
82 | def from_obj(cls, obj: F) -> t.Optional["_PassArg"]:
83 | if hasattr(obj, "jinja_pass_arg"):
84 | return obj.jinja_pass_arg # type: ignore
85 |
86 | return None
87 |
88 |
89 | def internalcode(f: F) -> F:
90 | """Marks the function as internally used"""
91 | internal_code.add(f.__code__)
92 | return f
93 |
94 |
95 | def is_undefined(obj: t.Any) -> bool:
96 | """Check if the object passed is undefined. This does nothing more than
97 | performing an instance check against :class:`Undefined` but looks nicer.
98 | This can be used for custom filters or tests that want to react to
99 | undefined variables. For example a custom default filter can look like
100 | this::
101 |
102 | def default(var, default=''):
103 | if is_undefined(var):
104 | return default
105 | return var
106 | """
107 | from .runtime import Undefined
108 |
109 | return isinstance(obj, Undefined)
110 |
111 |
112 | def consume(iterable: t.Iterable[t.Any]) -> None:
113 | """Consumes an iterable without doing anything with it."""
114 | for _ in iterable:
115 | pass
116 |
117 |
118 | def clear_caches() -> None:
119 | """Jinja keeps internal caches for environments and lexers. These are
120 | used so that Jinja doesn't have to recreate environments and lexers all
121 | the time. Normally you don't have to care about that but if you are
122 | measuring memory consumption you may want to clean the caches.
123 | """
124 | from .environment import get_spontaneous_environment
125 | from .lexer import _lexer_cache
126 |
127 | get_spontaneous_environment.cache_clear()
128 | _lexer_cache.clear()
129 |
130 |
131 | def import_string(import_name: str, silent: bool = False) -> t.Any:
132 | """Imports an object based on a string. This is useful if you want to
133 | use import paths as endpoints or something similar. An import path can
134 | be specified either in dotted notation (``xml.sax.saxutils.escape``)
135 | or with a colon as object delimiter (``xml.sax.saxutils:escape``).
136 |
137 | If the `silent` is True the return value will be `None` if the import
138 | fails.
139 |
140 | :return: imported object
141 | """
142 | try:
143 | if ":" in import_name:
144 | module, obj = import_name.split(":", 1)
145 | elif "." in import_name:
146 | module, _, obj = import_name.rpartition(".")
147 | else:
148 | return __import__(import_name)
149 | return getattr(__import__(module, None, None, [obj]), obj)
150 | except (ImportError, AttributeError):
151 | if not silent:
152 | raise
153 |
154 |
155 | def open_if_exists(filename: str, mode: str = "rb") -> t.Optional[t.IO[t.Any]]:
156 | """Returns a file descriptor for the filename if that file exists,
157 | otherwise ``None``.
158 | """
159 | if not os.path.isfile(filename):
160 | return None
161 |
162 | return open(filename, mode)
163 |
164 |
165 | def object_type_repr(obj: t.Any) -> str:
166 | """Returns the name of the object's type. For some recognized
167 | singletons the name of the object is returned instead. (For
168 | example for `None` and `Ellipsis`).
169 | """
170 | if obj is None:
171 | return "None"
172 | elif obj is Ellipsis:
173 | return "Ellipsis"
174 |
175 | cls = type(obj)
176 |
177 | if cls.__module__ == "builtins":
178 | return f"{cls.__name__} object"
179 |
180 | return f"{cls.__module__}.{cls.__name__} object"
181 |
182 |
183 | def pformat(obj: t.Any) -> str:
184 | """Format an object using :func:`pprint.pformat`."""
185 | from pprint import pformat
186 |
187 | return pformat(obj)
188 |
189 |
190 | _http_re = re.compile(
191 | r"""
192 | ^
193 | (
194 | (https?://|www\.) # scheme or www
195 | (([\w%-]+\.)+)? # subdomain
196 | (
197 | [a-z]{2,63} # basic tld
198 | |
199 | xn--[\w%]{2,59} # idna tld
200 | )
201 | |
202 | ([\w%-]{2,63}\.)+ # basic domain
203 | (com|net|int|edu|gov|org|info|mil) # basic tld
204 | |
205 | (https?://) # scheme
206 | (
207 | (([\d]{1,3})(\.[\d]{1,3}){3}) # IPv4
208 | |
209 | (\[([\da-f]{0,4}:){2}([\da-f]{0,4}:?){1,6}]) # IPv6
210 | )
211 | )
212 | (?::[\d]{1,5})? # port
213 | (?:[/?#]\S*)? # path, query, and fragment
214 | $
215 | """,
216 | re.IGNORECASE | re.VERBOSE,
217 | )
218 | _email_re = re.compile(r"^\S+@\w[\w.-]*\.\w+$")
219 |
220 |
221 | def urlize(
222 | text: str,
223 | trim_url_limit: t.Optional[int] = None,
224 | rel: t.Optional[str] = None,
225 | target: t.Optional[str] = None,
226 | extra_schemes: t.Optional[t.Iterable[str]] = None,
227 | ) -> str:
228 | """Convert URLs in text into clickable links.
229 |
230 | This may not recognize links in some situations. Usually, a more
231 | comprehensive formatter, such as a Markdown library, is a better
232 | choice.
233 |
234 | Works on ``http://``, ``https://``, ``www.``, ``mailto:``, and email
235 | addresses. Links with trailing punctuation (periods, commas, closing
236 | parentheses) and leading punctuation (opening parentheses) are
237 | recognized excluding the punctuation. Email addresses that include
238 | header fields are not recognized (for example,
239 | ``mailto:[email protected][email protected]``).
240 |
241 | :param text: Original text containing URLs to link.
242 | :param trim_url_limit: Shorten displayed URL values to this length.
243 | :param target: Add the ``target`` attribute to links.
244 | :param rel: Add the ``rel`` attribute to links.
245 | :param extra_schemes: Recognize URLs that start with these schemes
246 | in addition to the default behavior.
247 |
248 | .. versionchanged:: 3.0
249 | The ``extra_schemes`` parameter was added.
250 |
251 | .. versionchanged:: 3.0
252 | Generate ``https://`` links for URLs without a scheme.
253 |
254 | .. versionchanged:: 3.0
255 | The parsing rules were updated. Recognize email addresses with
256 | or without the ``mailto:`` scheme. Validate IP addresses. Ignore
257 | parentheses and brackets in more cases.
258 | """
259 | if trim_url_limit is not None:
260 |
261 | def trim_url(x: str) -> str:
262 | if len(x) > trim_url_limit:
263 | return f"{x[:trim_url_limit]}..."
264 |
265 | return x
266 |
267 | else:
268 |
269 | def trim_url(x: str) -> str:
270 | return x
271 |
272 | words = re.split(r"(\s+)", str(markupsafe.escape(text)))
273 | rel_attr = f' rel="{markupsafe.escape(rel)}"' if rel else ""
274 | target_attr = f' target="{markupsafe.escape(target)}"' if target else ""
275 |
276 | for i, word in enumerate(words):
277 | head, middle, tail = "", word, ""
278 | match = re.match(r"^([(<]|<)+", middle)
279 |
280 | if match:
281 | head = match.group()
282 | middle = middle[match.end() :]
283 |
284 | # Unlike lead, which is anchored to the start of the string,
285 | # need to check that the string ends with any of the characters
286 | # before trying to match all of them, to avoid backtracking.
287 | if middle.endswith((")", ">", ".", ",", "\n", ">")):
288 | match = re.search(r"([)>.,\n]|>)+$", middle)
289 |
290 | if match:
291 | tail = match.group()
292 | middle = middle[: match.start()]
293 |
294 | # Prefer balancing parentheses in URLs instead of ignoring a
295 | # trailing character.
296 | for start_char, end_char in ("(", ")"), ("<", ">"), ("<", ">"):
297 | start_count = middle.count(start_char)
298 |
299 | if start_count <= middle.count(end_char):
300 | # Balanced, or lighter on the left
301 | continue
302 |
303 | # Move as many as possible from the tail to balance
304 | for _ in range(min(start_count, tail.count(end_char))):
305 | end_index = tail.index(end_char) + len(end_char)
306 | # Move anything in the tail before the end char too
307 | middle += tail[:end_index]
308 | tail = tail[end_index:]
309 |
310 | if _http_re.match(middle):
311 | if middle.startswith("https://") or middle.startswith("http://"):
312 | middle = (
313 | f'<a href="{middle}"{rel_attr}{target_attr}>{trim_url(middle)}</a>'
314 | )
315 | else:
316 | middle = (
317 | f'<a href="https://{middle}"{rel_attr}{target_attr}>'
318 | f"{trim_url(middle)}</a>"
319 | )
320 |
321 | elif middle.startswith("mailto:") and _email_re.match(middle[7:]):
322 | middle = f'<a href="{middle}">{middle[7:]}</a>'
323 |
324 | elif (
325 | "@" in middle
326 | and not middle.startswith("www.")
327 | and ":" not in middle
328 | and _email_re.match(middle)
329 | ):
330 | middle = f'<a href="mailto:{middle}">{middle}</a>'
331 |
332 | elif extra_schemes is not None:
333 | for scheme in extra_schemes:
334 | if middle != scheme and middle.startswith(scheme):
335 | middle = f'<a href="{middle}"{rel_attr}{target_attr}>{middle}</a>'
336 |
337 | words[i] = f"{head}{middle}{tail}"
338 |
339 | return "".join(words)
340 |
341 |
342 | def generate_lorem_ipsum(
343 | n: int = 5, html: bool = True, min: int = 20, max: int = 100
344 | ) -> str:
345 | """Generate some lorem ipsum for the template."""
346 | from .constants import LOREM_IPSUM_WORDS
347 |
348 | words = LOREM_IPSUM_WORDS.split()
349 | result = []
350 |
351 | for _ in range(n):
352 | next_capitalized = True
353 | last_comma = last_fullstop = 0
354 | word = None
355 | last = None
356 | p = []
357 |
358 | # each paragraph contains out of 20 to 100 words.
359 | for idx, _ in enumerate(range(randrange(min, max))):
360 | while True:
361 | word = choice(words)
362 | if word != last:
363 | last = word
364 | break
365 | if next_capitalized:
366 | word = word.capitalize()
367 | next_capitalized = False
368 | # add commas
369 | if idx - randrange(3, 8) > last_comma:
370 | last_comma = idx
371 | last_fullstop += 2
372 | word += ","
373 | # add end of sentences
374 | if idx - randrange(10, 20) > last_fullstop:
375 | last_comma = last_fullstop = idx
376 | word += "."
377 | next_capitalized = True
378 | p.append(word)
379 |
380 | # ensure that the paragraph ends with a dot.
381 | p_str = " ".join(p)
382 |
383 | if p_str.endswith(","):
384 | p_str = p_str[:-1] + "."
385 | elif not p_str.endswith("."):
386 | p_str += "."
387 |
388 | result.append(p_str)
389 |
390 | if not html:
391 | return "\n\n".join(result)
392 | return markupsafe.Markup(
393 | "\n".join(f"<p>{markupsafe.escape(x)}</p>" for x in result)
394 | )
395 |
396 |
397 | def url_quote(obj: t.Any, charset: str = "utf-8", for_qs: bool = False) -> str:
398 | """Quote a string for use in a URL using the given charset.
399 |
400 | :param obj: String or bytes to quote. Other types are converted to
401 | string then encoded to bytes using the given charset.
402 | :param charset: Encode text to bytes using this charset.
403 | :param for_qs: Quote "/" and use "+" for spaces.
404 | """
405 | if not isinstance(obj, bytes):
406 | if not isinstance(obj, str):
407 | obj = str(obj)
408 |
409 | obj = obj.encode(charset)
410 |
411 | safe = b"" if for_qs else b"/"
412 | rv = quote_from_bytes(obj, safe)
413 |
414 | if for_qs:
415 | rv = rv.replace("%20", "+")
416 |
417 | return rv
418 |
419 |
420 | @abc.MutableMapping.register
421 | class LRUCache:
422 | """A simple LRU Cache implementation."""
423 |
424 | # this is fast for small capacities (something below 1000) but doesn't
425 | # scale. But as long as it's only used as storage for templates this
426 | # won't do any harm.
427 |
428 | def __init__(self, capacity: int) -> None:
429 | self.capacity = capacity
430 | self._mapping: t.Dict[t.Any, t.Any] = {}
431 | self._queue: "te.Deque[t.Any]" = deque()
432 | self._postinit()
433 |
434 | def _postinit(self) -> None:
435 | # alias all queue methods for faster lookup
436 | self._popleft = self._queue.popleft
437 | self._pop = self._queue.pop
438 | self._remove = self._queue.remove
439 | self._wlock = Lock()
440 | self._append = self._queue.append
441 |
442 | def __getstate__(self) -> t.Mapping[str, t.Any]:
443 | return {
444 | "capacity": self.capacity,
445 | "_mapping": self._mapping,
446 | "_queue": self._queue,
447 | }
448 |
449 | def __setstate__(self, d: t.Mapping[str, t.Any]) -> None:
450 | self.__dict__.update(d)
451 | self._postinit()
452 |
453 | def __getnewargs__(self) -> t.Tuple[t.Any, ...]:
454 | return (self.capacity,)
455 |
456 | def copy(self) -> "LRUCache":
457 | """Return a shallow copy of the instance."""
458 | rv = self.__class__(self.capacity)
459 | rv._mapping.update(self._mapping)
460 | rv._queue.extend(self._queue)
461 | return rv
462 |
463 | def get(self, key: t.Any, default: t.Any = None) -> t.Any:
464 | """Return an item from the cache dict or `default`"""
465 | try:
466 | return self[key]
467 | except KeyError:
468 | return default
469 |
470 | def setdefault(self, key: t.Any, default: t.Any = None) -> t.Any:
471 | """Set `default` if the key is not in the cache otherwise
472 | leave unchanged. Return the value of this key.
473 | """
474 | try:
475 | return self[key]
476 | except KeyError:
477 | self[key] = default
478 | return default
479 |
480 | def clear(self) -> None:
481 | """Clear the cache."""
482 | with self._wlock:
483 | self._mapping.clear()
484 | self._queue.clear()
485 |
486 | def __contains__(self, key: t.Any) -> bool:
487 | """Check if a key exists in this cache."""
488 | return key in self._mapping
489 |
490 | def __len__(self) -> int:
491 | """Return the current size of the cache."""
492 | return len(self._mapping)
493 |
494 | def __repr__(self) -> str:
495 | return f"<{type(self).__name__} {self._mapping!r}>"
496 |
497 | def __getitem__(self, key: t.Any) -> t.Any:
498 | """Get an item from the cache. Moves the item up so that it has the
499 | highest priority then.
500 |
501 | Raise a `KeyError` if it does not exist.
502 | """
503 | with self._wlock:
504 | rv = self._mapping[key]
505 |
506 | if self._queue[-1] != key:
507 | try:
508 | self._remove(key)
509 | except ValueError:
510 | # if something removed the key from the container
511 | # when we read, ignore the ValueError that we would
512 | # get otherwise.
513 | pass
514 |
515 | self._append(key)
516 |
517 | return rv
518 |
519 | def __setitem__(self, key: t.Any, value: t.Any) -> None:
520 | """Sets the value for an item. Moves the item up so that it
521 | has the highest priority then.
522 | """
523 | with self._wlock:
524 | if key in self._mapping:
525 | self._remove(key)
526 | elif len(self._mapping) == self.capacity:
527 | del self._mapping[self._popleft()]
528 |
529 | self._append(key)
530 | self._mapping[key] = value
531 |
532 | def __delitem__(self, key: t.Any) -> None:
533 | """Remove an item from the cache dict.
534 | Raise a `KeyError` if it does not exist.
535 | """
536 | with self._wlock:
537 | del self._mapping[key]
538 |
539 | try:
540 | self._remove(key)
541 | except ValueError:
542 | pass
543 |
544 | def items(self) -> t.Iterable[t.Tuple[t.Any, t.Any]]:
545 | """Return a list of items."""
546 | result = [(key, self._mapping[key]) for key in list(self._queue)]
547 | result.reverse()
548 | return result
549 |
550 | def values(self) -> t.Iterable[t.Any]:
551 | """Return a list of all values."""
552 | return [x[1] for x in self.items()]
553 |
554 | def keys(self) -> t.Iterable[t.Any]:
555 | """Return a list of all keys ordered by most recent usage."""
556 | return list(self)
557 |
558 | def __iter__(self) -> t.Iterator[t.Any]:
559 | return reversed(tuple(self._queue))
560 |
561 | def __reversed__(self) -> t.Iterator[t.Any]:
562 | """Iterate over the keys in the cache dict, oldest items
563 | coming first.
564 | """
565 | return iter(tuple(self._queue))
566 |
567 | __copy__ = copy
568 |
569 |
570 | def select_autoescape(
571 | enabled_extensions: t.Collection[str] = ("html", "htm", "xml"),
572 | disabled_extensions: t.Collection[str] = (),
573 | default_for_string: bool = True,
574 | default: bool = False,
575 | ) -> t.Callable[[t.Optional[str]], bool]:
576 | """Intelligently sets the initial value of autoescaping based on the
577 | filename of the template. This is the recommended way to configure
578 | autoescaping if you do not want to write a custom function yourself.
579 |
580 | If you want to enable it for all templates created from strings or
581 | for all templates with `.html` and `.xml` extensions::
582 |
583 | from jinja2 import Environment, select_autoescape
584 | env = Environment(autoescape=select_autoescape(
585 | enabled_extensions=('html', 'xml'),
586 | default_for_string=True,
587 | ))
588 |
589 | Example configuration to turn it on at all times except if the template
590 | ends with `.txt`::
591 |
592 | from jinja2 import Environment, select_autoescape
593 | env = Environment(autoescape=select_autoescape(
594 | disabled_extensions=('txt',),
595 | default_for_string=True,
596 | default=True,
597 | ))
598 |
599 | The `enabled_extensions` is an iterable of all the extensions that
600 | autoescaping should be enabled for. Likewise `disabled_extensions` is
601 | a list of all templates it should be disabled for. If a template is
602 | loaded from a string then the default from `default_for_string` is used.
603 | If nothing matches then the initial value of autoescaping is set to the
604 | value of `default`.
605 |
606 | For security reasons this function operates case insensitive.
607 |
608 | .. versionadded:: 2.9
609 | """
610 | enabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in enabled_extensions)
611 | disabled_patterns = tuple(f".{x.lstrip('.').lower()}" for x in disabled_extensions)
612 |
613 | def autoescape(template_name: t.Optional[str]) -> bool:
614 | if template_name is None:
615 | return default_for_string
616 | template_name = template_name.lower()
617 | if template_name.endswith(enabled_patterns):
618 | return True
619 | if template_name.endswith(disabled_patterns):
620 | return False
621 | return default
622 |
623 | return autoescape
624 |
625 |
626 | def htmlsafe_json_dumps(
627 | obj: t.Any, dumps: t.Optional[t.Callable[..., str]] = None, **kwargs: t.Any
628 | ) -> markupsafe.Markup:
629 | """Serialize an object to a string of JSON with :func:`json.dumps`,
630 | then replace HTML-unsafe characters with Unicode escapes and mark
631 | the result safe with :class:`~markupsafe.Markup`.
632 |
633 | This is available in templates as the ``|tojson`` filter.
634 |
635 | The following characters are escaped: ``<``, ``>``, ``&``, ``'``.
636 |
637 | The returned string is safe to render in HTML documents and
638 | ``<script>`` tags. The exception is in HTML attributes that are
639 | double quoted; either use single quotes or the ``|forceescape``
640 | filter.
641 |
642 | :param obj: The object to serialize to JSON.
643 | :param dumps: The ``dumps`` function to use. Defaults to
644 | ``env.policies["json.dumps_function"]``, which defaults to
645 | :func:`json.dumps`.
646 | :param kwargs: Extra arguments to pass to ``dumps``. Merged onto
647 | ``env.policies["json.dumps_kwargs"]``.
648 |
649 | .. versionchanged:: 3.0
650 | The ``dumper`` parameter is renamed to ``dumps``.
651 |
652 | .. versionadded:: 2.9
653 | """
654 | if dumps is None:
655 | dumps = json.dumps
656 |
657 | return markupsafe.Markup(
658 | dumps(obj, **kwargs)
659 | .replace("<", "\\u003c")
660 | .replace(">", "\\u003e")
661 | .replace("&", "\\u0026")
662 | .replace("'", "\\u0027")
663 | )
664 |
665 |
666 | class Cycler:
667 | """Cycle through values by yield them one at a time, then restarting
668 | once the end is reached. Available as ``cycler`` in templates.
669 |
670 | Similar to ``loop.cycle``, but can be used outside loops or across
671 | multiple loops. For example, render a list of folders and files in a
672 | list, alternating giving them "odd" and "even" classes.
673 |
674 | .. code-block:: html+jinja
675 |
676 | {% set row_class = cycler("odd", "even") %}
677 | <ul class="browser">
678 | {% for folder in folders %}
679 | <li class="folder {{ row_class.next() }}">{{ folder }}
680 | {% endfor %}
681 | {% for file in files %}
682 | <li class="file {{ row_class.next() }}">{{ file }}
683 | {% endfor %}
684 | </ul>
685 |
686 | :param items: Each positional argument will be yielded in the order
687 | given for each cycle.
688 |
689 | .. versionadded:: 2.1
690 | """
691 |
692 | def __init__(self, *items: t.Any) -> None:
693 | if not items:
694 | raise RuntimeError("at least one item has to be provided")
695 | self.items = items
696 | self.pos = 0
697 |
698 | def reset(self) -> None:
699 | """Resets the current item to the first item."""
700 | self.pos = 0
701 |
702 | @property
703 | def current(self) -> t.Any:
704 | """Return the current item. Equivalent to the item that will be
705 | returned next time :meth:`next` is called.
706 | """
707 | return self.items[self.pos]
708 |
709 | def next(self) -> t.Any:
710 | """Return the current item, then advance :attr:`current` to the
711 | next item.
712 | """
713 | rv = self.current
714 | self.pos = (self.pos + 1) % len(self.items)
715 | return rv
716 |
717 | __next__ = next
718 |
719 |
720 | class Joiner:
721 | """A joining helper for templates."""
722 |
723 | def __init__(self, sep: str = ", ") -> None:
724 | self.sep = sep
725 | self.used = False
726 |
727 | def __call__(self) -> str:
728 | if not self.used:
729 | self.used = True
730 | return ""
731 | return self.sep
732 |
733 |
734 | class Namespace:
735 | """A namespace object that can hold arbitrary attributes. It may be
736 | initialized from a dictionary or with keyword arguments."""
737 |
738 | def __init__(*args: t.Any, **kwargs: t.Any) -> None: # noqa: B902
739 | self, args = args[0], args[1:]
740 | self.__attrs = dict(*args, **kwargs)
741 |
742 | def __getattribute__(self, name: str) -> t.Any:
743 | # __class__ is needed for the awaitable check in async mode
744 | if name in {"_Namespace__attrs", "__class__"}:
745 | return object.__getattribute__(self, name)
746 | try:
747 | return self.__attrs[name]
748 | except KeyError:
749 | raise AttributeError(name) from None
750 |
751 | def __setitem__(self, name: str, value: t.Any) -> None:
752 | self.__attrs[name] = value
753 |
754 | def __repr__(self) -> str:
755 | return f"<Namespace {self.__attrs!r}>"
756 |
```