This is page 75 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/blinker/base.py:
--------------------------------------------------------------------------------
```python
1 | from __future__ import annotations
2 |
3 | import collections.abc as c
4 | import typing as t
5 | import warnings
6 | import weakref
7 | from collections import defaultdict
8 | from contextlib import AbstractContextManager
9 | from contextlib import contextmanager
10 | from functools import cached_property
11 | from inspect import iscoroutinefunction
12 | from weakref import WeakValueDictionary
13 |
14 | from ._utilities import make_id
15 | from ._utilities import make_ref
16 | from ._utilities import Symbol
17 |
18 | if t.TYPE_CHECKING:
19 | F = t.TypeVar("F", bound=c.Callable[..., t.Any])
20 |
21 | ANY = Symbol("ANY")
22 | """Symbol for "any sender"."""
23 |
24 | ANY_ID = 0
25 |
26 |
27 | class Signal:
28 | """A notification emitter.
29 |
30 | :param doc: The docstring for the signal.
31 | """
32 |
33 | ANY = ANY
34 | """An alias for the :data:`~blinker.ANY` sender symbol."""
35 |
36 | set_class: type[set[t.Any]] = set
37 | """The set class to use for tracking connected receivers and senders.
38 | Python's ``set`` is unordered. If receivers must be dispatched in the order
39 | they were connected, an ordered set implementation can be used.
40 |
41 | .. versionadded:: 1.7
42 | """
43 |
44 | @cached_property
45 | def receiver_connected(self) -> Signal:
46 | """Emitted at the end of each :meth:`connect` call.
47 |
48 | The signal sender is the signal instance, and the :meth:`connect`
49 | arguments are passed through: ``receiver``, ``sender``, and ``weak``.
50 |
51 | .. versionadded:: 1.2
52 | """
53 | return Signal(doc="Emitted after a receiver connects.")
54 |
55 | @cached_property
56 | def receiver_disconnected(self) -> Signal:
57 | """Emitted at the end of each :meth:`disconnect` call.
58 |
59 | The sender is the signal instance, and the :meth:`disconnect` arguments
60 | are passed through: ``receiver`` and ``sender``.
61 |
62 | This signal is emitted **only** when :meth:`disconnect` is called
63 | explicitly. This signal cannot be emitted by an automatic disconnect
64 | when a weakly referenced receiver or sender goes out of scope, as the
65 | instance is no longer be available to be used as the sender for this
66 | signal.
67 |
68 | An alternative approach is available by subscribing to
69 | :attr:`receiver_connected` and setting up a custom weakref cleanup
70 | callback on weak receivers and senders.
71 |
72 | .. versionadded:: 1.2
73 | """
74 | return Signal(doc="Emitted after a receiver disconnects.")
75 |
76 | def __init__(self, doc: str | None = None) -> None:
77 | if doc:
78 | self.__doc__ = doc
79 |
80 | self.receivers: dict[
81 | t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any]
82 | ] = {}
83 | """The map of connected receivers. Useful to quickly check if any
84 | receivers are connected to the signal: ``if s.receivers:``. The
85 | structure and data is not part of the public API, but checking its
86 | boolean value is.
87 | """
88 |
89 | self.is_muted: bool = False
90 | self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
91 | self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class)
92 | self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {}
93 |
94 | def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F:
95 | """Connect ``receiver`` to be called when the signal is sent by
96 | ``sender``.
97 |
98 | :param receiver: The callable to call when :meth:`send` is called with
99 | the given ``sender``, passing ``sender`` as a positional argument
100 | along with any extra keyword arguments.
101 | :param sender: Any object or :data:`ANY`. ``receiver`` will only be
102 | called when :meth:`send` is called with this sender. If ``ANY``, the
103 | receiver will be called for any sender. A receiver may be connected
104 | to multiple senders by calling :meth:`connect` multiple times.
105 | :param weak: Track the receiver with a :mod:`weakref`. The receiver will
106 | be automatically disconnected when it is garbage collected. When
107 | connecting a receiver defined within a function, set to ``False``,
108 | otherwise it will be disconnected when the function scope ends.
109 | """
110 | receiver_id = make_id(receiver)
111 | sender_id = ANY_ID if sender is ANY else make_id(sender)
112 |
113 | if weak:
114 | self.receivers[receiver_id] = make_ref(
115 | receiver, self._make_cleanup_receiver(receiver_id)
116 | )
117 | else:
118 | self.receivers[receiver_id] = receiver
119 |
120 | self._by_sender[sender_id].add(receiver_id)
121 | self._by_receiver[receiver_id].add(sender_id)
122 |
123 | if sender is not ANY and sender_id not in self._weak_senders:
124 | # store a cleanup for weakref-able senders
125 | try:
126 | self._weak_senders[sender_id] = make_ref(
127 | sender, self._make_cleanup_sender(sender_id)
128 | )
129 | except TypeError:
130 | pass
131 |
132 | if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers:
133 | try:
134 | self.receiver_connected.send(
135 | self, receiver=receiver, sender=sender, weak=weak
136 | )
137 | except TypeError:
138 | # TODO no explanation or test for this
139 | self.disconnect(receiver, sender)
140 | raise
141 |
142 | if _receiver_connected.receivers and self is not _receiver_connected:
143 | try:
144 | _receiver_connected.send(
145 | self, receiver_arg=receiver, sender_arg=sender, weak_arg=weak
146 | )
147 | except TypeError:
148 | self.disconnect(receiver, sender)
149 | raise
150 |
151 | return receiver
152 |
153 | def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]:
154 | """Connect the decorated function to be called when the signal is sent
155 | by ``sender``.
156 |
157 | The decorated function will be called when :meth:`send` is called with
158 | the given ``sender``, passing ``sender`` as a positional argument along
159 | with any extra keyword arguments.
160 |
161 | :param sender: Any object or :data:`ANY`. ``receiver`` will only be
162 | called when :meth:`send` is called with this sender. If ``ANY``, the
163 | receiver will be called for any sender. A receiver may be connected
164 | to multiple senders by calling :meth:`connect` multiple times.
165 | :param weak: Track the receiver with a :mod:`weakref`. The receiver will
166 | be automatically disconnected when it is garbage collected. When
167 | connecting a receiver defined within a function, set to ``False``,
168 | otherwise it will be disconnected when the function scope ends.=
169 |
170 | .. versionadded:: 1.1
171 | """
172 |
173 | def decorator(fn: F) -> F:
174 | self.connect(fn, sender, weak)
175 | return fn
176 |
177 | return decorator
178 |
179 | @contextmanager
180 | def connected_to(
181 | self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY
182 | ) -> c.Generator[None, None, None]:
183 | """A context manager that temporarily connects ``receiver`` to the
184 | signal while a ``with`` block executes. When the block exits, the
185 | receiver is disconnected. Useful for tests.
186 |
187 | :param receiver: The callable to call when :meth:`send` is called with
188 | the given ``sender``, passing ``sender`` as a positional argument
189 | along with any extra keyword arguments.
190 | :param sender: Any object or :data:`ANY`. ``receiver`` will only be
191 | called when :meth:`send` is called with this sender. If ``ANY``, the
192 | receiver will be called for any sender.
193 |
194 | .. versionadded:: 1.1
195 | """
196 | self.connect(receiver, sender=sender, weak=False)
197 |
198 | try:
199 | yield None
200 | finally:
201 | self.disconnect(receiver)
202 |
203 | @contextmanager
204 | def muted(self) -> c.Generator[None, None, None]:
205 | """A context manager that temporarily disables the signal. No receivers
206 | will be called if the signal is sent, until the ``with`` block exits.
207 | Useful for tests.
208 | """
209 | self.is_muted = True
210 |
211 | try:
212 | yield None
213 | finally:
214 | self.is_muted = False
215 |
216 | def temporarily_connected_to(
217 | self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY
218 | ) -> AbstractContextManager[None]:
219 | """Deprecated alias for :meth:`connected_to`.
220 |
221 | .. deprecated:: 1.1
222 | Renamed to ``connected_to``. Will be removed in Blinker 1.9.
223 |
224 | .. versionadded:: 0.9
225 | """
226 | warnings.warn(
227 | "'temporarily_connected_to' is renamed to 'connected_to'. The old name is"
228 | " deprecated and will be removed in Blinker 1.9.",
229 | DeprecationWarning,
230 | stacklevel=2,
231 | )
232 | return self.connected_to(receiver, sender)
233 |
234 | def send(
235 | self,
236 | sender: t.Any | None = None,
237 | /,
238 | *,
239 | _async_wrapper: c.Callable[
240 | [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any]
241 | ]
242 | | None = None,
243 | **kwargs: t.Any,
244 | ) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
245 | """Call all receivers that are connected to the given ``sender``
246 | or :data:`ANY`. Each receiver is called with ``sender`` as a positional
247 | argument along with any extra keyword arguments. Return a list of
248 | ``(receiver, return value)`` tuples.
249 |
250 | The order receivers are called is undefined, but can be influenced by
251 | setting :attr:`set_class`.
252 |
253 | If a receiver raises an exception, that exception will propagate up.
254 | This makes debugging straightforward, with an assumption that correctly
255 | implemented receivers will not raise.
256 |
257 | :param sender: Call receivers connected to this sender, in addition to
258 | those connected to :data:`ANY`.
259 | :param _async_wrapper: Will be called on any receivers that are async
260 | coroutines to turn them into sync callables. For example, could run
261 | the receiver with an event loop.
262 | :param kwargs: Extra keyword arguments to pass to each receiver.
263 |
264 | .. versionchanged:: 1.7
265 | Added the ``_async_wrapper`` argument.
266 | """
267 | if self.is_muted:
268 | return []
269 |
270 | results = []
271 |
272 | for receiver in self.receivers_for(sender):
273 | if iscoroutinefunction(receiver):
274 | if _async_wrapper is None:
275 | raise RuntimeError("Cannot send to a coroutine function.")
276 |
277 | result = _async_wrapper(receiver)(sender, **kwargs)
278 | else:
279 | result = receiver(sender, **kwargs)
280 |
281 | results.append((receiver, result))
282 |
283 | return results
284 |
285 | async def send_async(
286 | self,
287 | sender: t.Any | None = None,
288 | /,
289 | *,
290 | _sync_wrapper: c.Callable[
291 | [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]
292 | ]
293 | | None = None,
294 | **kwargs: t.Any,
295 | ) -> list[tuple[c.Callable[..., t.Any], t.Any]]:
296 | """Await all receivers that are connected to the given ``sender``
297 | or :data:`ANY`. Each receiver is called with ``sender`` as a positional
298 | argument along with any extra keyword arguments. Return a list of
299 | ``(receiver, return value)`` tuples.
300 |
301 | The order receivers are called is undefined, but can be influenced by
302 | setting :attr:`set_class`.
303 |
304 | If a receiver raises an exception, that exception will propagate up.
305 | This makes debugging straightforward, with an assumption that correctly
306 | implemented receivers will not raise.
307 |
308 | :param sender: Call receivers connected to this sender, in addition to
309 | those connected to :data:`ANY`.
310 | :param _sync_wrapper: Will be called on any receivers that are sync
311 | callables to turn them into async coroutines. For example,
312 | could call the receiver in a thread.
313 | :param kwargs: Extra keyword arguments to pass to each receiver.
314 |
315 | .. versionadded:: 1.7
316 | """
317 | if self.is_muted:
318 | return []
319 |
320 | results = []
321 |
322 | for receiver in self.receivers_for(sender):
323 | if not iscoroutinefunction(receiver):
324 | if _sync_wrapper is None:
325 | raise RuntimeError("Cannot send to a non-coroutine function.")
326 |
327 | result = await _sync_wrapper(receiver)(sender, **kwargs)
328 | else:
329 | result = await receiver(sender, **kwargs)
330 |
331 | results.append((receiver, result))
332 |
333 | return results
334 |
335 | def has_receivers_for(self, sender: t.Any) -> bool:
336 | """Check if there is at least one receiver that will be called with the
337 | given ``sender``. A receiver connected to :data:`ANY` will always be
338 | called, regardless of sender. Does not check if weakly referenced
339 | receivers are still live. See :meth:`receivers_for` for a stronger
340 | search.
341 |
342 | :param sender: Check for receivers connected to this sender, in addition
343 | to those connected to :data:`ANY`.
344 | """
345 | if not self.receivers:
346 | return False
347 |
348 | if self._by_sender[ANY_ID]:
349 | return True
350 |
351 | if sender is ANY:
352 | return False
353 |
354 | return make_id(sender) in self._by_sender
355 |
356 | def receivers_for(
357 | self, sender: t.Any
358 | ) -> c.Generator[c.Callable[..., t.Any], None, None]:
359 | """Yield each receiver to be called for ``sender``, in addition to those
360 | to be called for :data:`ANY`. Weakly referenced receivers that are not
361 | live will be disconnected and skipped.
362 |
363 | :param sender: Yield receivers connected to this sender, in addition
364 | to those connected to :data:`ANY`.
365 | """
366 | # TODO: test receivers_for(ANY)
367 | if not self.receivers:
368 | return
369 |
370 | sender_id = make_id(sender)
371 |
372 | if sender_id in self._by_sender:
373 | ids = self._by_sender[ANY_ID] | self._by_sender[sender_id]
374 | else:
375 | ids = self._by_sender[ANY_ID].copy()
376 |
377 | for receiver_id in ids:
378 | receiver = self.receivers.get(receiver_id)
379 |
380 | if receiver is None:
381 | continue
382 |
383 | if isinstance(receiver, weakref.ref):
384 | strong = receiver()
385 |
386 | if strong is None:
387 | self._disconnect(receiver_id, ANY_ID)
388 | continue
389 |
390 | yield strong
391 | else:
392 | yield receiver
393 |
394 | def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None:
395 | """Disconnect ``receiver`` from being called when the signal is sent by
396 | ``sender``.
397 |
398 | :param receiver: A connected receiver callable.
399 | :param sender: Disconnect from only this sender. By default, disconnect
400 | from all senders.
401 | """
402 | sender_id: c.Hashable
403 |
404 | if sender is ANY:
405 | sender_id = ANY_ID
406 | else:
407 | sender_id = make_id(sender)
408 |
409 | receiver_id = make_id(receiver)
410 | self._disconnect(receiver_id, sender_id)
411 |
412 | if (
413 | "receiver_disconnected" in self.__dict__
414 | and self.receiver_disconnected.receivers
415 | ):
416 | self.receiver_disconnected.send(self, receiver=receiver, sender=sender)
417 |
418 | def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None:
419 | if sender_id == ANY_ID:
420 | if self._by_receiver.pop(receiver_id, None) is not None:
421 | for bucket in self._by_sender.values():
422 | bucket.discard(receiver_id)
423 |
424 | self.receivers.pop(receiver_id, None)
425 | else:
426 | self._by_sender[sender_id].discard(receiver_id)
427 | self._by_receiver[receiver_id].discard(sender_id)
428 |
429 | def _make_cleanup_receiver(
430 | self, receiver_id: c.Hashable
431 | ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]:
432 | """Create a callback function to disconnect a weakly referenced
433 | receiver when it is garbage collected.
434 | """
435 |
436 | def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None:
437 | self._disconnect(receiver_id, ANY_ID)
438 |
439 | return cleanup
440 |
441 | def _make_cleanup_sender(
442 | self, sender_id: c.Hashable
443 | ) -> c.Callable[[weakref.ref[t.Any]], None]:
444 | """Create a callback function to disconnect all receivers for a weakly
445 | referenced sender when it is garbage collected.
446 | """
447 | assert sender_id != ANY_ID
448 |
449 | def cleanup(ref: weakref.ref[t.Any]) -> None:
450 | self._weak_senders.pop(sender_id, None)
451 |
452 | for receiver_id in self._by_sender.pop(sender_id, ()):
453 | self._by_receiver[receiver_id].discard(sender_id)
454 |
455 | return cleanup
456 |
457 | def _cleanup_bookkeeping(self) -> None:
458 | """Prune unused sender/receiver bookkeeping. Not threadsafe.
459 |
460 | Connecting & disconnecting leaves behind a small amount of bookkeeping
461 | data. Typical workloads using Blinker, for example in most web apps,
462 | Flask, CLI scripts, etc., are not adversely affected by this
463 | bookkeeping.
464 |
465 | With a long-running process performing dynamic signal routing with high
466 | volume, e.g. connecting to function closures, senders are all unique
467 | object instances. Doing all of this over and over may cause memory usage
468 | to grow due to extraneous bookkeeping. (An empty ``set`` for each stale
469 | sender/receiver pair.)
470 |
471 | This method will prune that bookkeeping away, with the caveat that such
472 | pruning is not threadsafe. The risk is that cleanup of a fully
473 | disconnected receiver/sender pair occurs while another thread is
474 | connecting that same pair. If you are in the highly dynamic, unique
475 | receiver/sender situation that has lead you to this method, that failure
476 | mode is perhaps not a big deal for you.
477 | """
478 | for mapping in (self._by_sender, self._by_receiver):
479 | for ident, bucket in list(mapping.items()):
480 | if not bucket:
481 | mapping.pop(ident, None)
482 |
483 | def _clear_state(self) -> None:
484 | """Disconnect all receivers and senders. Useful for tests."""
485 | self._weak_senders.clear()
486 | self.receivers.clear()
487 | self._by_sender.clear()
488 | self._by_receiver.clear()
489 |
490 |
491 | _receiver_connected = Signal(
492 | """\
493 | Sent by a :class:`Signal` after a receiver connects.
494 |
495 | :argument: the Signal that was connected to
496 | :keyword receiver_arg: the connected receiver
497 | :keyword sender_arg: the sender to connect to
498 | :keyword weak_arg: true if the connection to receiver_arg is a weak reference
499 |
500 | .. deprecated:: 1.2
501 | Individual signals have their own :attr:`~Signal.receiver_connected` and
502 | :attr:`~Signal.receiver_disconnected` signals with a slightly simplified
503 | call signature. This global signal will be removed in Blinker 1.9.
504 | """
505 | )
506 |
507 |
508 | class NamedSignal(Signal):
509 | """A named generic notification emitter. The name is not used by the signal
510 | itself, but matches the key in the :class:`Namespace` that it belongs to.
511 |
512 | :param name: The name of the signal within the namespace.
513 | :param doc: The docstring for the signal.
514 | """
515 |
516 | def __init__(self, name: str, doc: str | None = None) -> None:
517 | super().__init__(doc)
518 |
519 | #: The name of this signal.
520 | self.name: str = name
521 |
522 | def __repr__(self) -> str:
523 | base = super().__repr__()
524 | return f"{base[:-1]}; {self.name!r}>" # noqa: E702
525 |
526 |
527 | if t.TYPE_CHECKING:
528 |
529 | class PNamespaceSignal(t.Protocol):
530 | def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ...
531 |
532 | # Python < 3.9
533 | _NamespaceBase = dict[str, NamedSignal] # type: ignore[misc]
534 | else:
535 | _NamespaceBase = dict
536 |
537 |
538 | class Namespace(_NamespaceBase):
539 | """A dict mapping names to signals."""
540 |
541 | def signal(self, name: str, doc: str | None = None) -> NamedSignal:
542 | """Return the :class:`NamedSignal` for the given ``name``, creating it
543 | if required. Repeated calls with the same name return the same signal.
544 |
545 | :param name: The name of the signal.
546 | :param doc: The docstring of the signal.
547 | """
548 | if name not in self:
549 | self[name] = NamedSignal(name, doc)
550 |
551 | return self[name]
552 |
553 |
554 | class _WeakNamespace(WeakValueDictionary): # type: ignore[type-arg]
555 | """A weak mapping of names to signals.
556 |
557 | Automatically cleans up unused signals when the last reference goes out
558 | of scope. This namespace implementation provides similar behavior to Blinker
559 | <= 1.2.
560 |
561 | .. deprecated:: 1.3
562 | Will be removed in Blinker 1.9.
563 |
564 | .. versionadded:: 1.3
565 | """
566 |
567 | def __init__(self) -> None:
568 | warnings.warn(
569 | "'WeakNamespace' is deprecated and will be removed in Blinker 1.9."
570 | " Use 'Namespace' instead.",
571 | DeprecationWarning,
572 | stacklevel=2,
573 | )
574 | super().__init__()
575 |
576 | def signal(self, name: str, doc: str | None = None) -> NamedSignal:
577 | """Return the :class:`NamedSignal` for the given ``name``, creating it
578 | if required. Repeated calls with the same name return the same signal.
579 |
580 | :param name: The name of the signal.
581 | :param doc: The docstring of the signal.
582 | """
583 | if name not in self:
584 | self[name] = NamedSignal(name, doc)
585 |
586 | return self[name] # type: ignore[no-any-return]
587 |
588 |
589 | default_namespace: Namespace = Namespace()
590 | """A default :class:`Namespace` for creating named signals. :func:`signal`
591 | creates a :class:`NamedSignal` in this namespace.
592 | """
593 |
594 | signal: PNamespaceSignal = default_namespace.signal
595 | """Return a :class:`NamedSignal` in :data:`default_namespace` with the given
596 | ``name``, creating it if required. Repeated calls with the same name return the
597 | same signal.
598 | """
599 |
600 |
601 | def __getattr__(name: str) -> t.Any:
602 | if name == "receiver_connected":
603 | warnings.warn(
604 | "The global 'receiver_connected' signal is deprecated and will be"
605 | " removed in Blinker 1.9. Use 'Signal.receiver_connected' and"
606 | " 'Signal.receiver_disconnected' instead.",
607 | DeprecationWarning,
608 | stacklevel=2,
609 | )
610 | return _receiver_connected
611 |
612 | if name == "WeakNamespace":
613 | warnings.warn(
614 | "'WeakNamespace' is deprecated and will be removed in Blinker 1.9."
615 | " Use 'Namespace' instead.",
616 | DeprecationWarning,
617 | stacklevel=2,
618 | )
619 | return _WeakNamespace
620 |
621 | raise AttributeError(name)
622 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/_parser.py:
--------------------------------------------------------------------------------
```python
1 | # SPDX-License-Identifier: MIT
2 | # SPDX-FileCopyrightText: 2021 Taneli Hukkinen
3 | # Licensed to PSF under a Contributor Agreement.
4 |
5 | from __future__ import annotations
6 |
7 | from collections.abc import Iterable
8 | import string
9 | from types import MappingProxyType
10 | from typing import Any, BinaryIO, NamedTuple
11 |
12 | from ._re import (
13 | RE_DATETIME,
14 | RE_LOCALTIME,
15 | RE_NUMBER,
16 | match_to_datetime,
17 | match_to_localtime,
18 | match_to_number,
19 | )
20 | from ._types import Key, ParseFloat, Pos
21 |
22 | ASCII_CTRL = frozenset(chr(i) for i in range(32)) | frozenset(chr(127))
23 |
24 | # Neither of these sets include quotation mark or backslash. They are
25 | # currently handled as separate cases in the parser functions.
26 | ILLEGAL_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t")
27 | ILLEGAL_MULTILINE_BASIC_STR_CHARS = ASCII_CTRL - frozenset("\t\n")
28 |
29 | ILLEGAL_LITERAL_STR_CHARS = ILLEGAL_BASIC_STR_CHARS
30 | ILLEGAL_MULTILINE_LITERAL_STR_CHARS = ILLEGAL_MULTILINE_BASIC_STR_CHARS
31 |
32 | ILLEGAL_COMMENT_CHARS = ILLEGAL_BASIC_STR_CHARS
33 |
34 | TOML_WS = frozenset(" \t")
35 | TOML_WS_AND_NEWLINE = TOML_WS | frozenset("\n")
36 | BARE_KEY_CHARS = frozenset(string.ascii_letters + string.digits + "-_")
37 | KEY_INITIAL_CHARS = BARE_KEY_CHARS | frozenset("\"'")
38 | HEXDIGIT_CHARS = frozenset(string.hexdigits)
39 |
40 | BASIC_STR_ESCAPE_REPLACEMENTS = MappingProxyType(
41 | {
42 | "\\b": "\u0008", # backspace
43 | "\\t": "\u0009", # tab
44 | "\\n": "\u000A", # linefeed
45 | "\\f": "\u000C", # form feed
46 | "\\r": "\u000D", # carriage return
47 | '\\"': "\u0022", # quote
48 | "\\\\": "\u005C", # backslash
49 | }
50 | )
51 |
52 |
53 | class TOMLDecodeError(ValueError):
54 | """An error raised if a document is not valid TOML."""
55 |
56 |
57 | def load(__fp: BinaryIO, *, parse_float: ParseFloat = float) -> dict[str, Any]:
58 | """Parse TOML from a binary file object."""
59 | b = __fp.read()
60 | try:
61 | s = b.decode()
62 | except AttributeError:
63 | raise TypeError(
64 | "File must be opened in binary mode, e.g. use `open('foo.toml', 'rb')`"
65 | ) from None
66 | return loads(s, parse_float=parse_float)
67 |
68 |
69 | def loads(__s: str, *, parse_float: ParseFloat = float) -> dict[str, Any]: # noqa: C901
70 | """Parse TOML from a string."""
71 |
72 | # The spec allows converting "\r\n" to "\n", even in string
73 | # literals. Let's do so to simplify parsing.
74 | src = __s.replace("\r\n", "\n")
75 | pos = 0
76 | out = Output(NestedDict(), Flags())
77 | header: Key = ()
78 | parse_float = make_safe_parse_float(parse_float)
79 |
80 | # Parse one statement at a time
81 | # (typically means one line in TOML source)
82 | while True:
83 | # 1. Skip line leading whitespace
84 | pos = skip_chars(src, pos, TOML_WS)
85 |
86 | # 2. Parse rules. Expect one of the following:
87 | # - end of file
88 | # - end of line
89 | # - comment
90 | # - key/value pair
91 | # - append dict to list (and move to its namespace)
92 | # - create dict (and move to its namespace)
93 | # Skip trailing whitespace when applicable.
94 | try:
95 | char = src[pos]
96 | except IndexError:
97 | break
98 | if char == "\n":
99 | pos += 1
100 | continue
101 | if char in KEY_INITIAL_CHARS:
102 | pos = key_value_rule(src, pos, out, header, parse_float)
103 | pos = skip_chars(src, pos, TOML_WS)
104 | elif char == "[":
105 | try:
106 | second_char: str | None = src[pos + 1]
107 | except IndexError:
108 | second_char = None
109 | out.flags.finalize_pending()
110 | if second_char == "[":
111 | pos, header = create_list_rule(src, pos, out)
112 | else:
113 | pos, header = create_dict_rule(src, pos, out)
114 | pos = skip_chars(src, pos, TOML_WS)
115 | elif char != "#":
116 | raise suffixed_err(src, pos, "Invalid statement")
117 |
118 | # 3. Skip comment
119 | pos = skip_comment(src, pos)
120 |
121 | # 4. Expect end of line or end of file
122 | try:
123 | char = src[pos]
124 | except IndexError:
125 | break
126 | if char != "\n":
127 | raise suffixed_err(
128 | src, pos, "Expected newline or end of document after a statement"
129 | )
130 | pos += 1
131 |
132 | return out.data.dict
133 |
134 |
135 | class Flags:
136 | """Flags that map to parsed keys/namespaces."""
137 |
138 | # Marks an immutable namespace (inline array or inline table).
139 | FROZEN = 0
140 | # Marks a nest that has been explicitly created and can no longer
141 | # be opened using the "[table]" syntax.
142 | EXPLICIT_NEST = 1
143 |
144 | def __init__(self) -> None:
145 | self._flags: dict[str, dict] = {}
146 | self._pending_flags: set[tuple[Key, int]] = set()
147 |
148 | def add_pending(self, key: Key, flag: int) -> None:
149 | self._pending_flags.add((key, flag))
150 |
151 | def finalize_pending(self) -> None:
152 | for key, flag in self._pending_flags:
153 | self.set(key, flag, recursive=False)
154 | self._pending_flags.clear()
155 |
156 | def unset_all(self, key: Key) -> None:
157 | cont = self._flags
158 | for k in key[:-1]:
159 | if k not in cont:
160 | return
161 | cont = cont[k]["nested"]
162 | cont.pop(key[-1], None)
163 |
164 | def set(self, key: Key, flag: int, *, recursive: bool) -> None: # noqa: A003
165 | cont = self._flags
166 | key_parent, key_stem = key[:-1], key[-1]
167 | for k in key_parent:
168 | if k not in cont:
169 | cont[k] = {"flags": set(), "recursive_flags": set(), "nested": {}}
170 | cont = cont[k]["nested"]
171 | if key_stem not in cont:
172 | cont[key_stem] = {"flags": set(), "recursive_flags": set(), "nested": {}}
173 | cont[key_stem]["recursive_flags" if recursive else "flags"].add(flag)
174 |
175 | def is_(self, key: Key, flag: int) -> bool:
176 | if not key:
177 | return False # document root has no flags
178 | cont = self._flags
179 | for k in key[:-1]:
180 | if k not in cont:
181 | return False
182 | inner_cont = cont[k]
183 | if flag in inner_cont["recursive_flags"]:
184 | return True
185 | cont = inner_cont["nested"]
186 | key_stem = key[-1]
187 | if key_stem in cont:
188 | cont = cont[key_stem]
189 | return flag in cont["flags"] or flag in cont["recursive_flags"]
190 | return False
191 |
192 |
193 | class NestedDict:
194 | def __init__(self) -> None:
195 | # The parsed content of the TOML document
196 | self.dict: dict[str, Any] = {}
197 |
198 | def get_or_create_nest(
199 | self,
200 | key: Key,
201 | *,
202 | access_lists: bool = True,
203 | ) -> dict:
204 | cont: Any = self.dict
205 | for k in key:
206 | if k not in cont:
207 | cont[k] = {}
208 | cont = cont[k]
209 | if access_lists and isinstance(cont, list):
210 | cont = cont[-1]
211 | if not isinstance(cont, dict):
212 | raise KeyError("There is no nest behind this key")
213 | return cont
214 |
215 | def append_nest_to_list(self, key: Key) -> None:
216 | cont = self.get_or_create_nest(key[:-1])
217 | last_key = key[-1]
218 | if last_key in cont:
219 | list_ = cont[last_key]
220 | if not isinstance(list_, list):
221 | raise KeyError("An object other than list found behind this key")
222 | list_.append({})
223 | else:
224 | cont[last_key] = [{}]
225 |
226 |
227 | class Output(NamedTuple):
228 | data: NestedDict
229 | flags: Flags
230 |
231 |
232 | def skip_chars(src: str, pos: Pos, chars: Iterable[str]) -> Pos:
233 | try:
234 | while src[pos] in chars:
235 | pos += 1
236 | except IndexError:
237 | pass
238 | return pos
239 |
240 |
241 | def skip_until(
242 | src: str,
243 | pos: Pos,
244 | expect: str,
245 | *,
246 | error_on: frozenset[str],
247 | error_on_eof: bool,
248 | ) -> Pos:
249 | try:
250 | new_pos = src.index(expect, pos)
251 | except ValueError:
252 | new_pos = len(src)
253 | if error_on_eof:
254 | raise suffixed_err(src, new_pos, f"Expected {expect!r}") from None
255 |
256 | if not error_on.isdisjoint(src[pos:new_pos]):
257 | while src[pos] not in error_on:
258 | pos += 1
259 | raise suffixed_err(src, pos, f"Found invalid character {src[pos]!r}")
260 | return new_pos
261 |
262 |
263 | def skip_comment(src: str, pos: Pos) -> Pos:
264 | try:
265 | char: str | None = src[pos]
266 | except IndexError:
267 | char = None
268 | if char == "#":
269 | return skip_until(
270 | src, pos + 1, "\n", error_on=ILLEGAL_COMMENT_CHARS, error_on_eof=False
271 | )
272 | return pos
273 |
274 |
275 | def skip_comments_and_array_ws(src: str, pos: Pos) -> Pos:
276 | while True:
277 | pos_before_skip = pos
278 | pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
279 | pos = skip_comment(src, pos)
280 | if pos == pos_before_skip:
281 | return pos
282 |
283 |
284 | def create_dict_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]:
285 | pos += 1 # Skip "["
286 | pos = skip_chars(src, pos, TOML_WS)
287 | pos, key = parse_key(src, pos)
288 |
289 | if out.flags.is_(key, Flags.EXPLICIT_NEST) or out.flags.is_(key, Flags.FROZEN):
290 | raise suffixed_err(src, pos, f"Cannot declare {key} twice")
291 | out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
292 | try:
293 | out.data.get_or_create_nest(key)
294 | except KeyError:
295 | raise suffixed_err(src, pos, "Cannot overwrite a value") from None
296 |
297 | if not src.startswith("]", pos):
298 | raise suffixed_err(src, pos, "Expected ']' at the end of a table declaration")
299 | return pos + 1, key
300 |
301 |
302 | def create_list_rule(src: str, pos: Pos, out: Output) -> tuple[Pos, Key]:
303 | pos += 2 # Skip "[["
304 | pos = skip_chars(src, pos, TOML_WS)
305 | pos, key = parse_key(src, pos)
306 |
307 | if out.flags.is_(key, Flags.FROZEN):
308 | raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}")
309 | # Free the namespace now that it points to another empty list item...
310 | out.flags.unset_all(key)
311 | # ...but this key precisely is still prohibited from table declaration
312 | out.flags.set(key, Flags.EXPLICIT_NEST, recursive=False)
313 | try:
314 | out.data.append_nest_to_list(key)
315 | except KeyError:
316 | raise suffixed_err(src, pos, "Cannot overwrite a value") from None
317 |
318 | if not src.startswith("]]", pos):
319 | raise suffixed_err(src, pos, "Expected ']]' at the end of an array declaration")
320 | return pos + 2, key
321 |
322 |
323 | def key_value_rule(
324 | src: str, pos: Pos, out: Output, header: Key, parse_float: ParseFloat
325 | ) -> Pos:
326 | pos, key, value = parse_key_value_pair(src, pos, parse_float)
327 | key_parent, key_stem = key[:-1], key[-1]
328 | abs_key_parent = header + key_parent
329 |
330 | relative_path_cont_keys = (header + key[:i] for i in range(1, len(key)))
331 | for cont_key in relative_path_cont_keys:
332 | # Check that dotted key syntax does not redefine an existing table
333 | if out.flags.is_(cont_key, Flags.EXPLICIT_NEST):
334 | raise suffixed_err(src, pos, f"Cannot redefine namespace {cont_key}")
335 | # Containers in the relative path can't be opened with the table syntax or
336 | # dotted key/value syntax in following table sections.
337 | out.flags.add_pending(cont_key, Flags.EXPLICIT_NEST)
338 |
339 | if out.flags.is_(abs_key_parent, Flags.FROZEN):
340 | raise suffixed_err(
341 | src, pos, f"Cannot mutate immutable namespace {abs_key_parent}"
342 | )
343 |
344 | try:
345 | nest = out.data.get_or_create_nest(abs_key_parent)
346 | except KeyError:
347 | raise suffixed_err(src, pos, "Cannot overwrite a value") from None
348 | if key_stem in nest:
349 | raise suffixed_err(src, pos, "Cannot overwrite a value")
350 | # Mark inline table and array namespaces recursively immutable
351 | if isinstance(value, (dict, list)):
352 | out.flags.set(header + key, Flags.FROZEN, recursive=True)
353 | nest[key_stem] = value
354 | return pos
355 |
356 |
357 | def parse_key_value_pair(
358 | src: str, pos: Pos, parse_float: ParseFloat
359 | ) -> tuple[Pos, Key, Any]:
360 | pos, key = parse_key(src, pos)
361 | try:
362 | char: str | None = src[pos]
363 | except IndexError:
364 | char = None
365 | if char != "=":
366 | raise suffixed_err(src, pos, "Expected '=' after a key in a key/value pair")
367 | pos += 1
368 | pos = skip_chars(src, pos, TOML_WS)
369 | pos, value = parse_value(src, pos, parse_float)
370 | return pos, key, value
371 |
372 |
373 | def parse_key(src: str, pos: Pos) -> tuple[Pos, Key]:
374 | pos, key_part = parse_key_part(src, pos)
375 | key: Key = (key_part,)
376 | pos = skip_chars(src, pos, TOML_WS)
377 | while True:
378 | try:
379 | char: str | None = src[pos]
380 | except IndexError:
381 | char = None
382 | if char != ".":
383 | return pos, key
384 | pos += 1
385 | pos = skip_chars(src, pos, TOML_WS)
386 | pos, key_part = parse_key_part(src, pos)
387 | key += (key_part,)
388 | pos = skip_chars(src, pos, TOML_WS)
389 |
390 |
391 | def parse_key_part(src: str, pos: Pos) -> tuple[Pos, str]:
392 | try:
393 | char: str | None = src[pos]
394 | except IndexError:
395 | char = None
396 | if char in BARE_KEY_CHARS:
397 | start_pos = pos
398 | pos = skip_chars(src, pos, BARE_KEY_CHARS)
399 | return pos, src[start_pos:pos]
400 | if char == "'":
401 | return parse_literal_str(src, pos)
402 | if char == '"':
403 | return parse_one_line_basic_str(src, pos)
404 | raise suffixed_err(src, pos, "Invalid initial character for a key part")
405 |
406 |
407 | def parse_one_line_basic_str(src: str, pos: Pos) -> tuple[Pos, str]:
408 | pos += 1
409 | return parse_basic_str(src, pos, multiline=False)
410 |
411 |
412 | def parse_array(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, list]:
413 | pos += 1
414 | array: list = []
415 |
416 | pos = skip_comments_and_array_ws(src, pos)
417 | if src.startswith("]", pos):
418 | return pos + 1, array
419 | while True:
420 | pos, val = parse_value(src, pos, parse_float)
421 | array.append(val)
422 | pos = skip_comments_and_array_ws(src, pos)
423 |
424 | c = src[pos : pos + 1]
425 | if c == "]":
426 | return pos + 1, array
427 | if c != ",":
428 | raise suffixed_err(src, pos, "Unclosed array")
429 | pos += 1
430 |
431 | pos = skip_comments_and_array_ws(src, pos)
432 | if src.startswith("]", pos):
433 | return pos + 1, array
434 |
435 |
436 | def parse_inline_table(src: str, pos: Pos, parse_float: ParseFloat) -> tuple[Pos, dict]:
437 | pos += 1
438 | nested_dict = NestedDict()
439 | flags = Flags()
440 |
441 | pos = skip_chars(src, pos, TOML_WS)
442 | if src.startswith("}", pos):
443 | return pos + 1, nested_dict.dict
444 | while True:
445 | pos, key, value = parse_key_value_pair(src, pos, parse_float)
446 | key_parent, key_stem = key[:-1], key[-1]
447 | if flags.is_(key, Flags.FROZEN):
448 | raise suffixed_err(src, pos, f"Cannot mutate immutable namespace {key}")
449 | try:
450 | nest = nested_dict.get_or_create_nest(key_parent, access_lists=False)
451 | except KeyError:
452 | raise suffixed_err(src, pos, "Cannot overwrite a value") from None
453 | if key_stem in nest:
454 | raise suffixed_err(src, pos, f"Duplicate inline table key {key_stem!r}")
455 | nest[key_stem] = value
456 | pos = skip_chars(src, pos, TOML_WS)
457 | c = src[pos : pos + 1]
458 | if c == "}":
459 | return pos + 1, nested_dict.dict
460 | if c != ",":
461 | raise suffixed_err(src, pos, "Unclosed inline table")
462 | if isinstance(value, (dict, list)):
463 | flags.set(key, Flags.FROZEN, recursive=True)
464 | pos += 1
465 | pos = skip_chars(src, pos, TOML_WS)
466 |
467 |
468 | def parse_basic_str_escape(
469 | src: str, pos: Pos, *, multiline: bool = False
470 | ) -> tuple[Pos, str]:
471 | escape_id = src[pos : pos + 2]
472 | pos += 2
473 | if multiline and escape_id in {"\\ ", "\\\t", "\\\n"}:
474 | # Skip whitespace until next non-whitespace character or end of
475 | # the doc. Error if non-whitespace is found before newline.
476 | if escape_id != "\\\n":
477 | pos = skip_chars(src, pos, TOML_WS)
478 | try:
479 | char = src[pos]
480 | except IndexError:
481 | return pos, ""
482 | if char != "\n":
483 | raise suffixed_err(src, pos, "Unescaped '\\' in a string")
484 | pos += 1
485 | pos = skip_chars(src, pos, TOML_WS_AND_NEWLINE)
486 | return pos, ""
487 | if escape_id == "\\u":
488 | return parse_hex_char(src, pos, 4)
489 | if escape_id == "\\U":
490 | return parse_hex_char(src, pos, 8)
491 | try:
492 | return pos, BASIC_STR_ESCAPE_REPLACEMENTS[escape_id]
493 | except KeyError:
494 | raise suffixed_err(src, pos, "Unescaped '\\' in a string") from None
495 |
496 |
497 | def parse_basic_str_escape_multiline(src: str, pos: Pos) -> tuple[Pos, str]:
498 | return parse_basic_str_escape(src, pos, multiline=True)
499 |
500 |
501 | def parse_hex_char(src: str, pos: Pos, hex_len: int) -> tuple[Pos, str]:
502 | hex_str = src[pos : pos + hex_len]
503 | if len(hex_str) != hex_len or not HEXDIGIT_CHARS.issuperset(hex_str):
504 | raise suffixed_err(src, pos, "Invalid hex value")
505 | pos += hex_len
506 | hex_int = int(hex_str, 16)
507 | if not is_unicode_scalar_value(hex_int):
508 | raise suffixed_err(src, pos, "Escaped character is not a Unicode scalar value")
509 | return pos, chr(hex_int)
510 |
511 |
512 | def parse_literal_str(src: str, pos: Pos) -> tuple[Pos, str]:
513 | pos += 1 # Skip starting apostrophe
514 | start_pos = pos
515 | pos = skip_until(
516 | src, pos, "'", error_on=ILLEGAL_LITERAL_STR_CHARS, error_on_eof=True
517 | )
518 | return pos + 1, src[start_pos:pos] # Skip ending apostrophe
519 |
520 |
521 | def parse_multiline_str(src: str, pos: Pos, *, literal: bool) -> tuple[Pos, str]:
522 | pos += 3
523 | if src.startswith("\n", pos):
524 | pos += 1
525 |
526 | if literal:
527 | delim = "'"
528 | end_pos = skip_until(
529 | src,
530 | pos,
531 | "'''",
532 | error_on=ILLEGAL_MULTILINE_LITERAL_STR_CHARS,
533 | error_on_eof=True,
534 | )
535 | result = src[pos:end_pos]
536 | pos = end_pos + 3
537 | else:
538 | delim = '"'
539 | pos, result = parse_basic_str(src, pos, multiline=True)
540 |
541 | # Add at maximum two extra apostrophes/quotes if the end sequence
542 | # is 4 or 5 chars long instead of just 3.
543 | if not src.startswith(delim, pos):
544 | return pos, result
545 | pos += 1
546 | if not src.startswith(delim, pos):
547 | return pos, result + delim
548 | pos += 1
549 | return pos, result + (delim * 2)
550 |
551 |
552 | def parse_basic_str(src: str, pos: Pos, *, multiline: bool) -> tuple[Pos, str]:
553 | if multiline:
554 | error_on = ILLEGAL_MULTILINE_BASIC_STR_CHARS
555 | parse_escapes = parse_basic_str_escape_multiline
556 | else:
557 | error_on = ILLEGAL_BASIC_STR_CHARS
558 | parse_escapes = parse_basic_str_escape
559 | result = ""
560 | start_pos = pos
561 | while True:
562 | try:
563 | char = src[pos]
564 | except IndexError:
565 | raise suffixed_err(src, pos, "Unterminated string") from None
566 | if char == '"':
567 | if not multiline:
568 | return pos + 1, result + src[start_pos:pos]
569 | if src.startswith('"""', pos):
570 | return pos + 3, result + src[start_pos:pos]
571 | pos += 1
572 | continue
573 | if char == "\\":
574 | result += src[start_pos:pos]
575 | pos, parsed_escape = parse_escapes(src, pos)
576 | result += parsed_escape
577 | start_pos = pos
578 | continue
579 | if char in error_on:
580 | raise suffixed_err(src, pos, f"Illegal character {char!r}")
581 | pos += 1
582 |
583 |
584 | def parse_value( # noqa: C901
585 | src: str, pos: Pos, parse_float: ParseFloat
586 | ) -> tuple[Pos, Any]:
587 | try:
588 | char: str | None = src[pos]
589 | except IndexError:
590 | char = None
591 |
592 | # IMPORTANT: order conditions based on speed of checking and likelihood
593 |
594 | # Basic strings
595 | if char == '"':
596 | if src.startswith('"""', pos):
597 | return parse_multiline_str(src, pos, literal=False)
598 | return parse_one_line_basic_str(src, pos)
599 |
600 | # Literal strings
601 | if char == "'":
602 | if src.startswith("'''", pos):
603 | return parse_multiline_str(src, pos, literal=True)
604 | return parse_literal_str(src, pos)
605 |
606 | # Booleans
607 | if char == "t":
608 | if src.startswith("true", pos):
609 | return pos + 4, True
610 | if char == "f":
611 | if src.startswith("false", pos):
612 | return pos + 5, False
613 |
614 | # Arrays
615 | if char == "[":
616 | return parse_array(src, pos, parse_float)
617 |
618 | # Inline tables
619 | if char == "{":
620 | return parse_inline_table(src, pos, parse_float)
621 |
622 | # Dates and times
623 | datetime_match = RE_DATETIME.match(src, pos)
624 | if datetime_match:
625 | try:
626 | datetime_obj = match_to_datetime(datetime_match)
627 | except ValueError as e:
628 | raise suffixed_err(src, pos, "Invalid date or datetime") from e
629 | return datetime_match.end(), datetime_obj
630 | localtime_match = RE_LOCALTIME.match(src, pos)
631 | if localtime_match:
632 | return localtime_match.end(), match_to_localtime(localtime_match)
633 |
634 | # Integers and "normal" floats.
635 | # The regex will greedily match any type starting with a decimal
636 | # char, so needs to be located after handling of dates and times.
637 | number_match = RE_NUMBER.match(src, pos)
638 | if number_match:
639 | return number_match.end(), match_to_number(number_match, parse_float)
640 |
641 | # Special floats
642 | first_three = src[pos : pos + 3]
643 | if first_three in {"inf", "nan"}:
644 | return pos + 3, parse_float(first_three)
645 | first_four = src[pos : pos + 4]
646 | if first_four in {"-inf", "+inf", "-nan", "+nan"}:
647 | return pos + 4, parse_float(first_four)
648 |
649 | raise suffixed_err(src, pos, "Invalid value")
650 |
651 |
652 | def suffixed_err(src: str, pos: Pos, msg: str) -> TOMLDecodeError:
653 | """Return a `TOMLDecodeError` where error message is suffixed with
654 | coordinates in source."""
655 |
656 | def coord_repr(src: str, pos: Pos) -> str:
657 | if pos >= len(src):
658 | return "end of document"
659 | line = src.count("\n", 0, pos) + 1
660 | if line == 1:
661 | column = pos + 1
662 | else:
663 | column = pos - src.rindex("\n", 0, pos)
664 | return f"line {line}, column {column}"
665 |
666 | return TOMLDecodeError(f"{msg} (at {coord_repr(src, pos)})")
667 |
668 |
669 | def is_unicode_scalar_value(codepoint: int) -> bool:
670 | return (0 <= codepoint <= 55295) or (57344 <= codepoint <= 1114111)
671 |
672 |
673 | def make_safe_parse_float(parse_float: ParseFloat) -> ParseFloat:
674 | """A decorator to make `parse_float` safe.
675 |
676 | `parse_float` must not return dicts or lists, because these types
677 | would be mixed with parsed TOML tables and arrays, thus confusing
678 | the parser. The returned decorated callable raises `ValueError`
679 | instead of returning illegal types.
680 | """
681 | # The default `float` callable never returns illegal types. Optimize it.
682 | if parse_float is float: # type: ignore[comparison-overlap]
683 | return float
684 |
685 | def safe_parse_float(float_str: str) -> Any:
686 | float_value = parse_float(float_str)
687 | if isinstance(float_value, (dict, list)):
688 | raise ValueError("parse_float must not return dicts or lists")
689 | return float_value
690 |
691 | return safe_parse_float
692 |
```