This is page 151 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/rich/progress.py:
--------------------------------------------------------------------------------
```python
1 | import io
2 | import sys
3 | import typing
4 | import warnings
5 | from abc import ABC, abstractmethod
6 | from collections import deque
7 | from dataclasses import dataclass, field
8 | from datetime import timedelta
9 | from io import RawIOBase, UnsupportedOperation
10 | from math import ceil
11 | from mmap import mmap
12 | from operator import length_hint
13 | from os import PathLike, stat
14 | from threading import Event, RLock, Thread
15 | from types import TracebackType
16 | from typing import (
17 | Any,
18 | BinaryIO,
19 | Callable,
20 | ContextManager,
21 | Deque,
22 | Dict,
23 | Generic,
24 | Iterable,
25 | List,
26 | NamedTuple,
27 | NewType,
28 | Optional,
29 | Sequence,
30 | TextIO,
31 | Tuple,
32 | Type,
33 | TypeVar,
34 | Union,
35 | )
36 |
37 | if sys.version_info >= (3, 8):
38 | from typing import Literal
39 | else:
40 | from pip._vendor.typing_extensions import Literal # pragma: no cover
41 |
42 | from . import filesize, get_console
43 | from .console import Console, Group, JustifyMethod, RenderableType
44 | from .highlighter import Highlighter
45 | from .jupyter import JupyterMixin
46 | from .live import Live
47 | from .progress_bar import ProgressBar
48 | from .spinner import Spinner
49 | from .style import StyleType
50 | from .table import Column, Table
51 | from .text import Text, TextType
52 |
53 | TaskID = NewType("TaskID", int)
54 |
55 | ProgressType = TypeVar("ProgressType")
56 |
57 | GetTimeCallable = Callable[[], float]
58 |
59 |
60 | _I = typing.TypeVar("_I", TextIO, BinaryIO)
61 |
62 |
63 | class _TrackThread(Thread):
64 | """A thread to periodically update progress."""
65 |
66 | def __init__(self, progress: "Progress", task_id: "TaskID", update_period: float):
67 | self.progress = progress
68 | self.task_id = task_id
69 | self.update_period = update_period
70 | self.done = Event()
71 |
72 | self.completed = 0
73 | super().__init__()
74 |
75 | def run(self) -> None:
76 | task_id = self.task_id
77 | advance = self.progress.advance
78 | update_period = self.update_period
79 | last_completed = 0
80 | wait = self.done.wait
81 | while not wait(update_period):
82 | completed = self.completed
83 | if last_completed != completed:
84 | advance(task_id, completed - last_completed)
85 | last_completed = completed
86 |
87 | self.progress.update(self.task_id, completed=self.completed, refresh=True)
88 |
89 | def __enter__(self) -> "_TrackThread":
90 | self.start()
91 | return self
92 |
93 | def __exit__(
94 | self,
95 | exc_type: Optional[Type[BaseException]],
96 | exc_val: Optional[BaseException],
97 | exc_tb: Optional[TracebackType],
98 | ) -> None:
99 | self.done.set()
100 | self.join()
101 |
102 |
103 | def track(
104 | sequence: Union[Sequence[ProgressType], Iterable[ProgressType]],
105 | description: str = "Working...",
106 | total: Optional[float] = None,
107 | auto_refresh: bool = True,
108 | console: Optional[Console] = None,
109 | transient: bool = False,
110 | get_time: Optional[Callable[[], float]] = None,
111 | refresh_per_second: float = 10,
112 | style: StyleType = "bar.back",
113 | complete_style: StyleType = "bar.complete",
114 | finished_style: StyleType = "bar.finished",
115 | pulse_style: StyleType = "bar.pulse",
116 | update_period: float = 0.1,
117 | disable: bool = False,
118 | show_speed: bool = True,
119 | ) -> Iterable[ProgressType]:
120 | """Track progress by iterating over a sequence.
121 |
122 | Args:
123 | sequence (Iterable[ProgressType]): A sequence (must support "len") you wish to iterate over.
124 | description (str, optional): Description of task show next to progress bar. Defaults to "Working".
125 | total: (float, optional): Total number of steps. Default is len(sequence).
126 | auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True.
127 | transient: (bool, optional): Clear the progress on exit. Defaults to False.
128 | console (Console, optional): Console to write to. Default creates internal Console instance.
129 | refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10.
130 | style (StyleType, optional): Style for the bar background. Defaults to "bar.back".
131 | complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete".
132 | finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished".
133 | pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse".
134 | update_period (float, optional): Minimum time (in seconds) between calls to update(). Defaults to 0.1.
135 | disable (bool, optional): Disable display of progress.
136 | show_speed (bool, optional): Show speed if total isn't known. Defaults to True.
137 | Returns:
138 | Iterable[ProgressType]: An iterable of the values in the sequence.
139 |
140 | """
141 |
142 | columns: List["ProgressColumn"] = (
143 | [TextColumn("[progress.description]{task.description}")] if description else []
144 | )
145 | columns.extend(
146 | (
147 | BarColumn(
148 | style=style,
149 | complete_style=complete_style,
150 | finished_style=finished_style,
151 | pulse_style=pulse_style,
152 | ),
153 | TaskProgressColumn(show_speed=show_speed),
154 | TimeRemainingColumn(elapsed_when_finished=True),
155 | )
156 | )
157 | progress = Progress(
158 | *columns,
159 | auto_refresh=auto_refresh,
160 | console=console,
161 | transient=transient,
162 | get_time=get_time,
163 | refresh_per_second=refresh_per_second or 10,
164 | disable=disable,
165 | )
166 |
167 | with progress:
168 | yield from progress.track(
169 | sequence, total=total, description=description, update_period=update_period
170 | )
171 |
172 |
173 | class _Reader(RawIOBase, BinaryIO):
174 | """A reader that tracks progress while it's being read from."""
175 |
176 | def __init__(
177 | self,
178 | handle: BinaryIO,
179 | progress: "Progress",
180 | task: TaskID,
181 | close_handle: bool = True,
182 | ) -> None:
183 | self.handle = handle
184 | self.progress = progress
185 | self.task = task
186 | self.close_handle = close_handle
187 | self._closed = False
188 |
189 | def __enter__(self) -> "_Reader":
190 | self.handle.__enter__()
191 | return self
192 |
193 | def __exit__(
194 | self,
195 | exc_type: Optional[Type[BaseException]],
196 | exc_val: Optional[BaseException],
197 | exc_tb: Optional[TracebackType],
198 | ) -> None:
199 | self.close()
200 |
201 | def __iter__(self) -> BinaryIO:
202 | return self
203 |
204 | def __next__(self) -> bytes:
205 | line = next(self.handle)
206 | self.progress.advance(self.task, advance=len(line))
207 | return line
208 |
209 | @property
210 | def closed(self) -> bool:
211 | return self._closed
212 |
213 | def fileno(self) -> int:
214 | return self.handle.fileno()
215 |
216 | def isatty(self) -> bool:
217 | return self.handle.isatty()
218 |
219 | @property
220 | def mode(self) -> str:
221 | return self.handle.mode
222 |
223 | @property
224 | def name(self) -> str:
225 | return self.handle.name
226 |
227 | def readable(self) -> bool:
228 | return self.handle.readable()
229 |
230 | def seekable(self) -> bool:
231 | return self.handle.seekable()
232 |
233 | def writable(self) -> bool:
234 | return False
235 |
236 | def read(self, size: int = -1) -> bytes:
237 | block = self.handle.read(size)
238 | self.progress.advance(self.task, advance=len(block))
239 | return block
240 |
241 | def readinto(self, b: Union[bytearray, memoryview, mmap]): # type: ignore[no-untyped-def, override]
242 | n = self.handle.readinto(b) # type: ignore[attr-defined]
243 | self.progress.advance(self.task, advance=n)
244 | return n
245 |
246 | def readline(self, size: int = -1) -> bytes: # type: ignore[override]
247 | line = self.handle.readline(size)
248 | self.progress.advance(self.task, advance=len(line))
249 | return line
250 |
251 | def readlines(self, hint: int = -1) -> List[bytes]:
252 | lines = self.handle.readlines(hint)
253 | self.progress.advance(self.task, advance=sum(map(len, lines)))
254 | return lines
255 |
256 | def close(self) -> None:
257 | if self.close_handle:
258 | self.handle.close()
259 | self._closed = True
260 |
261 | def seek(self, offset: int, whence: int = 0) -> int:
262 | pos = self.handle.seek(offset, whence)
263 | self.progress.update(self.task, completed=pos)
264 | return pos
265 |
266 | def tell(self) -> int:
267 | return self.handle.tell()
268 |
269 | def write(self, s: Any) -> int:
270 | raise UnsupportedOperation("write")
271 |
272 |
273 | class _ReadContext(ContextManager[_I], Generic[_I]):
274 | """A utility class to handle a context for both a reader and a progress."""
275 |
276 | def __init__(self, progress: "Progress", reader: _I) -> None:
277 | self.progress = progress
278 | self.reader: _I = reader
279 |
280 | def __enter__(self) -> _I:
281 | self.progress.start()
282 | return self.reader.__enter__()
283 |
284 | def __exit__(
285 | self,
286 | exc_type: Optional[Type[BaseException]],
287 | exc_val: Optional[BaseException],
288 | exc_tb: Optional[TracebackType],
289 | ) -> None:
290 | self.progress.stop()
291 | self.reader.__exit__(exc_type, exc_val, exc_tb)
292 |
293 |
294 | def wrap_file(
295 | file: BinaryIO,
296 | total: int,
297 | *,
298 | description: str = "Reading...",
299 | auto_refresh: bool = True,
300 | console: Optional[Console] = None,
301 | transient: bool = False,
302 | get_time: Optional[Callable[[], float]] = None,
303 | refresh_per_second: float = 10,
304 | style: StyleType = "bar.back",
305 | complete_style: StyleType = "bar.complete",
306 | finished_style: StyleType = "bar.finished",
307 | pulse_style: StyleType = "bar.pulse",
308 | disable: bool = False,
309 | ) -> ContextManager[BinaryIO]:
310 | """Read bytes from a file while tracking progress.
311 |
312 | Args:
313 | file (Union[str, PathLike[str], BinaryIO]): The path to the file to read, or a file-like object in binary mode.
314 | total (int): Total number of bytes to read.
315 | description (str, optional): Description of task show next to progress bar. Defaults to "Reading".
316 | auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True.
317 | transient: (bool, optional): Clear the progress on exit. Defaults to False.
318 | console (Console, optional): Console to write to. Default creates internal Console instance.
319 | refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10.
320 | style (StyleType, optional): Style for the bar background. Defaults to "bar.back".
321 | complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete".
322 | finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished".
323 | pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse".
324 | disable (bool, optional): Disable display of progress.
325 | Returns:
326 | ContextManager[BinaryIO]: A context manager yielding a progress reader.
327 |
328 | """
329 |
330 | columns: List["ProgressColumn"] = (
331 | [TextColumn("[progress.description]{task.description}")] if description else []
332 | )
333 | columns.extend(
334 | (
335 | BarColumn(
336 | style=style,
337 | complete_style=complete_style,
338 | finished_style=finished_style,
339 | pulse_style=pulse_style,
340 | ),
341 | DownloadColumn(),
342 | TimeRemainingColumn(),
343 | )
344 | )
345 | progress = Progress(
346 | *columns,
347 | auto_refresh=auto_refresh,
348 | console=console,
349 | transient=transient,
350 | get_time=get_time,
351 | refresh_per_second=refresh_per_second or 10,
352 | disable=disable,
353 | )
354 |
355 | reader = progress.wrap_file(file, total=total, description=description)
356 | return _ReadContext(progress, reader)
357 |
358 |
359 | @typing.overload
360 | def open(
361 | file: Union[str, "PathLike[str]", bytes],
362 | mode: Union[Literal["rt"], Literal["r"]],
363 | buffering: int = -1,
364 | encoding: Optional[str] = None,
365 | errors: Optional[str] = None,
366 | newline: Optional[str] = None,
367 | *,
368 | total: Optional[int] = None,
369 | description: str = "Reading...",
370 | auto_refresh: bool = True,
371 | console: Optional[Console] = None,
372 | transient: bool = False,
373 | get_time: Optional[Callable[[], float]] = None,
374 | refresh_per_second: float = 10,
375 | style: StyleType = "bar.back",
376 | complete_style: StyleType = "bar.complete",
377 | finished_style: StyleType = "bar.finished",
378 | pulse_style: StyleType = "bar.pulse",
379 | disable: bool = False,
380 | ) -> ContextManager[TextIO]:
381 | pass
382 |
383 |
384 | @typing.overload
385 | def open(
386 | file: Union[str, "PathLike[str]", bytes],
387 | mode: Literal["rb"],
388 | buffering: int = -1,
389 | encoding: Optional[str] = None,
390 | errors: Optional[str] = None,
391 | newline: Optional[str] = None,
392 | *,
393 | total: Optional[int] = None,
394 | description: str = "Reading...",
395 | auto_refresh: bool = True,
396 | console: Optional[Console] = None,
397 | transient: bool = False,
398 | get_time: Optional[Callable[[], float]] = None,
399 | refresh_per_second: float = 10,
400 | style: StyleType = "bar.back",
401 | complete_style: StyleType = "bar.complete",
402 | finished_style: StyleType = "bar.finished",
403 | pulse_style: StyleType = "bar.pulse",
404 | disable: bool = False,
405 | ) -> ContextManager[BinaryIO]:
406 | pass
407 |
408 |
409 | def open(
410 | file: Union[str, "PathLike[str]", bytes],
411 | mode: Union[Literal["rb"], Literal["rt"], Literal["r"]] = "r",
412 | buffering: int = -1,
413 | encoding: Optional[str] = None,
414 | errors: Optional[str] = None,
415 | newline: Optional[str] = None,
416 | *,
417 | total: Optional[int] = None,
418 | description: str = "Reading...",
419 | auto_refresh: bool = True,
420 | console: Optional[Console] = None,
421 | transient: bool = False,
422 | get_time: Optional[Callable[[], float]] = None,
423 | refresh_per_second: float = 10,
424 | style: StyleType = "bar.back",
425 | complete_style: StyleType = "bar.complete",
426 | finished_style: StyleType = "bar.finished",
427 | pulse_style: StyleType = "bar.pulse",
428 | disable: bool = False,
429 | ) -> Union[ContextManager[BinaryIO], ContextManager[TextIO]]:
430 | """Read bytes from a file while tracking progress.
431 |
432 | Args:
433 | path (Union[str, PathLike[str], BinaryIO]): The path to the file to read, or a file-like object in binary mode.
434 | mode (str): The mode to use to open the file. Only supports "r", "rb" or "rt".
435 | buffering (int): The buffering strategy to use, see :func:`io.open`.
436 | encoding (str, optional): The encoding to use when reading in text mode, see :func:`io.open`.
437 | errors (str, optional): The error handling strategy for decoding errors, see :func:`io.open`.
438 | newline (str, optional): The strategy for handling newlines in text mode, see :func:`io.open`
439 | total: (int, optional): Total number of bytes to read. Must be provided if reading from a file handle. Default for a path is os.stat(file).st_size.
440 | description (str, optional): Description of task show next to progress bar. Defaults to "Reading".
441 | auto_refresh (bool, optional): Automatic refresh, disable to force a refresh after each iteration. Default is True.
442 | transient: (bool, optional): Clear the progress on exit. Defaults to False.
443 | console (Console, optional): Console to write to. Default creates internal Console instance.
444 | refresh_per_second (float): Number of times per second to refresh the progress information. Defaults to 10.
445 | style (StyleType, optional): Style for the bar background. Defaults to "bar.back".
446 | complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete".
447 | finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished".
448 | pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse".
449 | disable (bool, optional): Disable display of progress.
450 | encoding (str, optional): The encoding to use when reading in text mode.
451 |
452 | Returns:
453 | ContextManager[BinaryIO]: A context manager yielding a progress reader.
454 |
455 | """
456 |
457 | columns: List["ProgressColumn"] = (
458 | [TextColumn("[progress.description]{task.description}")] if description else []
459 | )
460 | columns.extend(
461 | (
462 | BarColumn(
463 | style=style,
464 | complete_style=complete_style,
465 | finished_style=finished_style,
466 | pulse_style=pulse_style,
467 | ),
468 | DownloadColumn(),
469 | TimeRemainingColumn(),
470 | )
471 | )
472 | progress = Progress(
473 | *columns,
474 | auto_refresh=auto_refresh,
475 | console=console,
476 | transient=transient,
477 | get_time=get_time,
478 | refresh_per_second=refresh_per_second or 10,
479 | disable=disable,
480 | )
481 |
482 | reader = progress.open(
483 | file,
484 | mode=mode,
485 | buffering=buffering,
486 | encoding=encoding,
487 | errors=errors,
488 | newline=newline,
489 | total=total,
490 | description=description,
491 | )
492 | return _ReadContext(progress, reader) # type: ignore[return-value, type-var]
493 |
494 |
495 | class ProgressColumn(ABC):
496 | """Base class for a widget to use in progress display."""
497 |
498 | max_refresh: Optional[float] = None
499 |
500 | def __init__(self, table_column: Optional[Column] = None) -> None:
501 | self._table_column = table_column
502 | self._renderable_cache: Dict[TaskID, Tuple[float, RenderableType]] = {}
503 | self._update_time: Optional[float] = None
504 |
505 | def get_table_column(self) -> Column:
506 | """Get a table column, used to build tasks table."""
507 | return self._table_column or Column()
508 |
509 | def __call__(self, task: "Task") -> RenderableType:
510 | """Called by the Progress object to return a renderable for the given task.
511 |
512 | Args:
513 | task (Task): An object containing information regarding the task.
514 |
515 | Returns:
516 | RenderableType: Anything renderable (including str).
517 | """
518 | current_time = task.get_time()
519 | if self.max_refresh is not None and not task.completed:
520 | try:
521 | timestamp, renderable = self._renderable_cache[task.id]
522 | except KeyError:
523 | pass
524 | else:
525 | if timestamp + self.max_refresh > current_time:
526 | return renderable
527 |
528 | renderable = self.render(task)
529 | self._renderable_cache[task.id] = (current_time, renderable)
530 | return renderable
531 |
532 | @abstractmethod
533 | def render(self, task: "Task") -> RenderableType:
534 | """Should return a renderable object."""
535 |
536 |
537 | class RenderableColumn(ProgressColumn):
538 | """A column to insert an arbitrary column.
539 |
540 | Args:
541 | renderable (RenderableType, optional): Any renderable. Defaults to empty string.
542 | """
543 |
544 | def __init__(
545 | self, renderable: RenderableType = "", *, table_column: Optional[Column] = None
546 | ):
547 | self.renderable = renderable
548 | super().__init__(table_column=table_column)
549 |
550 | def render(self, task: "Task") -> RenderableType:
551 | return self.renderable
552 |
553 |
554 | class SpinnerColumn(ProgressColumn):
555 | """A column with a 'spinner' animation.
556 |
557 | Args:
558 | spinner_name (str, optional): Name of spinner animation. Defaults to "dots".
559 | style (StyleType, optional): Style of spinner. Defaults to "progress.spinner".
560 | speed (float, optional): Speed factor of spinner. Defaults to 1.0.
561 | finished_text (TextType, optional): Text used when task is finished. Defaults to " ".
562 | """
563 |
564 | def __init__(
565 | self,
566 | spinner_name: str = "dots",
567 | style: Optional[StyleType] = "progress.spinner",
568 | speed: float = 1.0,
569 | finished_text: TextType = " ",
570 | table_column: Optional[Column] = None,
571 | ):
572 | self.spinner = Spinner(spinner_name, style=style, speed=speed)
573 | self.finished_text = (
574 | Text.from_markup(finished_text)
575 | if isinstance(finished_text, str)
576 | else finished_text
577 | )
578 | super().__init__(table_column=table_column)
579 |
580 | def set_spinner(
581 | self,
582 | spinner_name: str,
583 | spinner_style: Optional[StyleType] = "progress.spinner",
584 | speed: float = 1.0,
585 | ) -> None:
586 | """Set a new spinner.
587 |
588 | Args:
589 | spinner_name (str): Spinner name, see python -m rich.spinner.
590 | spinner_style (Optional[StyleType], optional): Spinner style. Defaults to "progress.spinner".
591 | speed (float, optional): Speed factor of spinner. Defaults to 1.0.
592 | """
593 | self.spinner = Spinner(spinner_name, style=spinner_style, speed=speed)
594 |
595 | def render(self, task: "Task") -> RenderableType:
596 | text = (
597 | self.finished_text
598 | if task.finished
599 | else self.spinner.render(task.get_time())
600 | )
601 | return text
602 |
603 |
604 | class TextColumn(ProgressColumn):
605 | """A column containing text."""
606 |
607 | def __init__(
608 | self,
609 | text_format: str,
610 | style: StyleType = "none",
611 | justify: JustifyMethod = "left",
612 | markup: bool = True,
613 | highlighter: Optional[Highlighter] = None,
614 | table_column: Optional[Column] = None,
615 | ) -> None:
616 | self.text_format = text_format
617 | self.justify: JustifyMethod = justify
618 | self.style = style
619 | self.markup = markup
620 | self.highlighter = highlighter
621 | super().__init__(table_column=table_column or Column(no_wrap=True))
622 |
623 | def render(self, task: "Task") -> Text:
624 | _text = self.text_format.format(task=task)
625 | if self.markup:
626 | text = Text.from_markup(_text, style=self.style, justify=self.justify)
627 | else:
628 | text = Text(_text, style=self.style, justify=self.justify)
629 | if self.highlighter:
630 | self.highlighter.highlight(text)
631 | return text
632 |
633 |
634 | class BarColumn(ProgressColumn):
635 | """Renders a visual progress bar.
636 |
637 | Args:
638 | bar_width (Optional[int], optional): Width of bar or None for full width. Defaults to 40.
639 | style (StyleType, optional): Style for the bar background. Defaults to "bar.back".
640 | complete_style (StyleType, optional): Style for the completed bar. Defaults to "bar.complete".
641 | finished_style (StyleType, optional): Style for a finished bar. Defaults to "bar.finished".
642 | pulse_style (StyleType, optional): Style for pulsing bars. Defaults to "bar.pulse".
643 | """
644 |
645 | def __init__(
646 | self,
647 | bar_width: Optional[int] = 40,
648 | style: StyleType = "bar.back",
649 | complete_style: StyleType = "bar.complete",
650 | finished_style: StyleType = "bar.finished",
651 | pulse_style: StyleType = "bar.pulse",
652 | table_column: Optional[Column] = None,
653 | ) -> None:
654 | self.bar_width = bar_width
655 | self.style = style
656 | self.complete_style = complete_style
657 | self.finished_style = finished_style
658 | self.pulse_style = pulse_style
659 | super().__init__(table_column=table_column)
660 |
661 | def render(self, task: "Task") -> ProgressBar:
662 | """Gets a progress bar widget for a task."""
663 | return ProgressBar(
664 | total=max(0, task.total) if task.total is not None else None,
665 | completed=max(0, task.completed),
666 | width=None if self.bar_width is None else max(1, self.bar_width),
667 | pulse=not task.started,
668 | animation_time=task.get_time(),
669 | style=self.style,
670 | complete_style=self.complete_style,
671 | finished_style=self.finished_style,
672 | pulse_style=self.pulse_style,
673 | )
674 |
675 |
676 | class TimeElapsedColumn(ProgressColumn):
677 | """Renders time elapsed."""
678 |
679 | def render(self, task: "Task") -> Text:
680 | """Show time elapsed."""
681 | elapsed = task.finished_time if task.finished else task.elapsed
682 | if elapsed is None:
683 | return Text("-:--:--", style="progress.elapsed")
684 | delta = timedelta(seconds=max(0, int(elapsed)))
685 | return Text(str(delta), style="progress.elapsed")
686 |
687 |
688 | class TaskProgressColumn(TextColumn):
689 | """Show task progress as a percentage.
690 |
691 | Args:
692 | text_format (str, optional): Format for percentage display. Defaults to "[progress.percentage]{task.percentage:>3.0f}%".
693 | text_format_no_percentage (str, optional): Format if percentage is unknown. Defaults to "".
694 | style (StyleType, optional): Style of output. Defaults to "none".
695 | justify (JustifyMethod, optional): Text justification. Defaults to "left".
696 | markup (bool, optional): Enable markup. Defaults to True.
697 | highlighter (Optional[Highlighter], optional): Highlighter to apply to output. Defaults to None.
698 | table_column (Optional[Column], optional): Table Column to use. Defaults to None.
699 | show_speed (bool, optional): Show speed if total is unknown. Defaults to False.
700 | """
701 |
702 | def __init__(
703 | self,
704 | text_format: str = "[progress.percentage]{task.percentage:>3.0f}%",
705 | text_format_no_percentage: str = "",
706 | style: StyleType = "none",
707 | justify: JustifyMethod = "left",
708 | markup: bool = True,
709 | highlighter: Optional[Highlighter] = None,
710 | table_column: Optional[Column] = None,
711 | show_speed: bool = False,
712 | ) -> None:
713 | self.text_format_no_percentage = text_format_no_percentage
714 | self.show_speed = show_speed
715 | super().__init__(
716 | text_format=text_format,
717 | style=style,
718 | justify=justify,
719 | markup=markup,
720 | highlighter=highlighter,
721 | table_column=table_column,
722 | )
723 |
724 | @classmethod
725 | def render_speed(cls, speed: Optional[float]) -> Text:
726 | """Render the speed in iterations per second.
727 |
728 | Args:
729 | task (Task): A Task object.
730 |
731 | Returns:
732 | Text: Text object containing the task speed.
733 | """
734 | if speed is None:
735 | return Text("", style="progress.percentage")
736 | unit, suffix = filesize.pick_unit_and_suffix(
737 | int(speed),
738 | ["", "×10³", "×10⁶", "×10⁹", "×10¹²"],
739 | 1000,
740 | )
741 | data_speed = speed / unit
742 | return Text(f"{data_speed:.1f}{suffix} it/s", style="progress.percentage")
743 |
744 | def render(self, task: "Task") -> Text:
745 | if task.total is None and self.show_speed:
746 | return self.render_speed(task.finished_speed or task.speed)
747 | text_format = (
748 | self.text_format_no_percentage if task.total is None else self.text_format
749 | )
750 | _text = text_format.format(task=task)
751 | if self.markup:
752 | text = Text.from_markup(_text, style=self.style, justify=self.justify)
753 | else:
754 | text = Text(_text, style=self.style, justify=self.justify)
755 | if self.highlighter:
756 | self.highlighter.highlight(text)
757 | return text
758 |
759 |
760 | class TimeRemainingColumn(ProgressColumn):
761 | """Renders estimated time remaining.
762 |
763 | Args:
764 | compact (bool, optional): Render MM:SS when time remaining is less than an hour. Defaults to False.
765 | elapsed_when_finished (bool, optional): Render time elapsed when the task is finished. Defaults to False.
766 | """
767 |
768 | # Only refresh twice a second to prevent jitter
769 | max_refresh = 0.5
770 |
771 | def __init__(
772 | self,
773 | compact: bool = False,
774 | elapsed_when_finished: bool = False,
775 | table_column: Optional[Column] = None,
776 | ):
777 | self.compact = compact
778 | self.elapsed_when_finished = elapsed_when_finished
779 | super().__init__(table_column=table_column)
780 |
781 | def render(self, task: "Task") -> Text:
782 | """Show time remaining."""
783 | if self.elapsed_when_finished and task.finished:
784 | task_time = task.finished_time
785 | style = "progress.elapsed"
786 | else:
787 | task_time = task.time_remaining
788 | style = "progress.remaining"
789 |
790 | if task.total is None:
791 | return Text("", style=style)
792 |
793 | if task_time is None:
794 | return Text("--:--" if self.compact else "-:--:--", style=style)
795 |
796 | # Based on https://github.com/tqdm/tqdm/blob/master/tqdm/std.py
797 | minutes, seconds = divmod(int(task_time), 60)
798 | hours, minutes = divmod(minutes, 60)
799 |
800 | if self.compact and not hours:
801 | formatted = f"{minutes:02d}:{seconds:02d}"
802 | else:
803 | formatted = f"{hours:d}:{minutes:02d}:{seconds:02d}"
804 |
805 | return Text(formatted, style=style)
806 |
807 |
808 | class FileSizeColumn(ProgressColumn):
809 | """Renders completed filesize."""
810 |
811 | def render(self, task: "Task") -> Text:
812 | """Show data completed."""
813 | data_size = filesize.decimal(int(task.completed))
814 | return Text(data_size, style="progress.filesize")
815 |
816 |
817 | class TotalFileSizeColumn(ProgressColumn):
818 | """Renders total filesize."""
819 |
820 | def render(self, task: "Task") -> Text:
821 | """Show data completed."""
822 | data_size = filesize.decimal(int(task.total)) if task.total is not None else ""
823 | return Text(data_size, style="progress.filesize.total")
824 |
825 |
826 | class MofNCompleteColumn(ProgressColumn):
827 | """Renders completed count/total, e.g. ' 10/1000'.
828 |
829 | Best for bounded tasks with int quantities.
830 |
831 | Space pads the completed count so that progress length does not change as task progresses
832 | past powers of 10.
833 |
834 | Args:
835 | separator (str, optional): Text to separate completed and total values. Defaults to "/".
836 | """
837 |
838 | def __init__(self, separator: str = "/", table_column: Optional[Column] = None):
839 | self.separator = separator
840 | super().__init__(table_column=table_column)
841 |
842 | def render(self, task: "Task") -> Text:
843 | """Show completed/total."""
844 | completed = int(task.completed)
845 | total = int(task.total) if task.total is not None else "?"
846 | total_width = len(str(total))
847 | return Text(
848 | f"{completed:{total_width}d}{self.separator}{total}",
849 | style="progress.download",
850 | )
851 |
852 |
853 | class DownloadColumn(ProgressColumn):
854 | """Renders file size downloaded and total, e.g. '0.5/2.3 GB'.
855 |
856 | Args:
857 | binary_units (bool, optional): Use binary units, KiB, MiB etc. Defaults to False.
858 | """
859 |
860 | def __init__(
861 | self, binary_units: bool = False, table_column: Optional[Column] = None
862 | ) -> None:
863 | self.binary_units = binary_units
864 | super().__init__(table_column=table_column)
865 |
866 | def render(self, task: "Task") -> Text:
867 | """Calculate common unit for completed and total."""
868 | completed = int(task.completed)
869 |
870 | unit_and_suffix_calculation_base = (
871 | int(task.total) if task.total is not None else completed
872 | )
873 | if self.binary_units:
874 | unit, suffix = filesize.pick_unit_and_suffix(
875 | unit_and_suffix_calculation_base,
876 | ["bytes", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB"],
877 | 1024,
878 | )
879 | else:
880 | unit, suffix = filesize.pick_unit_and_suffix(
881 | unit_and_suffix_calculation_base,
882 | ["bytes", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"],
883 | 1000,
884 | )
885 | precision = 0 if unit == 1 else 1
886 |
887 | completed_ratio = completed / unit
888 | completed_str = f"{completed_ratio:,.{precision}f}"
889 |
890 | if task.total is not None:
891 | total = int(task.total)
892 | total_ratio = total / unit
893 | total_str = f"{total_ratio:,.{precision}f}"
894 | else:
895 | total_str = "?"
896 |
897 | download_status = f"{completed_str}/{total_str} {suffix}"
898 | download_text = Text(download_status, style="progress.download")
899 | return download_text
900 |
901 |
902 | class TransferSpeedColumn(ProgressColumn):
903 | """Renders human readable transfer speed."""
904 |
905 | def render(self, task: "Task") -> Text:
906 | """Show data transfer speed."""
907 | speed = task.finished_speed or task.speed
908 | if speed is None:
909 | return Text("?", style="progress.data.speed")
910 | data_speed = filesize.decimal(int(speed))
911 | return Text(f"{data_speed}/s", style="progress.data.speed")
912 |
913 |
914 | class ProgressSample(NamedTuple):
915 | """Sample of progress for a given time."""
916 |
917 | timestamp: float
918 | """Timestamp of sample."""
919 | completed: float
920 | """Number of steps completed."""
921 |
922 |
923 | @dataclass
924 | class Task:
925 | """Information regarding a progress task.
926 |
927 | This object should be considered read-only outside of the :class:`~Progress` class.
928 |
929 | """
930 |
931 | id: TaskID
932 | """Task ID associated with this task (used in Progress methods)."""
933 |
934 | description: str
935 | """str: Description of the task."""
936 |
937 | total: Optional[float]
938 | """Optional[float]: Total number of steps in this task."""
939 |
940 | completed: float
941 | """float: Number of steps completed"""
942 |
943 | _get_time: GetTimeCallable
944 | """Callable to get the current time."""
945 |
946 | finished_time: Optional[float] = None
947 | """float: Time task was finished."""
948 |
949 | visible: bool = True
950 | """bool: Indicates if this task is visible in the progress display."""
951 |
952 | fields: Dict[str, Any] = field(default_factory=dict)
953 | """dict: Arbitrary fields passed in via Progress.update."""
954 |
955 | start_time: Optional[float] = field(default=None, init=False, repr=False)
956 | """Optional[float]: Time this task was started, or None if not started."""
957 |
958 | stop_time: Optional[float] = field(default=None, init=False, repr=False)
959 | """Optional[float]: Time this task was stopped, or None if not stopped."""
960 |
961 | finished_speed: Optional[float] = None
962 | """Optional[float]: The last speed for a finished task."""
963 |
964 | _progress: Deque[ProgressSample] = field(
965 | default_factory=lambda: deque(maxlen=1000), init=False, repr=False
966 | )
967 |
968 | _lock: RLock = field(repr=False, default_factory=RLock)
969 | """Thread lock."""
970 |
971 | def get_time(self) -> float:
972 | """float: Get the current time, in seconds."""
973 | return self._get_time()
974 |
975 | @property
976 | def started(self) -> bool:
977 | """bool: Check if the task as started."""
978 | return self.start_time is not None
979 |
980 | @property
981 | def remaining(self) -> Optional[float]:
982 | """Optional[float]: Get the number of steps remaining, if a non-None total was set."""
983 | if self.total is None:
984 | return None
985 | return self.total - self.completed
986 |
987 | @property
988 | def elapsed(self) -> Optional[float]:
989 | """Optional[float]: Time elapsed since task was started, or ``None`` if the task hasn't started."""
990 | if self.start_time is None:
991 | return None
992 | if self.stop_time is not None:
993 | return self.stop_time - self.start_time
994 | return self.get_time() - self.start_time
995 |
996 | @property
997 | def finished(self) -> bool:
998 | """Check if the task has finished."""
999 | return self.finished_time is not None
1000 |
1001 | @property
1002 | def percentage(self) -> float:
1003 | """float: Get progress of task as a percentage. If a None total was set, returns 0"""
1004 | if not self.total:
1005 | return 0.0
1006 | completed = (self.completed / self.total) * 100.0
1007 | completed = min(100.0, max(0.0, completed))
1008 | return completed
1009 |
1010 | @property
1011 | def speed(self) -> Optional[float]:
1012 | """Optional[float]: Get the estimated speed in steps per second."""
1013 | if self.start_time is None:
1014 | return None
1015 | with self._lock:
1016 | progress = self._progress
1017 | if not progress:
1018 | return None
1019 | total_time = progress[-1].timestamp - progress[0].timestamp
1020 | if total_time == 0:
1021 | return None
1022 | iter_progress = iter(progress)
1023 | next(iter_progress)
1024 | total_completed = sum(sample.completed for sample in iter_progress)
1025 | speed = total_completed / total_time
1026 | return speed
1027 |
1028 | @property
1029 | def time_remaining(self) -> Optional[float]:
1030 | """Optional[float]: Get estimated time to completion, or ``None`` if no data."""
1031 | if self.finished:
1032 | return 0.0
1033 | speed = self.speed
1034 | if not speed:
1035 | return None
1036 | remaining = self.remaining
1037 | if remaining is None:
1038 | return None
1039 | estimate = ceil(remaining / speed)
1040 | return estimate
1041 |
1042 | def _reset(self) -> None:
1043 | """Reset progress."""
1044 | self._progress.clear()
1045 | self.finished_time = None
1046 | self.finished_speed = None
1047 |
1048 |
1049 | class Progress(JupyterMixin):
1050 | """Renders an auto-updating progress bar(s).
1051 |
1052 | Args:
1053 | console (Console, optional): Optional Console instance. Default will an internal Console instance writing to stdout.
1054 | auto_refresh (bool, optional): Enable auto refresh. If disabled, you will need to call `refresh()`.
1055 | refresh_per_second (Optional[float], optional): Number of times per second to refresh the progress information or None to use default (10). Defaults to None.
1056 | speed_estimate_period: (float, optional): Period (in seconds) used to calculate the speed estimate. Defaults to 30.
1057 | transient: (bool, optional): Clear the progress on exit. Defaults to False.
1058 | redirect_stdout: (bool, optional): Enable redirection of stdout, so ``print`` may be used. Defaults to True.
1059 | redirect_stderr: (bool, optional): Enable redirection of stderr. Defaults to True.
1060 | get_time: (Callable, optional): A callable that gets the current time, or None to use Console.get_time. Defaults to None.
1061 | disable (bool, optional): Disable progress display. Defaults to False
1062 | expand (bool, optional): Expand tasks table to fit width. Defaults to False.
1063 | """
1064 |
1065 | def __init__(
1066 | self,
1067 | *columns: Union[str, ProgressColumn],
1068 | console: Optional[Console] = None,
1069 | auto_refresh: bool = True,
1070 | refresh_per_second: float = 10,
1071 | speed_estimate_period: float = 30.0,
1072 | transient: bool = False,
1073 | redirect_stdout: bool = True,
1074 | redirect_stderr: bool = True,
1075 | get_time: Optional[GetTimeCallable] = None,
1076 | disable: bool = False,
1077 | expand: bool = False,
1078 | ) -> None:
1079 | assert refresh_per_second > 0, "refresh_per_second must be > 0"
1080 | self._lock = RLock()
1081 | self.columns = columns or self.get_default_columns()
1082 | self.speed_estimate_period = speed_estimate_period
1083 |
1084 | self.disable = disable
1085 | self.expand = expand
1086 | self._tasks: Dict[TaskID, Task] = {}
1087 | self._task_index: TaskID = TaskID(0)
1088 | self.live = Live(
1089 | console=console or get_console(),
1090 | auto_refresh=auto_refresh,
1091 | refresh_per_second=refresh_per_second,
1092 | transient=transient,
1093 | redirect_stdout=redirect_stdout,
1094 | redirect_stderr=redirect_stderr,
1095 | get_renderable=self.get_renderable,
1096 | )
1097 | self.get_time = get_time or self.console.get_time
1098 | self.print = self.console.print
1099 | self.log = self.console.log
1100 |
1101 | @classmethod
1102 | def get_default_columns(cls) -> Tuple[ProgressColumn, ...]:
1103 | """Get the default columns used for a new Progress instance:
1104 | - a text column for the description (TextColumn)
1105 | - the bar itself (BarColumn)
1106 | - a text column showing completion percentage (TextColumn)
1107 | - an estimated-time-remaining column (TimeRemainingColumn)
1108 | If the Progress instance is created without passing a columns argument,
1109 | the default columns defined here will be used.
1110 |
1111 | You can also create a Progress instance using custom columns before
1112 | and/or after the defaults, as in this example:
1113 |
1114 | progress = Progress(
1115 | SpinnerColumn(),
1116 | *Progress.get_default_columns(),
1117 | "Elapsed:",
1118 | TimeElapsedColumn(),
1119 | )
1120 |
1121 | This code shows the creation of a Progress display, containing
1122 | a spinner to the left, the default columns, and a labeled elapsed
1123 | time column.
1124 | """
1125 | return (
1126 | TextColumn("[progress.description]{task.description}"),
1127 | BarColumn(),
1128 | TaskProgressColumn(),
1129 | TimeRemainingColumn(),
1130 | )
1131 |
1132 | @property
1133 | def console(self) -> Console:
1134 | return self.live.console
1135 |
1136 | @property
1137 | def tasks(self) -> List[Task]:
1138 | """Get a list of Task instances."""
1139 | with self._lock:
1140 | return list(self._tasks.values())
1141 |
1142 | @property
1143 | def task_ids(self) -> List[TaskID]:
1144 | """A list of task IDs."""
1145 | with self._lock:
1146 | return list(self._tasks.keys())
1147 |
1148 | @property
1149 | def finished(self) -> bool:
1150 | """Check if all tasks have been completed."""
1151 | with self._lock:
1152 | if not self._tasks:
1153 | return True
1154 | return all(task.finished for task in self._tasks.values())
1155 |
1156 | def start(self) -> None:
1157 | """Start the progress display."""
1158 | if not self.disable:
1159 | self.live.start(refresh=True)
1160 |
1161 | def stop(self) -> None:
1162 | """Stop the progress display."""
1163 | self.live.stop()
1164 | if not self.console.is_interactive:
1165 | self.console.print()
1166 |
1167 | def __enter__(self) -> "Progress":
1168 | self.start()
1169 | return self
1170 |
1171 | def __exit__(
1172 | self,
1173 | exc_type: Optional[Type[BaseException]],
1174 | exc_val: Optional[BaseException],
1175 | exc_tb: Optional[TracebackType],
1176 | ) -> None:
1177 | self.stop()
1178 |
1179 | def track(
1180 | self,
1181 | sequence: Union[Iterable[ProgressType], Sequence[ProgressType]],
1182 | total: Optional[float] = None,
1183 | task_id: Optional[TaskID] = None,
1184 | description: str = "Working...",
1185 | update_period: float = 0.1,
1186 | ) -> Iterable[ProgressType]:
1187 | """Track progress by iterating over a sequence.
1188 |
1189 | Args:
1190 | sequence (Sequence[ProgressType]): A sequence of values you want to iterate over and track progress.
1191 | total: (float, optional): Total number of steps. Default is len(sequence).
1192 | task_id: (TaskID): Task to track. Default is new task.
1193 | description: (str, optional): Description of task, if new task is created.
1194 | update_period (float, optional): Minimum time (in seconds) between calls to update(). Defaults to 0.1.
1195 |
1196 | Returns:
1197 | Iterable[ProgressType]: An iterable of values taken from the provided sequence.
1198 | """
1199 | if total is None:
1200 | total = float(length_hint(sequence)) or None
1201 |
1202 | if task_id is None:
1203 | task_id = self.add_task(description, total=total)
1204 | else:
1205 | self.update(task_id, total=total)
1206 |
1207 | if self.live.auto_refresh:
1208 | with _TrackThread(self, task_id, update_period) as track_thread:
1209 | for value in sequence:
1210 | yield value
1211 | track_thread.completed += 1
1212 | else:
1213 | advance = self.advance
1214 | refresh = self.refresh
1215 | for value in sequence:
1216 | yield value
1217 | advance(task_id, 1)
1218 | refresh()
1219 |
1220 | def wrap_file(
1221 | self,
1222 | file: BinaryIO,
1223 | total: Optional[int] = None,
1224 | *,
1225 | task_id: Optional[TaskID] = None,
1226 | description: str = "Reading...",
1227 | ) -> BinaryIO:
1228 | """Track progress file reading from a binary file.
1229 |
1230 | Args:
1231 | file (BinaryIO): A file-like object opened in binary mode.
1232 | total (int, optional): Total number of bytes to read. This must be provided unless a task with a total is also given.
1233 | task_id (TaskID): Task to track. Default is new task.
1234 | description (str, optional): Description of task, if new task is created.
1235 |
1236 | Returns:
1237 | BinaryIO: A readable file-like object in binary mode.
1238 |
1239 | Raises:
1240 | ValueError: When no total value can be extracted from the arguments or the task.
1241 | """
1242 | # attempt to recover the total from the task
1243 | total_bytes: Optional[float] = None
1244 | if total is not None:
1245 | total_bytes = total
1246 | elif task_id is not None:
1247 | with self._lock:
1248 | total_bytes = self._tasks[task_id].total
1249 | if total_bytes is None:
1250 | raise ValueError(
1251 | f"unable to get the total number of bytes, please specify 'total'"
1252 | )
1253 |
1254 | # update total of task or create new task
1255 | if task_id is None:
1256 | task_id = self.add_task(description, total=total_bytes)
1257 | else:
1258 | self.update(task_id, total=total_bytes)
1259 |
1260 | return _Reader(file, self, task_id, close_handle=False)
1261 |
1262 | @typing.overload
1263 | def open(
1264 | self,
1265 | file: Union[str, "PathLike[str]", bytes],
1266 | mode: Literal["rb"],
1267 | buffering: int = -1,
1268 | encoding: Optional[str] = None,
1269 | errors: Optional[str] = None,
1270 | newline: Optional[str] = None,
1271 | *,
1272 | total: Optional[int] = None,
1273 | task_id: Optional[TaskID] = None,
1274 | description: str = "Reading...",
1275 | ) -> BinaryIO:
1276 | pass
1277 |
1278 | @typing.overload
1279 | def open(
1280 | self,
1281 | file: Union[str, "PathLike[str]", bytes],
1282 | mode: Union[Literal["r"], Literal["rt"]],
1283 | buffering: int = -1,
1284 | encoding: Optional[str] = None,
1285 | errors: Optional[str] = None,
1286 | newline: Optional[str] = None,
1287 | *,
1288 | total: Optional[int] = None,
1289 | task_id: Optional[TaskID] = None,
1290 | description: str = "Reading...",
1291 | ) -> TextIO:
1292 | pass
1293 |
1294 | def open(
1295 | self,
1296 | file: Union[str, "PathLike[str]", bytes],
1297 | mode: Union[Literal["rb"], Literal["rt"], Literal["r"]] = "r",
1298 | buffering: int = -1,
1299 | encoding: Optional[str] = None,
1300 | errors: Optional[str] = None,
1301 | newline: Optional[str] = None,
1302 | *,
1303 | total: Optional[int] = None,
1304 | task_id: Optional[TaskID] = None,
1305 | description: str = "Reading...",
1306 | ) -> Union[BinaryIO, TextIO]:
1307 | """Track progress while reading from a binary file.
1308 |
1309 | Args:
1310 | path (Union[str, PathLike[str]]): The path to the file to read.
1311 | mode (str): The mode to use to open the file. Only supports "r", "rb" or "rt".
1312 | buffering (int): The buffering strategy to use, see :func:`io.open`.
1313 | encoding (str, optional): The encoding to use when reading in text mode, see :func:`io.open`.
1314 | errors (str, optional): The error handling strategy for decoding errors, see :func:`io.open`.
1315 | newline (str, optional): The strategy for handling newlines in text mode, see :func:`io.open`.
1316 | total (int, optional): Total number of bytes to read. If none given, os.stat(path).st_size is used.
1317 | task_id (TaskID): Task to track. Default is new task.
1318 | description (str, optional): Description of task, if new task is created.
1319 |
1320 | Returns:
1321 | BinaryIO: A readable file-like object in binary mode.
1322 |
1323 | Raises:
1324 | ValueError: When an invalid mode is given.
1325 | """
1326 | # normalize the mode (always rb, rt)
1327 | _mode = "".join(sorted(mode, reverse=False))
1328 | if _mode not in ("br", "rt", "r"):
1329 | raise ValueError("invalid mode {!r}".format(mode))
1330 |
1331 | # patch buffering to provide the same behaviour as the builtin `open`
1332 | line_buffering = buffering == 1
1333 | if _mode == "br" and buffering == 1:
1334 | warnings.warn(
1335 | "line buffering (buffering=1) isn't supported in binary mode, the default buffer size will be used",
1336 | RuntimeWarning,
1337 | )
1338 | buffering = -1
1339 | elif _mode in ("rt", "r"):
1340 | if buffering == 0:
1341 | raise ValueError("can't have unbuffered text I/O")
1342 | elif buffering == 1:
1343 | buffering = -1
1344 |
1345 | # attempt to get the total with `os.stat`
1346 | if total is None:
1347 | total = stat(file).st_size
1348 |
1349 | # update total of task or create new task
1350 | if task_id is None:
1351 | task_id = self.add_task(description, total=total)
1352 | else:
1353 | self.update(task_id, total=total)
1354 |
1355 | # open the file in binary mode,
1356 | handle = io.open(file, "rb", buffering=buffering)
1357 | reader = _Reader(handle, self, task_id, close_handle=True)
1358 |
1359 | # wrap the reader in a `TextIOWrapper` if text mode
1360 | if mode in ("r", "rt"):
1361 | return io.TextIOWrapper(
1362 | reader,
1363 | encoding=encoding,
1364 | errors=errors,
1365 | newline=newline,
1366 | line_buffering=line_buffering,
1367 | )
1368 |
1369 | return reader
1370 |
1371 | def start_task(self, task_id: TaskID) -> None:
1372 | """Start a task.
1373 |
1374 | Starts a task (used when calculating elapsed time). You may need to call this manually,
1375 | if you called ``add_task`` with ``start=False``.
1376 |
1377 | Args:
1378 | task_id (TaskID): ID of task.
1379 | """
1380 | with self._lock:
1381 | task = self._tasks[task_id]
1382 | if task.start_time is None:
1383 | task.start_time = self.get_time()
1384 |
1385 | def stop_task(self, task_id: TaskID) -> None:
1386 | """Stop a task.
1387 |
1388 | This will freeze the elapsed time on the task.
1389 |
1390 | Args:
1391 | task_id (TaskID): ID of task.
1392 | """
1393 | with self._lock:
1394 | task = self._tasks[task_id]
1395 | current_time = self.get_time()
1396 | if task.start_time is None:
1397 | task.start_time = current_time
1398 | task.stop_time = current_time
1399 |
1400 | def update(
1401 | self,
1402 | task_id: TaskID,
1403 | *,
1404 | total: Optional[float] = None,
1405 | completed: Optional[float] = None,
1406 | advance: Optional[float] = None,
1407 | description: Optional[str] = None,
1408 | visible: Optional[bool] = None,
1409 | refresh: bool = False,
1410 | **fields: Any,
1411 | ) -> None:
1412 | """Update information associated with a task.
1413 |
1414 | Args:
1415 | task_id (TaskID): Task id (returned by add_task).
1416 | total (float, optional): Updates task.total if not None.
1417 | completed (float, optional): Updates task.completed if not None.
1418 | advance (float, optional): Add a value to task.completed if not None.
1419 | description (str, optional): Change task description if not None.
1420 | visible (bool, optional): Set visible flag if not None.
1421 | refresh (bool): Force a refresh of progress information. Default is False.
1422 | **fields (Any): Additional data fields required for rendering.
1423 | """
1424 | with self._lock:
1425 | task = self._tasks[task_id]
1426 | completed_start = task.completed
1427 |
1428 | if total is not None and total != task.total:
1429 | task.total = total
1430 | task._reset()
1431 | if advance is not None:
1432 | task.completed += advance
1433 | if completed is not None:
1434 | task.completed = completed
1435 | if description is not None:
1436 | task.description = description
1437 | if visible is not None:
1438 | task.visible = visible
1439 | task.fields.update(fields)
1440 | update_completed = task.completed - completed_start
1441 |
1442 | current_time = self.get_time()
1443 | old_sample_time = current_time - self.speed_estimate_period
1444 | _progress = task._progress
1445 |
1446 | popleft = _progress.popleft
1447 | while _progress and _progress[0].timestamp < old_sample_time:
1448 | popleft()
1449 | if update_completed > 0:
1450 | _progress.append(ProgressSample(current_time, update_completed))
1451 | if (
1452 | task.total is not None
1453 | and task.completed >= task.total
1454 | and task.finished_time is None
1455 | ):
1456 | task.finished_time = task.elapsed
1457 |
1458 | if refresh:
1459 | self.refresh()
1460 |
1461 | def reset(
1462 | self,
1463 | task_id: TaskID,
1464 | *,
1465 | start: bool = True,
1466 | total: Optional[float] = None,
1467 | completed: int = 0,
1468 | visible: Optional[bool] = None,
1469 | description: Optional[str] = None,
1470 | **fields: Any,
1471 | ) -> None:
1472 | """Reset a task so completed is 0 and the clock is reset.
1473 |
1474 | Args:
1475 | task_id (TaskID): ID of task.
1476 | start (bool, optional): Start the task after reset. Defaults to True.
1477 | total (float, optional): New total steps in task, or None to use current total. Defaults to None.
1478 | completed (int, optional): Number of steps completed. Defaults to 0.
1479 | visible (bool, optional): Enable display of the task. Defaults to True.
1480 | description (str, optional): Change task description if not None. Defaults to None.
1481 | **fields (str): Additional data fields required for rendering.
1482 | """
1483 | current_time = self.get_time()
1484 | with self._lock:
1485 | task = self._tasks[task_id]
1486 | task._reset()
1487 | task.start_time = current_time if start else None
1488 | if total is not None:
1489 | task.total = total
1490 | task.completed = completed
1491 | if visible is not None:
1492 | task.visible = visible
1493 | if fields:
1494 | task.fields = fields
1495 | if description is not None:
1496 | task.description = description
1497 | task.finished_time = None
1498 | self.refresh()
1499 |
1500 | def advance(self, task_id: TaskID, advance: float = 1) -> None:
1501 | """Advance task by a number of steps.
1502 |
1503 | Args:
1504 | task_id (TaskID): ID of task.
1505 | advance (float): Number of steps to advance. Default is 1.
1506 | """
1507 | current_time = self.get_time()
1508 | with self._lock:
1509 | task = self._tasks[task_id]
1510 | completed_start = task.completed
1511 | task.completed += advance
1512 | update_completed = task.completed - completed_start
1513 | old_sample_time = current_time - self.speed_estimate_period
1514 | _progress = task._progress
1515 |
1516 | popleft = _progress.popleft
1517 | while _progress and _progress[0].timestamp < old_sample_time:
1518 | popleft()
1519 | while len(_progress) > 1000:
1520 | popleft()
1521 | _progress.append(ProgressSample(current_time, update_completed))
1522 | if (
1523 | task.total is not None
1524 | and task.completed >= task.total
1525 | and task.finished_time is None
1526 | ):
1527 | task.finished_time = task.elapsed
1528 | task.finished_speed = task.speed
1529 |
1530 | def refresh(self) -> None:
1531 | """Refresh (render) the progress information."""
1532 | if not self.disable and self.live.is_started:
1533 | self.live.refresh()
1534 |
1535 | def get_renderable(self) -> RenderableType:
1536 | """Get a renderable for the progress display."""
1537 | renderable = Group(*self.get_renderables())
1538 | return renderable
1539 |
1540 | def get_renderables(self) -> Iterable[RenderableType]:
1541 | """Get a number of renderables for the progress display."""
1542 | table = self.make_tasks_table(self.tasks)
1543 | yield table
1544 |
1545 | def make_tasks_table(self, tasks: Iterable[Task]) -> Table:
1546 | """Get a table to render the Progress display.
1547 |
1548 | Args:
1549 | tasks (Iterable[Task]): An iterable of Task instances, one per row of the table.
1550 |
1551 | Returns:
1552 | Table: A table instance.
1553 | """
1554 | table_columns = (
1555 | (
1556 | Column(no_wrap=True)
1557 | if isinstance(_column, str)
1558 | else _column.get_table_column().copy()
1559 | )
1560 | for _column in self.columns
1561 | )
1562 | table = Table.grid(*table_columns, padding=(0, 1), expand=self.expand)
1563 |
1564 | for task in tasks:
1565 | if task.visible:
1566 | table.add_row(
1567 | *(
1568 | (
1569 | column.format(task=task)
1570 | if isinstance(column, str)
1571 | else column(task)
1572 | )
1573 | for column in self.columns
1574 | )
1575 | )
1576 | return table
1577 |
1578 | def __rich__(self) -> RenderableType:
1579 | """Makes the Progress class itself renderable."""
1580 | with self._lock:
1581 | return self.get_renderable()
1582 |
1583 | def add_task(
1584 | self,
1585 | description: str,
1586 | start: bool = True,
1587 | total: Optional[float] = 100.0,
1588 | completed: int = 0,
1589 | visible: bool = True,
1590 | **fields: Any,
1591 | ) -> TaskID:
1592 | """Add a new 'task' to the Progress display.
1593 |
1594 | Args:
1595 | description (str): A description of the task.
1596 | start (bool, optional): Start the task immediately (to calculate elapsed time). If set to False,
1597 | you will need to call `start` manually. Defaults to True.
1598 | total (float, optional): Number of total steps in the progress if known.
1599 | Set to None to render a pulsing animation. Defaults to 100.
1600 | completed (int, optional): Number of steps completed so far. Defaults to 0.
1601 | visible (bool, optional): Enable display of the task. Defaults to True.
1602 | **fields (str): Additional data fields required for rendering.
1603 |
1604 | Returns:
1605 | TaskID: An ID you can use when calling `update`.
1606 | """
1607 | with self._lock:
1608 | task = Task(
1609 | self._task_index,
1610 | description,
1611 | total,
1612 | completed,
1613 | visible=visible,
1614 | fields=fields,
1615 | _get_time=self.get_time,
1616 | _lock=self._lock,
1617 | )
1618 | self._tasks[self._task_index] = task
1619 | if start:
1620 | self.start_task(self._task_index)
1621 | new_task_index = self._task_index
1622 | self._task_index = TaskID(int(self._task_index) + 1)
1623 | self.refresh()
1624 | return new_task_index
1625 |
1626 | def remove_task(self, task_id: TaskID) -> None:
1627 | """Delete a task if it exists.
1628 |
1629 | Args:
1630 | task_id (TaskID): A task ID.
1631 |
1632 | """
1633 | with self._lock:
1634 | del self._tasks[task_id]
1635 |
1636 |
1637 | if __name__ == "__main__": # pragma: no coverage
1638 | import random
1639 | import time
1640 |
1641 | from .panel import Panel
1642 | from .rule import Rule
1643 | from .syntax import Syntax
1644 | from .table import Table
1645 |
1646 | syntax = Syntax(
1647 | '''def loop_last(values: Iterable[T]) -> Iterable[Tuple[bool, T]]:
1648 | """Iterate and generate a tuple with a flag for last value."""
1649 | iter_values = iter(values)
1650 | try:
1651 | previous_value = next(iter_values)
1652 | except StopIteration:
1653 | return
1654 | for value in iter_values:
1655 | yield False, previous_value
1656 | previous_value = value
1657 | yield True, previous_value''',
1658 | "python",
1659 | line_numbers=True,
1660 | )
1661 |
1662 | table = Table("foo", "bar", "baz")
1663 | table.add_row("1", "2", "3")
1664 |
1665 | progress_renderables = [
1666 | "Text may be printed while the progress bars are rendering.",
1667 | Panel("In fact, [i]any[/i] renderable will work"),
1668 | "Such as [magenta]tables[/]...",
1669 | table,
1670 | "Pretty printed structures...",
1671 | {"type": "example", "text": "Pretty printed"},
1672 | "Syntax...",
1673 | syntax,
1674 | Rule("Give it a try!"),
1675 | ]
1676 |
1677 | from itertools import cycle
1678 |
1679 | examples = cycle(progress_renderables)
1680 |
1681 | console = Console(record=True)
1682 |
1683 | with Progress(
1684 | SpinnerColumn(),
1685 | *Progress.get_default_columns(),
1686 | TimeElapsedColumn(),
1687 | console=console,
1688 | transient=False,
1689 | ) as progress:
1690 | task1 = progress.add_task("[red]Downloading", total=1000)
1691 | task2 = progress.add_task("[green]Processing", total=1000)
1692 | task3 = progress.add_task("[yellow]Thinking", total=None)
1693 |
1694 | while not progress.finished:
1695 | progress.update(task1, advance=0.5)
1696 | progress.update(task2, advance=0.3)
1697 | time.sleep(0.01)
1698 | if random.randint(0, 100) < 1:
1699 | progress.log(next(examples))
1700 |
```