This is page 139 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/soupsieve/css_parser.py:
--------------------------------------------------------------------------------
```python
1 | """CSS selector parser."""
2 | from __future__ import annotations
3 | import re
4 | from functools import lru_cache
5 | from . import util
6 | from . import css_match as cm
7 | from . import css_types as ct
8 | from .util import SelectorSyntaxError
9 | import warnings
10 | from typing import Match, Any, Iterator, cast
11 |
12 | UNICODE_REPLACEMENT_CHAR = 0xFFFD
13 |
14 | # Simple pseudo classes that take no parameters
15 | PSEUDO_SIMPLE = {
16 | ":any-link",
17 | ":empty",
18 | ":first-child",
19 | ":first-of-type",
20 | ":in-range",
21 | ":out-of-range",
22 | ":last-child",
23 | ":last-of-type",
24 | ":link",
25 | ":only-child",
26 | ":only-of-type",
27 | ":root",
28 | ':checked',
29 | ':default',
30 | ':disabled',
31 | ':enabled',
32 | ':indeterminate',
33 | ':optional',
34 | ':placeholder-shown',
35 | ':read-only',
36 | ':read-write',
37 | ':required',
38 | ':scope',
39 | ':defined'
40 | }
41 |
42 | # Supported, simple pseudo classes that match nothing in the Soup Sieve environment
43 | PSEUDO_SIMPLE_NO_MATCH = {
44 | ':active',
45 | ':current',
46 | ':focus',
47 | ':focus-visible',
48 | ':focus-within',
49 | ':future',
50 | ':host',
51 | ':hover',
52 | ':local-link',
53 | ':past',
54 | ':paused',
55 | ':playing',
56 | ':target',
57 | ':target-within',
58 | ':user-invalid',
59 | ':visited'
60 | }
61 |
62 | # Complex pseudo classes that take selector lists
63 | PSEUDO_COMPLEX = {
64 | ':contains',
65 | ':-soup-contains',
66 | ':-soup-contains-own',
67 | ':has',
68 | ':is',
69 | ':matches',
70 | ':not',
71 | ':where'
72 | }
73 |
74 | PSEUDO_COMPLEX_NO_MATCH = {
75 | ':current',
76 | ':host',
77 | ':host-context'
78 | }
79 |
80 | # Complex pseudo classes that take very specific parameters and are handled special
81 | PSEUDO_SPECIAL = {
82 | ':dir',
83 | ':lang',
84 | ':nth-child',
85 | ':nth-last-child',
86 | ':nth-last-of-type',
87 | ':nth-of-type'
88 | }
89 |
90 | PSEUDO_SUPPORTED = PSEUDO_SIMPLE | PSEUDO_SIMPLE_NO_MATCH | PSEUDO_COMPLEX | PSEUDO_COMPLEX_NO_MATCH | PSEUDO_SPECIAL
91 |
92 | # Sub-patterns parts
93 | # Whitespace
94 | NEWLINE = r'(?:\r\n|(?!\r\n)[\n\f\r])'
95 | WS = fr'(?:[ \t]|{NEWLINE})'
96 | # Comments
97 | COMMENTS = r'(?:/\*[^*]*\*+(?:[^/*][^*]*\*+)*/)'
98 | # Whitespace with comments included
99 | WSC = fr'(?:{WS}|{COMMENTS})'
100 | # CSS escapes
101 | CSS_ESCAPES = fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$))'
102 | CSS_STRING_ESCAPES = fr'(?:\\(?:[a-f0-9]{{1,6}}{WS}?|[^\r\n\f]|$|{NEWLINE}))'
103 | # CSS Identifier
104 | IDENTIFIER = fr'''
105 | (?:(?:-?(?:[^\x00-\x2f\x30-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})+|--)
106 | (?:[^\x00-\x2c\x2e\x2f\x3A-\x40\x5B-\x5E\x60\x7B-\x9f]|{CSS_ESCAPES})*)
107 | '''
108 | # `nth` content
109 | NTH = fr'(?:[-+])?(?:[0-9]+n?|n)(?:(?<=n){WSC}*(?:[-+]){WSC}*(?:[0-9]+))?'
110 | # Value: quoted string or identifier
111 | VALUE = fr'''(?:"(?:\\(?:.|{NEWLINE})|[^\\"\r\n\f]+)*?"|'(?:\\(?:.|{NEWLINE})|[^\\'\r\n\f]+)*?'|{IDENTIFIER}+)'''
112 | # Attribute value comparison. `!=` is handled special as it is non-standard.
113 | ATTR = fr'(?:{WSC}*(?P<cmp>[!~^|*$]?=){WSC}*(?P<value>{VALUE})(?:{WSC}*(?P<case>[is]))?)?{WSC}*\]'
114 |
115 | # Selector patterns
116 | # IDs (`#id`)
117 | PAT_ID = fr'\#{IDENTIFIER}'
118 | # Classes (`.class`)
119 | PAT_CLASS = fr'\.{IDENTIFIER}'
120 | # Prefix:Tag (`prefix|tag`)
121 | PAT_TAG = fr'(?P<tag_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<tag_name>{IDENTIFIER}|\*)'
122 | # Attributes (`[attr]`, `[attr=value]`, etc.)
123 | PAT_ATTR = fr'\[{WSC}*(?P<attr_ns>(?:{IDENTIFIER}|\*)?\|)?(?P<attr_name>{IDENTIFIER}){ATTR}'
124 | # Pseudo class (`:pseudo-class`, `:pseudo-class(`)
125 | PAT_PSEUDO_CLASS = fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)?'
126 | # Pseudo class special patterns. Matches `:pseudo-class(` for special case pseudo classes.
127 | PAT_PSEUDO_CLASS_SPECIAL = fr'(?P<name>:{IDENTIFIER})(?P<open>\({WSC}*)'
128 | # Custom pseudo class (`:--custom-pseudo`)
129 | PAT_PSEUDO_CLASS_CUSTOM = fr'(?P<name>:(?=--){IDENTIFIER})'
130 | # Nesting ampersand selector. Matches `&`
131 | PAT_AMP = r'&'
132 | # Closing pseudo group (`)`)
133 | PAT_PSEUDO_CLOSE = fr'{WSC}*\)'
134 | # Pseudo element (`::pseudo-element`)
135 | PAT_PSEUDO_ELEMENT = fr':{PAT_PSEUDO_CLASS}'
136 | # At rule (`@page`, etc.) (not supported)
137 | PAT_AT_RULE = fr'@P{IDENTIFIER}'
138 | # Pseudo class `nth-child` (`:nth-child(an+b [of S]?)`, `:first-child`, etc.)
139 | PAT_PSEUDO_NTH_CHILD = fr'''
140 | (?P<pseudo_nth_child>{PAT_PSEUDO_CLASS_SPECIAL}
141 | (?P<nth_child>{NTH}|even|odd))(?:{WSC}*\)|(?P<of>{COMMENTS}*{WS}{WSC}*of{COMMENTS}*{WS}{WSC}*))
142 | '''
143 | # Pseudo class `nth-of-type` (`:nth-of-type(an+b)`, `:first-of-type`, etc.)
144 | PAT_PSEUDO_NTH_TYPE = fr'''
145 | (?P<pseudo_nth_type>{PAT_PSEUDO_CLASS_SPECIAL}
146 | (?P<nth_type>{NTH}|even|odd)){WSC}*\)
147 | '''
148 | # Pseudo class language (`:lang("*-de", en)`)
149 | PAT_PSEUDO_LANG = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'
150 | # Pseudo class direction (`:dir(ltr)`)
151 | PAT_PSEUDO_DIR = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<dir>ltr|rtl){WSC}*\)'
152 | # Combining characters (`>`, `~`, ` `, `+`, `,`)
153 | PAT_COMBINE = fr'{WSC}*?(?P<relation>[,+>~]|{WS}(?![,+>~])){WSC}*'
154 | # Extra: Contains (`:contains(text)`)
155 | PAT_PSEUDO_CONTAINS = fr'{PAT_PSEUDO_CLASS_SPECIAL}(?P<values>{VALUE}(?:{WSC}*,{WSC}*{VALUE})*){WSC}*\)'
156 |
157 | # Regular expressions
158 | # CSS escape pattern
159 | RE_CSS_ESC = re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WSC}?)|(\\[^\r\n\f])|(\\$))', re.I)
160 | RE_CSS_STR_ESC = re.compile(fr'(?:(\\[a-f0-9]{{1,6}}{WS}?)|(\\[^\r\n\f])|(\\$)|(\\{NEWLINE}))', re.I)
161 | # Pattern to break up `nth` specifiers
162 | RE_NTH = re.compile(fr'(?P<s1>[-+])?(?P<a>[0-9]+n?|n)(?:(?<=n){WSC}*(?P<s2>[-+]){WSC}*(?P<b>[0-9]+))?', re.I)
163 | # Pattern to iterate multiple values.
164 | RE_VALUES = re.compile(fr'(?:(?P<value>{VALUE})|(?P<split>{WSC}*,{WSC}*))', re.X)
165 | # Whitespace checks
166 | RE_WS = re.compile(WS)
167 | RE_WS_BEGIN = re.compile(fr'^{WSC}*')
168 | RE_WS_END = re.compile(fr'{WSC}*$')
169 | RE_CUSTOM = re.compile(fr'^{PAT_PSEUDO_CLASS_CUSTOM}$', re.X)
170 |
171 | # Constants
172 | # List split token
173 | COMMA_COMBINATOR = ','
174 | # Relation token for descendant
175 | WS_COMBINATOR = " "
176 |
177 | # Parse flags
178 | FLG_PSEUDO = 0x01
179 | FLG_NOT = 0x02
180 | FLG_RELATIVE = 0x04
181 | FLG_DEFAULT = 0x08
182 | FLG_HTML = 0x10
183 | FLG_INDETERMINATE = 0x20
184 | FLG_OPEN = 0x40
185 | FLG_IN_RANGE = 0x80
186 | FLG_OUT_OF_RANGE = 0x100
187 | FLG_PLACEHOLDER_SHOWN = 0x200
188 | FLG_FORGIVE = 0x400
189 |
190 | # Maximum cached patterns to store
191 | _MAXCACHE = 500
192 |
193 |
194 | @lru_cache(maxsize=_MAXCACHE)
195 | def _cached_css_compile(
196 | pattern: str,
197 | namespaces: ct.Namespaces | None,
198 | custom: ct.CustomSelectors | None,
199 | flags: int
200 | ) -> cm.SoupSieve:
201 | """Cached CSS compile."""
202 |
203 | custom_selectors = process_custom(custom)
204 | return cm.SoupSieve(
205 | pattern,
206 | CSSParser(
207 | pattern,
208 | custom=custom_selectors,
209 | flags=flags
210 | ).process_selectors(),
211 | namespaces,
212 | custom,
213 | flags
214 | )
215 |
216 |
217 | def _purge_cache() -> None:
218 | """Purge the cache."""
219 |
220 | _cached_css_compile.cache_clear()
221 |
222 |
223 | def process_custom(custom: ct.CustomSelectors | None) -> dict[str, str | ct.SelectorList]:
224 | """Process custom."""
225 |
226 | custom_selectors = {}
227 | if custom is not None:
228 | for key, value in custom.items():
229 | name = util.lower(key)
230 | if RE_CUSTOM.match(name) is None:
231 | raise SelectorSyntaxError(f"The name '{name}' is not a valid custom pseudo-class name")
232 | if name in custom_selectors:
233 | raise KeyError(f"The custom selector '{name}' has already been registered")
234 | custom_selectors[css_unescape(name)] = value
235 | return custom_selectors
236 |
237 |
238 | def css_unescape(content: str, string: bool = False) -> str:
239 | """
240 | Unescape CSS value.
241 |
242 | Strings allow for spanning the value on multiple strings by escaping a new line.
243 | """
244 |
245 | def replace(m: Match[str]) -> str:
246 | """Replace with the appropriate substitute."""
247 |
248 | if m.group(1):
249 | codepoint = int(m.group(1)[1:], 16)
250 | if codepoint == 0:
251 | codepoint = UNICODE_REPLACEMENT_CHAR
252 | value = chr(codepoint)
253 | elif m.group(2):
254 | value = m.group(2)[1:]
255 | elif m.group(3):
256 | value = '\ufffd'
257 | else:
258 | value = ''
259 |
260 | return value
261 |
262 | return (RE_CSS_ESC if not string else RE_CSS_STR_ESC).sub(replace, content)
263 |
264 |
265 | def escape(ident: str) -> str:
266 | """Escape identifier."""
267 |
268 | string = []
269 | length = len(ident)
270 | start_dash = length > 0 and ident[0] == '-'
271 | if length == 1 and start_dash:
272 | # Need to escape identifier that is a single `-` with no other characters
273 | string.append(f'\\{ident}')
274 | else:
275 | for index, c in enumerate(ident):
276 | codepoint = ord(c)
277 | if codepoint == 0x00:
278 | string.append('\ufffd')
279 | elif (0x01 <= codepoint <= 0x1F) or codepoint == 0x7F:
280 | string.append(f'\\{codepoint:x} ')
281 | elif (index == 0 or (start_dash and index == 1)) and (0x30 <= codepoint <= 0x39):
282 | string.append(f'\\{codepoint:x} ')
283 | elif (
284 | codepoint in (0x2D, 0x5F) or codepoint >= 0x80 or (0x30 <= codepoint <= 0x39) or
285 | (0x30 <= codepoint <= 0x39) or (0x41 <= codepoint <= 0x5A) or (0x61 <= codepoint <= 0x7A)
286 | ):
287 | string.append(c)
288 | else:
289 | string.append(f'\\{c}')
290 | return ''.join(string)
291 |
292 |
293 | class SelectorPattern:
294 | """Selector pattern."""
295 |
296 | def __init__(self, name: str, pattern: str) -> None:
297 | """Initialize."""
298 |
299 | self.name = name
300 | self.re_pattern = re.compile(pattern, re.I | re.X | re.U)
301 |
302 | def get_name(self) -> str:
303 | """Get name."""
304 |
305 | return self.name
306 |
307 | def match(self, selector: str, index: int, flags: int) -> Match[str] | None:
308 | """Match the selector."""
309 |
310 | return self.re_pattern.match(selector, index)
311 |
312 |
313 | class SpecialPseudoPattern(SelectorPattern):
314 | """Selector pattern."""
315 |
316 | def __init__(self, patterns: tuple[tuple[str, tuple[str, ...], str, type[SelectorPattern]], ...]) -> None:
317 | """Initialize."""
318 |
319 | self.patterns = {}
320 | for p in patterns:
321 | name = p[0]
322 | pattern = p[3](name, p[2])
323 | for pseudo in p[1]:
324 | self.patterns[pseudo] = pattern
325 |
326 | self.matched_name = None # type: SelectorPattern | None
327 | self.re_pseudo_name = re.compile(PAT_PSEUDO_CLASS_SPECIAL, re.I | re.X | re.U)
328 |
329 | def get_name(self) -> str:
330 | """Get name."""
331 |
332 | return '' if self.matched_name is None else self.matched_name.get_name()
333 |
334 | def match(self, selector: str, index: int, flags: int) -> Match[str] | None:
335 | """Match the selector."""
336 |
337 | pseudo = None
338 | m = self.re_pseudo_name.match(selector, index)
339 | if m:
340 | name = util.lower(css_unescape(m.group('name')))
341 | pattern = self.patterns.get(name)
342 | if pattern:
343 | pseudo = pattern.match(selector, index, flags)
344 | if pseudo:
345 | self.matched_name = pattern
346 |
347 | return pseudo
348 |
349 |
350 | class _Selector:
351 | """
352 | Intermediate selector class.
353 |
354 | This stores selector data for a compound selector as we are acquiring them.
355 | Once we are done collecting the data for a compound selector, we freeze
356 | the data in an object that can be pickled and hashed.
357 | """
358 |
359 | def __init__(self, **kwargs: Any) -> None:
360 | """Initialize."""
361 |
362 | self.tag = kwargs.get('tag', None) # type: ct.SelectorTag | None
363 | self.ids = kwargs.get('ids', []) # type: list[str]
364 | self.classes = kwargs.get('classes', []) # type: list[str]
365 | self.attributes = kwargs.get('attributes', []) # type: list[ct.SelectorAttribute]
366 | self.nth = kwargs.get('nth', []) # type: list[ct.SelectorNth]
367 | self.selectors = kwargs.get('selectors', []) # type: list[ct.SelectorList]
368 | self.relations = kwargs.get('relations', []) # type: list[_Selector]
369 | self.rel_type = kwargs.get('rel_type', None) # type: str | None
370 | self.contains = kwargs.get('contains', []) # type: list[ct.SelectorContains]
371 | self.lang = kwargs.get('lang', []) # type: list[ct.SelectorLang]
372 | self.flags = kwargs.get('flags', 0) # type: int
373 | self.no_match = kwargs.get('no_match', False) # type: bool
374 |
375 | def _freeze_relations(self, relations: list[_Selector]) -> ct.SelectorList:
376 | """Freeze relation."""
377 |
378 | if relations:
379 | sel = relations[0]
380 | sel.relations.extend(relations[1:])
381 | return ct.SelectorList([sel.freeze()])
382 | else:
383 | return ct.SelectorList()
384 |
385 | def freeze(self) -> ct.Selector | ct.SelectorNull:
386 | """Freeze self."""
387 |
388 | if self.no_match:
389 | return ct.SelectorNull()
390 | else:
391 | return ct.Selector(
392 | self.tag,
393 | tuple(self.ids),
394 | tuple(self.classes),
395 | tuple(self.attributes),
396 | tuple(self.nth),
397 | tuple(self.selectors),
398 | self._freeze_relations(self.relations),
399 | self.rel_type,
400 | tuple(self.contains),
401 | tuple(self.lang),
402 | self.flags
403 | )
404 |
405 | def __str__(self) -> str: # pragma: no cover
406 | """String representation."""
407 |
408 | return (
409 | f'_Selector(tag={self.tag!r}, ids={self.ids!r}, classes={self.classes!r}, attributes={self.attributes!r}, '
410 | f'nth={self.nth!r}, selectors={self.selectors!r}, relations={self.relations!r}, '
411 | f'rel_type={self.rel_type!r}, contains={self.contains!r}, lang={self.lang!r}, flags={self.flags!r}, '
412 | f'no_match={self.no_match!r})'
413 | )
414 |
415 | __repr__ = __str__
416 |
417 |
418 | class CSSParser:
419 | """Parse CSS selectors."""
420 |
421 | css_tokens = (
422 | SelectorPattern("pseudo_close", PAT_PSEUDO_CLOSE),
423 | SpecialPseudoPattern(
424 | (
425 | (
426 | "pseudo_contains",
427 | (':contains', ':-soup-contains', ':-soup-contains-own'),
428 | PAT_PSEUDO_CONTAINS,
429 | SelectorPattern
430 | ),
431 | ("pseudo_nth_child", (':nth-child', ':nth-last-child'), PAT_PSEUDO_NTH_CHILD, SelectorPattern),
432 | ("pseudo_nth_type", (':nth-of-type', ':nth-last-of-type'), PAT_PSEUDO_NTH_TYPE, SelectorPattern),
433 | ("pseudo_lang", (':lang',), PAT_PSEUDO_LANG, SelectorPattern),
434 | ("pseudo_dir", (':dir',), PAT_PSEUDO_DIR, SelectorPattern)
435 | )
436 | ),
437 | SelectorPattern("pseudo_class_custom", PAT_PSEUDO_CLASS_CUSTOM),
438 | SelectorPattern("pseudo_class", PAT_PSEUDO_CLASS),
439 | SelectorPattern("pseudo_element", PAT_PSEUDO_ELEMENT),
440 | SelectorPattern("amp", PAT_AMP),
441 | SelectorPattern("at_rule", PAT_AT_RULE),
442 | SelectorPattern("id", PAT_ID),
443 | SelectorPattern("class", PAT_CLASS),
444 | SelectorPattern("tag", PAT_TAG),
445 | SelectorPattern("attribute", PAT_ATTR),
446 | SelectorPattern("combine", PAT_COMBINE)
447 | )
448 |
449 | def __init__(
450 | self,
451 | selector: str,
452 | custom: dict[str, str | ct.SelectorList] | None = None,
453 | flags: int = 0
454 | ) -> None:
455 | """Initialize."""
456 |
457 | self.pattern = selector.replace('\x00', '\ufffd')
458 | self.flags = flags
459 | self.debug = self.flags & util.DEBUG
460 | self.custom = {} if custom is None else custom
461 |
462 | def parse_attribute_selector(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
463 | """Create attribute selector from the returned regex match."""
464 |
465 | inverse = False
466 | op = m.group('cmp')
467 | case = util.lower(m.group('case')) if m.group('case') else None
468 | ns = css_unescape(m.group('attr_ns')[:-1]) if m.group('attr_ns') else ''
469 | attr = css_unescape(m.group('attr_name'))
470 | is_type = False
471 | pattern2 = None
472 | value = ''
473 |
474 | if case:
475 | flags = (re.I if case == 'i' else 0) | re.DOTALL
476 | elif util.lower(attr) == 'type':
477 | flags = re.I | re.DOTALL
478 | is_type = True
479 | else:
480 | flags = re.DOTALL
481 |
482 | if op:
483 | if m.group('value').startswith(('"', "'")):
484 | value = css_unescape(m.group('value')[1:-1], True)
485 | else:
486 | value = css_unescape(m.group('value'))
487 |
488 | if not op:
489 | # Attribute name
490 | pattern = None
491 | elif op.startswith('^'):
492 | # Value start with
493 | pattern = re.compile(r'^%s.*' % re.escape(value), flags)
494 | elif op.startswith('$'):
495 | # Value ends with
496 | pattern = re.compile(r'.*?%s$' % re.escape(value), flags)
497 | elif op.startswith('*'):
498 | # Value contains
499 | pattern = re.compile(r'.*?%s.*' % re.escape(value), flags)
500 | elif op.startswith('~'):
501 | # Value contains word within space separated list
502 | # `~=` should match nothing if it is empty or contains whitespace,
503 | # so if either of these cases is present, use `[^\s\S]` which cannot be matched.
504 | value = r'[^\s\S]' if not value or RE_WS.search(value) else re.escape(value)
505 | pattern = re.compile(r'.*?(?:(?<=^)|(?<=[ \t\r\n\f]))%s(?=(?:[ \t\r\n\f]|$)).*' % value, flags)
506 | elif op.startswith('|'):
507 | # Value starts with word in dash separated list
508 | pattern = re.compile(r'^%s(?:-.*)?$' % re.escape(value), flags)
509 | else:
510 | # Value matches
511 | pattern = re.compile(r'^%s$' % re.escape(value), flags)
512 | if op.startswith('!'):
513 | # Equivalent to `:not([attr=value])`
514 | inverse = True
515 | if is_type and pattern:
516 | pattern2 = re.compile(pattern.pattern)
517 |
518 | # Append the attribute selector
519 | sel_attr = ct.SelectorAttribute(attr, ns, pattern, pattern2)
520 | if inverse:
521 | # If we are using `!=`, we need to nest the pattern under a `:not()`.
522 | sub_sel = _Selector()
523 | sub_sel.attributes.append(sel_attr)
524 | not_list = ct.SelectorList([sub_sel.freeze()], True, False)
525 | sel.selectors.append(not_list)
526 | else:
527 | sel.attributes.append(sel_attr)
528 |
529 | has_selector = True
530 | return has_selector
531 |
532 | def parse_tag_pattern(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
533 | """Parse tag pattern from regex match."""
534 |
535 | prefix = css_unescape(m.group('tag_ns')[:-1]) if m.group('tag_ns') else None
536 | tag = css_unescape(m.group('tag_name'))
537 | sel.tag = ct.SelectorTag(tag, prefix)
538 | has_selector = True
539 | return has_selector
540 |
541 | def parse_pseudo_class_custom(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
542 | """
543 | Parse custom pseudo class alias.
544 |
545 | Compile custom selectors as we need them. When compiling a custom selector,
546 | set it to `None` in the dictionary so we can avoid an infinite loop.
547 | """
548 |
549 | pseudo = util.lower(css_unescape(m.group('name')))
550 | selector = self.custom.get(pseudo)
551 | if selector is None:
552 | raise SelectorSyntaxError(
553 | f"Undefined custom selector '{pseudo}' found at position {m.end(0)}",
554 | self.pattern,
555 | m.end(0)
556 | )
557 |
558 | if not isinstance(selector, ct.SelectorList):
559 | del self.custom[pseudo]
560 | selector = CSSParser(
561 | selector, custom=self.custom, flags=self.flags
562 | ).process_selectors(flags=FLG_PSEUDO)
563 | self.custom[pseudo] = selector
564 |
565 | sel.selectors.append(selector)
566 | has_selector = True
567 | return has_selector
568 |
569 | def parse_pseudo_class(
570 | self,
571 | sel: _Selector,
572 | m: Match[str],
573 | has_selector: bool,
574 | iselector: Iterator[tuple[str, Match[str]]],
575 | is_html: bool
576 | ) -> tuple[bool, bool]:
577 | """Parse pseudo class."""
578 |
579 | complex_pseudo = False
580 | pseudo = util.lower(css_unescape(m.group('name')))
581 | if m.group('open'):
582 | complex_pseudo = True
583 | if complex_pseudo and pseudo in PSEUDO_COMPLEX:
584 | has_selector = self.parse_pseudo_open(sel, pseudo, has_selector, iselector, m.end(0))
585 | elif not complex_pseudo and pseudo in PSEUDO_SIMPLE:
586 | if pseudo == ':root':
587 | sel.flags |= ct.SEL_ROOT
588 | elif pseudo == ':defined':
589 | sel.flags |= ct.SEL_DEFINED
590 | is_html = True
591 | elif pseudo == ':scope':
592 | sel.flags |= ct.SEL_SCOPE
593 | elif pseudo == ':empty':
594 | sel.flags |= ct.SEL_EMPTY
595 | elif pseudo in (':link', ':any-link'):
596 | sel.selectors.append(CSS_LINK)
597 | elif pseudo == ':checked':
598 | sel.selectors.append(CSS_CHECKED)
599 | elif pseudo == ':default':
600 | sel.selectors.append(CSS_DEFAULT)
601 | elif pseudo == ':indeterminate':
602 | sel.selectors.append(CSS_INDETERMINATE)
603 | elif pseudo == ":disabled":
604 | sel.selectors.append(CSS_DISABLED)
605 | elif pseudo == ":enabled":
606 | sel.selectors.append(CSS_ENABLED)
607 | elif pseudo == ":required":
608 | sel.selectors.append(CSS_REQUIRED)
609 | elif pseudo == ":optional":
610 | sel.selectors.append(CSS_OPTIONAL)
611 | elif pseudo == ":read-only":
612 | sel.selectors.append(CSS_READ_ONLY)
613 | elif pseudo == ":read-write":
614 | sel.selectors.append(CSS_READ_WRITE)
615 | elif pseudo == ":in-range":
616 | sel.selectors.append(CSS_IN_RANGE)
617 | elif pseudo == ":out-of-range":
618 | sel.selectors.append(CSS_OUT_OF_RANGE)
619 | elif pseudo == ":placeholder-shown":
620 | sel.selectors.append(CSS_PLACEHOLDER_SHOWN)
621 | elif pseudo == ':first-child':
622 | sel.nth.append(ct.SelectorNth(1, False, 0, False, False, ct.SelectorList()))
623 | elif pseudo == ':last-child':
624 | sel.nth.append(ct.SelectorNth(1, False, 0, False, True, ct.SelectorList()))
625 | elif pseudo == ':first-of-type':
626 | sel.nth.append(ct.SelectorNth(1, False, 0, True, False, ct.SelectorList()))
627 | elif pseudo == ':last-of-type':
628 | sel.nth.append(ct.SelectorNth(1, False, 0, True, True, ct.SelectorList()))
629 | elif pseudo == ':only-child':
630 | sel.nth.extend(
631 | [
632 | ct.SelectorNth(1, False, 0, False, False, ct.SelectorList()),
633 | ct.SelectorNth(1, False, 0, False, True, ct.SelectorList())
634 | ]
635 | )
636 | elif pseudo == ':only-of-type':
637 | sel.nth.extend(
638 | [
639 | ct.SelectorNth(1, False, 0, True, False, ct.SelectorList()),
640 | ct.SelectorNth(1, False, 0, True, True, ct.SelectorList())
641 | ]
642 | )
643 | has_selector = True
644 | elif complex_pseudo and pseudo in PSEUDO_COMPLEX_NO_MATCH:
645 | self.parse_selectors(iselector, m.end(0), FLG_PSEUDO | FLG_OPEN)
646 | sel.no_match = True
647 | has_selector = True
648 | elif not complex_pseudo and pseudo in PSEUDO_SIMPLE_NO_MATCH:
649 | sel.no_match = True
650 | has_selector = True
651 | elif pseudo in PSEUDO_SUPPORTED:
652 | raise SelectorSyntaxError(
653 | f"Invalid syntax for pseudo class '{pseudo}'",
654 | self.pattern,
655 | m.start(0)
656 | )
657 | else:
658 | raise SelectorSyntaxError(
659 | f"'{pseudo}' was detected as a pseudo-class and is either unsupported or invalid. "
660 | "If the syntax was not intended to be recognized as a pseudo-class, please escape the colon.",
661 | self.pattern,
662 | m.start(0)
663 | )
664 |
665 | return has_selector, is_html
666 |
667 | def parse_pseudo_nth(
668 | self,
669 | sel: _Selector,
670 | m: Match[str],
671 | has_selector: bool,
672 | iselector: Iterator[tuple[str, Match[str]]]
673 | ) -> bool:
674 | """Parse `nth` pseudo."""
675 |
676 | mdict = m.groupdict()
677 | if mdict.get('pseudo_nth_child'):
678 | postfix = '_child'
679 | else:
680 | postfix = '_type'
681 | mdict['name'] = util.lower(css_unescape(mdict['name']))
682 | content = util.lower(mdict.get('nth' + postfix))
683 | if content == 'even':
684 | # 2n
685 | s1 = 2
686 | s2 = 0
687 | var = True
688 | elif content == 'odd':
689 | # 2n+1
690 | s1 = 2
691 | s2 = 1
692 | var = True
693 | else:
694 | nth_parts = cast(Match[str], RE_NTH.match(content))
695 | _s1 = '-' if nth_parts.group('s1') and nth_parts.group('s1') == '-' else ''
696 | a = nth_parts.group('a')
697 | var = a.endswith('n')
698 | if a.startswith('n'):
699 | _s1 += '1'
700 | elif var:
701 | _s1 += a[:-1]
702 | else:
703 | _s1 += a
704 | _s2 = '-' if nth_parts.group('s2') and nth_parts.group('s2') == '-' else ''
705 | if nth_parts.group('b'):
706 | _s2 += nth_parts.group('b')
707 | else:
708 | _s2 = '0'
709 | s1 = int(_s1, 10)
710 | s2 = int(_s2, 10)
711 |
712 | pseudo_sel = mdict['name']
713 | if postfix == '_child':
714 | if m.group('of'):
715 | # Parse the rest of `of S`.
716 | nth_sel = self.parse_selectors(iselector, m.end(0), FLG_PSEUDO | FLG_OPEN)
717 | else:
718 | # Use default `*|*` for `of S`.
719 | nth_sel = CSS_NTH_OF_S_DEFAULT
720 | if pseudo_sel == ':nth-child':
721 | sel.nth.append(ct.SelectorNth(s1, var, s2, False, False, nth_sel))
722 | elif pseudo_sel == ':nth-last-child':
723 | sel.nth.append(ct.SelectorNth(s1, var, s2, False, True, nth_sel))
724 | else:
725 | if pseudo_sel == ':nth-of-type':
726 | sel.nth.append(ct.SelectorNth(s1, var, s2, True, False, ct.SelectorList()))
727 | elif pseudo_sel == ':nth-last-of-type':
728 | sel.nth.append(ct.SelectorNth(s1, var, s2, True, True, ct.SelectorList()))
729 | has_selector = True
730 | return has_selector
731 |
732 | def parse_pseudo_open(
733 | self,
734 | sel: _Selector,
735 | name: str,
736 | has_selector: bool,
737 | iselector: Iterator[tuple[str, Match[str]]],
738 | index: int
739 | ) -> bool:
740 | """Parse pseudo with opening bracket."""
741 |
742 | flags = FLG_PSEUDO | FLG_OPEN
743 | if name == ':not':
744 | flags |= FLG_NOT
745 | elif name == ':has':
746 | flags |= FLG_RELATIVE
747 | elif name in (':where', ':is'):
748 | flags |= FLG_FORGIVE
749 |
750 | sel.selectors.append(self.parse_selectors(iselector, index, flags))
751 | has_selector = True
752 |
753 | return has_selector
754 |
755 | def parse_has_combinator(
756 | self,
757 | sel: _Selector,
758 | m: Match[str],
759 | has_selector: bool,
760 | selectors: list[_Selector],
761 | rel_type: str,
762 | index: int
763 | ) -> tuple[bool, _Selector, str]:
764 | """Parse combinator tokens."""
765 |
766 | combinator = m.group('relation').strip()
767 | if not combinator:
768 | combinator = WS_COMBINATOR
769 | if combinator == COMMA_COMBINATOR:
770 | sel.rel_type = rel_type
771 | selectors[-1].relations.append(sel)
772 | rel_type = ":" + WS_COMBINATOR
773 | selectors.append(_Selector())
774 | else:
775 | if has_selector:
776 | # End the current selector and associate the leading combinator with this selector.
777 | sel.rel_type = rel_type
778 | selectors[-1].relations.append(sel)
779 | elif rel_type[1:] != WS_COMBINATOR:
780 | # It's impossible to have two whitespace combinators after each other as the patterns
781 | # will gobble up trailing whitespace. It is also impossible to have a whitespace
782 | # combinator after any other kind for the same reason. But we could have
783 | # multiple non-whitespace combinators. So if the current combinator is not a whitespace,
784 | # then we've hit the multiple combinator case, so we should fail.
785 | raise SelectorSyntaxError(
786 | f'The multiple combinators at position {index}',
787 | self.pattern,
788 | index
789 | )
790 |
791 | # Set the leading combinator for the next selector.
792 | rel_type = ':' + combinator
793 |
794 | sel = _Selector()
795 | has_selector = False
796 | return has_selector, sel, rel_type
797 |
798 | def parse_combinator(
799 | self,
800 | sel: _Selector,
801 | m: Match[str],
802 | has_selector: bool,
803 | selectors: list[_Selector],
804 | relations: list[_Selector],
805 | is_pseudo: bool,
806 | is_forgive: bool,
807 | index: int
808 | ) -> tuple[bool, _Selector]:
809 | """Parse combinator tokens."""
810 |
811 | combinator = m.group('relation').strip()
812 | if not combinator:
813 | combinator = WS_COMBINATOR
814 | if not has_selector:
815 | if not is_forgive or combinator != COMMA_COMBINATOR:
816 | raise SelectorSyntaxError(
817 | f"The combinator '{combinator}' at position {index}, must have a selector before it",
818 | self.pattern,
819 | index
820 | )
821 |
822 | # If we are in a forgiving pseudo class, just make the selector a "no match"
823 | if combinator == COMMA_COMBINATOR:
824 | sel.no_match = True
825 | del relations[:]
826 | selectors.append(sel)
827 | else:
828 | if combinator == COMMA_COMBINATOR:
829 | if not sel.tag and not is_pseudo:
830 | # Implied `*`
831 | sel.tag = ct.SelectorTag('*', None)
832 | sel.relations.extend(relations)
833 | selectors.append(sel)
834 | del relations[:]
835 | else:
836 | sel.relations.extend(relations)
837 | sel.rel_type = combinator
838 | del relations[:]
839 | relations.append(sel)
840 |
841 | sel = _Selector()
842 | has_selector = False
843 |
844 | return has_selector, sel
845 |
846 | def parse_class_id(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
847 | """Parse HTML classes and ids."""
848 |
849 | selector = m.group(0)
850 | if selector.startswith('.'):
851 | sel.classes.append(css_unescape(selector[1:]))
852 | else:
853 | sel.ids.append(css_unescape(selector[1:]))
854 | has_selector = True
855 | return has_selector
856 |
857 | def parse_pseudo_contains(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
858 | """Parse contains."""
859 |
860 | pseudo = util.lower(css_unescape(m.group('name')))
861 | if pseudo == ":contains":
862 | warnings.warn( # noqa: B028
863 | "The pseudo class ':contains' is deprecated, ':-soup-contains' should be used moving forward.",
864 | FutureWarning
865 | )
866 | contains_own = pseudo == ":-soup-contains-own"
867 | values = css_unescape(m.group('values'))
868 | patterns = []
869 | for token in RE_VALUES.finditer(values):
870 | if token.group('split'):
871 | continue
872 | value = token.group('value')
873 | if value.startswith(("'", '"')):
874 | value = css_unescape(value[1:-1], True)
875 | else:
876 | value = css_unescape(value)
877 | patterns.append(value)
878 | sel.contains.append(ct.SelectorContains(patterns, contains_own))
879 | has_selector = True
880 | return has_selector
881 |
882 | def parse_pseudo_lang(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
883 | """Parse pseudo language."""
884 |
885 | values = m.group('values')
886 | patterns = []
887 | for token in RE_VALUES.finditer(values):
888 | if token.group('split'):
889 | continue
890 | value = token.group('value')
891 | if value.startswith(('"', "'")):
892 | value = css_unescape(value[1:-1], True)
893 | else:
894 | value = css_unescape(value)
895 |
896 | patterns.append(value)
897 |
898 | sel.lang.append(ct.SelectorLang(patterns))
899 | has_selector = True
900 |
901 | return has_selector
902 |
903 | def parse_pseudo_dir(self, sel: _Selector, m: Match[str], has_selector: bool) -> bool:
904 | """Parse pseudo direction."""
905 |
906 | value = ct.SEL_DIR_LTR if util.lower(m.group('dir')) == 'ltr' else ct.SEL_DIR_RTL
907 | sel.flags |= value
908 | has_selector = True
909 | return has_selector
910 |
911 | def parse_selectors(
912 | self,
913 | iselector: Iterator[tuple[str, Match[str]]],
914 | index: int = 0,
915 | flags: int = 0
916 | ) -> ct.SelectorList:
917 | """Parse selectors."""
918 |
919 | # Initialize important variables
920 | sel = _Selector()
921 | selectors = []
922 | has_selector = False
923 | closed = False
924 | relations = [] # type: list[_Selector]
925 | rel_type = ":" + WS_COMBINATOR
926 |
927 | # Setup various flags
928 | is_open = bool(flags & FLG_OPEN)
929 | is_pseudo = bool(flags & FLG_PSEUDO)
930 | is_relative = bool(flags & FLG_RELATIVE)
931 | is_not = bool(flags & FLG_NOT)
932 | is_html = bool(flags & FLG_HTML)
933 | is_default = bool(flags & FLG_DEFAULT)
934 | is_indeterminate = bool(flags & FLG_INDETERMINATE)
935 | is_in_range = bool(flags & FLG_IN_RANGE)
936 | is_out_of_range = bool(flags & FLG_OUT_OF_RANGE)
937 | is_placeholder_shown = bool(flags & FLG_PLACEHOLDER_SHOWN)
938 | is_forgive = bool(flags & FLG_FORGIVE)
939 |
940 | # Print out useful debug stuff
941 | if self.debug: # pragma: no cover
942 | if is_pseudo:
943 | print(' is_pseudo: True')
944 | if is_open:
945 | print(' is_open: True')
946 | if is_relative:
947 | print(' is_relative: True')
948 | if is_not:
949 | print(' is_not: True')
950 | if is_html:
951 | print(' is_html: True')
952 | if is_default:
953 | print(' is_default: True')
954 | if is_indeterminate:
955 | print(' is_indeterminate: True')
956 | if is_in_range:
957 | print(' is_in_range: True')
958 | if is_out_of_range:
959 | print(' is_out_of_range: True')
960 | if is_placeholder_shown:
961 | print(' is_placeholder_shown: True')
962 | if is_forgive:
963 | print(' is_forgive: True')
964 |
965 | # The algorithm for relative selectors require an initial selector in the selector list
966 | if is_relative:
967 | selectors.append(_Selector())
968 |
969 | try:
970 | while True:
971 | key, m = next(iselector)
972 |
973 | # Handle parts
974 | if key == "at_rule":
975 | raise NotImplementedError(f"At-rules found at position {m.start(0)}")
976 | elif key == "amp":
977 | sel.flags |= ct.SEL_SCOPE
978 | has_selector = True
979 | elif key == 'pseudo_class_custom':
980 | has_selector = self.parse_pseudo_class_custom(sel, m, has_selector)
981 | elif key == 'pseudo_class':
982 | has_selector, is_html = self.parse_pseudo_class(sel, m, has_selector, iselector, is_html)
983 | elif key == 'pseudo_element':
984 | raise NotImplementedError(f"Pseudo-element found at position {m.start(0)}")
985 | elif key == 'pseudo_contains':
986 | has_selector = self.parse_pseudo_contains(sel, m, has_selector)
987 | elif key in ('pseudo_nth_type', 'pseudo_nth_child'):
988 | has_selector = self.parse_pseudo_nth(sel, m, has_selector, iselector)
989 | elif key == 'pseudo_lang':
990 | has_selector = self.parse_pseudo_lang(sel, m, has_selector)
991 | elif key == 'pseudo_dir':
992 | has_selector = self.parse_pseudo_dir(sel, m, has_selector)
993 | # Currently only supports HTML
994 | is_html = True
995 | elif key == 'pseudo_close':
996 | if not has_selector:
997 | if not is_forgive:
998 | raise SelectorSyntaxError(
999 | f"Expected a selector at position {m.start(0)}",
1000 | self.pattern,
1001 | m.start(0)
1002 | )
1003 | sel.no_match = True
1004 | if is_open:
1005 | closed = True
1006 | break
1007 | else:
1008 | raise SelectorSyntaxError(
1009 | f"Unmatched pseudo-class close at position {m.start(0)}",
1010 | self.pattern,
1011 | m.start(0)
1012 | )
1013 | elif key == 'combine':
1014 | if is_relative:
1015 | has_selector, sel, rel_type = self.parse_has_combinator(
1016 | sel, m, has_selector, selectors, rel_type, index
1017 | )
1018 | else:
1019 | has_selector, sel = self.parse_combinator(
1020 | sel, m, has_selector, selectors, relations, is_pseudo, is_forgive, index
1021 | )
1022 | elif key == 'attribute':
1023 | has_selector = self.parse_attribute_selector(sel, m, has_selector)
1024 | elif key == 'tag':
1025 | if has_selector:
1026 | raise SelectorSyntaxError(
1027 | f"Tag name found at position {m.start(0)} instead of at the start",
1028 | self.pattern,
1029 | m.start(0)
1030 | )
1031 | has_selector = self.parse_tag_pattern(sel, m, has_selector)
1032 | elif key in ('class', 'id'):
1033 | has_selector = self.parse_class_id(sel, m, has_selector)
1034 |
1035 | index = m.end(0)
1036 | except StopIteration:
1037 | pass
1038 |
1039 | # Handle selectors that are not closed
1040 | if is_open and not closed:
1041 | raise SelectorSyntaxError(
1042 | f"Unclosed pseudo-class at position {index}",
1043 | self.pattern,
1044 | index
1045 | )
1046 |
1047 | # Cleanup completed selector piece
1048 | if has_selector:
1049 | if not sel.tag and not is_pseudo:
1050 | # Implied `*`
1051 | sel.tag = ct.SelectorTag('*', None)
1052 | if is_relative:
1053 | sel.rel_type = rel_type
1054 | selectors[-1].relations.append(sel)
1055 | else:
1056 | sel.relations.extend(relations)
1057 | del relations[:]
1058 | selectors.append(sel)
1059 |
1060 | # Forgive empty slots in pseudo-classes that have lists (and are forgiving)
1061 | elif is_forgive and (not selectors or not relations):
1062 | # Handle normal pseudo-classes with empty slots like `:is()` etc.
1063 | sel.no_match = True
1064 | del relations[:]
1065 | selectors.append(sel)
1066 | has_selector = True
1067 |
1068 | if not has_selector:
1069 | # We will always need to finish a selector when `:has()` is used as it leads with combining.
1070 | # May apply to others as well.
1071 | raise SelectorSyntaxError(
1072 | f'Expected a selector at position {index}',
1073 | self.pattern,
1074 | index
1075 | )
1076 |
1077 | # Some patterns require additional logic, such as default. We try to make these the
1078 | # last pattern, and append the appropriate flag to that selector which communicates
1079 | # to the matcher what additional logic is required.
1080 | if is_default:
1081 | selectors[-1].flags = ct.SEL_DEFAULT
1082 | if is_indeterminate:
1083 | selectors[-1].flags = ct.SEL_INDETERMINATE
1084 | if is_in_range:
1085 | selectors[-1].flags = ct.SEL_IN_RANGE
1086 | if is_out_of_range:
1087 | selectors[-1].flags = ct.SEL_OUT_OF_RANGE
1088 | if is_placeholder_shown:
1089 | selectors[-1].flags = ct.SEL_PLACEHOLDER_SHOWN
1090 |
1091 | # Return selector list
1092 | return ct.SelectorList([s.freeze() for s in selectors], is_not, is_html)
1093 |
1094 | def selector_iter(self, pattern: str) -> Iterator[tuple[str, Match[str]]]:
1095 | """Iterate selector tokens."""
1096 |
1097 | # Ignore whitespace and comments at start and end of pattern
1098 | m = RE_WS_BEGIN.search(pattern)
1099 | index = m.end(0) if m else 0
1100 | m = RE_WS_END.search(pattern)
1101 | end = (m.start(0) - 1) if m else (len(pattern) - 1)
1102 |
1103 | if self.debug: # pragma: no cover
1104 | print(f'## PARSING: {pattern!r}')
1105 | while index <= end:
1106 | m = None
1107 | for v in self.css_tokens:
1108 | m = v.match(pattern, index, self.flags)
1109 | if m:
1110 | name = v.get_name()
1111 | if self.debug: # pragma: no cover
1112 | print(f"TOKEN: '{name}' --> {m.group(0)!r} at position {m.start(0)}")
1113 | index = m.end(0)
1114 | yield name, m
1115 | break
1116 | if m is None:
1117 | c = pattern[index]
1118 | # If the character represents the start of one of the known selector types,
1119 | # throw an exception mentioning that the known selector type is in error;
1120 | # otherwise, report the invalid character.
1121 | if c == '[':
1122 | msg = f"Malformed attribute selector at position {index}"
1123 | elif c == '.':
1124 | msg = f"Malformed class selector at position {index}"
1125 | elif c == '#':
1126 | msg = f"Malformed id selector at position {index}"
1127 | elif c == ':':
1128 | msg = f"Malformed pseudo-class selector at position {index}"
1129 | else:
1130 | msg = f"Invalid character {c!r} position {index}"
1131 | raise SelectorSyntaxError(msg, self.pattern, index)
1132 | if self.debug: # pragma: no cover
1133 | print('## END PARSING')
1134 |
1135 | def process_selectors(self, index: int = 0, flags: int = 0) -> ct.SelectorList:
1136 | """Process selectors."""
1137 |
1138 | return self.parse_selectors(self.selector_iter(self.pattern), index, flags)
1139 |
1140 |
1141 | # Precompile CSS selector lists for pseudo-classes (additional logic may be required beyond the pattern)
1142 | # A few patterns are order dependent as they use patterns previous compiled.
1143 |
1144 | # CSS pattern for `:link` and `:any-link`
1145 | CSS_LINK = CSSParser(
1146 | 'html|*:is(a, area)[href]'
1147 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1148 | # CSS pattern for `:checked`
1149 | CSS_CHECKED = CSSParser(
1150 | '''
1151 | html|*:is(input[type=checkbox], input[type=radio])[checked], html|option[selected]
1152 | '''
1153 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1154 | # CSS pattern for `:default` (must compile CSS_CHECKED first)
1155 | CSS_DEFAULT = CSSParser(
1156 | '''
1157 | :checked,
1158 |
1159 | /*
1160 | This pattern must be at the end.
1161 | Special logic is applied to the last selector.
1162 | */
1163 | html|form html|*:is(button, input)[type="submit"]
1164 | '''
1165 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML | FLG_DEFAULT)
1166 | # CSS pattern for `:indeterminate`
1167 | CSS_INDETERMINATE = CSSParser(
1168 | '''
1169 | html|input[type="checkbox"][indeterminate],
1170 | html|input[type="radio"]:is(:not([name]), [name=""]):not([checked]),
1171 | html|progress:not([value]),
1172 |
1173 | /*
1174 | This pattern must be at the end.
1175 | Special logic is applied to the last selector.
1176 | */
1177 | html|input[type="radio"][name]:not([name='']):not([checked])
1178 | '''
1179 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML | FLG_INDETERMINATE)
1180 | # CSS pattern for `:disabled`
1181 | CSS_DISABLED = CSSParser(
1182 | '''
1183 | html|*:is(input:not([type=hidden]), button, select, textarea, fieldset, optgroup, option, fieldset)[disabled],
1184 | html|optgroup[disabled] > html|option,
1185 | html|fieldset[disabled] > html|*:is(input:not([type=hidden]), button, select, textarea, fieldset),
1186 | html|fieldset[disabled] >
1187 | html|*:not(legend:nth-of-type(1)) html|*:is(input:not([type=hidden]), button, select, textarea, fieldset)
1188 | '''
1189 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1190 | # CSS pattern for `:enabled`
1191 | CSS_ENABLED = CSSParser(
1192 | '''
1193 | html|*:is(input:not([type=hidden]), button, select, textarea, fieldset, optgroup, option, fieldset):not(:disabled)
1194 | '''
1195 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1196 | # CSS pattern for `:required`
1197 | CSS_REQUIRED = CSSParser(
1198 | 'html|*:is(input, textarea, select)[required]'
1199 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1200 | # CSS pattern for `:optional`
1201 | CSS_OPTIONAL = CSSParser(
1202 | 'html|*:is(input, textarea, select):not([required])'
1203 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1204 | # CSS pattern for `:placeholder-shown`
1205 | CSS_PLACEHOLDER_SHOWN = CSSParser(
1206 | '''
1207 | html|input:is(
1208 | :not([type]),
1209 | [type=""],
1210 | [type=text],
1211 | [type=search],
1212 | [type=url],
1213 | [type=tel],
1214 | [type=email],
1215 | [type=password],
1216 | [type=number]
1217 | )[placeholder]:not([placeholder='']):is(:not([value]), [value=""]),
1218 | html|textarea[placeholder]:not([placeholder=''])
1219 | '''
1220 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML | FLG_PLACEHOLDER_SHOWN)
1221 | # CSS pattern default for `:nth-child` "of S" feature
1222 | CSS_NTH_OF_S_DEFAULT = CSSParser(
1223 | '*|*'
1224 | ).process_selectors(flags=FLG_PSEUDO)
1225 | # CSS pattern for `:read-write` (CSS_DISABLED must be compiled first)
1226 | CSS_READ_WRITE = CSSParser(
1227 | '''
1228 | html|*:is(
1229 | textarea,
1230 | input:is(
1231 | :not([type]),
1232 | [type=""],
1233 | [type=text],
1234 | [type=search],
1235 | [type=url],
1236 | [type=tel],
1237 | [type=email],
1238 | [type=number],
1239 | [type=password],
1240 | [type=date],
1241 | [type=datetime-local],
1242 | [type=month],
1243 | [type=time],
1244 | [type=week]
1245 | )
1246 | ):not([readonly], :disabled),
1247 | html|*:is([contenteditable=""], [contenteditable="true" i])
1248 | '''
1249 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1250 | # CSS pattern for `:read-only`
1251 | CSS_READ_ONLY = CSSParser(
1252 | '''
1253 | html|*:not(:read-write)
1254 | '''
1255 | ).process_selectors(flags=FLG_PSEUDO | FLG_HTML)
1256 | # CSS pattern for `:in-range`
1257 | CSS_IN_RANGE = CSSParser(
1258 | '''
1259 | html|input:is(
1260 | [type="date"],
1261 | [type="month"],
1262 | [type="week"],
1263 | [type="time"],
1264 | [type="datetime-local"],
1265 | [type="number"],
1266 | [type="range"]
1267 | ):is(
1268 | [min],
1269 | [max]
1270 | )
1271 | '''
1272 | ).process_selectors(flags=FLG_PSEUDO | FLG_IN_RANGE | FLG_HTML)
1273 | # CSS pattern for `:out-of-range`
1274 | CSS_OUT_OF_RANGE = CSSParser(
1275 | '''
1276 | html|input:is(
1277 | [type="date"],
1278 | [type="month"],
1279 | [type="week"],
1280 | [type="time"],
1281 | [type="datetime-local"],
1282 | [type="number"],
1283 | [type="range"]
1284 | ):is(
1285 | [min],
1286 | [max]
1287 | )
1288 | '''
1289 | ).process_selectors(flags=FLG_PSEUDO | FLG_OUT_OF_RANGE | FLG_HTML)
1290 |
```