This is page 143 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/distro/distro.py:
--------------------------------------------------------------------------------
```python
1 | #!/usr/bin/env python
2 | # Copyright 2015-2021 Nir Cohen
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 |
16 | """
17 | The ``distro`` package (``distro`` stands for Linux Distribution) provides
18 | information about the Linux distribution it runs on, such as a reliable
19 | machine-readable distro ID, or version information.
20 |
21 | It is the recommended replacement for Python's original
22 | :py:func:`platform.linux_distribution` function, but it provides much more
23 | functionality. An alternative implementation became necessary because Python
24 | 3.5 deprecated this function, and Python 3.8 removed it altogether. Its
25 | predecessor function :py:func:`platform.dist` was already deprecated since
26 | Python 2.6 and removed in Python 3.8. Still, there are many cases in which
27 | access to OS distribution information is needed. See `Python issue 1322
28 | <https://bugs.python.org/issue1322>`_ for more information.
29 | """
30 |
31 | import argparse
32 | import json
33 | import logging
34 | import os
35 | import re
36 | import shlex
37 | import subprocess
38 | import sys
39 | import warnings
40 | from typing import (
41 | Any,
42 | Callable,
43 | Dict,
44 | Iterable,
45 | Optional,
46 | Sequence,
47 | TextIO,
48 | Tuple,
49 | Type,
50 | )
51 |
52 | try:
53 | from typing import TypedDict
54 | except ImportError:
55 | # Python 3.7
56 | TypedDict = dict
57 |
58 | __version__ = "1.9.0"
59 |
60 |
61 | class VersionDict(TypedDict):
62 | major: str
63 | minor: str
64 | build_number: str
65 |
66 |
67 | class InfoDict(TypedDict):
68 | id: str
69 | version: str
70 | version_parts: VersionDict
71 | like: str
72 | codename: str
73 |
74 |
75 | _UNIXCONFDIR = os.environ.get("UNIXCONFDIR", "/etc")
76 | _UNIXUSRLIBDIR = os.environ.get("UNIXUSRLIBDIR", "/usr/lib")
77 | _OS_RELEASE_BASENAME = "os-release"
78 |
79 | #: Translation table for normalizing the "ID" attribute defined in os-release
80 | #: files, for use by the :func:`distro.id` method.
81 | #:
82 | #: * Key: Value as defined in the os-release file, translated to lower case,
83 | #: with blanks translated to underscores.
84 | #:
85 | #: * Value: Normalized value.
86 | NORMALIZED_OS_ID = {
87 | "ol": "oracle", # Oracle Linux
88 | "opensuse-leap": "opensuse", # Newer versions of OpenSuSE report as opensuse-leap
89 | }
90 |
91 | #: Translation table for normalizing the "Distributor ID" attribute returned by
92 | #: the lsb_release command, for use by the :func:`distro.id` method.
93 | #:
94 | #: * Key: Value as returned by the lsb_release command, translated to lower
95 | #: case, with blanks translated to underscores.
96 | #:
97 | #: * Value: Normalized value.
98 | NORMALIZED_LSB_ID = {
99 | "enterpriseenterpriseas": "oracle", # Oracle Enterprise Linux 4
100 | "enterpriseenterpriseserver": "oracle", # Oracle Linux 5
101 | "redhatenterpriseworkstation": "rhel", # RHEL 6, 7 Workstation
102 | "redhatenterpriseserver": "rhel", # RHEL 6, 7 Server
103 | "redhatenterprisecomputenode": "rhel", # RHEL 6 ComputeNode
104 | }
105 |
106 | #: Translation table for normalizing the distro ID derived from the file name
107 | #: of distro release files, for use by the :func:`distro.id` method.
108 | #:
109 | #: * Key: Value as derived from the file name of a distro release file,
110 | #: translated to lower case, with blanks translated to underscores.
111 | #:
112 | #: * Value: Normalized value.
113 | NORMALIZED_DISTRO_ID = {
114 | "redhat": "rhel", # RHEL 6.x, 7.x
115 | }
116 |
117 | # Pattern for content of distro release file (reversed)
118 | _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN = re.compile(
119 | r"(?:[^)]*\)(.*)\()? *(?:STL )?([\d.+\-a-z]*\d) *(?:esaeler *)?(.+)"
120 | )
121 |
122 | # Pattern for base file name of distro release file
123 | _DISTRO_RELEASE_BASENAME_PATTERN = re.compile(r"(\w+)[-_](release|version)$")
124 |
125 | # Base file names to be looked up for if _UNIXCONFDIR is not readable.
126 | _DISTRO_RELEASE_BASENAMES = [
127 | "SuSE-release",
128 | "altlinux-release",
129 | "arch-release",
130 | "base-release",
131 | "centos-release",
132 | "fedora-release",
133 | "gentoo-release",
134 | "mageia-release",
135 | "mandrake-release",
136 | "mandriva-release",
137 | "mandrivalinux-release",
138 | "manjaro-release",
139 | "oracle-release",
140 | "redhat-release",
141 | "rocky-release",
142 | "sl-release",
143 | "slackware-version",
144 | ]
145 |
146 | # Base file names to be ignored when searching for distro release file
147 | _DISTRO_RELEASE_IGNORE_BASENAMES = (
148 | "debian_version",
149 | "lsb-release",
150 | "oem-release",
151 | _OS_RELEASE_BASENAME,
152 | "system-release",
153 | "plesk-release",
154 | "iredmail-release",
155 | "board-release",
156 | "ec2_version",
157 | )
158 |
159 |
160 | def linux_distribution(full_distribution_name: bool = True) -> Tuple[str, str, str]:
161 | """
162 | .. deprecated:: 1.6.0
163 |
164 | :func:`distro.linux_distribution()` is deprecated. It should only be
165 | used as a compatibility shim with Python's
166 | :py:func:`platform.linux_distribution()`. Please use :func:`distro.id`,
167 | :func:`distro.version` and :func:`distro.name` instead.
168 |
169 | Return information about the current OS distribution as a tuple
170 | ``(id_name, version, codename)`` with items as follows:
171 |
172 | * ``id_name``: If *full_distribution_name* is false, the result of
173 | :func:`distro.id`. Otherwise, the result of :func:`distro.name`.
174 |
175 | * ``version``: The result of :func:`distro.version`.
176 |
177 | * ``codename``: The extra item (usually in parentheses) after the
178 | os-release version number, or the result of :func:`distro.codename`.
179 |
180 | The interface of this function is compatible with the original
181 | :py:func:`platform.linux_distribution` function, supporting a subset of
182 | its parameters.
183 |
184 | The data it returns may not exactly be the same, because it uses more data
185 | sources than the original function, and that may lead to different data if
186 | the OS distribution is not consistent across multiple data sources it
187 | provides (there are indeed such distributions ...).
188 |
189 | Another reason for differences is the fact that the :func:`distro.id`
190 | method normalizes the distro ID string to a reliable machine-readable value
191 | for a number of popular OS distributions.
192 | """
193 | warnings.warn(
194 | "distro.linux_distribution() is deprecated. It should only be used as a "
195 | "compatibility shim with Python's platform.linux_distribution(). Please use "
196 | "distro.id(), distro.version() and distro.name() instead.",
197 | DeprecationWarning,
198 | stacklevel=2,
199 | )
200 | return _distro.linux_distribution(full_distribution_name)
201 |
202 |
203 | def id() -> str:
204 | """
205 | Return the distro ID of the current distribution, as a
206 | machine-readable string.
207 |
208 | For a number of OS distributions, the returned distro ID value is
209 | *reliable*, in the sense that it is documented and that it does not change
210 | across releases of the distribution.
211 |
212 | This package maintains the following reliable distro ID values:
213 |
214 | ============== =========================================
215 | Distro ID Distribution
216 | ============== =========================================
217 | "ubuntu" Ubuntu
218 | "debian" Debian
219 | "rhel" RedHat Enterprise Linux
220 | "centos" CentOS
221 | "fedora" Fedora
222 | "sles" SUSE Linux Enterprise Server
223 | "opensuse" openSUSE
224 | "amzn" Amazon Linux
225 | "arch" Arch Linux
226 | "buildroot" Buildroot
227 | "cloudlinux" CloudLinux OS
228 | "exherbo" Exherbo Linux
229 | "gentoo" GenToo Linux
230 | "ibm_powerkvm" IBM PowerKVM
231 | "kvmibm" KVM for IBM z Systems
232 | "linuxmint" Linux Mint
233 | "mageia" Mageia
234 | "mandriva" Mandriva Linux
235 | "parallels" Parallels
236 | "pidora" Pidora
237 | "raspbian" Raspbian
238 | "oracle" Oracle Linux (and Oracle Enterprise Linux)
239 | "scientific" Scientific Linux
240 | "slackware" Slackware
241 | "xenserver" XenServer
242 | "openbsd" OpenBSD
243 | "netbsd" NetBSD
244 | "freebsd" FreeBSD
245 | "midnightbsd" MidnightBSD
246 | "rocky" Rocky Linux
247 | "aix" AIX
248 | "guix" Guix System
249 | "altlinux" ALT Linux
250 | ============== =========================================
251 |
252 | If you have a need to get distros for reliable IDs added into this set,
253 | or if you find that the :func:`distro.id` function returns a different
254 | distro ID for one of the listed distros, please create an issue in the
255 | `distro issue tracker`_.
256 |
257 | **Lookup hierarchy and transformations:**
258 |
259 | First, the ID is obtained from the following sources, in the specified
260 | order. The first available and non-empty value is used:
261 |
262 | * the value of the "ID" attribute of the os-release file,
263 |
264 | * the value of the "Distributor ID" attribute returned by the lsb_release
265 | command,
266 |
267 | * the first part of the file name of the distro release file,
268 |
269 | The so determined ID value then passes the following transformations,
270 | before it is returned by this method:
271 |
272 | * it is translated to lower case,
273 |
274 | * blanks (which should not be there anyway) are translated to underscores,
275 |
276 | * a normalization of the ID is performed, based upon
277 | `normalization tables`_. The purpose of this normalization is to ensure
278 | that the ID is as reliable as possible, even across incompatible changes
279 | in the OS distributions. A common reason for an incompatible change is
280 | the addition of an os-release file, or the addition of the lsb_release
281 | command, with ID values that differ from what was previously determined
282 | from the distro release file name.
283 | """
284 | return _distro.id()
285 |
286 |
287 | def name(pretty: bool = False) -> str:
288 | """
289 | Return the name of the current OS distribution, as a human-readable
290 | string.
291 |
292 | If *pretty* is false, the name is returned without version or codename.
293 | (e.g. "CentOS Linux")
294 |
295 | If *pretty* is true, the version and codename are appended.
296 | (e.g. "CentOS Linux 7.1.1503 (Core)")
297 |
298 | **Lookup hierarchy:**
299 |
300 | The name is obtained from the following sources, in the specified order.
301 | The first available and non-empty value is used:
302 |
303 | * If *pretty* is false:
304 |
305 | - the value of the "NAME" attribute of the os-release file,
306 |
307 | - the value of the "Distributor ID" attribute returned by the lsb_release
308 | command,
309 |
310 | - the value of the "<name>" field of the distro release file.
311 |
312 | * If *pretty* is true:
313 |
314 | - the value of the "PRETTY_NAME" attribute of the os-release file,
315 |
316 | - the value of the "Description" attribute returned by the lsb_release
317 | command,
318 |
319 | - the value of the "<name>" field of the distro release file, appended
320 | with the value of the pretty version ("<version_id>" and "<codename>"
321 | fields) of the distro release file, if available.
322 | """
323 | return _distro.name(pretty)
324 |
325 |
326 | def version(pretty: bool = False, best: bool = False) -> str:
327 | """
328 | Return the version of the current OS distribution, as a human-readable
329 | string.
330 |
331 | If *pretty* is false, the version is returned without codename (e.g.
332 | "7.0").
333 |
334 | If *pretty* is true, the codename in parenthesis is appended, if the
335 | codename is non-empty (e.g. "7.0 (Maipo)").
336 |
337 | Some distributions provide version numbers with different precisions in
338 | the different sources of distribution information. Examining the different
339 | sources in a fixed priority order does not always yield the most precise
340 | version (e.g. for Debian 8.2, or CentOS 7.1).
341 |
342 | Some other distributions may not provide this kind of information. In these
343 | cases, an empty string would be returned. This behavior can be observed
344 | with rolling releases distributions (e.g. Arch Linux).
345 |
346 | The *best* parameter can be used to control the approach for the returned
347 | version:
348 |
349 | If *best* is false, the first non-empty version number in priority order of
350 | the examined sources is returned.
351 |
352 | If *best* is true, the most precise version number out of all examined
353 | sources is returned.
354 |
355 | **Lookup hierarchy:**
356 |
357 | In all cases, the version number is obtained from the following sources.
358 | If *best* is false, this order represents the priority order:
359 |
360 | * the value of the "VERSION_ID" attribute of the os-release file,
361 | * the value of the "Release" attribute returned by the lsb_release
362 | command,
363 | * the version number parsed from the "<version_id>" field of the first line
364 | of the distro release file,
365 | * the version number parsed from the "PRETTY_NAME" attribute of the
366 | os-release file, if it follows the format of the distro release files.
367 | * the version number parsed from the "Description" attribute returned by
368 | the lsb_release command, if it follows the format of the distro release
369 | files.
370 | """
371 | return _distro.version(pretty, best)
372 |
373 |
374 | def version_parts(best: bool = False) -> Tuple[str, str, str]:
375 | """
376 | Return the version of the current OS distribution as a tuple
377 | ``(major, minor, build_number)`` with items as follows:
378 |
379 | * ``major``: The result of :func:`distro.major_version`.
380 |
381 | * ``minor``: The result of :func:`distro.minor_version`.
382 |
383 | * ``build_number``: The result of :func:`distro.build_number`.
384 |
385 | For a description of the *best* parameter, see the :func:`distro.version`
386 | method.
387 | """
388 | return _distro.version_parts(best)
389 |
390 |
391 | def major_version(best: bool = False) -> str:
392 | """
393 | Return the major version of the current OS distribution, as a string,
394 | if provided.
395 | Otherwise, the empty string is returned. The major version is the first
396 | part of the dot-separated version string.
397 |
398 | For a description of the *best* parameter, see the :func:`distro.version`
399 | method.
400 | """
401 | return _distro.major_version(best)
402 |
403 |
404 | def minor_version(best: bool = False) -> str:
405 | """
406 | Return the minor version of the current OS distribution, as a string,
407 | if provided.
408 | Otherwise, the empty string is returned. The minor version is the second
409 | part of the dot-separated version string.
410 |
411 | For a description of the *best* parameter, see the :func:`distro.version`
412 | method.
413 | """
414 | return _distro.minor_version(best)
415 |
416 |
417 | def build_number(best: bool = False) -> str:
418 | """
419 | Return the build number of the current OS distribution, as a string,
420 | if provided.
421 | Otherwise, the empty string is returned. The build number is the third part
422 | of the dot-separated version string.
423 |
424 | For a description of the *best* parameter, see the :func:`distro.version`
425 | method.
426 | """
427 | return _distro.build_number(best)
428 |
429 |
430 | def like() -> str:
431 | """
432 | Return a space-separated list of distro IDs of distributions that are
433 | closely related to the current OS distribution in regards to packaging
434 | and programming interfaces, for example distributions the current
435 | distribution is a derivative from.
436 |
437 | **Lookup hierarchy:**
438 |
439 | This information item is only provided by the os-release file.
440 | For details, see the description of the "ID_LIKE" attribute in the
441 | `os-release man page
442 | <http://www.freedesktop.org/software/systemd/man/os-release.html>`_.
443 | """
444 | return _distro.like()
445 |
446 |
447 | def codename() -> str:
448 | """
449 | Return the codename for the release of the current OS distribution,
450 | as a string.
451 |
452 | If the distribution does not have a codename, an empty string is returned.
453 |
454 | Note that the returned codename is not always really a codename. For
455 | example, openSUSE returns "x86_64". This function does not handle such
456 | cases in any special way and just returns the string it finds, if any.
457 |
458 | **Lookup hierarchy:**
459 |
460 | * the codename within the "VERSION" attribute of the os-release file, if
461 | provided,
462 |
463 | * the value of the "Codename" attribute returned by the lsb_release
464 | command,
465 |
466 | * the value of the "<codename>" field of the distro release file.
467 | """
468 | return _distro.codename()
469 |
470 |
471 | def info(pretty: bool = False, best: bool = False) -> InfoDict:
472 | """
473 | Return certain machine-readable information items about the current OS
474 | distribution in a dictionary, as shown in the following example:
475 |
476 | .. sourcecode:: python
477 |
478 | {
479 | 'id': 'rhel',
480 | 'version': '7.0',
481 | 'version_parts': {
482 | 'major': '7',
483 | 'minor': '0',
484 | 'build_number': ''
485 | },
486 | 'like': 'fedora',
487 | 'codename': 'Maipo'
488 | }
489 |
490 | The dictionary structure and keys are always the same, regardless of which
491 | information items are available in the underlying data sources. The values
492 | for the various keys are as follows:
493 |
494 | * ``id``: The result of :func:`distro.id`.
495 |
496 | * ``version``: The result of :func:`distro.version`.
497 |
498 | * ``version_parts -> major``: The result of :func:`distro.major_version`.
499 |
500 | * ``version_parts -> minor``: The result of :func:`distro.minor_version`.
501 |
502 | * ``version_parts -> build_number``: The result of
503 | :func:`distro.build_number`.
504 |
505 | * ``like``: The result of :func:`distro.like`.
506 |
507 | * ``codename``: The result of :func:`distro.codename`.
508 |
509 | For a description of the *pretty* and *best* parameters, see the
510 | :func:`distro.version` method.
511 | """
512 | return _distro.info(pretty, best)
513 |
514 |
515 | def os_release_info() -> Dict[str, str]:
516 | """
517 | Return a dictionary containing key-value pairs for the information items
518 | from the os-release file data source of the current OS distribution.
519 |
520 | See `os-release file`_ for details about these information items.
521 | """
522 | return _distro.os_release_info()
523 |
524 |
525 | def lsb_release_info() -> Dict[str, str]:
526 | """
527 | Return a dictionary containing key-value pairs for the information items
528 | from the lsb_release command data source of the current OS distribution.
529 |
530 | See `lsb_release command output`_ for details about these information
531 | items.
532 | """
533 | return _distro.lsb_release_info()
534 |
535 |
536 | def distro_release_info() -> Dict[str, str]:
537 | """
538 | Return a dictionary containing key-value pairs for the information items
539 | from the distro release file data source of the current OS distribution.
540 |
541 | See `distro release file`_ for details about these information items.
542 | """
543 | return _distro.distro_release_info()
544 |
545 |
546 | def uname_info() -> Dict[str, str]:
547 | """
548 | Return a dictionary containing key-value pairs for the information items
549 | from the distro release file data source of the current OS distribution.
550 | """
551 | return _distro.uname_info()
552 |
553 |
554 | def os_release_attr(attribute: str) -> str:
555 | """
556 | Return a single named information item from the os-release file data source
557 | of the current OS distribution.
558 |
559 | Parameters:
560 |
561 | * ``attribute`` (string): Key of the information item.
562 |
563 | Returns:
564 |
565 | * (string): Value of the information item, if the item exists.
566 | The empty string, if the item does not exist.
567 |
568 | See `os-release file`_ for details about these information items.
569 | """
570 | return _distro.os_release_attr(attribute)
571 |
572 |
573 | def lsb_release_attr(attribute: str) -> str:
574 | """
575 | Return a single named information item from the lsb_release command output
576 | data source of the current OS distribution.
577 |
578 | Parameters:
579 |
580 | * ``attribute`` (string): Key of the information item.
581 |
582 | Returns:
583 |
584 | * (string): Value of the information item, if the item exists.
585 | The empty string, if the item does not exist.
586 |
587 | See `lsb_release command output`_ for details about these information
588 | items.
589 | """
590 | return _distro.lsb_release_attr(attribute)
591 |
592 |
593 | def distro_release_attr(attribute: str) -> str:
594 | """
595 | Return a single named information item from the distro release file
596 | data source of the current OS distribution.
597 |
598 | Parameters:
599 |
600 | * ``attribute`` (string): Key of the information item.
601 |
602 | Returns:
603 |
604 | * (string): Value of the information item, if the item exists.
605 | The empty string, if the item does not exist.
606 |
607 | See `distro release file`_ for details about these information items.
608 | """
609 | return _distro.distro_release_attr(attribute)
610 |
611 |
612 | def uname_attr(attribute: str) -> str:
613 | """
614 | Return a single named information item from the distro release file
615 | data source of the current OS distribution.
616 |
617 | Parameters:
618 |
619 | * ``attribute`` (string): Key of the information item.
620 |
621 | Returns:
622 |
623 | * (string): Value of the information item, if the item exists.
624 | The empty string, if the item does not exist.
625 | """
626 | return _distro.uname_attr(attribute)
627 |
628 |
629 | try:
630 | from functools import cached_property
631 | except ImportError:
632 | # Python < 3.8
633 | class cached_property: # type: ignore
634 | """A version of @property which caches the value. On access, it calls the
635 | underlying function and sets the value in `__dict__` so future accesses
636 | will not re-call the property.
637 | """
638 |
639 | def __init__(self, f: Callable[[Any], Any]) -> None:
640 | self._fname = f.__name__
641 | self._f = f
642 |
643 | def __get__(self, obj: Any, owner: Type[Any]) -> Any:
644 | assert obj is not None, f"call {self._fname} on an instance"
645 | ret = obj.__dict__[self._fname] = self._f(obj)
646 | return ret
647 |
648 |
649 | class LinuxDistribution:
650 | """
651 | Provides information about a OS distribution.
652 |
653 | This package creates a private module-global instance of this class with
654 | default initialization arguments, that is used by the
655 | `consolidated accessor functions`_ and `single source accessor functions`_.
656 | By using default initialization arguments, that module-global instance
657 | returns data about the current OS distribution (i.e. the distro this
658 | package runs on).
659 |
660 | Normally, it is not necessary to create additional instances of this class.
661 | However, in situations where control is needed over the exact data sources
662 | that are used, instances of this class can be created with a specific
663 | distro release file, or a specific os-release file, or without invoking the
664 | lsb_release command.
665 | """
666 |
667 | def __init__(
668 | self,
669 | include_lsb: Optional[bool] = None,
670 | os_release_file: str = "",
671 | distro_release_file: str = "",
672 | include_uname: Optional[bool] = None,
673 | root_dir: Optional[str] = None,
674 | include_oslevel: Optional[bool] = None,
675 | ) -> None:
676 | """
677 | The initialization method of this class gathers information from the
678 | available data sources, and stores that in private instance attributes.
679 | Subsequent access to the information items uses these private instance
680 | attributes, so that the data sources are read only once.
681 |
682 | Parameters:
683 |
684 | * ``include_lsb`` (bool): Controls whether the
685 | `lsb_release command output`_ is included as a data source.
686 |
687 | If the lsb_release command is not available in the program execution
688 | path, the data source for the lsb_release command will be empty.
689 |
690 | * ``os_release_file`` (string): The path name of the
691 | `os-release file`_ that is to be used as a data source.
692 |
693 | An empty string (the default) will cause the default path name to
694 | be used (see `os-release file`_ for details).
695 |
696 | If the specified or defaulted os-release file does not exist, the
697 | data source for the os-release file will be empty.
698 |
699 | * ``distro_release_file`` (string): The path name of the
700 | `distro release file`_ that is to be used as a data source.
701 |
702 | An empty string (the default) will cause a default search algorithm
703 | to be used (see `distro release file`_ for details).
704 |
705 | If the specified distro release file does not exist, or if no default
706 | distro release file can be found, the data source for the distro
707 | release file will be empty.
708 |
709 | * ``include_uname`` (bool): Controls whether uname command output is
710 | included as a data source. If the uname command is not available in
711 | the program execution path the data source for the uname command will
712 | be empty.
713 |
714 | * ``root_dir`` (string): The absolute path to the root directory to use
715 | to find distro-related information files. Note that ``include_*``
716 | parameters must not be enabled in combination with ``root_dir``.
717 |
718 | * ``include_oslevel`` (bool): Controls whether (AIX) oslevel command
719 | output is included as a data source. If the oslevel command is not
720 | available in the program execution path the data source will be
721 | empty.
722 |
723 | Public instance attributes:
724 |
725 | * ``os_release_file`` (string): The path name of the
726 | `os-release file`_ that is actually used as a data source. The
727 | empty string if no distro release file is used as a data source.
728 |
729 | * ``distro_release_file`` (string): The path name of the
730 | `distro release file`_ that is actually used as a data source. The
731 | empty string if no distro release file is used as a data source.
732 |
733 | * ``include_lsb`` (bool): The result of the ``include_lsb`` parameter.
734 | This controls whether the lsb information will be loaded.
735 |
736 | * ``include_uname`` (bool): The result of the ``include_uname``
737 | parameter. This controls whether the uname information will
738 | be loaded.
739 |
740 | * ``include_oslevel`` (bool): The result of the ``include_oslevel``
741 | parameter. This controls whether (AIX) oslevel information will be
742 | loaded.
743 |
744 | * ``root_dir`` (string): The result of the ``root_dir`` parameter.
745 | The absolute path to the root directory to use to find distro-related
746 | information files.
747 |
748 | Raises:
749 |
750 | * :py:exc:`ValueError`: Initialization parameters combination is not
751 | supported.
752 |
753 | * :py:exc:`OSError`: Some I/O issue with an os-release file or distro
754 | release file.
755 |
756 | * :py:exc:`UnicodeError`: A data source has unexpected characters or
757 | uses an unexpected encoding.
758 | """
759 | self.root_dir = root_dir
760 | self.etc_dir = os.path.join(root_dir, "etc") if root_dir else _UNIXCONFDIR
761 | self.usr_lib_dir = (
762 | os.path.join(root_dir, "usr/lib") if root_dir else _UNIXUSRLIBDIR
763 | )
764 |
765 | if os_release_file:
766 | self.os_release_file = os_release_file
767 | else:
768 | etc_dir_os_release_file = os.path.join(self.etc_dir, _OS_RELEASE_BASENAME)
769 | usr_lib_os_release_file = os.path.join(
770 | self.usr_lib_dir, _OS_RELEASE_BASENAME
771 | )
772 |
773 | # NOTE: The idea is to respect order **and** have it set
774 | # at all times for API backwards compatibility.
775 | if os.path.isfile(etc_dir_os_release_file) or not os.path.isfile(
776 | usr_lib_os_release_file
777 | ):
778 | self.os_release_file = etc_dir_os_release_file
779 | else:
780 | self.os_release_file = usr_lib_os_release_file
781 |
782 | self.distro_release_file = distro_release_file or "" # updated later
783 |
784 | is_root_dir_defined = root_dir is not None
785 | if is_root_dir_defined and (include_lsb or include_uname or include_oslevel):
786 | raise ValueError(
787 | "Including subprocess data sources from specific root_dir is disallowed"
788 | " to prevent false information"
789 | )
790 | self.include_lsb = (
791 | include_lsb if include_lsb is not None else not is_root_dir_defined
792 | )
793 | self.include_uname = (
794 | include_uname if include_uname is not None else not is_root_dir_defined
795 | )
796 | self.include_oslevel = (
797 | include_oslevel if include_oslevel is not None else not is_root_dir_defined
798 | )
799 |
800 | def __repr__(self) -> str:
801 | """Return repr of all info"""
802 | return (
803 | "LinuxDistribution("
804 | "os_release_file={self.os_release_file!r}, "
805 | "distro_release_file={self.distro_release_file!r}, "
806 | "include_lsb={self.include_lsb!r}, "
807 | "include_uname={self.include_uname!r}, "
808 | "include_oslevel={self.include_oslevel!r}, "
809 | "root_dir={self.root_dir!r}, "
810 | "_os_release_info={self._os_release_info!r}, "
811 | "_lsb_release_info={self._lsb_release_info!r}, "
812 | "_distro_release_info={self._distro_release_info!r}, "
813 | "_uname_info={self._uname_info!r}, "
814 | "_oslevel_info={self._oslevel_info!r})".format(self=self)
815 | )
816 |
817 | def linux_distribution(
818 | self, full_distribution_name: bool = True
819 | ) -> Tuple[str, str, str]:
820 | """
821 | Return information about the OS distribution that is compatible
822 | with Python's :func:`platform.linux_distribution`, supporting a subset
823 | of its parameters.
824 |
825 | For details, see :func:`distro.linux_distribution`.
826 | """
827 | return (
828 | self.name() if full_distribution_name else self.id(),
829 | self.version(),
830 | self._os_release_info.get("release_codename") or self.codename(),
831 | )
832 |
833 | def id(self) -> str:
834 | """Return the distro ID of the OS distribution, as a string.
835 |
836 | For details, see :func:`distro.id`.
837 | """
838 |
839 | def normalize(distro_id: str, table: Dict[str, str]) -> str:
840 | distro_id = distro_id.lower().replace(" ", "_")
841 | return table.get(distro_id, distro_id)
842 |
843 | distro_id = self.os_release_attr("id")
844 | if distro_id:
845 | return normalize(distro_id, NORMALIZED_OS_ID)
846 |
847 | distro_id = self.lsb_release_attr("distributor_id")
848 | if distro_id:
849 | return normalize(distro_id, NORMALIZED_LSB_ID)
850 |
851 | distro_id = self.distro_release_attr("id")
852 | if distro_id:
853 | return normalize(distro_id, NORMALIZED_DISTRO_ID)
854 |
855 | distro_id = self.uname_attr("id")
856 | if distro_id:
857 | return normalize(distro_id, NORMALIZED_DISTRO_ID)
858 |
859 | return ""
860 |
861 | def name(self, pretty: bool = False) -> str:
862 | """
863 | Return the name of the OS distribution, as a string.
864 |
865 | For details, see :func:`distro.name`.
866 | """
867 | name = (
868 | self.os_release_attr("name")
869 | or self.lsb_release_attr("distributor_id")
870 | or self.distro_release_attr("name")
871 | or self.uname_attr("name")
872 | )
873 | if pretty:
874 | name = self.os_release_attr("pretty_name") or self.lsb_release_attr(
875 | "description"
876 | )
877 | if not name:
878 | name = self.distro_release_attr("name") or self.uname_attr("name")
879 | version = self.version(pretty=True)
880 | if version:
881 | name = f"{name} {version}"
882 | return name or ""
883 |
884 | def version(self, pretty: bool = False, best: bool = False) -> str:
885 | """
886 | Return the version of the OS distribution, as a string.
887 |
888 | For details, see :func:`distro.version`.
889 | """
890 | versions = [
891 | self.os_release_attr("version_id"),
892 | self.lsb_release_attr("release"),
893 | self.distro_release_attr("version_id"),
894 | self._parse_distro_release_content(self.os_release_attr("pretty_name")).get(
895 | "version_id", ""
896 | ),
897 | self._parse_distro_release_content(
898 | self.lsb_release_attr("description")
899 | ).get("version_id", ""),
900 | self.uname_attr("release"),
901 | ]
902 | if self.uname_attr("id").startswith("aix"):
903 | # On AIX platforms, prefer oslevel command output.
904 | versions.insert(0, self.oslevel_info())
905 | elif self.id() == "debian" or "debian" in self.like().split():
906 | # On Debian-like, add debian_version file content to candidates list.
907 | versions.append(self._debian_version)
908 | version = ""
909 | if best:
910 | # This algorithm uses the last version in priority order that has
911 | # the best precision. If the versions are not in conflict, that
912 | # does not matter; otherwise, using the last one instead of the
913 | # first one might be considered a surprise.
914 | for v in versions:
915 | if v.count(".") > version.count(".") or version == "":
916 | version = v
917 | else:
918 | for v in versions:
919 | if v != "":
920 | version = v
921 | break
922 | if pretty and version and self.codename():
923 | version = f"{version} ({self.codename()})"
924 | return version
925 |
926 | def version_parts(self, best: bool = False) -> Tuple[str, str, str]:
927 | """
928 | Return the version of the OS distribution, as a tuple of version
929 | numbers.
930 |
931 | For details, see :func:`distro.version_parts`.
932 | """
933 | version_str = self.version(best=best)
934 | if version_str:
935 | version_regex = re.compile(r"(\d+)\.?(\d+)?\.?(\d+)?")
936 | matches = version_regex.match(version_str)
937 | if matches:
938 | major, minor, build_number = matches.groups()
939 | return major, minor or "", build_number or ""
940 | return "", "", ""
941 |
942 | def major_version(self, best: bool = False) -> str:
943 | """
944 | Return the major version number of the current distribution.
945 |
946 | For details, see :func:`distro.major_version`.
947 | """
948 | return self.version_parts(best)[0]
949 |
950 | def minor_version(self, best: bool = False) -> str:
951 | """
952 | Return the minor version number of the current distribution.
953 |
954 | For details, see :func:`distro.minor_version`.
955 | """
956 | return self.version_parts(best)[1]
957 |
958 | def build_number(self, best: bool = False) -> str:
959 | """
960 | Return the build number of the current distribution.
961 |
962 | For details, see :func:`distro.build_number`.
963 | """
964 | return self.version_parts(best)[2]
965 |
966 | def like(self) -> str:
967 | """
968 | Return the IDs of distributions that are like the OS distribution.
969 |
970 | For details, see :func:`distro.like`.
971 | """
972 | return self.os_release_attr("id_like") or ""
973 |
974 | def codename(self) -> str:
975 | """
976 | Return the codename of the OS distribution.
977 |
978 | For details, see :func:`distro.codename`.
979 | """
980 | try:
981 | # Handle os_release specially since distros might purposefully set
982 | # this to empty string to have no codename
983 | return self._os_release_info["codename"]
984 | except KeyError:
985 | return (
986 | self.lsb_release_attr("codename")
987 | or self.distro_release_attr("codename")
988 | or ""
989 | )
990 |
991 | def info(self, pretty: bool = False, best: bool = False) -> InfoDict:
992 | """
993 | Return certain machine-readable information about the OS
994 | distribution.
995 |
996 | For details, see :func:`distro.info`.
997 | """
998 | return InfoDict(
999 | id=self.id(),
1000 | version=self.version(pretty, best),
1001 | version_parts=VersionDict(
1002 | major=self.major_version(best),
1003 | minor=self.minor_version(best),
1004 | build_number=self.build_number(best),
1005 | ),
1006 | like=self.like(),
1007 | codename=self.codename(),
1008 | )
1009 |
1010 | def os_release_info(self) -> Dict[str, str]:
1011 | """
1012 | Return a dictionary containing key-value pairs for the information
1013 | items from the os-release file data source of the OS distribution.
1014 |
1015 | For details, see :func:`distro.os_release_info`.
1016 | """
1017 | return self._os_release_info
1018 |
1019 | def lsb_release_info(self) -> Dict[str, str]:
1020 | """
1021 | Return a dictionary containing key-value pairs for the information
1022 | items from the lsb_release command data source of the OS
1023 | distribution.
1024 |
1025 | For details, see :func:`distro.lsb_release_info`.
1026 | """
1027 | return self._lsb_release_info
1028 |
1029 | def distro_release_info(self) -> Dict[str, str]:
1030 | """
1031 | Return a dictionary containing key-value pairs for the information
1032 | items from the distro release file data source of the OS
1033 | distribution.
1034 |
1035 | For details, see :func:`distro.distro_release_info`.
1036 | """
1037 | return self._distro_release_info
1038 |
1039 | def uname_info(self) -> Dict[str, str]:
1040 | """
1041 | Return a dictionary containing key-value pairs for the information
1042 | items from the uname command data source of the OS distribution.
1043 |
1044 | For details, see :func:`distro.uname_info`.
1045 | """
1046 | return self._uname_info
1047 |
1048 | def oslevel_info(self) -> str:
1049 | """
1050 | Return AIX' oslevel command output.
1051 | """
1052 | return self._oslevel_info
1053 |
1054 | def os_release_attr(self, attribute: str) -> str:
1055 | """
1056 | Return a single named information item from the os-release file data
1057 | source of the OS distribution.
1058 |
1059 | For details, see :func:`distro.os_release_attr`.
1060 | """
1061 | return self._os_release_info.get(attribute, "")
1062 |
1063 | def lsb_release_attr(self, attribute: str) -> str:
1064 | """
1065 | Return a single named information item from the lsb_release command
1066 | output data source of the OS distribution.
1067 |
1068 | For details, see :func:`distro.lsb_release_attr`.
1069 | """
1070 | return self._lsb_release_info.get(attribute, "")
1071 |
1072 | def distro_release_attr(self, attribute: str) -> str:
1073 | """
1074 | Return a single named information item from the distro release file
1075 | data source of the OS distribution.
1076 |
1077 | For details, see :func:`distro.distro_release_attr`.
1078 | """
1079 | return self._distro_release_info.get(attribute, "")
1080 |
1081 | def uname_attr(self, attribute: str) -> str:
1082 | """
1083 | Return a single named information item from the uname command
1084 | output data source of the OS distribution.
1085 |
1086 | For details, see :func:`distro.uname_attr`.
1087 | """
1088 | return self._uname_info.get(attribute, "")
1089 |
1090 | @cached_property
1091 | def _os_release_info(self) -> Dict[str, str]:
1092 | """
1093 | Get the information items from the specified os-release file.
1094 |
1095 | Returns:
1096 | A dictionary containing all information items.
1097 | """
1098 | if os.path.isfile(self.os_release_file):
1099 | with open(self.os_release_file, encoding="utf-8") as release_file:
1100 | return self._parse_os_release_content(release_file)
1101 | return {}
1102 |
1103 | @staticmethod
1104 | def _parse_os_release_content(lines: TextIO) -> Dict[str, str]:
1105 | """
1106 | Parse the lines of an os-release file.
1107 |
1108 | Parameters:
1109 |
1110 | * lines: Iterable through the lines in the os-release file.
1111 | Each line must be a unicode string or a UTF-8 encoded byte
1112 | string.
1113 |
1114 | Returns:
1115 | A dictionary containing all information items.
1116 | """
1117 | props = {}
1118 | lexer = shlex.shlex(lines, posix=True)
1119 | lexer.whitespace_split = True
1120 |
1121 | tokens = list(lexer)
1122 | for token in tokens:
1123 | # At this point, all shell-like parsing has been done (i.e.
1124 | # comments processed, quotes and backslash escape sequences
1125 | # processed, multi-line values assembled, trailing newlines
1126 | # stripped, etc.), so the tokens are now either:
1127 | # * variable assignments: var=value
1128 | # * commands or their arguments (not allowed in os-release)
1129 | # Ignore any tokens that are not variable assignments
1130 | if "=" in token:
1131 | k, v = token.split("=", 1)
1132 | props[k.lower()] = v
1133 |
1134 | if "version" in props:
1135 | # extract release codename (if any) from version attribute
1136 | match = re.search(r"\((\D+)\)|,\s*(\D+)", props["version"])
1137 | if match:
1138 | release_codename = match.group(1) or match.group(2)
1139 | props["codename"] = props["release_codename"] = release_codename
1140 |
1141 | if "version_codename" in props:
1142 | # os-release added a version_codename field. Use that in
1143 | # preference to anything else Note that some distros purposefully
1144 | # do not have code names. They should be setting
1145 | # version_codename=""
1146 | props["codename"] = props["version_codename"]
1147 | elif "ubuntu_codename" in props:
1148 | # Same as above but a non-standard field name used on older Ubuntus
1149 | props["codename"] = props["ubuntu_codename"]
1150 |
1151 | return props
1152 |
1153 | @cached_property
1154 | def _lsb_release_info(self) -> Dict[str, str]:
1155 | """
1156 | Get the information items from the lsb_release command output.
1157 |
1158 | Returns:
1159 | A dictionary containing all information items.
1160 | """
1161 | if not self.include_lsb:
1162 | return {}
1163 | try:
1164 | cmd = ("lsb_release", "-a")
1165 | stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
1166 | # Command not found or lsb_release returned error
1167 | except (OSError, subprocess.CalledProcessError):
1168 | return {}
1169 | content = self._to_str(stdout).splitlines()
1170 | return self._parse_lsb_release_content(content)
1171 |
1172 | @staticmethod
1173 | def _parse_lsb_release_content(lines: Iterable[str]) -> Dict[str, str]:
1174 | """
1175 | Parse the output of the lsb_release command.
1176 |
1177 | Parameters:
1178 |
1179 | * lines: Iterable through the lines of the lsb_release output.
1180 | Each line must be a unicode string or a UTF-8 encoded byte
1181 | string.
1182 |
1183 | Returns:
1184 | A dictionary containing all information items.
1185 | """
1186 | props = {}
1187 | for line in lines:
1188 | kv = line.strip("\n").split(":", 1)
1189 | if len(kv) != 2:
1190 | # Ignore lines without colon.
1191 | continue
1192 | k, v = kv
1193 | props.update({k.replace(" ", "_").lower(): v.strip()})
1194 | return props
1195 |
1196 | @cached_property
1197 | def _uname_info(self) -> Dict[str, str]:
1198 | if not self.include_uname:
1199 | return {}
1200 | try:
1201 | cmd = ("uname", "-rs")
1202 | stdout = subprocess.check_output(cmd, stderr=subprocess.DEVNULL)
1203 | except OSError:
1204 | return {}
1205 | content = self._to_str(stdout).splitlines()
1206 | return self._parse_uname_content(content)
1207 |
1208 | @cached_property
1209 | def _oslevel_info(self) -> str:
1210 | if not self.include_oslevel:
1211 | return ""
1212 | try:
1213 | stdout = subprocess.check_output("oslevel", stderr=subprocess.DEVNULL)
1214 | except (OSError, subprocess.CalledProcessError):
1215 | return ""
1216 | return self._to_str(stdout).strip()
1217 |
1218 | @cached_property
1219 | def _debian_version(self) -> str:
1220 | try:
1221 | with open(
1222 | os.path.join(self.etc_dir, "debian_version"), encoding="ascii"
1223 | ) as fp:
1224 | return fp.readline().rstrip()
1225 | except FileNotFoundError:
1226 | return ""
1227 |
1228 | @staticmethod
1229 | def _parse_uname_content(lines: Sequence[str]) -> Dict[str, str]:
1230 | if not lines:
1231 | return {}
1232 | props = {}
1233 | match = re.search(r"^([^\s]+)\s+([\d\.]+)", lines[0].strip())
1234 | if match:
1235 | name, version = match.groups()
1236 |
1237 | # This is to prevent the Linux kernel version from
1238 | # appearing as the 'best' version on otherwise
1239 | # identifiable distributions.
1240 | if name == "Linux":
1241 | return {}
1242 | props["id"] = name.lower()
1243 | props["name"] = name
1244 | props["release"] = version
1245 | return props
1246 |
1247 | @staticmethod
1248 | def _to_str(bytestring: bytes) -> str:
1249 | encoding = sys.getfilesystemencoding()
1250 | return bytestring.decode(encoding)
1251 |
1252 | @cached_property
1253 | def _distro_release_info(self) -> Dict[str, str]:
1254 | """
1255 | Get the information items from the specified distro release file.
1256 |
1257 | Returns:
1258 | A dictionary containing all information items.
1259 | """
1260 | if self.distro_release_file:
1261 | # If it was specified, we use it and parse what we can, even if
1262 | # its file name or content does not match the expected pattern.
1263 | distro_info = self._parse_distro_release_file(self.distro_release_file)
1264 | basename = os.path.basename(self.distro_release_file)
1265 | # The file name pattern for user-specified distro release files
1266 | # is somewhat more tolerant (compared to when searching for the
1267 | # file), because we want to use what was specified as best as
1268 | # possible.
1269 | match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
1270 | else:
1271 | try:
1272 | basenames = [
1273 | basename
1274 | for basename in os.listdir(self.etc_dir)
1275 | if basename not in _DISTRO_RELEASE_IGNORE_BASENAMES
1276 | and os.path.isfile(os.path.join(self.etc_dir, basename))
1277 | ]
1278 | # We sort for repeatability in cases where there are multiple
1279 | # distro specific files; e.g. CentOS, Oracle, Enterprise all
1280 | # containing `redhat-release` on top of their own.
1281 | basenames.sort()
1282 | except OSError:
1283 | # This may occur when /etc is not readable but we can't be
1284 | # sure about the *-release files. Check common entries of
1285 | # /etc for information. If they turn out to not be there the
1286 | # error is handled in `_parse_distro_release_file()`.
1287 | basenames = _DISTRO_RELEASE_BASENAMES
1288 | for basename in basenames:
1289 | match = _DISTRO_RELEASE_BASENAME_PATTERN.match(basename)
1290 | if match is None:
1291 | continue
1292 | filepath = os.path.join(self.etc_dir, basename)
1293 | distro_info = self._parse_distro_release_file(filepath)
1294 | # The name is always present if the pattern matches.
1295 | if "name" not in distro_info:
1296 | continue
1297 | self.distro_release_file = filepath
1298 | break
1299 | else: # the loop didn't "break": no candidate.
1300 | return {}
1301 |
1302 | if match is not None:
1303 | distro_info["id"] = match.group(1)
1304 |
1305 | # CloudLinux < 7: manually enrich info with proper id.
1306 | if "cloudlinux" in distro_info.get("name", "").lower():
1307 | distro_info["id"] = "cloudlinux"
1308 |
1309 | return distro_info
1310 |
1311 | def _parse_distro_release_file(self, filepath: str) -> Dict[str, str]:
1312 | """
1313 | Parse a distro release file.
1314 |
1315 | Parameters:
1316 |
1317 | * filepath: Path name of the distro release file.
1318 |
1319 | Returns:
1320 | A dictionary containing all information items.
1321 | """
1322 | try:
1323 | with open(filepath, encoding="utf-8") as fp:
1324 | # Only parse the first line. For instance, on SLES there
1325 | # are multiple lines. We don't want them...
1326 | return self._parse_distro_release_content(fp.readline())
1327 | except OSError:
1328 | # Ignore not being able to read a specific, seemingly version
1329 | # related file.
1330 | # See https://github.com/python-distro/distro/issues/162
1331 | return {}
1332 |
1333 | @staticmethod
1334 | def _parse_distro_release_content(line: str) -> Dict[str, str]:
1335 | """
1336 | Parse a line from a distro release file.
1337 |
1338 | Parameters:
1339 | * line: Line from the distro release file. Must be a unicode string
1340 | or a UTF-8 encoded byte string.
1341 |
1342 | Returns:
1343 | A dictionary containing all information items.
1344 | """
1345 | matches = _DISTRO_RELEASE_CONTENT_REVERSED_PATTERN.match(line.strip()[::-1])
1346 | distro_info = {}
1347 | if matches:
1348 | # regexp ensures non-None
1349 | distro_info["name"] = matches.group(3)[::-1]
1350 | if matches.group(2):
1351 | distro_info["version_id"] = matches.group(2)[::-1]
1352 | if matches.group(1):
1353 | distro_info["codename"] = matches.group(1)[::-1]
1354 | elif line:
1355 | distro_info["name"] = line.strip()
1356 | return distro_info
1357 |
1358 |
1359 | _distro = LinuxDistribution()
1360 |
1361 |
1362 | def main() -> None:
1363 | logger = logging.getLogger(__name__)
1364 | logger.setLevel(logging.DEBUG)
1365 | logger.addHandler(logging.StreamHandler(sys.stdout))
1366 |
1367 | parser = argparse.ArgumentParser(description="OS distro info tool")
1368 | parser.add_argument(
1369 | "--json", "-j", help="Output in machine readable format", action="store_true"
1370 | )
1371 |
1372 | parser.add_argument(
1373 | "--root-dir",
1374 | "-r",
1375 | type=str,
1376 | dest="root_dir",
1377 | help="Path to the root filesystem directory (defaults to /)",
1378 | )
1379 |
1380 | args = parser.parse_args()
1381 |
1382 | if args.root_dir:
1383 | dist = LinuxDistribution(
1384 | include_lsb=False,
1385 | include_uname=False,
1386 | include_oslevel=False,
1387 | root_dir=args.root_dir,
1388 | )
1389 | else:
1390 | dist = _distro
1391 |
1392 | if args.json:
1393 | logger.info(json.dumps(dist.info(), indent=4, sort_keys=True))
1394 | else:
1395 | logger.info("Name: %s", dist.name(pretty=True))
1396 | distribution_version = dist.version(pretty=True)
1397 | logger.info("Version: %s", distribution_version)
1398 | distribution_codename = dist.codename()
1399 | logger.info("Codename: %s", distribution_codename)
1400 |
1401 |
1402 | if __name__ == "__main__":
1403 | main()
1404 |
```