This is page 58 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/bs4/tests/test_css.py:
--------------------------------------------------------------------------------
```python
1 | import pytest
2 | import types
3 | from unittest.mock import MagicMock
4 |
5 | from bs4 import (
6 | CSS,
7 | BeautifulSoup,
8 | ResultSet,
9 | )
10 |
11 | from . import (
12 | SoupTest,
13 | SOUP_SIEVE_PRESENT,
14 | )
15 |
16 | if SOUP_SIEVE_PRESENT:
17 | from soupsieve import SelectorSyntaxError
18 |
19 |
20 | @pytest.mark.skipif(not SOUP_SIEVE_PRESENT, reason="Soup Sieve not installed")
21 | class TestCSSSelectors(SoupTest):
22 | """Test basic CSS selector functionality.
23 |
24 | This functionality is implemented in soupsieve, which has a much
25 | more comprehensive test suite, so this is basically an extra check
26 | that soupsieve works as expected.
27 | """
28 |
29 | HTML = """
30 | <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
31 | "http://www.w3.org/TR/html4/strict.dtd">
32 | <html>
33 | <head>
34 | <title>The title</title>
35 | <link rel="stylesheet" href="blah.css" type="text/css" id="l1">
36 | </head>
37 | <body>
38 | <custom-dashed-tag class="dashed" id="dash1">Hello there.</custom-dashed-tag>
39 | <div id="main" class="fancy">
40 | <div id="inner">
41 | <h1 id="header1">An H1</h1>
42 | <p>Some text</p>
43 | <p class="onep" id="p1">Some more text</p>
44 | <h2 id="header2">An H2</h2>
45 | <p class="class1 class2 class3" id="pmulti">Another</p>
46 | <a href="http://bob.example.org/" rel="friend met" id="bob">Bob</a>
47 | <h2 id="header3">Another H2</h2>
48 | <a id="me" href="http://simonwillison.net/" rel="me">me</a>
49 | <span class="s1">
50 | <a href="#" id="s1a1">span1a1</a>
51 | <a href="#" id="s1a2">span1a2 <span id="s1a2s1">test</span></a>
52 | <span class="span2">
53 | <a href="#" id="s2a1">span2a1</a>
54 | </span>
55 | <span class="span3"></span>
56 | <custom-dashed-tag class="dashed" id="dash2"/>
57 | <div data-tag="dashedvalue" id="data1"/>
58 | </span>
59 | </div>
60 | <x id="xid">
61 | <z id="zida"/>
62 | <z id="zidab"/>
63 | <z id="zidac"/>
64 | </x>
65 | <y id="yid">
66 | <z id="zidb"/>
67 | </y>
68 | <p lang="en" id="lang-en">English</p>
69 | <p lang="en-gb" id="lang-en-gb">English UK</p>
70 | <p lang="en-us" id="lang-en-us">English US</p>
71 | <p lang="fr" id="lang-fr">French</p>
72 | </div>
73 |
74 | <div id="footer">
75 | </div>
76 | """
77 |
78 | def setup_method(self):
79 | self.soup = BeautifulSoup(self.HTML, 'html.parser')
80 |
81 | def assert_selects(self, selector, expected_ids, **kwargs):
82 | results = self.soup.select(selector, **kwargs)
83 | assert isinstance(results, ResultSet)
84 | el_ids = [el['id'] for el in results]
85 | el_ids.sort()
86 | expected_ids.sort()
87 | assert expected_ids == el_ids, "Selector %s, expected [%s], got [%s]" % (
88 | selector, ', '.join(expected_ids), ', '.join(el_ids)
89 | )
90 |
91 | assertSelect = assert_selects
92 |
93 | def assert_select_multiple(self, *tests):
94 | for selector, expected_ids in tests:
95 | self.assert_selects(selector, expected_ids)
96 |
97 | def test_precompiled(self):
98 | sel = self.soup.css.compile('div')
99 |
100 | els = self.soup.select(sel)
101 | assert len(els) == 4
102 | for div in els:
103 | assert div.name == 'div'
104 |
105 | el = self.soup.select_one(sel)
106 | assert 'main' == el['id']
107 |
108 | def test_one_tag_one(self):
109 | els = self.soup.select('title')
110 | assert len(els) == 1
111 | assert els[0].name == 'title'
112 | assert els[0].contents == ['The title']
113 |
114 | def test_one_tag_many(self):
115 | els = self.soup.select('div')
116 | assert len(els) == 4
117 | for div in els:
118 | assert div.name == 'div'
119 |
120 | el = self.soup.select_one('div')
121 | assert 'main' == el['id']
122 |
123 | def test_select_one_returns_none_if_no_match(self):
124 | match = self.soup.select_one('nonexistenttag')
125 | assert None == match
126 |
127 |
128 | def test_tag_in_tag_one(self):
129 | els = self.soup.select('div div')
130 | self.assert_selects('div div', ['inner', 'data1'])
131 |
132 | def test_tag_in_tag_many(self):
133 | for selector in ('html div', 'html body div', 'body div'):
134 | self.assert_selects(selector, ['data1', 'main', 'inner', 'footer'])
135 |
136 |
137 | def test_limit(self):
138 | self.assert_selects('html div', ['main'], limit=1)
139 | self.assert_selects('html body div', ['inner', 'main'], limit=2)
140 | self.assert_selects('body div', ['data1', 'main', 'inner', 'footer'],
141 | limit=10)
142 |
143 | def test_tag_no_match(self):
144 | assert len(self.soup.select('del')) == 0
145 |
146 | def test_invalid_tag(self):
147 | with pytest.raises(SelectorSyntaxError):
148 | self.soup.select('tag%t')
149 |
150 | def test_select_dashed_tag_ids(self):
151 | self.assert_selects('custom-dashed-tag', ['dash1', 'dash2'])
152 |
153 | def test_select_dashed_by_id(self):
154 | dashed = self.soup.select('custom-dashed-tag[id=\"dash2\"]')
155 | assert dashed[0].name == 'custom-dashed-tag'
156 | assert dashed[0]['id'] == 'dash2'
157 |
158 | def test_dashed_tag_text(self):
159 | assert self.soup.select('body > custom-dashed-tag')[0].text == 'Hello there.'
160 |
161 | def test_select_dashed_matches_find_all(self):
162 | assert self.soup.select('custom-dashed-tag') == self.soup.find_all('custom-dashed-tag')
163 |
164 | def test_header_tags(self):
165 | self.assert_select_multiple(
166 | ('h1', ['header1']),
167 | ('h2', ['header2', 'header3']),
168 | )
169 |
170 | def test_class_one(self):
171 | for selector in ('.onep', 'p.onep', 'html p.onep'):
172 | els = self.soup.select(selector)
173 | assert len(els) == 1
174 | assert els[0].name == 'p'
175 | assert els[0]['class'] == ['onep']
176 |
177 | def test_class_mismatched_tag(self):
178 | els = self.soup.select('div.onep')
179 | assert len(els) == 0
180 |
181 | def test_one_id(self):
182 | for selector in ('div#inner', '#inner', 'div div#inner'):
183 | self.assert_selects(selector, ['inner'])
184 |
185 | def test_bad_id(self):
186 | els = self.soup.select('#doesnotexist')
187 | assert len(els) == 0
188 |
189 | def test_items_in_id(self):
190 | els = self.soup.select('div#inner p')
191 | assert len(els) == 3
192 | for el in els:
193 | assert el.name == 'p'
194 | assert els[1]['class'] == ['onep']
195 | assert not els[0].has_attr('class')
196 |
197 | def test_a_bunch_of_emptys(self):
198 | for selector in ('div#main del', 'div#main div.oops', 'div div#main'):
199 | assert len(self.soup.select(selector)) == 0
200 |
201 | def test_multi_class_support(self):
202 | for selector in ('.class1', 'p.class1', '.class2', 'p.class2',
203 | '.class3', 'p.class3', 'html p.class2', 'div#inner .class2'):
204 | self.assert_selects(selector, ['pmulti'])
205 |
206 | def test_multi_class_selection(self):
207 | for selector in ('.class1.class3', '.class3.class2',
208 | '.class1.class2.class3'):
209 | self.assert_selects(selector, ['pmulti'])
210 |
211 | def test_child_selector(self):
212 | self.assert_selects('.s1 > a', ['s1a1', 's1a2'])
213 | self.assert_selects('.s1 > a span', ['s1a2s1'])
214 |
215 | def test_child_selector_id(self):
216 | self.assert_selects('.s1 > a#s1a2 span', ['s1a2s1'])
217 |
218 | def test_attribute_equals(self):
219 | self.assert_select_multiple(
220 | ('p[class="onep"]', ['p1']),
221 | ('p[id="p1"]', ['p1']),
222 | ('[class="onep"]', ['p1']),
223 | ('[id="p1"]', ['p1']),
224 | ('link[rel="stylesheet"]', ['l1']),
225 | ('link[type="text/css"]', ['l1']),
226 | ('link[href="blah.css"]', ['l1']),
227 | ('link[href="no-blah.css"]', []),
228 | ('[rel="stylesheet"]', ['l1']),
229 | ('[type="text/css"]', ['l1']),
230 | ('[href="blah.css"]', ['l1']),
231 | ('[href="no-blah.css"]', []),
232 | ('p[href="no-blah.css"]', []),
233 | ('[href="no-blah.css"]', []),
234 | )
235 |
236 | def test_attribute_tilde(self):
237 | self.assert_select_multiple(
238 | ('p[class~="class1"]', ['pmulti']),
239 | ('p[class~="class2"]', ['pmulti']),
240 | ('p[class~="class3"]', ['pmulti']),
241 | ('[class~="class1"]', ['pmulti']),
242 | ('[class~="class2"]', ['pmulti']),
243 | ('[class~="class3"]', ['pmulti']),
244 | ('a[rel~="friend"]', ['bob']),
245 | ('a[rel~="met"]', ['bob']),
246 | ('[rel~="friend"]', ['bob']),
247 | ('[rel~="met"]', ['bob']),
248 | )
249 |
250 | def test_attribute_startswith(self):
251 | self.assert_select_multiple(
252 | ('[rel^="style"]', ['l1']),
253 | ('link[rel^="style"]', ['l1']),
254 | ('notlink[rel^="notstyle"]', []),
255 | ('[rel^="notstyle"]', []),
256 | ('link[rel^="notstyle"]', []),
257 | ('link[href^="bla"]', ['l1']),
258 | ('a[href^="http://"]', ['bob', 'me']),
259 | ('[href^="http://"]', ['bob', 'me']),
260 | ('[id^="p"]', ['pmulti', 'p1']),
261 | ('[id^="m"]', ['me', 'main']),
262 | ('div[id^="m"]', ['main']),
263 | ('a[id^="m"]', ['me']),
264 | ('div[data-tag^="dashed"]', ['data1'])
265 | )
266 |
267 | def test_attribute_endswith(self):
268 | self.assert_select_multiple(
269 | ('[href$=".css"]', ['l1']),
270 | ('link[href$=".css"]', ['l1']),
271 | ('link[id$="1"]', ['l1']),
272 | ('[id$="1"]', ['data1', 'l1', 'p1', 'header1', 's1a1', 's2a1', 's1a2s1', 'dash1']),
273 | ('div[id$="1"]', ['data1']),
274 | ('[id$="noending"]', []),
275 | )
276 |
277 | def test_attribute_contains(self):
278 | self.assert_select_multiple(
279 | # From test_attribute_startswith
280 | ('[rel*="style"]', ['l1']),
281 | ('link[rel*="style"]', ['l1']),
282 | ('notlink[rel*="notstyle"]', []),
283 | ('[rel*="notstyle"]', []),
284 | ('link[rel*="notstyle"]', []),
285 | ('link[href*="bla"]', ['l1']),
286 | ('[href*="http://"]', ['bob', 'me']),
287 | ('[id*="p"]', ['pmulti', 'p1']),
288 | ('div[id*="m"]', ['main']),
289 | ('a[id*="m"]', ['me']),
290 | # From test_attribute_endswith
291 | ('[href*=".css"]', ['l1']),
292 | ('link[href*=".css"]', ['l1']),
293 | ('link[id*="1"]', ['l1']),
294 | ('[id*="1"]', ['data1', 'l1', 'p1', 'header1', 's1a1', 's1a2', 's2a1', 's1a2s1', 'dash1']),
295 | ('div[id*="1"]', ['data1']),
296 | ('[id*="noending"]', []),
297 | # New for this test
298 | ('[href*="."]', ['bob', 'me', 'l1']),
299 | ('a[href*="."]', ['bob', 'me']),
300 | ('link[href*="."]', ['l1']),
301 | ('div[id*="n"]', ['main', 'inner']),
302 | ('div[id*="nn"]', ['inner']),
303 | ('div[data-tag*="edval"]', ['data1'])
304 | )
305 |
306 | def test_attribute_exact_or_hypen(self):
307 | self.assert_select_multiple(
308 | ('p[lang|="en"]', ['lang-en', 'lang-en-gb', 'lang-en-us']),
309 | ('[lang|="en"]', ['lang-en', 'lang-en-gb', 'lang-en-us']),
310 | ('p[lang|="fr"]', ['lang-fr']),
311 | ('p[lang|="gb"]', []),
312 | )
313 |
314 | def test_attribute_exists(self):
315 | self.assert_select_multiple(
316 | ('[rel]', ['l1', 'bob', 'me']),
317 | ('link[rel]', ['l1']),
318 | ('a[rel]', ['bob', 'me']),
319 | ('[lang]', ['lang-en', 'lang-en-gb', 'lang-en-us', 'lang-fr']),
320 | ('p[class]', ['p1', 'pmulti']),
321 | ('[blah]', []),
322 | ('p[blah]', []),
323 | ('div[data-tag]', ['data1'])
324 | )
325 |
326 | def test_quoted_space_in_selector_name(self):
327 | html = """<div style="display: wrong">nope</div>
328 | <div style="display: right">yes</div>
329 | """
330 | soup = BeautifulSoup(html, 'html.parser')
331 | [chosen] = soup.select('div[style="display: right"]')
332 | assert "yes" == chosen.string
333 |
334 | def test_unsupported_pseudoclass(self):
335 | with pytest.raises(NotImplementedError):
336 | self.soup.select("a:no-such-pseudoclass")
337 |
338 | with pytest.raises(SelectorSyntaxError):
339 | self.soup.select("a:nth-of-type(a)")
340 |
341 | def test_nth_of_type(self):
342 | # Try to select first paragraph
343 | els = self.soup.select('div#inner p:nth-of-type(1)')
344 | assert len(els) == 1
345 | assert els[0].string == 'Some text'
346 |
347 | # Try to select third paragraph
348 | els = self.soup.select('div#inner p:nth-of-type(3)')
349 | assert len(els) == 1
350 | assert els[0].string == 'Another'
351 |
352 | # Try to select (non-existent!) fourth paragraph
353 | els = self.soup.select('div#inner p:nth-of-type(4)')
354 | assert len(els) == 0
355 |
356 | # Zero will select no tags.
357 | els = self.soup.select('div p:nth-of-type(0)')
358 | assert len(els) == 0
359 |
360 | def test_nth_of_type_direct_descendant(self):
361 | els = self.soup.select('div#inner > p:nth-of-type(1)')
362 | assert len(els) == 1
363 | assert els[0].string == 'Some text'
364 |
365 | def test_id_child_selector_nth_of_type(self):
366 | self.assert_selects('#inner > p:nth-of-type(2)', ['p1'])
367 |
368 | def test_select_on_element(self):
369 | # Other tests operate on the tree; this operates on an element
370 | # within the tree.
371 | inner = self.soup.find("div", id="main")
372 | selected = inner.select("div")
373 | # The <div id="inner"> tag was selected. The <div id="footer">
374 | # tag was not.
375 | self.assert_selects_ids(selected, ['inner', 'data1'])
376 |
377 | def test_overspecified_child_id(self):
378 | self.assert_selects(".fancy #inner", ['inner'])
379 | self.assert_selects(".normal #inner", [])
380 |
381 | def test_adjacent_sibling_selector(self):
382 | self.assert_selects('#p1 + h2', ['header2'])
383 | self.assert_selects('#p1 + h2 + p', ['pmulti'])
384 | self.assert_selects('#p1 + #header2 + .class1', ['pmulti'])
385 | assert [] == self.soup.select('#p1 + p')
386 |
387 | def test_general_sibling_selector(self):
388 | self.assert_selects('#p1 ~ h2', ['header2', 'header3'])
389 | self.assert_selects('#p1 ~ #header2', ['header2'])
390 | self.assert_selects('#p1 ~ h2 + a', ['me'])
391 | self.assert_selects('#p1 ~ h2 + [rel="me"]', ['me'])
392 | assert [] == self.soup.select('#inner ~ h2')
393 |
394 | def test_dangling_combinator(self):
395 | with pytest.raises(SelectorSyntaxError):
396 | self.soup.select('h1 >')
397 |
398 | def test_sibling_combinator_wont_select_same_tag_twice(self):
399 | self.assert_selects('p[lang] ~ p', ['lang-en-gb', 'lang-en-us', 'lang-fr'])
400 |
401 | # Test the selector grouping operator (the comma)
402 | def test_multiple_select(self):
403 | self.assert_selects('x, y', ['xid', 'yid'])
404 |
405 | def test_multiple_select_with_no_space(self):
406 | self.assert_selects('x,y', ['xid', 'yid'])
407 |
408 | def test_multiple_select_with_more_space(self):
409 | self.assert_selects('x, y', ['xid', 'yid'])
410 |
411 | def test_multiple_select_duplicated(self):
412 | self.assert_selects('x, x', ['xid'])
413 |
414 | def test_multiple_select_sibling(self):
415 | self.assert_selects('x, y ~ p[lang=fr]', ['xid', 'lang-fr'])
416 |
417 | def test_multiple_select_tag_and_direct_descendant(self):
418 | self.assert_selects('x, y > z', ['xid', 'zidb'])
419 |
420 | def test_multiple_select_direct_descendant_and_tags(self):
421 | self.assert_selects('div > x, y, z', ['xid', 'yid', 'zida', 'zidb', 'zidab', 'zidac'])
422 |
423 | def test_multiple_select_indirect_descendant(self):
424 | self.assert_selects('div x,y, z', ['xid', 'yid', 'zida', 'zidb', 'zidab', 'zidac'])
425 |
426 | def test_invalid_multiple_select(self):
427 | with pytest.raises(SelectorSyntaxError):
428 | self.soup.select(',x, y')
429 | with pytest.raises(SelectorSyntaxError):
430 | self.soup.select('x,,y')
431 |
432 | def test_multiple_select_attrs(self):
433 | self.assert_selects('p[lang=en], p[lang=en-gb]', ['lang-en', 'lang-en-gb'])
434 |
435 | def test_multiple_select_ids(self):
436 | self.assert_selects('x, y > z[id=zida], z[id=zidab], z[id=zidb]', ['xid', 'zidb', 'zidab'])
437 |
438 | def test_multiple_select_nested(self):
439 | self.assert_selects('body > div > x, y > z', ['xid', 'zidb'])
440 |
441 | def test_select_duplicate_elements(self):
442 | # When markup contains duplicate elements, a multiple select
443 | # will find all of them.
444 | markup = '<div class="c1"/><div class="c2"/><div class="c1"/>'
445 | soup = BeautifulSoup(markup, 'html.parser')
446 | selected = soup.select(".c1, .c2")
447 | assert 3 == len(selected)
448 |
449 | # Verify that find_all finds the same elements, though because
450 | # of an implementation detail it finds them in a different
451 | # order.
452 | for element in soup.find_all(class_=['c1', 'c2']):
453 | assert element in selected
454 |
455 | def test_closest(self):
456 | inner = self.soup.find("div", id="inner")
457 | closest = inner.css.closest("div[id=main]")
458 | assert closest == self.soup.find("div", id="main")
459 |
460 | def test_match(self):
461 | inner = self.soup.find("div", id="inner")
462 | main = self.soup.find("div", id="main")
463 | assert inner.css.match("div[id=main]") == False
464 | assert main.css.match("div[id=main]") == True
465 |
466 | def test_iselect(self):
467 | gen = self.soup.css.iselect("h2")
468 | assert isinstance(gen, types.GeneratorType)
469 | [header2, header3] = gen
470 | assert header2['id'] == 'header2'
471 | assert header3['id'] == 'header3'
472 |
473 | def test_filter(self):
474 | inner = self.soup.find("div", id="inner")
475 | results = inner.css.filter("h2")
476 | assert len(inner.css.filter("h2")) == 2
477 |
478 | results = inner.css.filter("h2[id=header3]")
479 | assert isinstance(results, ResultSet)
480 | [result] = results
481 | assert result['id'] == 'header3'
482 |
483 | def test_escape(self):
484 | m = self.soup.css.escape
485 | assert m(".foo#bar") == '\\.foo\\#bar'
486 | assert m("()[]{}") == '\\(\\)\\[\\]\\{\\}'
487 | assert m(".foo") == self.soup.css.escape(".foo")
488 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/werkzeug/datastructures/headers.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import re
4 | import typing as t
5 |
6 | from .._internal import _missing
7 | from ..exceptions import BadRequestKeyError
8 | from .mixins import ImmutableHeadersMixin
9 | from .structures import iter_multi_items
10 | from .structures import MultiDict
11 |
12 |
13 | class Headers:
14 | """An object that stores some headers. It has a dict-like interface,
15 | but is ordered, can store the same key multiple times, and iterating
16 | yields ``(key, value)`` pairs instead of only keys.
17 |
18 | This data structure is useful if you want a nicer way to handle WSGI
19 | headers which are stored as tuples in a list.
20 |
21 | From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is
22 | also a subclass of the :class:`~exceptions.BadRequest` HTTP exception
23 | and will render a page for a ``400 BAD REQUEST`` if caught in a
24 | catch-all for HTTP exceptions.
25 |
26 | Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers`
27 | class, with the exception of `__getitem__`. :mod:`wsgiref` will return
28 | `None` for ``headers['missing']``, whereas :class:`Headers` will raise
29 | a :class:`KeyError`.
30 |
31 | To create a new ``Headers`` object, pass it a list, dict, or
32 | other ``Headers`` object with default values. These values are
33 | validated the same way values added later are.
34 |
35 | :param defaults: The list of default values for the :class:`Headers`.
36 |
37 | .. versionchanged:: 2.1.0
38 | Default values are validated the same as values added later.
39 |
40 | .. versionchanged:: 0.9
41 | This data structure now stores unicode values similar to how the
42 | multi dicts do it. The main difference is that bytes can be set as
43 | well which will automatically be latin1 decoded.
44 |
45 | .. versionchanged:: 0.9
46 | The :meth:`linked` function was removed without replacement as it
47 | was an API that does not support the changes to the encoding model.
48 | """
49 |
50 | def __init__(self, defaults=None):
51 | self._list = []
52 | if defaults is not None:
53 | self.extend(defaults)
54 |
55 | def __getitem__(self, key, _get_mode=False):
56 | if not _get_mode:
57 | if isinstance(key, int):
58 | return self._list[key]
59 | elif isinstance(key, slice):
60 | return self.__class__(self._list[key])
61 | if not isinstance(key, str):
62 | raise BadRequestKeyError(key)
63 | ikey = key.lower()
64 | for k, v in self._list:
65 | if k.lower() == ikey:
66 | return v
67 | # micro optimization: if we are in get mode we will catch that
68 | # exception one stack level down so we can raise a standard
69 | # key error instead of our special one.
70 | if _get_mode:
71 | raise KeyError()
72 | raise BadRequestKeyError(key)
73 |
74 | def __eq__(self, other):
75 | def lowered(item):
76 | return (item[0].lower(),) + item[1:]
77 |
78 | return other.__class__ is self.__class__ and set(
79 | map(lowered, other._list)
80 | ) == set(map(lowered, self._list))
81 |
82 | __hash__ = None
83 |
84 | def get(self, key, default=None, type=None):
85 | """Return the default value if the requested data doesn't exist.
86 | If `type` is provided and is a callable it should convert the value,
87 | return it or raise a :exc:`ValueError` if that is not possible. In
88 | this case the function will return the default as if the value was not
89 | found:
90 |
91 | >>> d = Headers([('Content-Length', '42')])
92 | >>> d.get('Content-Length', type=int)
93 | 42
94 |
95 | :param key: The key to be looked up.
96 | :param default: The default value to be returned if the key can't
97 | be looked up. If not further specified `None` is
98 | returned.
99 | :param type: A callable that is used to cast the value in the
100 | :class:`Headers`. If a :exc:`ValueError` is raised
101 | by this callable the default value is returned.
102 |
103 | .. versionchanged:: 3.0
104 | The ``as_bytes`` parameter was removed.
105 |
106 | .. versionchanged:: 0.9
107 | The ``as_bytes`` parameter was added.
108 | """
109 | try:
110 | rv = self.__getitem__(key, _get_mode=True)
111 | except KeyError:
112 | return default
113 | if type is None:
114 | return rv
115 | try:
116 | return type(rv)
117 | except ValueError:
118 | return default
119 |
120 | def getlist(self, key, type=None):
121 | """Return the list of items for a given key. If that key is not in the
122 | :class:`Headers`, the return value will be an empty list. Just like
123 | :meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will
124 | be converted with the callable defined there.
125 |
126 | :param key: The key to be looked up.
127 | :param type: A callable that is used to cast the value in the
128 | :class:`Headers`. If a :exc:`ValueError` is raised
129 | by this callable the value will be removed from the list.
130 | :return: a :class:`list` of all the values for the key.
131 |
132 | .. versionchanged:: 3.0
133 | The ``as_bytes`` parameter was removed.
134 |
135 | .. versionchanged:: 0.9
136 | The ``as_bytes`` parameter was added.
137 | """
138 | ikey = key.lower()
139 | result = []
140 | for k, v in self:
141 | if k.lower() == ikey:
142 | if type is not None:
143 | try:
144 | v = type(v)
145 | except ValueError:
146 | continue
147 | result.append(v)
148 | return result
149 |
150 | def get_all(self, name):
151 | """Return a list of all the values for the named field.
152 |
153 | This method is compatible with the :mod:`wsgiref`
154 | :meth:`~wsgiref.headers.Headers.get_all` method.
155 | """
156 | return self.getlist(name)
157 |
158 | def items(self, lower=False):
159 | for key, value in self:
160 | if lower:
161 | key = key.lower()
162 | yield key, value
163 |
164 | def keys(self, lower=False):
165 | for key, _ in self.items(lower):
166 | yield key
167 |
168 | def values(self):
169 | for _, value in self.items():
170 | yield value
171 |
172 | def extend(self, *args, **kwargs):
173 | """Extend headers in this object with items from another object
174 | containing header items as well as keyword arguments.
175 |
176 | To replace existing keys instead of extending, use
177 | :meth:`update` instead.
178 |
179 | If provided, the first argument can be another :class:`Headers`
180 | object, a :class:`MultiDict`, :class:`dict`, or iterable of
181 | pairs.
182 |
183 | .. versionchanged:: 1.0
184 | Support :class:`MultiDict`. Allow passing ``kwargs``.
185 | """
186 | if len(args) > 1:
187 | raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
188 |
189 | if args:
190 | for key, value in iter_multi_items(args[0]):
191 | self.add(key, value)
192 |
193 | for key, value in iter_multi_items(kwargs):
194 | self.add(key, value)
195 |
196 | def __delitem__(self, key, _index_operation=True):
197 | if _index_operation and isinstance(key, (int, slice)):
198 | del self._list[key]
199 | return
200 | key = key.lower()
201 | new = []
202 | for k, v in self._list:
203 | if k.lower() != key:
204 | new.append((k, v))
205 | self._list[:] = new
206 |
207 | def remove(self, key):
208 | """Remove a key.
209 |
210 | :param key: The key to be removed.
211 | """
212 | return self.__delitem__(key, _index_operation=False)
213 |
214 | def pop(self, key=None, default=_missing):
215 | """Removes and returns a key or index.
216 |
217 | :param key: The key to be popped. If this is an integer the item at
218 | that position is removed, if it's a string the value for
219 | that key is. If the key is omitted or `None` the last
220 | item is removed.
221 | :return: an item.
222 | """
223 | if key is None:
224 | return self._list.pop()
225 | if isinstance(key, int):
226 | return self._list.pop(key)
227 | try:
228 | rv = self[key]
229 | self.remove(key)
230 | except KeyError:
231 | if default is not _missing:
232 | return default
233 | raise
234 | return rv
235 |
236 | def popitem(self):
237 | """Removes a key or index and returns a (key, value) item."""
238 | return self.pop()
239 |
240 | def __contains__(self, key):
241 | """Check if a key is present."""
242 | try:
243 | self.__getitem__(key, _get_mode=True)
244 | except KeyError:
245 | return False
246 | return True
247 |
248 | def __iter__(self):
249 | """Yield ``(key, value)`` tuples."""
250 | return iter(self._list)
251 |
252 | def __len__(self):
253 | return len(self._list)
254 |
255 | def add(self, _key, _value, **kw):
256 | """Add a new header tuple to the list.
257 |
258 | Keyword arguments can specify additional parameters for the header
259 | value, with underscores converted to dashes::
260 |
261 | >>> d = Headers()
262 | >>> d.add('Content-Type', 'text/plain')
263 | >>> d.add('Content-Disposition', 'attachment', filename='foo.png')
264 |
265 | The keyword argument dumping uses :func:`dump_options_header`
266 | behind the scenes.
267 |
268 | .. versionadded:: 0.4.1
269 | keyword arguments were added for :mod:`wsgiref` compatibility.
270 | """
271 | if kw:
272 | _value = _options_header_vkw(_value, kw)
273 | _value = _str_header_value(_value)
274 | self._list.append((_key, _value))
275 |
276 | def add_header(self, _key, _value, **_kw):
277 | """Add a new header tuple to the list.
278 |
279 | An alias for :meth:`add` for compatibility with the :mod:`wsgiref`
280 | :meth:`~wsgiref.headers.Headers.add_header` method.
281 | """
282 | self.add(_key, _value, **_kw)
283 |
284 | def clear(self):
285 | """Clears all headers."""
286 | del self._list[:]
287 |
288 | def set(self, _key, _value, **kw):
289 | """Remove all header tuples for `key` and add a new one. The newly
290 | added key either appears at the end of the list if there was no
291 | entry or replaces the first one.
292 |
293 | Keyword arguments can specify additional parameters for the header
294 | value, with underscores converted to dashes. See :meth:`add` for
295 | more information.
296 |
297 | .. versionchanged:: 0.6.1
298 | :meth:`set` now accepts the same arguments as :meth:`add`.
299 |
300 | :param key: The key to be inserted.
301 | :param value: The value to be inserted.
302 | """
303 | if kw:
304 | _value = _options_header_vkw(_value, kw)
305 | _value = _str_header_value(_value)
306 | if not self._list:
307 | self._list.append((_key, _value))
308 | return
309 | listiter = iter(self._list)
310 | ikey = _key.lower()
311 | for idx, (old_key, _old_value) in enumerate(listiter):
312 | if old_key.lower() == ikey:
313 | # replace first occurrence
314 | self._list[idx] = (_key, _value)
315 | break
316 | else:
317 | self._list.append((_key, _value))
318 | return
319 | self._list[idx + 1 :] = [t for t in listiter if t[0].lower() != ikey]
320 |
321 | def setlist(self, key, values):
322 | """Remove any existing values for a header and add new ones.
323 |
324 | :param key: The header key to set.
325 | :param values: An iterable of values to set for the key.
326 |
327 | .. versionadded:: 1.0
328 | """
329 | if values:
330 | values_iter = iter(values)
331 | self.set(key, next(values_iter))
332 |
333 | for value in values_iter:
334 | self.add(key, value)
335 | else:
336 | self.remove(key)
337 |
338 | def setdefault(self, key, default):
339 | """Return the first value for the key if it is in the headers,
340 | otherwise set the header to the value given by ``default`` and
341 | return that.
342 |
343 | :param key: The header key to get.
344 | :param default: The value to set for the key if it is not in the
345 | headers.
346 | """
347 | if key in self:
348 | return self[key]
349 |
350 | self.set(key, default)
351 | return default
352 |
353 | def setlistdefault(self, key, default):
354 | """Return the list of values for the key if it is in the
355 | headers, otherwise set the header to the list of values given
356 | by ``default`` and return that.
357 |
358 | Unlike :meth:`MultiDict.setlistdefault`, modifying the returned
359 | list will not affect the headers.
360 |
361 | :param key: The header key to get.
362 | :param default: An iterable of values to set for the key if it
363 | is not in the headers.
364 |
365 | .. versionadded:: 1.0
366 | """
367 | if key not in self:
368 | self.setlist(key, default)
369 |
370 | return self.getlist(key)
371 |
372 | def __setitem__(self, key, value):
373 | """Like :meth:`set` but also supports index/slice based setting."""
374 | if isinstance(key, (slice, int)):
375 | if isinstance(key, int):
376 | value = [value]
377 | value = [(k, _str_header_value(v)) for (k, v) in value]
378 | if isinstance(key, int):
379 | self._list[key] = value[0]
380 | else:
381 | self._list[key] = value
382 | else:
383 | self.set(key, value)
384 |
385 | def update(self, *args, **kwargs):
386 | """Replace headers in this object with items from another
387 | headers object and keyword arguments.
388 |
389 | To extend existing keys instead of replacing, use :meth:`extend`
390 | instead.
391 |
392 | If provided, the first argument can be another :class:`Headers`
393 | object, a :class:`MultiDict`, :class:`dict`, or iterable of
394 | pairs.
395 |
396 | .. versionadded:: 1.0
397 | """
398 | if len(args) > 1:
399 | raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
400 |
401 | if args:
402 | mapping = args[0]
403 |
404 | if isinstance(mapping, (Headers, MultiDict)):
405 | for key in mapping.keys():
406 | self.setlist(key, mapping.getlist(key))
407 | elif isinstance(mapping, dict):
408 | for key, value in mapping.items():
409 | if isinstance(value, (list, tuple)):
410 | self.setlist(key, value)
411 | else:
412 | self.set(key, value)
413 | else:
414 | for key, value in mapping:
415 | self.set(key, value)
416 |
417 | for key, value in kwargs.items():
418 | if isinstance(value, (list, tuple)):
419 | self.setlist(key, value)
420 | else:
421 | self.set(key, value)
422 |
423 | def to_wsgi_list(self):
424 | """Convert the headers into a list suitable for WSGI.
425 |
426 | :return: list
427 | """
428 | return list(self)
429 |
430 | def copy(self):
431 | return self.__class__(self._list)
432 |
433 | def __copy__(self):
434 | return self.copy()
435 |
436 | def __str__(self):
437 | """Returns formatted headers suitable for HTTP transmission."""
438 | strs = []
439 | for key, value in self.to_wsgi_list():
440 | strs.append(f"{key}: {value}")
441 | strs.append("\r\n")
442 | return "\r\n".join(strs)
443 |
444 | def __repr__(self):
445 | return f"{type(self).__name__}({list(self)!r})"
446 |
447 |
448 | def _options_header_vkw(value: str, kw: dict[str, t.Any]):
449 | return http.dump_options_header(
450 | value, {k.replace("_", "-"): v for k, v in kw.items()}
451 | )
452 |
453 |
454 | _newline_re = re.compile(r"[\r\n]")
455 |
456 |
457 | def _str_header_value(value: t.Any) -> str:
458 | if not isinstance(value, str):
459 | value = str(value)
460 |
461 | if _newline_re.search(value) is not None:
462 | raise ValueError("Header values must not contain newline characters.")
463 |
464 | return value
465 |
466 |
467 | class EnvironHeaders(ImmutableHeadersMixin, Headers):
468 | """Read only version of the headers from a WSGI environment. This
469 | provides the same interface as `Headers` and is constructed from
470 | a WSGI environment.
471 | From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
472 | subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
473 | render a page for a ``400 BAD REQUEST`` if caught in a catch-all for
474 | HTTP exceptions.
475 | """
476 |
477 | def __init__(self, environ):
478 | self.environ = environ
479 |
480 | def __eq__(self, other):
481 | return self.environ is other.environ
482 |
483 | __hash__ = None
484 |
485 | def __getitem__(self, key, _get_mode=False):
486 | # _get_mode is a no-op for this class as there is no index but
487 | # used because get() calls it.
488 | if not isinstance(key, str):
489 | raise KeyError(key)
490 | key = key.upper().replace("-", "_")
491 | if key in {"CONTENT_TYPE", "CONTENT_LENGTH"}:
492 | return self.environ[key]
493 | return self.environ[f"HTTP_{key}"]
494 |
495 | def __len__(self):
496 | # the iter is necessary because otherwise list calls our
497 | # len which would call list again and so forth.
498 | return len(list(iter(self)))
499 |
500 | def __iter__(self):
501 | for key, value in self.environ.items():
502 | if key.startswith("HTTP_") and key not in {
503 | "HTTP_CONTENT_TYPE",
504 | "HTTP_CONTENT_LENGTH",
505 | }:
506 | yield key[5:].replace("_", "-").title(), value
507 | elif key in {"CONTENT_TYPE", "CONTENT_LENGTH"} and value:
508 | yield key.replace("_", "-").title(), value
509 |
510 | def copy(self):
511 | raise TypeError(f"cannot create {type(self).__name__!r} copies")
512 |
513 |
514 | # circular dependencies
515 | from .. import http
516 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/urllib3/_collections.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import typing
4 | from collections import OrderedDict
5 | from enum import Enum, auto
6 | from threading import RLock
7 |
8 | if typing.TYPE_CHECKING:
9 | # We can only import Protocol if TYPE_CHECKING because it's a development
10 | # dependency, and is not available at runtime.
11 | from typing import Protocol
12 |
13 | from typing_extensions import Self
14 |
15 | class HasGettableStringKeys(Protocol):
16 | def keys(self) -> typing.Iterator[str]:
17 | ...
18 |
19 | def __getitem__(self, key: str) -> str:
20 | ...
21 |
22 |
23 | __all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"]
24 |
25 |
26 | # Key type
27 | _KT = typing.TypeVar("_KT")
28 | # Value type
29 | _VT = typing.TypeVar("_VT")
30 | # Default type
31 | _DT = typing.TypeVar("_DT")
32 |
33 | ValidHTTPHeaderSource = typing.Union[
34 | "HTTPHeaderDict",
35 | typing.Mapping[str, str],
36 | typing.Iterable[typing.Tuple[str, str]],
37 | "HasGettableStringKeys",
38 | ]
39 |
40 |
41 | class _Sentinel(Enum):
42 | not_passed = auto()
43 |
44 |
45 | def ensure_can_construct_http_header_dict(
46 | potential: object,
47 | ) -> ValidHTTPHeaderSource | None:
48 | if isinstance(potential, HTTPHeaderDict):
49 | return potential
50 | elif isinstance(potential, typing.Mapping):
51 | # Full runtime checking of the contents of a Mapping is expensive, so for the
52 | # purposes of typechecking, we assume that any Mapping is the right shape.
53 | return typing.cast(typing.Mapping[str, str], potential)
54 | elif isinstance(potential, typing.Iterable):
55 | # Similarly to Mapping, full runtime checking of the contents of an Iterable is
56 | # expensive, so for the purposes of typechecking, we assume that any Iterable
57 | # is the right shape.
58 | return typing.cast(typing.Iterable[typing.Tuple[str, str]], potential)
59 | elif hasattr(potential, "keys") and hasattr(potential, "__getitem__"):
60 | return typing.cast("HasGettableStringKeys", potential)
61 | else:
62 | return None
63 |
64 |
65 | class RecentlyUsedContainer(typing.Generic[_KT, _VT], typing.MutableMapping[_KT, _VT]):
66 | """
67 | Provides a thread-safe dict-like container which maintains up to
68 | ``maxsize`` keys while throwing away the least-recently-used keys beyond
69 | ``maxsize``.
70 |
71 | :param maxsize:
72 | Maximum number of recent elements to retain.
73 |
74 | :param dispose_func:
75 | Every time an item is evicted from the container,
76 | ``dispose_func(value)`` is called. Callback which will get called
77 | """
78 |
79 | _container: typing.OrderedDict[_KT, _VT]
80 | _maxsize: int
81 | dispose_func: typing.Callable[[_VT], None] | None
82 | lock: RLock
83 |
84 | def __init__(
85 | self,
86 | maxsize: int = 10,
87 | dispose_func: typing.Callable[[_VT], None] | None = None,
88 | ) -> None:
89 | super().__init__()
90 | self._maxsize = maxsize
91 | self.dispose_func = dispose_func
92 | self._container = OrderedDict()
93 | self.lock = RLock()
94 |
95 | def __getitem__(self, key: _KT) -> _VT:
96 | # Re-insert the item, moving it to the end of the eviction line.
97 | with self.lock:
98 | item = self._container.pop(key)
99 | self._container[key] = item
100 | return item
101 |
102 | def __setitem__(self, key: _KT, value: _VT) -> None:
103 | evicted_item = None
104 | with self.lock:
105 | # Possibly evict the existing value of 'key'
106 | try:
107 | # If the key exists, we'll overwrite it, which won't change the
108 | # size of the pool. Because accessing a key should move it to
109 | # the end of the eviction line, we pop it out first.
110 | evicted_item = key, self._container.pop(key)
111 | self._container[key] = value
112 | except KeyError:
113 | # When the key does not exist, we insert the value first so that
114 | # evicting works in all cases, including when self._maxsize is 0
115 | self._container[key] = value
116 | if len(self._container) > self._maxsize:
117 | # If we didn't evict an existing value, and we've hit our maximum
118 | # size, then we have to evict the least recently used item from
119 | # the beginning of the container.
120 | evicted_item = self._container.popitem(last=False)
121 |
122 | # After releasing the lock on the pool, dispose of any evicted value.
123 | if evicted_item is not None and self.dispose_func:
124 | _, evicted_value = evicted_item
125 | self.dispose_func(evicted_value)
126 |
127 | def __delitem__(self, key: _KT) -> None:
128 | with self.lock:
129 | value = self._container.pop(key)
130 |
131 | if self.dispose_func:
132 | self.dispose_func(value)
133 |
134 | def __len__(self) -> int:
135 | with self.lock:
136 | return len(self._container)
137 |
138 | def __iter__(self) -> typing.NoReturn:
139 | raise NotImplementedError(
140 | "Iteration over this class is unlikely to be threadsafe."
141 | )
142 |
143 | def clear(self) -> None:
144 | with self.lock:
145 | # Copy pointers to all values, then wipe the mapping
146 | values = list(self._container.values())
147 | self._container.clear()
148 |
149 | if self.dispose_func:
150 | for value in values:
151 | self.dispose_func(value)
152 |
153 | def keys(self) -> set[_KT]: # type: ignore[override]
154 | with self.lock:
155 | return set(self._container.keys())
156 |
157 |
158 | class HTTPHeaderDictItemView(typing.Set[typing.Tuple[str, str]]):
159 | """
160 | HTTPHeaderDict is unusual for a Mapping[str, str] in that it has two modes of
161 | address.
162 |
163 | If we directly try to get an item with a particular name, we will get a string
164 | back that is the concatenated version of all the values:
165 |
166 | >>> d['X-Header-Name']
167 | 'Value1, Value2, Value3'
168 |
169 | However, if we iterate over an HTTPHeaderDict's items, we will optionally combine
170 | these values based on whether combine=True was called when building up the dictionary
171 |
172 | >>> d = HTTPHeaderDict({"A": "1", "B": "foo"})
173 | >>> d.add("A", "2", combine=True)
174 | >>> d.add("B", "bar")
175 | >>> list(d.items())
176 | [
177 | ('A', '1, 2'),
178 | ('B', 'foo'),
179 | ('B', 'bar'),
180 | ]
181 |
182 | This class conforms to the interface required by the MutableMapping ABC while
183 | also giving us the nonstandard iteration behavior we want; items with duplicate
184 | keys, ordered by time of first insertion.
185 | """
186 |
187 | _headers: HTTPHeaderDict
188 |
189 | def __init__(self, headers: HTTPHeaderDict) -> None:
190 | self._headers = headers
191 |
192 | def __len__(self) -> int:
193 | return len(list(self._headers.iteritems()))
194 |
195 | def __iter__(self) -> typing.Iterator[tuple[str, str]]:
196 | return self._headers.iteritems()
197 |
198 | def __contains__(self, item: object) -> bool:
199 | if isinstance(item, tuple) and len(item) == 2:
200 | passed_key, passed_val = item
201 | if isinstance(passed_key, str) and isinstance(passed_val, str):
202 | return self._headers._has_value_for_header(passed_key, passed_val)
203 | return False
204 |
205 |
206 | class HTTPHeaderDict(typing.MutableMapping[str, str]):
207 | """
208 | :param headers:
209 | An iterable of field-value pairs. Must not contain multiple field names
210 | when compared case-insensitively.
211 |
212 | :param kwargs:
213 | Additional field-value pairs to pass in to ``dict.update``.
214 |
215 | A ``dict`` like container for storing HTTP Headers.
216 |
217 | Field names are stored and compared case-insensitively in compliance with
218 | RFC 7230. Iteration provides the first case-sensitive key seen for each
219 | case-insensitive pair.
220 |
221 | Using ``__setitem__`` syntax overwrites fields that compare equal
222 | case-insensitively in order to maintain ``dict``'s api. For fields that
223 | compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add``
224 | in a loop.
225 |
226 | If multiple fields that are equal case-insensitively are passed to the
227 | constructor or ``.update``, the behavior is undefined and some will be
228 | lost.
229 |
230 | >>> headers = HTTPHeaderDict()
231 | >>> headers.add('Set-Cookie', 'foo=bar')
232 | >>> headers.add('set-cookie', 'baz=quxx')
233 | >>> headers['content-length'] = '7'
234 | >>> headers['SET-cookie']
235 | 'foo=bar, baz=quxx'
236 | >>> headers['Content-Length']
237 | '7'
238 | """
239 |
240 | _container: typing.MutableMapping[str, list[str]]
241 |
242 | def __init__(self, headers: ValidHTTPHeaderSource | None = None, **kwargs: str):
243 | super().__init__()
244 | self._container = {} # 'dict' is insert-ordered
245 | if headers is not None:
246 | if isinstance(headers, HTTPHeaderDict):
247 | self._copy_from(headers)
248 | else:
249 | self.extend(headers)
250 | if kwargs:
251 | self.extend(kwargs)
252 |
253 | def __setitem__(self, key: str, val: str) -> None:
254 | # avoid a bytes/str comparison by decoding before httplib
255 | if isinstance(key, bytes):
256 | key = key.decode("latin-1")
257 | self._container[key.lower()] = [key, val]
258 |
259 | def __getitem__(self, key: str) -> str:
260 | val = self._container[key.lower()]
261 | return ", ".join(val[1:])
262 |
263 | def __delitem__(self, key: str) -> None:
264 | del self._container[key.lower()]
265 |
266 | def __contains__(self, key: object) -> bool:
267 | if isinstance(key, str):
268 | return key.lower() in self._container
269 | return False
270 |
271 | def setdefault(self, key: str, default: str = "") -> str:
272 | return super().setdefault(key, default)
273 |
274 | def __eq__(self, other: object) -> bool:
275 | maybe_constructable = ensure_can_construct_http_header_dict(other)
276 | if maybe_constructable is None:
277 | return False
278 | else:
279 | other_as_http_header_dict = type(self)(maybe_constructable)
280 |
281 | return {k.lower(): v for k, v in self.itermerged()} == {
282 | k.lower(): v for k, v in other_as_http_header_dict.itermerged()
283 | }
284 |
285 | def __ne__(self, other: object) -> bool:
286 | return not self.__eq__(other)
287 |
288 | def __len__(self) -> int:
289 | return len(self._container)
290 |
291 | def __iter__(self) -> typing.Iterator[str]:
292 | # Only provide the originally cased names
293 | for vals in self._container.values():
294 | yield vals[0]
295 |
296 | def discard(self, key: str) -> None:
297 | try:
298 | del self[key]
299 | except KeyError:
300 | pass
301 |
302 | def add(self, key: str, val: str, *, combine: bool = False) -> None:
303 | """Adds a (name, value) pair, doesn't overwrite the value if it already
304 | exists.
305 |
306 | If this is called with combine=True, instead of adding a new header value
307 | as a distinct item during iteration, this will instead append the value to
308 | any existing header value with a comma. If no existing header value exists
309 | for the key, then the value will simply be added, ignoring the combine parameter.
310 |
311 | >>> headers = HTTPHeaderDict(foo='bar')
312 | >>> headers.add('Foo', 'baz')
313 | >>> headers['foo']
314 | 'bar, baz'
315 | >>> list(headers.items())
316 | [('foo', 'bar'), ('foo', 'baz')]
317 | >>> headers.add('foo', 'quz', combine=True)
318 | >>> list(headers.items())
319 | [('foo', 'bar, baz, quz')]
320 | """
321 | # avoid a bytes/str comparison by decoding before httplib
322 | if isinstance(key, bytes):
323 | key = key.decode("latin-1")
324 | key_lower = key.lower()
325 | new_vals = [key, val]
326 | # Keep the common case aka no item present as fast as possible
327 | vals = self._container.setdefault(key_lower, new_vals)
328 | if new_vals is not vals:
329 | # if there are values here, then there is at least the initial
330 | # key/value pair
331 | assert len(vals) >= 2
332 | if combine:
333 | vals[-1] = vals[-1] + ", " + val
334 | else:
335 | vals.append(val)
336 |
337 | def extend(self, *args: ValidHTTPHeaderSource, **kwargs: str) -> None:
338 | """Generic import function for any type of header-like object.
339 | Adapted version of MutableMapping.update in order to insert items
340 | with self.add instead of self.__setitem__
341 | """
342 | if len(args) > 1:
343 | raise TypeError(
344 | f"extend() takes at most 1 positional arguments ({len(args)} given)"
345 | )
346 | other = args[0] if len(args) >= 1 else ()
347 |
348 | if isinstance(other, HTTPHeaderDict):
349 | for key, val in other.iteritems():
350 | self.add(key, val)
351 | elif isinstance(other, typing.Mapping):
352 | for key, val in other.items():
353 | self.add(key, val)
354 | elif isinstance(other, typing.Iterable):
355 | other = typing.cast(typing.Iterable[typing.Tuple[str, str]], other)
356 | for key, value in other:
357 | self.add(key, value)
358 | elif hasattr(other, "keys") and hasattr(other, "__getitem__"):
359 | # THIS IS NOT A TYPESAFE BRANCH
360 | # In this branch, the object has a `keys` attr but is not a Mapping or any of
361 | # the other types indicated in the method signature. We do some stuff with
362 | # it as though it partially implements the Mapping interface, but we're not
363 | # doing that stuff safely AT ALL.
364 | for key in other.keys():
365 | self.add(key, other[key])
366 |
367 | for key, value in kwargs.items():
368 | self.add(key, value)
369 |
370 | @typing.overload
371 | def getlist(self, key: str) -> list[str]:
372 | ...
373 |
374 | @typing.overload
375 | def getlist(self, key: str, default: _DT) -> list[str] | _DT:
376 | ...
377 |
378 | def getlist(
379 | self, key: str, default: _Sentinel | _DT = _Sentinel.not_passed
380 | ) -> list[str] | _DT:
381 | """Returns a list of all the values for the named field. Returns an
382 | empty list if the key doesn't exist."""
383 | try:
384 | vals = self._container[key.lower()]
385 | except KeyError:
386 | if default is _Sentinel.not_passed:
387 | # _DT is unbound; empty list is instance of List[str]
388 | return []
389 | # _DT is bound; default is instance of _DT
390 | return default
391 | else:
392 | # _DT may or may not be bound; vals[1:] is instance of List[str], which
393 | # meets our external interface requirement of `Union[List[str], _DT]`.
394 | return vals[1:]
395 |
396 | def _prepare_for_method_change(self) -> Self:
397 | """
398 | Remove content-specific header fields before changing the request
399 | method to GET or HEAD according to RFC 9110, Section 15.4.
400 | """
401 | content_specific_headers = [
402 | "Content-Encoding",
403 | "Content-Language",
404 | "Content-Location",
405 | "Content-Type",
406 | "Content-Length",
407 | "Digest",
408 | "Last-Modified",
409 | ]
410 | for header in content_specific_headers:
411 | self.discard(header)
412 | return self
413 |
414 | # Backwards compatibility for httplib
415 | getheaders = getlist
416 | getallmatchingheaders = getlist
417 | iget = getlist
418 |
419 | # Backwards compatibility for http.cookiejar
420 | get_all = getlist
421 |
422 | def __repr__(self) -> str:
423 | return f"{type(self).__name__}({dict(self.itermerged())})"
424 |
425 | def _copy_from(self, other: HTTPHeaderDict) -> None:
426 | for key in other:
427 | val = other.getlist(key)
428 | self._container[key.lower()] = [key, *val]
429 |
430 | def copy(self) -> Self:
431 | clone = type(self)()
432 | clone._copy_from(self)
433 | return clone
434 |
435 | def iteritems(self) -> typing.Iterator[tuple[str, str]]:
436 | """Iterate over all header lines, including duplicate ones."""
437 | for key in self:
438 | vals = self._container[key.lower()]
439 | for val in vals[1:]:
440 | yield vals[0], val
441 |
442 | def itermerged(self) -> typing.Iterator[tuple[str, str]]:
443 | """Iterate over all headers, merging duplicate ones together."""
444 | for key in self:
445 | val = self._container[key.lower()]
446 | yield val[0], ", ".join(val[1:])
447 |
448 | def items(self) -> HTTPHeaderDictItemView: # type: ignore[override]
449 | return HTTPHeaderDictItemView(self)
450 |
451 | def _has_value_for_header(self, header_name: str, potential_value: str) -> bool:
452 | if header_name in self:
453 | return potential_value in self._container[header_name.lower()][1:]
454 | return False
455 |
456 | def __ior__(self, other: object) -> HTTPHeaderDict:
457 | # Supports extending a header dict in-place using operator |=
458 | # combining items with add instead of __setitem__
459 | maybe_constructable = ensure_can_construct_http_header_dict(other)
460 | if maybe_constructable is None:
461 | return NotImplemented
462 | self.extend(maybe_constructable)
463 | return self
464 |
465 | def __or__(self, other: object) -> Self:
466 | # Supports merging header dicts using operator |
467 | # combining items with add instead of __setitem__
468 | maybe_constructable = ensure_can_construct_http_header_dict(other)
469 | if maybe_constructable is None:
470 | return NotImplemented
471 | result = self.copy()
472 | result.extend(maybe_constructable)
473 | return result
474 |
475 | def __ror__(self, other: object) -> Self:
476 | # Supports merging header dicts using operator | when other is on left side
477 | # combining items with add instead of __setitem__
478 | maybe_constructable = ensure_can_construct_http_header_dict(other)
479 | if maybe_constructable is None:
480 | return NotImplemented
481 | result = type(self)(maybe_constructable)
482 | result.extend(self)
483 | return result
484 |
```