This is page 33 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/werkzeug/middleware/shared_data.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | Serve Shared Static Files
3 | =========================
4 |
5 | .. autoclass:: SharedDataMiddleware
6 | :members: is_allowed
7 |
8 | :copyright: 2007 Pallets
9 | :license: BSD-3-Clause
10 | """
11 |
12 | from __future__ import annotations
13 |
14 | import importlib.util
15 | import mimetypes
16 | import os
17 | import posixpath
18 | import typing as t
19 | from datetime import datetime
20 | from datetime import timezone
21 | from io import BytesIO
22 | from time import time
23 | from zlib import adler32
24 |
25 | from ..http import http_date
26 | from ..http import is_resource_modified
27 | from ..security import safe_join
28 | from ..utils import get_content_type
29 | from ..wsgi import get_path_info
30 | from ..wsgi import wrap_file
31 |
32 | _TOpener = t.Callable[[], t.Tuple[t.IO[bytes], datetime, int]]
33 | _TLoader = t.Callable[[t.Optional[str]], t.Tuple[t.Optional[str], t.Optional[_TOpener]]]
34 |
35 | if t.TYPE_CHECKING:
36 | from _typeshed.wsgi import StartResponse
37 | from _typeshed.wsgi import WSGIApplication
38 | from _typeshed.wsgi import WSGIEnvironment
39 |
40 |
41 | class SharedDataMiddleware:
42 | """A WSGI middleware which provides static content for development
43 | environments or simple server setups. Its usage is quite simple::
44 |
45 | import os
46 | from werkzeug.middleware.shared_data import SharedDataMiddleware
47 |
48 | app = SharedDataMiddleware(app, {
49 | '/shared': os.path.join(os.path.dirname(__file__), 'shared')
50 | })
51 |
52 | The contents of the folder ``./shared`` will now be available on
53 | ``http://example.com/shared/``. This is pretty useful during development
54 | because a standalone media server is not required. Files can also be
55 | mounted on the root folder and still continue to use the application because
56 | the shared data middleware forwards all unhandled requests to the
57 | application, even if the requests are below one of the shared folders.
58 |
59 | If `pkg_resources` is available you can also tell the middleware to serve
60 | files from package data::
61 |
62 | app = SharedDataMiddleware(app, {
63 | '/static': ('myapplication', 'static')
64 | })
65 |
66 | This will then serve the ``static`` folder in the `myapplication`
67 | Python package.
68 |
69 | The optional `disallow` parameter can be a list of :func:`~fnmatch.fnmatch`
70 | rules for files that are not accessible from the web. If `cache` is set to
71 | `False` no caching headers are sent.
72 |
73 | Currently the middleware does not support non-ASCII filenames. If the
74 | encoding on the file system happens to match the encoding of the URI it may
75 | work but this could also be by accident. We strongly suggest using ASCII
76 | only file names for static files.
77 |
78 | The middleware will guess the mimetype using the Python `mimetype`
79 | module. If it's unable to figure out the charset it will fall back
80 | to `fallback_mimetype`.
81 |
82 | :param app: the application to wrap. If you don't want to wrap an
83 | application you can pass it :exc:`NotFound`.
84 | :param exports: a list or dict of exported files and folders.
85 | :param disallow: a list of :func:`~fnmatch.fnmatch` rules.
86 | :param cache: enable or disable caching headers.
87 | :param cache_timeout: the cache timeout in seconds for the headers.
88 | :param fallback_mimetype: The fallback mimetype for unknown files.
89 |
90 | .. versionchanged:: 1.0
91 | The default ``fallback_mimetype`` is
92 | ``application/octet-stream``. If a filename looks like a text
93 | mimetype, the ``utf-8`` charset is added to it.
94 |
95 | .. versionadded:: 0.6
96 | Added ``fallback_mimetype``.
97 |
98 | .. versionchanged:: 0.5
99 | Added ``cache_timeout``.
100 | """
101 |
102 | def __init__(
103 | self,
104 | app: WSGIApplication,
105 | exports: (
106 | dict[str, str | tuple[str, str]]
107 | | t.Iterable[tuple[str, str | tuple[str, str]]]
108 | ),
109 | disallow: None = None,
110 | cache: bool = True,
111 | cache_timeout: int = 60 * 60 * 12,
112 | fallback_mimetype: str = "application/octet-stream",
113 | ) -> None:
114 | self.app = app
115 | self.exports: list[tuple[str, _TLoader]] = []
116 | self.cache = cache
117 | self.cache_timeout = cache_timeout
118 |
119 | if isinstance(exports, dict):
120 | exports = exports.items()
121 |
122 | for key, value in exports:
123 | if isinstance(value, tuple):
124 | loader = self.get_package_loader(*value)
125 | elif isinstance(value, str):
126 | if os.path.isfile(value):
127 | loader = self.get_file_loader(value)
128 | else:
129 | loader = self.get_directory_loader(value)
130 | else:
131 | raise TypeError(f"unknown def {value!r}")
132 |
133 | self.exports.append((key, loader))
134 |
135 | if disallow is not None:
136 | from fnmatch import fnmatch
137 |
138 | self.is_allowed = lambda x: not fnmatch(x, disallow)
139 |
140 | self.fallback_mimetype = fallback_mimetype
141 |
142 | def is_allowed(self, filename: str) -> bool:
143 | """Subclasses can override this method to disallow the access to
144 | certain files. However by providing `disallow` in the constructor
145 | this method is overwritten.
146 | """
147 | return True
148 |
149 | def _opener(self, filename: str) -> _TOpener:
150 | return lambda: (
151 | open(filename, "rb"),
152 | datetime.fromtimestamp(os.path.getmtime(filename), tz=timezone.utc),
153 | int(os.path.getsize(filename)),
154 | )
155 |
156 | def get_file_loader(self, filename: str) -> _TLoader:
157 | return lambda x: (os.path.basename(filename), self._opener(filename))
158 |
159 | def get_package_loader(self, package: str, package_path: str) -> _TLoader:
160 | load_time = datetime.now(timezone.utc)
161 | spec = importlib.util.find_spec(package)
162 | reader = spec.loader.get_resource_reader(package) # type: ignore[union-attr]
163 |
164 | def loader(
165 | path: str | None,
166 | ) -> tuple[str | None, _TOpener | None]:
167 | if path is None:
168 | return None, None
169 |
170 | path = safe_join(package_path, path)
171 |
172 | if path is None:
173 | return None, None
174 |
175 | basename = posixpath.basename(path)
176 |
177 | try:
178 | resource = reader.open_resource(path)
179 | except OSError:
180 | return None, None
181 |
182 | if isinstance(resource, BytesIO):
183 | return (
184 | basename,
185 | lambda: (resource, load_time, len(resource.getvalue())),
186 | )
187 |
188 | return (
189 | basename,
190 | lambda: (
191 | resource,
192 | datetime.fromtimestamp(
193 | os.path.getmtime(resource.name), tz=timezone.utc
194 | ),
195 | os.path.getsize(resource.name),
196 | ),
197 | )
198 |
199 | return loader
200 |
201 | def get_directory_loader(self, directory: str) -> _TLoader:
202 | def loader(
203 | path: str | None,
204 | ) -> tuple[str | None, _TOpener | None]:
205 | if path is not None:
206 | path = safe_join(directory, path)
207 |
208 | if path is None:
209 | return None, None
210 | else:
211 | path = directory
212 |
213 | if os.path.isfile(path):
214 | return os.path.basename(path), self._opener(path)
215 |
216 | return None, None
217 |
218 | return loader
219 |
220 | def generate_etag(self, mtime: datetime, file_size: int, real_filename: str) -> str:
221 | fn_str = os.fsencode(real_filename)
222 | timestamp = mtime.timestamp()
223 | checksum = adler32(fn_str) & 0xFFFFFFFF
224 | return f"wzsdm-{timestamp}-{file_size}-{checksum}"
225 |
226 | def __call__(
227 | self, environ: WSGIEnvironment, start_response: StartResponse
228 | ) -> t.Iterable[bytes]:
229 | path = get_path_info(environ)
230 | file_loader = None
231 |
232 | for search_path, loader in self.exports:
233 | if search_path == path:
234 | real_filename, file_loader = loader(None)
235 |
236 | if file_loader is not None:
237 | break
238 |
239 | if not search_path.endswith("/"):
240 | search_path += "/"
241 |
242 | if path.startswith(search_path):
243 | real_filename, file_loader = loader(path[len(search_path) :])
244 |
245 | if file_loader is not None:
246 | break
247 |
248 | if file_loader is None or not self.is_allowed(real_filename): # type: ignore
249 | return self.app(environ, start_response)
250 |
251 | guessed_type = mimetypes.guess_type(real_filename) # type: ignore
252 | mime_type = get_content_type(guessed_type[0] or self.fallback_mimetype, "utf-8")
253 | f, mtime, file_size = file_loader()
254 |
255 | headers = [("Date", http_date())]
256 |
257 | if self.cache:
258 | timeout = self.cache_timeout
259 | etag = self.generate_etag(mtime, file_size, real_filename) # type: ignore
260 | headers += [
261 | ("Etag", f'"{etag}"'),
262 | ("Cache-Control", f"max-age={timeout}, public"),
263 | ]
264 |
265 | if not is_resource_modified(environ, etag, last_modified=mtime):
266 | f.close()
267 | start_response("304 Not Modified", headers)
268 | return []
269 |
270 | headers.append(("Expires", http_date(time() + timeout)))
271 | else:
272 | headers.append(("Cache-Control", "public"))
273 |
274 | headers.extend(
275 | (
276 | ("Content-Type", mime_type),
277 | ("Content-Length", str(file_size)),
278 | ("Last-Modified", http_date(mtime)),
279 | )
280 | )
281 | start_response("200 OK", headers)
282 | return wrap_file(environ, f)
283 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/rich/highlighter.py:
--------------------------------------------------------------------------------
```python
1 | import re
2 | from abc import ABC, abstractmethod
3 | from typing import List, Union
4 |
5 | from .text import Span, Text
6 |
7 |
8 | def _combine_regex(*regexes: str) -> str:
9 | """Combine a number of regexes in to a single regex.
10 |
11 | Returns:
12 | str: New regex with all regexes ORed together.
13 | """
14 | return "|".join(regexes)
15 |
16 |
17 | class Highlighter(ABC):
18 | """Abstract base class for highlighters."""
19 |
20 | def __call__(self, text: Union[str, Text]) -> Text:
21 | """Highlight a str or Text instance.
22 |
23 | Args:
24 | text (Union[str, ~Text]): Text to highlight.
25 |
26 | Raises:
27 | TypeError: If not called with text or str.
28 |
29 | Returns:
30 | Text: A test instance with highlighting applied.
31 | """
32 | if isinstance(text, str):
33 | highlight_text = Text(text)
34 | elif isinstance(text, Text):
35 | highlight_text = text.copy()
36 | else:
37 | raise TypeError(f"str or Text instance required, not {text!r}")
38 | self.highlight(highlight_text)
39 | return highlight_text
40 |
41 | @abstractmethod
42 | def highlight(self, text: Text) -> None:
43 | """Apply highlighting in place to text.
44 |
45 | Args:
46 | text (~Text): A text object highlight.
47 | """
48 |
49 |
50 | class NullHighlighter(Highlighter):
51 | """A highlighter object that doesn't highlight.
52 |
53 | May be used to disable highlighting entirely.
54 |
55 | """
56 |
57 | def highlight(self, text: Text) -> None:
58 | """Nothing to do"""
59 |
60 |
61 | class RegexHighlighter(Highlighter):
62 | """Applies highlighting from a list of regular expressions."""
63 |
64 | highlights: List[str] = []
65 | base_style: str = ""
66 |
67 | def highlight(self, text: Text) -> None:
68 | """Highlight :class:`rich.text.Text` using regular expressions.
69 |
70 | Args:
71 | text (~Text): Text to highlighted.
72 |
73 | """
74 |
75 | highlight_regex = text.highlight_regex
76 | for re_highlight in self.highlights:
77 | highlight_regex(re_highlight, style_prefix=self.base_style)
78 |
79 |
80 | class ReprHighlighter(RegexHighlighter):
81 | """Highlights the text typically produced from ``__repr__`` methods."""
82 |
83 | base_style = "repr."
84 | highlights = [
85 | r"(?P<tag_start><)(?P<tag_name>[-\w.:|]*)(?P<tag_contents>[\w\W]*)(?P<tag_end>>)",
86 | r'(?P<attrib_name>[\w_]{1,50})=(?P<attrib_value>"?[\w_]+"?)?',
87 | r"(?P<brace>[][{}()])",
88 | _combine_regex(
89 | r"(?P<ipv4>[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3})",
90 | r"(?P<ipv6>([A-Fa-f0-9]{1,4}::?){1,7}[A-Fa-f0-9]{1,4})",
91 | r"(?P<eui64>(?:[0-9A-Fa-f]{1,2}-){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){7}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){3}[0-9A-Fa-f]{4})",
92 | r"(?P<eui48>(?:[0-9A-Fa-f]{1,2}-){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{1,2}:){5}[0-9A-Fa-f]{1,2}|(?:[0-9A-Fa-f]{4}\.){2}[0-9A-Fa-f]{4})",
93 | r"(?P<uuid>[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12})",
94 | r"(?P<call>[\w.]*?)\(",
95 | r"\b(?P<bool_true>True)\b|\b(?P<bool_false>False)\b|\b(?P<none>None)\b",
96 | r"(?P<ellipsis>\.\.\.)",
97 | r"(?P<number_complex>(?<!\w)(?:\-?[0-9]+\.?[0-9]*(?:e[-+]?\d+?)?)(?:[-+](?:[0-9]+\.?[0-9]*(?:e[-+]?\d+)?))?j)",
98 | r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[-+]?\d+?)?\b|0x[0-9a-fA-F]*)",
99 | r"(?P<path>\B(/[-\w._+]+)*\/)(?P<filename>[-\w._+]*)?",
100 | r"(?<![\\\w])(?P<str>b?'''.*?(?<!\\)'''|b?'.*?(?<!\\)'|b?\"\"\".*?(?<!\\)\"\"\"|b?\".*?(?<!\\)\")",
101 | r"(?P<url>(file|https|http|ws|wss)://[-0-9a-zA-Z$_+!`(),.?/;:&=%#~]*)",
102 | ),
103 | ]
104 |
105 |
106 | class JSONHighlighter(RegexHighlighter):
107 | """Highlights JSON"""
108 |
109 | # Captures the start and end of JSON strings, handling escaped quotes
110 | JSON_STR = r"(?<![\\\w])(?P<str>b?\".*?(?<!\\)\")"
111 | JSON_WHITESPACE = {" ", "\n", "\r", "\t"}
112 |
113 | base_style = "json."
114 | highlights = [
115 | _combine_regex(
116 | r"(?P<brace>[\{\[\(\)\]\}])",
117 | r"\b(?P<bool_true>true)\b|\b(?P<bool_false>false)\b|\b(?P<null>null)\b",
118 | r"(?P<number>(?<!\w)\-?[0-9]+\.?[0-9]*(e[\-\+]?\d+?)?\b|0x[0-9a-fA-F]*)",
119 | JSON_STR,
120 | ),
121 | ]
122 |
123 | def highlight(self, text: Text) -> None:
124 | super().highlight(text)
125 |
126 | # Additional work to handle highlighting JSON keys
127 | plain = text.plain
128 | append = text.spans.append
129 | whitespace = self.JSON_WHITESPACE
130 | for match in re.finditer(self.JSON_STR, plain):
131 | start, end = match.span()
132 | cursor = end
133 | while cursor < len(plain):
134 | char = plain[cursor]
135 | cursor += 1
136 | if char == ":":
137 | append(Span(start, end, "json.key"))
138 | elif char in whitespace:
139 | continue
140 | break
141 |
142 |
143 | class ISO8601Highlighter(RegexHighlighter):
144 | """Highlights the ISO8601 date time strings.
145 | Regex reference: https://www.oreilly.com/library/view/regular-expressions-cookbook/9781449327453/ch04s07.html
146 | """
147 |
148 | base_style = "iso8601."
149 | highlights = [
150 | #
151 | # Dates
152 | #
153 | # Calendar month (e.g. 2008-08). The hyphen is required
154 | r"^(?P<year>[0-9]{4})-(?P<month>1[0-2]|0[1-9])$",
155 | # Calendar date w/o hyphens (e.g. 20080830)
156 | r"^(?P<date>(?P<year>[0-9]{4})(?P<month>1[0-2]|0[1-9])(?P<day>3[01]|0[1-9]|[12][0-9]))$",
157 | # Ordinal date (e.g. 2008-243). The hyphen is optional
158 | r"^(?P<date>(?P<year>[0-9]{4})-?(?P<day>36[0-6]|3[0-5][0-9]|[12][0-9]{2}|0[1-9][0-9]|00[1-9]))$",
159 | #
160 | # Weeks
161 | #
162 | # Week of the year (e.g., 2008-W35). The hyphen is optional
163 | r"^(?P<date>(?P<year>[0-9]{4})-?W(?P<week>5[0-3]|[1-4][0-9]|0[1-9]))$",
164 | # Week date (e.g., 2008-W35-6). The hyphens are optional
165 | r"^(?P<date>(?P<year>[0-9]{4})-?W(?P<week>5[0-3]|[1-4][0-9]|0[1-9])-?(?P<day>[1-7]))$",
166 | #
167 | # Times
168 | #
169 | # Hours and minutes (e.g., 17:21). The colon is optional
170 | r"^(?P<time>(?P<hour>2[0-3]|[01][0-9]):?(?P<minute>[0-5][0-9]))$",
171 | # Hours, minutes, and seconds w/o colons (e.g., 172159)
172 | r"^(?P<time>(?P<hour>2[0-3]|[01][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9]))$",
173 | # Time zone designator (e.g., Z, +07 or +07:00). The colons and the minutes are optional
174 | r"^(?P<timezone>(Z|[+-](?:2[0-3]|[01][0-9])(?::?(?:[0-5][0-9]))?))$",
175 | # Hours, minutes, and seconds with time zone designator (e.g., 17:21:59+07:00).
176 | # All the colons are optional. The minutes in the time zone designator are also optional
177 | r"^(?P<time>(?P<hour>2[0-3]|[01][0-9])(?P<minute>[0-5][0-9])(?P<second>[0-5][0-9]))(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9])(?::?(?:[0-5][0-9]))?)$",
178 | #
179 | # Date and Time
180 | #
181 | # Calendar date with hours, minutes, and seconds (e.g., 2008-08-30 17:21:59 or 20080830 172159).
182 | # A space is required between the date and the time. The hyphens and colons are optional.
183 | # This regex matches dates and times that specify some hyphens or colons but omit others.
184 | # This does not follow ISO 8601
185 | r"^(?P<date>(?P<year>[0-9]{4})(?P<hyphen>-)?(?P<month>1[0-2]|0[1-9])(?(hyphen)-)(?P<day>3[01]|0[1-9]|[12][0-9])) (?P<time>(?P<hour>2[0-3]|[01][0-9])(?(hyphen):)(?P<minute>[0-5][0-9])(?(hyphen):)(?P<second>[0-5][0-9]))$",
186 | #
187 | # XML Schema dates and times
188 | #
189 | # Date, with optional time zone (e.g., 2008-08-30 or 2008-08-30+07:00).
190 | # Hyphens are required. This is the XML Schema 'date' type
191 | r"^(?P<date>(?P<year>-?(?:[1-9][0-9]*)?[0-9]{4})-(?P<month>1[0-2]|0[1-9])-(?P<day>3[01]|0[1-9]|[12][0-9]))(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
192 | # Time, with optional fractional seconds and time zone (e.g., 01:45:36 or 01:45:36.123+07:00).
193 | # There is no limit on the number of digits for the fractional seconds. This is the XML Schema 'time' type
194 | r"^(?P<time>(?P<hour>2[0-3]|[01][0-9]):(?P<minute>[0-5][0-9]):(?P<second>[0-5][0-9])(?P<frac>\.[0-9]+)?)(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
195 | # Date and time, with optional fractional seconds and time zone (e.g., 2008-08-30T01:45:36 or 2008-08-30T01:45:36.123Z).
196 | # This is the XML Schema 'dateTime' type
197 | r"^(?P<date>(?P<year>-?(?:[1-9][0-9]*)?[0-9]{4})-(?P<month>1[0-2]|0[1-9])-(?P<day>3[01]|0[1-9]|[12][0-9]))T(?P<time>(?P<hour>2[0-3]|[01][0-9]):(?P<minute>[0-5][0-9]):(?P<second>[0-5][0-9])(?P<ms>\.[0-9]+)?)(?P<timezone>Z|[+-](?:2[0-3]|[01][0-9]):[0-5][0-9])?$",
198 | ]
199 |
200 |
201 | if __name__ == "__main__": # pragma: no cover
202 | from .console import Console
203 |
204 | console = Console()
205 | console.print("[bold green]hello world![/bold green]")
206 | console.print("'[bold green]hello world![/bold green]'")
207 |
208 | console.print(" /foo")
209 | console.print("/foo/")
210 | console.print("/foo/bar")
211 | console.print("foo/bar/baz")
212 |
213 | console.print("/foo/bar/baz?foo=bar+egg&egg=baz")
214 | console.print("/foo/bar/baz/")
215 | console.print("/foo/bar/baz/egg")
216 | console.print("/foo/bar/baz/egg.py")
217 | console.print("/foo/bar/baz/egg.py word")
218 | console.print(" /foo/bar/baz/egg.py word")
219 | console.print("foo /foo/bar/baz/egg.py word")
220 | console.print("foo /foo/bar/ba._++z/egg+.py word")
221 | console.print("https://example.org?foo=bar#header")
222 |
223 | console.print(1234567.34)
224 | console.print(1 / 2)
225 | console.print(-1 / 123123123123)
226 |
227 | console.print(
228 | "127.0.1.1 bar 192.168.1.4 2001:0db8:85a3:0000:0000:8a2e:0370:7334 foo"
229 | )
230 | import json
231 |
232 | console.print_json(json.dumps(obj={"name": "apple", "count": 1}), indent=None)
233 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/_manylinux.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import collections
4 | import contextlib
5 | import functools
6 | import os
7 | import re
8 | import sys
9 | import warnings
10 | from typing import Generator, Iterator, NamedTuple, Sequence
11 |
12 | from ._elffile import EIClass, EIData, ELFFile, EMachine
13 |
14 | EF_ARM_ABIMASK = 0xFF000000
15 | EF_ARM_ABI_VER5 = 0x05000000
16 | EF_ARM_ABI_FLOAT_HARD = 0x00000400
17 |
18 |
19 | # `os.PathLike` not a generic type until Python 3.9, so sticking with `str`
20 | # as the type for `path` until then.
21 | @contextlib.contextmanager
22 | def _parse_elf(path: str) -> Generator[ELFFile | None, None, None]:
23 | try:
24 | with open(path, "rb") as f:
25 | yield ELFFile(f)
26 | except (OSError, TypeError, ValueError):
27 | yield None
28 |
29 |
30 | def _is_linux_armhf(executable: str) -> bool:
31 | # hard-float ABI can be detected from the ELF header of the running
32 | # process
33 | # https://static.docs.arm.com/ihi0044/g/aaelf32.pdf
34 | with _parse_elf(executable) as f:
35 | return (
36 | f is not None
37 | and f.capacity == EIClass.C32
38 | and f.encoding == EIData.Lsb
39 | and f.machine == EMachine.Arm
40 | and f.flags & EF_ARM_ABIMASK == EF_ARM_ABI_VER5
41 | and f.flags & EF_ARM_ABI_FLOAT_HARD == EF_ARM_ABI_FLOAT_HARD
42 | )
43 |
44 |
45 | def _is_linux_i686(executable: str) -> bool:
46 | with _parse_elf(executable) as f:
47 | return (
48 | f is not None
49 | and f.capacity == EIClass.C32
50 | and f.encoding == EIData.Lsb
51 | and f.machine == EMachine.I386
52 | )
53 |
54 |
55 | def _have_compatible_abi(executable: str, archs: Sequence[str]) -> bool:
56 | if "armv7l" in archs:
57 | return _is_linux_armhf(executable)
58 | if "i686" in archs:
59 | return _is_linux_i686(executable)
60 | allowed_archs = {
61 | "x86_64",
62 | "aarch64",
63 | "ppc64",
64 | "ppc64le",
65 | "s390x",
66 | "loongarch64",
67 | "riscv64",
68 | }
69 | return any(arch in allowed_archs for arch in archs)
70 |
71 |
72 | # If glibc ever changes its major version, we need to know what the last
73 | # minor version was, so we can build the complete list of all versions.
74 | # For now, guess what the highest minor version might be, assume it will
75 | # be 50 for testing. Once this actually happens, update the dictionary
76 | # with the actual value.
77 | _LAST_GLIBC_MINOR: dict[int, int] = collections.defaultdict(lambda: 50)
78 |
79 |
80 | class _GLibCVersion(NamedTuple):
81 | major: int
82 | minor: int
83 |
84 |
85 | def _glibc_version_string_confstr() -> str | None:
86 | """
87 | Primary implementation of glibc_version_string using os.confstr.
88 | """
89 | # os.confstr is quite a bit faster than ctypes.DLL. It's also less likely
90 | # to be broken or missing. This strategy is used in the standard library
91 | # platform module.
92 | # https://github.com/python/cpython/blob/fcf1d003bf4f0100c/Lib/platform.py#L175-L183
93 | try:
94 | # Should be a string like "glibc 2.17".
95 | version_string: str | None = os.confstr("CS_GNU_LIBC_VERSION")
96 | assert version_string is not None
97 | _, version = version_string.rsplit()
98 | except (AssertionError, AttributeError, OSError, ValueError):
99 | # os.confstr() or CS_GNU_LIBC_VERSION not available (or a bad value)...
100 | return None
101 | return version
102 |
103 |
104 | def _glibc_version_string_ctypes() -> str | None:
105 | """
106 | Fallback implementation of glibc_version_string using ctypes.
107 | """
108 | try:
109 | import ctypes
110 | except ImportError:
111 | return None
112 |
113 | # ctypes.CDLL(None) internally calls dlopen(NULL), and as the dlopen
114 | # manpage says, "If filename is NULL, then the returned handle is for the
115 | # main program". This way we can let the linker do the work to figure out
116 | # which libc our process is actually using.
117 | #
118 | # We must also handle the special case where the executable is not a
119 | # dynamically linked executable. This can occur when using musl libc,
120 | # for example. In this situation, dlopen() will error, leading to an
121 | # OSError. Interestingly, at least in the case of musl, there is no
122 | # errno set on the OSError. The single string argument used to construct
123 | # OSError comes from libc itself and is therefore not portable to
124 | # hard code here. In any case, failure to call dlopen() means we
125 | # can proceed, so we bail on our attempt.
126 | try:
127 | process_namespace = ctypes.CDLL(None)
128 | except OSError:
129 | return None
130 |
131 | try:
132 | gnu_get_libc_version = process_namespace.gnu_get_libc_version
133 | except AttributeError:
134 | # Symbol doesn't exist -> therefore, we are not linked to
135 | # glibc.
136 | return None
137 |
138 | # Call gnu_get_libc_version, which returns a string like "2.5"
139 | gnu_get_libc_version.restype = ctypes.c_char_p
140 | version_str: str = gnu_get_libc_version()
141 | # py2 / py3 compatibility:
142 | if not isinstance(version_str, str):
143 | version_str = version_str.decode("ascii")
144 |
145 | return version_str
146 |
147 |
148 | def _glibc_version_string() -> str | None:
149 | """Returns glibc version string, or None if not using glibc."""
150 | return _glibc_version_string_confstr() or _glibc_version_string_ctypes()
151 |
152 |
153 | def _parse_glibc_version(version_str: str) -> tuple[int, int]:
154 | """Parse glibc version.
155 |
156 | We use a regexp instead of str.split because we want to discard any
157 | random junk that might come after the minor version -- this might happen
158 | in patched/forked versions of glibc (e.g. Linaro's version of glibc
159 | uses version strings like "2.20-2014.11"). See gh-3588.
160 | """
161 | m = re.match(r"(?P<major>[0-9]+)\.(?P<minor>[0-9]+)", version_str)
162 | if not m:
163 | warnings.warn(
164 | f"Expected glibc version with 2 components major.minor,"
165 | f" got: {version_str}",
166 | RuntimeWarning,
167 | )
168 | return -1, -1
169 | return int(m.group("major")), int(m.group("minor"))
170 |
171 |
172 | @functools.lru_cache
173 | def _get_glibc_version() -> tuple[int, int]:
174 | version_str = _glibc_version_string()
175 | if version_str is None:
176 | return (-1, -1)
177 | return _parse_glibc_version(version_str)
178 |
179 |
180 | # From PEP 513, PEP 600
181 | def _is_compatible(arch: str, version: _GLibCVersion) -> bool:
182 | sys_glibc = _get_glibc_version()
183 | if sys_glibc < version:
184 | return False
185 | # Check for presence of _manylinux module.
186 | try:
187 | import _manylinux
188 | except ImportError:
189 | return True
190 | if hasattr(_manylinux, "manylinux_compatible"):
191 | result = _manylinux.manylinux_compatible(version[0], version[1], arch)
192 | if result is not None:
193 | return bool(result)
194 | return True
195 | if version == _GLibCVersion(2, 5):
196 | if hasattr(_manylinux, "manylinux1_compatible"):
197 | return bool(_manylinux.manylinux1_compatible)
198 | if version == _GLibCVersion(2, 12):
199 | if hasattr(_manylinux, "manylinux2010_compatible"):
200 | return bool(_manylinux.manylinux2010_compatible)
201 | if version == _GLibCVersion(2, 17):
202 | if hasattr(_manylinux, "manylinux2014_compatible"):
203 | return bool(_manylinux.manylinux2014_compatible)
204 | return True
205 |
206 |
207 | _LEGACY_MANYLINUX_MAP = {
208 | # CentOS 7 w/ glibc 2.17 (PEP 599)
209 | (2, 17): "manylinux2014",
210 | # CentOS 6 w/ glibc 2.12 (PEP 571)
211 | (2, 12): "manylinux2010",
212 | # CentOS 5 w/ glibc 2.5 (PEP 513)
213 | (2, 5): "manylinux1",
214 | }
215 |
216 |
217 | def platform_tags(archs: Sequence[str]) -> Iterator[str]:
218 | """Generate manylinux tags compatible to the current platform.
219 |
220 | :param archs: Sequence of compatible architectures.
221 | The first one shall be the closest to the actual architecture and be the part of
222 | platform tag after the ``linux_`` prefix, e.g. ``x86_64``.
223 | The ``linux_`` prefix is assumed as a prerequisite for the current platform to
224 | be manylinux-compatible.
225 |
226 | :returns: An iterator of compatible manylinux tags.
227 | """
228 | if not _have_compatible_abi(sys.executable, archs):
229 | return
230 | # Oldest glibc to be supported regardless of architecture is (2, 17).
231 | too_old_glibc2 = _GLibCVersion(2, 16)
232 | if set(archs) & {"x86_64", "i686"}:
233 | # On x86/i686 also oldest glibc to be supported is (2, 5).
234 | too_old_glibc2 = _GLibCVersion(2, 4)
235 | current_glibc = _GLibCVersion(*_get_glibc_version())
236 | glibc_max_list = [current_glibc]
237 | # We can assume compatibility across glibc major versions.
238 | # https://sourceware.org/bugzilla/show_bug.cgi?id=24636
239 | #
240 | # Build a list of maximum glibc versions so that we can
241 | # output the canonical list of all glibc from current_glibc
242 | # down to too_old_glibc2, including all intermediary versions.
243 | for glibc_major in range(current_glibc.major - 1, 1, -1):
244 | glibc_minor = _LAST_GLIBC_MINOR[glibc_major]
245 | glibc_max_list.append(_GLibCVersion(glibc_major, glibc_minor))
246 | for arch in archs:
247 | for glibc_max in glibc_max_list:
248 | if glibc_max.major == too_old_glibc2.major:
249 | min_minor = too_old_glibc2.minor
250 | else:
251 | # For other glibc major versions oldest supported is (x, 0).
252 | min_minor = -1
253 | for glibc_minor in range(glibc_max.minor, min_minor, -1):
254 | glibc_version = _GLibCVersion(glibc_max.major, glibc_minor)
255 | tag = "manylinux_{}_{}".format(*glibc_version)
256 | if _is_compatible(arch, glibc_version):
257 | yield f"{tag}_{arch}"
258 | # Handle the legacy manylinux1, manylinux2010, manylinux2014 tags.
259 | if glibc_version in _LEGACY_MANYLINUX_MAP:
260 | legacy_tag = _LEGACY_MANYLINUX_MAP[glibc_version]
261 | if _is_compatible(arch, glibc_version):
262 | yield f"{legacy_tag}_{arch}"
263 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/bs4/tests/test_tag.py:
--------------------------------------------------------------------------------
```python
1 | import warnings
2 | from bs4.element import (
3 | Comment,
4 | NavigableString,
5 | )
6 | from . import SoupTest
7 |
8 | class TestTag(SoupTest):
9 | """Test various methods of Tag which aren't so complicated they
10 | need their own classes.
11 | """
12 |
13 | def test__should_pretty_print(self):
14 | # Test the rules about when a tag should be pretty-printed.
15 | tag = self.soup("").new_tag("a_tag")
16 |
17 | # No list of whitespace-preserving tags -> pretty-print
18 | tag._preserve_whitespace_tags = None
19 | assert True == tag._should_pretty_print(0)
20 |
21 | # List exists but tag is not on the list -> pretty-print
22 | tag.preserve_whitespace_tags = ["some_other_tag"]
23 | assert True == tag._should_pretty_print(1)
24 |
25 | # Indent level is None -> don't pretty-print
26 | assert False == tag._should_pretty_print(None)
27 |
28 | # Tag is on the whitespace-preserving list -> don't pretty-print
29 | tag.preserve_whitespace_tags = ["some_other_tag", "a_tag"]
30 | assert False == tag._should_pretty_print(1)
31 |
32 | def test_len(self):
33 | """The length of a Tag is its number of children."""
34 | soup = self.soup("<top>1<b>2</b>3</top>")
35 |
36 | # The BeautifulSoup object itself contains one element: the
37 | # <top> tag.
38 | assert len(soup.contents) == 1
39 | assert len(soup) == 1
40 |
41 | # The <top> tag contains three elements: the text node "1", the
42 | # <b> tag, and the text node "3".
43 | assert len(soup.top) == 3
44 | assert len(soup.top.contents) == 3
45 |
46 | def test_member_access_invokes_find(self):
47 | """Accessing a Python member .foo invokes find('foo')"""
48 | soup = self.soup('<b><i></i></b>')
49 | assert soup.b == soup.find('b')
50 | assert soup.b.i == soup.find('b').find('i')
51 | assert soup.a == None
52 |
53 | def test_deprecated_member_access(self):
54 | soup = self.soup('<b><i></i></b>')
55 | with warnings.catch_warnings(record=True) as w:
56 | tag = soup.bTag
57 | assert soup.b == tag
58 | assert '.bTag is deprecated, use .find("b") instead. If you really were looking for a tag called bTag, use .find("bTag")' == str(w[0].message)
59 |
60 | def test_has_attr(self):
61 | """has_attr() checks for the presence of an attribute.
62 |
63 | Please note note: has_attr() is different from
64 | __in__. has_attr() checks the tag's attributes and __in__
65 | checks the tag's chidlren.
66 | """
67 | soup = self.soup("<foo attr='bar'>")
68 | assert soup.foo.has_attr('attr')
69 | assert not soup.foo.has_attr('attr2')
70 |
71 | def test_attributes_come_out_in_alphabetical_order(self):
72 | markup = '<b a="1" z="5" m="3" f="2" y="4"></b>'
73 | self.assertSoupEquals(markup, '<b a="1" f="2" m="3" y="4" z="5"></b>')
74 |
75 | def test_string(self):
76 | # A Tag that contains only a text node makes that node
77 | # available as .string.
78 | soup = self.soup("<b>foo</b>")
79 | assert soup.b.string == 'foo'
80 |
81 | def test_empty_tag_has_no_string(self):
82 | # A Tag with no children has no .stirng.
83 | soup = self.soup("<b></b>")
84 | assert soup.b.string == None
85 |
86 | def test_tag_with_multiple_children_has_no_string(self):
87 | # A Tag with no children has no .string.
88 | soup = self.soup("<a>foo<b></b><b></b></b>")
89 | assert soup.b.string == None
90 |
91 | soup = self.soup("<a>foo<b></b>bar</b>")
92 | assert soup.b.string == None
93 |
94 | # Even if all the children are strings, due to trickery,
95 | # it won't work--but this would be a good optimization.
96 | soup = self.soup("<a>foo</b>")
97 | soup.a.insert(1, "bar")
98 | assert soup.a.string == None
99 |
100 | def test_tag_with_recursive_string_has_string(self):
101 | # A Tag with a single child which has a .string inherits that
102 | # .string.
103 | soup = self.soup("<a><b>foo</b></a>")
104 | assert soup.a.string == "foo"
105 | assert soup.string == "foo"
106 |
107 | def test_lack_of_string(self):
108 | """Only a Tag containing a single text node has a .string."""
109 | soup = self.soup("<b>f<i>e</i>o</b>")
110 | assert soup.b.string is None
111 |
112 | soup = self.soup("<b></b>")
113 | assert soup.b.string is None
114 |
115 | def test_all_text(self):
116 | """Tag.text and Tag.get_text(sep=u"") -> all child text, concatenated"""
117 | soup = self.soup("<a>a<b>r</b> <r> t </r></a>")
118 | assert soup.a.text == "ar t "
119 | assert soup.a.get_text(strip=True) == "art"
120 | assert soup.a.get_text(",") == "a,r, , t "
121 | assert soup.a.get_text(",", strip=True) == "a,r,t"
122 |
123 | def test_get_text_ignores_special_string_containers(self):
124 | soup = self.soup("foo<!--IGNORE-->bar")
125 | assert soup.get_text() == "foobar"
126 |
127 | assert soup.get_text(types=(NavigableString, Comment)) == "fooIGNOREbar"
128 | assert soup.get_text(types=None) == "fooIGNOREbar"
129 |
130 | soup = self.soup("foo<style>CSS</style><script>Javascript</script>bar")
131 | assert soup.get_text() == "foobar"
132 |
133 | def test_all_strings_ignores_special_string_containers(self):
134 | soup = self.soup("foo<!--IGNORE-->bar")
135 | assert ['foo', 'bar'] == list(soup.strings)
136 |
137 | soup = self.soup("foo<style>CSS</style><script>Javascript</script>bar")
138 | assert ['foo', 'bar'] == list(soup.strings)
139 |
140 | def test_string_methods_inside_special_string_container_tags(self):
141 | # Strings inside tags like <script> are generally ignored by
142 | # methods like get_text, because they're not what humans
143 | # consider 'text'. But if you call get_text on the <script>
144 | # tag itself, those strings _are_ considered to be 'text',
145 | # because there's nothing else you might be looking for.
146 |
147 | style = self.soup("<div>a<style>Some CSS</style></div>")
148 | template = self.soup("<div>a<template><p>Templated <b>text</b>.</p><!--With a comment.--></template></div>")
149 | script = self.soup("<div>a<script><!--a comment-->Some text</script></div>")
150 |
151 | assert style.div.get_text() == "a"
152 | assert list(style.div.strings) == ["a"]
153 | assert style.div.style.get_text() == "Some CSS"
154 | assert list(style.div.style.strings) == ['Some CSS']
155 |
156 | # The comment is not picked up here. That's because it was
157 | # parsed into a Comment object, which is not considered
158 | # interesting by template.strings.
159 | assert template.div.get_text() == "a"
160 | assert list(template.div.strings) == ["a"]
161 | assert template.div.template.get_text() == "Templated text."
162 | assert list(template.div.template.strings) == ["Templated ", "text", "."]
163 |
164 | # The comment is included here, because it didn't get parsed
165 | # into a Comment object--it's part of the Script string.
166 | assert script.div.get_text() == "a"
167 | assert list(script.div.strings) == ["a"]
168 | assert script.div.script.get_text() == "<!--a comment-->Some text"
169 | assert list(script.div.script.strings) == ['<!--a comment-->Some text']
170 |
171 |
172 | class TestMultiValuedAttributes(SoupTest):
173 | """Test the behavior of multi-valued attributes like 'class'.
174 |
175 | The values of such attributes are always presented as lists.
176 | """
177 |
178 | def test_single_value_becomes_list(self):
179 | soup = self.soup("<a class='foo'>")
180 | assert ["foo"] ==soup.a['class']
181 |
182 | def test_multiple_values_becomes_list(self):
183 | soup = self.soup("<a class='foo bar'>")
184 | assert ["foo", "bar"] == soup.a['class']
185 |
186 | def test_multiple_values_separated_by_weird_whitespace(self):
187 | soup = self.soup("<a class='foo\tbar\nbaz'>")
188 | assert ["foo", "bar", "baz"] ==soup.a['class']
189 |
190 | def test_attributes_joined_into_string_on_output(self):
191 | soup = self.soup("<a class='foo\tbar'>")
192 | assert b'<a class="foo bar"></a>' == soup.a.encode()
193 |
194 | def test_get_attribute_list(self):
195 | soup = self.soup("<a id='abc def'>")
196 | assert ['abc def'] == soup.a.get_attribute_list('id')
197 |
198 | def test_accept_charset(self):
199 | soup = self.soup('<form accept-charset="ISO-8859-1 UTF-8">')
200 | assert ['ISO-8859-1', 'UTF-8'] == soup.form['accept-charset']
201 |
202 | def test_cdata_attribute_applying_only_to_one_tag(self):
203 | data = '<a accept-charset="ISO-8859-1 UTF-8"></a>'
204 | soup = self.soup(data)
205 | # We saw in another test that accept-charset is a cdata-list
206 | # attribute for the <form> tag. But it's not a cdata-list
207 | # attribute for any other tag.
208 | assert 'ISO-8859-1 UTF-8' == soup.a['accept-charset']
209 |
210 | def test_customization(self):
211 | # It's possible to change which attributes of which tags
212 | # are treated as multi-valued attributes.
213 | #
214 | # Here, 'id' is a multi-valued attribute and 'class' is not.
215 | #
216 | # TODO: This code is in the builder and should be tested there.
217 | soup = self.soup(
218 | '<a class="foo" id="bar">', multi_valued_attributes={ '*' : 'id' }
219 | )
220 | assert soup.a['class'] == 'foo'
221 | assert soup.a['id'] == ['bar']
222 |
223 | def test_hidden_tag_is_invisible(self):
224 | # Setting .hidden on a tag makes it invisible in output, but
225 | # leaves its contents visible.
226 | #
227 | # This is not a documented or supported feature of Beautiful
228 | # Soup (e.g. NavigableString doesn't support .hidden even
229 | # though it could), but some people use it and it's not
230 | # hurting anything to verify that it keeps working.
231 | #
232 | soup = self.soup('<div id="1"><span id="2">a string</span></div>')
233 | soup.span.hidden = True
234 | assert '<div id="1">a string</div>' == str(soup.div)
235 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/itsdangerous/signer.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import collections.abc as cabc
4 | import hashlib
5 | import hmac
6 | import typing as t
7 |
8 | from .encoding import _base64_alphabet
9 | from .encoding import base64_decode
10 | from .encoding import base64_encode
11 | from .encoding import want_bytes
12 | from .exc import BadSignature
13 |
14 |
15 | class SigningAlgorithm:
16 | """Subclasses must implement :meth:`get_signature` to provide
17 | signature generation functionality.
18 | """
19 |
20 | def get_signature(self, key: bytes, value: bytes) -> bytes:
21 | """Returns the signature for the given key and value."""
22 | raise NotImplementedError()
23 |
24 | def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool:
25 | """Verifies the given signature matches the expected
26 | signature.
27 | """
28 | return hmac.compare_digest(sig, self.get_signature(key, value))
29 |
30 |
31 | class NoneAlgorithm(SigningAlgorithm):
32 | """Provides an algorithm that does not perform any signing and
33 | returns an empty signature.
34 | """
35 |
36 | def get_signature(self, key: bytes, value: bytes) -> bytes:
37 | return b""
38 |
39 |
40 | def _lazy_sha1(string: bytes = b"") -> t.Any:
41 | """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include
42 | SHA-1, in which case the import and use as a default would fail before the
43 | developer can configure something else.
44 | """
45 | return hashlib.sha1(string)
46 |
47 |
48 | class HMACAlgorithm(SigningAlgorithm):
49 | """Provides signature generation using HMACs."""
50 |
51 | #: The digest method to use with the MAC algorithm. This defaults to
52 | #: SHA1, but can be changed to any other function in the hashlib
53 | #: module.
54 | default_digest_method: t.Any = staticmethod(_lazy_sha1)
55 |
56 | def __init__(self, digest_method: t.Any = None):
57 | if digest_method is None:
58 | digest_method = self.default_digest_method
59 |
60 | self.digest_method: t.Any = digest_method
61 |
62 | def get_signature(self, key: bytes, value: bytes) -> bytes:
63 | mac = hmac.new(key, msg=value, digestmod=self.digest_method)
64 | return mac.digest()
65 |
66 |
67 | def _make_keys_list(
68 | secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
69 | ) -> list[bytes]:
70 | if isinstance(secret_key, (str, bytes)):
71 | return [want_bytes(secret_key)]
72 |
73 | return [want_bytes(s) for s in secret_key] # pyright: ignore
74 |
75 |
76 | class Signer:
77 | """A signer securely signs bytes, then unsigns them to verify that
78 | the value hasn't been changed.
79 |
80 | The secret key should be a random string of ``bytes`` and should not
81 | be saved to code or version control. Different salts should be used
82 | to distinguish signing in different contexts. See :doc:`/concepts`
83 | for information about the security of the secret key and salt.
84 |
85 | :param secret_key: The secret key to sign and verify with. Can be a
86 | list of keys, oldest to newest, to support key rotation.
87 | :param salt: Extra key to combine with ``secret_key`` to distinguish
88 | signatures in different contexts.
89 | :param sep: Separator between the signature and value.
90 | :param key_derivation: How to derive the signing key from the secret
91 | key and salt. Possible values are ``concat``, ``django-concat``,
92 | or ``hmac``. Defaults to :attr:`default_key_derivation`, which
93 | defaults to ``django-concat``.
94 | :param digest_method: Hash function to use when generating the HMAC
95 | signature. Defaults to :attr:`default_digest_method`, which
96 | defaults to :func:`hashlib.sha1`. Note that the security of the
97 | hash alone doesn't apply when used intermediately in HMAC.
98 | :param algorithm: A :class:`SigningAlgorithm` instance to use
99 | instead of building a default :class:`HMACAlgorithm` with the
100 | ``digest_method``.
101 |
102 | .. versionchanged:: 2.0
103 | Added support for key rotation by passing a list to
104 | ``secret_key``.
105 |
106 | .. versionchanged:: 0.18
107 | ``algorithm`` was added as an argument to the class constructor.
108 |
109 | .. versionchanged:: 0.14
110 | ``key_derivation`` and ``digest_method`` were added as arguments
111 | to the class constructor.
112 | """
113 |
114 | #: The default digest method to use for the signer. The default is
115 | #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or
116 | #: compatible object. Note that the security of the hash alone
117 | #: doesn't apply when used intermediately in HMAC.
118 | #:
119 | #: .. versionadded:: 0.14
120 | default_digest_method: t.Any = staticmethod(_lazy_sha1)
121 |
122 | #: The default scheme to use to derive the signing key from the
123 | #: secret key and salt. The default is ``django-concat``. Possible
124 | #: values are ``concat``, ``django-concat``, and ``hmac``.
125 | #:
126 | #: .. versionadded:: 0.14
127 | default_key_derivation: str = "django-concat"
128 |
129 | def __init__(
130 | self,
131 | secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes],
132 | salt: str | bytes | None = b"itsdangerous.Signer",
133 | sep: str | bytes = b".",
134 | key_derivation: str | None = None,
135 | digest_method: t.Any | None = None,
136 | algorithm: SigningAlgorithm | None = None,
137 | ):
138 | #: The list of secret keys to try for verifying signatures, from
139 | #: oldest to newest. The newest (last) key is used for signing.
140 | #:
141 | #: This allows a key rotation system to keep a list of allowed
142 | #: keys and remove expired ones.
143 | self.secret_keys: list[bytes] = _make_keys_list(secret_key)
144 | self.sep: bytes = want_bytes(sep)
145 |
146 | if self.sep in _base64_alphabet:
147 | raise ValueError(
148 | "The given separator cannot be used because it may be"
149 | " contained in the signature itself. ASCII letters,"
150 | " digits, and '-_=' must not be used."
151 | )
152 |
153 | if salt is not None:
154 | salt = want_bytes(salt)
155 | else:
156 | salt = b"itsdangerous.Signer"
157 |
158 | self.salt = salt
159 |
160 | if key_derivation is None:
161 | key_derivation = self.default_key_derivation
162 |
163 | self.key_derivation: str = key_derivation
164 |
165 | if digest_method is None:
166 | digest_method = self.default_digest_method
167 |
168 | self.digest_method: t.Any = digest_method
169 |
170 | if algorithm is None:
171 | algorithm = HMACAlgorithm(self.digest_method)
172 |
173 | self.algorithm: SigningAlgorithm = algorithm
174 |
175 | @property
176 | def secret_key(self) -> bytes:
177 | """The newest (last) entry in the :attr:`secret_keys` list. This
178 | is for compatibility from before key rotation support was added.
179 | """
180 | return self.secret_keys[-1]
181 |
182 | def derive_key(self, secret_key: str | bytes | None = None) -> bytes:
183 | """This method is called to derive the key. The default key
184 | derivation choices can be overridden here. Key derivation is not
185 | intended to be used as a security method to make a complex key
186 | out of a short password. Instead you should use large random
187 | secret keys.
188 |
189 | :param secret_key: A specific secret key to derive from.
190 | Defaults to the last item in :attr:`secret_keys`.
191 |
192 | .. versionchanged:: 2.0
193 | Added the ``secret_key`` parameter.
194 | """
195 | if secret_key is None:
196 | secret_key = self.secret_keys[-1]
197 | else:
198 | secret_key = want_bytes(secret_key)
199 |
200 | if self.key_derivation == "concat":
201 | return t.cast(bytes, self.digest_method(self.salt + secret_key).digest())
202 | elif self.key_derivation == "django-concat":
203 | return t.cast(
204 | bytes, self.digest_method(self.salt + b"signer" + secret_key).digest()
205 | )
206 | elif self.key_derivation == "hmac":
207 | mac = hmac.new(secret_key, digestmod=self.digest_method)
208 | mac.update(self.salt)
209 | return mac.digest()
210 | elif self.key_derivation == "none":
211 | return secret_key
212 | else:
213 | raise TypeError("Unknown key derivation method")
214 |
215 | def get_signature(self, value: str | bytes) -> bytes:
216 | """Returns the signature for the given value."""
217 | value = want_bytes(value)
218 | key = self.derive_key()
219 | sig = self.algorithm.get_signature(key, value)
220 | return base64_encode(sig)
221 |
222 | def sign(self, value: str | bytes) -> bytes:
223 | """Signs the given string."""
224 | value = want_bytes(value)
225 | return value + self.sep + self.get_signature(value)
226 |
227 | def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool:
228 | """Verifies the signature for the given value."""
229 | try:
230 | sig = base64_decode(sig)
231 | except Exception:
232 | return False
233 |
234 | value = want_bytes(value)
235 |
236 | for secret_key in reversed(self.secret_keys):
237 | key = self.derive_key(secret_key)
238 |
239 | if self.algorithm.verify_signature(key, value, sig):
240 | return True
241 |
242 | return False
243 |
244 | def unsign(self, signed_value: str | bytes) -> bytes:
245 | """Unsigns the given string."""
246 | signed_value = want_bytes(signed_value)
247 |
248 | if self.sep not in signed_value:
249 | raise BadSignature(f"No {self.sep!r} found in value")
250 |
251 | value, sig = signed_value.rsplit(self.sep, 1)
252 |
253 | if self.verify_signature(value, sig):
254 | return value
255 |
256 | raise BadSignature(f"Signature {sig!r} does not match", payload=value)
257 |
258 | def validate(self, signed_value: str | bytes) -> bool:
259 | """Only validates the given signed value. Returns ``True`` if
260 | the signature exists and is valid.
261 | """
262 | try:
263 | self.unsign(signed_value)
264 | return True
265 | except BadSignature:
266 | return False
267 |
```