This is page 63 of 168. Use http://codebase.md/romanshablio/mcp_server?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .DS_Store
├── .venv
│ ├── __pycache__
│ │ └── hello.cpython-312.pyc
│ ├── bin
│ │ ├── activate
│ │ ├── activate.csh
│ │ ├── activate.fish
│ │ ├── Activate.ps1
│ │ ├── flask
│ │ ├── normalizer
│ │ ├── pip
│ │ ├── pip3
│ │ ├── pip3.12
│ │ ├── python
│ │ ├── python3
│ │ └── python3.12
│ ├── hello.py
│ ├── lib
│ │ └── python3.12
│ │ └── site-packages
│ │ ├── beautifulsoup4-4.12.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ ├── AUTHORS
│ │ │ │ └── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── blinker
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _utilities.cpython-312.pyc
│ │ │ │ └── base.cpython-312.pyc
│ │ │ ├── _utilities.py
│ │ │ ├── base.py
│ │ │ └── py.typed
│ │ ├── blinker-1.8.2.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── bs4
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── css.cpython-312.pyc
│ │ │ │ ├── dammit.cpython-312.pyc
│ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ ├── element.cpython-312.pyc
│ │ │ │ └── formatter.cpython-312.pyc
│ │ │ ├── builder
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _html5lib.cpython-312.pyc
│ │ │ │ │ ├── _htmlparser.cpython-312.pyc
│ │ │ │ │ └── _lxml.cpython-312.pyc
│ │ │ │ ├── _html5lib.py
│ │ │ │ ├── _htmlparser.py
│ │ │ │ └── _lxml.py
│ │ │ ├── css.py
│ │ │ ├── dammit.py
│ │ │ ├── diagnose.py
│ │ │ ├── element.py
│ │ │ ├── formatter.py
│ │ │ └── tests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── test_builder_registry.cpython-312.pyc
│ │ │ │ ├── test_builder.cpython-312.pyc
│ │ │ │ ├── test_css.cpython-312.pyc
│ │ │ │ ├── test_dammit.cpython-312.pyc
│ │ │ │ ├── test_docs.cpython-312.pyc
│ │ │ │ ├── test_element.cpython-312.pyc
│ │ │ │ ├── test_formatter.cpython-312.pyc
│ │ │ │ ├── test_fuzz.cpython-312.pyc
│ │ │ │ ├── test_html5lib.cpython-312.pyc
│ │ │ │ ├── test_htmlparser.cpython-312.pyc
│ │ │ │ ├── test_lxml.cpython-312.pyc
│ │ │ │ ├── test_navigablestring.cpython-312.pyc
│ │ │ │ ├── test_pageelement.cpython-312.pyc
│ │ │ │ ├── test_soup.cpython-312.pyc
│ │ │ │ ├── test_tag.cpython-312.pyc
│ │ │ │ └── test_tree.cpython-312.pyc
│ │ │ ├── fuzz
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4670634698080256.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4818336571064320.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-4999465949331456.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5000587759190016.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5167584867909632.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5270998950477824.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5375146639360000.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5492400320282624.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5703933063462912.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5843991618256896.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-5984173902397440.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6124268085182464.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6241471367348224.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6306874195312640.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6450958476902400.testcase
│ │ │ │ ├── clusterfuzz-testcase-minimized-bs4_fuzzer-6600557255327744.testcase
│ │ │ │ ├── crash-0d306a50c8ed8bcd0785b67000fcd5dea1d33f08.testcase
│ │ │ │ └── crash-ffbdfa8a2b26f13537b68d3794b0478a4090ee4a.testcase
│ │ │ ├── test_builder_registry.py
│ │ │ ├── test_builder.py
│ │ │ ├── test_css.py
│ │ │ ├── test_dammit.py
│ │ │ ├── test_docs.py
│ │ │ ├── test_element.py
│ │ │ ├── test_formatter.py
│ │ │ ├── test_fuzz.py
│ │ │ ├── test_html5lib.py
│ │ │ ├── test_htmlparser.py
│ │ │ ├── test_lxml.py
│ │ │ ├── test_navigablestring.py
│ │ │ ├── test_pageelement.py
│ │ │ ├── test_soup.py
│ │ │ ├── test_tag.py
│ │ │ └── test_tree.py
│ │ ├── certifi
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── core.cpython-312.pyc
│ │ │ ├── cacert.pem
│ │ │ ├── core.py
│ │ │ └── py.typed
│ │ ├── certifi-2024.8.30.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── charset_normalizer
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── cd.cpython-312.pyc
│ │ │ │ ├── constant.cpython-312.pyc
│ │ │ │ ├── legacy.cpython-312.pyc
│ │ │ │ ├── md.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── version.cpython-312.pyc
│ │ │ ├── api.py
│ │ │ ├── cd.py
│ │ │ ├── cli
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __main__.py
│ │ │ │ └── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── __main__.cpython-312.pyc
│ │ │ ├── constant.py
│ │ │ ├── legacy.py
│ │ │ ├── md__mypyc.cpython-312-darwin.so
│ │ │ ├── md.cpython-312-darwin.so
│ │ │ ├── md.py
│ │ │ ├── models.py
│ │ │ ├── py.typed
│ │ │ ├── utils.py
│ │ │ └── version.py
│ │ ├── charset_normalizer-3.4.0.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── click
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ ├── _termui_impl.cpython-312.pyc
│ │ │ │ ├── _textwrap.cpython-312.pyc
│ │ │ │ ├── _winconsole.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── decorators.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formatting.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── shell_completion.cpython-312.pyc
│ │ │ │ ├── termui.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── types.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── _compat.py
│ │ │ ├── _termui_impl.py
│ │ │ ├── _textwrap.py
│ │ │ ├── _winconsole.py
│ │ │ ├── core.py
│ │ │ ├── decorators.py
│ │ │ ├── exceptions.py
│ │ │ ├── formatting.py
│ │ │ ├── globals.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── shell_completion.py
│ │ │ ├── termui.py
│ │ │ ├── testing.py
│ │ │ ├── types.py
│ │ │ └── utils.py
│ │ ├── click-8.1.7.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.rst
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── fake_useragent
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ ├── fake.cpython-312.pyc
│ │ │ │ ├── log.cpython-312.pyc
│ │ │ │ ├── settings.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── data
│ │ │ │ └── browsers.json
│ │ │ ├── errors.py
│ │ │ ├── fake.py
│ │ │ ├── log.py
│ │ │ ├── settings.py
│ │ │ └── utils.py
│ │ ├── fake_useragent-1.5.1.dist-info
│ │ │ ├── AUTHORS
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── flask
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ ├── cli.cpython-312.pyc
│ │ │ │ ├── config.cpython-312.pyc
│ │ │ │ ├── ctx.cpython-312.pyc
│ │ │ │ ├── debughelpers.cpython-312.pyc
│ │ │ │ ├── globals.cpython-312.pyc
│ │ │ │ ├── helpers.cpython-312.pyc
│ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── signals.cpython-312.pyc
│ │ │ │ ├── templating.cpython-312.pyc
│ │ │ │ ├── testing.cpython-312.pyc
│ │ │ │ ├── typing.cpython-312.pyc
│ │ │ │ ├── views.cpython-312.pyc
│ │ │ │ └── wrappers.cpython-312.pyc
│ │ │ ├── app.py
│ │ │ ├── blueprints.py
│ │ │ ├── cli.py
│ │ │ ├── config.py
│ │ │ ├── ctx.py
│ │ │ ├── debughelpers.py
│ │ │ ├── globals.py
│ │ │ ├── helpers.py
│ │ │ ├── json
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ └── tag.cpython-312.pyc
│ │ │ │ ├── provider.py
│ │ │ │ └── tag.py
│ │ │ ├── logging.py
│ │ │ ├── py.typed
│ │ │ ├── sansio
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── app.cpython-312.pyc
│ │ │ │ │ ├── blueprints.cpython-312.pyc
│ │ │ │ │ └── scaffold.cpython-312.pyc
│ │ │ │ ├── app.py
│ │ │ │ ├── blueprints.py
│ │ │ │ ├── README.md
│ │ │ │ └── scaffold.py
│ │ │ ├── sessions.py
│ │ │ ├── signals.py
│ │ │ ├── templating.py
│ │ │ ├── testing.py
│ │ │ ├── typing.py
│ │ │ ├── views.py
│ │ │ └── wrappers.py
│ │ ├── flask-3.0.3.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ └── WHEEL
│ │ ├── idna
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ ├── codec.py
│ │ │ ├── compat.py
│ │ │ ├── core.py
│ │ │ ├── idnadata.py
│ │ │ ├── intranges.py
│ │ │ ├── package_data.py
│ │ │ ├── py.typed
│ │ │ └── uts46data.py
│ │ ├── idna-3.10.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── itsdangerous
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ ├── exc.cpython-312.pyc
│ │ │ │ ├── serializer.cpython-312.pyc
│ │ │ │ ├── signer.cpython-312.pyc
│ │ │ │ ├── timed.cpython-312.pyc
│ │ │ │ └── url_safe.cpython-312.pyc
│ │ │ ├── _json.py
│ │ │ ├── encoding.py
│ │ │ ├── exc.py
│ │ │ ├── py.typed
│ │ │ ├── serializer.py
│ │ │ ├── signer.py
│ │ │ ├── timed.py
│ │ │ └── url_safe.py
│ │ ├── itsdangerous-2.2.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── jinja2
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _identifier.cpython-312.pyc
│ │ │ │ ├── async_utils.cpython-312.pyc
│ │ │ │ ├── bccache.cpython-312.pyc
│ │ │ │ ├── compiler.cpython-312.pyc
│ │ │ │ ├── constants.cpython-312.pyc
│ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ ├── defaults.cpython-312.pyc
│ │ │ │ ├── environment.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ ├── filters.cpython-312.pyc
│ │ │ │ ├── idtracking.cpython-312.pyc
│ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ ├── loaders.cpython-312.pyc
│ │ │ │ ├── meta.cpython-312.pyc
│ │ │ │ ├── nativetypes.cpython-312.pyc
│ │ │ │ ├── nodes.cpython-312.pyc
│ │ │ │ ├── optimizer.cpython-312.pyc
│ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ ├── runtime.cpython-312.pyc
│ │ │ │ ├── sandbox.cpython-312.pyc
│ │ │ │ ├── tests.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── visitor.cpython-312.pyc
│ │ │ ├── _identifier.py
│ │ │ ├── async_utils.py
│ │ │ ├── bccache.py
│ │ │ ├── compiler.py
│ │ │ ├── constants.py
│ │ │ ├── debug.py
│ │ │ ├── defaults.py
│ │ │ ├── environment.py
│ │ │ ├── exceptions.py
│ │ │ ├── ext.py
│ │ │ ├── filters.py
│ │ │ ├── idtracking.py
│ │ │ ├── lexer.py
│ │ │ ├── loaders.py
│ │ │ ├── meta.py
│ │ │ ├── nativetypes.py
│ │ │ ├── nodes.py
│ │ │ ├── optimizer.py
│ │ │ ├── parser.py
│ │ │ ├── py.typed
│ │ │ ├── runtime.py
│ │ │ ├── sandbox.py
│ │ │ ├── tests.py
│ │ │ ├── utils.py
│ │ │ └── visitor.py
│ │ ├── jinja2-3.1.4.dist-info
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── lxml
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _elementpath.cpython-312.pyc
│ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ ├── cssselect.cpython-312.pyc
│ │ │ │ ├── doctestcompare.cpython-312.pyc
│ │ │ │ ├── ElementInclude.cpython-312.pyc
│ │ │ │ ├── pyclasslookup.cpython-312.pyc
│ │ │ │ ├── sax.cpython-312.pyc
│ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ ├── _elementpath.cpython-312-darwin.so
│ │ │ ├── _elementpath.py
│ │ │ ├── apihelpers.pxi
│ │ │ ├── builder.cpython-312-darwin.so
│ │ │ ├── builder.py
│ │ │ ├── classlookup.pxi
│ │ │ ├── cleanup.pxi
│ │ │ ├── cssselect.py
│ │ │ ├── debug.pxi
│ │ │ ├── docloader.pxi
│ │ │ ├── doctestcompare.py
│ │ │ ├── dtd.pxi
│ │ │ ├── ElementInclude.py
│ │ │ ├── etree_api.h
│ │ │ ├── etree.cpython-312-darwin.so
│ │ │ ├── etree.h
│ │ │ ├── etree.pyx
│ │ │ ├── extensions.pxi
│ │ │ ├── html
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── _diffcommand.cpython-312.pyc
│ │ │ │ │ ├── _html5builder.cpython-312.pyc
│ │ │ │ │ ├── _setmixin.cpython-312.pyc
│ │ │ │ │ ├── builder.cpython-312.pyc
│ │ │ │ │ ├── clean.cpython-312.pyc
│ │ │ │ │ ├── defs.cpython-312.pyc
│ │ │ │ │ ├── diff.cpython-312.pyc
│ │ │ │ │ ├── ElementSoup.cpython-312.pyc
│ │ │ │ │ ├── formfill.cpython-312.pyc
│ │ │ │ │ ├── html5parser.cpython-312.pyc
│ │ │ │ │ ├── soupparser.cpython-312.pyc
│ │ │ │ │ └── usedoctest.cpython-312.pyc
│ │ │ │ ├── _diffcommand.py
│ │ │ │ ├── _html5builder.py
│ │ │ │ ├── _setmixin.py
│ │ │ │ ├── builder.py
│ │ │ │ ├── clean.py
│ │ │ │ ├── defs.py
│ │ │ │ ├── diff.cpython-312-darwin.so
│ │ │ │ ├── diff.py
│ │ │ │ ├── ElementSoup.py
│ │ │ │ ├── formfill.py
│ │ │ │ ├── html5parser.py
│ │ │ │ ├── soupparser.py
│ │ │ │ └── usedoctest.py
│ │ │ ├── includes
│ │ │ │ ├── __init__.pxd
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── c14n.pxd
│ │ │ │ ├── config.pxd
│ │ │ │ ├── dtdvalid.pxd
│ │ │ │ ├── etree_defs.h
│ │ │ │ ├── etreepublic.pxd
│ │ │ │ ├── extlibs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── libcharset.h
│ │ │ │ │ ├── localcharset.h
│ │ │ │ │ ├── zconf.h
│ │ │ │ │ └── zlib.h
│ │ │ │ ├── htmlparser.pxd
│ │ │ │ ├── libexslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── exslt.h
│ │ │ │ │ ├── exsltconfig.h
│ │ │ │ │ └── exsltexports.h
│ │ │ │ ├── libxml
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── c14n.h
│ │ │ │ │ ├── catalog.h
│ │ │ │ │ ├── chvalid.h
│ │ │ │ │ ├── debugXML.h
│ │ │ │ │ ├── dict.h
│ │ │ │ │ ├── encoding.h
│ │ │ │ │ ├── entities.h
│ │ │ │ │ ├── globals.h
│ │ │ │ │ ├── hash.h
│ │ │ │ │ ├── HTMLparser.h
│ │ │ │ │ ├── HTMLtree.h
│ │ │ │ │ ├── list.h
│ │ │ │ │ ├── nanoftp.h
│ │ │ │ │ ├── nanohttp.h
│ │ │ │ │ ├── parser.h
│ │ │ │ │ ├── parserInternals.h
│ │ │ │ │ ├── relaxng.h
│ │ │ │ │ ├── SAX.h
│ │ │ │ │ ├── SAX2.h
│ │ │ │ │ ├── schemasInternals.h
│ │ │ │ │ ├── schematron.h
│ │ │ │ │ ├── threads.h
│ │ │ │ │ ├── tree.h
│ │ │ │ │ ├── uri.h
│ │ │ │ │ ├── valid.h
│ │ │ │ │ ├── xinclude.h
│ │ │ │ │ ├── xlink.h
│ │ │ │ │ ├── xmlautomata.h
│ │ │ │ │ ├── xmlerror.h
│ │ │ │ │ ├── xmlexports.h
│ │ │ │ │ ├── xmlIO.h
│ │ │ │ │ ├── xmlmemory.h
│ │ │ │ │ ├── xmlmodule.h
│ │ │ │ │ ├── xmlreader.h
│ │ │ │ │ ├── xmlregexp.h
│ │ │ │ │ ├── xmlsave.h
│ │ │ │ │ ├── xmlschemas.h
│ │ │ │ │ ├── xmlschemastypes.h
│ │ │ │ │ ├── xmlstring.h
│ │ │ │ │ ├── xmlunicode.h
│ │ │ │ │ ├── xmlversion.h
│ │ │ │ │ ├── xmlwriter.h
│ │ │ │ │ ├── xpath.h
│ │ │ │ │ ├── xpathInternals.h
│ │ │ │ │ └── xpointer.h
│ │ │ │ ├── libxslt
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── attributes.h
│ │ │ │ │ ├── documents.h
│ │ │ │ │ ├── extensions.h
│ │ │ │ │ ├── extra.h
│ │ │ │ │ ├── functions.h
│ │ │ │ │ ├── imports.h
│ │ │ │ │ ├── keys.h
│ │ │ │ │ ├── namespaces.h
│ │ │ │ │ ├── numbersInternals.h
│ │ │ │ │ ├── pattern.h
│ │ │ │ │ ├── preproc.h
│ │ │ │ │ ├── security.h
│ │ │ │ │ ├── templates.h
│ │ │ │ │ ├── transform.h
│ │ │ │ │ ├── variables.h
│ │ │ │ │ ├── xslt.h
│ │ │ │ │ ├── xsltconfig.h
│ │ │ │ │ ├── xsltexports.h
│ │ │ │ │ ├── xsltInternals.h
│ │ │ │ │ ├── xsltlocale.h
│ │ │ │ │ └── xsltutils.h
│ │ │ │ ├── lxml-version.h
│ │ │ │ ├── relaxng.pxd
│ │ │ │ ├── schematron.pxd
│ │ │ │ ├── tree.pxd
│ │ │ │ ├── uri.pxd
│ │ │ │ ├── xinclude.pxd
│ │ │ │ ├── xmlerror.pxd
│ │ │ │ ├── xmlparser.pxd
│ │ │ │ ├── xmlschema.pxd
│ │ │ │ ├── xpath.pxd
│ │ │ │ └── xslt.pxd
│ │ │ ├── isoschematron
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ └── resources
│ │ │ │ ├── rng
│ │ │ │ │ └── iso-schematron.rng
│ │ │ │ └── xsl
│ │ │ │ ├── iso-schematron-xslt1
│ │ │ │ │ ├── iso_abstract_expand.xsl
│ │ │ │ │ ├── iso_dsdl_include.xsl
│ │ │ │ │ ├── iso_schematron_message.xsl
│ │ │ │ │ ├── iso_schematron_skeleton_for_xslt1.xsl
│ │ │ │ │ ├── iso_svrl_for_xslt1.xsl
│ │ │ │ │ └── readme.txt
│ │ │ │ ├── RNG2Schtrn.xsl
│ │ │ │ └── XSD2Schtrn.xsl
│ │ │ ├── iterparse.pxi
│ │ │ ├── lxml.etree_api.h
│ │ │ ├── lxml.etree.h
│ │ │ ├── nsclasses.pxi
│ │ │ ├── objectify.cpython-312-darwin.so
│ │ │ ├── objectify.pyx
│ │ │ ├── objectpath.pxi
│ │ │ ├── parser.pxi
│ │ │ ├── parsertarget.pxi
│ │ │ ├── proxy.pxi
│ │ │ ├── public-api.pxi
│ │ │ ├── pyclasslookup.py
│ │ │ ├── readonlytree.pxi
│ │ │ ├── relaxng.pxi
│ │ │ ├── sax.cpython-312-darwin.so
│ │ │ ├── sax.py
│ │ │ ├── saxparser.pxi
│ │ │ ├── schematron.pxi
│ │ │ ├── serializer.pxi
│ │ │ ├── usedoctest.py
│ │ │ ├── xinclude.pxi
│ │ │ ├── xmlerror.pxi
│ │ │ ├── xmlid.pxi
│ │ │ ├── xmlschema.pxi
│ │ │ ├── xpath.pxi
│ │ │ ├── xslt.pxi
│ │ │ └── xsltext.pxi
│ │ ├── lxml-5.3.0.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── LICENSES.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── markupsafe
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ └── _native.cpython-312.pyc
│ │ │ ├── _native.py
│ │ │ ├── _speedups.c
│ │ │ ├── _speedups.cpython-312-darwin.so
│ │ │ ├── _speedups.pyi
│ │ │ └── py.typed
│ │ ├── MarkupSafe-3.0.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── pip
│ │ │ ├── __init__.py
│ │ │ ├── __main__.py
│ │ │ ├── __pip-runner__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ └── __pip-runner__.cpython-312.pyc
│ │ │ ├── _internal
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── build_env.cpython-312.pyc
│ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ ├── pyproject.cpython-312.pyc
│ │ │ │ │ ├── self_outdated_check.cpython-312.pyc
│ │ │ │ │ └── wheel_builder.cpython-312.pyc
│ │ │ │ ├── build_env.py
│ │ │ │ ├── cache.py
│ │ │ │ ├── cli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── autocompletion.cpython-312.pyc
│ │ │ │ │ │ ├── base_command.cpython-312.pyc
│ │ │ │ │ │ ├── cmdoptions.cpython-312.pyc
│ │ │ │ │ │ ├── command_context.cpython-312.pyc
│ │ │ │ │ │ ├── index_command.cpython-312.pyc
│ │ │ │ │ │ ├── main_parser.cpython-312.pyc
│ │ │ │ │ │ ├── main.cpython-312.pyc
│ │ │ │ │ │ ├── parser.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bars.cpython-312.pyc
│ │ │ │ │ │ ├── req_command.cpython-312.pyc
│ │ │ │ │ │ ├── spinners.cpython-312.pyc
│ │ │ │ │ │ └── status_codes.cpython-312.pyc
│ │ │ │ │ ├── autocompletion.py
│ │ │ │ │ ├── base_command.py
│ │ │ │ │ ├── cmdoptions.py
│ │ │ │ │ ├── command_context.py
│ │ │ │ │ ├── index_command.py
│ │ │ │ │ ├── main_parser.py
│ │ │ │ │ ├── main.py
│ │ │ │ │ ├── parser.py
│ │ │ │ │ ├── progress_bars.py
│ │ │ │ │ ├── req_command.py
│ │ │ │ │ ├── spinners.py
│ │ │ │ │ └── status_codes.py
│ │ │ │ ├── commands
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── completion.cpython-312.pyc
│ │ │ │ │ │ ├── configuration.cpython-312.pyc
│ │ │ │ │ │ ├── debug.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ ├── hash.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── inspect.cpython-312.pyc
│ │ │ │ │ │ ├── install.cpython-312.pyc
│ │ │ │ │ │ ├── list.cpython-312.pyc
│ │ │ │ │ │ ├── search.cpython-312.pyc
│ │ │ │ │ │ ├── show.cpython-312.pyc
│ │ │ │ │ │ ├── uninstall.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── completion.py
│ │ │ │ │ ├── configuration.py
│ │ │ │ │ ├── debug.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── hash.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── inspect.py
│ │ │ │ │ ├── install.py
│ │ │ │ │ ├── list.py
│ │ │ │ │ ├── search.py
│ │ │ │ │ ├── show.py
│ │ │ │ │ ├── uninstall.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── configuration.py
│ │ │ │ ├── distributions
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── installed.cpython-312.pyc
│ │ │ │ │ │ ├── sdist.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── installed.py
│ │ │ │ │ ├── sdist.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── index
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── collector.cpython-312.pyc
│ │ │ │ │ │ ├── package_finder.cpython-312.pyc
│ │ │ │ │ │ └── sources.cpython-312.pyc
│ │ │ │ │ ├── collector.py
│ │ │ │ │ ├── package_finder.py
│ │ │ │ │ └── sources.py
│ │ │ │ ├── locations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _distutils.cpython-312.pyc
│ │ │ │ │ │ ├── _sysconfig.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── _distutils.py
│ │ │ │ │ ├── _sysconfig.py
│ │ │ │ │ └── base.py
│ │ │ │ ├── main.py
│ │ │ │ ├── metadata
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _json.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ └── pkg_resources.cpython-312.pyc
│ │ │ │ │ ├── _json.py
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── importlib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ │ ├── _dists.cpython-312.pyc
│ │ │ │ │ │ │ └── _envs.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.py
│ │ │ │ │ │ ├── _dists.py
│ │ │ │ │ │ └── _envs.py
│ │ │ │ │ └── pkg_resources.py
│ │ │ │ ├── models
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── candidate.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url.cpython-312.pyc
│ │ │ │ │ │ ├── format_control.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── installation_report.cpython-312.pyc
│ │ │ │ │ │ ├── link.cpython-312.pyc
│ │ │ │ │ │ ├── scheme.cpython-312.pyc
│ │ │ │ │ │ ├── search_scope.cpython-312.pyc
│ │ │ │ │ │ ├── selection_prefs.cpython-312.pyc
│ │ │ │ │ │ ├── target_python.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── candidate.py
│ │ │ │ │ ├── direct_url.py
│ │ │ │ │ ├── format_control.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── installation_report.py
│ │ │ │ │ ├── link.py
│ │ │ │ │ ├── scheme.py
│ │ │ │ │ ├── search_scope.py
│ │ │ │ │ ├── selection_prefs.py
│ │ │ │ │ ├── target_python.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── network
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── download.cpython-312.pyc
│ │ │ │ │ │ ├── lazy_wheel.cpython-312.pyc
│ │ │ │ │ │ ├── session.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── xmlrpc.cpython-312.pyc
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── download.py
│ │ │ │ │ ├── lazy_wheel.py
│ │ │ │ │ ├── session.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── xmlrpc.py
│ │ │ │ ├── operations
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── check.cpython-312.pyc
│ │ │ │ │ │ ├── freeze.cpython-312.pyc
│ │ │ │ │ │ └── prepare.cpython-312.pyc
│ │ │ │ │ ├── build
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── build_tracker.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata_legacy.cpython-312.pyc
│ │ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_editable.cpython-312.pyc
│ │ │ │ │ │ │ ├── wheel_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── build_tracker.py
│ │ │ │ │ │ ├── metadata_editable.py
│ │ │ │ │ │ ├── metadata_legacy.py
│ │ │ │ │ │ ├── metadata.py
│ │ │ │ │ │ ├── wheel_editable.py
│ │ │ │ │ │ ├── wheel_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ ├── check.py
│ │ │ │ │ ├── freeze.py
│ │ │ │ │ ├── install
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── editable_legacy.cpython-312.pyc
│ │ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ │ ├── editable_legacy.py
│ │ │ │ │ │ └── wheel.py
│ │ │ │ │ └── prepare.py
│ │ │ │ ├── pyproject.py
│ │ │ │ ├── req
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── constructors.cpython-312.pyc
│ │ │ │ │ │ ├── req_file.cpython-312.pyc
│ │ │ │ │ │ ├── req_install.cpython-312.pyc
│ │ │ │ │ │ ├── req_set.cpython-312.pyc
│ │ │ │ │ │ └── req_uninstall.cpython-312.pyc
│ │ │ │ │ ├── constructors.py
│ │ │ │ │ ├── req_file.py
│ │ │ │ │ ├── req_install.py
│ │ │ │ │ ├── req_set.py
│ │ │ │ │ └── req_uninstall.py
│ │ │ │ ├── resolution
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── base.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── legacy
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ │ └── resolver.py
│ │ │ │ │ └── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── base.cpython-312.pyc
│ │ │ │ │ │ ├── candidates.cpython-312.pyc
│ │ │ │ │ │ ├── factory.cpython-312.pyc
│ │ │ │ │ │ ├── found_candidates.cpython-312.pyc
│ │ │ │ │ │ ├── provider.cpython-312.pyc
│ │ │ │ │ │ ├── reporter.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ └── resolver.cpython-312.pyc
│ │ │ │ │ ├── base.py
│ │ │ │ │ ├── candidates.py
│ │ │ │ │ ├── factory.py
│ │ │ │ │ ├── found_candidates.py
│ │ │ │ │ ├── provider.py
│ │ │ │ │ ├── reporter.py
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ └── resolver.py
│ │ │ │ ├── self_outdated_check.py
│ │ │ │ ├── utils
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _jaraco_text.cpython-312.pyc
│ │ │ │ │ │ ├── _log.cpython-312.pyc
│ │ │ │ │ │ ├── appdirs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── compatibility_tags.cpython-312.pyc
│ │ │ │ │ │ ├── datetime.cpython-312.pyc
│ │ │ │ │ │ ├── deprecation.cpython-312.pyc
│ │ │ │ │ │ ├── direct_url_helpers.cpython-312.pyc
│ │ │ │ │ │ ├── egg_link.cpython-312.pyc
│ │ │ │ │ │ ├── encoding.cpython-312.pyc
│ │ │ │ │ │ ├── entrypoints.cpython-312.pyc
│ │ │ │ │ │ ├── filesystem.cpython-312.pyc
│ │ │ │ │ │ ├── filetypes.cpython-312.pyc
│ │ │ │ │ │ ├── glibc.cpython-312.pyc
│ │ │ │ │ │ ├── hashes.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── misc.cpython-312.pyc
│ │ │ │ │ │ ├── packaging.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── setuptools_build.cpython-312.pyc
│ │ │ │ │ │ ├── subprocess.cpython-312.pyc
│ │ │ │ │ │ ├── temp_dir.cpython-312.pyc
│ │ │ │ │ │ ├── unpacking.cpython-312.pyc
│ │ │ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ │ │ ├── virtualenv.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── _jaraco_text.py
│ │ │ │ │ ├── _log.py
│ │ │ │ │ ├── appdirs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── compatibility_tags.py
│ │ │ │ │ ├── datetime.py
│ │ │ │ │ ├── deprecation.py
│ │ │ │ │ ├── direct_url_helpers.py
│ │ │ │ │ ├── egg_link.py
│ │ │ │ │ ├── encoding.py
│ │ │ │ │ ├── entrypoints.py
│ │ │ │ │ ├── filesystem.py
│ │ │ │ │ ├── filetypes.py
│ │ │ │ │ ├── glibc.py
│ │ │ │ │ ├── hashes.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── misc.py
│ │ │ │ │ ├── packaging.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── setuptools_build.py
│ │ │ │ │ ├── subprocess.py
│ │ │ │ │ ├── temp_dir.py
│ │ │ │ │ ├── unpacking.py
│ │ │ │ │ ├── urls.py
│ │ │ │ │ ├── virtualenv.py
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── vcs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── bazaar.cpython-312.pyc
│ │ │ │ │ │ ├── git.cpython-312.pyc
│ │ │ │ │ │ ├── mercurial.cpython-312.pyc
│ │ │ │ │ │ ├── subversion.cpython-312.pyc
│ │ │ │ │ │ └── versioncontrol.cpython-312.pyc
│ │ │ │ │ ├── bazaar.py
│ │ │ │ │ ├── git.py
│ │ │ │ │ ├── mercurial.py
│ │ │ │ │ ├── subversion.py
│ │ │ │ │ └── versioncontrol.py
│ │ │ │ └── wheel_builder.py
│ │ │ ├── _vendor
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ └── typing_extensions.cpython-312.pyc
│ │ │ │ ├── cachecontrol
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _cmd.cpython-312.pyc
│ │ │ │ │ │ ├── adapter.cpython-312.pyc
│ │ │ │ │ │ ├── cache.cpython-312.pyc
│ │ │ │ │ │ ├── controller.cpython-312.pyc
│ │ │ │ │ │ ├── filewrapper.cpython-312.pyc
│ │ │ │ │ │ ├── heuristics.cpython-312.pyc
│ │ │ │ │ │ ├── serialize.cpython-312.pyc
│ │ │ │ │ │ └── wrapper.cpython-312.pyc
│ │ │ │ │ ├── _cmd.py
│ │ │ │ │ ├── adapter.py
│ │ │ │ │ ├── cache.py
│ │ │ │ │ ├── caches
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── file_cache.cpython-312.pyc
│ │ │ │ │ │ │ └── redis_cache.cpython-312.pyc
│ │ │ │ │ │ ├── file_cache.py
│ │ │ │ │ │ └── redis_cache.py
│ │ │ │ │ ├── controller.py
│ │ │ │ │ ├── filewrapper.py
│ │ │ │ │ ├── heuristics.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── serialize.py
│ │ │ │ │ └── wrapper.py
│ │ │ │ ├── certifi
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── core.cpython-312.pyc
│ │ │ │ │ ├── cacert.pem
│ │ │ │ │ ├── core.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── distlib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── database.cpython-312.pyc
│ │ │ │ │ │ ├── index.cpython-312.pyc
│ │ │ │ │ │ ├── locators.cpython-312.pyc
│ │ │ │ │ │ ├── manifest.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── resources.cpython-312.pyc
│ │ │ │ │ │ ├── scripts.cpython-312.pyc
│ │ │ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── wheel.cpython-312.pyc
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── database.py
│ │ │ │ │ ├── index.py
│ │ │ │ │ ├── locators.py
│ │ │ │ │ ├── manifest.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── resources.py
│ │ │ │ │ ├── scripts.py
│ │ │ │ │ ├── t32.exe
│ │ │ │ │ ├── t64-arm.exe
│ │ │ │ │ ├── t64.exe
│ │ │ │ │ ├── util.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ ├── w32.exe
│ │ │ │ │ ├── w64-arm.exe
│ │ │ │ │ ├── w64.exe
│ │ │ │ │ └── wheel.py
│ │ │ │ ├── distro
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ └── distro.cpython-312.pyc
│ │ │ │ │ ├── distro.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── idna
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── codec.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── core.cpython-312.pyc
│ │ │ │ │ │ ├── idnadata.cpython-312.pyc
│ │ │ │ │ │ ├── intranges.cpython-312.pyc
│ │ │ │ │ │ ├── package_data.cpython-312.pyc
│ │ │ │ │ │ └── uts46data.cpython-312.pyc
│ │ │ │ │ ├── codec.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── core.py
│ │ │ │ │ ├── idnadata.py
│ │ │ │ │ ├── intranges.py
│ │ │ │ │ ├── package_data.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ └── uts46data.py
│ │ │ │ ├── msgpack
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── ext.cpython-312.pyc
│ │ │ │ │ │ └── fallback.cpython-312.pyc
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── ext.py
│ │ │ │ │ └── fallback.py
│ │ │ │ ├── packaging
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _elffile.cpython-312.pyc
│ │ │ │ │ │ ├── _manylinux.cpython-312.pyc
│ │ │ │ │ │ ├── _musllinux.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _structures.cpython-312.pyc
│ │ │ │ │ │ ├── _tokenizer.cpython-312.pyc
│ │ │ │ │ │ ├── markers.cpython-312.pyc
│ │ │ │ │ │ ├── metadata.cpython-312.pyc
│ │ │ │ │ │ ├── requirements.cpython-312.pyc
│ │ │ │ │ │ ├── specifiers.cpython-312.pyc
│ │ │ │ │ │ ├── tags.cpython-312.pyc
│ │ │ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ │ │ └── version.cpython-312.pyc
│ │ │ │ │ ├── _elffile.py
│ │ │ │ │ ├── _manylinux.py
│ │ │ │ │ ├── _musllinux.py
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _structures.py
│ │ │ │ │ ├── _tokenizer.py
│ │ │ │ │ ├── markers.py
│ │ │ │ │ ├── metadata.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── requirements.py
│ │ │ │ │ ├── specifiers.py
│ │ │ │ │ ├── tags.py
│ │ │ │ │ ├── utils.py
│ │ │ │ │ └── version.py
│ │ │ │ ├── pkg_resources
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ └── __pycache__
│ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ ├── platformdirs
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── android.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── macos.cpython-312.pyc
│ │ │ │ │ │ ├── unix.cpython-312.pyc
│ │ │ │ │ │ ├── version.cpython-312.pyc
│ │ │ │ │ │ └── windows.cpython-312.pyc
│ │ │ │ │ ├── android.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── macos.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── unix.py
│ │ │ │ │ ├── version.py
│ │ │ │ │ └── windows.py
│ │ │ │ ├── pygments
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── cmdline.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── filter.cpython-312.pyc
│ │ │ │ │ │ ├── formatter.cpython-312.pyc
│ │ │ │ │ │ ├── lexer.cpython-312.pyc
│ │ │ │ │ │ ├── modeline.cpython-312.pyc
│ │ │ │ │ │ ├── plugin.cpython-312.pyc
│ │ │ │ │ │ ├── regexopt.cpython-312.pyc
│ │ │ │ │ │ ├── scanner.cpython-312.pyc
│ │ │ │ │ │ ├── sphinxext.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── token.cpython-312.pyc
│ │ │ │ │ │ ├── unistring.cpython-312.pyc
│ │ │ │ │ │ └── util.cpython-312.pyc
│ │ │ │ │ ├── cmdline.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── filter.py
│ │ │ │ │ ├── filters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ └── __pycache__
│ │ │ │ │ │ └── __init__.cpython-312.pyc
│ │ │ │ │ ├── formatter.py
│ │ │ │ │ ├── formatters
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ ├── bbcode.cpython-312.pyc
│ │ │ │ │ │ │ ├── groff.cpython-312.pyc
│ │ │ │ │ │ │ ├── html.cpython-312.pyc
│ │ │ │ │ │ │ ├── img.cpython-312.pyc
│ │ │ │ │ │ │ ├── irc.cpython-312.pyc
│ │ │ │ │ │ │ ├── latex.cpython-312.pyc
│ │ │ │ │ │ │ ├── other.cpython-312.pyc
│ │ │ │ │ │ │ ├── pangomarkup.cpython-312.pyc
│ │ │ │ │ │ │ ├── rtf.cpython-312.pyc
│ │ │ │ │ │ │ ├── svg.cpython-312.pyc
│ │ │ │ │ │ │ ├── terminal.cpython-312.pyc
│ │ │ │ │ │ │ └── terminal256.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ ├── bbcode.py
│ │ │ │ │ │ ├── groff.py
│ │ │ │ │ │ ├── html.py
│ │ │ │ │ │ ├── img.py
│ │ │ │ │ │ ├── irc.py
│ │ │ │ │ │ ├── latex.py
│ │ │ │ │ │ ├── other.py
│ │ │ │ │ │ ├── pangomarkup.py
│ │ │ │ │ │ ├── rtf.py
│ │ │ │ │ │ ├── svg.py
│ │ │ │ │ │ ├── terminal.py
│ │ │ │ │ │ └── terminal256.py
│ │ │ │ │ ├── lexer.py
│ │ │ │ │ ├── lexers
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _mapping.cpython-312.pyc
│ │ │ │ │ │ │ └── python.cpython-312.pyc
│ │ │ │ │ │ ├── _mapping.py
│ │ │ │ │ │ └── python.py
│ │ │ │ │ ├── modeline.py
│ │ │ │ │ ├── plugin.py
│ │ │ │ │ ├── regexopt.py
│ │ │ │ │ ├── scanner.py
│ │ │ │ │ ├── sphinxext.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styles
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── _mapping.cpython-312.pyc
│ │ │ │ │ │ └── _mapping.py
│ │ │ │ │ ├── token.py
│ │ │ │ │ ├── unistring.py
│ │ │ │ │ └── util.py
│ │ │ │ ├── pyproject_hooks
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _compat.cpython-312.pyc
│ │ │ │ │ │ └── _impl.cpython-312.pyc
│ │ │ │ │ ├── _compat.py
│ │ │ │ │ ├── _impl.py
│ │ │ │ │ └── _in_process
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ └── _in_process.cpython-312.pyc
│ │ │ │ │ └── _in_process.py
│ │ │ │ ├── requests
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ │ ├── __version__.py
│ │ │ │ │ ├── _internal_utils.py
│ │ │ │ │ ├── adapters.py
│ │ │ │ │ ├── api.py
│ │ │ │ │ ├── auth.py
│ │ │ │ │ ├── certs.py
│ │ │ │ │ ├── compat.py
│ │ │ │ │ ├── cookies.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── help.py
│ │ │ │ │ ├── hooks.py
│ │ │ │ │ ├── models.py
│ │ │ │ │ ├── packages.py
│ │ │ │ │ ├── sessions.py
│ │ │ │ │ ├── status_codes.py
│ │ │ │ │ ├── structures.py
│ │ │ │ │ └── utils.py
│ │ │ │ ├── resolvelib
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── providers.cpython-312.pyc
│ │ │ │ │ │ ├── reporters.cpython-312.pyc
│ │ │ │ │ │ ├── resolvers.cpython-312.pyc
│ │ │ │ │ │ └── structs.cpython-312.pyc
│ │ │ │ │ ├── compat
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── collections_abc.cpython-312.pyc
│ │ │ │ │ │ └── collections_abc.py
│ │ │ │ │ ├── providers.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── reporters.py
│ │ │ │ │ ├── resolvers.py
│ │ │ │ │ └── structs.py
│ │ │ │ ├── rich
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __main__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── __main__.cpython-312.pyc
│ │ │ │ │ │ ├── _cell_widths.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_codes.cpython-312.pyc
│ │ │ │ │ │ ├── _emoji_replace.cpython-312.pyc
│ │ │ │ │ │ ├── _export_format.cpython-312.pyc
│ │ │ │ │ │ ├── _extension.cpython-312.pyc
│ │ │ │ │ │ ├── _fileno.cpython-312.pyc
│ │ │ │ │ │ ├── _inspect.cpython-312.pyc
│ │ │ │ │ │ ├── _log_render.cpython-312.pyc
│ │ │ │ │ │ ├── _loop.cpython-312.pyc
│ │ │ │ │ │ ├── _null_file.cpython-312.pyc
│ │ │ │ │ │ ├── _palettes.cpython-312.pyc
│ │ │ │ │ │ ├── _pick.cpython-312.pyc
│ │ │ │ │ │ ├── _ratio.cpython-312.pyc
│ │ │ │ │ │ ├── _spinners.cpython-312.pyc
│ │ │ │ │ │ ├── _stack.cpython-312.pyc
│ │ │ │ │ │ ├── _timer.cpython-312.pyc
│ │ │ │ │ │ ├── _win32_console.cpython-312.pyc
│ │ │ │ │ │ ├── _windows_renderer.cpython-312.pyc
│ │ │ │ │ │ ├── _windows.cpython-312.pyc
│ │ │ │ │ │ ├── _wrap.cpython-312.pyc
│ │ │ │ │ │ ├── abc.cpython-312.pyc
│ │ │ │ │ │ ├── align.cpython-312.pyc
│ │ │ │ │ │ ├── ansi.cpython-312.pyc
│ │ │ │ │ │ ├── bar.cpython-312.pyc
│ │ │ │ │ │ ├── box.cpython-312.pyc
│ │ │ │ │ │ ├── cells.cpython-312.pyc
│ │ │ │ │ │ ├── color_triplet.cpython-312.pyc
│ │ │ │ │ │ ├── color.cpython-312.pyc
│ │ │ │ │ │ ├── columns.cpython-312.pyc
│ │ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ │ ├── constrain.cpython-312.pyc
│ │ │ │ │ │ ├── containers.cpython-312.pyc
│ │ │ │ │ │ ├── control.cpython-312.pyc
│ │ │ │ │ │ ├── default_styles.cpython-312.pyc
│ │ │ │ │ │ ├── diagnose.cpython-312.pyc
│ │ │ │ │ │ ├── emoji.cpython-312.pyc
│ │ │ │ │ │ ├── errors.cpython-312.pyc
│ │ │ │ │ │ ├── file_proxy.cpython-312.pyc
│ │ │ │ │ │ ├── filesize.cpython-312.pyc
│ │ │ │ │ │ ├── highlighter.cpython-312.pyc
│ │ │ │ │ │ ├── json.cpython-312.pyc
│ │ │ │ │ │ ├── jupyter.cpython-312.pyc
│ │ │ │ │ │ ├── layout.cpython-312.pyc
│ │ │ │ │ │ ├── live_render.cpython-312.pyc
│ │ │ │ │ │ ├── live.cpython-312.pyc
│ │ │ │ │ │ ├── logging.cpython-312.pyc
│ │ │ │ │ │ ├── markup.cpython-312.pyc
│ │ │ │ │ │ ├── measure.cpython-312.pyc
│ │ │ │ │ │ ├── padding.cpython-312.pyc
│ │ │ │ │ │ ├── pager.cpython-312.pyc
│ │ │ │ │ │ ├── palette.cpython-312.pyc
│ │ │ │ │ │ ├── panel.cpython-312.pyc
│ │ │ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ │ │ ├── progress_bar.cpython-312.pyc
│ │ │ │ │ │ ├── progress.cpython-312.pyc
│ │ │ │ │ │ ├── prompt.cpython-312.pyc
│ │ │ │ │ │ ├── protocol.cpython-312.pyc
│ │ │ │ │ │ ├── region.cpython-312.pyc
│ │ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ │ ├── rule.cpython-312.pyc
│ │ │ │ │ │ ├── scope.cpython-312.pyc
│ │ │ │ │ │ ├── screen.cpython-312.pyc
│ │ │ │ │ │ ├── segment.cpython-312.pyc
│ │ │ │ │ │ ├── spinner.cpython-312.pyc
│ │ │ │ │ │ ├── status.cpython-312.pyc
│ │ │ │ │ │ ├── style.cpython-312.pyc
│ │ │ │ │ │ ├── styled.cpython-312.pyc
│ │ │ │ │ │ ├── syntax.cpython-312.pyc
│ │ │ │ │ │ ├── table.cpython-312.pyc
│ │ │ │ │ │ ├── terminal_theme.cpython-312.pyc
│ │ │ │ │ │ ├── text.cpython-312.pyc
│ │ │ │ │ │ ├── theme.cpython-312.pyc
│ │ │ │ │ │ ├── themes.cpython-312.pyc
│ │ │ │ │ │ ├── traceback.cpython-312.pyc
│ │ │ │ │ │ └── tree.cpython-312.pyc
│ │ │ │ │ ├── _cell_widths.py
│ │ │ │ │ ├── _emoji_codes.py
│ │ │ │ │ ├── _emoji_replace.py
│ │ │ │ │ ├── _export_format.py
│ │ │ │ │ ├── _extension.py
│ │ │ │ │ ├── _fileno.py
│ │ │ │ │ ├── _inspect.py
│ │ │ │ │ ├── _log_render.py
│ │ │ │ │ ├── _loop.py
│ │ │ │ │ ├── _null_file.py
│ │ │ │ │ ├── _palettes.py
│ │ │ │ │ ├── _pick.py
│ │ │ │ │ ├── _ratio.py
│ │ │ │ │ ├── _spinners.py
│ │ │ │ │ ├── _stack.py
│ │ │ │ │ ├── _timer.py
│ │ │ │ │ ├── _win32_console.py
│ │ │ │ │ ├── _windows_renderer.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ ├── _wrap.py
│ │ │ │ │ ├── abc.py
│ │ │ │ │ ├── align.py
│ │ │ │ │ ├── ansi.py
│ │ │ │ │ ├── bar.py
│ │ │ │ │ ├── box.py
│ │ │ │ │ ├── cells.py
│ │ │ │ │ ├── color_triplet.py
│ │ │ │ │ ├── color.py
│ │ │ │ │ ├── columns.py
│ │ │ │ │ ├── console.py
│ │ │ │ │ ├── constrain.py
│ │ │ │ │ ├── containers.py
│ │ │ │ │ ├── control.py
│ │ │ │ │ ├── default_styles.py
│ │ │ │ │ ├── diagnose.py
│ │ │ │ │ ├── emoji.py
│ │ │ │ │ ├── errors.py
│ │ │ │ │ ├── file_proxy.py
│ │ │ │ │ ├── filesize.py
│ │ │ │ │ ├── highlighter.py
│ │ │ │ │ ├── json.py
│ │ │ │ │ ├── jupyter.py
│ │ │ │ │ ├── layout.py
│ │ │ │ │ ├── live_render.py
│ │ │ │ │ ├── live.py
│ │ │ │ │ ├── logging.py
│ │ │ │ │ ├── markup.py
│ │ │ │ │ ├── measure.py
│ │ │ │ │ ├── padding.py
│ │ │ │ │ ├── pager.py
│ │ │ │ │ ├── palette.py
│ │ │ │ │ ├── panel.py
│ │ │ │ │ ├── pretty.py
│ │ │ │ │ ├── progress_bar.py
│ │ │ │ │ ├── progress.py
│ │ │ │ │ ├── prompt.py
│ │ │ │ │ ├── protocol.py
│ │ │ │ │ ├── py.typed
│ │ │ │ │ ├── region.py
│ │ │ │ │ ├── repr.py
│ │ │ │ │ ├── rule.py
│ │ │ │ │ ├── scope.py
│ │ │ │ │ ├── screen.py
│ │ │ │ │ ├── segment.py
│ │ │ │ │ ├── spinner.py
│ │ │ │ │ ├── status.py
│ │ │ │ │ ├── style.py
│ │ │ │ │ ├── styled.py
│ │ │ │ │ ├── syntax.py
│ │ │ │ │ ├── table.py
│ │ │ │ │ ├── terminal_theme.py
│ │ │ │ │ ├── text.py
│ │ │ │ │ ├── theme.py
│ │ │ │ │ ├── themes.py
│ │ │ │ │ ├── traceback.py
│ │ │ │ │ └── tree.py
│ │ │ │ ├── tomli
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _parser.cpython-312.pyc
│ │ │ │ │ │ ├── _re.cpython-312.pyc
│ │ │ │ │ │ └── _types.cpython-312.pyc
│ │ │ │ │ ├── _parser.py
│ │ │ │ │ ├── _re.py
│ │ │ │ │ ├── _types.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── truststore
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _api.cpython-312.pyc
│ │ │ │ │ │ ├── _macos.cpython-312.pyc
│ │ │ │ │ │ ├── _openssl.cpython-312.pyc
│ │ │ │ │ │ ├── _ssl_constants.cpython-312.pyc
│ │ │ │ │ │ └── _windows.cpython-312.pyc
│ │ │ │ │ ├── _api.py
│ │ │ │ │ ├── _macos.py
│ │ │ │ │ ├── _openssl.py
│ │ │ │ │ ├── _ssl_constants.py
│ │ │ │ │ ├── _windows.py
│ │ │ │ │ └── py.typed
│ │ │ │ ├── typing_extensions.py
│ │ │ │ ├── urllib3
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── _collections.py
│ │ │ │ │ ├── _version.py
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── connectionpool.py
│ │ │ │ │ ├── contrib
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ ├── _appengine_environ.cpython-312.pyc
│ │ │ │ │ │ │ ├── appengine.cpython-312.pyc
│ │ │ │ │ │ │ ├── ntlmpool.cpython-312.pyc
│ │ │ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ │ │ ├── securetransport.cpython-312.pyc
│ │ │ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ │ │ ├── _appengine_environ.py
│ │ │ │ │ │ ├── _securetransport
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── bindings.cpython-312.pyc
│ │ │ │ │ │ │ │ └── low_level.cpython-312.pyc
│ │ │ │ │ │ │ ├── bindings.py
│ │ │ │ │ │ │ └── low_level.py
│ │ │ │ │ │ ├── appengine.py
│ │ │ │ │ │ ├── ntlmpool.py
│ │ │ │ │ │ ├── pyopenssl.py
│ │ │ │ │ │ ├── securetransport.py
│ │ │ │ │ │ └── socks.py
│ │ │ │ │ ├── exceptions.py
│ │ │ │ │ ├── fields.py
│ │ │ │ │ ├── filepost.py
│ │ │ │ │ ├── packages
│ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ └── six.cpython-312.pyc
│ │ │ │ │ │ ├── backports
│ │ │ │ │ │ │ ├── __init__.py
│ │ │ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ │ │ ├── makefile.cpython-312.pyc
│ │ │ │ │ │ │ │ └── weakref_finalize.cpython-312.pyc
│ │ │ │ │ │ │ ├── makefile.py
│ │ │ │ │ │ │ └── weakref_finalize.py
│ │ │ │ │ │ └── six.py
│ │ │ │ │ ├── poolmanager.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ └── util
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ │ │ ├── queue.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ │ │ └── wait.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── proxy.py
│ │ │ │ │ ├── queue.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ ├── response.py
│ │ │ │ │ ├── retry.py
│ │ │ │ │ ├── ssl_.py
│ │ │ │ │ ├── ssl_match_hostname.py
│ │ │ │ │ ├── ssltransport.py
│ │ │ │ │ ├── timeout.py
│ │ │ │ │ ├── url.py
│ │ │ │ │ └── wait.py
│ │ │ │ └── vendor.txt
│ │ │ └── py.typed
│ │ ├── pip-24.2.dist-info
│ │ │ ├── AUTHORS.txt
│ │ │ ├── entry_points.txt
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── requests
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __version__.cpython-312.pyc
│ │ │ │ ├── _internal_utils.cpython-312.pyc
│ │ │ │ ├── adapters.cpython-312.pyc
│ │ │ │ ├── api.cpython-312.pyc
│ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ ├── certs.cpython-312.pyc
│ │ │ │ ├── compat.cpython-312.pyc
│ │ │ │ ├── cookies.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── help.cpython-312.pyc
│ │ │ │ ├── hooks.cpython-312.pyc
│ │ │ │ ├── models.cpython-312.pyc
│ │ │ │ ├── packages.cpython-312.pyc
│ │ │ │ ├── sessions.cpython-312.pyc
│ │ │ │ ├── status_codes.cpython-312.pyc
│ │ │ │ ├── structures.cpython-312.pyc
│ │ │ │ └── utils.cpython-312.pyc
│ │ │ ├── __version__.py
│ │ │ ├── _internal_utils.py
│ │ │ ├── adapters.py
│ │ │ ├── api.py
│ │ │ ├── auth.py
│ │ │ ├── certs.py
│ │ │ ├── compat.py
│ │ │ ├── cookies.py
│ │ │ ├── exceptions.py
│ │ │ ├── help.py
│ │ │ ├── hooks.py
│ │ │ ├── models.py
│ │ │ ├── packages.py
│ │ │ ├── sessions.py
│ │ │ ├── status_codes.py
│ │ │ ├── structures.py
│ │ │ └── utils.py
│ │ ├── requests-2.32.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── soupsieve
│ │ │ ├── __init__.py
│ │ │ ├── __meta__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── __meta__.cpython-312.pyc
│ │ │ │ ├── css_match.cpython-312.pyc
│ │ │ │ ├── css_parser.cpython-312.pyc
│ │ │ │ ├── css_types.cpython-312.pyc
│ │ │ │ ├── pretty.cpython-312.pyc
│ │ │ │ └── util.cpython-312.pyc
│ │ │ ├── css_match.py
│ │ │ ├── css_parser.py
│ │ │ ├── css_types.py
│ │ │ ├── pretty.py
│ │ │ ├── py.typed
│ │ │ └── util.py
│ │ ├── soupsieve-2.6.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.md
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── urllib3
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _base_connection.cpython-312.pyc
│ │ │ │ ├── _collections.cpython-312.pyc
│ │ │ │ ├── _request_methods.cpython-312.pyc
│ │ │ │ ├── _version.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── connectionpool.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── fields.cpython-312.pyc
│ │ │ │ ├── filepost.cpython-312.pyc
│ │ │ │ ├── poolmanager.cpython-312.pyc
│ │ │ │ └── response.cpython-312.pyc
│ │ │ ├── _base_connection.py
│ │ │ ├── _collections.py
│ │ │ ├── _request_methods.py
│ │ │ ├── _version.py
│ │ │ ├── connection.py
│ │ │ ├── connectionpool.py
│ │ │ ├── contrib
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── pyopenssl.cpython-312.pyc
│ │ │ │ │ └── socks.cpython-312.pyc
│ │ │ │ ├── emscripten
│ │ │ │ │ ├── __init__.py
│ │ │ │ │ ├── __pycache__
│ │ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ │ ├── fetch.cpython-312.pyc
│ │ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ │ ├── connection.py
│ │ │ │ │ ├── emscripten_fetch_worker.js
│ │ │ │ │ ├── fetch.py
│ │ │ │ │ ├── request.py
│ │ │ │ │ └── response.py
│ │ │ │ ├── pyopenssl.py
│ │ │ │ └── socks.py
│ │ │ ├── exceptions.py
│ │ │ ├── fields.py
│ │ │ ├── filepost.py
│ │ │ ├── http2
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ │ └── probe.cpython-312.pyc
│ │ │ │ ├── connection.py
│ │ │ │ └── probe.py
│ │ │ ├── poolmanager.py
│ │ │ ├── py.typed
│ │ │ ├── response.py
│ │ │ └── util
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── connection.cpython-312.pyc
│ │ │ │ ├── proxy.cpython-312.pyc
│ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ ├── retry.cpython-312.pyc
│ │ │ │ ├── ssl_.cpython-312.pyc
│ │ │ │ ├── ssl_match_hostname.cpython-312.pyc
│ │ │ │ ├── ssltransport.cpython-312.pyc
│ │ │ │ ├── timeout.cpython-312.pyc
│ │ │ │ ├── url.cpython-312.pyc
│ │ │ │ ├── util.cpython-312.pyc
│ │ │ │ └── wait.cpython-312.pyc
│ │ │ ├── connection.py
│ │ │ ├── proxy.py
│ │ │ ├── request.py
│ │ │ ├── response.py
│ │ │ ├── retry.py
│ │ │ ├── ssl_.py
│ │ │ ├── ssl_match_hostname.py
│ │ │ ├── ssltransport.py
│ │ │ ├── timeout.py
│ │ │ ├── url.py
│ │ │ ├── util.py
│ │ │ └── wait.py
│ │ ├── urllib3-2.2.3.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── licenses
│ │ │ │ └── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ └── WHEEL
│ │ ├── useragent
│ │ │ ├── __init__.py
│ │ │ ├── __init__.pyc
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── resources
│ │ │ │ └── user_agent_data.json
│ │ │ └── test
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ └── __init__.cpython-312.pyc
│ │ │ ├── test_additional_os.json
│ │ │ ├── test_browser.json
│ │ │ ├── test_device.json
│ │ │ ├── test_firefox.json
│ │ │ ├── test_os.json
│ │ │ └── test_pgts_browser.json
│ │ ├── useragent-0.1.1.dist-info
│ │ │ ├── INSTALLER
│ │ │ ├── LICENSE.txt
│ │ │ ├── METADATA
│ │ │ ├── RECORD
│ │ │ ├── REQUESTED
│ │ │ ├── top_level.txt
│ │ │ └── WHEEL
│ │ ├── werkzeug
│ │ │ ├── __init__.py
│ │ │ ├── __pycache__
│ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ ├── _internal.cpython-312.pyc
│ │ │ │ ├── _reloader.cpython-312.pyc
│ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ ├── formparser.cpython-312.pyc
│ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ ├── local.cpython-312.pyc
│ │ │ │ ├── security.cpython-312.pyc
│ │ │ │ ├── serving.cpython-312.pyc
│ │ │ │ ├── test.cpython-312.pyc
│ │ │ │ ├── testapp.cpython-312.pyc
│ │ │ │ ├── urls.cpython-312.pyc
│ │ │ │ ├── user_agent.cpython-312.pyc
│ │ │ │ ├── utils.cpython-312.pyc
│ │ │ │ └── wsgi.cpython-312.pyc
│ │ │ ├── _internal.py
│ │ │ ├── _reloader.py
│ │ │ ├── datastructures
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── accept.cpython-312.pyc
│ │ │ │ │ ├── auth.cpython-312.pyc
│ │ │ │ │ ├── cache_control.cpython-312.pyc
│ │ │ │ │ ├── csp.cpython-312.pyc
│ │ │ │ │ ├── etag.cpython-312.pyc
│ │ │ │ │ ├── file_storage.cpython-312.pyc
│ │ │ │ │ ├── headers.cpython-312.pyc
│ │ │ │ │ ├── mixins.cpython-312.pyc
│ │ │ │ │ ├── range.cpython-312.pyc
│ │ │ │ │ └── structures.cpython-312.pyc
│ │ │ │ ├── accept.py
│ │ │ │ ├── accept.pyi
│ │ │ │ ├── auth.py
│ │ │ │ ├── cache_control.py
│ │ │ │ ├── cache_control.pyi
│ │ │ │ ├── csp.py
│ │ │ │ ├── csp.pyi
│ │ │ │ ├── etag.py
│ │ │ │ ├── etag.pyi
│ │ │ │ ├── file_storage.py
│ │ │ │ ├── file_storage.pyi
│ │ │ │ ├── headers.py
│ │ │ │ ├── headers.pyi
│ │ │ │ ├── mixins.py
│ │ │ │ ├── mixins.pyi
│ │ │ │ ├── range.py
│ │ │ │ ├── range.pyi
│ │ │ │ ├── structures.py
│ │ │ │ └── structures.pyi
│ │ │ ├── debug
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── console.cpython-312.pyc
│ │ │ │ │ ├── repr.cpython-312.pyc
│ │ │ │ │ └── tbtools.cpython-312.pyc
│ │ │ │ ├── console.py
│ │ │ │ ├── repr.py
│ │ │ │ ├── shared
│ │ │ │ │ ├── console.png
│ │ │ │ │ ├── debugger.js
│ │ │ │ │ ├── ICON_LICENSE.md
│ │ │ │ │ ├── less.png
│ │ │ │ │ ├── more.png
│ │ │ │ │ └── style.css
│ │ │ │ └── tbtools.py
│ │ │ ├── exceptions.py
│ │ │ ├── formparser.py
│ │ │ ├── http.py
│ │ │ ├── local.py
│ │ │ ├── middleware
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── dispatcher.cpython-312.pyc
│ │ │ │ │ ├── http_proxy.cpython-312.pyc
│ │ │ │ │ ├── lint.cpython-312.pyc
│ │ │ │ │ ├── profiler.cpython-312.pyc
│ │ │ │ │ ├── proxy_fix.cpython-312.pyc
│ │ │ │ │ └── shared_data.cpython-312.pyc
│ │ │ │ ├── dispatcher.py
│ │ │ │ ├── http_proxy.py
│ │ │ │ ├── lint.py
│ │ │ │ ├── profiler.py
│ │ │ │ ├── proxy_fix.py
│ │ │ │ └── shared_data.py
│ │ │ ├── py.typed
│ │ │ ├── routing
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── converters.cpython-312.pyc
│ │ │ │ │ ├── exceptions.cpython-312.pyc
│ │ │ │ │ ├── map.cpython-312.pyc
│ │ │ │ │ ├── matcher.cpython-312.pyc
│ │ │ │ │ └── rules.cpython-312.pyc
│ │ │ │ ├── converters.py
│ │ │ │ ├── exceptions.py
│ │ │ │ ├── map.py
│ │ │ │ ├── matcher.py
│ │ │ │ └── rules.py
│ │ │ ├── sansio
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── http.cpython-312.pyc
│ │ │ │ │ ├── multipart.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ ├── response.cpython-312.pyc
│ │ │ │ │ └── utils.cpython-312.pyc
│ │ │ │ ├── http.py
│ │ │ │ ├── multipart.py
│ │ │ │ ├── request.py
│ │ │ │ ├── response.py
│ │ │ │ └── utils.py
│ │ │ ├── security.py
│ │ │ ├── serving.py
│ │ │ ├── test.py
│ │ │ ├── testapp.py
│ │ │ ├── urls.py
│ │ │ ├── user_agent.py
│ │ │ ├── utils.py
│ │ │ ├── wrappers
│ │ │ │ ├── __init__.py
│ │ │ │ ├── __pycache__
│ │ │ │ │ ├── __init__.cpython-312.pyc
│ │ │ │ │ ├── request.cpython-312.pyc
│ │ │ │ │ └── response.cpython-312.pyc
│ │ │ │ ├── request.py
│ │ │ │ └── response.py
│ │ │ └── wsgi.py
│ │ └── werkzeug-3.0.4.dist-info
│ │ ├── INSTALLER
│ │ ├── LICENSE.txt
│ │ ├── METADATA
│ │ ├── RECORD
│ │ └── WHEEL
│ ├── pyvenv.cfg
│ ├── static
│ │ └── styles.css
│ ├── templates
│ │ └── index.html
│ └── test.py
├── cline_config.json
├── mcp_server.py
├── README.md
├── search_results.json
├── settings.json
└── test_files
├── text1.txt
└── text2.txt
```
# Files
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/controller.py:
--------------------------------------------------------------------------------
```python
1 | # SPDX-FileCopyrightText: 2015 Eric Larson
2 | #
3 | # SPDX-License-Identifier: Apache-2.0
4 |
5 | """
6 | The httplib2 algorithms ported for use with requests.
7 | """
8 | from __future__ import annotations
9 |
10 | import calendar
11 | import logging
12 | import re
13 | import time
14 | from email.utils import parsedate_tz
15 | from typing import TYPE_CHECKING, Collection, Mapping
16 |
17 | from pip._vendor.requests.structures import CaseInsensitiveDict
18 |
19 | from pip._vendor.cachecontrol.cache import DictCache, SeparateBodyBaseCache
20 | from pip._vendor.cachecontrol.serialize import Serializer
21 |
22 | if TYPE_CHECKING:
23 | from typing import Literal
24 |
25 | from pip._vendor.requests import PreparedRequest
26 | from pip._vendor.urllib3 import HTTPResponse
27 |
28 | from pip._vendor.cachecontrol.cache import BaseCache
29 |
30 | logger = logging.getLogger(__name__)
31 |
32 | URI = re.compile(r"^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?")
33 |
34 | PERMANENT_REDIRECT_STATUSES = (301, 308)
35 |
36 |
37 | def parse_uri(uri: str) -> tuple[str, str, str, str, str]:
38 | """Parses a URI using the regex given in Appendix B of RFC 3986.
39 |
40 | (scheme, authority, path, query, fragment) = parse_uri(uri)
41 | """
42 | match = URI.match(uri)
43 | assert match is not None
44 | groups = match.groups()
45 | return (groups[1], groups[3], groups[4], groups[6], groups[8])
46 |
47 |
48 | class CacheController:
49 | """An interface to see if request should cached or not."""
50 |
51 | def __init__(
52 | self,
53 | cache: BaseCache | None = None,
54 | cache_etags: bool = True,
55 | serializer: Serializer | None = None,
56 | status_codes: Collection[int] | None = None,
57 | ):
58 | self.cache = DictCache() if cache is None else cache
59 | self.cache_etags = cache_etags
60 | self.serializer = serializer or Serializer()
61 | self.cacheable_status_codes = status_codes or (200, 203, 300, 301, 308)
62 |
63 | @classmethod
64 | def _urlnorm(cls, uri: str) -> str:
65 | """Normalize the URL to create a safe key for the cache"""
66 | (scheme, authority, path, query, fragment) = parse_uri(uri)
67 | if not scheme or not authority:
68 | raise Exception("Only absolute URIs are allowed. uri = %s" % uri)
69 |
70 | scheme = scheme.lower()
71 | authority = authority.lower()
72 |
73 | if not path:
74 | path = "/"
75 |
76 | # Could do syntax based normalization of the URI before
77 | # computing the digest. See Section 6.2.2 of Std 66.
78 | request_uri = query and "?".join([path, query]) or path
79 | defrag_uri = scheme + "://" + authority + request_uri
80 |
81 | return defrag_uri
82 |
83 | @classmethod
84 | def cache_url(cls, uri: str) -> str:
85 | return cls._urlnorm(uri)
86 |
87 | def parse_cache_control(self, headers: Mapping[str, str]) -> dict[str, int | None]:
88 | known_directives = {
89 | # https://tools.ietf.org/html/rfc7234#section-5.2
90 | "max-age": (int, True),
91 | "max-stale": (int, False),
92 | "min-fresh": (int, True),
93 | "no-cache": (None, False),
94 | "no-store": (None, False),
95 | "no-transform": (None, False),
96 | "only-if-cached": (None, False),
97 | "must-revalidate": (None, False),
98 | "public": (None, False),
99 | "private": (None, False),
100 | "proxy-revalidate": (None, False),
101 | "s-maxage": (int, True),
102 | }
103 |
104 | cc_headers = headers.get("cache-control", headers.get("Cache-Control", ""))
105 |
106 | retval: dict[str, int | None] = {}
107 |
108 | for cc_directive in cc_headers.split(","):
109 | if not cc_directive.strip():
110 | continue
111 |
112 | parts = cc_directive.split("=", 1)
113 | directive = parts[0].strip()
114 |
115 | try:
116 | typ, required = known_directives[directive]
117 | except KeyError:
118 | logger.debug("Ignoring unknown cache-control directive: %s", directive)
119 | continue
120 |
121 | if not typ or not required:
122 | retval[directive] = None
123 | if typ:
124 | try:
125 | retval[directive] = typ(parts[1].strip())
126 | except IndexError:
127 | if required:
128 | logger.debug(
129 | "Missing value for cache-control " "directive: %s",
130 | directive,
131 | )
132 | except ValueError:
133 | logger.debug(
134 | "Invalid value for cache-control directive " "%s, must be %s",
135 | directive,
136 | typ.__name__,
137 | )
138 |
139 | return retval
140 |
141 | def _load_from_cache(self, request: PreparedRequest) -> HTTPResponse | None:
142 | """
143 | Load a cached response, or return None if it's not available.
144 | """
145 | # We do not support caching of partial content: so if the request contains a
146 | # Range header then we don't want to load anything from the cache.
147 | if "Range" in request.headers:
148 | return None
149 |
150 | cache_url = request.url
151 | assert cache_url is not None
152 | cache_data = self.cache.get(cache_url)
153 | if cache_data is None:
154 | logger.debug("No cache entry available")
155 | return None
156 |
157 | if isinstance(self.cache, SeparateBodyBaseCache):
158 | body_file = self.cache.get_body(cache_url)
159 | else:
160 | body_file = None
161 |
162 | result = self.serializer.loads(request, cache_data, body_file)
163 | if result is None:
164 | logger.warning("Cache entry deserialization failed, entry ignored")
165 | return result
166 |
167 | def cached_request(self, request: PreparedRequest) -> HTTPResponse | Literal[False]:
168 | """
169 | Return a cached response if it exists in the cache, otherwise
170 | return False.
171 | """
172 | assert request.url is not None
173 | cache_url = self.cache_url(request.url)
174 | logger.debug('Looking up "%s" in the cache', cache_url)
175 | cc = self.parse_cache_control(request.headers)
176 |
177 | # Bail out if the request insists on fresh data
178 | if "no-cache" in cc:
179 | logger.debug('Request header has "no-cache", cache bypassed')
180 | return False
181 |
182 | if "max-age" in cc and cc["max-age"] == 0:
183 | logger.debug('Request header has "max_age" as 0, cache bypassed')
184 | return False
185 |
186 | # Check whether we can load the response from the cache:
187 | resp = self._load_from_cache(request)
188 | if not resp:
189 | return False
190 |
191 | # If we have a cached permanent redirect, return it immediately. We
192 | # don't need to test our response for other headers b/c it is
193 | # intrinsically "cacheable" as it is Permanent.
194 | #
195 | # See:
196 | # https://tools.ietf.org/html/rfc7231#section-6.4.2
197 | #
198 | # Client can try to refresh the value by repeating the request
199 | # with cache busting headers as usual (ie no-cache).
200 | if int(resp.status) in PERMANENT_REDIRECT_STATUSES:
201 | msg = (
202 | "Returning cached permanent redirect response "
203 | "(ignoring date and etag information)"
204 | )
205 | logger.debug(msg)
206 | return resp
207 |
208 | headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(resp.headers)
209 | if not headers or "date" not in headers:
210 | if "etag" not in headers:
211 | # Without date or etag, the cached response can never be used
212 | # and should be deleted.
213 | logger.debug("Purging cached response: no date or etag")
214 | self.cache.delete(cache_url)
215 | logger.debug("Ignoring cached response: no date")
216 | return False
217 |
218 | now = time.time()
219 | time_tuple = parsedate_tz(headers["date"])
220 | assert time_tuple is not None
221 | date = calendar.timegm(time_tuple[:6])
222 | current_age = max(0, now - date)
223 | logger.debug("Current age based on date: %i", current_age)
224 |
225 | # TODO: There is an assumption that the result will be a
226 | # urllib3 response object. This may not be best since we
227 | # could probably avoid instantiating or constructing the
228 | # response until we know we need it.
229 | resp_cc = self.parse_cache_control(headers)
230 |
231 | # determine freshness
232 | freshness_lifetime = 0
233 |
234 | # Check the max-age pragma in the cache control header
235 | max_age = resp_cc.get("max-age")
236 | if max_age is not None:
237 | freshness_lifetime = max_age
238 | logger.debug("Freshness lifetime from max-age: %i", freshness_lifetime)
239 |
240 | # If there isn't a max-age, check for an expires header
241 | elif "expires" in headers:
242 | expires = parsedate_tz(headers["expires"])
243 | if expires is not None:
244 | expire_time = calendar.timegm(expires[:6]) - date
245 | freshness_lifetime = max(0, expire_time)
246 | logger.debug("Freshness lifetime from expires: %i", freshness_lifetime)
247 |
248 | # Determine if we are setting freshness limit in the
249 | # request. Note, this overrides what was in the response.
250 | max_age = cc.get("max-age")
251 | if max_age is not None:
252 | freshness_lifetime = max_age
253 | logger.debug(
254 | "Freshness lifetime from request max-age: %i", freshness_lifetime
255 | )
256 |
257 | min_fresh = cc.get("min-fresh")
258 | if min_fresh is not None:
259 | # adjust our current age by our min fresh
260 | current_age += min_fresh
261 | logger.debug("Adjusted current age from min-fresh: %i", current_age)
262 |
263 | # Return entry if it is fresh enough
264 | if freshness_lifetime > current_age:
265 | logger.debug('The response is "fresh", returning cached response')
266 | logger.debug("%i > %i", freshness_lifetime, current_age)
267 | return resp
268 |
269 | # we're not fresh. If we don't have an Etag, clear it out
270 | if "etag" not in headers:
271 | logger.debug('The cached response is "stale" with no etag, purging')
272 | self.cache.delete(cache_url)
273 |
274 | # return the original handler
275 | return False
276 |
277 | def conditional_headers(self, request: PreparedRequest) -> dict[str, str]:
278 | resp = self._load_from_cache(request)
279 | new_headers = {}
280 |
281 | if resp:
282 | headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(resp.headers)
283 |
284 | if "etag" in headers:
285 | new_headers["If-None-Match"] = headers["ETag"]
286 |
287 | if "last-modified" in headers:
288 | new_headers["If-Modified-Since"] = headers["Last-Modified"]
289 |
290 | return new_headers
291 |
292 | def _cache_set(
293 | self,
294 | cache_url: str,
295 | request: PreparedRequest,
296 | response: HTTPResponse,
297 | body: bytes | None = None,
298 | expires_time: int | None = None,
299 | ) -> None:
300 | """
301 | Store the data in the cache.
302 | """
303 | if isinstance(self.cache, SeparateBodyBaseCache):
304 | # We pass in the body separately; just put a placeholder empty
305 | # string in the metadata.
306 | self.cache.set(
307 | cache_url,
308 | self.serializer.dumps(request, response, b""),
309 | expires=expires_time,
310 | )
311 | # body is None can happen when, for example, we're only updating
312 | # headers, as is the case in update_cached_response().
313 | if body is not None:
314 | self.cache.set_body(cache_url, body)
315 | else:
316 | self.cache.set(
317 | cache_url,
318 | self.serializer.dumps(request, response, body),
319 | expires=expires_time,
320 | )
321 |
322 | def cache_response(
323 | self,
324 | request: PreparedRequest,
325 | response: HTTPResponse,
326 | body: bytes | None = None,
327 | status_codes: Collection[int] | None = None,
328 | ) -> None:
329 | """
330 | Algorithm for caching requests.
331 |
332 | This assumes a requests Response object.
333 | """
334 | # From httplib2: Don't cache 206's since we aren't going to
335 | # handle byte range requests
336 | cacheable_status_codes = status_codes or self.cacheable_status_codes
337 | if response.status not in cacheable_status_codes:
338 | logger.debug(
339 | "Status code %s not in %s", response.status, cacheable_status_codes
340 | )
341 | return
342 |
343 | response_headers: CaseInsensitiveDict[str] = CaseInsensitiveDict(
344 | response.headers
345 | )
346 |
347 | if "date" in response_headers:
348 | time_tuple = parsedate_tz(response_headers["date"])
349 | assert time_tuple is not None
350 | date = calendar.timegm(time_tuple[:6])
351 | else:
352 | date = 0
353 |
354 | # If we've been given a body, our response has a Content-Length, that
355 | # Content-Length is valid then we can check to see if the body we've
356 | # been given matches the expected size, and if it doesn't we'll just
357 | # skip trying to cache it.
358 | if (
359 | body is not None
360 | and "content-length" in response_headers
361 | and response_headers["content-length"].isdigit()
362 | and int(response_headers["content-length"]) != len(body)
363 | ):
364 | return
365 |
366 | cc_req = self.parse_cache_control(request.headers)
367 | cc = self.parse_cache_control(response_headers)
368 |
369 | assert request.url is not None
370 | cache_url = self.cache_url(request.url)
371 | logger.debug('Updating cache with response from "%s"', cache_url)
372 |
373 | # Delete it from the cache if we happen to have it stored there
374 | no_store = False
375 | if "no-store" in cc:
376 | no_store = True
377 | logger.debug('Response header has "no-store"')
378 | if "no-store" in cc_req:
379 | no_store = True
380 | logger.debug('Request header has "no-store"')
381 | if no_store and self.cache.get(cache_url):
382 | logger.debug('Purging existing cache entry to honor "no-store"')
383 | self.cache.delete(cache_url)
384 | if no_store:
385 | return
386 |
387 | # https://tools.ietf.org/html/rfc7234#section-4.1:
388 | # A Vary header field-value of "*" always fails to match.
389 | # Storing such a response leads to a deserialization warning
390 | # during cache lookup and is not allowed to ever be served,
391 | # so storing it can be avoided.
392 | if "*" in response_headers.get("vary", ""):
393 | logger.debug('Response header has "Vary: *"')
394 | return
395 |
396 | # If we've been given an etag, then keep the response
397 | if self.cache_etags and "etag" in response_headers:
398 | expires_time = 0
399 | if response_headers.get("expires"):
400 | expires = parsedate_tz(response_headers["expires"])
401 | if expires is not None:
402 | expires_time = calendar.timegm(expires[:6]) - date
403 |
404 | expires_time = max(expires_time, 14 * 86400)
405 |
406 | logger.debug(f"etag object cached for {expires_time} seconds")
407 | logger.debug("Caching due to etag")
408 | self._cache_set(cache_url, request, response, body, expires_time)
409 |
410 | # Add to the cache any permanent redirects. We do this before looking
411 | # that the Date headers.
412 | elif int(response.status) in PERMANENT_REDIRECT_STATUSES:
413 | logger.debug("Caching permanent redirect")
414 | self._cache_set(cache_url, request, response, b"")
415 |
416 | # Add to the cache if the response headers demand it. If there
417 | # is no date header then we can't do anything about expiring
418 | # the cache.
419 | elif "date" in response_headers:
420 | time_tuple = parsedate_tz(response_headers["date"])
421 | assert time_tuple is not None
422 | date = calendar.timegm(time_tuple[:6])
423 | # cache when there is a max-age > 0
424 | max_age = cc.get("max-age")
425 | if max_age is not None and max_age > 0:
426 | logger.debug("Caching b/c date exists and max-age > 0")
427 | expires_time = max_age
428 | self._cache_set(
429 | cache_url,
430 | request,
431 | response,
432 | body,
433 | expires_time,
434 | )
435 |
436 | # If the request can expire, it means we should cache it
437 | # in the meantime.
438 | elif "expires" in response_headers:
439 | if response_headers["expires"]:
440 | expires = parsedate_tz(response_headers["expires"])
441 | if expires is not None:
442 | expires_time = calendar.timegm(expires[:6]) - date
443 | else:
444 | expires_time = None
445 |
446 | logger.debug(
447 | "Caching b/c of expires header. expires in {} seconds".format(
448 | expires_time
449 | )
450 | )
451 | self._cache_set(
452 | cache_url,
453 | request,
454 | response,
455 | body,
456 | expires_time,
457 | )
458 |
459 | def update_cached_response(
460 | self, request: PreparedRequest, response: HTTPResponse
461 | ) -> HTTPResponse:
462 | """On a 304 we will get a new set of headers that we want to
463 | update our cached value with, assuming we have one.
464 |
465 | This should only ever be called when we've sent an ETag and
466 | gotten a 304 as the response.
467 | """
468 | assert request.url is not None
469 | cache_url = self.cache_url(request.url)
470 | cached_response = self._load_from_cache(request)
471 |
472 | if not cached_response:
473 | # we didn't have a cached response
474 | return response
475 |
476 | # Lets update our headers with the headers from the new request:
477 | # http://tools.ietf.org/html/draft-ietf-httpbis-p4-conditional-26#section-4.1
478 | #
479 | # The server isn't supposed to send headers that would make
480 | # the cached body invalid. But... just in case, we'll be sure
481 | # to strip out ones we know that might be problmatic due to
482 | # typical assumptions.
483 | excluded_headers = ["content-length"]
484 |
485 | cached_response.headers.update(
486 | {
487 | k: v
488 | for k, v in response.headers.items()
489 | if k.lower() not in excluded_headers
490 | }
491 | )
492 |
493 | # we want a 200 b/c we have content via the cache
494 | cached_response.status = 200
495 |
496 | # update our cache
497 | self._cache_set(cache_url, request, cached_response)
498 |
499 | return cached_response
500 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | requests.cookies
3 | ~~~~~~~~~~~~~~~~
4 |
5 | Compatibility code to be able to use `http.cookiejar.CookieJar` with requests.
6 |
7 | requests.utils imports from here, so be careful with imports.
8 | """
9 |
10 | import calendar
11 | import copy
12 | import time
13 |
14 | from ._internal_utils import to_native_string
15 | from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse
16 |
17 | try:
18 | import threading
19 | except ImportError:
20 | import dummy_threading as threading
21 |
22 |
23 | class MockRequest:
24 | """Wraps a `requests.Request` to mimic a `urllib2.Request`.
25 |
26 | The code in `http.cookiejar.CookieJar` expects this interface in order to correctly
27 | manage cookie policies, i.e., determine whether a cookie can be set, given the
28 | domains of the request and the cookie.
29 |
30 | The original request object is read-only. The client is responsible for collecting
31 | the new headers via `get_new_headers()` and interpreting them appropriately. You
32 | probably want `get_cookie_header`, defined below.
33 | """
34 |
35 | def __init__(self, request):
36 | self._r = request
37 | self._new_headers = {}
38 | self.type = urlparse(self._r.url).scheme
39 |
40 | def get_type(self):
41 | return self.type
42 |
43 | def get_host(self):
44 | return urlparse(self._r.url).netloc
45 |
46 | def get_origin_req_host(self):
47 | return self.get_host()
48 |
49 | def get_full_url(self):
50 | # Only return the response's URL if the user hadn't set the Host
51 | # header
52 | if not self._r.headers.get("Host"):
53 | return self._r.url
54 | # If they did set it, retrieve it and reconstruct the expected domain
55 | host = to_native_string(self._r.headers["Host"], encoding="utf-8")
56 | parsed = urlparse(self._r.url)
57 | # Reconstruct the URL as we expect it
58 | return urlunparse(
59 | [
60 | parsed.scheme,
61 | host,
62 | parsed.path,
63 | parsed.params,
64 | parsed.query,
65 | parsed.fragment,
66 | ]
67 | )
68 |
69 | def is_unverifiable(self):
70 | return True
71 |
72 | def has_header(self, name):
73 | return name in self._r.headers or name in self._new_headers
74 |
75 | def get_header(self, name, default=None):
76 | return self._r.headers.get(name, self._new_headers.get(name, default))
77 |
78 | def add_header(self, key, val):
79 | """cookiejar has no legitimate use for this method; add it back if you find one."""
80 | raise NotImplementedError(
81 | "Cookie headers should be added with add_unredirected_header()"
82 | )
83 |
84 | def add_unredirected_header(self, name, value):
85 | self._new_headers[name] = value
86 |
87 | def get_new_headers(self):
88 | return self._new_headers
89 |
90 | @property
91 | def unverifiable(self):
92 | return self.is_unverifiable()
93 |
94 | @property
95 | def origin_req_host(self):
96 | return self.get_origin_req_host()
97 |
98 | @property
99 | def host(self):
100 | return self.get_host()
101 |
102 |
103 | class MockResponse:
104 | """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
105 |
106 | ...what? Basically, expose the parsed HTTP headers from the server response
107 | the way `http.cookiejar` expects to see them.
108 | """
109 |
110 | def __init__(self, headers):
111 | """Make a MockResponse for `cookiejar` to read.
112 |
113 | :param headers: a httplib.HTTPMessage or analogous carrying the headers
114 | """
115 | self._headers = headers
116 |
117 | def info(self):
118 | return self._headers
119 |
120 | def getheaders(self, name):
121 | self._headers.getheaders(name)
122 |
123 |
124 | def extract_cookies_to_jar(jar, request, response):
125 | """Extract the cookies from the response into a CookieJar.
126 |
127 | :param jar: http.cookiejar.CookieJar (not necessarily a RequestsCookieJar)
128 | :param request: our own requests.Request object
129 | :param response: urllib3.HTTPResponse object
130 | """
131 | if not (hasattr(response, "_original_response") and response._original_response):
132 | return
133 | # the _original_response field is the wrapped httplib.HTTPResponse object,
134 | req = MockRequest(request)
135 | # pull out the HTTPMessage with the headers and put it in the mock:
136 | res = MockResponse(response._original_response.msg)
137 | jar.extract_cookies(res, req)
138 |
139 |
140 | def get_cookie_header(jar, request):
141 | """
142 | Produce an appropriate Cookie header string to be sent with `request`, or None.
143 |
144 | :rtype: str
145 | """
146 | r = MockRequest(request)
147 | jar.add_cookie_header(r)
148 | return r.get_new_headers().get("Cookie")
149 |
150 |
151 | def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
152 | """Unsets a cookie by name, by default over all domains and paths.
153 |
154 | Wraps CookieJar.clear(), is O(n).
155 | """
156 | clearables = []
157 | for cookie in cookiejar:
158 | if cookie.name != name:
159 | continue
160 | if domain is not None and domain != cookie.domain:
161 | continue
162 | if path is not None and path != cookie.path:
163 | continue
164 | clearables.append((cookie.domain, cookie.path, cookie.name))
165 |
166 | for domain, path, name in clearables:
167 | cookiejar.clear(domain, path, name)
168 |
169 |
170 | class CookieConflictError(RuntimeError):
171 | """There are two cookies that meet the criteria specified in the cookie jar.
172 | Use .get and .set and include domain and path args in order to be more specific.
173 | """
174 |
175 |
176 | class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
177 | """Compatibility class; is a http.cookiejar.CookieJar, but exposes a dict
178 | interface.
179 |
180 | This is the CookieJar we create by default for requests and sessions that
181 | don't specify one, since some clients may expect response.cookies and
182 | session.cookies to support dict operations.
183 |
184 | Requests does not use the dict interface internally; it's just for
185 | compatibility with external client code. All requests code should work
186 | out of the box with externally provided instances of ``CookieJar``, e.g.
187 | ``LWPCookieJar`` and ``FileCookieJar``.
188 |
189 | Unlike a regular CookieJar, this class is pickleable.
190 |
191 | .. warning:: dictionary operations that are normally O(1) may be O(n).
192 | """
193 |
194 | def get(self, name, default=None, domain=None, path=None):
195 | """Dict-like get() that also supports optional domain and path args in
196 | order to resolve naming collisions from using one cookie jar over
197 | multiple domains.
198 |
199 | .. warning:: operation is O(n), not O(1).
200 | """
201 | try:
202 | return self._find_no_duplicates(name, domain, path)
203 | except KeyError:
204 | return default
205 |
206 | def set(self, name, value, **kwargs):
207 | """Dict-like set() that also supports optional domain and path args in
208 | order to resolve naming collisions from using one cookie jar over
209 | multiple domains.
210 | """
211 | # support client code that unsets cookies by assignment of a None value:
212 | if value is None:
213 | remove_cookie_by_name(
214 | self, name, domain=kwargs.get("domain"), path=kwargs.get("path")
215 | )
216 | return
217 |
218 | if isinstance(value, Morsel):
219 | c = morsel_to_cookie(value)
220 | else:
221 | c = create_cookie(name, value, **kwargs)
222 | self.set_cookie(c)
223 | return c
224 |
225 | def iterkeys(self):
226 | """Dict-like iterkeys() that returns an iterator of names of cookies
227 | from the jar.
228 |
229 | .. seealso:: itervalues() and iteritems().
230 | """
231 | for cookie in iter(self):
232 | yield cookie.name
233 |
234 | def keys(self):
235 | """Dict-like keys() that returns a list of names of cookies from the
236 | jar.
237 |
238 | .. seealso:: values() and items().
239 | """
240 | return list(self.iterkeys())
241 |
242 | def itervalues(self):
243 | """Dict-like itervalues() that returns an iterator of values of cookies
244 | from the jar.
245 |
246 | .. seealso:: iterkeys() and iteritems().
247 | """
248 | for cookie in iter(self):
249 | yield cookie.value
250 |
251 | def values(self):
252 | """Dict-like values() that returns a list of values of cookies from the
253 | jar.
254 |
255 | .. seealso:: keys() and items().
256 | """
257 | return list(self.itervalues())
258 |
259 | def iteritems(self):
260 | """Dict-like iteritems() that returns an iterator of name-value tuples
261 | from the jar.
262 |
263 | .. seealso:: iterkeys() and itervalues().
264 | """
265 | for cookie in iter(self):
266 | yield cookie.name, cookie.value
267 |
268 | def items(self):
269 | """Dict-like items() that returns a list of name-value tuples from the
270 | jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a
271 | vanilla python dict of key value pairs.
272 |
273 | .. seealso:: keys() and values().
274 | """
275 | return list(self.iteritems())
276 |
277 | def list_domains(self):
278 | """Utility method to list all the domains in the jar."""
279 | domains = []
280 | for cookie in iter(self):
281 | if cookie.domain not in domains:
282 | domains.append(cookie.domain)
283 | return domains
284 |
285 | def list_paths(self):
286 | """Utility method to list all the paths in the jar."""
287 | paths = []
288 | for cookie in iter(self):
289 | if cookie.path not in paths:
290 | paths.append(cookie.path)
291 | return paths
292 |
293 | def multiple_domains(self):
294 | """Returns True if there are multiple domains in the jar.
295 | Returns False otherwise.
296 |
297 | :rtype: bool
298 | """
299 | domains = []
300 | for cookie in iter(self):
301 | if cookie.domain is not None and cookie.domain in domains:
302 | return True
303 | domains.append(cookie.domain)
304 | return False # there is only one domain in jar
305 |
306 | def get_dict(self, domain=None, path=None):
307 | """Takes as an argument an optional domain and path and returns a plain
308 | old Python dict of name-value pairs of cookies that meet the
309 | requirements.
310 |
311 | :rtype: dict
312 | """
313 | dictionary = {}
314 | for cookie in iter(self):
315 | if (domain is None or cookie.domain == domain) and (
316 | path is None or cookie.path == path
317 | ):
318 | dictionary[cookie.name] = cookie.value
319 | return dictionary
320 |
321 | def __contains__(self, name):
322 | try:
323 | return super().__contains__(name)
324 | except CookieConflictError:
325 | return True
326 |
327 | def __getitem__(self, name):
328 | """Dict-like __getitem__() for compatibility with client code. Throws
329 | exception if there are more than one cookie with name. In that case,
330 | use the more explicit get() method instead.
331 |
332 | .. warning:: operation is O(n), not O(1).
333 | """
334 | return self._find_no_duplicates(name)
335 |
336 | def __setitem__(self, name, value):
337 | """Dict-like __setitem__ for compatibility with client code. Throws
338 | exception if there is already a cookie of that name in the jar. In that
339 | case, use the more explicit set() method instead.
340 | """
341 | self.set(name, value)
342 |
343 | def __delitem__(self, name):
344 | """Deletes a cookie given a name. Wraps ``http.cookiejar.CookieJar``'s
345 | ``remove_cookie_by_name()``.
346 | """
347 | remove_cookie_by_name(self, name)
348 |
349 | def set_cookie(self, cookie, *args, **kwargs):
350 | if (
351 | hasattr(cookie.value, "startswith")
352 | and cookie.value.startswith('"')
353 | and cookie.value.endswith('"')
354 | ):
355 | cookie.value = cookie.value.replace('\\"', "")
356 | return super().set_cookie(cookie, *args, **kwargs)
357 |
358 | def update(self, other):
359 | """Updates this jar with cookies from another CookieJar or dict-like"""
360 | if isinstance(other, cookielib.CookieJar):
361 | for cookie in other:
362 | self.set_cookie(copy.copy(cookie))
363 | else:
364 | super().update(other)
365 |
366 | def _find(self, name, domain=None, path=None):
367 | """Requests uses this method internally to get cookie values.
368 |
369 | If there are conflicting cookies, _find arbitrarily chooses one.
370 | See _find_no_duplicates if you want an exception thrown if there are
371 | conflicting cookies.
372 |
373 | :param name: a string containing name of cookie
374 | :param domain: (optional) string containing domain of cookie
375 | :param path: (optional) string containing path of cookie
376 | :return: cookie.value
377 | """
378 | for cookie in iter(self):
379 | if cookie.name == name:
380 | if domain is None or cookie.domain == domain:
381 | if path is None or cookie.path == path:
382 | return cookie.value
383 |
384 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
385 |
386 | def _find_no_duplicates(self, name, domain=None, path=None):
387 | """Both ``__get_item__`` and ``get`` call this function: it's never
388 | used elsewhere in Requests.
389 |
390 | :param name: a string containing name of cookie
391 | :param domain: (optional) string containing domain of cookie
392 | :param path: (optional) string containing path of cookie
393 | :raises KeyError: if cookie is not found
394 | :raises CookieConflictError: if there are multiple cookies
395 | that match name and optionally domain and path
396 | :return: cookie.value
397 | """
398 | toReturn = None
399 | for cookie in iter(self):
400 | if cookie.name == name:
401 | if domain is None or cookie.domain == domain:
402 | if path is None or cookie.path == path:
403 | if toReturn is not None:
404 | # if there are multiple cookies that meet passed in criteria
405 | raise CookieConflictError(
406 | f"There are multiple cookies with name, {name!r}"
407 | )
408 | # we will eventually return this as long as no cookie conflict
409 | toReturn = cookie.value
410 |
411 | if toReturn:
412 | return toReturn
413 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
414 |
415 | def __getstate__(self):
416 | """Unlike a normal CookieJar, this class is pickleable."""
417 | state = self.__dict__.copy()
418 | # remove the unpickleable RLock object
419 | state.pop("_cookies_lock")
420 | return state
421 |
422 | def __setstate__(self, state):
423 | """Unlike a normal CookieJar, this class is pickleable."""
424 | self.__dict__.update(state)
425 | if "_cookies_lock" not in self.__dict__:
426 | self._cookies_lock = threading.RLock()
427 |
428 | def copy(self):
429 | """Return a copy of this RequestsCookieJar."""
430 | new_cj = RequestsCookieJar()
431 | new_cj.set_policy(self.get_policy())
432 | new_cj.update(self)
433 | return new_cj
434 |
435 | def get_policy(self):
436 | """Return the CookiePolicy instance used."""
437 | return self._policy
438 |
439 |
440 | def _copy_cookie_jar(jar):
441 | if jar is None:
442 | return None
443 |
444 | if hasattr(jar, "copy"):
445 | # We're dealing with an instance of RequestsCookieJar
446 | return jar.copy()
447 | # We're dealing with a generic CookieJar instance
448 | new_jar = copy.copy(jar)
449 | new_jar.clear()
450 | for cookie in jar:
451 | new_jar.set_cookie(copy.copy(cookie))
452 | return new_jar
453 |
454 |
455 | def create_cookie(name, value, **kwargs):
456 | """Make a cookie from underspecified parameters.
457 |
458 | By default, the pair of `name` and `value` will be set for the domain ''
459 | and sent on every request (this is sometimes called a "supercookie").
460 | """
461 | result = {
462 | "version": 0,
463 | "name": name,
464 | "value": value,
465 | "port": None,
466 | "domain": "",
467 | "path": "/",
468 | "secure": False,
469 | "expires": None,
470 | "discard": True,
471 | "comment": None,
472 | "comment_url": None,
473 | "rest": {"HttpOnly": None},
474 | "rfc2109": False,
475 | }
476 |
477 | badargs = set(kwargs) - set(result)
478 | if badargs:
479 | raise TypeError(
480 | f"create_cookie() got unexpected keyword arguments: {list(badargs)}"
481 | )
482 |
483 | result.update(kwargs)
484 | result["port_specified"] = bool(result["port"])
485 | result["domain_specified"] = bool(result["domain"])
486 | result["domain_initial_dot"] = result["domain"].startswith(".")
487 | result["path_specified"] = bool(result["path"])
488 |
489 | return cookielib.Cookie(**result)
490 |
491 |
492 | def morsel_to_cookie(morsel):
493 | """Convert a Morsel object into a Cookie containing the one k/v pair."""
494 |
495 | expires = None
496 | if morsel["max-age"]:
497 | try:
498 | expires = int(time.time() + int(morsel["max-age"]))
499 | except ValueError:
500 | raise TypeError(f"max-age: {morsel['max-age']} must be integer")
501 | elif morsel["expires"]:
502 | time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
503 | expires = calendar.timegm(time.strptime(morsel["expires"], time_template))
504 | return create_cookie(
505 | comment=morsel["comment"],
506 | comment_url=bool(morsel["comment"]),
507 | discard=False,
508 | domain=morsel["domain"],
509 | expires=expires,
510 | name=morsel.key,
511 | path=morsel["path"],
512 | port=None,
513 | rest={"HttpOnly": morsel["httponly"]},
514 | rfc2109=False,
515 | secure=bool(morsel["secure"]),
516 | value=morsel.value,
517 | version=morsel["version"] or 0,
518 | )
519 |
520 |
521 | def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
522 | """Returns a CookieJar from a key/value dictionary.
523 |
524 | :param cookie_dict: Dict of key/values to insert into CookieJar.
525 | :param cookiejar: (optional) A cookiejar to add the cookies to.
526 | :param overwrite: (optional) If False, will not replace cookies
527 | already in the jar with new ones.
528 | :rtype: CookieJar
529 | """
530 | if cookiejar is None:
531 | cookiejar = RequestsCookieJar()
532 |
533 | if cookie_dict is not None:
534 | names_from_jar = [cookie.name for cookie in cookiejar]
535 | for name in cookie_dict:
536 | if overwrite or (name not in names_from_jar):
537 | cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
538 |
539 | return cookiejar
540 |
541 |
542 | def merge_cookies(cookiejar, cookies):
543 | """Add cookies to cookiejar and returns a merged CookieJar.
544 |
545 | :param cookiejar: CookieJar object to add the cookies to.
546 | :param cookies: Dictionary or CookieJar object to be added.
547 | :rtype: CookieJar
548 | """
549 | if not isinstance(cookiejar, cookielib.CookieJar):
550 | raise ValueError("You can only merge into CookieJar")
551 |
552 | if isinstance(cookies, dict):
553 | cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False)
554 | elif isinstance(cookies, cookielib.CookieJar):
555 | try:
556 | cookiejar.update(cookies)
557 | except AttributeError:
558 | for cookie_in_jar in cookies:
559 | cookiejar.set_cookie(cookie_in_jar)
560 |
561 | return cookiejar
562 |
```
--------------------------------------------------------------------------------
/.venv/lib/python3.12/site-packages/requests/cookies.py:
--------------------------------------------------------------------------------
```python
1 | """
2 | requests.cookies
3 | ~~~~~~~~~~~~~~~~
4 |
5 | Compatibility code to be able to use `http.cookiejar.CookieJar` with requests.
6 |
7 | requests.utils imports from here, so be careful with imports.
8 | """
9 |
10 | import calendar
11 | import copy
12 | import time
13 |
14 | from ._internal_utils import to_native_string
15 | from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse
16 |
17 | try:
18 | import threading
19 | except ImportError:
20 | import dummy_threading as threading
21 |
22 |
23 | class MockRequest:
24 | """Wraps a `requests.Request` to mimic a `urllib2.Request`.
25 |
26 | The code in `http.cookiejar.CookieJar` expects this interface in order to correctly
27 | manage cookie policies, i.e., determine whether a cookie can be set, given the
28 | domains of the request and the cookie.
29 |
30 | The original request object is read-only. The client is responsible for collecting
31 | the new headers via `get_new_headers()` and interpreting them appropriately. You
32 | probably want `get_cookie_header`, defined below.
33 | """
34 |
35 | def __init__(self, request):
36 | self._r = request
37 | self._new_headers = {}
38 | self.type = urlparse(self._r.url).scheme
39 |
40 | def get_type(self):
41 | return self.type
42 |
43 | def get_host(self):
44 | return urlparse(self._r.url).netloc
45 |
46 | def get_origin_req_host(self):
47 | return self.get_host()
48 |
49 | def get_full_url(self):
50 | # Only return the response's URL if the user hadn't set the Host
51 | # header
52 | if not self._r.headers.get("Host"):
53 | return self._r.url
54 | # If they did set it, retrieve it and reconstruct the expected domain
55 | host = to_native_string(self._r.headers["Host"], encoding="utf-8")
56 | parsed = urlparse(self._r.url)
57 | # Reconstruct the URL as we expect it
58 | return urlunparse(
59 | [
60 | parsed.scheme,
61 | host,
62 | parsed.path,
63 | parsed.params,
64 | parsed.query,
65 | parsed.fragment,
66 | ]
67 | )
68 |
69 | def is_unverifiable(self):
70 | return True
71 |
72 | def has_header(self, name):
73 | return name in self._r.headers or name in self._new_headers
74 |
75 | def get_header(self, name, default=None):
76 | return self._r.headers.get(name, self._new_headers.get(name, default))
77 |
78 | def add_header(self, key, val):
79 | """cookiejar has no legitimate use for this method; add it back if you find one."""
80 | raise NotImplementedError(
81 | "Cookie headers should be added with add_unredirected_header()"
82 | )
83 |
84 | def add_unredirected_header(self, name, value):
85 | self._new_headers[name] = value
86 |
87 | def get_new_headers(self):
88 | return self._new_headers
89 |
90 | @property
91 | def unverifiable(self):
92 | return self.is_unverifiable()
93 |
94 | @property
95 | def origin_req_host(self):
96 | return self.get_origin_req_host()
97 |
98 | @property
99 | def host(self):
100 | return self.get_host()
101 |
102 |
103 | class MockResponse:
104 | """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
105 |
106 | ...what? Basically, expose the parsed HTTP headers from the server response
107 | the way `http.cookiejar` expects to see them.
108 | """
109 |
110 | def __init__(self, headers):
111 | """Make a MockResponse for `cookiejar` to read.
112 |
113 | :param headers: a httplib.HTTPMessage or analogous carrying the headers
114 | """
115 | self._headers = headers
116 |
117 | def info(self):
118 | return self._headers
119 |
120 | def getheaders(self, name):
121 | self._headers.getheaders(name)
122 |
123 |
124 | def extract_cookies_to_jar(jar, request, response):
125 | """Extract the cookies from the response into a CookieJar.
126 |
127 | :param jar: http.cookiejar.CookieJar (not necessarily a RequestsCookieJar)
128 | :param request: our own requests.Request object
129 | :param response: urllib3.HTTPResponse object
130 | """
131 | if not (hasattr(response, "_original_response") and response._original_response):
132 | return
133 | # the _original_response field is the wrapped httplib.HTTPResponse object,
134 | req = MockRequest(request)
135 | # pull out the HTTPMessage with the headers and put it in the mock:
136 | res = MockResponse(response._original_response.msg)
137 | jar.extract_cookies(res, req)
138 |
139 |
140 | def get_cookie_header(jar, request):
141 | """
142 | Produce an appropriate Cookie header string to be sent with `request`, or None.
143 |
144 | :rtype: str
145 | """
146 | r = MockRequest(request)
147 | jar.add_cookie_header(r)
148 | return r.get_new_headers().get("Cookie")
149 |
150 |
151 | def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
152 | """Unsets a cookie by name, by default over all domains and paths.
153 |
154 | Wraps CookieJar.clear(), is O(n).
155 | """
156 | clearables = []
157 | for cookie in cookiejar:
158 | if cookie.name != name:
159 | continue
160 | if domain is not None and domain != cookie.domain:
161 | continue
162 | if path is not None and path != cookie.path:
163 | continue
164 | clearables.append((cookie.domain, cookie.path, cookie.name))
165 |
166 | for domain, path, name in clearables:
167 | cookiejar.clear(domain, path, name)
168 |
169 |
170 | class CookieConflictError(RuntimeError):
171 | """There are two cookies that meet the criteria specified in the cookie jar.
172 | Use .get and .set and include domain and path args in order to be more specific.
173 | """
174 |
175 |
176 | class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
177 | """Compatibility class; is a http.cookiejar.CookieJar, but exposes a dict
178 | interface.
179 |
180 | This is the CookieJar we create by default for requests and sessions that
181 | don't specify one, since some clients may expect response.cookies and
182 | session.cookies to support dict operations.
183 |
184 | Requests does not use the dict interface internally; it's just for
185 | compatibility with external client code. All requests code should work
186 | out of the box with externally provided instances of ``CookieJar``, e.g.
187 | ``LWPCookieJar`` and ``FileCookieJar``.
188 |
189 | Unlike a regular CookieJar, this class is pickleable.
190 |
191 | .. warning:: dictionary operations that are normally O(1) may be O(n).
192 | """
193 |
194 | def get(self, name, default=None, domain=None, path=None):
195 | """Dict-like get() that also supports optional domain and path args in
196 | order to resolve naming collisions from using one cookie jar over
197 | multiple domains.
198 |
199 | .. warning:: operation is O(n), not O(1).
200 | """
201 | try:
202 | return self._find_no_duplicates(name, domain, path)
203 | except KeyError:
204 | return default
205 |
206 | def set(self, name, value, **kwargs):
207 | """Dict-like set() that also supports optional domain and path args in
208 | order to resolve naming collisions from using one cookie jar over
209 | multiple domains.
210 | """
211 | # support client code that unsets cookies by assignment of a None value:
212 | if value is None:
213 | remove_cookie_by_name(
214 | self, name, domain=kwargs.get("domain"), path=kwargs.get("path")
215 | )
216 | return
217 |
218 | if isinstance(value, Morsel):
219 | c = morsel_to_cookie(value)
220 | else:
221 | c = create_cookie(name, value, **kwargs)
222 | self.set_cookie(c)
223 | return c
224 |
225 | def iterkeys(self):
226 | """Dict-like iterkeys() that returns an iterator of names of cookies
227 | from the jar.
228 |
229 | .. seealso:: itervalues() and iteritems().
230 | """
231 | for cookie in iter(self):
232 | yield cookie.name
233 |
234 | def keys(self):
235 | """Dict-like keys() that returns a list of names of cookies from the
236 | jar.
237 |
238 | .. seealso:: values() and items().
239 | """
240 | return list(self.iterkeys())
241 |
242 | def itervalues(self):
243 | """Dict-like itervalues() that returns an iterator of values of cookies
244 | from the jar.
245 |
246 | .. seealso:: iterkeys() and iteritems().
247 | """
248 | for cookie in iter(self):
249 | yield cookie.value
250 |
251 | def values(self):
252 | """Dict-like values() that returns a list of values of cookies from the
253 | jar.
254 |
255 | .. seealso:: keys() and items().
256 | """
257 | return list(self.itervalues())
258 |
259 | def iteritems(self):
260 | """Dict-like iteritems() that returns an iterator of name-value tuples
261 | from the jar.
262 |
263 | .. seealso:: iterkeys() and itervalues().
264 | """
265 | for cookie in iter(self):
266 | yield cookie.name, cookie.value
267 |
268 | def items(self):
269 | """Dict-like items() that returns a list of name-value tuples from the
270 | jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a
271 | vanilla python dict of key value pairs.
272 |
273 | .. seealso:: keys() and values().
274 | """
275 | return list(self.iteritems())
276 |
277 | def list_domains(self):
278 | """Utility method to list all the domains in the jar."""
279 | domains = []
280 | for cookie in iter(self):
281 | if cookie.domain not in domains:
282 | domains.append(cookie.domain)
283 | return domains
284 |
285 | def list_paths(self):
286 | """Utility method to list all the paths in the jar."""
287 | paths = []
288 | for cookie in iter(self):
289 | if cookie.path not in paths:
290 | paths.append(cookie.path)
291 | return paths
292 |
293 | def multiple_domains(self):
294 | """Returns True if there are multiple domains in the jar.
295 | Returns False otherwise.
296 |
297 | :rtype: bool
298 | """
299 | domains = []
300 | for cookie in iter(self):
301 | if cookie.domain is not None and cookie.domain in domains:
302 | return True
303 | domains.append(cookie.domain)
304 | return False # there is only one domain in jar
305 |
306 | def get_dict(self, domain=None, path=None):
307 | """Takes as an argument an optional domain and path and returns a plain
308 | old Python dict of name-value pairs of cookies that meet the
309 | requirements.
310 |
311 | :rtype: dict
312 | """
313 | dictionary = {}
314 | for cookie in iter(self):
315 | if (domain is None or cookie.domain == domain) and (
316 | path is None or cookie.path == path
317 | ):
318 | dictionary[cookie.name] = cookie.value
319 | return dictionary
320 |
321 | def __contains__(self, name):
322 | try:
323 | return super().__contains__(name)
324 | except CookieConflictError:
325 | return True
326 |
327 | def __getitem__(self, name):
328 | """Dict-like __getitem__() for compatibility with client code. Throws
329 | exception if there are more than one cookie with name. In that case,
330 | use the more explicit get() method instead.
331 |
332 | .. warning:: operation is O(n), not O(1).
333 | """
334 | return self._find_no_duplicates(name)
335 |
336 | def __setitem__(self, name, value):
337 | """Dict-like __setitem__ for compatibility with client code. Throws
338 | exception if there is already a cookie of that name in the jar. In that
339 | case, use the more explicit set() method instead.
340 | """
341 | self.set(name, value)
342 |
343 | def __delitem__(self, name):
344 | """Deletes a cookie given a name. Wraps ``http.cookiejar.CookieJar``'s
345 | ``remove_cookie_by_name()``.
346 | """
347 | remove_cookie_by_name(self, name)
348 |
349 | def set_cookie(self, cookie, *args, **kwargs):
350 | if (
351 | hasattr(cookie.value, "startswith")
352 | and cookie.value.startswith('"')
353 | and cookie.value.endswith('"')
354 | ):
355 | cookie.value = cookie.value.replace('\\"', "")
356 | return super().set_cookie(cookie, *args, **kwargs)
357 |
358 | def update(self, other):
359 | """Updates this jar with cookies from another CookieJar or dict-like"""
360 | if isinstance(other, cookielib.CookieJar):
361 | for cookie in other:
362 | self.set_cookie(copy.copy(cookie))
363 | else:
364 | super().update(other)
365 |
366 | def _find(self, name, domain=None, path=None):
367 | """Requests uses this method internally to get cookie values.
368 |
369 | If there are conflicting cookies, _find arbitrarily chooses one.
370 | See _find_no_duplicates if you want an exception thrown if there are
371 | conflicting cookies.
372 |
373 | :param name: a string containing name of cookie
374 | :param domain: (optional) string containing domain of cookie
375 | :param path: (optional) string containing path of cookie
376 | :return: cookie.value
377 | """
378 | for cookie in iter(self):
379 | if cookie.name == name:
380 | if domain is None or cookie.domain == domain:
381 | if path is None or cookie.path == path:
382 | return cookie.value
383 |
384 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
385 |
386 | def _find_no_duplicates(self, name, domain=None, path=None):
387 | """Both ``__get_item__`` and ``get`` call this function: it's never
388 | used elsewhere in Requests.
389 |
390 | :param name: a string containing name of cookie
391 | :param domain: (optional) string containing domain of cookie
392 | :param path: (optional) string containing path of cookie
393 | :raises KeyError: if cookie is not found
394 | :raises CookieConflictError: if there are multiple cookies
395 | that match name and optionally domain and path
396 | :return: cookie.value
397 | """
398 | toReturn = None
399 | for cookie in iter(self):
400 | if cookie.name == name:
401 | if domain is None or cookie.domain == domain:
402 | if path is None or cookie.path == path:
403 | if toReturn is not None:
404 | # if there are multiple cookies that meet passed in criteria
405 | raise CookieConflictError(
406 | f"There are multiple cookies with name, {name!r}"
407 | )
408 | # we will eventually return this as long as no cookie conflict
409 | toReturn = cookie.value
410 |
411 | if toReturn:
412 | return toReturn
413 | raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
414 |
415 | def __getstate__(self):
416 | """Unlike a normal CookieJar, this class is pickleable."""
417 | state = self.__dict__.copy()
418 | # remove the unpickleable RLock object
419 | state.pop("_cookies_lock")
420 | return state
421 |
422 | def __setstate__(self, state):
423 | """Unlike a normal CookieJar, this class is pickleable."""
424 | self.__dict__.update(state)
425 | if "_cookies_lock" not in self.__dict__:
426 | self._cookies_lock = threading.RLock()
427 |
428 | def copy(self):
429 | """Return a copy of this RequestsCookieJar."""
430 | new_cj = RequestsCookieJar()
431 | new_cj.set_policy(self.get_policy())
432 | new_cj.update(self)
433 | return new_cj
434 |
435 | def get_policy(self):
436 | """Return the CookiePolicy instance used."""
437 | return self._policy
438 |
439 |
440 | def _copy_cookie_jar(jar):
441 | if jar is None:
442 | return None
443 |
444 | if hasattr(jar, "copy"):
445 | # We're dealing with an instance of RequestsCookieJar
446 | return jar.copy()
447 | # We're dealing with a generic CookieJar instance
448 | new_jar = copy.copy(jar)
449 | new_jar.clear()
450 | for cookie in jar:
451 | new_jar.set_cookie(copy.copy(cookie))
452 | return new_jar
453 |
454 |
455 | def create_cookie(name, value, **kwargs):
456 | """Make a cookie from underspecified parameters.
457 |
458 | By default, the pair of `name` and `value` will be set for the domain ''
459 | and sent on every request (this is sometimes called a "supercookie").
460 | """
461 | result = {
462 | "version": 0,
463 | "name": name,
464 | "value": value,
465 | "port": None,
466 | "domain": "",
467 | "path": "/",
468 | "secure": False,
469 | "expires": None,
470 | "discard": True,
471 | "comment": None,
472 | "comment_url": None,
473 | "rest": {"HttpOnly": None},
474 | "rfc2109": False,
475 | }
476 |
477 | badargs = set(kwargs) - set(result)
478 | if badargs:
479 | raise TypeError(
480 | f"create_cookie() got unexpected keyword arguments: {list(badargs)}"
481 | )
482 |
483 | result.update(kwargs)
484 | result["port_specified"] = bool(result["port"])
485 | result["domain_specified"] = bool(result["domain"])
486 | result["domain_initial_dot"] = result["domain"].startswith(".")
487 | result["path_specified"] = bool(result["path"])
488 |
489 | return cookielib.Cookie(**result)
490 |
491 |
492 | def morsel_to_cookie(morsel):
493 | """Convert a Morsel object into a Cookie containing the one k/v pair."""
494 |
495 | expires = None
496 | if morsel["max-age"]:
497 | try:
498 | expires = int(time.time() + int(morsel["max-age"]))
499 | except ValueError:
500 | raise TypeError(f"max-age: {morsel['max-age']} must be integer")
501 | elif morsel["expires"]:
502 | time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
503 | expires = calendar.timegm(time.strptime(morsel["expires"], time_template))
504 | return create_cookie(
505 | comment=morsel["comment"],
506 | comment_url=bool(morsel["comment"]),
507 | discard=False,
508 | domain=morsel["domain"],
509 | expires=expires,
510 | name=morsel.key,
511 | path=morsel["path"],
512 | port=None,
513 | rest={"HttpOnly": morsel["httponly"]},
514 | rfc2109=False,
515 | secure=bool(morsel["secure"]),
516 | value=morsel.value,
517 | version=morsel["version"] or 0,
518 | )
519 |
520 |
521 | def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
522 | """Returns a CookieJar from a key/value dictionary.
523 |
524 | :param cookie_dict: Dict of key/values to insert into CookieJar.
525 | :param cookiejar: (optional) A cookiejar to add the cookies to.
526 | :param overwrite: (optional) If False, will not replace cookies
527 | already in the jar with new ones.
528 | :rtype: CookieJar
529 | """
530 | if cookiejar is None:
531 | cookiejar = RequestsCookieJar()
532 |
533 | if cookie_dict is not None:
534 | names_from_jar = [cookie.name for cookie in cookiejar]
535 | for name in cookie_dict:
536 | if overwrite or (name not in names_from_jar):
537 | cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
538 |
539 | return cookiejar
540 |
541 |
542 | def merge_cookies(cookiejar, cookies):
543 | """Add cookies to cookiejar and returns a merged CookieJar.
544 |
545 | :param cookiejar: CookieJar object to add the cookies to.
546 | :param cookies: Dictionary or CookieJar object to be added.
547 | :rtype: CookieJar
548 | """
549 | if not isinstance(cookiejar, cookielib.CookieJar):
550 | raise ValueError("You can only merge into CookieJar")
551 |
552 | if isinstance(cookies, dict):
553 | cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False)
554 | elif isinstance(cookies, cookielib.CookieJar):
555 | try:
556 | cookiejar.update(cookies)
557 | except AttributeError:
558 | for cookie_in_jar in cookies:
559 | cookiejar.set_cookie(cookie_in_jar)
560 |
561 | return cookiejar
562 |
```