From e461752581c359a05b7e30a245701768c1a434b6 Mon Sep 17 00:00:00 2001 From: ua1zbe Date: Thu, 16 Apr 2026 15:11:33 +0300 Subject: [PATCH] Initial commit: UV-K5 firmware site with flasher --- __pycache__/app.cpython-312.pyc | Bin 0 -> 4417 bytes app.py | 83 + docs/changelog.md | 19 + docs/faq.md | 34 + docs/index.md | 0 docs/installation.md | 39 + docs/user_guide.md | 47 + firmware/firmware.packed.bin | Bin 0 -> 45674 bytes requirements.txt | 2 + static/css/style.css | 324 + static/js/flasher.js | 63 + templates/base.html | 32 + templates/doc_page.html | 17 + templates/docs_list.html | 17 + templates/downloads.html | 46 + templates/flasher.html | 34 + templates/index.html | 63 + templates/info.html | 29 + venv/bin/Activate.ps1 | 247 + venv/bin/activate | 70 + venv/bin/activate.csh | 27 + venv/bin/activate.fish | 69 + venv/bin/flask | 8 + venv/bin/markdown_py | 8 + venv/bin/pip | 8 + venv/bin/pip3 | 8 + venv/bin/pip3.12 | 8 + venv/bin/python | 1 + venv/bin/python3 | 1 + venv/bin/python3.12 | 1 + .../blinker-1.9.0.dist-info/INSTALLER | 1 + .../blinker-1.9.0.dist-info/LICENSE.txt | 20 + .../blinker-1.9.0.dist-info/METADATA | 60 + .../blinker-1.9.0.dist-info/RECORD | 12 + .../blinker-1.9.0.dist-info/WHEEL | 4 + .../site-packages/blinker/__init__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 495 bytes .../__pycache__/_utilities.cpython-312.pyc | Bin 0 -> 2722 bytes .../blinker/__pycache__/base.cpython-312.pyc | Bin 0 -> 21999 bytes .../site-packages/blinker/_utilities.py | 64 + .../python3.12/site-packages/blinker/base.py | 512 + .../python3.12/site-packages/blinker/py.typed | 0 .../click-8.3.2.dist-info/INSTALLER | 1 + .../click-8.3.2.dist-info/METADATA | 84 + .../click-8.3.2.dist-info/RECORD | 40 + .../site-packages/click-8.3.2.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + .../site-packages/click/__init__.py | 123 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4067 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 24189 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 31611 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2420 bytes .../click/__pycache__/_utils.cpython-312.pyc | Bin 0 -> 1195 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11765 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 135157 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 22132 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14771 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 13667 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 2960 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 20437 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 23332 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 34646 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 27145 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 50033 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 24874 bytes .../python3.12/site-packages/click/_compat.py | 622 ++ .../site-packages/click/_termui_impl.py | 852 ++ .../site-packages/click/_textwrap.py | 51 + .../python3.12/site-packages/click/_utils.py | 36 + .../site-packages/click/_winconsole.py | 296 + .../python3.12/site-packages/click/core.py | 3437 +++++++ .../site-packages/click/decorators.py | 551 ++ .../site-packages/click/exceptions.py | 308 + .../site-packages/click/formatting.py | 301 + .../python3.12/site-packages/click/globals.py | 67 + .../python3.12/site-packages/click/parser.py | 532 + .../python3.12/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 667 ++ .../python3.12/site-packages/click/termui.py | 883 ++ .../python3.12/site-packages/click/testing.py | 574 ++ .../python3.12/site-packages/click/types.py | 1209 +++ .../python3.12/site-packages/click/utils.py | 627 ++ .../flask-3.1.3.dist-info/INSTALLER | 1 + .../flask-3.1.3.dist-info/METADATA | 91 + .../flask-3.1.3.dist-info/RECORD | 58 + .../flask-3.1.3.dist-info/REQUESTED | 0 .../site-packages/flask-3.1.3.dist-info/WHEEL | 4 + .../flask-3.1.3.dist-info/entry_points.txt | 3 + .../licenses/LICENSE.txt | 28 + .../site-packages/flask/__init__.py | 61 + .../site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2527 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 235 bytes .../flask/__pycache__/app.cpython-312.pyc | Bin 0 -> 62487 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 4994 bytes .../flask/__pycache__/cli.cpython-312.pyc | Bin 0 -> 43538 bytes .../flask/__pycache__/config.cpython-312.pyc | Bin 0 -> 16246 bytes .../flask/__pycache__/ctx.cpython-312.pyc | Bin 0 -> 20427 bytes .../__pycache__/debughelpers.cpython-312.pyc | Bin 0 -> 9144 bytes .../flask/__pycache__/globals.cpython-312.pyc | Bin 0 -> 1859 bytes .../flask/__pycache__/helpers.cpython-312.pyc | Bin 0 -> 25560 bytes .../flask/__pycache__/logging.cpython-312.pyc | Bin 0 -> 3261 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 16362 bytes .../flask/__pycache__/signals.cpython-312.pyc | Bin 0 -> 1216 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9922 bytes .../flask/__pycache__/testing.cpython-312.pyc | Bin 0 -> 13606 bytes .../flask/__pycache__/typing.cpython-312.pyc | Bin 0 -> 4124 bytes .../flask/__pycache__/views.cpython-312.pyc | Bin 0 -> 7015 bytes .../__pycache__/wrappers.cpython-312.pyc | Bin 0 -> 10047 bytes .../lib/python3.12/site-packages/flask/app.py | 1536 +++ .../site-packages/flask/blueprints.py | 128 + .../lib/python3.12/site-packages/flask/cli.py | 1135 +++ .../python3.12/site-packages/flask/config.py | 367 + .../lib/python3.12/site-packages/flask/ctx.py | 459 + .../site-packages/flask/debughelpers.py | 178 + .../python3.12/site-packages/flask/globals.py | 51 + .../python3.12/site-packages/flask/helpers.py | 641 ++ .../site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6687 bytes .../json/__pycache__/provider.cpython-312.pyc | Bin 0 -> 9254 bytes .../json/__pycache__/tag.cpython-312.pyc | Bin 0 -> 13949 bytes .../site-packages/flask/json/provider.py | 215 + .../site-packages/flask/json/tag.py | 327 + .../python3.12/site-packages/flask/logging.py | 79 + .../python3.12/site-packages/flask/py.typed | 0 .../site-packages/flask/sansio/README.md | 6 + .../sansio/__pycache__/app.cpython-312.pyc | Bin 0 -> 33706 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 31207 bytes .../__pycache__/scaffold.cpython-312.pyc | Bin 0 -> 30220 bytes .../site-packages/flask/sansio/app.py | 964 ++ .../site-packages/flask/sansio/blueprints.py | 632 ++ .../site-packages/flask/sansio/scaffold.py | 792 ++ .../site-packages/flask/sessions.py | 385 + .../python3.12/site-packages/flask/signals.py | 17 + .../site-packages/flask/templating.py | 220 + .../python3.12/site-packages/flask/testing.py | 298 + .../python3.12/site-packages/flask/typing.py | 93 + .../python3.12/site-packages/flask/views.py | 191 + .../site-packages/flask/wrappers.py | 257 + .../itsdangerous-2.2.0.dist-info/INSTALLER | 1 + .../itsdangerous-2.2.0.dist-info/LICENSE.txt | 28 + .../itsdangerous-2.2.0.dist-info/METADATA | 60 + .../itsdangerous-2.2.0.dist-info/RECORD | 22 + .../itsdangerous-2.2.0.dist-info/WHEEL | 4 + .../site-packages/itsdangerous/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1626 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 1180 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2680 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 3940 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 15421 bytes .../__pycache__/signer.cpython-312.pyc | Bin 0 -> 11286 bytes .../__pycache__/timed.cpython-312.pyc | Bin 0 -> 8734 bytes .../__pycache__/url_safe.cpython-312.pyc | Bin 0 -> 3530 bytes .../site-packages/itsdangerous/_json.py | 18 + .../site-packages/itsdangerous/encoding.py | 54 + .../site-packages/itsdangerous/exc.py | 106 + .../site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 406 + .../site-packages/itsdangerous/signer.py | 266 + .../site-packages/itsdangerous/timed.py | 228 + .../site-packages/itsdangerous/url_safe.py | 83 + .../jinja2-3.1.6.dist-info/INSTALLER | 1 + .../jinja2-3.1.6.dist-info/METADATA | 84 + .../jinja2-3.1.6.dist-info/RECORD | 57 + .../jinja2-3.1.6.dist-info/WHEEL | 4 + .../jinja2-3.1.6.dist-info/entry_points.txt | 3 + .../licenses/LICENSE.txt | 28 + .../site-packages/jinja2/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1651 bytes .../__pycache__/_identifier.cpython-312.pyc | Bin 0 -> 2132 bytes .../__pycache__/async_utils.cpython-312.pyc | Bin 0 -> 4972 bytes .../__pycache__/bccache.cpython-312.pyc | Bin 0 -> 19343 bytes .../__pycache__/compiler.cpython-312.pyc | Bin 0 -> 104058 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 1554 bytes .../jinja2/__pycache__/debug.cpython-312.pyc | Bin 0 -> 6579 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1604 bytes .../__pycache__/environment.cpython-312.pyc | Bin 0 -> 76680 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7718 bytes .../jinja2/__pycache__/ext.cpython-312.pyc | Bin 0 -> 41911 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 72328 bytes .../__pycache__/idtracking.cpython-312.pyc | Bin 0 -> 19193 bytes .../jinja2/__pycache__/lexer.cpython-312.pyc | Bin 0 -> 32074 bytes .../__pycache__/loaders.cpython-312.pyc | Bin 0 -> 32353 bytes .../jinja2/__pycache__/meta.cpython-312.pyc | Bin 0 -> 5488 bytes .../__pycache__/nativetypes.cpython-312.pyc | Bin 0 -> 7009 bytes .../jinja2/__pycache__/nodes.cpython-312.pyc | Bin 0 -> 58271 bytes .../__pycache__/optimizer.cpython-312.pyc | Bin 0 -> 2687 bytes .../jinja2/__pycache__/parser.cpython-312.pyc | Bin 0 -> 61201 bytes .../__pycache__/runtime.cpython-312.pyc | Bin 0 -> 48889 bytes .../__pycache__/sandbox.cpython-312.pyc | Bin 0 -> 18105 bytes .../jinja2/__pycache__/tests.cpython-312.pyc | Bin 0 -> 9048 bytes .../jinja2/__pycache__/utils.cpython-312.pyc | Bin 0 -> 34861 bytes .../__pycache__/visitor.cpython-312.pyc | Bin 0 -> 5363 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 99 + .../site-packages/jinja2/bccache.py | 408 + .../site-packages/jinja2/compiler.py | 1998 ++++ .../site-packages/jinja2/constants.py | 20 + .../python3.12/site-packages/jinja2/debug.py | 191 + .../site-packages/jinja2/defaults.py | 48 + .../site-packages/jinja2/environment.py | 1672 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.12/site-packages/jinja2/ext.py | 870 ++ .../site-packages/jinja2/filters.py | 1873 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.12/site-packages/jinja2/lexer.py | 868 ++ .../site-packages/jinja2/loaders.py | 693 ++ .../python3.12/site-packages/jinja2/meta.py | 112 + .../site-packages/jinja2/nativetypes.py | 130 + .../python3.12/site-packages/jinja2/nodes.py | 1206 +++ .../site-packages/jinja2/optimizer.py | 48 + .../python3.12/site-packages/jinja2/parser.py | 1049 ++ .../python3.12/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1062 ++ .../site-packages/jinja2/sandbox.py | 436 + .../python3.12/site-packages/jinja2/tests.py | 256 + .../python3.12/site-packages/jinja2/utils.py | 766 ++ .../site-packages/jinja2/visitor.py | 92 + .../markdown-3.10.2.dist-info/INSTALLER | 1 + .../markdown-3.10.2.dist-info/METADATA | 115 + .../markdown-3.10.2.dist-info/RECORD | 75 + .../markdown-3.10.2.dist-info/REQUESTED | 0 .../markdown-3.10.2.dist-info/WHEEL | 5 + .../entry_points.txt | 22 + .../licenses/LICENSE.md | 30 + .../markdown-3.10.2.dist-info/top_level.txt | 1 + .../site-packages/markdown/__init__.py | 48 + .../site-packages/markdown/__main__.py | 154 + .../site-packages/markdown/__meta__.py | 51 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1181 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 5723 bytes .../__pycache__/__meta__.cpython-312.pyc | Bin 0 -> 1135 bytes .../__pycache__/blockparser.cpython-312.pyc | Bin 0 -> 6417 bytes .../blockprocessors.cpython-312.pyc | Bin 0 -> 30381 bytes .../markdown/__pycache__/core.cpython-312.pyc | Bin 0 -> 24039 bytes .../__pycache__/htmlparser.cpython-312.pyc | Bin 0 -> 20124 bytes .../inlinepatterns.cpython-312.pyc | Bin 0 -> 45401 bytes .../postprocessors.cpython-312.pyc | Bin 0 -> 6282 bytes .../__pycache__/preprocessors.cpython-312.pyc | Bin 0 -> 4021 bytes .../__pycache__/serializers.cpython-312.pyc | Bin 0 -> 6347 bytes .../__pycache__/test_tools.cpython-312.pyc | Bin 0 -> 10643 bytes .../treeprocessors.cpython-312.pyc | Bin 0 -> 20989 bytes .../markdown/__pycache__/util.cpython-312.pyc | Bin 0 -> 16090 bytes .../site-packages/markdown/blockparser.py | 160 + .../site-packages/markdown/blockprocessors.py | 641 ++ .../python3.12/site-packages/markdown/core.py | 531 + .../markdown/extensions/__init__.py | 145 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5260 bytes .../__pycache__/abbr.cpython-312.pyc | Bin 0 -> 11040 bytes .../__pycache__/admonition.cpython-312.pyc | Bin 0 -> 6923 bytes .../__pycache__/attr_list.cpython-312.pyc | Bin 0 -> 9283 bytes .../__pycache__/codehilite.cpython-312.pyc | Bin 0 -> 14644 bytes .../__pycache__/def_list.cpython-312.pyc | Bin 0 -> 5407 bytes .../__pycache__/extra.cpython-312.pyc | Bin 0 -> 2379 bytes .../__pycache__/fenced_code.cpython-312.pyc | Bin 0 -> 8793 bytes .../__pycache__/footnotes.cpython-312.pyc | Bin 0 -> 25493 bytes .../__pycache__/legacy_attrs.cpython-312.pyc | Bin 0 -> 3589 bytes .../__pycache__/legacy_em.cpython-312.pyc | Bin 0 -> 2517 bytes .../__pycache__/md_in_html.cpython-312.pyc | Bin 0 -> 21331 bytes .../__pycache__/meta.cpython-312.pyc | Bin 0 -> 3607 bytes .../__pycache__/nl2br.cpython-312.pyc | Bin 0 -> 1304 bytes .../__pycache__/sane_lists.cpython-312.pyc | Bin 0 -> 2902 bytes .../__pycache__/smarty.cpython-312.pyc | Bin 0 -> 8894 bytes .../__pycache__/tables.cpython-312.pyc | Bin 0 -> 10241 bytes .../__pycache__/toc.cpython-312.pyc | Bin 0 -> 22266 bytes .../__pycache__/wikilinks.cpython-312.pyc | Bin 0 -> 4803 bytes .../site-packages/markdown/extensions/abbr.py | 190 + .../markdown/extensions/admonition.py | 184 + .../markdown/extensions/attr_list.py | 204 + .../markdown/extensions/codehilite.py | 347 + .../markdown/extensions/def_list.py | 119 + .../markdown/extensions/extra.py | 66 + .../markdown/extensions/fenced_code.py | 193 + .../markdown/extensions/footnotes.py | 482 + .../markdown/extensions/legacy_attrs.py | 71 + .../markdown/extensions/legacy_em.py | 52 + .../markdown/extensions/md_in_html.py | 440 + .../site-packages/markdown/extensions/meta.py | 86 + .../markdown/extensions/nl2br.py | 41 + .../markdown/extensions/sane_lists.py | 69 + .../markdown/extensions/smarty.py | 280 + .../markdown/extensions/tables.py | 248 + .../site-packages/markdown/extensions/toc.py | 488 + .../markdown/extensions/wikilinks.py | 97 + .../site-packages/markdown/htmlparser.py | 422 + .../site-packages/markdown/inlinepatterns.py | 996 ++ .../site-packages/markdown/postprocessors.py | 131 + .../site-packages/markdown/preprocessors.py | 91 + .../site-packages/markdown/serializers.py | 194 + .../site-packages/markdown/test_tools.py | 224 + .../site-packages/markdown/treeprocessors.py | 476 + .../python3.12/site-packages/markdown/util.py | 409 + .../markupsafe-3.0.3.dist-info/INSTALLER | 1 + .../markupsafe-3.0.3.dist-info/METADATA | 74 + .../markupsafe-3.0.3.dist-info/RECORD | 14 + .../markupsafe-3.0.3.dist-info/WHEEL | 7 + .../licenses/LICENSE.txt | 28 + .../markupsafe-3.0.3.dist-info/top_level.txt | 1 + .../site-packages/markupsafe/__init__.py | 396 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 20961 bytes .../__pycache__/_native.cpython-312.pyc | Bin 0 -> 613 bytes .../site-packages/markupsafe/_native.py | 8 + .../site-packages/markupsafe/_speedups.c | 200 + .../_speedups.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 44072 bytes .../site-packages/markupsafe/_speedups.pyi | 1 + .../site-packages/markupsafe/py.typed | 0 .../pip-24.0.dist-info/AUTHORS.txt | 760 ++ .../pip-24.0.dist-info/INSTALLER | 1 + .../pip-24.0.dist-info/LICENSE.txt | 20 + .../site-packages/pip-24.0.dist-info/METADATA | 88 + .../site-packages/pip-24.0.dist-info/RECORD | 1005 ++ .../pip-24.0.dist-info/REQUESTED | 0 .../site-packages/pip-24.0.dist-info/WHEEL | 5 + .../pip-24.0.dist-info/entry_points.txt | 4 + .../pip-24.0.dist-info/top_level.txt | 1 + .../python3.12/site-packages/pip/__init__.py | 13 + .../python3.12/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 688 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 844 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2207 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 790 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14297 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12668 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17669 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33287 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 673 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 4974 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10555 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13652 bytes .../site-packages/pip/_internal/build_env.py | 311 + .../site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 281 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8468 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10458 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30377 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1784 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2301 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4908 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15025 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 2623 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 18855 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7843 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 378 bytes .../pip/_internal/cli/autocompletion.py | 172 + .../pip/_internal/cli/base_command.py | 236 + .../pip/_internal/cli/cmdoptions.py | 1074 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 505 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4005 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9714 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2093 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5195 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13215 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10164 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7592 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4419 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2986 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1676 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6723 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3978 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 28916 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15659 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7624 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 9731 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4729 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8959 bytes .../pip/_internal/commands/cache.py | 225 + .../pip/_internal/commands/check.py | 54 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 147 + .../pip/_internal/commands/freeze.py | 109 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 774 ++ .../pip/_internal/commands/list.py | 370 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 189 + .../pip/_internal/commands/uninstall.py | 113 + .../pip/_internal/commands/wheel.py | 183 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 944 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2865 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1703 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8491 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2251 bytes .../pip/_internal/distributions/base.py | 51 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 156 + .../pip/_internal/distributions/wheel.py | 40 + .../site-packages/pip/_internal/exceptions.py | 728 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 235 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21889 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 40738 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12607 bytes .../pip/_internal/index/collector.py | 507 + .../pip/_internal/index/package_finder.py | 1027 ++ .../pip/_internal/index/sources.py | 285 + .../pip/_internal/locations/__init__.py | 467 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16779 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6859 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8014 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3784 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 213 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 128 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5885 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2878 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35715 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 15793 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 702 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 361 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 3336 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 13428 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11183 bytes .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 227 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 278 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 269 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1908 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 11202 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4230 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1697 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2275 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26005 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1172 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 5091 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1854 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4957 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5783 bytes .../pip/_internal/models/candidate.py | 30 + .../pip/_internal/models/direct_url.py | 235 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 579 ++ .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 132 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 122 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 257 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 21999 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 6521 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8556 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11666 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18777 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2256 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2952 bytes .../pip/_internal/network/auth.py | 561 ++ .../pip/_internal/network/cache.py | 106 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 520 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 200 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7582 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10120 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25750 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 206 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7826 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1883 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1917 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3068 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1687 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2028 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3932 bytes .../operations/build/build_tracker.py | 139 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 187 + .../pip/_internal/operations/freeze.py | 255 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 269 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1820 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 33862 bytes .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 734 ++ .../pip/_internal/operations/prepare.py | 730 ++ .../site-packages/pip/_internal/pyproject.py | 179 + .../pip/_internal/req/__init__.py | 92 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3746 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21585 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 21464 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38417 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 7221 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 32980 bytes .../pip/_internal/req/constructors.py | 576 ++ .../pip/_internal/req/req_file.py | 554 ++ .../pip/_internal/req/req_install.py | 923 ++ .../pip/_internal/req/req_set.py | 119 + .../pip/_internal/req/req_uninstall.py | 649 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 200 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1188 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 207 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22442 bytes .../_internal/resolution/legacy/resolver.py | 598 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 211 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8340 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 30401 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32117 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6211 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10381 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 4938 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 11432 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12354 bytes .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 597 ++ .../resolution/resolvelib/factory.py | 812 ++ .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 255 + .../resolution/resolvelib/reporter.py | 80 + .../resolution/resolvelib/requirements.py | 166 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 248 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4536 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1866 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2410 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2213 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 5561 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 684 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4186 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3563 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3226 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2158 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 3993 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7458 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1164 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2342 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7554 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13557 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 34121 bytes .../utils/__pycache__/models.cpython-312.pyc | Bin 0 -> 2712 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2583 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4550 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8718 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12062 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 11108 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2405 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4480 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5926 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 120 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 151 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 783 ++ .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 534 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5026 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 18995 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7615 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12487 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29013 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 ++ .../pip/_internal/wheel_builder.py | 354 + .../site-packages/pip/_vendor/__init__.py | 121 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4696 bytes .../_vendor/__pycache__/six.cpython-312.pyc | Bin 0 -> 41273 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 122053 bytes .../pip/_vendor/cachecontrol/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 906 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2650 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6468 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3813 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16171 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4351 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6698 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 6409 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1678 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 161 + .../pip/_vendor/cachecontrol/cache.py | 74 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 439 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7714 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2742 bytes .../_vendor/cachecontrol/caches/file_cache.py | 181 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 494 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 154 + .../pip/_vendor/cachecontrol/serialize.py | 206 + .../pip/_vendor/cachecontrol/wrapper.py | 43 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 322 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 649 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3331 bytes .../pip/_vendor/certifi/cacert.pem | 4635 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 119 + .../pip/_vendor/chardet/__init__.py | 115 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4572 bytes .../__pycache__/big5freq.cpython-312.pyc | Bin 0 -> 27203 bytes .../__pycache__/big5prober.cpython-312.pyc | Bin 0 -> 1391 bytes .../chardistribution.cpython-312.pyc | Bin 0 -> 9642 bytes .../charsetgroupprober.cpython-312.pyc | Bin 0 -> 4126 bytes .../__pycache__/charsetprober.cpython-312.pyc | Bin 0 -> 5022 bytes .../codingstatemachine.cpython-312.pyc | Bin 0 -> 3882 bytes .../codingstatemachinedict.cpython-312.pyc | Bin 0 -> 793 bytes .../__pycache__/cp949prober.cpython-312.pyc | Bin 0 -> 1400 bytes .../chardet/__pycache__/enums.cpython-312.pyc | Bin 0 -> 3000 bytes .../__pycache__/escprober.cpython-312.pyc | Bin 0 -> 4570 bytes .../chardet/__pycache__/escsm.cpython-312.pyc | Bin 0 -> 15314 bytes .../__pycache__/eucjpprober.cpython-312.pyc | Bin 0 -> 4387 bytes .../__pycache__/euckrfreq.cpython-312.pyc | Bin 0 -> 12086 bytes .../__pycache__/euckrprober.cpython-312.pyc | Bin 0 -> 1394 bytes .../__pycache__/euctwfreq.cpython-312.pyc | Bin 0 -> 27208 bytes .../__pycache__/euctwprober.cpython-312.pyc | Bin 0 -> 1394 bytes .../__pycache__/gb2312freq.cpython-312.pyc | Bin 0 -> 19130 bytes .../__pycache__/gb2312prober.cpython-312.pyc | Bin 0 -> 1407 bytes .../__pycache__/hebrewprober.cpython-312.pyc | Bin 0 -> 5826 bytes .../__pycache__/jisfreq.cpython-312.pyc | Bin 0 -> 22159 bytes .../__pycache__/johabfreq.cpython-312.pyc | Bin 0 -> 83007 bytes .../__pycache__/johabprober.cpython-312.pyc | Bin 0 -> 1398 bytes .../__pycache__/jpcntx.cpython-312.pyc | Bin 0 -> 39553 bytes .../langbulgarianmodel.cpython-312.pyc | Bin 0 -> 83126 bytes .../langgreekmodel.cpython-312.pyc | Bin 0 -> 76992 bytes .../langhebrewmodel.cpython-312.pyc | Bin 0 -> 77503 bytes .../langhungarianmodel.cpython-312.pyc | Bin 0 -> 83080 bytes .../langrussianmodel.cpython-312.pyc | Bin 0 -> 105255 bytes .../__pycache__/langthaimodel.cpython-312.pyc | Bin 0 -> 77681 bytes .../langturkishmodel.cpython-312.pyc | Bin 0 -> 77520 bytes .../__pycache__/latin1prober.cpython-312.pyc | Bin 0 -> 7006 bytes .../macromanprober.cpython-312.pyc | Bin 0 -> 7186 bytes .../mbcharsetprober.cpython-312.pyc | Bin 0 -> 3907 bytes .../mbcsgroupprober.cpython-312.pyc | Bin 0 -> 1592 bytes .../__pycache__/mbcssm.cpython-312.pyc | Bin 0 -> 38649 bytes .../__pycache__/resultdict.cpython-312.pyc | Bin 0 -> 636 bytes .../sbcharsetprober.cpython-312.pyc | Bin 0 -> 6391 bytes .../sbcsgroupprober.cpython-312.pyc | Bin 0 -> 2361 bytes .../__pycache__/sjisprober.cpython-312.pyc | Bin 0 -> 4499 bytes .../universaldetector.cpython-312.pyc | Bin 0 -> 12273 bytes .../__pycache__/utf1632prober.cpython-312.pyc | Bin 0 -> 9983 bytes .../__pycache__/utf8prober.cpython-312.pyc | Bin 0 -> 3179 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 492 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 261 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 147 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 199 bytes .../__pycache__/chardetect.cpython-312.pyc | Bin 0 -> 4016 bytes .../pip/_vendor/chardet/cli/chardetect.py | 112 + .../pip/_vendor/chardet/codingstatemachine.py | 90 + .../_vendor/chardet/codingstatemachinedict.py | 19 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 85 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 261 + .../pip/_vendor/chardet/eucjpprober.py | 102 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 316 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 238 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 147 + .../pip/_vendor/chardet/macromanprober.py | 162 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 57 + .../pip/_vendor/chardet/mbcssm.py | 661 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 204 bytes .../__pycache__/languages.cpython-312.pyc | Bin 0 -> 9759 bytes .../pip/_vendor/chardet/metadata/languages.py | 352 + .../pip/_vendor/chardet/resultdict.py | 16 + .../pip/_vendor/chardet/sbcharsetprober.py | 162 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 105 + .../pip/_vendor/chardet/universaldetector.py | 362 + .../pip/_vendor/chardet/utf1632prober.py | 225 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 7 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 496 bytes .../colorama/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 3954 bytes .../__pycache__/ansitowin32.cpython-312.pyc | Bin 0 -> 16425 bytes .../__pycache__/initialise.cpython-312.pyc | Bin 0 -> 3554 bytes .../__pycache__/win32.cpython-312.pyc | Bin 0 -> 8130 bytes .../__pycache__/winterm.cpython-312.pyc | Bin 0 -> 9092 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 277 + .../pip/_vendor/colorama/initialise.py | 121 + .../pip/_vendor/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 202 bytes .../__pycache__/ansi_test.cpython-312.pyc | Bin 0 -> 5471 bytes .../ansitowin32_test.cpython-312.pyc | Bin 0 -> 18107 bytes .../initialise_test.cpython-312.pyc | Bin 0 -> 11752 bytes .../__pycache__/isatty_test.cpython-312.pyc | Bin 0 -> 4908 bytes .../tests/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2492 bytes .../__pycache__/winterm_test.cpython-312.pyc | Bin 0 -> 6616 bytes .../pip/_vendor/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../_vendor/colorama/tests/initialise_test.py | 189 + .../pip/_vendor/colorama/tests/isatty_test.py | 57 + .../pip/_vendor/colorama/tests/utils.py | 49 + .../_vendor/colorama/tests/winterm_test.py | 131 + .../pip/_vendor/colorama/win32.py | 180 + .../pip/_vendor/colorama/winterm.py | 195 + .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1273 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45609 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 66031 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24370 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 60162 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15129 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7686 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41803 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17329 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19584 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88260 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30370 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 51865 bytes .../pip/_vendor/distlib/compat.py | 1138 +++ .../pip/_vendor/distlib/database.py | 1359 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1303 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 167 + .../pip/_vendor/distlib/metadata.py | 1068 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 452 + .../site-packages/pip/_vendor/distlib/util.py | 2025 ++++ .../pip/_vendor/distlib/version.py | 751 ++ .../pip/_vendor/distlib/wheel.py | 1099 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 964 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 296 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53758 bytes .../pip/_vendor/distro/distro.py | 1399 +++ .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 885 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4637 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 891 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16027 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99501 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2642 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 220 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158874 bytes .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 4246 ++++++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8600 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1835 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2029 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8672 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 43580 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-312.pyc | Bin 0 -> 634 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 470 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 12080 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 6914 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3245 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 14062 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 6950 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 31251 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 18960 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 5872 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 19943 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 ++ .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pkg_resources/__init__.py | 3361 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 146478 bytes .../pip/_vendor/platformdirs/__init__.py | 566 ++ .../pip/_vendor/platformdirs/__main__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 18033 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1950 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 9448 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 9676 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 5641 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 12445 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 315 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13003 bytes .../pip/_vendor/platformdirs/android.py | 210 + .../pip/_vendor/platformdirs/api.py | 223 + .../pip/_vendor/platformdirs/macos.py | 91 + .../pip/_vendor/platformdirs/unix.py | 223 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 255 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3493 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 739 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26610 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2631 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3237 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4574 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38334 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1573 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 3401 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4086 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4761 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 11051 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6679 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8147 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 32993 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 13986 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37941 bytes .../pip/_vendor/pygments/formatter.py | 124 + .../_vendor/pygments/formatters/__init__.py | 158 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6931 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4220 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4199 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7269 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 40577 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 27048 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6070 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 19959 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6889 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2935 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 6131 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9071 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5834 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15162 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 943 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14657 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 64409 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42644 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 559 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 217 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 103 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4453 bytes .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 330 + .../pip/_vendor/pyparsing/__init__.py | 322 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7916 bytes .../__pycache__/actions.cpython-312.pyc | Bin 0 -> 8400 bytes .../__pycache__/common.cpython-312.pyc | Bin 0 -> 13419 bytes .../__pycache__/core.cpython-312.pyc | Bin 0 -> 267713 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 12999 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 48506 bytes .../__pycache__/results.cpython-312.pyc | Bin 0 -> 34115 bytes .../__pycache__/testing.cpython-312.pyc | Bin 0 -> 17193 bytes .../__pycache__/unicode.cpython-312.pyc | Bin 0 -> 13189 bytes .../__pycache__/util.cpython-312.pyc | Bin 0 -> 14909 bytes .../pip/_vendor/pyparsing/actions.py | 217 + .../pip/_vendor/pyparsing/common.py | 432 + .../pip/_vendor/pyparsing/core.py | 6115 ++++++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 656 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 26818 bytes .../pip/_vendor/pyparsing/exceptions.py | 299 + .../pip/_vendor/pyparsing/helpers.py | 1100 +++ .../pip/_vendor/pyparsing/results.py | 796 ++ .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 361 + .../pip/_vendor/pyparsing/util.py | 284 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 618 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 379 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 14730 bytes .../pip/_vendor/pyproject_hooks/_compat.py | 8 + .../pip/_vendor/pyproject_hooks/_impl.py | 330 + .../pyproject_hooks/_in_process/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1085 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 14402 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 182 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5458 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 589 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2029 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 21285 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7209 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13928 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 927 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1512 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25251 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7052 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4317 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1057 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35453 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 777 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27762 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 5964 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5622 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36080 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 538 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 833 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1088 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 639 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6856 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2659 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25902 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10511 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 425 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 ++ .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 274 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7020 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10309 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7826 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205981 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1734 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2326 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 542 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 860 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12082 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4152 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1890 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3625 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5165 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 731 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6584 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13184 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 970 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 870 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28981 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2495 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3578 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 2365 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1613 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12327 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9111 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4277 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11863 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5623 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26575 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1706 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8592 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 113798 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2263 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9231 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10934 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10378 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1492 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4214 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1850 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3582 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3087 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9903 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6040 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5214 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20225 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19148 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4899 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13559 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9303 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6381 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 7139 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1825 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5319 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12102 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40061 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 75083 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10394 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 14786 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1797 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 572 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6631 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6573 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3835 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2489 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28166 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6069 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6073 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33519 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2144 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 39617 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43589 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3353 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 58968 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6345 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 319 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 31553 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11444 bytes .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_null_file.py | 69 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 94 + .../site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 622 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2633 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 190 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 443 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 308 + .../site-packages/pip/_vendor/rich/pretty.py | 994 ++ .../pip/_vendor/rich/progress.py | 1702 ++++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/region.py | 10 + .../site-packages/pip/_vendor/rich/repr.py | 149 + .../site-packages/pip/_vendor/rich/rule.py | 130 + .../site-packages/pip/_vendor/rich/scope.py | 86 + .../site-packages/pip/_vendor/rich/screen.py | 54 + .../site-packages/pip/_vendor/rich/segment.py | 739 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 948 ++ .../site-packages/pip/_vendor/rich/table.py | 1002 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1307 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 756 ++ .../site-packages/pip/_vendor/rich/tree.py | 251 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 608 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 27091 bytes .../__pycache__/_asyncio.cpython-312.pyc | Bin 0 -> 4811 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 2320 bytes .../__pycache__/after.cpython-312.pyc | Bin 0 -> 1629 bytes .../__pycache__/before.cpython-312.pyc | Bin 0 -> 1469 bytes .../__pycache__/before_sleep.cpython-312.pyc | Bin 0 -> 2307 bytes .../tenacity/__pycache__/nap.cpython-312.pyc | Bin 0 -> 1417 bytes .../__pycache__/retry.cpython-312.pyc | Bin 0 -> 14286 bytes .../tenacity/__pycache__/stop.cpython-312.pyc | Bin 0 -> 5573 bytes .../__pycache__/tornadoweb.cpython-312.pyc | Bin 0 -> 2591 bytes .../tenacity/__pycache__/wait.cpython-312.pyc | Bin 0 -> 12418 bytes .../pip/_vendor/tenacity/_asyncio.py | 94 + .../pip/_vendor/tenacity/_utils.py | 76 + .../pip/_vendor/tenacity/after.py | 51 + .../pip/_vendor/tenacity/before.py | 46 + .../pip/_vendor/tenacity/before_sleep.py | 71 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/retry.py | 272 + .../pip/_vendor/tenacity/stop.py | 103 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 228 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 389 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 26932 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 3913 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 371 bytes .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../pip/_vendor/truststore/__init__.py | 13 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 623 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 15802 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 16667 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2220 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1104 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15511 bytes .../pip/_vendor/truststore/_api.py | 302 + .../pip/_vendor/truststore/_macos.py | 501 + .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 554 ++ .../pip/_vendor/typing_extensions.py | 3072 ++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3410 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 16493 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 223 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20412 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36447 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13498 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10418 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4023 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20805 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7299 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33973 bytes .../pip/_vendor/urllib3/_collections.py | 355 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1137 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 203 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1853 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11569 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5724 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24455 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35561 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7516 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 220 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17432 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14806 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 204 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41324 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 214 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1830 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7336 bytes .../urllib3/packages/backports/makefile.py | 51 + .../packages/backports/weakref_finalize.py | 155 + .../pip/_vendor/urllib3/packages/six.py | 1076 +++ .../pip/_vendor/urllib3/poolmanager.py | 556 ++ .../pip/_vendor/urllib3/request.py | 191 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1151 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4761 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1557 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1357 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4188 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2994 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21723 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15108 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5076 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10777 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11144 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15800 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4408 bytes .../pip/_vendor/urllib3/util/connection.py | 149 + .../pip/_vendor/urllib3/util/proxy.py | 57 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 137 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 622 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 24 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 12006 bytes .../__pycache__/labels.cpython-312.pyc | Bin 0 -> 7137 bytes .../__pycache__/mklabels.cpython-312.pyc | Bin 0 -> 2704 bytes .../__pycache__/tests.cpython-312.pyc | Bin 0 -> 9256 bytes .../x_user_defined.cpython-312.pyc | Bin 0 -> 3300 bytes .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../werkzeug-3.1.8.dist-info/INSTALLER | 1 + .../werkzeug-3.1.8.dist-info/METADATA | 109 + .../werkzeug-3.1.8.dist-info/RECORD | 116 + .../werkzeug-3.1.8.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + .../site-packages/werkzeug/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 338 bytes .../__pycache__/_internal.cpython-312.pyc | Bin 0 -> 9751 bytes .../__pycache__/_reloader.cpython-312.pyc | Bin 0 -> 20922 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 34017 bytes .../__pycache__/formparser.cpython-312.pyc | Bin 0 -> 17024 bytes .../werkzeug/__pycache__/http.cpython-312.pyc | Bin 0 -> 51012 bytes .../__pycache__/local.cpython-312.pyc | Bin 0 -> 28479 bytes .../__pycache__/security.cpython-312.pyc | Bin 0 -> 8688 bytes .../__pycache__/serving.cpython-312.pyc | Bin 0 -> 46079 bytes .../werkzeug/__pycache__/test.cpython-312.pyc | Bin 0 -> 59868 bytes .../__pycache__/testapp.cpython-312.pyc | Bin 0 -> 8889 bytes .../werkzeug/__pycache__/urls.cpython-312.pyc | Bin 0 -> 8268 bytes .../__pycache__/user_agent.cpython-312.pyc | Bin 0 -> 2151 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 27701 bytes .../werkzeug/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 25970 bytes .../site-packages/werkzeug/_internal.py | 211 + .../site-packages/werkzeug/_reloader.py | 465 + .../werkzeug/datastructures/__init__.py | 64 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2415 bytes .../__pycache__/accept.cpython-312.pyc | Bin 0 -> 15942 bytes .../__pycache__/auth.cpython-312.pyc | Bin 0 -> 14557 bytes .../__pycache__/cache_control.cpython-312.pyc | Bin 0 -> 12224 bytes .../__pycache__/csp.cpython-312.pyc | Bin 0 -> 6185 bytes .../__pycache__/etag.cpython-312.pyc | Bin 0 -> 5400 bytes .../__pycache__/file_storage.cpython-312.pyc | Bin 0 -> 8822 bytes .../__pycache__/headers.cpython-312.pyc | Bin 0 -> 30518 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 16398 bytes .../__pycache__/range.cpython-312.pyc | Bin 0 -> 10053 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 59112 bytes .../werkzeug/datastructures/accept.py | 350 + .../werkzeug/datastructures/auth.py | 320 + .../werkzeug/datastructures/cache_control.py | 273 + .../werkzeug/datastructures/csp.py | 100 + .../werkzeug/datastructures/etag.py | 106 + .../werkzeug/datastructures/file_storage.py | 209 + .../werkzeug/datastructures/headers.py | 662 ++ .../werkzeug/datastructures/mixins.py | 317 + .../werkzeug/datastructures/range.py | 214 + .../werkzeug/datastructures/structures.py | 1239 +++ .../site-packages/werkzeug/debug/__init__.py | 574 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 23604 bytes .../debug/__pycache__/console.cpython-312.pyc | Bin 0 -> 11635 bytes .../debug/__pycache__/repr.cpython-312.pyc | Bin 0 -> 13808 bytes .../debug/__pycache__/tbtools.cpython-312.pyc | Bin 0 -> 17040 bytes .../site-packages/werkzeug/debug/console.py | 219 + .../site-packages/werkzeug/debug/repr.py | 282 + .../werkzeug/debug/shared/ICON_LICENSE.md | 6 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 344 + .../werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes .../werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes .../werkzeug/debug/shared/style.css | 150 + .../site-packages/werkzeug/debug/tbtools.py | 449 + .../site-packages/werkzeug/exceptions.py | 905 ++ .../site-packages/werkzeug/formparser.py | 430 + .../python3.12/site-packages/werkzeug/http.py | 1443 +++ .../site-packages/werkzeug/local.py | 653 ++ .../werkzeug/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../__pycache__/dispatcher.cpython-312.pyc | Bin 0 -> 3313 bytes .../__pycache__/http_proxy.cpython-312.pyc | Bin 0 -> 9405 bytes .../__pycache__/lint.cpython-312.pyc | Bin 0 -> 17775 bytes .../__pycache__/profiler.cpython-312.pyc | Bin 0 -> 7199 bytes .../__pycache__/proxy_fix.cpython-312.pyc | Bin 0 -> 7196 bytes .../__pycache__/shared_data.cpython-312.pyc | Bin 0 -> 12751 bytes .../werkzeug/middleware/dispatcher.py | 81 + .../werkzeug/middleware/http_proxy.py | 236 + .../site-packages/werkzeug/middleware/lint.py | 439 + .../werkzeug/middleware/profiler.py | 155 + .../werkzeug/middleware/proxy_fix.py | 183 + .../werkzeug/middleware/shared_data.py | 283 + .../site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 134 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4668 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 10908 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7911 bytes .../routing/__pycache__/map.cpython-312.pyc | Bin 0 -> 39184 bytes .../__pycache__/matcher.cpython-312.pyc | Bin 0 -> 8278 bytes .../routing/__pycache__/rules.cpython-312.pyc | Bin 0 -> 39169 bytes .../werkzeug/routing/converters.py | 261 + .../werkzeug/routing/exceptions.py | 152 + .../site-packages/werkzeug/routing/map.py | 928 ++ .../site-packages/werkzeug/routing/matcher.py | 202 + .../site-packages/werkzeug/routing/rules.py | 927 ++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 191 bytes .../sansio/__pycache__/http.cpython-312.pyc | Bin 0 -> 5642 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 14327 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 21943 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 31736 bytes .../sansio/__pycache__/utils.cpython-312.pyc | Bin 0 -> 8245 bytes .../site-packages/werkzeug/sansio/http.py | 170 + .../werkzeug/sansio/multipart.py | 331 + .../site-packages/werkzeug/sansio/request.py | 536 + .../site-packages/werkzeug/sansio/response.py | 763 ++ .../site-packages/werkzeug/sansio/utils.py | 224 + .../site-packages/werkzeug/security.py | 201 + .../site-packages/werkzeug/serving.py | 1126 +++ .../python3.12/site-packages/werkzeug/test.py | 1464 +++ .../site-packages/werkzeug/testapp.py | 194 + .../python3.12/site-packages/werkzeug/urls.py | 203 + .../site-packages/werkzeug/user_agent.py | 47 + .../site-packages/werkzeug/utils.py | 684 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 315 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 26145 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34807 bytes .../werkzeug/wrappers/request.py | 650 ++ .../werkzeug/wrappers/response.py | 838 ++ .../python3.12/site-packages/werkzeug/wsgi.py | 609 ++ venv/lib64 | 1 + venv/pyvenv.cfg | 5 + 1426 files changed, 261828 insertions(+) create mode 100644 __pycache__/app.cpython-312.pyc create mode 100644 app.py create mode 100644 docs/changelog.md create mode 100644 docs/faq.md create mode 100644 docs/index.md create mode 100644 docs/installation.md create mode 100644 docs/user_guide.md create mode 100644 firmware/firmware.packed.bin create mode 100644 requirements.txt create mode 100644 static/css/style.css create mode 100644 static/js/flasher.js create mode 100644 templates/base.html create mode 100644 templates/doc_page.html create mode 100644 templates/docs_list.html create mode 100644 templates/downloads.html create mode 100644 templates/flasher.html create mode 100644 templates/index.html create mode 100644 templates/info.html create mode 100644 venv/bin/Activate.ps1 create mode 100644 venv/bin/activate create mode 100644 venv/bin/activate.csh create mode 100644 venv/bin/activate.fish create mode 100755 venv/bin/flask create mode 100755 venv/bin/markdown_py create mode 100755 venv/bin/pip create mode 100755 venv/bin/pip3 create mode 100755 venv/bin/pip3.12 create mode 120000 venv/bin/python create mode 120000 venv/bin/python3 create mode 120000 venv/bin/python3.12 create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/blinker/__init__.py create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/_utilities.py create mode 100644 venv/lib/python3.12/site-packages/blinker/base.py create mode 100644 venv/lib/python3.12/site-packages/blinker/py.typed create mode 100644 venv/lib/python3.12/site-packages/click-8.3.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/click-8.3.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/click-8.3.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/click-8.3.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/click-8.3.2.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/click/__init__.py create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/_compat.py create mode 100644 venv/lib/python3.12/site-packages/click/_termui_impl.py create mode 100644 venv/lib/python3.12/site-packages/click/_textwrap.py create mode 100644 venv/lib/python3.12/site-packages/click/_utils.py create mode 100644 venv/lib/python3.12/site-packages/click/_winconsole.py create mode 100644 venv/lib/python3.12/site-packages/click/core.py create mode 100644 venv/lib/python3.12/site-packages/click/decorators.py create mode 100644 venv/lib/python3.12/site-packages/click/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/click/formatting.py create mode 100644 venv/lib/python3.12/site-packages/click/globals.py create mode 100644 venv/lib/python3.12/site-packages/click/parser.py create mode 100644 venv/lib/python3.12/site-packages/click/py.typed create mode 100644 venv/lib/python3.12/site-packages/click/shell_completion.py create mode 100644 venv/lib/python3.12/site-packages/click/termui.py create mode 100644 venv/lib/python3.12/site-packages/click/testing.py create mode 100644 venv/lib/python3.12/site-packages/click/types.py create mode 100644 venv/lib/python3.12/site-packages/click/utils.py create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/flask/__init__.py create mode 100644 venv/lib/python3.12/site-packages/flask/__main__.py create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/app.py create mode 100644 venv/lib/python3.12/site-packages/flask/blueprints.py create mode 100644 venv/lib/python3.12/site-packages/flask/cli.py create mode 100644 venv/lib/python3.12/site-packages/flask/config.py create mode 100644 venv/lib/python3.12/site-packages/flask/ctx.py create mode 100644 venv/lib/python3.12/site-packages/flask/debughelpers.py create mode 100644 venv/lib/python3.12/site-packages/flask/globals.py create mode 100644 venv/lib/python3.12/site-packages/flask/helpers.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/__init__.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/provider.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/tag.py create mode 100644 venv/lib/python3.12/site-packages/flask/logging.py create mode 100644 venv/lib/python3.12/site-packages/flask/py.typed create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/README.md create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/app.py create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/blueprints.py create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/scaffold.py create mode 100644 venv/lib/python3.12/site-packages/flask/sessions.py create mode 100644 venv/lib/python3.12/site-packages/flask/signals.py create mode 100644 venv/lib/python3.12/site-packages/flask/templating.py create mode 100644 venv/lib/python3.12/site-packages/flask/testing.py create mode 100644 venv/lib/python3.12/site-packages/flask/typing.py create mode 100644 venv/lib/python3.12/site-packages/flask/views.py create mode 100644 venv/lib/python3.12/site-packages/flask/wrappers.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__init__.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/_json.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/encoding.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/exc.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/py.typed create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/serializer.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/signer.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/timed.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/url_safe.py create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/jinja2/__init__.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/_identifier.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/async_utils.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/bccache.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/compiler.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/constants.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/debug.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/defaults.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/environment.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/ext.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/filters.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/idtracking.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/lexer.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/loaders.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/meta.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/nativetypes.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/nodes.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/optimizer.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/parser.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/py.typed create mode 100644 venv/lib/python3.12/site-packages/jinja2/runtime.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/sandbox.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/tests.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/utils.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/visitor.py create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/licenses/LICENSE.md create mode 100644 venv/lib/python3.12/site-packages/markdown-3.10.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/markdown/__init__.py create mode 100644 venv/lib/python3.12/site-packages/markdown/__main__.py create mode 100644 venv/lib/python3.12/site-packages/markdown/__meta__.py create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/__meta__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/blockparser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/blockprocessors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/htmlparser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/inlinepatterns.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/postprocessors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/preprocessors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/serializers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/test_tools.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/treeprocessors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/blockparser.py create mode 100644 venv/lib/python3.12/site-packages/markdown/blockprocessors.py create mode 100644 venv/lib/python3.12/site-packages/markdown/core.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__init__.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/abbr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/admonition.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/attr_list.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/codehilite.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/def_list.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/extra.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/fenced_code.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/footnotes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/legacy_attrs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/legacy_em.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/md_in_html.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/meta.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/nl2br.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/sane_lists.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/smarty.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/tables.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/toc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/__pycache__/wikilinks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/abbr.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/admonition.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/attr_list.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/codehilite.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/def_list.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/extra.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/fenced_code.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/footnotes.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/legacy_attrs.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/legacy_em.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/md_in_html.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/meta.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/nl2br.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/sane_lists.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/smarty.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/tables.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/toc.py create mode 100644 venv/lib/python3.12/site-packages/markdown/extensions/wikilinks.py create mode 100644 venv/lib/python3.12/site-packages/markdown/htmlparser.py create mode 100644 venv/lib/python3.12/site-packages/markdown/inlinepatterns.py create mode 100644 venv/lib/python3.12/site-packages/markdown/postprocessors.py create mode 100644 venv/lib/python3.12/site-packages/markdown/preprocessors.py create mode 100644 venv/lib/python3.12/site-packages/markdown/serializers.py create mode 100644 venv/lib/python3.12/site-packages/markdown/test_tools.py create mode 100644 venv/lib/python3.12/site-packages/markdown/treeprocessors.py create mode 100644 venv/lib/python3.12/site-packages/markdown/util.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/markupsafe-3.0.3.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__init__.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_native.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_speedups.c create mode 100755 venv/lib/python3.12/site-packages/markupsafe/_speedups.cpython-312-x86_64-linux-gnu.so create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_speedups.pyi create mode 100644 venv/lib/python3.12/site-packages/markupsafe/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.0.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/pip/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pip-runner__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/build_env.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/command_context.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/req_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/completion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/debug.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/hash.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/list.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/search.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/show.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/installed.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/sdist.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/collector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/sources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_distutils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/_json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/candidate.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/direct_url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/format_control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/installation_report.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/scheme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/search_scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/target_python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/session.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/prepare.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/pyproject.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/constructors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_set.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/self_outdated_check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_log.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/appdirs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/datetime.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/deprecation.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/egg_link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/encoding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filesystem.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filetypes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/glibc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/hashes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/misc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/packaging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/subprocess.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/unpacking.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/urls.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/git.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/subversion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/wheel_builder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachinedict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/enums.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/macromanprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/resultdict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansi_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/initialise_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/isatty_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/winterm_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/win32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/database.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/locators.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distro/distro.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/codec.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/intranges.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/package_data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/token.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__version__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/certs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/hooks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/packages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_extension.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_loop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_pick.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_stack.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_timer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/align.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/box.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/cells.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/columns.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/constrain.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/containers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/emoji.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/errors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/filesize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/layout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/markup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/measure.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/padding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/palette.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/panel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pretty.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/prompt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/protocol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/region.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/repr.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/rule.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/screen.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/segment.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/spinner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/status.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/styled.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/syntax.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/table.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/themes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/traceback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/tree.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/after.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_re.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_types.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_macos.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_openssl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_ssl_constants.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/truststore/_windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/typing_extensions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/vendor.txt create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 venv/lib/python3.12/site-packages/pip/py.typed create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.8.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.8.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.8.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.8.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.8.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/local.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/security.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/_internal.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/_reloader.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/accept.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/auth.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/cache_control.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/csp.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/etag.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/file_storage.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/headers.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/mixins.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/range.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/structures.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/console.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/repr.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/console.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/less.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/more.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/style.css create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/tbtools.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/formparser.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/http.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/local.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/lint.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/profiler.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/shared_data.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/py.typed create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/converters.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/map.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/matcher.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/rules.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/http.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/multipart.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/request.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/response.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/utils.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/security.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/serving.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/test.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/testapp.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/urls.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/user_agent.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/utils.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/request.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/response.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wsgi.py create mode 120000 venv/lib64 create mode 100644 venv/pyvenv.cfg diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a097491afad145adc11c76e6f882a36ae6dd2386 GIT binary patch literal 4417 zcmb^zTW}NC_3lI3m1J2q7(al35-7Hk+6Kz2gkUfa^Jr{plO|C=)Wvrt%jn_UU16*d zi3m(FQ#vM-%m583H2pDSe>fR3p-G`>ryrT=&#HE&nhi6hQ-1nq3Ny^`)pK^WYeDPj zPp)QD~aw(A)fRQ>N!iO*QM2g-*r@?GWAhE4I~Jy`IwsyPI>L!CAerkt)(Ga zN9*Yly7a0ix`Z~ICDEm-Z#ZJhR71MV^|0|QnX0g&%NCJta-aVvS7`%+PH|; za#w4`f>yL?5$Tn#^mA3x&5KB{a-~;SNw+K_9d@OkuaaJ_%JhZfZGk#v zuBG3bUNmuf(W#aT8Tqe-R? z>RC2s%1pHpQ_8VaES_b(rW{YQ^r*sAQ>58JZO~rEhLyY|4>A2O5tT$aN}@a!D1VlV z3S(SEG(-C<`u%E3RW!ACP^vP47I5bee+J+ZDR2c6gPA=FJYbb7Bcvbz=B!8xB48Dt zf#(5CboIO^IgRH?f&kUyP{+s(uJ?x5luoEjOJ+0R4+aAKOQ{(pt(v~UAtjSgQ`v+m zYRNpZR7KA*Rf|YKQB!di0%NQWK|O*c2$mwi0BGn~*d9+>JBPAqwKJz|$RC5h6Ya-0 zw>yz+*OI#0sf>(tj6lp|v1BHx$71>BXCl?%Z~|z2J%A!9H?0~MFVvJ9n&Hn^ZVtm= zu-x(j{M9ZHe^qjlLfJ<8d8>!{sS@MYYdRlE6WaoV+Hgv3SKc?zR-oJ7E#x3pZH??orl3(h$+cBaH z9#?6{v1BGc(jGnt-X@h)7!|_IP6~f}c>k+mrqE@p;dtZQ;Y+5l>!* z75Z@nQ+5pJrHZ+{Y#HiSnCZ3kSuMDhLtwmbd}+)WpBlG~nbJfK&)oQJ>2&E`Al^3a z0OJc|CfAAN>!mY*AnA^A(-MJM*!TmWUzRQypIfXM(EJSWiQMz3bJ>!+Qz{y_N)ut@ z7D)Xb__wX^mhn4N*uVS7Sjb5z;FD%eGNb8A3ThZr*q_s&s1rE|ij|C}5LezBbV~;8 zV{^6&tPQA_hz_VdhTT$fD1;2V#j-%tEA1VMjC=@}?#267VgxCt3|G{l{hX-Lmi}+0$JwJ>fc^x-2latW4Yl6Uan2ODU(jxk!0@ z3oYQ&f|C;i(8GH3eya*PhV*obp;Cl5y?CE#I$mDZ1*6^I8OF(!`}h55-|m5Z18gOr zRZT67D1r|7v}FK_0H`=)alW4nh$?bfqIk-oHxl_IEg##!+$-~CcIT+T)k3y~o6)mRdx-vMF zhP;gM3{9Ce`w#ZN`ugtveVFIq4_=ZQp0ks%jvH(@5b-smp$JBQ)z!k}8($rr3mh`U zL$(uMaANQ~3iO~BOF_|90&RLmlmyglB~koVX&%|#^WUk0EsP;}88?eJzm+N&@a=Pf zorbv6-fPg_D+D{C?(BRj$ZiMz7_{MuQ`Lh{aI8VEgch>i?Y`9Ql1{fAAiDc(DiDWy ziYsu%AmtbOaDia`K%W*q5}-f39hi#G$`q=)_q1n91T`3Nz}{ZV;XJ=4oO=mKe!uaX z(z|d!;dOVb^mAh-Y%MncM>m|iD#d#a6Bda9^%`mx>Od<3S!6i=6$H^6f{Ql*;*D+fE@x3ei~kK zcKdmGHqdH__R9)iYiT8!foGw#zQg(@$Kj=UG$NSdP!`&qh>s-GL)BxsL}aDuiQ_w; z;TElES_N4Z<`(cxWV zdRR86t5y@WI+9h;R^C`=WVvSwESGu4`zP`a`{}upy#{u$H)!txoEJEb`#U-E4LR~H z@qJ4||L_LJ51h#sg?kHk+2!tQJy&|J^nc2&8dt-NGUxqeeQQ1>9ugUf7f}ry7@Z7d(O3-ZW;ftQ^VW2}!P$$W+ve)Ffv#9Hp8u=RQWm9i aJ*Rsvwp?$RJX-AeM%*|r5OKLx3I73p_2%XP literal 0 HcmV?d00001 diff --git a/app.py b/app.py new file mode 100644 index 0000000..8f409fa --- /dev/null +++ b/app.py @@ -0,0 +1,83 @@ +from flask import Flask, render_template, send_from_directory, redirect, url_for +import os +import markdown + +app = Flask(__name__) + +FIRMWARE_DIR = os.path.join(os.path.dirname(__file__), 'firmware') +DOCS_DIR = os.path.join(os.path.dirname(__file__), 'docs') + +class FirmwareRelease: + def __init__(self, version, date, filename, changelog, size, features=None): + self.version = version + self.date = date + self.filename = filename + self.changelog = changelog + self.size = size + self.features = features or [] + +RELEASES = [ + FirmwareRelease( + version="v1.0-beta", + date="2026-04-16", + filename="firmware.packed.bin", + changelog="- Initial beta release\n- FM radio support\n- Spectrum analyzer\n- Wide Rx band\n- RSSI bar display\n- POCSAG decoder", + size="48 KB", + features=["FM Radio", "Spectrum", "Wide Rx", "RSSI Bar", "POCSAG"] + ), +] + +DOCS_PAGES = { + 'index': 'Главная', + 'installation': 'Установка', + 'user_guide': 'Руководство пользователя', + 'changelog': 'История изменений', + 'faq': 'FAQ', +} + +def load_doc(filename): + doc_path = os.path.join(DOCS_DIR, f'{filename}.md') + if os.path.exists(doc_path): + with open(doc_path, 'r', encoding='utf-8') as f: + content = f.read() + return markdown.markdown(content, extensions=['fenced_code', 'tables']) + return None + +@app.route('/') +def index(): + return render_template('index.html', latest=RELEASES[0], releases=RELEASES) + +@app.route('/download/') +@app.route('/downloads/') +def downloads(): + return render_template('downloads.html', releases=RELEASES) + +@app.route('/download/') +def download(filename): + return send_from_directory(FIRMWARE_DIR, filename, as_attachment=True) + +@app.route('/docs/') +def docs(): + return render_template('docs_list.html', pages=DOCS_PAGES) + +@app.route('/docs//') +def doc_page(page): + if page not in DOCS_PAGES: + return redirect(url_for('docs')) + + content = load_doc(page) + if content is None: + content = f"# {DOCS_PAGES[page]}\n\nСтраница в разработке." + + return render_template('doc_page.html', title=DOCS_PAGES[page], content=content, pages=DOCS_PAGES) + +@app.route('/info/') +def info(): + return render_template('info.html') + +@app.route('/flasher/') +def flasher(): + return render_template('flasher.html') + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) \ No newline at end of file diff --git a/docs/changelog.md b/docs/changelog.md new file mode 100644 index 0000000..b35fd97 --- /dev/null +++ b/docs/changelog.md @@ -0,0 +1,19 @@ +# История изменений + +## v1.0-beta (2026-04-16) + +### Добавлено +- FM радио (88-108 МГц) +- Spectrum analyzer +- Расширенный RX диапазон (50-10800 МГц) +- RSSI bar display +- POCSAG decoder +- Wide TX band + +### Известные проблемы +- Некоторые функции могут работать нестабильно +- RTC могут сбрасываться + +### Тестируется +- GPS интерфейс +- Расширенное меню \ No newline at end of file diff --git a/docs/faq.md b/docs/faq.md new file mode 100644 index 0000000..02c10c5 --- /dev/null +++ b/docs/faq.md @@ -0,0 +1,34 @@ +# FAQ + +## Общие вопросы + +### Безопасна ли прошивка? +Да, прошивка устанавливается на свой страх и риск. Большинство пользователей без проблем устанавливают альтернативные прошивки. + +### Можно ли вернуть заводскую прошивку? +Да, через официальную CPS можно восстановить заводскую прошивку. + +### Что делать если рация не включается после прошивки? +1. Выключите рацию +2. Запустите режим загрузчика (PTT + включение) +3. Прошейте заново + +## Функции + +### Как включить FM радио? +Нажмите [F] + [3] для включения FM приёмника. + +### Как работает Spectrum analyzer? +Нажмите [F] + [2] для сканирования эфира. + +### Поддерживается ли POCSAG? +Да, встроенный декодер POCSAG добавлен в версии 1.0+. + +## Технические вопросы + +### Какой микроконтроллер используется? +MCU: GigaDevice GD32F103 (ARM Cortex-M3) + +### Какой диапазон частот поддерживается? +- RX: 50-10800 МГц +- TX: 134-174 МГц, 400-520 МГц \ No newline at end of file diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 0000000..e69de29 diff --git a/docs/installation.md b/docs/installation.md new file mode 100644 index 0000000..917252b --- /dev/null +++ b/docs/installation.md @@ -0,0 +1,39 @@ +# Установка прошивки + +## Подготовка + +1. Скачайте последнюю версию прошивки со страницы [Загрузки](/downloads/) +2. Подготовьте кабель USB-C для программирования + +## Через CPS (Windows) + +1. Скачайте и установите официальную CPS с сайта Baofeng +2. Запустите CPS +3. Подключите рацию к компьютеру +4. В меню "Extras" выберите "Firmware Loader" +5. Выберите файл прошивки `.bin` +6. Выключите рацию, затем вклюните с зажатой кнопкой PTT +7. Дождитесь завершения прошивки + +## Через USB (Linux/macOS) + +Требуется программа `dfu-util`: + +```bash +dfu-util -d 15a2:0001 -R -D firmware.bin +``` + +## Режим загрузчика + +1. Выключите рацию +2. Зажмите и держите кнопку PTT +3. Включите рацию +4. Дождитесь сигнала или сообщения на экране +5. Отпустите PTT + +## Восстановление + +Если прошивка не загружается: +1. Повторите процесс прошивки +2. Используйте другой кабель +3. Попробуйте другой порт USB \ No newline at end of file diff --git a/docs/user_guide.md b/docs/user_guide.md new file mode 100644 index 0000000..22bb10b --- /dev/null +++ b/docs/user_guide.md @@ -0,0 +1,47 @@ +# Руководство пользователя + +## Основные функции + +### VFO режим +Настройка частоты вручную: +- Вращайте ручку для изменения частоты +- Нажмите кнопку [A/B] для переключения VFO A/B +- Длительное нажатие [MENU] для шага сетки частот + +### Каналы +Сохранённые каналы: +-short press [▼] или [▲] для переключения каналов +- Нажмите [MENU] для входа в меню каналов +- Длительное нажатие [MENU] для редактирования канала + +### FM Радио +Встроенный FM приёмник: +1. Нажмите [F] + [3] для включения FM +2. Используйте [▼]/[▲] для настройки +3. Нажмите [MENU] для поиска станций + +### Spectrum Analyzer +Анализатор спектра: +1. Нажмите [F] + [2] для включения +2. Отображаются активные частоты в диапазоне + +## Меню + +| Кнопка | Функция | +|--------|---------| +| [MENU] | Меню | +| [F] | Функции | +| [A/B] | Переключение VFO | +| [▼]/[▲] | Навигация | +| [VFO/MR] | VFO/Каналы | + +## CTCSS/DCS + +- CTCSS: 67.0-254.1 Гц (стандартные тоны) +- DCS: 023-754 (отрицательные/положительные) + +## Параметры + +- Мощность: 1W / 5W / 10W +- Диапазон VHF: 134-174 МГц +- Диапазон UHF: 400-520 МГц (расширенный) \ No newline at end of file diff --git a/firmware/firmware.packed.bin b/firmware/firmware.packed.bin new file mode 100644 index 0000000000000000000000000000000000000000..ee13edb7a73354ae3a595ed7d22c95319916fef2 GIT binary patch literal 45674 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ՠk&%uY@5n- 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.3.0 +markdown>=3.4.0 \ No newline at end of file diff --git a/static/css/style.css b/static/css/style.css new file mode 100644 index 0000000..fdeb529 --- /dev/null +++ b/static/css/style.css @@ -0,0 +1,324 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +:root { + --primary: #1a73e8; + --primary-dark: #1557b0; + --bg: #f5f5f5; + --surface: #ffffff; + --text: #333333; + --text-muted: #666666; + --border: #e0e0e0; + --success: #4caf50; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; + background: var(--bg); + color: var(--text); + line-height: 1.6; +} + +header { + background: var(--primary); + color: white; + padding: 1rem 0; + box-shadow: 0 2px 4px rgba(0,0,0,0.1); +} + +header .container { + max-width: 900px; + margin: 0 auto; + padding: 0 1rem; + display: flex; + justify-content: space-between; + align-items: center; +} + +header h1 { + font-size: 1.5rem; +} + +nav a { + color: white; + text-decoration: none; + margin-left: 1.5rem; + padding: 0.5rem 1rem; + border-radius: 4px; + transition: background 0.2s; +} + +nav a:hover { + background: rgba(255,255,255,0.15); +} + +main { + max-width: 900px; + margin: 2rem auto; + padding: 0 1rem; +} + +.card { + background: var(--surface); + border-radius: 8px; + padding: 1.5rem; + margin-bottom: 1rem; + box-shadow: 0 1px 3px rgba(0,0,0,0.1); +} + +.btn { + display: inline-block; + background: var(--primary); + color: white; + padding: 0.75rem 1.5rem; + border-radius: 4px; + text-decoration: none; + font-weight: 500; + transition: background 0.2s; +} + +.btn:hover { + background: var(--primary-dark); +} + +.btn-download { + display: inline-flex; + align-items: center; + gap: 0.5rem; +} + +.release-version { + font-size: 1.25rem; + font-weight: 600; + color: var(--primary); +} + +.release-date { + color: var(--text-muted); + font-size: 0.9rem; +} + +.changelog { + background: #f8f9fa; + padding: 1rem; + border-radius: 4px; + font-family: monospace; + white-space: pre-wrap; + margin: 1rem 0; +} + +.feature-tags { + display: flex; + flex-wrap: wrap; + gap: 0.5rem; + margin: 0.5rem 0; +} + +.tag { + background: #e3f2fd; + color: var(--primary); + padding: 0.25rem 0.75rem; + border-radius: 12px; + font-size: 0.8rem; +} + +.doc-list { + list-style: none; +} + +.doc-list li { + margin-bottom: 0.5rem; +} + +.doc-list a { + display: block; + padding: 0.75rem 1rem; + background: var(--surface); + border-radius: 4px; + text-decoration: none; + color: var(--text); + transition: background 0.2s; +} + +.doc-list a:hover { + background: #e3f2fd; +} + +.markdown-content h1 { font-size: 1.75rem; margin: 1.5rem 0 1rem; } +.markdown-content h2 { font-size: 1.5rem; margin: 1.25rem 0 0.75rem; } +.markdown-content h3 { font-size: 1.25rem; margin: 1rem 0 0.5rem; } +.markdown-content p { margin: 0.75rem 0; } +.markdown-content ul, .markdown-content ol { margin: 0.75rem 0 0.75rem 1.5rem; } +.markdown-content li { margin: 0.25rem 0; } +.markdown-content code { + background: #f5f5f5; + padding: 0.125rem 0.375rem; + border-radius: 3px; + font-size: 0.9em; +} +.markdown-content pre { + background: #263238; + color: #aed581; + padding: 1rem; + border-radius: 4px; + overflow-x: auto; +} +.markdown-content pre code { + background: none; + padding: 0; + color: inherit; +} +.markdown-content table { + width: 100%; + border-collapse: collapse; + margin: 1rem 0; +} +.markdown-content th, .markdown-content td { + border: 1px solid var(--border); + padding: 0.5rem; + text-align: left; +} +.markdown-content th { + background: #f5f5f5; +} + +footer { + text-align: center; + padding: 2rem 0; + color: var(--text-muted); + font-size: 0.9rem; +} + +.hero { + text-align: center; + padding: 2rem 1rem; +} + +.hero h2 { + font-size: 2rem; + margin-bottom: 1rem; +} + +.hero p { + font-size: 1.1rem; + color: var(--text-muted); + max-width: 600px; + margin: 0 auto 1.5rem; +} + +.features-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); + gap: 1rem; + margin-top: 1.5rem; +} + +.feature-item { + background: #f8f9fa; + padding: 1rem; + border-radius: 4px; +} + +.feature-item h3 { + color: var(--primary); + font-size: 1rem; + margin-bottom: 0.5rem; +} + +table.downloads { + width: 100%; + border-collapse: collapse; +} + +table.downloads th, table.downloads td { + padding: 0.75rem; + border-bottom: 1px solid var(--border); + text-align: left; +} + +table.downloads th { + background: #f5f5f5; + font-weight: 600; +} + +.version-badge { + display: inline-block; + background: var(--success); + color: white; + padding: 0.125rem 0.5rem; + border-radius: 4px; + font-size: 0.75rem; + margin-left: 0.5rem; +} + +@media (max-width: 600px) { + header .container { + flex-direction: column; + gap: 0.5rem; + } + nav a { + margin: 0 0.5rem; + } +} + +input[type="file"] { + display: block; + width: 100%; + padding: 1rem; + border: 2px dashed var(--border); + border-radius: 4px; + background: #fafafa; + cursor: pointer; + margin: 1rem 0; +} + +input[type="file"]:hover { + border-color: var(--primary); + background: #f0f7ff; +} + +#fileInfo { + margin: 1rem 0; + padding: 0.75rem; + background: #f5f5f5; + border-radius: 4px; +} + +#status { + margin-top: 1rem; + padding: 1rem; + border-radius: 4px; +} + +#status.loading { + background: #fff3e0; + color: #e65100; +} + +#status.success { + background: #e8f5e9; + color: #2e7d32; +} + +#status.error { + background: #ffebee; + color: #c62828; +} + +.note { + color: var(--text-muted); + font-size: 0.9rem; + margin-top: 1rem; +} + +.note a { + color: var(--primary); +} + +.btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} \ No newline at end of file diff --git a/static/js/flasher.js b/static/js/flasher.js new file mode 100644 index 0000000..d4d2b13 --- /dev/null +++ b/static/js/flasher.js @@ -0,0 +1,63 @@ +const firmwareFile = document.getElementById('firmwareFile'); +const fileInfo = document.getElementById('fileInfo'); +const flashBtn = document.getElementById('flashBtn'); +const status = document.getElementById('status'); + +let selectedFile = null; + +firmwareFile.addEventListener('change', (e) => { + selectedFile = e.target.files[0]; + if (selectedFile) { + fileInfo.textContent = `Выбран файл: ${selectedFile.name} (${(selectedFile.size / 1024).toFixed(1)} KB)`; + flashBtn.disabled = false; + } else { + fileInfo.textContent = ''; + flashBtn.disabled = true; + } +}); + +flashBtn.addEventListener('click', async () => { + if (!selectedFile) return; + + status.textContent = 'Подключите радиостанцию к компьютеру и нажмите кнопку на устройстве...'; + status.className = 'loading'; + + try { + const device = await navigator.usb.requestDevice({ + filters: [{ vendorId: 0x15e2, productId: 0x9100 }] + }); + + await device.open(); + await device.selectConfiguration(1); + await device.claimInterface(0); + + const buffer = await selectedFile.arrayBuffer(); + const chunkSize = 64; + const totalChunks = Math.ceil(buffer.byteLength / chunkSize); + + for (let i = 0; i < totalChunks; i++) { + const start = i * chunkSize; + const end = Math.min(start + chunkSize, buffer.byteLength); + const chunk = buffer.slice(start, end); + + await device.transferOut(1, chunk); + + status.textContent = `Загрузка: ${Math.round((i / totalChunks) * 100)}%`; + await new Promise(r => setTimeout(r, 10)); + } + + await device.releaseInterface(0); + await device.close(); + + status.textContent = 'Прошивка успешно загружена!'; + status.className = 'success'; + } catch (err) { + if (err.name === 'NotFoundError') { + status.textContent = 'Устройство не найдено. Подключите радиостанцию и разрешите доступ.'; + status.className = 'error'; + } else { + status.textContent = 'Ошибка: ' + err.message; + status.className = 'error'; + } + } +}); \ No newline at end of file diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..a6cae3c --- /dev/null +++ b/templates/base.html @@ -0,0 +1,32 @@ + + + + + + {% block title %}UV-K5 Firmware{% endblock %} - UA1ZBE + + + +
+ +
+ +
+ {% block content %}{% endblock %} +
+ +
+

UV-K5 Open Firmware by UA1ZBE © 2026

+

Прошивка для радиостанции UV-K5 (K5, K4, K6)

+
+ + \ No newline at end of file diff --git a/templates/doc_page.html b/templates/doc_page.html new file mode 100644 index 0000000..05b91f7 --- /dev/null +++ b/templates/doc_page.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} + +{% block title %}{{ title }}{% endblock %} + +{% block content %} +
+

{{ title }}

+
+ + + +
+ {{ content|safe }} +
+{% endblock %} \ No newline at end of file diff --git a/templates/docs_list.html b/templates/docs_list.html new file mode 100644 index 0000000..6fdbf68 --- /dev/null +++ b/templates/docs_list.html @@ -0,0 +1,17 @@ +{% extends "base.html" %} + +{% block title %}Документация{% endblock %} + +{% block content %} +
+

Документация

+
+ +
+
    + {% for page_id, page_title in pages.items() %} +
  • {{ page_title }}
  • + {% endfor %} +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/downloads.html b/templates/downloads.html new file mode 100644 index 0000000..9898fd0 --- /dev/null +++ b/templates/downloads.html @@ -0,0 +1,46 @@ +{% extends "base.html" %} + +{% block title %}Загрузки{% endblock %} + +{% block content %} +
+

Загрузки прошивок

+

Скачайте последнюю версию прошивки для вашей радиостанции

+
+ +
+

Последняя версия

+ + + + + + + + + + + {% for release in releases %} + + + + + + + {% endfor %} + +
ВерсияДатаРазмерФайл
+ {{ release.version }} + {% if loop.first %} + LATEST + {% endif %} + {{ release.date }}{{ release.size }} + Скачать +
+
+ +
+

История изменений

+
{{ releases[0].changelog }}
+
+{% endblock %} \ No newline at end of file diff --git a/templates/flasher.html b/templates/flasher.html new file mode 100644 index 0000000..a7505cd --- /dev/null +++ b/templates/flasher.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} + +{% block title %}Прошивка{% endblock %} + +{% block content %} +
+

Flasher

+

Загрузка прошивки на радиостанцию

+
+ +
+

Выберите файл прошивки

+ +
+
+ +
+ +
+
+ +
+

Инструкция

+
    +
  1. Выберите файл прошивки .bin
  2. +
  3. Подключите радиостанцию к компьютеру
  4. +
  5. Нажмите "Прошить устройство"
  6. +
  7. Дождитесь завершения
  8. +
+

Основано на https://github.com/whosmatt/uvmod

+
+ + +{% endblock %} \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..530c7b8 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,63 @@ +{% extends "base.html" %} + +{% block title %}Главная{% endblock %} + +{% block content %} +
+

UV-K5 Open Firmware

+

Альтернативная прошивка для радиостанций UV-K5, K4, K6 и их клонов с расширенным функционалом

+ + Скачать прошивку + +
+ +
+

Последняя версия: {{ latest.version }}

+

Дата: {{ latest.date }} | Размер: {{ latest.size }}

+
+ {% for feature in latest.features %} + {{ feature }} + {% endfor %} +
+
+ +
+

Возможности прошивки

+
+
+

FM Радио

+

Встроенный FM-приёмник 88-108 МГц

+
+
+

Анализатор спектра

+

Сканирование эфира и отображение сигналов

+
+
+

Расширенный RX

+

Приём от 50 до 10800 МГц

+
+
+

RSSI индикатор

+

Отображение уровня сигнала на экране

+
+
+

POCSAG

+

Декодирование POCSAG пейджинга

+
+
+

DCS/CTCSS

+

Полная поддержка DCS/CTCSS кодов

+
+
+
+ +
+

Поддерживаемые модели

+
    +
  • UV-K5 / K4 / K6
  • +
  • Baofeng K5 (K5 Plus)
  • +
  • Luiton LT-7255
  • +
  • П compatible devices
  • +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/info.html b/templates/info.html new file mode 100644 index 0000000..9afb925 --- /dev/null +++ b/templates/info.html @@ -0,0 +1,29 @@ +{% extends "base.html" %} + +{% block title %}Информация{% endblock %} + +{% block content %} +
+

Информация о проекте

+
+ +
+

О прошивке

+

UV-K5 Open Firmware - альтернативная прошивка с открытым исходным кодом для радиостанций UV-K5 и совместимых моделей.

+
+ +
+

Автор

+

UA1ZBE

+
+ +
+

Версия

+

v1.0-beta (12.04.2026)

+
+ +
+

Отказ от ответственности

+

Прошивка устанавливается на свой страх и риск. Автор не несёт ответственности за возможные повреждения устройства.

+
+{% endblock %} \ No newline at end of file diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..da7186d --- /dev/null +++ b/venv/bin/activate @@ -0,0 +1,70 @@ +# This file must be used with "source bin/activate" *from bash* +# You cannot run it directly + +deactivate () { + # reset old environment variables + if [ -n "${_OLD_VIRTUAL_PATH:-}" ] ; then + PATH="${_OLD_VIRTUAL_PATH:-}" + export PATH + unset _OLD_VIRTUAL_PATH + fi + if [ -n "${_OLD_VIRTUAL_PYTHONHOME:-}" ] ; then + PYTHONHOME="${_OLD_VIRTUAL_PYTHONHOME:-}" + export PYTHONHOME + unset _OLD_VIRTUAL_PYTHONHOME + fi + + # Call hash to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + hash -r 2> /dev/null + + if [ -n "${_OLD_VIRTUAL_PS1:-}" ] ; then + PS1="${_OLD_VIRTUAL_PS1:-}" + export PS1 + unset _OLD_VIRTUAL_PS1 + fi + + unset VIRTUAL_ENV + unset VIRTUAL_ENV_PROMPT + if [ ! "${1:-}" = "nondestructive" ] ; then + # Self destruct! + unset -f deactivate + fi +} + +# unset irrelevant variables +deactivate nondestructive + +# on Windows, a path can contain colons and backslashes and has to be converted: +if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then + # transform D:\path\to\venv to /d/path/to/venv on MSYS + # and to /cygdrive/d/path/to/venv on Cygwin + export VIRTUAL_ENV=$(cygpath /home/ua1zbe/uv-k5-firmware-site/venv) +else + # use the path as-is + export VIRTUAL_ENV=/home/ua1zbe/uv-k5-firmware-site/venv +fi + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/"bin":$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1='(venv) '"${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT='(venv) ' + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..efd5edd --- /dev/null +++ b/venv/bin/activate.csh @@ -0,0 +1,27 @@ +# This file must be used with "source bin/activate.csh" *from csh*. +# You cannot run it directly. + +# Created by Davide Di Blasi . +# Ported to Python 3.3 venv by Andrew Svetlov + +alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PATH" && unset _OLD_VIRTUAL_PATH; rehash; test $?_OLD_VIRTUAL_PROMPT != 0 && set prompt="$_OLD_VIRTUAL_PROMPT" && unset _OLD_VIRTUAL_PROMPT; unsetenv VIRTUAL_ENV; unsetenv VIRTUAL_ENV_PROMPT; test "\!:*" != "nondestructive" && unalias deactivate' + +# Unset irrelevant variables. +deactivate nondestructive + +setenv VIRTUAL_ENV /home/ua1zbe/uv-k5-firmware-site/venv + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/"bin":$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = '(venv) '"$prompt" + setenv VIRTUAL_ENV_PROMPT '(venv) ' +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..49ca413 --- /dev/null +++ b/venv/bin/activate.fish @@ -0,0 +1,69 @@ +# This file must be used with "source /bin/activate.fish" *from fish* +# (https://fishshell.com/). You cannot run it directly. + +function deactivate -d "Exit virtual environment and return to normal shell environment" + # reset old environment variables + if test -n "$_OLD_VIRTUAL_PATH" + set -gx PATH $_OLD_VIRTUAL_PATH + set -e _OLD_VIRTUAL_PATH + end + if test -n "$_OLD_VIRTUAL_PYTHONHOME" + set -gx PYTHONHOME $_OLD_VIRTUAL_PYTHONHOME + set -e _OLD_VIRTUAL_PYTHONHOME + end + + if test -n "$_OLD_FISH_PROMPT_OVERRIDE" + set -e _OLD_FISH_PROMPT_OVERRIDE + # prevents error when using nested fish instances (Issue #93858) + if functions -q _old_fish_prompt + functions -e fish_prompt + functions -c _old_fish_prompt fish_prompt + functions -e _old_fish_prompt + end + end + + set -e VIRTUAL_ENV + set -e VIRTUAL_ENV_PROMPT + if test "$argv[1]" != "nondestructive" + # Self-destruct! + functions -e deactivate + end +end + +# Unset irrelevant variables. +deactivate nondestructive + +set -gx VIRTUAL_ENV /home/ua1zbe/uv-k5-firmware-site/venv + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/"bin $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) '(venv) ' (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT '(venv) ' +end diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 0000000..2d8b4aa --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,8 @@ +#!/home/ua1zbe/uv-k5-firmware-site/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/markdown_py b/venv/bin/markdown_py new file mode 100755 index 0000000..c2243d0 --- /dev/null +++ b/venv/bin/markdown_py @@ -0,0 +1,8 @@ +#!/home/ua1zbe/uv-k5-firmware-site/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from markdown.__main__ import run +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(run()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 0000000..6edb11a --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/home/ua1zbe/uv-k5-firmware-site/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 0000000..6edb11a --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/home/ua1zbe/uv-k5-firmware-site/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.12 b/venv/bin/pip3.12 new file mode 100755 index 0000000..6edb11a --- /dev/null +++ b/venv/bin/pip3.12 @@ -0,0 +1,8 @@ +#!/home/ua1zbe/uv-k5-firmware-site/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 0000000..ae65fda --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/usr/bin/python3 \ No newline at end of file diff --git a/venv/bin/python3.12 b/venv/bin/python3.12 new file mode 120000 index 0000000..b8a0adb --- /dev/null +++ b/venv/bin/python3.12 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..79c9825 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2010 Jason Kirtland + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA new file mode 100644 index 0000000..6d343f5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.3 +Name: blinker +Version: 1.9.0 +Summary: Fast, simple object-to-object and broadcast signaling +Author: Jason Kirtland +Maintainer-email: Pallets Ecosystem +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://blinker.readthedocs.io +Project-URL: Source, https://github.com/pallets-eco/blinker/ + +# Blinker + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + + +## Pallets Community Ecosystem + +> [!IMPORTANT]\ +> This project is part of the Pallets Community Ecosystem. Pallets is the open +> source organization that maintains Flask; Pallets-Eco enables community +> maintenance of related projects. If you are interested in helping maintain +> this project, please reach out on [the Pallets Discord server][discord]. +> +> [discord]: https://discord.gg/pallets + + +## Example + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + +```pycon +>>> from blinker import signal +>>> started = signal('round-started') +>>> def each(round): +... print(f"Round {round}") +... +>>> started.connect(each) + +>>> def round_two(round): +... print("This is round two.") +... +>>> started.connect(round_two, sender=2) + +>>> for round in range(1, 4): +... started.send(round) +... +Round 1! +Round 2! +This is round two. +Round 3! +``` + diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD new file mode 100644 index 0000000..7cfb714 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD @@ -0,0 +1,12 @@ +blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 +blinker-1.9.0.dist-info/RECORD,, +blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 +blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 +blinker/__pycache__/__init__.cpython-312.pyc,, +blinker/__pycache__/_utilities.cpython-312.pyc,, +blinker/__pycache__/base.cpython-312.pyc,, +blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 +blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL new file mode 100644 index 0000000..e3c6fee --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.10.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/blinker/__init__.py b/venv/lib/python3.12/site-packages/blinker/__init__.py new file mode 100644 index 0000000..1772fa4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/__init__.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from .base import ANY +from .base import default_namespace +from .base import NamedSignal +from .base import Namespace +from .base import Signal +from .base import signal + +__all__ = [ + "ANY", + "default_namespace", + "NamedSignal", + "Namespace", + "Signal", + "signal", +] diff --git a/venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e1ea327571db40e8f144b59024a154a11e450825 GIT binary patch literal 495 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 F{{@;D2crN0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/blinker/_utilities.py b/venv/lib/python3.12/site-packages/blinker/_utilities.py new file mode 100644 index 0000000..000c902 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/_utilities.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import collections.abc as c +import inspect +import typing as t +from weakref import ref +from weakref import WeakMethod + +T = t.TypeVar("T") + + +class Symbol: + """A constant symbol, nicer than ``object()``. Repeated calls return the + same instance. + + >>> Symbol('foo') is Symbol('foo') + True + >>> Symbol('foo') + foo + """ + + symbols: t.ClassVar[dict[str, Symbol]] = {} + + def __new__(cls, name: str) -> Symbol: + if name in cls.symbols: + return cls.symbols[name] + + obj = super().__new__(cls) + cls.symbols[name] = obj + return obj + + def __init__(self, name: str) -> None: + self.name = name + + def __repr__(self) -> str: + return self.name + + def __getnewargs__(self) -> tuple[t.Any, ...]: + return (self.name,) + + +def make_id(obj: object) -> c.Hashable: + """Get a stable identifier for a receiver or sender, to be used as a dict + key or in a set. + """ + if inspect.ismethod(obj): + # The id of a bound method is not stable, but the id of the unbound + # function and instance are. + return id(obj.__func__), id(obj.__self__) + + if isinstance(obj, (str, int)): + # Instances with the same value always compare equal and have the same + # hash, even if the id may change. + return obj + + # Assume other types are not hashable but will always be the same instance. + return id(obj) + + +def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: + if inspect.ismethod(obj): + return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] + + return ref(obj, callback) diff --git a/venv/lib/python3.12/site-packages/blinker/base.py b/venv/lib/python3.12/site-packages/blinker/base.py new file mode 100644 index 0000000..d051b94 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/base.py @@ -0,0 +1,512 @@ +from __future__ import annotations + +import collections.abc as c +import sys +import typing as t +import weakref +from collections import defaultdict +from contextlib import contextmanager +from functools import cached_property +from inspect import iscoroutinefunction + +from ._utilities import make_id +from ._utilities import make_ref +from ._utilities import Symbol + +F = t.TypeVar("F", bound=c.Callable[..., t.Any]) + +ANY = Symbol("ANY") +"""Symbol for "any sender".""" + +ANY_ID = 0 + + +class Signal: + """A notification emitter. + + :param doc: The docstring for the signal. + """ + + ANY = ANY + """An alias for the :data:`~blinker.ANY` sender symbol.""" + + set_class: type[set[t.Any]] = set + """The set class to use for tracking connected receivers and senders. + Python's ``set`` is unordered. If receivers must be dispatched in the order + they were connected, an ordered set implementation can be used. + + .. versionadded:: 1.7 + """ + + @cached_property + def receiver_connected(self) -> Signal: + """Emitted at the end of each :meth:`connect` call. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: ``receiver``, ``sender``, and ``weak``. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver connects.") + + @cached_property + def receiver_disconnected(self) -> Signal: + """Emitted at the end of each :meth:`disconnect` call. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: ``receiver`` and ``sender``. + + This signal is emitted **only** when :meth:`disconnect` is called + explicitly. This signal cannot be emitted by an automatic disconnect + when a weakly referenced receiver or sender goes out of scope, as the + instance is no longer be available to be used as the sender for this + signal. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc: str | None = None) -> None: + if doc: + self.__doc__ = doc + + self.receivers: dict[ + t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] + ] = {} + """The map of connected receivers. Useful to quickly check if any + receivers are connected to the signal: ``if s.receivers:``. The + structure and data is not part of the public API, but checking its + boolean value is. + """ + + self.is_muted: bool = False + self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} + + def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: + """Connect ``receiver`` to be called when the signal is sent by + ``sender``. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends. + """ + receiver_id = make_id(receiver) + sender_id = ANY_ID if sender is ANY else make_id(sender) + + if weak: + self.receivers[receiver_id] = make_ref( + receiver, self._make_cleanup_receiver(receiver_id) + ) + else: + self.receivers[receiver_id] = receiver + + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + + if sender is not ANY and sender_id not in self._weak_senders: + # store a cleanup for weakref-able senders + try: + self._weak_senders[sender_id] = make_ref( + sender, self._make_cleanup_sender(sender_id) + ) + except TypeError: + pass + + if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: + try: + self.receiver_connected.send( + self, receiver=receiver, sender=sender, weak=weak + ) + except TypeError: + # TODO no explanation or test for this + self.disconnect(receiver, sender) + raise + + return receiver + + def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: + """Connect the decorated function to be called when the signal is sent + by ``sender``. + + The decorated function will be called when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument along + with any extra keyword arguments. + + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends.= + + .. versionadded:: 1.1 + """ + + def decorator(fn: F) -> F: + self.connect(fn, sender, weak) + return fn + + return decorator + + @contextmanager + def connected_to( + self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY + ) -> c.Generator[None, None, None]: + """A context manager that temporarily connects ``receiver`` to the + signal while a ``with`` block executes. When the block exits, the + receiver is disconnected. Useful for tests. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. + + .. versionadded:: 1.1 + """ + self.connect(receiver, sender=sender, weak=False) + + try: + yield None + finally: + self.disconnect(receiver) + + @contextmanager + def muted(self) -> c.Generator[None, None, None]: + """A context manager that temporarily disables the signal. No receivers + will be called if the signal is sent, until the ``with`` block exits. + Useful for tests. + """ + self.is_muted = True + + try: + yield None + finally: + self.is_muted = False + + def send( + self, + sender: t.Any | None = None, + /, + *, + _async_wrapper: c.Callable[ + [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Call all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _async_wrapper: Will be called on any receivers that are async + coroutines to turn them into sync callables. For example, could run + the receiver with an event loop. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionchanged:: 1.7 + Added the ``_async_wrapper`` argument. + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if iscoroutinefunction(receiver): + if _async_wrapper is None: + raise RuntimeError("Cannot send to a coroutine function.") + + result = _async_wrapper(receiver)(sender, **kwargs) + else: + result = receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + async def send_async( + self, + sender: t.Any | None = None, + /, + *, + _sync_wrapper: c.Callable[ + [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Await all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _sync_wrapper: Will be called on any receivers that are sync + callables to turn them into async coroutines. For example, + could call the receiver in a thread. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionadded:: 1.7 + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if not iscoroutinefunction(receiver): + if _sync_wrapper is None: + raise RuntimeError("Cannot send to a non-coroutine function.") + + result = await _sync_wrapper(receiver)(sender, **kwargs) + else: + result = await receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + def has_receivers_for(self, sender: t.Any) -> bool: + """Check if there is at least one receiver that will be called with the + given ``sender``. A receiver connected to :data:`ANY` will always be + called, regardless of sender. Does not check if weakly referenced + receivers are still live. See :meth:`receivers_for` for a stronger + search. + + :param sender: Check for receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + if not self.receivers: + return False + + if self._by_sender[ANY_ID]: + return True + + if sender is ANY: + return False + + return make_id(sender) in self._by_sender + + def receivers_for( + self, sender: t.Any + ) -> c.Generator[c.Callable[..., t.Any], None, None]: + """Yield each receiver to be called for ``sender``, in addition to those + to be called for :data:`ANY`. Weakly referenced receivers that are not + live will be disconnected and skipped. + + :param sender: Yield receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + # TODO: test receivers_for(ANY) + if not self.receivers: + return + + sender_id = make_id(sender) + + if sender_id in self._by_sender: + ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] + else: + ids = self._by_sender[ANY_ID].copy() + + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + + if receiver is None: + continue + + if isinstance(receiver, weakref.ref): + strong = receiver() + + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + + yield strong + else: + yield receiver + + def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: + """Disconnect ``receiver`` from being called when the signal is sent by + ``sender``. + + :param receiver: A connected receiver callable. + :param sender: Disconnect from only this sender. By default, disconnect + from all senders. + """ + sender_id: c.Hashable + + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = make_id(sender) + + receiver_id = make_id(receiver) + self._disconnect(receiver_id, sender_id) + + if ( + "receiver_disconnected" in self.__dict__ + and self.receiver_disconnected.receivers + ): + self.receiver_disconnected.send(self, receiver=receiver, sender=sender) + + def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, None) is not None: + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _make_cleanup_receiver( + self, receiver_id: c.Hashable + ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: + """Create a callback function to disconnect a weakly referenced + receiver when it is garbage collected. + """ + + def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: + # If the interpreter is shutting down, disconnecting can result in a + # weird ignored exception. Don't call it in that case. + if not sys.is_finalizing(): + self._disconnect(receiver_id, ANY_ID) + + return cleanup + + def _make_cleanup_sender( + self, sender_id: c.Hashable + ) -> c.Callable[[weakref.ref[t.Any]], None]: + """Create a callback function to disconnect all receivers for a weakly + referenced sender when it is garbage collected. + """ + assert sender_id != ANY_ID + + def cleanup(ref: weakref.ref[t.Any]) -> None: + self._weak_senders.pop(sender_id, None) + + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + return cleanup + + def _cleanup_bookkeeping(self) -> None: + """Prune unused sender/receiver bookkeeping. Not threadsafe. + + Connecting & disconnecting leaves behind a small amount of bookkeeping + data. Typical workloads using Blinker, for example in most web apps, + Flask, CLI scripts, etc., are not adversely affected by this + bookkeeping. + + With a long-running process performing dynamic signal routing with high + volume, e.g. connecting to function closures, senders are all unique + object instances. Doing all of this over and over may cause memory usage + to grow due to extraneous bookkeeping. (An empty ``set`` for each stale + sender/receiver pair.) + + This method will prune that bookkeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that failure + mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for ident, bucket in list(mapping.items()): + if not bucket: + mapping.pop(ident, None) + + def _clear_state(self) -> None: + """Disconnect all receivers and senders. Useful for tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +class NamedSignal(Signal): + """A named generic notification emitter. The name is not used by the signal + itself, but matches the key in the :class:`Namespace` that it belongs to. + + :param name: The name of the signal within the namespace. + :param doc: The docstring for the signal. + """ + + def __init__(self, name: str, doc: str | None = None) -> None: + super().__init__(doc) + + #: The name of this signal. + self.name: str = name + + def __repr__(self) -> str: + base = super().__repr__() + return f"{base[:-1]}; {self.name!r}>" # noqa: E702 + + +class Namespace(dict[str, NamedSignal]): + """A dict mapping names to signals.""" + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` for the given ``name``, creating it + if required. Repeated calls with the same name return the same signal. + + :param name: The name of the signal. + :param doc: The docstring of the signal. + """ + if name not in self: + self[name] = NamedSignal(name, doc) + + return self[name] + + +class _PNamespaceSignal(t.Protocol): + def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... + + +default_namespace: Namespace = Namespace() +"""A default :class:`Namespace` for creating named signals. :func:`signal` +creates a :class:`NamedSignal` in this namespace. +""" + +signal: _PNamespaceSignal = default_namespace.signal +"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given +``name``, creating it if required. Repeated calls with the same name return the +same signal. +""" diff --git a/venv/lib/python3.12/site-packages/blinker/py.typed b/venv/lib/python3.12/site-packages/blinker/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/METADATA new file mode 100644 index 0000000..00bad31 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/METADATA @@ -0,0 +1,84 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.3.2 +Summary: Composable command line interface toolkit +Maintainer-email: Pallets +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: colorama; platform_system == 'Windows' +Project-URL: Changes, https://click.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/click/ + +
+ +# Click + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +## A Simple Example + +```python +import click + +@click.command() +@click.option("--count", default=1, help="Number of greetings.") +@click.option("--name", prompt="Your name", help="The person to greet.") +def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + +if __name__ == '__main__': + hello() +``` + +``` +$ python hello.py --count=3 +Your name: Click +Hello, Click! +Hello, Click! +Hello, Click! +``` + + +## Donate + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/RECORD new file mode 100644 index 0000000..5bd5e90 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/RECORD @@ -0,0 +1,40 @@ +click-8.3.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.3.2.dist-info/METADATA,sha256=yA3Hu5bMxtntTd4QrI8hTFAc58rHSPhDbP6bklbUQkA,2621 +click-8.3.2.dist-info/RECORD,, +click-8.3.2.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.3.2.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 +click/__pycache__/__init__.cpython-312.pyc,, +click/__pycache__/_compat.cpython-312.pyc,, +click/__pycache__/_termui_impl.cpython-312.pyc,, +click/__pycache__/_textwrap.cpython-312.pyc,, +click/__pycache__/_utils.cpython-312.pyc,, +click/__pycache__/_winconsole.cpython-312.pyc,, +click/__pycache__/core.cpython-312.pyc,, +click/__pycache__/decorators.cpython-312.pyc,, +click/__pycache__/exceptions.cpython-312.pyc,, +click/__pycache__/formatting.cpython-312.pyc,, +click/__pycache__/globals.cpython-312.pyc,, +click/__pycache__/parser.cpython-312.pyc,, +click/__pycache__/shell_completion.cpython-312.pyc,, +click/__pycache__/termui.cpython-312.pyc,, +click/__pycache__/testing.cpython-312.pyc,, +click/__pycache__/types.cpython-312.pyc,, +click/__pycache__/utils.cpython-312.pyc,, +click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 +click/_termui_impl.py,sha256=rgCb3On8X5A4200rA5L6i13u5iapmFer7sru57Jy6zA,27093 +click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 +click/_utils.py,sha256=kZwtTf5gMuCilJJceS2iTCvRvCY-0aN5rJq8gKw7p8g,943 +click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 +click/core.py,sha256=7db9qr_wqXbQriDHCDc26OK0MsaLCSt4yrz14Kn7AEQ,132905 +click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 +click/exceptions.py,sha256=8utf8w6V5hJXMnO_ic1FNrtbwuEn1NUu1aDwV8UqnG4,9954 +click/formatting.py,sha256=RVfwwr0rwWNpgGr8NaHodPzkIr7_tUyVh_nDdanLMNc,9730 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=Q31pH0FlQZEq-UXE_ABRzlygEfvxPTuZbWNh4xfXmzw,19010 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=Cc4GQUFuWpfQBa9sF5qXeeYI7n3tI_1k6ZdSn4BZbT0,20994 +click/termui.py,sha256=hqCEjNndU-nzW08nRAkBaVgfZp_FdCA9KxfIWlKYaMc,31037 +click/testing.py,sha256=LjNfHqNctxc3GfRkLgifO6gnRetblh8yGXzjw4FPFCQ,18978 +click/types.py,sha256=ek54BNSFwPKsqtfT7jsqcc4WHui8AIFVMKM4oVZIXhc,39927 +click/utils.py,sha256=gCUoewdAhA-QLBUUHxrLh4uj6m7T1WjZZMNPvR0I7YA,20257 diff --git a/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.3.2.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/click/__init__.py b/venv/lib/python3.12/site-packages/click/__init__.py new file mode 100644 index 0000000..1aa547c --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/__init__.py @@ -0,0 +1,123 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" + +from __future__ import annotations + +from .core import Argument as Argument +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + from .core import _BaseCommand + + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + from .core import _MultiCommand + + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + if name == "OptionParser": + from .parser import _OptionParser + + warnings.warn( + "'OptionParser' is deprecated and will be removed in Click 9.0. The" + " old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return _OptionParser + + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Click 9.1. Use feature detection or" + " 'importlib.metadata.version(\"click\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("click") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3d085a62b6cbe5e6801343f4bafa5d2e52fdd905 GIT binary patch literal 4067 zcmbW4TW=f36~~tn?^j)Xk!@X8l5L8%L`t$HTef`B)mEBFh9x8D^kK2&uB5e=yTt5L ziUcbtiaxYYedt5`5mKZdq(FhfNr0xHLBK%L2fw+n`;w>r&mk!hXj~vA>_2~VX6DSy zndLdFzot@g1)snF<+XL#ttj77qxI=%K;T`lQ&Ik)7>ZDgfYD(G${nI3pctJ-(C#b; zMUXiJ4v7$R7#tR1<_I_p{lhL{Jzs!*AS?BVi=7-3ey zqhgeK*uGr8BCarx*jLM0k!2nQkBKqn%ix^IF<${+6W5rpg0G9~%vtcb7-t>>PlyTT z95^rX%-6sLQDD9fo)nYJ@rZc={8&5&FB^-$4vMwIrQFI< zExu%1r9IX1R9*F~a>X{)Cx`y7>!@YdsG?;#Ud588p%xESf7et!->|Ks>Q?-UETPbZ7YYQ-y(QP#wq%+2pdoS%$Dy63x5Tb#S5ED{6i=<9 zd!A;PC0FXcOU}b56O-Hrr_F6ex$PF8V^oItz?H_Szx2K-JuG=@2`v;|NeAj$)Qwgs zo_YF?30oSr#_?K~BrNU6O!G6d@>$7j9VNDE+2)FrywR>tEYHKE&^{%(?r!3?PQn&v z->n&`#|XfxOA%@WGIk*KiqI(&2oir+#`=P)bkH*8XBoO zEetMhY1)iT0=j(iD!^uhR!O$DB! zC!S&`(4phb4|Sma#f&jZW0)uO3Nv+VA}W;tr3ILzfIk-d@Yv&{uC8$SY5H}Y?2 zaV!=0e7&@1oBO6+OMX(deXBVXeJQQoaI~3iZ~mVf;Y578jassiS&(u({@JIrcEgdC zZEybcHMdasT-#79?4PUUzHZr6Xedlsw^T5J*hq=$`$(=WR!E#M<&w4N zfi4{+YOfYVnK9)GJxD<^)_Rtk&j#wor;Sl^jk?2)5XhfVqvyXDu0>m0s70E4sHGQL zXKp0?a4krANv^{OFUqbPE@LMyy)e2}{`|02*hS?pRQ0K&BEI$~_GTuiqGGS+glG9? zVc&H23y46W!f!7(@>A0V>X@kDxkN4S3ViBZ90@K>4PZ!@{CGPy6Z-(;p=MyJ1z_xqHr- zg{6sy%fXvQ@j0HZ+()&DrWtNY(`s=|+pf}+he%PXmK!8g2qayTq!ceHqstfx{ShV; zkXroY6~>cEvZhGVBpH$}68xp6NXm(_m*flyr9*iRQj43dHw{lx5|n);7f3FWTq5Zw z86X)X8G_W}jY3GTrBWs9Fj*rzwp-L~PmWM4j2Dh_)smysf0^V8$yJgp2@0Abb0pVD zu9J+DOpxRuwUCdJ?a2ZeCP}79rb%v)+$5PHnI*YJa+_q1euoFcKFVTo_y^-qT^X$_S%%@da=oq$a5LBHf^mWwBWIZB7;^8!Q-L8q?|%TAB4`8v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9e8a96fbbbda230f4045edf58fd889727330fdf4 GIT binary patch literal 24189 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 F{}Wb3hZq0= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f53ef1fddbb4ad5ac49e777305b98407c65a55d4 GIT binary patch literal 31611 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d2b4dafcac67193a98e29d608582c11255181c54 GIT binary patch literal 2420 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

3Z6!#$bG<3D}| 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 P#EA!A&-0mTd7}S+(e(FS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a4b4e430436ef61984f55ff67c9604eb8222cedd GIT binary patch literal 22132 zcmdUXeQ+GdmEX+Heqt9`d=Vf4ehf&Ez>>gH{18b&q$mm$MOqTgh&(xh%mS7>18~8` zF5I&q33zFPI=O^Z>?3$*g;Xq+kgK~KS#qwJO6shtToUKvN?j%YECe`Qt*I)wPWj{h zNkN8uc9?(id)+g$vx^1A%gL2wB+m5CbiaQ6`t|$j*Z8lswKWp1|Mu5QiA^UZ>2K(V zb$LWVUb*O&q+60EX>w8;lLus(%C4kqz{Q`+fE!OG=^675c=C3-4?o~Cu`w&ts7`@NqWm@wDiR)X>}jUqCBu3b=;$StuLjg7PjlOty!nuuG0=E zhf1xjlGcFteb%qibJ(>3KL$3h3As^g`f>AzF41COi?&-^_ojP5)t=B=@azak+Ma-9 z{ip5KTHo{xY}H)a`uAk(E$ZykHoWN_*tTXbZF#8WRO@uMt4fb&we6rsw{}e1 z0j`RGf4ZFf!`nQkb%Td?R{hqmMeuExc3j(u_C0v+!m}5nJ%IZ3U(b6=B_&F~wdb|o zH+=(9w2PwM?nzhV#NQI1MdV^ImP(~Fu}mVJGEU!>i**y@S}davUSYBEah;)tZ$!^z z^sAY_rL~M2{$p%pVoXnE=v#k!Y%G@2L@`CxQ1raO(i7vT>izmS0miGqnHYC#wQp9kimG`YUbAC7t=-gOi_NND4&ZKT_^gdS_Y4$Ci`Q_Wb8sxSF>uVKhK5q zL`sXB0*0>|2vA9pBzc9T)mtP?T{F_KtjTYNuE`m@W>(Hg){;LfMU<)YFUQy=Lyf6% zbaWvWzof1nTu)rq)yzd*HPKd0v};sc=?kNJJVT9!6U;!tBv6!p zjdR@08%g^ugkld0@5r|#my~mrP_x$Kh@6%FSpJvZgp`&4ME(Q$EC_#^)uYW_rRWBH zqv*YKg+JwC17ns{b^76}yDz54^xYG&JyRF(xZHc`$zEVIhKhQxk;v$~FYBqxyOW6v zyT>Op7t^VI(LH;2(}&)1j5;==8@uDlMEufjO^>HpER$wNbbPYtPw7_%hbL0;sm

C+K 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 ZdAXLqt&_ZMD`6^raZXt;i@yo;zX6qu9Sr~g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c14b09397a3a537af4a3cc532fa79f0fb328be8 GIT binary patch literal 14771 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 O`JT+7&p4de!v8O`8=SuY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1084364938d84268ac7e298b32ab9ac4de781978 GIT binary patch literal 13667 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 U`>;iSxSg};WB<;L(UOV7H~GQUa{vGU literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9da9fb2eb8af69a5607ca977650dd04624047e99 GIT binary patch literal 20437 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

c-m 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 F{{RC$6!8E6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e896b58b0aa02f26e732a6f48d8b64aaee8f80d5 GIT binary patch literal 50033 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 BBVPaj literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0d44e51702f8d98405062875185be7913bf6ceb5 GIT binary patch literal 24874 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/_compat.py b/venv/lib/python3.12/site-packages/click/_compat.py new file mode 100644 index 0000000..f2726b9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_compat.py @@ -0,0 +1,622 @@ +from __future__ import annotations + +import codecs +import collections.abc as cabc +import io +import os +import re +import sys +import typing as t +from types import TracebackType +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write(b"") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: str | None, errors: str | None +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: str | None, + errors: str | None, + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: str | os.PathLike[str] | int, + mode: str, + encoding: str | None, + errors: str | None, +) -> t.IO[t.Any]: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, +) -> tuple[t.IO[t.Any], bool]: + binary = "b" in mode + filename = os.fspath(filename) + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: int | None = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[t.Any], af), True + + +class _AtomicFile: + def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> _AtomicFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s: str) -> int: + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write # type: ignore[method-assign] + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None + ) -> t.TextIO | None: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO | None], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.TextIO | None]: + cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO | None: + stream = src_func() + + if stream is None: + return None + + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/venv/lib/python3.12/site-packages/click/_termui_impl.py b/venv/lib/python3.12/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..ee8225c --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_termui_impl.py @@ -0,0 +1,852 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" + +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import math +import os +import shlex +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +from pathlib import Path +from types import TracebackType + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: cabc.Iterable[V] | None, + length: int | None = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + label: str | None = None, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.hidden = hidden + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: str = label or "" + + if file is None: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + file = StringIO() + + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width: int = width + self.autowidth: bool = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast("cabc.Iterable[V]", range(length)) + self.iter: cabc.Iterable[V] = iter(iterable) + self.length = length + self.pos: int = 0 + self.avg: list[float] = [] + self.last_eta: float + self.start: float + self.start = self.last_eta = time.time() + self.eta_known: bool = False + self.finished: bool = False + self.max_width: int | None = None + self.entered: bool = False + self.current_item: V | None = None + self._is_atty = isatty(self.file) + self._last_line: str | None = None + + def __enter__(self) -> ProgressBar[V]: + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.render_finish() + + def __iter__(self) -> cabc.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.hidden or not self._is_atty: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + if self.hidden: + return + + if not self._is_atty: + # Only output the label once if the output is not a TTY. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + import shutil + + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width and self.max_width is not None: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: V | None = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> cabc.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if not self._is_atty: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: cabc.Iterable[str], color: bool | None = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if stdout is None: + stdout = StringIO() + + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + + # Split and normalize the pager command into parts. + pager_cmd_parts = shlex.split(os.environ.get("PAGER", ""), posix=False) + if pager_cmd_parts: + if WIN: + if _tempfilepager(generator, pager_cmd_parts, color): + return + elif _pipepager(generator, pager_cmd_parts, color): + return + + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if (WIN or sys.platform.startswith("os2")) and _tempfilepager( + generator, ["more"], color + ): + return + if _pipepager(generator, ["less"], color): + return + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if _pipepager(generator, ["more"], color): + return + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + cmd_params = cmd_parts[1:] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + + # Produces a normalized absolute path string. + # multi-call binaries such as busybox derive their identity from the symlink + # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) + cmd_path = Path(cmd_filepath).absolute() + cmd_name = cmd_path.name + + import subprocess + + # Make a local copy of the environment to not affect the global one. + env = dict(os.environ) + + # If we're piping to less and the user hasn't decided on colors, we enable + # them by default we find the -R flag in the command line arguments. + if color is None and cmd_name == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_params)}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen( + [str(cmd_path)] + cmd_params, + shell=False, + stdin=subprocess.PIPE, + env=env, + errors="replace", + text=True, + ) + assert c.stdin is not None + try: + for text in generator: + if not color: + text = strip_ansi(text) + + c.stdin.write(text) + except BrokenPipeError: + # In case the pager exited unexpectedly, ignore the broken pipe error. + pass + except Exception as e: + # In case there is an exception we want to close the pager immediately + # and let the caller handle it. + # Otherwise the pager will keep running, and the user may not notice + # the error message, or worse yet it may leave the terminal in a broken state. + c.terminate() + raise e + finally: + # We must close stdin and wait for the pager to exit before we continue + try: + c.stdin.close() + # Close implies flush, so it might throw a BrokenPipeError if the pager + # process exited already. + except BrokenPipeError: + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + return True + + +def _tempfilepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by invoking a program on a temporary file. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + + import shutil + + cmd = cmd_parts[0] + + cmd_filepath = shutil.which(cmd) + if not cmd_filepath: + return False + # Produces a normalized absolute path string. + # multi-call binaries such as busybox derive their identity from the symlink + # less -> busybox. resolve() causes them to misbehave. (eg. less becomes busybox) + cmd_path = Path(cmd_filepath).absolute() + + import subprocess + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + subprocess.call([str(cmd_path), filename]) + except OSError: + # Command not found + pass + finally: + os.close(fd) + os.unlink(filename) + + return True + + +def _nullpager( + stream: t.TextIO, generator: cabc.Iterable[str], color: bool | None +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + + from shutil import which + + for editor in "sensible-editor", "vim", "nano": + if which(editor) is not None: + return editor + return "vi" + + def edit_files(self, filenames: cabc.Iterable[str]) -> None: + import subprocess + + editor = self.get_editor() + environ: dict[str, str] | None = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + exc_filename = " ".join(f'"{filename}"' for filename in filenames) + + try: + c = subprocess.Popen( + args=f"{editor} {exc_filename}", env=environ, shell=True + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + @t.overload + def edit(self, text: bytes | bytearray) -> bytes | None: ... + + # We cannot know whether or not the type expected is str or bytes when None + # is passed, so str is returned as that was what was done before. + @t.overload + def edit(self, text: str | None) -> str | None: ... + + def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: + import tempfile + + if text is None: + data: bytes | bytearray = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_files((name,)) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = ["explorer", f"/select,{url}"] + else: + args = ["start"] + if wait: + args.append("/WAIT") + args.append("") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> None: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if sys.platform == "win32": + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + + if echo: + func = t.cast(t.Callable[[], str], msvcrt.getwche) + else: + func = t.cast(t.Callable[[], str], msvcrt.getwch) + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import termios + import tty + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + f: t.TextIO | None + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/venv/lib/python3.12/site-packages/click/_textwrap.py b/venv/lib/python3.12/site-packages/click/_textwrap.py new file mode 100644 index 0000000..97fbee3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_textwrap.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import collections.abc as cabc +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: list[str], + cur_line: list[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> cabc.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/venv/lib/python3.12/site-packages/click/_utils.py b/venv/lib/python3.12/site-packages/click/_utils.py new file mode 100644 index 0000000..09fb008 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_utils.py @@ -0,0 +1,36 @@ +from __future__ import annotations + +import enum +import typing as t + + +class Sentinel(enum.Enum): + """Enum used to define sentinel values. + + .. seealso:: + + `PEP 661 - Sentinel Values `_. + """ + + UNSET = object() + FLAG_NEEDS_VALUE = object() + + def __repr__(self) -> str: + return f"{self.__class__.__name__}.{self.name}" + + +UNSET = Sentinel.UNSET +"""Sentinel used to indicate that a value is not set.""" + +FLAG_NEEDS_VALUE = Sentinel.FLAG_NEEDS_VALUE +"""Sentinel used to indicate an option was passed as a flag without a +value but is not a flag option. + +``Option.consume_value`` uses this to prompt or use the ``flag_value``. +""" + +T_UNSET = t.Literal[UNSET] # type: ignore[valid-type] +"""Type hint for the :data:`UNSET` sentinel value.""" + +T_FLAG_NEEDS_VALUE = t.Literal[FLAG_NEEDS_VALUE] # type: ignore[valid-type] +"""Type hint for the :data:`FLAG_NEEDS_VALUE` sentinel value.""" diff --git a/venv/lib/python3.12/site-packages/click/_winconsole.py b/venv/lib/python3.12/site-packages/click/_winconsole.py new file mode 100644 index 0000000..e56c7c6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_winconsole.py @@ -0,0 +1,296 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +from __future__ import annotations + +import collections.abc as cabc +import io +import sys +import time +import typing as t +from ctypes import Array +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +if t.TYPE_CHECKING: + try: + # Using `typing_extensions.Buffer` instead of `collections.abc` + # on Windows for some reason does not have `Sized` implemented. + from collections.abc import Buffer # type: ignore + except ImportError: + from typing_extensions import Buffer + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ # noqa: RUF012 + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: + buf = Py_buffer() + flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + out: Array[c_char] = buffer_type.from_address(buf.buf) + return out + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle: int | None) -> None: + self.handle = handle + + def isatty(self) -> t.Literal[True]: + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self) -> t.Literal[True]: + return True + + def readinto(self, b: Buffer) -> int: + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self) -> t.Literal[True]: + return True + + @staticmethod + def _get_error_message(errno: int) -> str: + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b: Buffer) -> int: + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self) -> str: + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None +) -> t.TextIO | None: + if ( + get_buffer is None + or encoding not in {"utf-16-le", None} + or errors not in {"strict", None} + or not _is_console(f) + ): + return None + + func = _stream_factories.get(f.fileno()) + if func is None: + return None + + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/venv/lib/python3.12/site-packages/click/core.py b/venv/lib/python3.12/site-packages/click/core.py new file mode 100644 index 0000000..f0a624b --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/core.py @@ -0,0 +1,3437 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from collections import Counter +from contextlib import AbstractContextManager +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import NoArgsIsHelpError +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _OptionParser +from .parser import _split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound="t.Callable[..., t.Any]") +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: Context, incomplete: str +) -> cabc.Iterator[tuple[str, Command]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(Group, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_nested_chain( + base_command: Group, cmd_name: str, cmd: Command, register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, Group): + return + + if register: + message = ( + f"It is not possible to add the group {cmd_name!r} to another" + f" group {base_command.name!r} that is in chain mode." + ) + else: + message = ( + f"Found the group {cmd_name!r} as subcommand to another group " + f" {base_command.name!r} that is in chain mode. This is not supported." + ) + + raise RuntimeError(message) + + +def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size), strict=False)) + + +@contextmanager +def augment_usage_errors( + ctx: Context, param: Parameter | None = None +) -> cabc.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: cabc.Sequence[Parameter], + declaration_order: cabc.Sequence[Parameter], +) -> list[Parameter]: + """Returns all declared parameters in the order they should be processed. + + The declared parameters are re-shuffled depending on the order in which + they were invoked, as well as the eagerness of each parameters. + + The invocation order takes precedence over the declaration order. I.e. the + order in which the user provided them to the CLI is respected. + + This behavior and its effect on callback evaluation is detailed at: + https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order + """ + + def sort_key(item: Parameter) -> tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.2 + The ``protected_args`` attribute is deprecated and will be removed in + Click 9.0. ``args`` will contain remaining unparsed tokens. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: type[HelpFormatter] = HelpFormatter + + def __init__( + self, + command: Command, + parent: Context | None = None, + info_name: str | None = None, + obj: t.Any | None = None, + auto_envvar_prefix: str | None = None, + default_map: cabc.MutableMapping[str, t.Any] | None = None, + terminal_width: int | None = None, + max_content_width: int | None = None, + resilient_parsing: bool = False, + allow_extra_args: bool | None = None, + allow_interspersed_args: bool | None = None, + ignore_unknown_options: bool | None = None, + help_option_names: list[str] | None = None, + token_normalize_func: t.Callable[[str], str] | None = None, + color: bool | None = None, + show_default: bool | None = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: dict[str, t.Any] = {} + #: the leftover arguments. + self.args: list[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self._protected_args: list[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: str | None = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: int | None = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: int | None = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: list[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: str | None = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: bool | None = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: bool | None = show_default + + self._close_callbacks: list[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + @property + def protected_args(self) -> list[str]: + import warnings + + warnings.warn( + "'protected_args' is deprecated and will be removed in Click 9.0." + " 'args' will contain remaining unparsed tokens.", + DeprecationWarning, + stacklevel=2, + ) + return self._protected_args + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> Context: + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + self._depth -= 1 + exit_result: bool | None = None + if self._depth == 0: + exit_result = self._close_with_exception_info(exc_type, exc_value, tb) + pop_context() + + return exit_result + + @contextmanager + def scope(self, cleanup: bool = True) -> cabc.Iterator[Context]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: AbstractContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._close_with_exception_info(None, None, None) + + def _close_with_exception_info( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> bool | None: + """Unwind the exit stack by calling its :meth:`__exit__` providing the exception + information to allow for exception handling by the various resources registered + using :meth;`with_resource` + + :return: Whatever ``exit_stack.__exit__()`` returns. + """ + exit_result = self._exit_stack.__exit__(exc_type, exc_value, tb) + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + return exit_result + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> Context: + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: type[V]) -> V | None: + """Finds the closest object of a given type.""" + node: Context | None = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[False] = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def lookup_default(self, name: str, call: bool = True) -> t.Any | None: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> t.NoReturn: + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> t.NoReturn: + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> t.NoReturn: + """Exits the application with a given exit code. + + .. versionchanged:: 8.2 + Callbacks and context managers registered with :meth:`call_on_close` + and :meth:`with_resource` are closed before exiting. + """ + self.close() + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: Command) -> Context: + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + @t.overload + def invoke( + self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> V: ... + + @t.overload + def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... + + def invoke( + self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> t.Any | V: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + + .. versionchanged:: 3.2 + A new context is created, and missing arguments use default values. + """ + if isinstance(callback, Command): + other_cmd = callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + callback = t.cast("t.Callable[..., V]", other_cmd.callback) + + ctx = self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + default_value = param.get_default(ctx) + # We explicitly hide the :attr:`UNSET` value to the user, as we + # choose to make it an implementation detail. And because ``invoke`` + # has been designed as part of Click public API, we return ``None`` + # instead. Refs: + # https://github.com/pallets/click/issues/3066 + # https://github.com/pallets/click/issues/3065 + # https://github.com/pallets/click/pull/3068 + if default_value is UNSET: + default_value = None + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, default_value + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = self + + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(cmd, Command): + raise TypeError("Callback is not a command.") + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> ParameterSource | None: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class Command: + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the command is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. + + .. versionchanged:: 8.2 + This is the base class for all commands, not ``BaseCommand``. + ``deprecated`` can be set to a string as well to customize the + deprecation message. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: type[Context] = Context + + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: str | None, + context_settings: cabc.MutableMapping[str, t.Any] | None = None, + callback: t.Callable[..., t.Any] | None = None, + params: list[Parameter] | None = None, + help: str | None = None, + epilog: str | None = None, + short_help: str | None = None, + options_metavar: str | None = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool | str = False, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: cabc.MutableMapping[str, t.Any] = context_settings + + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: list[Parameter] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self._help_option = None + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + return { + "name": self.name, + "params": [param.to_info_dict() for param in self.get_params(ctx)], + "help": self.help, + "epilog": self.epilog, + "short_help": self.short_help, + "hidden": self.hidden, + "deprecated": self.deprecated, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> list[Parameter]: + params = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + params = [*params, help_option] + + if __debug__: + import warnings + + opts = [opt for param in params for opt in param.opts] + opts_counter = Counter(opts) + duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) + + for duplicate_opt in duplicate_opts: + warnings.warn( + ( + f"The parameter {duplicate_opt} is used more than once. " + "Remove its duplicate as parameters should be unique." + ), + stacklevel=3, + ) + + return params + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> list[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> Option | None: + """Returns the help option object. + + Skipped if :attr:`add_help_option` is ``False``. + + .. versionchanged:: 8.1.8 + The help option is now cached to avoid creating it multiple times. + """ + help_option_names = self.get_help_option_names(ctx) + + if not help_option_names or not self.add_help_option: + return None + + # Cache the help option object in private _help_option attribute to + # avoid creating it multiple times. Not doing this will break the + # callback odering by iter_params_for_processing(), which relies on + # object comparison. + if self._help_option is None: + # Avoid circular import. + from .decorators import help_option + + # Apply help_option decorator and pop resulting option + help_option(*help_option_names)(self) + self._help_option = self.params.pop() # type: ignore[assignment] + + return self._help_option + + def make_parser(self, ctx: Context) -> _OptionParser: + """Creates the underlying option parser for this command.""" + parser = _OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: Context | None = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + _, args = param.handle_parse_result(ctx, opts, args) + + # We now have all parameters' values into `ctx.params`, but the data may contain + # the `UNSET` sentinel. + # Convert `UNSET` to `None` to ensure that the user doesn't see `UNSET`. + # + # Waiting until after the initial parse to convert allows us to treat `UNSET` + # more like a missing value when multiple params use the same name. + # Refs: + # https://github.com/pallets/click/issues/3071 + # https://github.com/pallets/click/pull/3079 + for name, value in ctx.params.items(): + if value is UNSET: + ctx.params[name] = None + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" + ).format(name=self.name, extra_message=extra_message) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: list[CompletionItem] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, Group) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx._protected_args + ) + + return results + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: t.Literal[True] = True, + **extra: t.Any, + ) -> t.NoReturn: ... + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: ... + + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) as e: + echo(file=sys.stderr) + raise Abort() from e + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str | None = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. versionchanged:: 8.2.0 + Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). + """ + if complete_var is None: + complete_name = prog_name.replace("-", "_").replace(".", "_") + complete_var = f"_{complete_name}_COMPLETE".upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: type) -> bool: + return issubclass(subclass, cls.__bases__[0]) + + def __instancecheck__(cls, instance: t.Any) -> bool: + return isinstance(instance, cls.__bases__[0]) + + +class _BaseCommand(Command, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Command`` instead. + """ + + +class Group(Command): + """A group is a command that nests other commands (or more groups). + + :param name: The name of the group command. + :param commands: Map names to :class:`Command` objects. Can be a list, which + will use :attr:`Command.name` as the keys. + :param invoke_without_command: Invoke the group's callback even if a + subcommand is not given. + :param no_args_is_help: If no arguments are given, show the group's help and + exit. Defaults to the opposite of ``invoke_without_command``. + :param subcommand_metavar: How to represent the subcommand argument in help. + The default will represent whether ``chain`` is set or not. + :param chain: Allow passing more than one subcommand argument. After parsing + a command's arguments, if any arguments remain another command will be + matched, and so on. + :param result_callback: A function to call after the group's and + subcommand's callbacks. The value returned by the subcommand is passed. + If ``chain`` is enabled, the value will be a list of values returned by + all the commands. If ``invoke_without_command`` is enabled, the value + will be the value returned by the group's callback, or an empty list if + ``chain`` is enabled. + :param kwargs: Other arguments passed to :class:`Command`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + + .. versionchanged:: 8.2 + Merged with and replaces the ``MultiCommand`` base class. + """ + + allow_extra_args = True + allow_interspersed_args = False + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: type[Command] | None = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: type[Group] | type[type] | None = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: str | None = None, + commands: cabc.MutableMapping[str, Command] + | cabc.Sequence[Command] + | None = None, + invoke_without_command: bool = False, + no_args_is_help: bool | None = None, + subcommand_metavar: str | None = None, + chain: bool = False, + result_callback: t.Callable[..., t.Any] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: cabc.MutableMapping[str, Command] = commands + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "A group in chain mode cannot have optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def add_command(self, cmd: Command, name: str | None = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_nested_chain(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'command(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> Group: ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'group(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> Group: + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + inner = old_callback(value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv # type: ignore[return-value] + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Given a context and a command name, this returns a :class:`Command` + object if it exists or returns ``None``. + """ + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> list[str]: + """Returns a list of subcommand names in the order they should appear.""" + return sorted(self.commands) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx._protected_args = rest + ctx.args = [] + elif rest: + ctx._protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx._protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx._protected_args, *ctx.args] + ctx.args = [] + ctx._protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if _split_opt(cmd_name)[0]: + self.parse_args(ctx, args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class _MultiCommand(Group, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Group`` instead. + """ + + +class CommandCollection(Group): + """A :class:`Group` that looks up subcommands on other groups. If a command + is not found on this group, each registered source is checked in order. + Parameters on a source are not added to this group, and a source's callback + is not invoked when invoking its commands. In other words, this "flattens" + commands in many groups into this one group. + + :param name: The name of the group command. + :param sources: A list of :class:`Group` objects to look up commands from. + :param kwargs: Other arguments passed to :class:`Group`. + + .. versionchanged:: 8.2 + This is a subclass of ``Group``. Commands are looked up first on this + group, then each of its sources. + """ + + def __init__( + self, + name: str | None = None, + sources: list[Group] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + #: The list of registered groups. + self.sources: list[Group] = sources or [] + + def add_source(self, group: Group) -> None: + """Add a group as a source of commands.""" + self.sources.append(group) + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + rv = super().get_command(ctx, cmd_name) + + if rv is not None: + return rv + + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_nested_chain(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> list[str]: + rv: set[str] = set(super().list_commands(ctx)) + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The latter is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: environment variable(s) that are used to provide a default value for + this parameter. This can be a string or a sequence of strings. If a sequence is + given, only the first non-empty environment variable is used for the parameter. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the argument is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. A deprecated parameter + cannot be required, a ValueError will be raised otherwise. + + .. versionchanged:: 8.2.0 + Introduction of ``deprecated``. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + type: types.ParamType | t.Any | None = None, + required: bool = False, + # XXX The default historically embed two concepts: + # - the declaration of a Parameter object carrying the default (handy to + # arbitrage the default value of coupled Parameters sharing the same + # self.name, like flag options), + # - and the actual value of the default. + # It is confusing and is the source of many issues discussed in: + # https://github.com/pallets/click/pull/3030 + # In the future, we might think of splitting it in two, not unlike + # Option.is_flag and Option.flag_value: we could have something like + # Parameter.is_default and Parameter.default_value. + default: t.Any | t.Callable[[], t.Any] | None = UNSET, + callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, + nargs: int | None = None, + multiple: bool = False, + metavar: str | None = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: str | cabc.Sequence[str] | None = None, + shell_complete: t.Callable[ + [Context, Parameter, str], list[CompletionItem] | list[str] + ] + | None = None, + deprecated: bool | str = False, + ) -> None: + self.name: str | None + self.opts: list[str] + self.secondary_opts: list[str] + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type: types.ParamType = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default: t.Any | t.Callable[[], t.Any] | None = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + self.deprecated = deprecated + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + if required and deprecated: + raise ValueError( + f"The {self.param_type_name} '{self.human_readable_name}' " + "is deprecated and still required. A deprecated " + f"{self.param_type_name} cannot be required." + ) + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`default` if it was not set. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + # We explicitly hide the :attr:`UNSET` value to the user, as we choose to + # make it an implementation detail. And because ``to_info_dict`` has been + # designed for documentation purposes, we return ``None`` instead. + "default": self.default if self.default is not UNSET else None, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(param=self, ctx=ctx) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + name = self.name + value = ctx.lookup_default(name, call=False) if name is not None else None + + if value is None and not ( + ctx.default_map is not None and name is not None and name in ctx.default_map + ): + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, t.Any] + ) -> tuple[t.Any, ParameterSource]: + """Returns the parameter value produced by the parser. + + If the parser did not produce a value from user input, the value is either + sourced from the environment variable, the default map, or the parameter's + default value. In that order of precedence. + + If no value is found, an internal sentinel value is returned. + + :meta private: + """ + # Collect from the parse the value passed by the user to the CLI. + value = opts.get(self.name, UNSET) # type: ignore + # If the value is set, it means it was sourced from the command line by the + # parser, otherwise it left unset by default. + source = ( + ParameterSource.COMMANDLINE + if value is not UNSET + else ParameterSource.DEFAULT + ) + + if value is UNSET: + envvar_value = self.value_from_envvar(ctx) + if envvar_value is not None: + value = envvar_value + source = ParameterSource.ENVIRONMENT + + if value is UNSET: + default_map_value = ctx.lookup_default(self.name) # type: ignore[arg-type] + if default_map_value is not None or ( + ctx.default_map is not None and self.name in ctx.default_map + ): + value = default_map_value + source = ParameterSource.DEFAULT_MAP + + if value is UNSET: + default_value = self.get_default(ctx) + if default_value is not UNSET: + value = default_value + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the parameter's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + if self.multiple or self.nargs == -1: + return () + else: + return value + + def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + # Define the conversion function based on nargs and type. + + if self.nargs == 1 or self.type.is_composite: + + def convert(value: t.Any) -> t.Any: + return self.type(value, param=self, ctx=ctx) + + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + """A value is considered missing if: + + - it is :attr:`UNSET`, + - or if it is an empty sequence while the parameter is suppose to have + non-single value (i.e. :attr:`nargs` is not ``1`` or :attr:`multiple` is + set). + + :meta private: + """ + if value is UNSET: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + """Process the value of this parameter: + + 1. Type cast the value using :meth:`type_cast_value`. + 2. Check if the value is missing (see: :meth:`value_is_missing`), and raise + :exc:`MissingParameter` if it is required. + 3. If a :attr:`callback` is set, call it to have the value replaced by the + result of the callback. If the value was not set, the callback receive + ``None``. This keep the legacy behavior as it was before the introduction of + the :attr:`UNSET` sentinel. + + :meta private: + """ + # shelter `type_cast_value` from ever seeing an `UNSET` value by handling the + # cases in which `UNSET` gets special treatment explicitly at this layer + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if value is UNSET: + if self.multiple or self.nargs == -1: + value = () + else: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + # Legacy case: UNSET is not exposed directly to the callback, but converted + # to None. + if value is UNSET: + value = None + + # Search for parameters with UNSET values in the context. + unset_keys = {k: None for k, v in ctx.params.items() if v is UNSET} + # No UNSET values, call the callback as usual. + if not unset_keys: + value = self.callback(ctx, self, value) + + # Legacy case: provide a temporarily manipulated context to the callback + # to hide UNSET values as None. + # + # Refs: + # https://github.com/pallets/click/issues/3136 + # https://github.com/pallets/click/pull/3137 + else: + # Add another layer to the context stack to clearly hint that the + # context is temporarily modified. + with ctx: + # Update the context parameters to replace UNSET with None. + ctx.params.update(unset_keys) + # Feed these fake context parameters to the callback. + value = self.callback(ctx, self, value) + # Restore the UNSET values in the context parameters. + ctx.params.update( + { + k: UNSET + for k in unset_keys + # Only restore keys that are present and still None, in case + # the callback modified other parameters. + if k in ctx.params and ctx.params[k] is None + } + ) + + return value + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """Returns the value found in the environment variable(s) attached to this + parameter. + + Environment variables values are `always returned as strings + `_. + + This method returns ``None`` if: + + - the :attr:`envvar` property is not set on the :class:`Parameter`, + - the environment variable is not found in the environment, + - the variable is found in the environment but its value is empty (i.e. the + environment variable is present but has an empty string). + + If :attr:`envvar` is setup with multiple environment variables, + then only the first non-empty value is returned. + + .. caution:: + + The raw value extracted from the environment is not normalized and is + returned as-is. Any normalization or reconciliation is performed later by + the :class:`Parameter`'s :attr:`type`. + + :meta private: + """ + if not self.envvar: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + # Return the first non-empty value of the list of environment variables. + if rv: + return rv + # Else, absence of value is interpreted as an environment variable that + # is not set, so proceed to the next one. + + return None + + def value_from_envvar(self, ctx: Context) -> str | cabc.Sequence[str] | None: + """Process the raw environment variable string for this parameter. + + Returns the string as-is or splits it into a sequence of strings if the + parameter is expecting multiple values (i.e. its :attr:`nargs` property is set + to a value other than ``1``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + return self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] + ) -> tuple[t.Any, list[str]]: + """Process the value produced by the parser from user input. + + Always process the value through the Parameter's :attr:`type`, wherever it + comes from. + + If the parameter is deprecated, this method warn the user about it. But only if + the value has been explicitly set by the user (and as such, is not coming from + a default). + + :meta private: + """ + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + ctx.set_parameter_source(self.name, source) # type: ignore + + # Display a deprecation warning if necessary. + if ( + self.deprecated + and value is not UNSET + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ): + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The {param_type} {name!r} is deprecated." + "{extra_message}" + ).format( + param_type=self.param_type_name, + name=self.human_readable_name, + extra_message=extra_message, + ) + echo(style(message, fg="red"), err=True) + + # Process the value through the parameter's type. + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + # In resilient parsing mode, we do not want to fail the command if the + # value is incompatible with the parameter type, so we reset the value + # to UNSET, which will be interpreted as a missing value. + value = UNSET + + # Add parameter's value to the context. + if ( + self.expose_value + # We skip adding the value if it was previously set by another parameter + # targeting the same variable name. This prevents parameters competing for + # the same name to override each other. + and (self.name not in ctx.params or ctx.params[self.name] is UNSET) + ): + # Click is logically enforcing that the name is None if the parameter is + # not to be exposed. We still assert it here to please the type checker. + assert self.name is not None, ( + f"{self!r} parameter's name should not be None when exposing value." + ) + ctx.params[self.name] = value + + return value, args + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + pass + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast("list[CompletionItem]", results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page and error messages. + Normally, environment variables are not shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. A deprecated option cannot be + prompted. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.2 + ``envvar`` used with ``flag_value`` will always use the ``flag_value``, + previously it would use the value of the environment variable. + + .. versionchanged:: 8.1 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + show_default: bool | str | None = None, + prompt: bool | str = False, + confirmation_prompt: bool | str = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: bool | None = None, + flag_value: t.Any = UNSET, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: types.ParamType | t.Any | None = None, + help: str | None = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + deprecated: bool | str = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + super().__init__( + param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs + ) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: str | None = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + if deprecated: + deprecated_message = ( + f"(DEPRECATED: {deprecated})" + if isinstance(deprecated, str) + else "(DEPRECATED)" + ) + help = help + deprecated_message if help is not None else deprecated_message + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # The _flag_needs_value property tells the parser that this option is a flag + # that cannot be used standalone and needs a value. With this information, the + # parser can determine whether to consider the next user-provided argument in + # the CLI as a value for this flag or as a new option. + # If prompt is enabled but not required, then it opens the possibility for the + # option to gets its value from the user. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + # Auto-detect if this is a flag or not. + if is_flag is None: + # Implicitly a flag because flag_value was set. + if flag_value is not UNSET: + is_flag = True + # Not a flag, but when used as a flag it shows a prompt. + elif self._flag_needs_value: + is_flag = False + # Implicitly a flag because secondary options names were given. + elif self.secondary_opts: + is_flag = True + + # The option is explicitly not a flag, but to determine whether or not it needs + # value, we need to check if `flag_value` or `default` was set. Either one is + # sufficient. + # Ref: https://github.com/pallets/click/issues/3084 + elif is_flag is False and not self._flag_needs_value: + self._flag_needs_value = flag_value is not UNSET or self.default is UNSET + + if is_flag: + # Set missing default for flags if not explicitly required or prompted. + if self.default is UNSET and not self.required and not self.prompt: + if multiple: + self.default = () + + # Auto-detect the type of the flag based on the flag_value. + if type is None: + # A flag without a flag_value is a boolean flag. + if flag_value is UNSET: + self.type: types.ParamType = types.BoolParamType() + # If the flag value is a boolean, use BoolParamType. + elif isinstance(flag_value, bool): + self.type = types.BoolParamType() + # Otherwise, guess the type from the flag value. + else: + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = bool(is_flag) + self.is_bool_flag: bool = bool( + is_flag and isinstance(self.type, types.BoolParamType) + ) + self.flag_value: t.Any = flag_value + + # Set boolean flag default to False if unset and not required. + if self.is_bool_flag: + if self.default is UNSET and not self.required: + self.default = False + + # The alignement of default to the flag_value is resolved lazily in + # get_default() to prevent callable flag_values (like classes) from + # being instantiated. Refs: + # https://github.com/pallets/click/issues/3121 + # https://github.com/pallets/click/issues/3024#issuecomment-3146199461 + # https://github.com/pallets/click/pull/3030/commits/06847da + + # Set the default flag_value if it is not set. + if self.flag_value is UNSET: + if self.is_flag: + self.flag_value = True + else: + self.flag_value = None + + # Counting. + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if self.default is UNSET: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if deprecated and prompt: + raise ValueError("`deprecated` options cannot use `prompt`.") + + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + def to_info_dict(self) -> dict[str, t.Any]: + """ + .. versionchanged:: 8.3.0 + Returns ``None`` for the :attr:`flag_value` if it was not set. + """ + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + # We explicitly hide the :attr:`UNSET` value to the user, as we choose to + # make it an implementation detail. And because ``to_info_dict`` has been + # designed for documentation purposes, we return ``None`` instead. + flag_value=self.flag_value if self.flag_value is not UNSET else None, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + value = super().get_default(ctx, call=False) + + # Lazily resolve default=True to flag_value. Doing this here + # (instead of eagerly in __init__) prevents callable flag_values + # (like classes) from being instantiated by the callable check below. + # https://github.com/pallets/click/issues/3121 + if value is True and self.is_flag: + value = self.flag_value + elif call and callable(value): + value = value() + + return value + + def get_error_hint(self, ctx: Context) -> str: + result = super().get_error_hint(ctx) + if self.show_envvar and self.envvar is not None: + result += f" (env var: '{self.envvar}')" + return result + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(_split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(_split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError( + f"Could not determine name for option with declarations {decls!r}" + ) + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: cabc.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar(ctx=ctx)}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + + extra = self.get_help_extra(ctx) + extra_items = [] + if "envvars" in extra: + extra_items.append( + _("env var: {var}").format(var=", ".join(extra["envvars"])) + ) + if "default" in extra: + extra_items.append(_("default: {default}").format(default=extra["default"])) + if "range" in extra: + extra_items.append(extra["range"]) + if "required" in extra: + extra_items.append(_(extra["required"])) + + if extra_items: + extra_str = "; ".join(extra_items) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: + extra: types.OptionHelpExtra = {} + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + if isinstance(envvar, str): + extra["envvars"] = (envvar,) + else: + extra["envvars"] = tuple(str(d) for d in envvar) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or ( + show_default and (default_value not in (None, UNSET)) + ): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif isinstance(default_value, enum.Enum): + default_string = default_value.name + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = _split_opt( + (self.opts if default_value else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + elif default_value == "": + default_string = '""' + else: + default_string = str(default_value) + + if default_string: + extra["default"] = default_string + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra["range"] = range_str + + if self.required: + extra["required"] = "required" + + return extra + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to lock in the value before + # attempting any user interaction. + default = self.get_default(ctx) + + # A boolean flag can use a simplified [y/n] confirmation prompt. + if self.is_bool_flag: + # If we have no boolean default, we force the user to explicitly provide + # one. + if default in (UNSET, None): + default = None + # Nothing prevent you to declare an option that is simultaneously: + # 1) auto-detected as a boolean flag, + # 2) allowed to prompt, and + # 3) still declare a non-boolean default. + # This forced casting into a boolean is necessary to align any non-boolean + # default to the prompt, which is going to be a [y/n]-style confirmation + # because the option is still a boolean flag. That way, instead of [y/n], + # we get [Y/n] or [y/N] depending on the truthy value of the default. + # Refs: https://github.com/pallets/click/pull/3030#discussion_r2289180249 + else: + default = bool(default) + return confirm(self.prompt, default) + + # If show_default is set to True/False, provide this to `prompt` as well. For + # non-bool values of `show_default`, we use `prompt`'s default behavior + prompt_kwargs: t.Any = {} + if isinstance(self.show_default, bool): + prompt_kwargs["show_default"] = self.show_default + + return prompt( + self.prompt, + # Use ``None`` to inform the prompt() function to reiterate until a valid + # value is provided by the user if we have no default. + default=None if default is UNSET else default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + **prompt_kwargs, + ) + + def resolve_envvar_value(self, ctx: Context) -> str | None: + """:class:`Option` resolves its environment variable the same way as + :func:`Parameter.resolve_envvar_value`, but it also supports + :attr:`Context.auto_envvar_prefix`. If we could not find an environment from + the :attr:`envvar` property, we fallback on :attr:`Context.auto_envvar_prefix` + to build dynamiccaly the environment variable name using the + :python:`{ctx.auto_envvar_prefix}_{self.name.upper()}` template. + + :meta private: + """ + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any: + """For :class:`Option`, this method processes the raw environment variable + string the same way as :func:`Parameter.value_from_envvar` does. + + But in the case of non-boolean flags, the value is analyzed to determine if the + flag is activated or not, and returns a boolean of its activation, or the + :attr:`flag_value` if the latter is set. + + This method also takes care of repeated options (i.e. options with + :attr:`multiple` set to ``True``). + + :meta private: + """ + rv = self.resolve_envvar_value(ctx) + + # Absent environment variable or an empty string is interpreted as unset. + if rv is None: + return None + + # Non-boolean flags are more liberal in what they accept. But a flag being a + # flag, its envvar value still needs to be analyzed to determine if the flag is + # activated or not. + if self.is_flag and not self.is_bool_flag: + # If the flag_value is set and match the envvar value, return it + # directly. + if self.flag_value is not UNSET and rv == self.flag_value: + return self.flag_value + # Analyze the envvar value as a boolean to know if the flag is + # activated or not. + return types.BoolParamType.str_to_bool(rv) + + # Split the envvar value if it is allowed to be repeated. + value_depth = (self.nargs != 1) + bool(self.multiple) + if value_depth > 0: + multi_rv = self.type.split_envvar_value(rv) + if self.multiple and self.nargs != 1: + multi_rv = batch(multi_rv, self.nargs) # type: ignore[assignment] + + return multi_rv + + return rv + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, Parameter] + ) -> tuple[t.Any, ParameterSource]: + """For :class:`Option`, the value can be collected from an interactive prompt + if the option is a flag that needs a value (and the :attr:`prompt` property is + set). + + Additionally, this method handles flag option that are activated without a + value, in which case the :attr:`flag_value` is returned. + + :meta private: + """ + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option is allowed to as a flag + # without a value. + if value is FLAG_NEEDS_VALUE: + # If the option allows for a prompt, we start an interaction with the user. + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + # Else the flag takes its flag_value as value. + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + # A flag which is activated always returns the flag value, unless the value + # comes from the explicitly sets default. + elif ( + self.is_flag + and value is True + and not self.is_bool_flag + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ): + value = self.flag_value + + # Re-interpret a multiple option which has been sent as-is by the parser. + # Here we replace each occurrence of value-less flags (marked by the + # FLAG_NEEDS_VALUE sentinel) with the flag_value. + elif ( + self.multiple + and value is not UNSET + and source not in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + and any(v is FLAG_NEEDS_VALUE for v in value) + ): + value = [self.flag_value if v is FLAG_NEEDS_VALUE else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt for one to the user + # if prompting is enabled. + elif ( + ( + value is UNSET + or source in (ParameterSource.DEFAULT, ParameterSource.DEFAULT_MAP) + ) + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + # process_value has to be overridden on Options in order to capture + # `value == UNSET` cases before `type_cast_value()` gets called. + # + # Refs: + # https://github.com/pallets/click/issues/3069 + if self.is_flag and not self.required and self.is_bool_flag and value is UNSET: + value = False + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + # in the normal case, rely on Parameter.process_value + return super().process_value(ctx, value) + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the constructor of :class:`Parameter`. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: cabc.Sequence[str], + required: bool | None = None, + **attrs: t.Any, + ) -> None: + # Auto-detect the requirement status of the argument if not explicitly set. + if required is None: + # The argument gets automatically required if it has no explicit default + # value set and is setup to match at least one value. + if attrs.get("default", UNSET) is UNSET: + required = attrs.get("nargs", 1) > 0 + # If the argument has a default value, it is not required. + else: + required = False + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(param=self, ctx=ctx) + if not var: + var = self.name.upper() # type: ignore + if self.deprecated: + var += "!" + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Argument is marked as exposed, but does not have a name.") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}: {decls}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [self.make_metavar(ctx)] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar(ctx)}'" + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/decorators.py b/venv/lib/python3.12/site-packages/click/decorators.py new file mode 100644 index 0000000..21f4c34 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/decorators.py @@ -0,0 +1,551 @@ +from __future__ import annotations + +import inspect +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") +T = t.TypeVar("T") +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound="_AnyCallable | Command") + + +def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator( + object_type: type[T], ensure: bool = False +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + + obj: T | None + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: str | None = None +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +# variant: no call, directly as decorator for a function. +@t.overload +def command(name: _AnyCallable) -> Command: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) +@t.overload +def command( + name: str | None, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) +@t.overload +def command( + name: None = None, + *, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: ... + + +def command( + name: str | _AnyCallable | None = None, + cls: type[CmdType] | None = None, + **attrs: t.Any, +) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function, converted to + lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes + ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, + ``init_data_command`` becomes ``init-data``. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: The name of the command. Defaults to modifying the function's + name as described above. + :param cls: The command class to create. Defaults to :class:`Command`. + + .. versionchanged:: 8.2 + The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are + removed when generating the name. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Callable[[_AnyCallable], t.Any] | None = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast("type[CmdType]", Command) + + def decorator(f: _AnyCallable) -> CmdType: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + if t.TYPE_CHECKING: + assert cls is not None + assert not callable(name) + + if name is not None: + cmd_name = name + else: + cmd_name = f.__name__.lower().replace("_", "-") + cmd_left, sep, suffix = cmd_name.rpartition("-") + + if sep and suffix in {"command", "cmd", "group", "grp"}: + cmd_name = cmd_left + + cmd = cls(name=cmd_name, callback=f, params=params, **attrs) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +GrpType = t.TypeVar("GrpType", bound=Group) + + +# variant: no call, directly as decorator for a function. +@t.overload +def group(name: _AnyCallable) -> Group: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) +@t.overload +def group( + name: str | None, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) +@t.overload +def group( + name: None = None, + *, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: ... + + +def group( + name: str | _AnyCallable | None = None, + cls: type[GrpType] | None = None, + **attrs: t.Any, +) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if cls is None: + cls = t.cast("type[GrpType]", Group) + + if callable(name): + return command(cls=cls, **attrs)(name) + + return command(name, cls, **attrs) + + +def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument( + *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default argument class, refer to :class:`Argument` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Argument + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def option( + *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default option class, refer to :class:`Option` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Option + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: str | None = None, + *param_decls: str, + package_name: str | None = None, + prog_name: str | None = None, + message: str | None = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + import importlib.metadata + + try: + version = importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Pre-configured ``--help`` option which immediately prints the help page + and exits the program. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", show_help) + + return option(*param_decls, **kwargs) diff --git a/venv/lib/python3.12/site-packages/click/exceptions.py b/venv/lib/python3.12/site-packages/click/exceptions.py new file mode 100644 index 0000000..4d782ee --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/exceptions.py @@ -0,0 +1,308 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .globals import resolve_color_default +from .utils import echo +from .utils import format_filename + +if t.TYPE_CHECKING: + from .core import Command + from .core import Context + from .core import Parameter + + +def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + # The context will be removed by the time we print the message, so cache + # the color settings here to be used later on (in `show`) + self.show_color: bool | None = resolve_color_default() + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=self.show_color, + ) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: Context | None = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: Command | None = self.ctx.command if self.ctx else None + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: str | None = None, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: cabc.Sequence[str] | str | None = None, + param_type: str | None = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: cabc.Sequence[str] | str | None = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message( + param=self.param, ctx=self.ctx + ) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: str | None = None, + possibilities: cabc.Sequence[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: Context | None = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class NoArgsIsHelpError(UsageError): + def __init__(self, ctx: Context) -> None: + self.ctx: Context + super().__init__(ctx.get_help(), ctx=ctx) + + def show(self, file: t.IO[t.Any] | None = None) -> None: + echo(self.format_message(), file=file, err=True, color=self.ctx.color) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: str | None = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: str = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code: int = code diff --git a/venv/lib/python3.12/site-packages/click/formatting.py b/venv/lib/python3.12/site-packages/click/formatting.py new file mode 100644 index 0000000..0b64f83 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +import collections.abc as cabc +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import _split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: int | None = None + + +def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: + widths: dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: cabc.Iterable[tuple[str, str]], col_count: int +) -> cabc.Iterator[tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: list[tuple[int, bool, str]] = [] + buf: list[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: int | None = None, + max_width: int | None = None, + ) -> None: + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + import shutil + + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent: int = 0 + self.buffer: list[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: cabc.Sequence[tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> cabc.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> cabc.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = _split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/venv/lib/python3.12/site-packages/click/globals.py b/venv/lib/python3.12/site-packages/click/globals.py new file mode 100644 index 0000000..a2f9172 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/globals.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import typing as t +from threading import local + +if t.TYPE_CHECKING: + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: t.Literal[False] = False) -> Context: ... + + +@t.overload +def get_current_context(silent: bool = ...) -> Context | None: ... + + +def get_current_context(silent: bool = False) -> Context | None: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: Context) -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: bool | None = None) -> bool | None: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/venv/lib/python3.12/site-packages/click/parser.py b/venv/lib/python3.12/site-packages/click/parser.py new file mode 100644 index 0000000..1ea1f71 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/parser.py @@ -0,0 +1,532 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" + +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from ._utils import FLAG_NEEDS_VALUE +from ._utils import UNSET +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + from ._utils import T_FLAG_NEEDS_VALUE + from ._utils import T_UNSET + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + + +def _unpack_args( + args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] +) -> tuple[cabc.Sequence[str | cabc.Sequence[str | None] | None], list[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with ``UNSET``. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: list[str | tuple[str | T_UNSET, ...] | T_UNSET] = [] + spos: int | None = None + + def _fetch(c: deque[V]) -> V | T_UNSET: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return UNSET + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) # type: ignore[arg-type] + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(UNSET) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def _split_opt(opt: str) -> tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def _normalize_opt(opt: str, ctx: Context | None) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = _split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +class _Option: + def __init__( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: set[str] = set() + + for opt in opts: + prefix, value = _split_opt(opt) + if not prefix: + raise ValueError(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: t.Any, state: _ParsingState) -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class _Argument: + def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: str | cabc.Sequence[str | None] | None | T_UNSET, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert isinstance(value, cabc.Sequence) + holes = sum(1 for x in value if x is UNSET) + if holes == len(value): + value = UNSET + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + # We failed to collect any argument value so we consider the argument as unset. + if value == (): + value = UNSET + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class _ParsingState: + def __init__(self, rargs: list[str]) -> None: + self.opts: dict[str, t.Any] = {} + self.largs: list[str] = [] + self.rargs = rargs + self.order: list[CoreParameter] = [] + + +class _OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + + .. deprecated:: 8.2 + Will be removed in Click 9.0. + """ + + def __init__(self, ctx: Context | None = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args: bool = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options: bool = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: dict[str, _Option] = {} + self._long_opt: dict[str, _Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: list[_Argument] = [] + + def add_option( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [_normalize_opt(opt, self.ctx) for opt in opts] + option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(_Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: list[str] + ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = _ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: _ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: _ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: str | None, state: _ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = UNSET + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: _ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = _normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = UNSET + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we recombine the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: _Option, state: _ParsingState + ) -> str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE: + nargs = option.nargs + + value: str | cabc.Sequence[str] | T_FLAG_NEEDS_VALUE + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = FLAG_NEEDS_VALUE + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = FLAG_NEEDS_VALUE + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: _ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = _normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) + + +def __getattr__(name: str) -> object: + import warnings + + if name in { + "OptionParser", + "Argument", + "Option", + "split_opt", + "normalize_opt", + "ParsingState", + }: + warnings.warn( + f"'parser.{name}' is deprecated and will be removed in Click 9.0." + " The old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return globals()[f"_{name}"] + + if name == "split_arg_string": + from .shell_completion import split_arg_string + + warnings.warn( + "Importing 'parser.split_arg_string' is deprecated, it will only be" + " available in 'shell_completion' in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return split_arg_string + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/py.typed b/venv/lib/python3.12/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/click/shell_completion.py b/venv/lib/python3.12/site-packages/click/shell_completion.py new file mode 100644 index 0000000..8f1564c --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/shell_completion.py @@ -0,0 +1,667 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .utils import echo + + +def shell_complete( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: str | None = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: str | None = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +# See ZshComplete.format_completion below, and issue #2703, before +# changing this script. +# +# (TL;DR: _describe is picky about the format, but this Zsh script snippet +# is already widely deployed. So freeze this script, and use clever-ish +# handling of colons in ZshComplet.format_completion.) +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +if [[ $zsh_eval_context[-1] == loadautofunc ]]; then + # autoload from fpath, call function directly + %(complete_func)s "$@" +else + # eval/source/. command, register function for later + compdef %(complete_func)s %(prog_name)s +fi +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> tuple[list[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import shutil + import subprocess + + bash_exe = shutil.which("bash") + + if bash_exe is None: + match = None + else: + output = subprocess.run( + [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], + stdout=subprocess.PIPE, + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + echo( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ), + err=True, + ) + else: + echo( + _("Couldn't detect Bash version, shell completion is not supported."), + err=True, + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + help_ = item.help or "_" + # The zsh completion script uses `_describe` on items with help + # texts (which splits the item help from the item value at the + # first unescaped colon) and `compadd` on items without help + # text (which uses the item value as-is and does not support + # colon escaping). So escape colons in the item value if and + # only if the item help is not the sentinel "_" value, as used + # by the completion script. + # + # (The zsh completion script is potentially widely deployed, and + # thus harder to fix than this method.) + # + # See issue #1812 and issue #2703 for further context. + value = item.value.replace(":", r"\:") if help_ != "_" else item.value + return f"{item.type}\n{value}\n{help_}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + if incomplete: + incomplete = split_arg_string(incomplete)[0] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") + + +_available_shells: dict[str, type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: str | None = None +) -> ShellCompleteType: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + return cls + + +def get_completion_class(shell: str) -> type[ShellComplete] | None: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def split_arg_string(string: str) -> list[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + + .. versionchanged:: 8.2 + Moved to ``shell_completion`` from ``parser``. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + # Will be None if expose_value is False. + value = ctx.params.get(param.name) + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + break + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + args: list[str], +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: + args = ctx._protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, Group): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, args, parent=ctx, resilient_parsing=True + ) as sub_ctx: + ctx = sub_ctx + args = ctx._protected_args + ctx.args + else: + sub_ctx = ctx + + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) as sub_sub_ctx: + sub_ctx = sub_sub_ctx + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx._protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: list[str], incomplete: str +) -> tuple[Command | Parameter, str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/venv/lib/python3.12/site-packages/click/termui.py b/venv/lib/python3.12/site-packages/click/termui.py new file mode 100644 index 0000000..2e98a07 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/termui.py @@ -0,0 +1,883 @@ +from __future__ import annotations + +import collections.abc as cabc +import inspect +import io +import itertools +import sys +import typing as t +from contextlib import AbstractContextManager +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Any | None = None, + show_choices: bool = True, + type: ParamType | None = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text: str, + default: t.Any | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType | t.Any | None = None, + value_proc: t.Callable[[str], t.Any] | None = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text[:-1], nl=False, err=err) + # Echo the last character to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(text[-1:]) + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: bool | None = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.3.1 + A space is no longer appended to the prompt. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt[:-1], nl=False, err=err) + # Echo the last character to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(prompt[-1:]).lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, + color: bool | None = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +@t.overload +def progressbar( + *, + length: int, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[int]: ... + + +@t.overload +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: ... + + +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param hidden: hide the progressbar. Defaults to ``False``. When no tty is + detected, it will only print the progressbar label. Setting this to + ``False`` also disables that. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionadded:: 8.2 + The ``hidden`` argument. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + The ``update_min_steps`` parameter. + + .. versionadded:: 4.0 + The ``color`` parameter and ``update`` method. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + hidden=hidden, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor + echo("\033[2J\033[1;1H", nl=False) + + +def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: int | tuple[int, int, int] | str | None = None, + bg: int | tuple[int, int, int] | str | None = None, + bold: bool | None = None, + dim: bool | None = None, + underline: bool | None = None, + overline: bool | None = None, + italic: bool | None = None, + blink: bool | None = None, + reverse: bool | None = None, + strikethrough: bool | None = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Any | None = None, + file: t.IO[t.AnyStr] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +@t.overload +def edit( + text: bytes | bytearray, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = False, + extension: str = ".txt", +) -> bytes | None: ... + + +@t.overload +def edit( + text: str, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", +) -> str | None: ... + + +@t.overload +def edit( + text: None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> None: ... + + +def edit( + text: str | bytes | bytearray | None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> str | bytes | bytearray | None: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. If the editor supports + editing multiple files at once, a sequence of files may be + passed as well. Invoke `click.file` once per file instead + if multiple files cannot be managed at once or editing the + files serially is desired. + + .. versionchanged:: 8.2.0 + ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` + if the ``editor`` supports editing multiple files at once. + + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + if isinstance(filename, str): + filename = (filename,) + + ed.edit_files(filenames=filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Callable[[bool], str] | None = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> AbstractContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: str | None = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/venv/lib/python3.12/site-packages/click/testing.py b/venv/lib/python3.12/site-packages/click/testing.py new file mode 100644 index 0000000..ebfd54d --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/testing.py @@ -0,0 +1,574 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +import shlex +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import _compat +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from _typeshed import ReadableBuffer + + from .core import Command + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> list[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> cabc.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class BytesIOCopy(io.BytesIO): + """Patch ``io.BytesIO`` to let the written stream be copied to another. + + .. versionadded:: 8.2 + """ + + def __init__(self, copy_to: io.BytesIO) -> None: + super().__init__() + self.copy_to = copy_to + + def flush(self) -> None: + super().flush() + self.copy_to.flush() + + def write(self, b: ReadableBuffer) -> int: + self.copy_to.write(b) + return super().write(b) + + +class StreamMixer: + """Mixes `` and `` streams. + + The result is available in the ``output`` attribute. + + .. versionadded:: 8.2 + """ + + def __init__(self) -> None: + self.output: io.BytesIO = io.BytesIO() + self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) + self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + def close(self) -> None: + """ + The buffer this object contains belongs to some other object, so + prevent the default __del__ implementation from closing that buffer. + + .. versionadded:: 8.3.2 + """ + ... + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: str | bytes | t.IO[t.Any] | None, charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(input) + + +class Result: + """Holds the captured result of an invoked CLI script. + + :param runner: The runner that created the result + :param stdout_bytes: The standard output as bytes. + :param stderr_bytes: The standard error as bytes. + :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the + user would see it in its terminal. + :param return_value: The value returned from the invoked command. + :param exit_code: The exit code as integer. + :param exception: The exception that happened if one did. + :param exc_info: Exception information (exception type, exception instance, + traceback type). + + .. versionchanged:: 8.2 + ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and + ``mix_stderr`` has been removed. + + .. versionadded:: 8.0 + Added ``return_value``. + """ + + def __init__( + self, + runner: CliRunner, + stdout_bytes: bytes, + stderr_bytes: bytes, + output_bytes: bytes, + return_value: t.Any, + exit_code: int, + exception: BaseException | None, + exc_info: tuple[type[BaseException], BaseException, TracebackType] + | None = None, + ): + self.runner = runner + self.stdout_bytes = stdout_bytes + self.stderr_bytes = stderr_bytes + self.output_bytes = output_bytes + self.return_value = return_value + self.exit_code = exit_code + self.exception = exception + self.exc_info = exc_info + + @property + def output(self) -> str: + """The terminal output as unicode string, as the user would see it. + + .. versionchanged:: 8.2 + No longer a proxy for ``self.stdout``. Now has its own independent stream + that is mixing `` and ``, in the order they were written. + """ + return self.output_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string. + + .. versionchanged:: 8.2 + No longer raise an exception, always returns the `` string. + """ + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from `` writes + to ``. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param catch_exceptions: Whether to catch any exceptions other than + ``SystemExit`` when running :meth:`~CliRunner.invoke`. + + .. versionchanged:: 8.2 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 8.2 + ``mix_stderr`` parameter has been removed. + """ + + def __init__( + self, + charset: str = "utf-8", + env: cabc.Mapping[str, str | None] | None = None, + echo_stdin: bool = False, + catch_exceptions: bool = True, + ) -> None: + self.charset = charset + self.env: cabc.Mapping[str, str | None] = env or {} + self.echo_stdin = echo_stdin + self.catch_exceptions = catch_exceptions + + def get_default_prog_name(self, cli: Command) -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: cabc.Mapping[str, str | None] | None = None + ) -> cabc.Mapping[str, str | None]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + color: bool = False, + ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up `` with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into `sys.stdin`. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + An additional output stream is returned, which is a mix of + `` and `` streams. + + .. versionchanged:: 8.2 + Always returns the `` stream. + + .. versionchanged:: 8.0 + `` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + stream_mixer = StreamMixer() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + stream_mixer.stdout, encoding=self.charset, name="", mode="w" + ) + + sys.stderr = _NamedTextIOWrapper( + stream_mixer.stderr, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: str | None = None) -> str: + sys.stdout.write(prompt or "") + try: + val = next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: str | None = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + try: + return next(text_input).rstrip("\r\n") + except StopIteration as e: + raise EOFError() from e + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + old__compat_should_strip_ansi = _compat.should_strip_ansi + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + _compat.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + _compat.should_strip_ansi = old__compat_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: Command, + args: str | cabc.Sequence[str] | None = None, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + catch_exceptions: bool | None = None, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. If :data:`None`, the value + from :class:`CliRunner` is used. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + The result object has the ``output_bytes`` attribute with + the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would + see it in its terminal. + + .. versionchanged:: 8.2 + The result object always returns the ``stderr_bytes`` stream. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + if catch_exceptions is None: + catch_exceptions = self.catch_exceptions + + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: BaseException | None = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast("int | t.Any | None", e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + sys.stderr.flush() + stdout = outstreams[0].getvalue() + stderr = outstreams[1].getvalue() + output = outstreams[2].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + output_bytes=output, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: str | os.PathLike[str] | None = None + ) -> cabc.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + import shutil + + try: + shutil.rmtree(dt) + except OSError: + pass diff --git a/venv/lib/python3.12/site-packages/click/types.py b/venv/lib/python3.12/site-packages/click/types.py new file mode 100644 index 0000000..e71c1c2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/types.py @@ -0,0 +1,1209 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import os +import stat +import sys +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import format_filename +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + +ParamTypeValue = t.TypeVar("ParamTypeValue") + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[str | None] = None + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.NoReturn: + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name: str = func.__name__ + self.func = func + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = sys.getfilesystemencoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType, t.Generic[ParamTypeValue]): + """The choice type allows a value to be checked against a fixed set + of supported values. + + You may pass any iterable value which will be converted to a tuple + and thus will only be iterated once. + + The resulting value will always be one of the originally passed choices. + See :meth:`normalize_choice` for more info on the mapping of strings + to choices. See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + + .. versionchanged:: 8.2.0 + Non-``str`` ``choices`` are now supported. It can additionally be any + iterable. Before you were not recommended to pass anything but a list or + tuple. + + .. versionadded:: 8.2.0 + Choice normalization can be overridden via :meth:`normalize_choice`. + """ + + name = "choice" + + def __init__( + self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True + ) -> None: + self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def _normalized_mapping( + self, ctx: Context | None = None + ) -> cabc.Mapping[ParamTypeValue, str]: + """ + Returns mapping where keys are the original choices and the values are + the normalized values that are accepted via the command line. + + This is a simple wrapper around :meth:`normalize_choice`, use that + instead which is supported. + """ + return { + choice: self.normalize_choice( + choice=choice, + ctx=ctx, + ) + for choice in self.choices + } + + def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: + """ + Normalize a choice value, used to map a passed string to a choice. + Each choice must have a unique normalized value. + + By default uses :meth:`Context.token_normalize_func` and if not case + sensitive, convert it to a casefolded value. + + .. versionadded:: 8.2.0 + """ + normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(normed_value) + + if not self.case_sensitive: + normed_value = normed_value.casefold() + + return normed_value + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + if param.param_type_name == "option" and not param.show_choices: # type: ignore + choice_metavars = [ + convert_type(type(choice)).name.upper() for choice in self.choices + ] + choices_str = "|".join([*dict.fromkeys(choice_metavars)]) + else: + choices_str = "|".join( + [str(i) for i in self._normalized_mapping(ctx=ctx).values()] + ) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: + """ + Message shown when no choice is passed. + + .. versionchanged:: 8.2.0 Added ``ctx`` argument. + """ + return _("Choose from:\n\t{choices}").format( + choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) + ) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> ParamTypeValue: + """ + For a given value from the parser, normalize it and find its + matching normalized value in the list of choices. Then return the + matched "original" choice. + """ + normed_value = self.normalize_choice(choice=value, ctx=ctx) + normalized_mapping = self._normalized_mapping(ctx=ctx) + + try: + return next( + original + for original, normalized in normalized_mapping.items() + if normalized == normed_value + ) + except StopIteration: + self.fail( + self.get_invalid_choice_message(value=value, ctx=ctx), + param=param, + ctx=ctx, + ) + + def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: + """Get the error message when the given choice is invalid. + + :param value: The invalid value. + + .. versionadded:: 8.2 + """ + choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) + return ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: cabc.Sequence[str] | None = None): + self.formats: cabc.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[type[t.Any]] + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: t.Literal[1, -1], open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + if not open: + return bound + + # Could use math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + bool_states: dict[str, bool] = { + "1": True, + "0": False, + "yes": True, + "no": False, + "true": True, + "false": False, + "on": True, + "off": False, + "t": True, + "f": False, + "y": True, + "n": False, + # Absence of value is considered False. + "": False, + } + """A mapping of string values to boolean states. + + Mapping is inspired by :py:attr:`configparser.ConfigParser.BOOLEAN_STATES` + and extends it. + + .. caution:: + String values are lower-cased, as the ``str_to_bool`` comparison function + below is case-insensitive. + + .. warning:: + The mapping is not exhaustive, and does not cover all possible boolean strings + representations. It will remains as it is to avoid endless bikeshedding. + + Future work my be considered to make this mapping user-configurable from public + API. + """ + + @staticmethod + def str_to_bool(value: str | bool) -> bool | None: + """Convert a string to a boolean value. + + If the value is already a boolean, it is returned as-is. If the value is a + string, it is stripped of whitespaces and lower-cased, then checked against + the known boolean states pre-defined in the `BoolParamType.bool_states` mapping + above. + + Returns `None` if the value does not match any known boolean state. + """ + if isinstance(value, bool): + return value + return BoolParamType.bool_states.get(value.strip().lower()) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> bool: + normalized = self.str_to_bool(value) + if normalized is None: + self.fail( + _( + "{value!r} is not a valid boolean. Recognized values: {states}" + ).format(value=value, states=", ".join(sorted(self.bool_states))), + param, + ctx, + ) + return normalized + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Files can also be opened atomically in which case all writes go into a + separate file in the same folder and upon completion the file will + be moved over to the original location. This is useful if a file + regularly read by other users is modified. + + See :ref:`file-args` for more information. + + .. versionchanged:: 2.0 + Added the ``atomic`` parameter. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool | None = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: + if self.lazy is not None: + return self.lazy + if os.fspath(value) == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, + value: str | os.PathLike[str] | t.IO[t.Any], + param: Parameter | None, + ctx: Context | None, + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("str | os.PathLike[str]", value) + + try: + lazy = self.resolve_lazy_flag(value) + + if lazy: + lf = LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + if ctx is not None: + ctx.call_on_close(lf.close_intelligently) + + return t.cast("t.IO[t.Any]", lf) + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: + return hasattr(value, "read") or hasattr(value, "write") + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``path_type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: type[t.Any] | None = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name: str = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result( + self, value: str | os.PathLike[str] + ) -> str | bytes | os.PathLike[str]: + if self.type is not None and not isinstance(value, self.type): + if self.type is str: + return os.fsdecode(value) + elif self.type is bytes: + return os.fsencode(value) + else: + return t.cast("os.PathLike[str]", self.type(value)) + + return value + + def convert( + self, + value: str | os.PathLike[str], + param: Parameter | None, + ctx: Context | None, + ) -> str | bytes | os.PathLike[str]: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} {filename!r} is a directory.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: + self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple( + ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) + ) + + +def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() + + +class OptionHelpExtra(t.TypedDict, total=False): + envvars: tuple[str, ...] + default: str + range: str + required: str diff --git a/venv/lib/python3.12/site-packages/click/utils.py b/venv/lib/python3.12/site-packages/click/utils.py new file mode 100644 index 0000000..beae26f --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/utils.py @@ -0,0 +1,627 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType +from types import TracebackType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: + try: + return func(*args, **kwargs) + except Exception: + pass + return None + + return update_wrapper(wrapper, func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(sys.getfilesystemencoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, + ): + self.name: str = os.fspath(filename) + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.IO[t.Any] | None + self.should_close: bool + + if self.name == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO[t.Any]: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> LazyFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close_intelligently() + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO[t.Any]) -> None: + self._file: t.IO[t.Any] = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> KeepOpenFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Any | None = None, + file: t.IO[t.Any] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + return + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: str | bytes | bytearray | None = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file, color) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: t.Literal["stdin", "stdout", "stderr"], + encoding: str | None = None, + errors: str | None = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[t.Any]: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name or Path of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast( + "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) + ) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) + + return f + + +def format_filename( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], + shorten: bool = False, +) -> str: + """Format a filename as a string for display. Ensures the filename can be + displayed by replacing any invalid bytes or surrogate escapes in the name + with the replacement character ``�``. + + Invalid bytes or surrogate escapes will raise an error when written to a + stream with ``errors="strict"``. This will typically happen with ``stdout`` + when the locale is something like ``en_GB.UTF-8``. + + Many scenarios *are* safe to write surrogates though, due to PEP 538 and + PEP 540, including: + + - Writing to ``stderr``, which uses ``errors="backslashreplace"``. + - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens + stdout and stderr with ``errors="surrogateescape"``. + - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. + - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. + Python opens stdout and stderr with ``errors="surrogateescape"``. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + else: + filename = os.fspath(filename) + + if isinstance(filename, bytes): + filename = filename.decode(sys.getfilesystemencoding(), "replace") + else: + filename = filename.encode("utf-8", "surrogateescape").decode( + "utf-8", "replace" + ) + + return filename + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no effect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO[t.Any]) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: str | None = None, _main: ModuleType | None = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # It is set to "" inside a Shiv or PEX zipapp. + if getattr(_main, "__package__", None) in {None, ""} or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: cabc.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> list[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/METADATA b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/METADATA new file mode 100644 index 0000000..9d8623c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/METADATA @@ -0,0 +1,91 @@ +Metadata-Version: 2.4 +Name: Flask +Version: 3.1.3 +Summary: A simple framework for building complex web applications. +Maintainer-email: Pallets +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: blinker>=1.9.0 +Requires-Dist: click>=8.1.3 +Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10' +Requires-Dist: itsdangerous>=2.2.0 +Requires-Dist: jinja2>=3.1.2 +Requires-Dist: markupsafe>=2.1.1 +Requires-Dist: werkzeug>=3.1.0 +Requires-Dist: asgiref>=3.2 ; extra == "async" +Requires-Dist: python-dotenv ; extra == "dotenv" +Project-URL: Changes, https://flask.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/flask/ +Provides-Extra: async +Provides-Extra: dotenv + +

+ +# Flask + +Flask is a lightweight [WSGI] web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around [Werkzeug] +and [Jinja], and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +[WSGI]: https://wsgi.readthedocs.io/ +[Werkzeug]: https://werkzeug.palletsprojects.com/ +[Jinja]: https://jinja.palletsprojects.com/ + +## A Simple Example + +```python +# save this as app.py +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def hello(): + return "Hello, World!" +``` + +``` +$ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + +## Donate + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/RECORD b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/RECORD new file mode 100644 index 0000000..9d5a84b --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/RECORD @@ -0,0 +1,58 @@ +../../../bin/flask,sha256=3nmqKd-5A1gNbrEDPOgeN--eYOGK0-CE5HTfojOdFl8,241 +flask-3.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.1.3.dist-info/METADATA,sha256=qmdg7W9UVwRHTXBzPkpjp_FIHjdpc-3IlqE9AqciTHw,3167 +flask-3.1.3.dist-info/RECORD,, +flask-3.1.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask-3.1.3.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +flask-3.1.3.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask-3.1.3.dist-info/licenses/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask/__init__.py,sha256=mHvJN9Swtl1RDtjCqCIYyIniK_SZ_l_hqUynOzgpJ9o,2701 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-312.pyc,, +flask/__pycache__/__main__.cpython-312.pyc,, +flask/__pycache__/app.cpython-312.pyc,, +flask/__pycache__/blueprints.cpython-312.pyc,, +flask/__pycache__/cli.cpython-312.pyc,, +flask/__pycache__/config.cpython-312.pyc,, +flask/__pycache__/ctx.cpython-312.pyc,, +flask/__pycache__/debughelpers.cpython-312.pyc,, +flask/__pycache__/globals.cpython-312.pyc,, +flask/__pycache__/helpers.cpython-312.pyc,, +flask/__pycache__/logging.cpython-312.pyc,, +flask/__pycache__/sessions.cpython-312.pyc,, +flask/__pycache__/signals.cpython-312.pyc,, +flask/__pycache__/templating.cpython-312.pyc,, +flask/__pycache__/testing.cpython-312.pyc,, +flask/__pycache__/typing.cpython-312.pyc,, +flask/__pycache__/views.cpython-312.pyc,, +flask/__pycache__/wrappers.cpython-312.pyc,, +flask/app.py,sha256=k7tW8LHRSldUi6zKsFKK7Axa_WL4zu1e2wPNthIsu7o,61719 +flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541 +flask/cli.py,sha256=Pfh72-BxlvoH0QHCDOc1HvXG7Kq5Xetf3zzNz2kNSHk,37184 +flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219 +flask/ctx.py,sha256=oMe0TRsScW0qdaIqavVsk8P9qiEvAY5VHn1FAgkX8nk,15521 +flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 +flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 +flask/helpers.py,sha256=rJZge7_J288J1UQv5-kNf4oEaw332PP8NTW0QRIBbXE,23517 +flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602 +flask/json/__pycache__/__init__.cpython-312.pyc,, +flask/json/__pycache__/provider.cpython-312.pyc,, +flask/json/__pycache__/tag.cpython-312.pyc,, +flask/json/provider.py,sha256=5imEzY5HjV2HoUVrQbJLqXCzMNpZXfD0Y1XqdLV2XBA,7672 +flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281 +flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228 +flask/sansio/__pycache__/app.cpython-312.pyc,, +flask/sansio/__pycache__/blueprints.cpython-312.pyc,, +flask/sansio/__pycache__/scaffold.cpython-312.pyc,, +flask/sansio/app.py,sha256=whGURQDkN0jmhS4CHO7DQ96GGlZS0kETkKkAkoRjl4U,38106 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=wSASXYdFRWJmqcL0Xq-T7N-PDVUSiFGvjO9kPZg58bk,30371 +flask/sessions.py,sha256=eywRqmytTmYnX_EC78-YBGJoTc5XD_lRphQG5LbN1d0,14969 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=vbIkwYAxsSEfDxQID1gKRvBQQcGWEuWYCnH0XK3EqOI,7678 +flask/testing.py,sha256=zzC7XxhBWOP9H697IV_4SG7Lg3Lzb5PWiyEP93_KQXE,10117 +flask/typing.py,sha256=L-L5t2jKgS0aOmVhioQ_ylqcgiVFnA6yxO-RLNhq-GU,3293 +flask/views.py,sha256=xzJx6oJqGElThtEghZN7ZQGMw5TDFyuRxUkecwRuAoA,6962 +flask/wrappers.py,sha256=jUkv4mVek2Iq4hwxd4RvqrIMb69Bv0PElDgWLmd5ORo,9406 diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/REQUESTED b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/WHEEL b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/WHEEL new file mode 100644 index 0000000..d8b9936 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/entry_points.txt new file mode 100644 index 0000000..eec6733 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask=flask.cli:main + diff --git a/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.3.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/flask/__init__.py b/venv/lib/python3.12/site-packages/flask/__init__.py new file mode 100644 index 0000000..1fdc50c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__init__.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import typing as t + +from . import json as json +from .app import Flask as Flask +from .blueprints import Blueprint as Blueprint +from .config import Config as Config +from .ctx import after_this_request as after_this_request +from .ctx import copy_current_request_context as copy_current_request_context +from .ctx import has_app_context as has_app_context +from .ctx import has_request_context as has_request_context +from .globals import current_app as current_app +from .globals import g as g +from .globals import request as request +from .globals import session as session +from .helpers import abort as abort +from .helpers import flash as flash +from .helpers import get_flashed_messages as get_flashed_messages +from .helpers import get_template_attribute as get_template_attribute +from .helpers import make_response as make_response +from .helpers import redirect as redirect +from .helpers import send_file as send_file +from .helpers import send_from_directory as send_from_directory +from .helpers import stream_with_context as stream_with_context +from .helpers import url_for as url_for +from .json import jsonify as jsonify +from .signals import appcontext_popped as appcontext_popped +from .signals import appcontext_pushed as appcontext_pushed +from .signals import appcontext_tearing_down as appcontext_tearing_down +from .signals import before_render_template as before_render_template +from .signals import got_request_exception as got_request_exception +from .signals import message_flashed as message_flashed +from .signals import request_finished as request_finished +from .signals import request_started as request_started +from .signals import request_tearing_down as request_tearing_down +from .signals import template_rendered as template_rendered +from .templating import render_template as render_template +from .templating import render_template_string as render_template_string +from .templating import stream_template as stream_template +from .templating import stream_template_string as stream_template_string +from .wrappers import Request as Request +from .wrappers import Response as Response + +if not t.TYPE_CHECKING: + + def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Flask 3.2. Use feature detection or" + " 'importlib.metadata.version(\"flask\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("flask") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/flask/__main__.py b/venv/lib/python3.12/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..73c2343ed1f2eb6c2cc1e58d36bebdb7eb1c8297 GIT binary patch literal 2527 zcmZXWTW=dh6vti78d`)Jp*9FHFRQh8Y;Up`GrLae zDpgU1gm^%JcqktMR6Yn2FD;d5wbe?M3J-mY)IRlzb0*#<3M=dEZ~kX?=FFTkBmbF7 z^%8jg{^Pm+Jaw+=!YpbVl%mkvC`Qtl&xDIXWkJ3V5E*3qA$BKoasyqd*_O+0p+D199Yt-mj!9XRx+5HulffX+8$Oh9&iK(pafdk$1P*Fct=b$1 zkJcgNCP1#iTtzgPrkK!CZ7>J)Vbon_whYx}it4&tueMzVo|LKXFo?ow!Cs({;7rpw ztKqmk4zo0+t{dpc9yYjbDu*3x-Vw6PnQAI~y4yUqig=qFO5NtrBaR!Z*Rk^etf{*v zO3QAwn08WZJ53>u9P8;a6|&G!GB8Y)t+HM%4GkkwCq~Q~i;=tZpn9~dpZd@=B zNW&+jqt5XgZ!0ZvqnoT67H;rF0m6hxuYLizPxj&7+gT)pU(`YxF~}WByrny#{m?e{ zJ@IH^Hx@`*`U8;Lq2Y|lgC?!ti>L5Bf3f4RN&tyfqG9W#y7pBqUZ3)7}M5w`6f*<+bu^ zS^nH%a-FGen=|;(g*t|rWSh$c-E6^WG4yKLWUi{Iu3GK}vY5vsvy(3tU@!*~t(9M5 zWRQ_wsD#>%!FHK(c*=H)ac}VdLwSikm0OTl$BQ6&gIBsy!}MPqy1Ya%u@~>o?4>UU zXK{mbI4xl>VyPzcdfraKS0NGy(;>_9o2^RIHd&>uuH3G|YqzxXPN}YQ6Xs+kM|W9e zmsz_NSY@TvahtZaR$f`Hprh1+h2V8i5sR%T3e>%;DCJfMa{?CxZaU=TB1~1mId6jb znmkQretiG0r2MRJ{#oC|^S;~<*T1`d5DE=kkzU8h!0gkB$%71k-^^xzl8n^VBRDynYPw8*av(Qns`W^pTHc1 zB}wv0{skHQmyG*l+9ze7%=zR!pIrCJnolnJq~enapA^Jz)+g}0?2`@QE&62HCm)I* ybbt?`Km4wW4(mQSFNOjOpMZYBC)WbI=#!=A@x-@x@7;YJNk?Z7q9idQLjDi@8_@g! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..edb440583ac8e0144b16453682e6bc8557101ff0 GIT binary patch literal 235 zcmX@j%ge<81lLYH$dm)pk3k$5V1hC}gJh;Nq%fo~<}lE~o7=@(R%WaQ@=>lqs9gCukd5|gtN(^HG}({d7vv-RWS xL6*eF>lIY~;;_lhPbtkwwJYKPS^{!JF)xt#z|6?Vc$Y!+Ap=V*TM-*j1ORGLI}ZQ= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d6a9a2857405258afe57c373de7de7502c8c502b GIT binary patch literal 62487 zcmdqKdw5&tc_#=EAPEv6!8<8Z7l@QZQX)a!Wm6Z6lBkO%Q3^@fF>?Vx9!P=&63hW8 zSuB;>+02$o-CAm#imsipGWBfb$DT&*(~Gm)-8xBkn%UWBhcK0rLDgMlH}h=s?Eaxt z&NHd|>^}Q@-|un`z(d)|%>1zfTj0St-}$cZ_uk+4`?nPpj~{rLa&xLmhghRbj#UE}T%x0|kul11a55wE;19x3K~B_k#Lw{*nEf6GS7@Yj +{% endblock %} +``` + +## Donate + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD new file mode 100644 index 0000000..ffa3866 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD @@ -0,0 +1,57 @@ +jinja2-3.1.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2-3.1.6.dist-info/METADATA,sha256=aMVUj7Z8QTKhOJjZsx7FDGvqKr3ZFdkh8hQ1XDpkmcg,2871 +jinja2-3.1.6.dist-info/RECORD,, +jinja2-3.1.6.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82 +jinja2-3.1.6.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 +jinja2-3.1.6.dist-info/licenses/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +jinja2/__init__.py,sha256=xxepO9i7DHsqkQrgBEduLtfoz2QCuT6_gbL4XSN1hbU,1928 +jinja2/__pycache__/__init__.cpython-312.pyc,, +jinja2/__pycache__/_identifier.cpython-312.pyc,, +jinja2/__pycache__/async_utils.cpython-312.pyc,, +jinja2/__pycache__/bccache.cpython-312.pyc,, +jinja2/__pycache__/compiler.cpython-312.pyc,, +jinja2/__pycache__/constants.cpython-312.pyc,, +jinja2/__pycache__/debug.cpython-312.pyc,, +jinja2/__pycache__/defaults.cpython-312.pyc,, +jinja2/__pycache__/environment.cpython-312.pyc,, +jinja2/__pycache__/exceptions.cpython-312.pyc,, +jinja2/__pycache__/ext.cpython-312.pyc,, +jinja2/__pycache__/filters.cpython-312.pyc,, +jinja2/__pycache__/idtracking.cpython-312.pyc,, +jinja2/__pycache__/lexer.cpython-312.pyc,, +jinja2/__pycache__/loaders.cpython-312.pyc,, +jinja2/__pycache__/meta.cpython-312.pyc,, +jinja2/__pycache__/nativetypes.cpython-312.pyc,, +jinja2/__pycache__/nodes.cpython-312.pyc,, +jinja2/__pycache__/optimizer.cpython-312.pyc,, +jinja2/__pycache__/parser.cpython-312.pyc,, +jinja2/__pycache__/runtime.cpython-312.pyc,, +jinja2/__pycache__/sandbox.cpython-312.pyc,, +jinja2/__pycache__/tests.cpython-312.pyc,, +jinja2/__pycache__/utils.cpython-312.pyc,, +jinja2/__pycache__/visitor.cpython-312.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=vK-PdsuorOMnWSnEkT3iUJRIkTnYgO2T6MnGxDgHI5o,2834 +jinja2/bccache.py,sha256=gh0qs9rulnXo0PhX5jTJy2UHzI8wFnQ63o_vw7nhzRg,14061 +jinja2/compiler.py,sha256=9RpCQl5X88BHllJiPsHPh295Hh0uApvwFJNQuutULeM,74131 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=CnHqCDHd-BVGvti_8ZsTolnXNhA3ECsY-6n_2pwU8Hw,6297 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=9nhrP7Ch-NbGX00wvyr4yy-uhNHq2OCc60ggGrni_fk,61513 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=5PF5eHfh8mXAIxXHHRB2xXbXohi8pE3nHSOxa66uS7E,31875 +jinja2/filters.py,sha256=PQ_Egd9n9jSgtnGQYyF4K5j2nYwhUIulhPnyimkdr-k,55212 +jinja2/idtracking.py,sha256=-ll5lIp73pML3ErUYiIJj7tdmWxcH_IlDv3yA_hiZYo,10555 +jinja2/lexer.py,sha256=LYiYio6br-Tep9nPcupWXsPEtjluw3p1mU-lNBVRUfk,29786 +jinja2/loaders.py,sha256=wIrnxjvcbqh5VwW28NSkfotiDq8qNCxIOSFbGUiSLB4,24055 +jinja2/meta.py,sha256=OTDPkaFvU2Hgvx-6akz7154F8BIWaRmvJcBFvwopHww,4397 +jinja2/nativetypes.py,sha256=7GIGALVJgdyL80oZJdQUaUfwSt5q2lSSZbXt0dNf_M4,4210 +jinja2/nodes.py,sha256=m1Duzcr6qhZI8JQ6VyJgUNinjAf5bQzijSmDnMsvUx8,34579 +jinja2/optimizer.py,sha256=rJnCRlQ7pZsEEmMhsQDgC_pKyDHxP5TPS6zVPGsgcu8,1651 +jinja2/parser.py,sha256=lLOFy3sEmHc5IaEHRiH1sQVnId2moUQzhyeJZTtdY30,40383 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=gDk-GvdriJXqgsGbHgrcKTP0Yp6zPXzhzrIpCFH3jAU,34249 +jinja2/sandbox.py,sha256=Mw2aitlY2I8la7FYhcX2YG9BtUYcLnD0Gh3d29cDWrY,15009 +jinja2/tests.py,sha256=VLsBhVFnWg-PxSBz1MhRnNWgP1ovXk3neO1FLQMeC9Q,5926 +jinja2/utils.py,sha256=rRp3o9e7ZKS4fyrWRbELyLcpuGVTFcnooaOa1qx_FIk,24129 +jinja2/visitor.py,sha256=EcnL1PIwf_4RVCOMxsRNuR8AXHbS1qfAdMOE2ngKJz4,3557 diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL new file mode 100644 index 0000000..23d2d7e --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.11.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt new file mode 100644 index 0000000..abc3eae --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2=jinja2.ext:babel_extract[i18n] + diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/jinja2/__init__.py b/venv/lib/python3.12/site-packages/jinja2/__init__.py new file mode 100644 index 0000000..1a423a3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/__init__.py @@ -0,0 +1,38 @@ +"""Jinja is a template engine written in pure Python. It provides a +non-XML syntax that supports inline expressions and an optional +sandboxed environment. +""" + +from .bccache import BytecodeCache as BytecodeCache +from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache +from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache +from .environment import Environment as Environment +from .environment import Template as Template +from .exceptions import TemplateAssertionError as TemplateAssertionError +from .exceptions import TemplateError as TemplateError +from .exceptions import TemplateNotFound as TemplateNotFound +from .exceptions import TemplateRuntimeError as TemplateRuntimeError +from .exceptions import TemplatesNotFound as TemplatesNotFound +from .exceptions import TemplateSyntaxError as TemplateSyntaxError +from .exceptions import UndefinedError as UndefinedError +from .loaders import BaseLoader as BaseLoader +from .loaders import ChoiceLoader as ChoiceLoader +from .loaders import DictLoader as DictLoader +from .loaders import FileSystemLoader as FileSystemLoader +from .loaders import FunctionLoader as FunctionLoader +from .loaders import ModuleLoader as ModuleLoader +from .loaders import PackageLoader as PackageLoader +from .loaders import PrefixLoader as PrefixLoader +from .runtime import ChainableUndefined as ChainableUndefined +from .runtime import DebugUndefined as DebugUndefined +from .runtime import make_logging_undefined as make_logging_undefined +from .runtime import StrictUndefined as StrictUndefined +from .runtime import Undefined as Undefined +from .utils import clear_caches as clear_caches +from .utils import is_undefined as is_undefined +from .utils import pass_context as pass_context +from .utils import pass_environment as pass_environment +from .utils import pass_eval_context as pass_eval_context +from .utils import select_autoescape as select_autoescape + +__version__ = "3.1.6" diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c6399a8f67518eca8d7c0611435998e7f77c496d GIT binary patch literal 1651 zcmZ9MTW{Mo6vrt$iEa53UlQk@C`r2^C>$g0+O0rWV7cvrrU;f582BR45*xFTD1oG0 zJ5Sr&zQOht_Du%teGdi%6xh?=HWYj5(+-)+@haGV{rKl0c}N}U_iEKfaQ*Sy8}?HH zp+9vayK?X0?GF}0KO-MunO;aX4+8@OS39=M5{hU>sB z+%nt%Ucd{6o4|{B(Qpg6joXG7fS2%+;YHwOyll7~tc0t0)$kJV8eTKJ47`rl4X*%i z;0?p8z?*o}@LI4HI@mG14!n)G4Q~MN;2p!8z`J7vZ-o_t|cJ_9! zfBA;-SHxk`A&#P991ukv$}btG&TGMxqTFHJi4#Gc^O5RDeBb$6IkAWa%%?EQ<`M6F zfA-9gBd*BMQGKEunZ$7$|tvT!yLu$-ftDS zo$(h^QlXPN5h48vL+>Y4F8Qm0YEeF$2}yl)e(SV*(jM&`?@;8tc{n8V6qYcIG@ zU&2B8nPVRkNuNc;r#g|!Q9okdZQDL(o|^R5Zx3YR)lL)c>Ag&x%30(m!R;K?bK+f* z%Uh#zE+B{DWI*$%PZ%e?fKIZ5RBFexmt0Oe?T}niH;68wW-eVgl$)JE?EHlikmz)9 zX}VGI0!oByo|x3zWb%LGD>0GM^&+n5P(gp)w5O^ByvB_;Ai-2%L(+hH$|Z@4sPsro zuV)|ZAM8JRzW4FC;JSX~x$d~o^UTsB50xfnw9JBx%Tp_eIc>v742^9%^r$IXDT>-H zY0+OgQPxt?Qq@ue85aWc^rV>AR$WU&OH)fr%Yv3gEp3o-LEIFOSkl(AmK80lTGl|u zvx#DX6zkg9(6XszON*mr8)RH|-2oN)Rdd~6(Oa<4yBFPl6w+=&4z7D}8+5K7c3v_O zz9xcpBvZ6IfIW8u*6YUR9f!lZ-_;$R_@+u^_m%!m-0!+B<4n2kemr_td=i?PdMY}w zihf@u2l+d1S=K+fyfyQ$jjT^n^ks@pQuH82ofLhQqDLuulA_}jJx$SJias;`fzih) kdYB?$2nPM!G-2$gDY}=UZuWyFL_U5~Tl}#s?!l7(0Yd@i00000 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fa8c0b9950a3fe5bdfc6aa03c45f51fe59796a9c GIT binary patch literal 2132 zcmYL~%Wvb>8O3EA?KBOt?5>Lb7kMu-ABjfp&i@elzb?<)bKi~L zn}0I*#=`&P;P;PygJs|U0r>@t3tyi8qYzR0mJ z4qt4u7bh>;S9x}Ie09REs#lGx=9R^+oUgR6+U&nuU)R~!?Uy!t>Af72o@b;NNk4)Z zq}Lz~(oKj%r$t7mM`Y|XGET`b7*!Kgy?_K%oiM8HQcZ&ts8*qxLG>7;dV=Z!)iK*h zQX@l+EH$<}*&_={D?wI3 z7Ls;~>qgQ%mDlP9M@PK6wU&f;{2 zh#Mz24at(b1yRW@P+MWtPEs4wog{TI-N{l1(;byM;PK7!Kb+K7DLEV75hj;=UWIxF_2bk}&|r%O zyNm`;X^^ME0o(}sT3SgP^6$o z!GMBu3MLdxY20BnNzx=ulMGE%3<@;CGoA!AO>@O&T$%7#p7B_b$I1|$$10F2k2N3; zk98nEkH;C0t31BTrWv037HmN=ayYH;mY@?e%cn|Usqd7W8rIveP0Hke*37Q0s5>v-`xekh8r zDEdqk$KtRo4o}2UTO4(S9v6CA=-Wa!n9v)dqKHaNR1h>$!q6cdVN6A}&P3G_wG0!r zeNk7Ks3%0-W1^vmMolzLCYpU=CWN^oOjVd8Cd{$0+QRBGVfn%u2x};;iLj=^jtSdl z!ght-6Lw#?*x9v&+Y+vG(<vPmED~0-UQPyml=n-Z9UAX zeTK_Ln8SY+mjp%nMfLo0{co~-U;)w~On?*VzD z0{ST&gHos+$Vd@|LmTE0eI1uzj_pv>Wv4pMDsQOP+ye46&2uo41_vQ2}_%Cn9XEZYU06^ntdR{W()Mfl7$)T2nFi|oJ!+{W%;`)D`}9G<^Uj5 zR!)HdssInHtXN^$$iW!-uv|;R)V6MQ{Gx94jQgjz-dOl@em(l-oev+}Ut75cv$nLc z5nW$3Be(M1`pq8}KYnmOy7*}6oxgqndCWffHT!5~{r;y*>rwV_Wh1)yIJ)|H@!rY@ zi)&9dK7O$JtGC~IcTrBTwWSX~S^7)#;o{wu)w@gYF8+CCIl8*B^3h6k{q40U-~8ma z_a7`jx)=T3`YYH-zSbZ90+(=MZf@=>@=EyQ$g4lgzP|hB=9}Ssv-2kz6A@z0tNs8 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..213f034c5a1c2056b143668cdedf72e81642e723 GIT binary patch literal 4972 zcmb_fZ%kX)6~FiW@v|}5fB}ad`b_&pL+W7GSd zAy6~X1P!O^)^uA7sj7ucl}eOM%Ex?}w5rlHY5QPiG}tSZsFq3VH@8Gno9@HTdCz|! zq02Vyg6}=|-gD2r@7&+{bN^6LQAVKr`S+{QYC9o+#ZI9ZGtgN(O$nJHGLdPF1kIKP zIp}jSenj#{lxoGL)F`#Eu1=-}p0n1VTeg9uJ?5JAHH@~d@0+wN)dL|* z1Dw&80VT-xDIvI(BV9x;pCWPvtlW41N~HowmdQz*Vw1!D$r*$(plBRTiiMiU#rP?0Um6vAV+U(uB5N2mo-NFJL>Q3O`w5|0D%pv%*Wmy-fBM_3OQFQu?0Kt2C? zJ>(kK&9LJWbgJn>B&D=`+&$?(n;263$?)FserQH^ zztX;YAj*bD!%W$&Mm5DhqQpo1v1q@4cuYH+h(FP?x7CjmyNAP(SHfo$)jt@G4~AR) zhV)QUi^kNJ;W37g9&a@VN5U)`j%zIkV~I#Oras*wE0F{XYYA2wDx9wl54R1fNwVVJ zGBfh_$oul#cjv3Fb}f0^7QAg)cYCI?eGM4M=6aQ3=KrJD&0t^BHFLm5K9M0_8A6p+ zL8aS4Us0Bb4=HiYPy)l-Hr35)knMlfOasc<0o5j&=~(b~EO`$vcn@dYflOt9p#}JO zy(|JV&tbTaE+vQMu%^fn=oAZL z_aXSLJqy)4!VKZaMIl9s#=u<^nTSZ0$yPD}CdRD5!KX-+r056qr{L3|Z&}|5AIDHE zYlO-t8Q9b)2rf&B5(An_IQE~ftN)lRRTF4k7p8!p>AD5 z2R*E?@xA{!81qXW23hJMsJ@ycUsy<0{cO$89qGVlPS3KtVKy*(B<~pUKEO;WX)J1!c=tlr$LRL!-w-~v=wc3-18tsqBW?0gz6iBs;gni zoXxgpjVEPCDAxOP0`$MABjwvx>UPdc*}6UH zuGL2#O-qZ`9m~$Tw8OYW6Q-P@B-VnTiSG8a$AntN2E{NxOrdvB(J=so?r@KY?%Z)o z%4;)1jUi7LAw5Vc3VVERDZ`ixGmY!oflqPtlPC9?OJhGzBO`jjxooJcC$@2Y4t z=L2A98hA+fs9pj(0;9!JxSzFMFf>CH5(MW6S-J(%JR!)-5@t?8LFN>3fRiB~ z3R=cQpH<%yI;tr~i0n-SFm4yRk%C0r0%_24@xG7ZVL zE@e)U&64IqMC&0tNGS*NLRvgQHQdf9DY|KfkWa@`^gKMqCg_joC>nG*BF_iTnjhQ@{cB*&* zhB@Ro-qyb2a?c7^9G4wg*Un7&&aYOSjb9Q9`Sceu|k>32&GW9R?|o!AobuDh6#+8~72rfR=#?8@A{^*IQ2B@!=GE z4!BRiPkkIJh&&czb*9hFHY`dHFFV~!&ZY%tQ`Wg7W8HDvx$}lFfAYE`>+Hx_JMK3i zwA%~tTkC`B+apmcd5cE4GbF-2QHTP983pj&`8M}vIm7{JAIwic8W`cIL5-4Jz034^`r=nLifDB)_eb>C0-PW>X_b=N0v-FKX#_s>> zPj-Js@P7@>*Qyto&pUkd66Y0uCU`9G((Pq4yvOpM;1zyJJ(fA@6|P!+)F-fGz{evtbIV!Fx+JayKJi(?#P=WaNHk?pD$J((%sF zGvDic=Gf8hF1^Z>5CRic;wnH?)j3VkrCx}MePL$W0p=1qAB}6eI1o#OH8WY{K^MA! zD$xZw8qwHJJaQ{mPv8R4fV^%ihFc>d>Qa{yS6DP+7?GiMU3jjb*L$q(uJxe#f_R#p z29fC8)Q_P8S3v0}#PJEK{*?GWB@KTg4WAP4DlbeQI)CUBp?OuPm<&uGef?-Ua-n;Y zerfU1+T2M>+z?#nyz~5g@6EPbwI2z;?ftkcQ+q5!s&f`At(py7>AKuC7x?hl)nhk# zc<|kfWV}xPTOZ+y)t%rY`*Gp>JEW!uF*pGFFOw8cxYF}`ZW>S gTs2SkEZaMBJhZE#WxDV6zVtJ%pSmML-@y96033ByCjbBd literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b7b06ebd3a7a2e1d483dc1f549e317baf142104 GIT binary patch literal 19343 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9b33ade5677a057f4dfff7a9fd235673504d24b9 GIT binary patch literal 104058 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 VJjgj-X5D6;+51Zii!hk_e*tkhoCg2^ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..168cd0cd7680acccb8c62d14b6c1fe10e23281d8 GIT binary patch literal 1554 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d433d20c462a9d1aff152fadcc04dae1a6168dbf GIT binary patch literal 1604 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..af7e961123d5099a8a8b0532aab4123cecc31c50 GIT binary patch literal 72328 zcmdSC3w%`9c`v%>sgXv~2t7c&2R)DkVt79+1GadBdD!M*Bb!L0*;`_SG$ZdB0TLre z#!e#{T14ywImV6LI1MgNLz=X4+S7AP&&&7r_S_L7L7v0uC9Q97b8qiG*z##?+H-sU z-?#Q_q!9+&Nl)h|?OC(;+UxnPZ+-9e=XrTK5BZX;*trhquAY zX*bfj4Y{1oYR~J)Z^-Ag2Wek}kJH&m7c>+gog;hOr*#xI6mmKj>7s@rPUj(A+)&Kv ze56YnN;vInpWZQ}VFsrQ+DkiTHq7MowDwsYvm0h}x)A9(4RbhMg!J5oxtuOWdS1gk zPM07(zhOS7rz7oe@N;?w(hC|E*d)c(wnZN{^IKic<5AvFfwq^nS9UCHSjg|qY_IC5 zZm8z;EVQepp@!45+ZS~#Zdh!S?9z5gp7Vkv&s8ego-|9;Qdx1N&c<9?I=%lvM!&%}?n{Fm+GUc>S!OI~ozHQC|AkVXiJ;f20ewl?Rwh$R@N%(L@TMKa?Oh2}+$T>9VT#ME&M{Dbqc??%8Hm>woHnA)`<_SnA!Qf(uoh7Juw~pH zv5Zqa+PHhlHf}O-=^o2FoAJ(G!ljtSzvD5^)G}i<%?Dv^tpr;h0 z3?9)Oc?Z_sK4q>}_y5b7sa)R4B~vY*2dh`eyIOMPM=ay?sHjQ)|BQM*e;vDlS@&4# zcno7-s63{RGmoiW-(DWM&(|laZ=a>U$Bn)`DnIrGl>a!!Y(L;(|F2-I9!J{`SlWKz zS5(JAOC1M!2L3Bk4u?QJJi#!#5-aFQz}_KRk%0Q!ye0|fX2z3EIs}{FjKekp%YCl- z#9Gdg4_n&%1jEl0Y4BsVF4KPEYP({#N>8CDO?uk=rZ(SiA2rPR#q_kn($mB82bh($ z@>9w>#%XT(Y0OB2jtw-N@S%L<1*fq?JjJ8)ly!7OKFr~`{3T1yrze#2k=$r`dPJEc z|2MhWa_39(-%q)_tW_F8FN$3+#PGAW#VyNdZ4=Su!W?gTYYRKzoY3l;fdNXMsWsYyxX%UzcCD3%iM zFovWO3DS+D2atbqlRQ`u4;bRfnl3>VR z2VB&PQ3%Wbc$eIbfT%`5-LuHqhJ0(~FQXTkAg^zV`+{zG4(&Py9)L%fcHBv+bBW)iu@bs!B^#exk4U5FJ4662(QqHJ|jtDw?_H5@bsKK$fM?w&*SMc%n5%DobXF%$NMH$)Kdm0 z923wZ|Nq9`N;p0fR2zJxeE-}X(H<4@%h+$fZs}i~$1iS64QYIPj{J(Hj^o_d<7s`>>l1y=g!?{aCKzta`o3wY@5G=@mgH9f z!6&)qlX}g#Z<8-tc7twSAA%oy4f%Vt-?RdL8^2E}&bE(rxG}#ixxQs7tv7RS)M}T9 zt@-f&RK3fLlUGu2Exb);*!a|U(W}?dt6pU;&-U-26-{QZ^pyN<;0)rRGSxCO^E;w# zzzuI$`uS|;@sOM3AdkTP(O}f7`^SZu$0TFFd5m-A?^t^99C?Nr$L6cqOoh=cil2c7~Zm!_8gDr zbLrzL@BIuVe-9=9zNO^TI_CMz?fkx_wCA~<&woMfykaT&h0op2A6QEJ3b*qsUr;;$ zz*6#WeC~Gs&{Eo0xt(AAg4+2bOUeBfc`;EunP`na#QjXvpU(05KvVpYg|-{ubxzRU zr_(Fu_Y`%^*C;1&OoO(zVl%&rZ6xf-6hF-jl_I^RV zkblCw^A}bgc%whYsGJozT*DH5=1A+Q%p)#;-ueB)M+UexU;Y#H=r^?<2`u_Axkuka zkNy>U^jl#`{!``LOEzfIp2hWFE1kIh8)Y}H?qnT4A*y+u9s}6=MNPbzy22`jO+iZ9LDv}l_R)5 z!!`VGN;lGfp=`nRKPlUA{oj>7T$9QHTt}3HxL#9&xQ;4c!u7iH0f4vI*Di zO7Bay?@&!QlxOgJOzFY(J>@j6DdjhC{m)7i*PF_txc(QV0N1}%I&l3zloPn#QugBd zbEO^Ezfu%j|5|w**Y}mpxc;9?J+6PFgmC@8l%rIW(xN<~49I_b(eWKy!})G|wF7GL zp0%60!tL=T;fO!3bab`{uIfSqLRwW*c$JNFdzQT0J6*?LWN07*BRij;<&D}`4l~^d)sl18Qo}hZH zs}uJ;v1m&iuc^NvH9cgbH&c5Y`d z7HbSeBXQ*<6;;5$mB{h18jVn4xHnDQJ05J;GroxqcD6*-jvzHByGw0ve5NZJSCH9_ zAK@NKdAFvO;@ye@HX9XXnaSe)!HC=(J*mi+H$pVl`bV>Okj6`K=Yph2ux^pavPE&U z*kwCbiL={L<4k4k2*!3C*t0w3R+V^{8VPAe5PCThnPiMRxsYz@P21i#aY;F2N_$I; zvik2FSb8+tp)BnRF7Ii^*YPFCRxfD@s~snTsCFBMpCJV^4wB!hn9K8r8;Jxb#V5xdr1$ z0K#1KMkLswG&ZJk8XG&Ja#uU0a~mybETThwaagUx(NNrv{ZGP)av|iqRDIx90Lg_iVEvnKg^#^1A zpuaO3i+8HgkP?gGHXzbp*U}XU)irelk136`HnBvpgqi|=z}s;}jmP{LwQ!_0mgC1K z9`(0JPbg|ANF_#Ozkr*VKZ@nA`s3Z53aW`M3C998?o>`V7LH)8M?#7kKwDF`c*==a zI2=w5cocOTZJ)N6H&+jYL(Yk!n%v@NhY0p!w>PK5|Q*!okXmMc1?D-t-lm zJ3esy<={}sw`RXG`_;LlzN)0B>Xx^lZ#U0b%4=Df>Kqi1%BD_+o4evl%4->oR2G(g zu&X^DB52n?X;b)B>8tjyI=<>kn@XEbmA(l3FmqbltfgqB$@aTHZ*lfJ`lWtXza3IA z#|yc=&V&{Lpe8@d|5RkA0najOsGE9Im(^jxXl2=M@OGv)4{JX1PU;Rr; z^6%TFQttGmvxFNQGG-G6(a_TGaVO@B7pXgaiJHq!pKrA=VQVw+E#B2Wvay_d9T7*u z)@ti@Bph3$bIy>xRSMaUWP?ywvdciLLbu*)HjU8*BxZ9+-frkiGi%k8j9)x zF!$O_BxgPWs$42bPlMp-wF8&|z68)mAYL=U4xj|uLy zHzjNdJK=(}%bh^D`z0MgI@*;;DqD$wwkBv&Hz7|=wm^|C!kn>`Eu6|XMvn1J%1uui z!|G<_7I=nmia?&(ND=kH2vm@4gmrpq7{PR4*A81~mrUrBM6NNij3o3qtz^)Bv1sVv ztFuN5%KKgKFIaSG_2`1-A4=KT^G0&#_Sg46J61BYf7`9ng&#_`yaxxJV>2sm%&Z-m zS$pZwl>?(Q>(0AxJMiGPTPm2H^eudEX2tNK(V4Y_?prhF_HP|r@Zyf!MJVj{bg7`E zKUd(`ER{D5rh{Cu&h~Iz-G&CKgkM!c?aZ!P$K<(rkSZ}_EzTetlJJ%93HrIhy& z6X@S7tl!{FIcc8L=wbt3|32Du0efp7aO?h0qmS!A_uds_154X9EIpqV12DXSr%{pi z(dlH>8z-pZ52yug8Ab3GF!=(;Jje z0g|T1t{$YDwv#a;^ZkASu{_yy`7-`_EANv4K%U&b#F%edfA;%X(*`RpI<9BU8Cz5L zzZ~r%YFJ1NfTbY~!0%W7N>jQhEvUXxfVo*dTCfsG#XIfg z@ik=%FQ93-(ty8St3|+Rvm)-xC`$$J)!vO9+!kuj#PW#%X=`?1+c;n zJPNW;1*0GH$5jP9CFKHR&!v}DuGm)QSDxt#gP4MB3kyzX=mP$oE&lFkmp`JQJ=}TO zA8QZBjw-QQmN!5kz=c322+pEC7*eWHHs~TMlzJxQJz9$c0Y5bYI4da2idYDr)){xmL+NH*R=j#Owgj;+^jSt^ivy=5S?R{@@uXZG}GuQ|S9yI`|P zXBRr9ZpZf=Cu}v&0}%DNfd?9&iQTbn*sBuh4PMC}SeCLKOWBUcXaQp)8NuJlUf-%j zl#`w6#-91W9|ky?^oWt+dw7p=$=?z|@}XoecE7j%k$0YXcfr{Q1|J)WU-wodb1H`) zd!zfxw6|AXuX;GSu>QJd(+3V@{3J%G`XLre8;*srE;z9Rf$%33I8!t#(-w1FeNT;G+c50DE8yT4-(fax7_rV4wa1h<|jS# zY4fVQSbRNe-q`XrKc4-A**}~Mk^;n!>y|hF+`55vA5b61_8s_$x-c%;bKSQkyUWdZ zG38MJUyY&oNp&u2Oxa>7N3>l|IU>plNQkk{<00$TZx9e0flxs}IQt;k1Vt)Q!zX@X z0dos8H~LJZge9N-vWBWH_Z<2?P{B0V_yCz2Bt`;qRUL`ON-g&t=6%(AA2wG;{#$Pl_29d&~jdeUkVOYyQe%Alv94x;ba z#g0b1+QFu<0IAVS+(hn)na$c|5{Bt*suO%5a8@kZ1xkfB4PY#mV~a;X3jR~4{AD{7 z$j|&wMAde=%tV8Hmr&vMXjE?QR?2Gpy}evFy+@xV8~xfd@p5{pLHekzM=eDLsW`bR zdK6!^{uP-D6i>xfyw6qs;-Bzgf`}xxq$$ye9_CcCv_7kZZB?e2h-Lr@e2i`oU!``? zB|?`dE=-1UCm1cJU|HR$7eXA^A5fm>aRK=Y%#zpFJ62Fgc%tZrciuJcyqmtl!R2R; zpL=%T*^8m!@>h?(<+!x@vgb7y(O~_V2XA=ijCkjadgmpb^L~9DFvR|P2h??F zlzIXeE9Fd$=d9`}Jo(R*rJF8`a7o+7X%j2Q|M*+Dh;7`mIcL(4*t#vEkIzB{1L0~@ zc-nS%Ey`B#K&LRx->_e>|Axy2BBR^3RyylqvcM7C2TE2)nGr!ALfz?)f`VaOGKq*| zsR!ZJpuYp;E3q?TMK?8_Oz=a2lo%^QjYR|=9tHSOHHalhi%y1=&bU8JB;rZV&8rtQ zuuxfoX!Aok8wZI-Gyt^+SWXvrY1J_YCFm}C3i7+9tDVXuN)Dt8sRyVHhME_U%eWY| zsG##`GvI1bS(s#Cgo2^UjYg<*yGW16^gL)xQU`%eYXzy?L6m%ZFw)uubsx$Hl_>+s za6v?k9t|ExkI^r)zy1yd%0j3tXn14#ps{|*Bp3;MAGk8_qe`oOABPs3E88bLxw2S95KUK3vUnBi)nr)YGx0 z8#f#wb!kg`uoY528QM4OFEMC-l@K*u|B$$xevda`fnJbWB}gi5nN&MEo`nQc)+l}_ ziNBvKuuy8Q$qF9Tc6Mf*=tlmu8KNKk4wOcQDF3;9lai8c3FoW!*Q|)ck%>Ky8_cj- z4)Yu4eb;3T`QX0eHKR6g94$^scD7A3+oGpTnyuHJu&Y@Kx9XCe2{$Ria7SvRp`Y-9 zV2gGO{v_OboyhIR-sB3t2E4nO7(G(o`uA_&vwP{2kg^!USe<=s##Y74kI(_bj9}Dh zwP-7F(V|17_>L`FB-S)hND&1X0xQ3%DFWgTXbO5<{4lT-?oc*@0@y-?NeJJ~@Goc% zPlyKCZ+d=4XX+3~-+ z>jmT?@`f^Q;Hnj6pW24{81IuIntg>bmKH#SbpL_X)HWR+12AQ;)AHM_?S$N2F>bOJahop$4JTpCg)L` zl;`W)dTaWO3$5o{UkZOHWw{<0$bqrP!7*<^|AvdZhP&PhU!SvXEVuZ5?+kE3Bi?yK zu~Bb%(!2C#;hg0BE${4qXM1w)?$N?M$=p4+JbCAG2XZgEhhndK2YZJ%y>a}K^6lQ? z=#|HkC2N1`S$Erq3T_ulIeF(w2TBJk&&==J^z*EO^N)|^6%4Kzc(UJqE6aByYu2@_ zSvT{F1~;8)z#VU1-_FTYI&I3lF@Fwr=9$b8*khXc_EeU@5+NdOvfKoOisbWg;GYXqb!I2@GzpT|^(PS+a znk=;{0dWzDA2X3II#Gl?um_lRSNkv`9iZV_A~aljjcGbAS5Lpr-1uSX(ykEOD(m7| z9hYhIxHEvsJP}oa^?3SV?WGD6Bc35+D*f$jSB5Q)rc_lru-_62H)da;g9#Iyl2ou- zlIq1}F9=^+sxVcd`Wl;+R_NAIMk6azvD8@?$IP{QoZcb^6(GVgiieR-6L}IX%)L`d z)cFX3L=zHNuK3^TsX<4ZdG7vH^KQuc zlw8h!TfYnTsUEU@vq(hm3ed1aaJ-dmN@Qztg7A=+_D2DRnhJ;P6uZL;fhrD>&fm|S4qxeIWeB*9Z z)&v%H3a*ryQo3-V7G{#R9K9l;K!RZl0HqcNEv!s4;K?L>?xl`u4Y)Rd+E!|;?CZVP zSc`Sd5Gn@jJ{xeq6@S)_GVKKNm6ui3r+1a}Wf)!>7xhIf0fC}eu|jyNr}i)ag@{CE z=6SL(M;c?qi<*>*+Oigg9c6egZHJ*fw+R2^wYYrUPF4~F9QFe?k9KHwjorwqE-;O7 zY-}}K;}oTH(_ThFDF-ZGS$*V(DWafUvZ;ZMWCYwZ4=7QGIa6t6JU>o2avq9-%4)2j zcyRyu?0(nJeRFRX&mVS;7BB4I3ekXO?eeBw49z!?9eA5~Th_j(TnD-!HWKzOZYo-l znZQCOqnYa0DLcKYev>Y*;35ntn=s}Ni*|c0ja7deIi95E5w8CPI6NSEa{3RRJ~fu_ z8*q$ed;3qkIG5A!=PyW>Jvy5ISkm*@ZKoS%Ew*oEy^{5Y?YpkmU2i<|-LBWWhI2`O$(OSN@>#?JdZT#X%Zu zVW`ga(^6&hX!6Br#T(L(2_*}IX|U(2*d9Qh-ji>40O%(HWU!bSSd|37)Ag|ge zc0(DDLya+fG|dd1X`2})4cs7GG;g5MgR*VHetLJ{1=k-W`H~tBb@ATMohHCz0~4YT zgmDK+!7)~JBStcO5(9(S<>nbp0GN^)Es9LHxiu_M&75E0Kp8-DpMB3HTUZfT4s%vx z&Mu+}2unO?UYB5;eqI4hBr za2>b7Gom2jYBRW1RIGgxhVijYO1Le?Gd4|2_7@lf!AKIgYf}z+ZWsnjnn;;d8?<1A znHDoXrlA$)`>wmwDgRSdEzu~+BAbIMec_ju+7^v&!o4F2QD1_qw`gi;-k@ZkqJSfU zb|r{PYcJtN<|M!mYrFw3b-^G2#?Y5A{Hoa8!L%MgUItR?soqCM11N^2xVk7%Tk=!v zdI#7*Yr+PnZEV6vi}Z$IO|UJJl%D#i6=f{2I{!BIebk(RG`XPGNhWn6T?FD{$+Gd5 zwrbSh!Q6wYBtH&bE-6P$fzc~g7HpB&Im9I5)+1BOE!@e-Wl)I-YLrOk7%6 zC!hT}v4%uj)ZasnpU^5ggoMygRZIDEC#<7%C9l9QEsqdGdYR;iW zBrNLfJQivJ3V+j?X_PgJULVP9a}a+Y@1$rDYmg9wm@nnd!XRE;f5|mEJ8+{Ua3%kp z>~V)~kTq5kxHF!M+^0(_U=LT8Gvuv+$0zd#h4H{p!UL zqSNVK!(8h>px89J*BFjoSGHssCPOUI>$ZvkG%A^9jX$80B@30D1q^178@8(ncPnUR z-NY)91)7;;N%-ss5;awX6_Q#E3?^m5ai%{|$bJ~_osdpC4ohSj2z~8dII^@tC)7&X z6-HRR0)x{)Qmp86>bdzJ1p```|8t`*&i*2>zzG-XUFe%&PZ0uFkjNnzqN$ zPUFD;I3!r<&;rY1Q-H(^hQRDFJz{C=`+<1OSUg| zqJk$gOw`JM&WS>c?s1~9M5mf4Ji3aB$_Exx|1}akBdI*iZyBKwpjb&|HAkcE3Ouf9 z4e1}6bzV~|kVwP88SJcLPM8|Nm^Nl7d6MuV4>sX-D9s59MMnT^2DZW)6T*L?$mCp_ zub|dA@sdyxvuV(YFqmVrG)+IMtA?jg=T4MPoFelb{hfqXRW+%o^_#?xkxhVRBL!(6 zNI<5Gn5|`vMYJmplY;cdG&NZY0ZXIlYmH)o-MJL4T7nM8J)O5E7klr8TsEd*X zRS4@q5)}ylbD^l!YtndfvXAZ}n+;HlEWhLu*lsEwr-5E@`d?Y*VXsO#SzGS_YgDn~MZ?^fjg(*PB^CagF)rBt3J? zkO*lg+#t=~2Tq2N+3}p;6fIi_GAWbu7bsSZpn?!uOTji>%H)(3tF{nwhBZ|i$;&5v zEcFwUz#p^x%V;NkV0mv6deC?2^~YK*mRKfv3FRp?N`{4%DKrQ3Tc+8Oxj<~1WxCBW zp+|GT54Ob81H-P0#IeNaoUMQltW(X67jg4&Nf^ECwL|AdDr5dw?*P8GOpdJFQi5PaBCK6!#8~oHzj-Yjg ziN7XV1?$+X#7}_RGuIRmCc1H|Rw1mLxeN`6YYoF1+<=FZ*ip2gLWViNAy~R+RAy3d zE61=|VCC!C8fM6GUX}5wPt* zjTh8ouv0K3%;B@84EYAIHlFxUG0QFk^bG*G7U>h4l0@|H*l4n{nYtGGrqL=p#@3>L1Zlq$}+cl%bTi#Jd z3wHOr;8vSkobF8ki`9!OFUE$qzWUIpZ*kJIm@Gev2A9K&(+e-o;=zM2!TTAJHQ

    zQuaXo`vox6f63ine@g_Y8C1^n0tu6#LNhj*J>s2xaq}CVOO>N@mW?t4 zHJQNvmCF@qTv@IFna(jvr_a>{xdI6|c{=_AS$k9IbxvM%jaJ zKc@2y$+8FUsNYA%lQbiVZ1kVtKQnwl+M~tm!9=hQr zn<04qdaIMpYB7J--VuAsy(6vU1y~JPur%H0kJ%T!$6tVW!roJ%p?JdGLLAAAFb{^o z1m7ux48weyQG5Z=_(L>Q{SjUMh%P_I1^Qh=1|dCO4IOFPeeIq8}A@l9_ji47jHiVb#-`gUFO>>{zjBM=*~K&oiE^o?07 z9e-e3=|}@2CyIU^|Knf7MTp<5Lv0RlCQ!PJcj#jXu z4?Jbs!_eMpw(B66VD>_l5bGgS9rwJsvoCxCf+^V9ad5=yD&Ehr(Qnv5I*ncARfFw4 zAyg>%q7G@QjGhHp!A1`=FJPCsfKwh#2QQmTc`~pOqNg&||AN7OonY-DB(QpCIb6HM z>b+PB&%C*##Z{xe>ZGSyU&FhsYk0?~Z|617PFlme^ff$ZzVxkG>m7e$TaQ3m#8Xkg zop~rd4VY*}GvYjrL^?3Fp*a&jCNNDxojB?;GeeTej`A)5Rb^1jDmX+0R+~bs*i(-A zuw-|&?oK-djm?TD{7x#aOt-~MZ! z{WM1h^f@Y?Azi50==f9HMn}rs4DMR(PMaNK%XoHh?&lPnb}wW{D%dhe=qczBr5#8k zWDrs=q}-g!LdwIbY@~8HCSyV1`pv9zHr65a*tR62= z&x}`{a%sZ-s`MK6A{*FIuzy;PFI#eanR7rsJ+tTIZS4MFku$M5NYGz(w5uZ+Spwaj zOmd7WY{)RKh>^8)b(pMcm#_36+azRXs{+gYdp6bjmoHo4-_#waPz#76RfE_lkHSDv zW2W#O3Pb!&{s=AMlQ7&MwIvt@*gx)pwn7xOJ&Y8`psInnh!E{f5*~qbW5E(+NC!xU z#H|+~kwdIf#u}Q#wf^nl=5UP=YlJa2QuuEHF)7C*;Y}&~u}vw*9!l&%Vml?aBXNKd z2atG_5|1LWl@eQ#XrM#`5{D^qcoUlg_qdny5cIgkNc@5jLyse{yhZ&AQV7!kud`?{ zt{%oOW=)_)VM6bH+&~0R8ord1{G3uAy&vj6dgc~CQ%-Ip8DrV`gT*h-xmgGwy_XgZ&KWwCgs#O?L7dAv#GxY2Wdk^u`u^i%MKgx#hi$KH zJ^xVu7TD(v#?K_iX3ZNed8PJJ@yM(tmqN*zE3PcKvhB*cZ@m|UK z+Tr4n!ph-La@wLx3odQDv@YpemGrC54L5BrCV4P5jADIbx($e$<9#tU|>jvN; zP?Dd#0Yt=}fd8QIMJ3&{tTcDE!nnINpprsjk{ctTzfLYe{U<#CIgL9}h~yz%IJo-E z#-wv5H?gPmOVv+3eIl@U$&phlYJ2Odm)4wGR=c9NrXrOOg?R_X=zu#@2UKXDNVFwN zu`W|?Sg=EImvX>ZDwW3p;TmHh*!hBMB`Qb%7!=PfMuXU9^e2|@Oxsm&mIW2LPTFEX zAaEhDmaUbb6Q??D)ayw&5TM7Caq}_|9=1GBCK*v8OJ)<&`>7EvbAF1yqepL@{;ieo zf^mtn&xKmuj-<>f?~@ zgZ2ldc`yc}yLMP}!%-X&aB~RBl0lxTAfiu@TxH-R>O5bhsCC$X+RK$?uxFrNuL>+5RG7N42GJ=~lvz~M$2E$r1Q-tVMb5FpI zPl2_Brb1X60WJ{9sWpBytsEWs)%ojXm?UA)nwo(AHt6@E0yAWWR1O1hS_uMaTHhCU zKK)J9V|@)jKmDCFtX$`R+*ny+q{xibbVQ>5K)=I1y?#daZ9Qvs;Y$90HfwVT29ihc?g2n1usZ<8E zU`G9%UvHIZkC4HMa-y+iT1^-%LoN;m6(CFTv+l9H?Sjdr={DEChMow_c{oY^M%t{P z*4TS2`v5IH#A72wAR_Lh&8c=pV4YqV^{uJNfbfhH zK%k)MOwUNy%xbSH-I`T8o*7VR;X@VQrYOa2q_JhT&AbgGbk$tc1prf=^tSY zNF<&Z4>cDr6LBA-^1$JK3Ffq=H+NEHtJnG;$3;Ou=3LMOF79E2a*d9juswD z<{rB3qP$Q-a|@DOb}v3?d0P=DZtqq+uQBu#hl3n91>UxUo33|WyinwqX@rC1Og>Kc0} z^qdg;KnTX+saJ{M6QHGlUKrB|(L84)x{GIHA^?a3|0I1FUxv%qZ9+|vkT{?`)*c`UA~S*{3PG$H)B6yK zQZnp-c`JZjNC=ro;Ti#M77ZiTfy#$dA7f9o1wVS`0ELR@rZ1lnfU*(!V`a$pF{==O zxoYyq);{?9mci_yE!PVCm*mlc6$m$3lP|(eK3_E52DgaSctb?YrIjk&v2)n{nx~We z3p*iZA$^xh`ZPvUY90n6m4$$Sl!=i(j{YDhRtxdODqwlo#Qvh`>I~#~fExR!DDGoO zRxH6Np{*UrzEwP9sPg}ibQ^j!!&l<6sCq>!jWnrR$xj|gcl*~M?=;4OE; zg{O8M8J@O;nm48I#A*`=ADe}l7uJIgwHQ$ez=UV2wFj2mvuJz3JFqnTlzf?@D9Bl| zN8grY7mFEy{PhxRvV(tzp)=4itk&4F1;PI+8m)dIn=JtBLV;YCu7fa}uPHUB=8 z#wLbbmTqzhPA`NgLfkmk0}(i}jUiReWe`&UW~T+`8t|*;FzAJdXeeZvf^e1L&KUI{ z;f?&&aKnP3e;F~XRf)JgUJ)?NA6No@Tdna7e zjIl6xl236tDua)aA5KR2??K$-lVu6LjOqt6Mct(QG=|($+F4*;bhk2U{Rh|sf3mNV z_SStAwtV?iElTUbJvMDQOyRdt;2|g_(Fo`!m))&+ZYLLg0JEmE)&j!`%S-TsTFgL= z=>?p|{HvKeBcNS|83Gro_;Fej7o_d}B#hCFM`eF&J6ygXG7}r{-X5Pm9RX2QPmzdg z2bj%{@M1ha>NGy`icfS;Mr)T}3uDezgDXq8~naW!Kv+?;Lt(M{@q2QQY><9rI2b zeC)*slg_cUFP+s*a4m_HZUH%QjHp>ES@?hpc7(L-hXI3*^ZOh zHEYK+%LVI5L|WHmFOrJTtpiGP{)7%_0v|2>zr`fX>XAWn2L6ncN?%r*PAx%62&geVY3HG)T zp$lTELM>EuBV?yg&{CvObpe)@T8;~y^GGBO6`m@XIJiQHRfK#gC*{z+=1gvc3o6q~ zQ>!R74Hqj5VnNV^x2Pa>5%Ro32s(lG_DSRGC0FsSESR9q94qnPC|N#Ivb;Zs4p^Ih z?xBH)a8lXKS>MWiCHK|*zn_ttodeD7w36E;Qr?Vn`v&%n6_j4cJD)dJTsk&u{+PdV ztg3dbay9;L=SkD%jZ0b63jdoUJ1_r32VNa_+5k&oh*RqkUt&1J%omPqxJ0+C(T%4gN>{LK`IpGh!A=tNVp_C%~2l0fp_=n>($ zAUe!~DYuNhS%l;|fo54FMbnuBR1n8xSBbm1PD4Bg*+`L_fA-`J-~18Zd>F}2`?hz~ zS3Bxml5{TN?M3|rxk9u@=pTbk`YYT?HyMHq%h)q?W&xJ^nl=z79b~Jo^eZG@c~j0z0~&nzpRtH0OcK&e^K;=;o2Fbt!t zj;DqLsxA1N7%^QRNpvx5c`zx!S|H@{O~)|moB$&hU`cKLa&Qom=wJel5!Pjz7^-=k z0SnG#8SyV#6eE6O5jb zC=!ZJI1-J@%|ZXb`he<``CZ+X2B(=peg^Fdibc57B?9O*)tcC+Kn} zmg_~+2fK#k(W3HXZu$F&oWJ@^Ptr5<I06S z6xI9e6yiDHxayl;zsPm9(oX3b8>JUHkxsJ{bD{uRqT@SonYbh`8>j`#!C0QAS2iy# zm%a!rp4YaXx2A%6KO6iIXW0p_0R-ORIs1%DAn>^t0Yf8ZndaUE1>M}7rajH5k4=2p zVreDD=D*UEFG3znIgF-f+=S`Q!83`ZXSQW-ZLS%x=zB4r%=cz!R?<0n(r->%;25?o zaNz7U6=ApC$8Z>PYb0rMA2%L=ry% zLGx+cc_j=BDq{=E^k~EI&&P4Ck=9y2$#c{ARX&BIR-CV~Kvb|35#ez{vQPyQUNp}m z5h_B$pph^{_KXOWmKM?h)2=9dIDvwc-(a%9A9cCRx_N}9y1%w5MrB7*b?1{b+ zjUiHrgavw+{FVOdyL5-Lp6adjpXyyurqz)tyFQRO?-grAn+*z|FHAq=Xefpgxap+s zKvZpAsu`3ljm2d?+&RE8m8og;DYq7);lw4Pe>CV^SIa*mi32A@o?#?lZPEgJeC|6JZG z8}@^{=mbk83|wds41*acn?=ZDKrsYd`bKNg!iMvTi`Gb|j!f3kP!JZ?=TKyHJ{QURkLXZHsH1UK0EM+w`#;&HR`QNI%|YYqYqJ7V5vyt3l4ZZbOhRT zSfap|H5*do_C_L%dJvFspLPfma?o**J7EY$hk`t1#3nqFMn9v0h>8N({ySVI$FRAK zPSB^(9Swz3PR;U8qX~`b0BrePUOszdc6tzbJO`fs5f94>CL3gH9c-YPIxul+9vaq zx8OEZx}U}nzyhQ%21)}QrijhxRpjRwvzTTvh6Az$9ZMboY{6$eQ$_a}3GvYZehNr? zeDdqqqx=X?&+y7D6#y0_DnV)}+TPU>xm$qy$%md$70?C5Hk66CiHC*toh86Morbc6 z>06P5=x=U+f?=t8<)k=qmf-o~l_l73aF}~%fE0BUa3igFvjQrXiq|Td5PAjiDCQ1=>U{Rd@|?6=_}#m+VLwpMdSqzz(=AcO*vz1 zK4=9Z6|ki|HgsA}e(jJ0o@b4iA$u{>Ly#K|nvG?Jg(z46mTa)NcrV!DcLBD7Cw4(a z0d8ynH)?Xl7WNQUlnP0&aPLq_dYtm{95iCC8hIX4)5Ox|Mcv3|UnzIArGdsoKVwu&@kc1Su1&c{at4k_iet3 zVDUv~o`h(3`kZ0+$n=GM`^HM=4Nrf?hf~C=EcONt)uf-+k@K&L8vY3;atYfKq_9w@MJLqX}Q3@-8jlixJCxOD1sMPJ*_vaCLvR5CWA9# z_61ViDI^sTdkXh~4zhd};Z%9Jo4ANJI{k!}rZ|0yG&y`oEI2^2;3ZTJdI0Ys8${Ux zm+PusEeNw)Uf6yhdlsW;R>D(w z3T8Zwg`>Ng_)$mVDq^b`7@UW$dL@)}3nR_3&IjQ-n1*!M$5pcg6Hl8P0hN~a29R`| z&%4s{5Sqpf?(f}DFCE}wt!yd;ZRyosP_!gP6sXcAP~~n~eT*u1a0<^^5XyB6#6}B` zJFf0UmM3W8okTX_AG=7JUJ5Hd5gl-5zw@Ryzdv?n-C*}MuYattWpXMT_`dAwtcmEPEYsp#8JUdg^z`2Y~p;LgDZhil#nT`9kObfj#} zNYUDn+_flx(A4d0yriS4Ira0fkO8xyFr93ha*I>VdMd3^{>dCZ8lgb{Atl^S-wNjh8kFG^s!1gOJSLk@mh^KGLS7%7mLNKA*e0GHsE zDlr*VVBR?sV)%ia22#Q@1_44Y7F?Lfi|L}A!FFI89JNP%!s_odbMQn?&celTE{!0O zg>@a9oZ#py{qVcA_GpOZo+TlxRs>eBPH>}iXJN5cIqvDIm6i~`AipfRtD)wv5-m>? zm(be?mO?p&e1cr3F}&c{5%nMRV~ZF9(kMltyEmqVoLN{hM`}QUhGC$NuuvlYFU7** zL!^Uv2&sT3xkjAia3=?Xi62ETT95jh@Z{d3SXp|MAYtHSdx}*nc@8$xvPwB=@v+Nb zRE1YAugRVY0U&<;SS@iIo-4>p@W7*_9stDuf~6B#EU8Gjc+^u_@FF9XV9E*e>7$mz z=Sd(4@{lDN`v{}qgdj=1g1ZwUZV*=Eved)Kksz$rj9d^2u7`y{vSisv)-s4Rl4Uza z^LHjaJ7K6iSb8mMCJPIP5JO>M(z6ggaWAhLnm+3F_ied}qfpljta-WemEs{~SiSVX z>%AlM5bI>k+huQuf3jp`=8jSC&ZJX22nbaf9~vb3jFSrNf}}_dHd$)0ACweF8{wu2 z9|ac0>v0cH4ZVh$CG$IEzJ>Sf^q%ZcvTzcJ^95&vM@zeq&hB<2gr>J~J4U6GPZGc= zQyS_CrnbxQ?j%7cwVe-AfFuJ+@ySU27}#sSq*fqbjXmXx(}4vkPa}-sJ5^j4;=V1`yh@dKm2vZSYsr44&)a@57>fm%zKC3Inl$abVsK8j=kLn`6ChFbU2bCQnm zpr}+STdi_Yyiu!9(LK7nK^2p}hTN0^Pw zaY8WCi+9kj)fS=~8$Q})96V0K64aJ6skR(zZP=X2;ganlFQf1DLDX)I2rz2HI|+|w zpyKGw>UEz$`)yFKBAo+s6?gC%tZ-g({vcRpEy69xWBq&t$k0g7r-#|s%=`4CCm74t zQ3T<-CgPXlh)@{|@Um_0hNAHRwq)~Nvhe~1oqloxxPLB1i`EwmLEZ%s=~M?QAQCY@ z(p!L?U9YZ5xa<)bpt18o7?@Gqc2f9p+-`*OVw*z}3-W8$eT#)AWDvsbvBu5TcIIu^ z7j*AH442MqG&RA&Sp~JAj~VkFL9~ocfgmbEA3ZMEuyliPg;bHC?zt%tFzqDq19noQ z60LJwIz0Y45Rz~+qh1;n2>mc-jqY+`Q_vC_IS(Afs2w9j?IrsfNV}+6m@5P)(}uUY zjL)=~$Z-e}4?UW=4MVJ?mrDgvfuiII42U5oqFezs&7ZKLTTdOCC>ctZDoxJGLvDc) z5#t>(E1`ps8UOPUojBH+`$@jHG_N&=kDqnU&_bFo<3tl0ZY~3{BVo>Rj0n$QGxXtf z%7IoM<{vYPoLo@aOc`(?d~chYsAeO-Hd-1J3sQ{V{cIDy0T_N+1|qwj~LNpoZ155L1HLRAhO=%^Gwo5?VezF zw>StDaa0AG6=77D2#HE8KG5L+LD9D1oS( znxL`6bdWrj?cxN~u>A;)H_re~2bCn^QtM7a)MWxMW*Nk5z(zc;Kx=7uGb~sG6MZt4 zfeI0_cRqv&pz&1M=6V7x3^(!4LE&;sRnr5}Gj5I1Hh=s?)TobL^EEUJBYJY(XD=)g z4r4(0P2f)S!aSmH1DR%9wb7b6jp-w*ALmWXlGPk8y&R06!OX(i{VwxC<=kaXY7v$S zf-;&wA@kB^T#T`7Ivay?L5<-U1sO1O=^0vYx=dMHZ>~bK*;ALYB49+DoUpgYaCQYc z3kxFHUh9M-gHqbYE@bI@-?WP}TG&A5hoD^$M4!_{z`z-42foCiEhH4>lUoFNNu0o& zUdu@d#8HS>Uq&kBgu$W8@%U420e&e59Gp{LTwq%SL3^i~vNdM*O!esj?ihlbyVZ73 zRzDzOmW1eVP}*dda%UrOK3q@Vt6Kf_N8VmFRxsnEY*((kZwpQln^XSAnoE^e4qPv< zdwa|1?D}829A5X&b7vsT&D~PSoc_NjjOzO`@0~ z0(#4K`K}bRg#tFzfRiNfF3{Z?Z8`-_4est~z4ElNkt<6Gl*IpGz21zP`ysA*@E&yLZ znV6|+LC(w|n*%X|4y_U7!g(VS`x*$94^FoG6nOnn?%M}Pmuu3|98o z4b%B6AsmI)qrFRrIt3AgdL84gsYJvP}wYOf4mGXat5{lOr5Yq0N{;TOEMV08u|Qy)O=S>*}!3K~=CS3T2LH zZ0@v{UFHDBZ>l56jEEQ{l!PrZbQ`D)hhDUDC$I%_zp>34gf@r~e?0|srV%4!G-y_> zJ2pqz=l}taGwndlhL+SpLLono-pLEV=IZGM< zqYQz~zk!72bc|r;0OULqkgW#Ly{<@sYzY(~+fD1t7N_iZ!D*F=n7*GY;N7epX{2FX za@YZOgsZ)d7ulr4dA0-?uwV_unfuwf8E5IJ4KzH!?&-2S41zcWmG*b6KIko2D#tP< z5CimrE@4z^WlYu-=E-fnV-@yZgd14Y`1@5cRPtwuv8Rm%{ zmRUNhK8#G0V^x!-E=}4AwD&=pv=(F&nkSsDS1fSv3-XMUWV zzK8-`=lAXWBvy&4PA{p?wte4O@3#LC!CBouav=5NJlwnLv>|!b?Laz2gQN)EgD_OZ}MbJgTooer07jkH_dw5CM38Ipk0

    omN-IJZ{BpWY|kxDH(g&Lov7R^95p7r;q%^gxkr&ZkWRwSJjNpFRw-S?H+&fBIt zzve3aY_stdit@$dE4BeJL$P2B9KP5GxdVs3&?W&H0C+5L$8a@;Brbilk13zhVEd}&UyB3wIS3K2J=dNK_MnY_XI_E;meNbSX#97&%g ziiWr$=`77WOZNhdJGlEC0SD&?qVru5sti!btelXa0Q88f0p|&o0L!JBz0lZV%HI^I zu?ZRVL`cim`ydKdzl>hU)Cf=HGOKz}rFEH`FPBW_>GW#Sq%&%|&!To6t zFQ%JIx|2%|}94C`IC+jdtr0ys~j zu%Wa2HzAq@*;t+3JyrxGh>vgjC=NSiD6C8_tRF4h^sX(LyYnB&D+B?YZ+oeTJAA6? zH*+eb?_}54I=(-rKHq-TYeVvCes+De>*|c$`f}IRau=nmowyI)y15Mp-a(ccB9PNR z1_%!0&II=mGR7jN2Ooe!#<)Oiu%+c;z|+!_1Td+vSv<0=Ib$U#jR=7WAIbwJRx3mJ zTpgCqZZv?%9?ZsCrIXkIE(WQ{B)cw%BzZ2J{S)-Gx(p!#${-+S4=ZwKHJlqL9snMa z>==IS8W0jTgOmj(Uum*qob?1VuvT~`g@E}v+)On36qk(va}0hEg%VVoO(O9p+1o4R zJ*<)PWOGyp-9TLvDeXD*W2~z=7J>;m2cGn=hcrfsEg{Dy>-~*F(8sHDZ<%5LAe})xH4W#1Mw8?r_={^0C}G$F#i%> z2kAR2%e4WtQTB|%*w7Y4@gg_N893Wx#5->&HoQexMt}T~7t)arC5LOn`#7qDa{3mG z70tU*R6SBueQE!dc(SN^v}pac-1Q$gq=K^BF66uuqn-V9u3s9iuFrFjXH%Xd4Mg!+ zc*#)z($V^xE)koXmH0FY>MFXhPXa+UZI!w!sZPPrIVxw7>mo8})adPeY33Y8&lpid zOl5c-=rGNwIzuCzmPQzFr!y8@BVT?O)vDw*D7FK=Z0aPncq#tJ_u`_l2{v`Ubz2|> zq;4Py2Eqn=L+p#aE|B<6h-*+ReKhOpd{|eTHh#ZA%gHea(GvZ1DhHeSfprRIR3-uo z!~O}eM8RZQ*O~x4eXoZ=7=h`;5!^D&Mrf6=7KF$|*4F5XHdBYq5sh;~dB5y4^%cfWd%AjMGNGqyw^ zguOMkloz&dkkBb$i8|kOTX3|oM_A+uB;26BYukm1ude_r$JXH~bCn+)LR6T%o4#2? zYlpX7S~%)k-tW9sOb6~}&+XsxULg*sdTG&U?wk)mtr^vv2(qQXMdG>3(>a{2Z|ogQ0zG>mhPLqq|&&^zsp=CwUS20hqA}N ziG;B$Jv8;MWRb`kYK9DgDVHgiP2asPqfzvkC=vLcQ`^@Tc7wNr_^KTLxof1e9z#k1 z^5#5siR4Hs2`ALAQKu(PuF>tkr^!8ld}4B8YCK_X-=9@6d~kHuVn~Csmy)1p>0rgp z(z4fAU2=ZAZnQLTqcCtiH}Emp8|RTYY3avfh4|@^X4l?fyQ%F$uob}oE*KPGK z_wPUoWdBYH?)@>&^>P164pLWLHr%|LWutU9T@A_uEt81TXGp0)VuIlm=;ee%w!I+9 zc0KwH`QQbA2lKU!cX-xCRpmE?^ zE&!N_;)5ZRF1v1leo;KbCaBvB%Q)}?raL+ds0*d^(^cVxN{!Y|(A7%Xs$p#2_Dxjx zDSpVB=N2*3I0pL@##UnZE6LtfL|4YUY1EsGTl_Q#3U0@cSL z5+dvJRVyZD76Lo7e&_~*2=h+pwxe4-6m4eo{Hxdz5R?wo9@uZ3!>YwsAa({I(TD-7 zj?`FohP&jo3`%u`Mr9JVpNOQ>q@lFvi|{{Ai*=%yS?!`_Oj!gqf5)@FJ=oDK2RHWk zb-G?mpeb?IbNEpp7uqMiQ{N}Z?rm?{QU&4#I+9&g+Th6frj?Fgg~|jUk%lo-`RUcE zzm0rO)DR=pBjf?=q}(|}+lLQc+Hz&#PZqz^HR|1iFkwvV_Y}qhmSe`?1$yYnq?LY- zhJegGCre6+JD$ASSy}1W``O1*eFa_UnT>6Gsu5gdj^MisEF(BQ$b&I)9M#uQVERUr zBA;-PPkjSV%W1^sqL++!KgySK%Z95it-ez6w)?90-Gigv{YmHkPk0kMU0D42@!=n# z&Myof3TXKkiV8*JEoko7j8-7wNJlMPzey3^8;+nok#IzAnlfr4mJpC_APCX*$p~T# zfj5=dC%tQXXR8k2>Z<^nOt5UA08ya&Ch{$@pn!lC1uT7c^{Dr;r1P=K>^@cb#V+^z z85UabQ;o=8%ZLQutu#jDccvH-THV@Ud=FW+(_qZYyt;kK#}18ppGZ2N_(c5<@=ij4 z_e<&=`HZ9vkue5E!a!&W@4#1DC=_Axc@I<&mvWz!5H-W77;eu(=8=ge5^elK=py3j zbc%y2uPzJ68WETljQAw_XmVaYD1zt{aQ9k%ZriVdHlf-Dt4Rq^DBK+Ka-u}QXtsq! znfetbX{gcF{4)3BS4pJ^{8N!mG0=EV#zE~^GU_*Jd6BKbfhloM;pD>9D|qcO3;tPS z#XpPRiH~}BC!M>09ry>0_*BwO49a|i9>_c%$7wuXH^*Zt%#)W^j`~Bq5v8G+lD0T7 z>U})veEbVSKD&QS$VVX8yOJEd1n->#`+}GWb(8!*oYPzI*&t2X<=Wge2 z=bpQIDz{njbnU3`P}Fhgli)TVr&!2uGMRY3M83@u`EI5}=HfS*bb@c=i*KeFkp~|64XFcF3$eww5;AYV^V>TtD zsdIh4PJnj>>^!TQdY_KZtz2_lz`eRR^snjINHWgkfx)%o$v7PC;Ke)~uvq8z6yrWj#Jsk)3^9BQUgRDJuKr*x976iIlDiUPV zJLP$gl%RYE=1FORCbccX(;o{Bf~KO#d<~M-+X1IfZ&C-XTW}go6+h}C1vT2s;VTof z2+YjKEJ+^hAq#iyy4;IBAE=whDQ(xr^rduA&ASSz5M+oF3=~?V`aA51b$6b52^SV5 z4V7(cS8MvibIf9M5q)+eeNHH&2b>C?)EjHLxq<*Wp!*m7Fk)eBWL zJn05GLIgK}u{n+>K$nT?xYWQRlTVAb*_LD*8F~e>egA>e?B1Af)5xx`t)|J-NaNW^wLrY3y#-kx*74pk;+y1o1i9fS2 z{*i6!JDeH8pMGsNEfUZi;h1uzRbEi?ATR2|>TM?=XBQp_xs6And$^@8zl)T3pYiMR z%pHEt5z<3i$QE)!gw^|6mU^uTqD7SKk{@J7@Jh{;9H%c5bZK9)rKLc8ZJ9&*zS5(Y z(hmpBRAUIXfHKLbgX$~CQ4l<@^j^SuGdP&Vgi@!4B3k;q1S}<0WNUIKfNwca)3#Yz zbh@TgZfN%7<*k0bAGHm+7OVEaSZz3;k^?Eo8&KFa;p@ba_$fsWgc@FepAu!DWSDdX z5%N%{LO1YJ_qZP*v~R(bbFR$D#*P_f_uyvYhm^Ptyzj4#`D@?zua5aw$MXuqU6Gx` zwGZlWT2Z(LZ|4-|KpSIrj?9!}Us1R}s7)(gD3MDH)UWWpoHx3Bl>z z(@aIFvo^|Ti0tlZaI4D77gRRn%!bB0BsdD3zk;$zNZ00t_YF733hU#Afx*24dm~>O zEnE`v#0%yRHViaGPL4Q63zmgk|L)6&uoMnnzT5McJ0BJQ#s1M1+oH>NM)P(-$E087 z3NosB6_Km&SFDaztbWk?`07t`4~86O061>!Gv_%xM|3{YtPeDWb_x)&h1Z96nr^!% z=bKjsdk1<=4d5I3_loWo{eqylP22}U0v|rh*YZku3V1}xZMBRR?0(u2%{ol6ts~Z( z?oXC@w^wTKRTgh=v?p9&xZK4$O86*e(fg9f-Aua!l%5w*nU2L~?6+LE+_yZ~`*H*; zq?@Yof68GRx;eS#j9=z1&uvea{kro~0VMUDU5*|yGx>EH85kYZ`I_UlhZwHO!@;-R zU12?d_U(34f3b{h|kmsDe%kvs;!h2sGnB@+ z{a>WxXKqL)JkT+Eshic_w3ph$!}Oxy2IGpOwd{=YJ) z40{SzBbgLu@(5?*)=BU^c3!s1${8G}_BZE+c}9;`n%JhZqm?oL$_IrHdLDH=ZhYD_ z>Ti!`wW~oF_|m_09?8$XWgpaRV8i&=@ek!ksljiiJ@v8zCLu52W5tR7j>Y+uIdZ^{ zIa0hxPD2`gbB0pKOTS>I_zpHQHRQVMxO;M>=R2oHE7y(AZ@i%@3{N2ZEwKqR-9rlG zf`i<6NVCp_gD0L)^f7~h3Z38Q=ST4+#5m8L%dk?F0d_O+Q(>qtD3+R-|4}&z{u9!Q zljx`T?0>*#aq8_iZFbLz3*th(t@;b`F&aNV5Te*1V%Zpdyrcwr)6 z-J7@~_a;oI+bE3Z`tkbA7efvL+amUX-Qm{ItKhPT-=U|tDB%8@--KEIP9~j#< zXzw&`FVLQBDBhlHf3F~Sd$s+&Djnvur)}7ls_;K~0!CV-p}GepqkeM35)&hEO>5A` zJsJwzVR!nv3*rh+Xz;LNck5rxy5_P(6Y}|3;FRYAG0d~P@4IIeKgrZB2Xbkg-Q>p@ z8Re&1q!sWqDWnzZMqKDTFF(5a6t6RMSkfpqPYI+^PzyW%urFR5 z_=Y!Wz{`?HA%?G1H0XcgZqT1A7CRPvlV3)Rbg`_NyI3-_wK=aLJzr=A*Ia3dj`@~E zM-iksoEd2jn-rds=7^#IW+|NSuyAO2QK{Yge?#G9#5q_T&^=ueuFe$GH@zR4J`v~iZ>QL;*3we%`1!91^x5$u8`RSN{2*K%Z5_xDdK{QLO1EA=4^Vz7 z?+$v~@Jf$OO;|95twDq-xg3Tw<(tXdRNqXA5UT$=^;2Pc1)8ExuwKXEnXuuZ7$;QA zV<$jVOJPBh)^6P$0 zd`ecJw+F)OK`!{F$Y|xsx9P2zZl%A?g~rtb&GW$m1{>;2F2jO_G>T{x)8O^FV1R}+ zx9pCShjyLXv1iwgeXVV~6ZtAv)Z0sS8c@BEuz~b+t4SD_&{DgDJTVBeY7?$*Y#M#` z@+-j#y4;6?mwPUwG=d8yu;Ys_ojrCYm~ijFicQ^D=9epItfC>qdNbp?Q`)~1#?ec_ ztS&rBr{2Su?KCKT7HpyM85-AVuo(ouP2(aB&Vz%m(D)LJgu4~=Q;T@;RXSZ12L)S6 z7~9%+w6+F+pAr9oHTzXUuhaNCjc?HSV;XPJ_){8xPUCwt{+h-U8sDe!_b?LK8F3YK zhTuOkAV%X~Xe4Ni(fBD1>eCDUH;rG@aFc>88uMsW(%=hD!KE~o(^y4g4UHxm8)@LO zk|r9FgZl_^=_6|Q65ckd0TOL<>ZbkY8FYyTw_)Vor(8^wyMS`}P412*+`K=87d^Vv z1s>jPP|}^>Bt-cg5lN9_{2-67l2l4P@6HhE>YDdE@&maZfWIjYN`EQ3$*$8>V^ zNw`{C_jl|%(jKf~DKyYn3@1CV_M0Wwn)sfpJ`=d{HyqxRy(Fu$zRQwwq#5zAEQr&_*9Q+fibOgOj|H+cih_g zm8~B*7X8ezc+9bA%uzY!SoX|eGxEcW2A2#hd4?C#^RaR@a&Bz9)q1lv)EUXY6Br5% z?-=&@ZQ*h6+dyTyrIV(*{LYM*Y=##bUO9?@D)>o6*)Xf3$Jc%+!|k4lk_am zi{ts_rXBWpZr3=9M!+wSZg+KWek zjr+#%)d%`p#zSNH%dyhNSbme~VobM|ll%IM{VzuJJI0U^%Pu#G203xMZoPQ(MWwMW z>_TpehKj;DF{5JA#|T?MRMJ&zQ3QJqiV*r+QpA|<=TR3A6%Xt8jJw8ASv0RUX4Fl3 z81snk(F>?ruc5yoe0cEq!0|}?a8=|)tf)5T#U2bo#|`JLV>ge5w!OZ)e|LCC#2?-h z%PNZ*<&y?N&H0929u2HAHP{c%P0}*+N_A%(>Li=`o5E{QES@0`3i!&s-n+fS4YB#l zMy|Zscfaq^!guT5u6tbd_{tA@pY%R%h&3OGt!Rt-+hV?hrX5L)8}3O1HcHCoA3t&| zX|L3q<2fa!*p*evZdj)5wN1)?VcQS9PrOgpJjoR|5}7dY-J~6fm^MIWi*C~^!gkEG z^oocbdrW$T>7B)^L@x_(8{9px8*QLV3bI<)fKgnHpBMWtj9JL-u+MD$p z$r0_!h4(ynJtI{pp5FVtBMq_2b*4nv-XgYS1re>R05bb@hh80SH#Jz1_DNc}HdI<0 zS$(H@s5x5OI9k#a)#jT{ukK`yVKK+B%yO-CAs?74T#!Ul*rv0>HuP@@ACBm_EV$LQ z({sFVzG)Bu#hw}ytrZ{|e1R$7s79V?9oxcJ!aMs9#EihCPof^tHCq8bCd{Pf)=YRIq^x2wa4)_4ZK+_$9MeG~okeApn#_ecEzEUmispceD72#f`R3mI8a+ z*JK*7Ei8oQ!oqNc1rV`Rm^S(q=j*E_N!UU-Y$WNcFkOUH84;SRj2MnGDx1tEw0K&< zh-bh5~alK_#DH?A7oIz^Y|}$wFrD`Y8CDBrRVNN4y3b%LL@B6anQbmRTTZa`n9m zjQ}-`rk#L%K)^yn5Q%q!Q|MGoINK6HGz9lEmo!>3|p>r4&4 zk9x$49s(bP6P0e$0~pkf4jg5E1Ceg#H-P*Wl!gm9wns~wM)TL-$U*T+^Qc=A2cs%q z6fdcWuUePP-LG5RnE-TUnFayGE-IFd|L%cQwdw78 z(!LBtxxA*>{=&hgfu_isVS8jf9%ojbt1xUZQp;YkWf+CqJZ-T@e{sCH1oy&`(`5Ei zeSX|iY}#RuBUJ-7GMJrbx(K1M6`CGGUd@|r`UquB%^<(Why#Li0a?{Yzu&Qt6%@wH z7RDFV!c2l)D_#j(kiiDBtXwjG^2&K7Wd7ue`2~aC0dHi@K&}aP?*vkW@p}syAPX7& z!1%L@L#w4HpBwd+-Ef;uo4!1}gB8C#vV#@BJn8l8CE%p!`y3FDQNEN*Z*03D92>4*(TQv`nD109Q7p&xZo4z=_ zhUgbZuH5Mx>KmyVdR3f{sz}XZ(`)Dr(fPQ(1N#BKf`vZPsvkfVFUF({yh!ZYdSy56 z5*uA*(m*)xe5JafTdQ82bQ$_?4C0st5g13I8U#?j>2a=Rs3w+MX-Z6#HaNJ4QCN`Z zr4qY9+pD*Mf<>etV2WMWpzJ10L*OqIz&6`-t$1F%aZA!w!(Q#nGwlS%a|=v^0Nc@8 zQv!+2H|e48vqQR9uR=X69a#DdGm$DBcYy(UHMEhE%B1g*uICC%As~Yj0hNub{a0~; zdq?;c$%gpPGW!;PF9&)_jKg5bL^ge`CPOfJ&c^b4b(E986z+KzYS=QC!=4Q>y=TEo zZ-thS!U~8;D@_~y)~fMw^YGzTp=N(kN_f*QquYeGM-e+092$mNO{n%sl9jf?orcDcr}=L(?ge6!}9ZN z|5<3xfD3I!trhh_W59?R#S_`^mb?oN4xUn8_^x;XRF`qVihY*J3TivzgzTnk%IT``%%pgYXoLVa`~Iil7Yy~l1kJ3 zEclno)67!*7*nH9u7E!lQUC9B9LHm^;80J=BPULi4=h+rV|L~R082l5qLsU6$0U_2n=9MmjneM zfdZrm6i13cI)p$17J&ql%^)zEyKq!r#LTy+C~Qwr*gl;?IHytwXNtmhNw!L*Vo^9> zKdcfIfD{UlqEH+u3h59E30M>oOg2uV@OX;C<0%S{Pp1&hsT9JQqVRZzLinN#{o}h@ zli0J{EGsD5)iw8a-Nl56@S3%6H9u^A)cFv57I2Rnz6tE$Z6;}0kO4B+FVOR(0%(_4 z+&MpVe)!D2vv<#qv=3j5m9OG=dGU>#-fjF|{aLuh5$$ zb=c!x-|Kb#b!wK0t+Ixg7Xv#2(7v%OXt~`Y8)Dce3^&KJ%1sx8(o+f9A&j`x%rcS_ z%dRs$jDQtOvFRg}9w=rZCYup<>e+gUPy<_LPp~-(Wj#-qi$U&L>GCkho7&i%g)Sc> zWRb3HLRbM5P397+gpt9I{SbP768Hla{wAL-?(l@xn07$p4sU3;X#fHZMpo#A=_2gb zuqkg+)I2IKER&?zj*AOt zi;~JoalHr^i}6$9`ZQdu+0Tdz>sO)Wl(?{TmhaAp3sV=t&?&AiE9O~ool{}S^WyrP WuH~1;a~H&O=1qKoJ~v%*`trZ30)+xOSx*vPgUHMx!`e47pnc)NaK%bra)CDvOg;)=B=z41#EGUy@QPH&wZns?=aP zb(5|9k>7XvF%PvQQ{HT)t91JG>GPdF=R4o|-lKn4US7uG`VU_%hW7b6?!VB3ewApI zrM*1I&2kba@grP6FIgn(h~I?!FFHsSFT}xi-BfIoMmL{} z`AFYt6cG6DbPJ9~1CjA77s4YErR1zuvB|;cm^?bDO_ILI5d=+dNkTEpMQH-;iu1qXf2loP zw?wria9rGCv|8g_5BIK@#(Rp=I(Jp@5^&Hs|CQG+q+r|c7ie13%+Sbdv zwho2lD<1$ITQO8{+qK~6wQVDz3)`-aM=ym(cXqwBV;jBLdUas%^1#JlWZQ6Pba-IL zwvZH+(G(iJ*mZSWaRRxLj!wA-A9Ud_@(PLx?i(BD@FW_alyyuTdRE~}dgm)zCyr*^ z)n9YG*f1$%?5M%*%N><2n( zSDedXn=ma`;Dz6!V%Rw_IxsRG3kC>jKs$Y!AyxLE7NOyQL%AAv#jR0JU??oJ{xTgu zIy;e#C<@n{5lR+>shHzg=e=^4+bUlSE}v6njlr;*^}4LgJ*BvdoP}=z^JUloy*s*?GE8kkgCzM zhOMe=c~4-;q2gl5BGsU09qYNntS4KmMXE)wdN9THjC6ZtI&F$L61)~1kx6_E<`X|L zGkRY75sF!`n2D-5KVg;l>y}YhoF7JO@g-SeXu58RTjE^6cp2yMWU#*whbMzkvM1xK zQJtK*Uuw|kYp}m@&Ts9N2~;KszfC4Fr7l8{gF_K4B|IQSz|DeD#TEf)2dlR#LL@jc z#JVwn!Xs%91VW>sXdn=CYuvm`Z)wKpks~N3xU7wHR!;8ExT+`rFjKc~MqI3GyzQKG zCf`rjbxezk^-Yt)&9Y1l*wRf$rmX|F(u{vIH9l)@{nOS-;qN%u;brVWv0Vo1ycj9q zP_#^9*-LMrDBw^A_qlGhaF7QE^3YMc;`|T~R9b$)|Agncaqd3f>$fP5GvRPlM)XiEy{ioV9^iYN%04XDG6mOg=g6X!qSelA?M#vu^Rm;EZn zh+A&Bh~kE6BOVA70mNRg3gIXYT8r~!%?&O}Ippf5y>;s~hP zKmfEB^Xdr7Yup9U$Qvja!Fa2u`)2!R`lnAN`D9D7Cgtv!6f;CAw@RlX@Ae+ z5Sk(M#(ML1Qys+6V$Oo%qYX7(+3JJQ~cdo}ak z?J4K>MVD6o;yRTu7sIvfjI|+LR*V4NmrEY{lLY`~7dv?#v zp0uNZaD-Z-Z|3!sv)Kf9?P+iOJz?IvHRarDiaTOZjPy>R0@CA#4W5n$?TQ;jK~iAC zl~ZqV&iPL)lI7=CU77kJPs$X|W$Z|w912RlXxOJ|;JyJLaSv)4K-*9ddiNk6FAYR} z9}Gl%W22Wx!yk;&`{<>hZ-|s!U&n8GKS+(xqEsA+M1pcO6dpY+%V8OW$taL;s95A{ zg)+cO2il>NAs*gBx5!=;z+rjit#_y1O?1zf`z9?JNBQL5XC7bH!dG@?I=k-GJ*b54 zS=qg0wR$VEoVC0nYv%ir(O^46jhYk6e zYr{U7^wdY69tLVEF2|%C9!! zS!YsYd=wnBH_#As>eN9%?@*VEC?E&Ry|;ca^@Bvu?cTZG`SQ&m5qsG!$CP8iUZ1wt zC%SL%pWFY$?$3B?X8kk%*{+$cc~A4C zYJtQdWYVaWit`7~1Wuhk&=WXt>iB`PipO|9*V}XW$noC8Jq4_zG&~0KAqAk2gNRJo zjFszD!X5|kg~$yQ;39S>5ydUnlq(@Tv2OsAaJr|Xv*R=4X@`$kM%As4ranr!+AY%S;9xLgn#1Vn_xm^tpn*O~;xnd=2ngLDeF2gmgw zz5#WMc11o!1>1%k+TS{G=D?eW`wpLxyYV*v94eJk5GPs=2AH!Zh<%8y)A7CRRfM2v z?B%%6xV#IlrnIXmDLmQo+9M&g`EbhBH19f+vL9ImQT-TfZK*dwbWWVU=mMP^Ck@Ja z5uHPQVu-Oa;icllZII%b!)H&QI)8W>Mi`0bI1_1FAK42|k7jSA|PjBN4vxqnuzWhFOmvLq;57QkH%zEZ# zgKwJ2MYFvX%z74#WHS2|=48?{H_}a5BykJYdKGIGF+&q69T)Zf*KKjzM9B$QSo$78 z<1&@kH+Gu0uQ7f}yyQkr)R5ruk|DCfOt2QWkrj6H`%%MP6c^X%3+E*4eM@hwGIA+A zHX`{(!%^R*fvZ=8qy944hv8(h5LEtNDTRhK9Wjt6;#J|!xIL-Vat{@!P(Us;Q~gaU zn1ryYq|bbIGP48e6e&)X->ZgLgftJB$?Q@cdga=QQ9l~1*7;FE^G5)SICwgg&o=lz zIX7urtZ9K0v(!I%B;)kldUNW{MBDAHb6cM}JD^OK`oYdiT?=+!+U`qM-CciY{S*7v zMeoM1Icw?W$wN5Fw~kL8*G}`<+uxh}-V-OCZ?Yj5oEu<7CI)YZ=0Z=L9n^Yq>g0m6 zG3{(jL~h6CVo#l&*%AztE#s=!f6bMa?w#z(RIi(Tcjnz>_k48+=Hy+MA`5G8s(tS~ zN^dLd0bM*bZMyx@+(!#dJJU@&AN0&O?U{CFyiFts%t9eL&$6VV}f}X1vq%qMyQi5a3(EQcv2OO&*~Zz zQNsRw-R7@3OZm=e0ZL>-{^@HO?8^1I>-YNRn|4eeoR0qVSXRV)=oL^YVHr>MWF4H# zo33cgR;*y180de5Z=3RWeLGGAsgME1ml>jUzJra~#BtvT)O9N>1#mARrzTtmrm$UJ zST$xAjImt^cC@mMGT|}WMxD-Wlucz5K()o;6Y?;Ah%=e(2Jqb zNK}@$phtu#BLBd9*j6zOB%pDHSiOGgm%mHW7`mn4{@dpY_A}Ggd3X5E@Iu?m>9&{W z+g_nP-IR7WPuu3o64gmQ0&w6B}i*jI4PUezwLFt2W` zBpU2G3m>R|J=sEJSi=@73k0r&rLhsJI|G6D#|B2UH+)pFpT0`A^T3E=4UI-+Y#yhE zzyu1LDb@p{ z&E_m?*!SwM_kOYW(cl-av**Rq@+A=+vyB$9Em?iH{!V?CL-oP?pO1Yu#;T91mZ${` z@f80S|J+(4R%fbev+UmFBc6G0CU6+remzzVySaU z1X$KnB331>Sq`^*{HJC2%O1S+`L54)r91X4Q5$=oILqEA-@e;_r~iTVPQZBONia}P z(n?L9C67(?WZiDDhfi$Ea&%9&EU|mG#UdW%lY=z>qx`)=TEJ00Yqy98`Gl8R5AsR2 ztb=H+5%=CZ@ac*BCmxKaw;afFczz@;(Ji~(A$k&T-#$NgK6&V#H+d|*Ve1lywro9$ zCTC7s7>YB*aPFz59`u5*pyuKNpeY6L>jD!N0_Qck{Gm^xeX+Qw-L{= z0oES0_m|?Y41W&%Iq_GHzY6@h*tkAp7Di=_aZ506C4+4-K#a;7uoTVmGFW2jMb{dz zrGTwQB+Sj=iLDe}h>q2+I)(6=9mp1$)Jeq=8NU+H!qJ-lQz=0kh28Uw zLdKb5Re5m^BYN{G#)%M@ht{=z>%EKf>tCJ}p4#hF#=@esG_`_B3uquGg%-1iI09W4 zUwJ}JHFmzWILzrC5M(fRv_;>yDsG4;IWTxBG$OIMa6}%)XIaeVesRo35m~y~l#x`pb_bam%^^%l}cJ0}ktX5xagIqhst?t1FQVHr7l;C$}-uVuQxP);SB21`8;(ul2cl<7p0=GG`J%qu5krCWWf*%f! zj7dRx6jLxmj7welA#_*KvVJ*QjF#U*EAHlR2cCqWt6p{T6W6#?LQSIPF`}iq!%ySn z-FNrh+4nGt;NKG`Gx)*lrjBIFYZEU&F5gJZ53%aJhE>7g4;Y^sPq|t$?y3d1FYWd% zxZBe1wq*3~_?_`5?w8=#_)AY?s%huEr#t2B{?CreOkE>*NBLG5t;H};-CH1I%D0j$ zQqwX`1EaNArr3|x4f(j zMn>>wauM=gX+YkCr&i~i=cJ~Kx5iRI^paQq=pUcb6S1Eb{eqo}q| zQ~Z2%=#bCj?F~ndldf|GIT}HUohqEq@vA|Zob2w zD$kM72vo>|_e{nqb`|pYkkX{qShIBa+Q7)6F!1+b^vy8br=g&%IP&x+`5H~5)X)iJ z@?t8^eDNq>rzR^HkbD6(`A7695Dm&x^!yVl$oZkF+|^WL)&dp(5Py*a5SSlxOBP<- zowZrS&SdM|&O4oCzIHz3e=U9?vg#uky=Z~gqh`}YZ^qL!aZ)YnT2n%`T6Hx{9Lu!r zObMH^0u2;gXxp7`+pWUC^qXB@?qb!i`m~{_&*8hL@0?aY_WrNOzF^LP&aar&jE_-| zv4!?M>GnP9C~yDf+?VInQKIT7W!#Qeo?AWQ)=bs9+2b?Ev#h?kOT8cJVV|Wo=7hjK z+aZXZi7|31WI0qHy#4vP&oCyc4>2ZgStl=^=XE?#UGGEnM+3hJei_Un|MfhddaLgn zR#CA_I32{FaT&JxFJOk{+2%a#@>)rNO(?J|Q86f*rH)h9Co(+krWu|{LLahAcH~`_ z!S)n~DRZ~zS{2qNkxlGmu=PcNcw7Uv46qdpmg4wD*BY=6z`7YMvD~6-4Op_HJq)(3 z2oR5Jz*3fJ6@%@3VOYvLtzobf&@8&v_%7wB)-hN!zrkwzYh!t>^$hmqqL1Qnjqg$p zYy*R(G@7Do4Oq&TZDg>o6#?RL4Oq&p^)c9kFAQ4+*k%TM&~m-vyuaRV28)*Ja{su>g$uT0E$bf&|ZsF$>+Z!mE<$ zGF~kApsZj1GXcYq^4|%9xCs=B+D2rus_BWUx-x-wCSMCIBAN`dh>mC$QDmirVbxM< zdjajrH1SEd3Scb==8g!-!mOW_zNB+YOkBUr^}%oPCF`nRBD@q`Ykz56@Qbk>2S!GG zNNIv=gEXHAWxtWjKH|GbX>f9Q?BXTdLlNK5*yten@4IAD&Q$-qAGKb;O|cF}KU7J9 zC{>Mh9;F&}DA1iIsI>(}k?y1^p}qKYY=a5msA>ki{vQNPdh7)E92qb5i9U)}-m87Q zVLL@8PfeX#aCWAho%gyw-E)7>Q|B(qw)@`H_Y$>_%Y8-<7Q2kz9-kYBGfMAK^SGQ$ z9CZv9^OPv&$wH`Hg^vlv0^goNlf9S^4#~H-7fo&RJUTFPUzzGhXk=KuujL#vJ(Qu5 zrT}GL4IOJ5UGLd5NIq;_8IAP*e*-W=Ka{``L?)4Q%DG@)m$t7JRh==elp>@ssbM9Yk~ zPQ8}9uR|5TVzUkjla|SnNp1)sgO8nRnmguHk?X0~bhKX=C>0)kh-DUCMjuh@Lu|3= z`jC%U@C!P_6>!~VzQSSBT8pl@5EtXNi+NE=I1p^T>d&cYl}!B~1m2B{aOB0`(uXL1 zW}W4xgw+P)$s zA0O&^6&~4vk;rS1W(EWYJVlP-#5lq7J+vxL@h1J&|#_ss2is{Lf8KwcOOG>Y+wb(%|z!e8F}4)qvK zstBqX%|r{s0`meVbO?zFenj+CuUqt+0iQNc}+~*4LbXJhPr>E+`AX5T78y*j+X2oN+F= zn~`dg?7qj}+5ObLd9kqdsk`HODFBzBc;i@*BwOuRtfW!sKT=!yK$*$6f}gj+Ll|p6 zPd{QVP=`bKJqUgbG6;VZEG1u9h8*kaMgBI4In`WQ{qU&nuT>6@+M$s!znx)zaRug_ z*NpV5wB4Uq3pVkiPD|{4h7wciT|VEj@CW#* zr_8X#8hsHh6Q_)%6J0PK7&YS8IQW?j@|=LjAqK!QA$<{wn{^r8@hd}yT^6~JO_=kK zu&!9c%H$lDHxV|Gwg)rx{rg;sVjE&EVUyKRj$y22#nt4wlDC+zXH}XOFgmk5NU2*TTmyX=nd0Ulx;)*Q z{=I?j!>}kexUI*65k_>&nJXRdLgvam(W_XgsW~5GKKoTRR%Kr-MzAxt zvH3h~)r|#))QzPbp5++JsarN<#vw3O)$_khQIY=yz^kZhEIP3pvs)sI^oANcD9}03 z{4J)TF})S1F|+zK7?S8;ugG7bWVhq%WyveXHtY#aiY;zT)P$VVR zy5fnARHBklgRpKUeo`EN~8rO^D+15LdTN8i%pOw zuk3$rEfxI~o`EWqW%cdd>iyX9e=q(Uk=0pv2K}-%yx5u)?>g={D8|yN=ZK<8Iik2_ zZEo>2pEyTuEXv3{%|EF8y!x|hwf?Z1vNKQf*%ltTrp7o%t|?m8aoQ-_)q!l(hC2-u zQR;YD`RnR0Fbb-VFbHm0dx_{zo?B?$m2TZd38Vf;mA|R}5`9qp3Vm?PdaMXiX``U3 zkAfk_8k7(RlK#+T-NTf zJr}s+#qE!@z#XbzMJZ&qogHVH(M}ua#$T=25IqLRWv4<>Q=QqrMvzI}Rm%I`dFycC z(6PgZP9E<)s#L0-0|=c4Mf+Q3V3CNA8bpIxbg5RE4|35jpvqk=2&RCP5 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3d0aee62948ce1e455bf466648280e6dc150894 GIT binary patch literal 32074 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..618b88f2f33619b7ff87d051b36beb90ed799128 GIT binary patch literal 5488 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 DWqC$f literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c1b557b75ebd2b13f5a427c258f972ae2e9a3076 GIT binary patch literal 7009 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..561d59e9e4d02992b1a078eaf1f445dd31982adc GIT binary patch literal 58271 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2d97c250501c60349314d575ffdd7510722ba502 GIT binary patch literal 2687 zcmaJ@UuYaf7@yhO+xwSG(&l2));|M{#;fh6twz*HwXJDwB~fS)dZNqbb}rfL-p)C* zmw%p8q+t4>HlW0U*eZgRD)v#IM4tp-j8z*J3kC7Px6@QCee#>x+axW~ft&ee=G*Vj z@B6;_?)z*ujbQxp-8DxT2>m8E(SW@gD<8nJh-_3uHnuev7d1O(>u#*77j=w)j=S-y zQ8X~3TBW`9)w+cnz+2q7Sibhv}Dx< zjYJTefnJaKQn7D=K+AR2r6{qQ<4q99D>GiTe6T^80J_s9R;@WM$ey&6(Pam0QwFfQ zzmrT;QnEZL)Ml&lTD~el0$9@1;AMdvVjR4*sx_DHBran$QujD>U8!2y=Joqzn(-6h zP-u8~O>M<2($mV@No$G{ivT!f$|;~Ht)~SdK^DxdE9*m60LCJMg1a^mv*7a#fKO>! znJ;|CLA1m-@}JjTDhla8WB^D1fWVDF|e& z@06l+Rv}Ik7~_`Yg~XA7MzSWHDe4vSMv!_oO8)=@QYA=NE`17g32G3Za)jgOV>|(8 zT)GpaRtrW*7(m0#=LaTPl@8RcJ#*u*Ozk=`xU1~&>a@k_F8H1ffVQat*BKwE&H9tf zd$6!)?|{76RkKPbtO+UxDvnpN_71EHFVtp(`R)fVXCC@Ne`p2xQAtkGh+?ub4<~Oxj43K& zc&ju!VQcVa#OxTnDe9GrJ_%P_r^ZIFl^y?&bG)&fa&jJ(v2C1cD*`oxiz$e8lFO{% zDVT1_N0|*OA0+~dsDT^E1S%Y}kRzjctm2Z_0$otItTsY^MhM>oOOP~8$8&tsoZGw_ z>_T*QCvXVq>`An|?Y?>a=VUMMf~^X8pj&)G1jY#n^Pdn`Pe9z5rUW*@W@h+g(1uYaZ!ho4zd%}queQ(s{Dd96rt)!CE6;^VdzOg{GjYp zL3^3As#*7ZUWZ;|2T4nqQ0Gv{+dxNHwCN+&8iO7-?$Ugm-yzRcMfXZd!V#oQv*cPr zn5K|1g0dzjRsQh1U^~~dmO8iCb`M;NvoPIIRoU5ndU~m&@BG*g9YYtM`mtl^(xIh} zp?Up!61ClN#(sbJ+|jc~f6DYXwM4f2*Pc5UUs-tNO3$99o;}OC-o=rHkx$3Y_nm+F zqy9_&<=o@T+wM6xbarT&^j#slm&opB0`=})L3;1zCek-;Zg!&1+BcFvqTzUd)7TWxE$6l@9$h%vj7hrx{!i*3 z)_bCH=bcRRyAq R2d}qx$F&c1f9kHIvIFZ4wGjN@GB9mQb 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 NjYXdt=*&Rk{{ud3a&Z6v literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4d53df7c6e81c1f8b40cb216c880ce8954628688 GIT binary patch literal 48889 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9a7f18885ee7996480b7e183623ab5b0d2ab99b1 GIT binary patch literal 18105 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..09cf65b4c2056f6e8111f7e8f681002ce598e38a GIT binary patch literal 9048 zcmcgwU2Gi3k)GKf?sAu;C`y$0ui^inxilqFmZ=~AP?W7Wp)V$Rh?%>P!=0wM)b0+| zGfRn-0{EQZjzWSnh2TOe2q5NgMkM&*{BRHVdT#;pvbKPWGZzB}a`)h;o0xex=;^-d z-q~ILEY}7OH^6jPcU5;+byZhY_iwAKBMQEM|IHVPp3{o*M{0OqCZ~ei->e_CKN&~`XM-x?0?CS0Xf^~mXjCM_smj?(0f&;2RCG3~D$Kv!;7wns zc?Iah$?8I!9As)S&MK`uxj%g&934H_tK9 z)R&>D1a~ z0Gie^G>xEXD?`%+nlqr0yAd#&(bkIEEoirwnWGgn9c5_RK+{=<<_u`M%Ft+_=`Kmr zeuRxw7#$efQ*x}d$4=1nmZ9kaOQMHx6DS8*J<36L3gru|0p$>DL>XgED2G`y$`@G+$`RIz@+@mZd5)byd7fz~M_D_{ z3#ORV!}D%QEky3l%=b)y_(y(llSL6nzS56Ua759L)hfbtclE`P5ei3b7mYDvs% zB{8o9GwaP!s4?4kNz651{;ELhK^QYp5_7#I<_%ze;LTB}G25G^FdwSG%ok`q=o|Jf zc;gB+W;mqRxbe&2hwALvHDCX?)-SxCNhIx|L|U_1Y9*=L41i@@TE=3Ab|+ykY4#G+ z=I0aE{JdtaFs|Dsk9|ptO!ljeUtfr$s+i2A78w6hMK_w2Giie@CeqA6qjp8NtT~om zO>i@vVrd(F(TPIS39jnN409?tvoky$r#ZaO2f&Yiw+_XYavx!0y#i+Ky9IYWrS$vP zJKqtbG@ECbmRJL{JR9ar+g8u-5h!F^0xZmYBtcgi$3KW3fomiSO#umyb2R@ zA#ycAH7KOGoS1Pc1%E`!PohmfKTZYhvExr?QgIsWeFs!%e)z%~M{=Q%KeLEYxs&G} zT-t8`B-)$}Gz-r6Y-Ips!fv_%Y$vY*${aqwC*2@@kB(QFn`S~(2i;M?iB|9ut1F|S<+$$ zCn(r^+O)MCoB2g(SlR$HSXgvUF&uLo>#@a5IzBcJdOef0=e0%n0>-sPlS5xt0uF&` zcl0&QHZ_acTE;uoViHd>D<+yxeNF`GPFuE~jx&x^deHQ$q+;bZ@Me&-;kU>H-&6kF zqSQ8RcmGr4vtxtV=wLQ5c!XX%Fr=JbNvrEa-%i{r7L=UQyta_B#Rizz1ujJ7CZvmT zGO`0Frbe)xm!7wRXc)gm=jlD=Kcn@V?3eF8i}q#%y}45auffB>9)6TaYIrmCzOoEx z|FoL5e$PF;PPDTMIjhsNJz3{J@s+gPwCc+-AGiZO;T|(nDh9p6DZzO+%~1^_~!W5 zTMysLM$cpeXQZv=JOW4*g<#=BzLvJ$->WTJT02Ttg5dvBQ%N&p2rY@3_v47BIJoYrQFY~Akr6WQD6`EK6?fx%{zw=^z=&9^p$XB9tXv1A8=nsnnjT0w|G0W zw*+9b)yqqfH<*sT4RLYNhf-nF2=~3Q673sD3I|I{q-}N+30^+D zl(r>geof%V@ng(^Xe&)BHyeKubnEynIQ+Zl%2T}+$GK}aPy%imQkp+tL0w?#Le zNw~amP{wzCy5H~klPv8-=jLuQ8`#v`oKrb*H_pU0<-l%LixBNC%HM!czs7G-OhA+l z2ZHr~2uC+2ej52KT>ZOn_0E{?DI7N>%+=iW;o{{jrm-AN6yQSiOI`N%=)( zkN-op$L|Ei(S4BFduK#!8CYIK6M|H(Skh17-y=BT-vZ)ah$5Ffous6% zRPsa?D8iP^M@m_-u-3dCA8M^5d5t9OUQ1gsE&0|2bqKq|ZkfnHu>CoG#bAIwCqPK2 za(ZorO>l1V5=Q5lE}sO$|3=bLh7O|(_{r$1HfDYrEn{oZ8s+aRoBWT|Cja5#f>NNp z-q%ozJgjfMEiWP|Pd*btlgx_iD~QQXcy4aVP9^8&=r+8hTcq{_@WyEqo5bJiA@)P{#89z)g~Y*6 zr1=amS;7`4=HnZevw_n&Zt>3Q1n4o-i55K=I-%Sfm{Xa5ws9)tQ-Bko*_{C0yPQz& z>f!{&fdURGHnIYl%kr~W+X;%S#tDjKz^RZS*9qm~k5eJtxfAvrl@s=?#|g)A{Ky4j zm^dv?D5nX>mq@Ssu3T|^>^3@YXY{0PuKU{2k!H`;tB&uc?L=?l{K8(zkD!CC`>tN; z4?b5fJHDjtgp=?wgj)Aq#;_#oKj(zz<_t3qw;J}|>YWOEjpDGQV!pVUOyUZN2NjFU z7%Q2#I2}wU#4~9-k&>@>5ZF#6Egm9F_4K=cF)=s(=EV40Hzwb3qD9a7;+>1rdzcfT z-4xH>;%Qkt+dBT&(reIc}zH9S?k5*bS!}9ZykVQbBhnZc&k;;tmQYI6W~nJtePPl-G&( z=jY+eDbvU#*;W3x=%XyvGO#}gB&zy*_q(*&VTYVgS6m%7U zJ6*d}xg9>WZ@c|*_oHs2?%NSl_u+!=t8;xdsf@7NQ7cCX$Q|&hjho-ynt3=w3pH-r#8#sl395r0TL6hIRBmk$qUl@g zA#>4g+6hp16Lse&0Z5aea_fTX+iGE!w^cdK+bUtY3iEWydAi(MA0!j|qiq|+h(?=v zNLR<^?XAqi46)p?bCM`Kh~oa0eumOY}{~zfZPftSeHG~>4vBg zR)RGf_uWc@BTBG#v(1eXT%`o7H*UGr1lK6RCRD>r)G5rWSW-1ouYgF*Kkwa*vYqtw1Y48C;9sHkt15PW^WxT}hnL*fRO)#hJsu0= rqUTzn=T8%&=envy>S)r>P=VLaY8$qq52Id7c7F9X(f&QdmI8IFNcp`E=iJ*+Ugu}p6ttN|9Bbuy_3ysc25GDoE44L?2{9}ocQg@ z3uJoZ8Ey6?zgyMa07y`t*-g&2#O^|Mecrlt>)u5WDP$ceI$I=CS~J47vo;o% zLiPd2SqBSS5O$t*vamJe8gQR=vv5(Uc))Yk!@{;u$w2AZQWh3NWoOF*mi`TT1G7(6 zVs%%XtuzTp(Vl&yhZH;Fz51{0Q*j`EbN06$>NBlE@VA}sn|RFGRVLv%L2HA?Xwq_GP~U1y|Ti`4tHtT~T>hw4Qh59Lux`k&2tsRhs0E2V)| zN?Bl4pQMz(A)Rf=`CWnEjXA$7@q0aMdllMV9T57DEHCkWGmksFAtz@IayBcg3ik@N zx1jb~q-j;C=ckvKS~w^5PbpJG(SP&Uz4T@X|`ds&Ha~_ zw?f%~`2OYbhz%`|jTZ@mfp5E3EVKE2k>@@8lpUBx|CGZ@3n0|G0)(DsW?pnV1HtH9Gee2F&}p6ur=o8GY0&QDNmt?qswy#ICP$V;@eKN zZMTNY1?bKSuwx}(6fw6L{Q(^Ipl4lx)A1D{v3G^CR-$(uylgfW`;fN)^}`sH^}n&a z=YaGxXiqnT-?M;Umkz(P2Uy&G#C02S2U*+!#2qx^4h@T~CqAd5Pqd0@v+sf*4~r7G zG890->c12T`YB{rePIQE7wLy|EaJb6r>#4p1WpeRQe4TEp-3#y)2BuTdM*sd0@1X1 z$cuQ(g~(7?@#i*Pqv68hdc@uo0s^gFShvK0xzD7SFk2-pY)05JEVWwFuAbw;XfznU zNY$mSY9KbGhW*+sGYTiVxhSzxhsC?56X~J>p6jk~7tM|aLVZ!nBR@X5=~84MuxZG* zC4K>qs~wkjbo2$)foncB&=C#B0-LS|!dEwif)_Ro4#zG zbW?vY-0$1EX($#9MZJT=Xc2dg7J2t@Y~B)zmr*Zll72r)CiW;mJKvOOQk@ zqgy#{yy;?*5X(tXiI<6baMr zU^o^~!@f|DA9#}%(qf-lj2C%8Amm`fNb}&P5W}5c{W{v{5qKtq9wRm(oDy0^-|u65 zzu}8U<=CZw-02S?*xCDSK2%#q81ial5wB&lMSN8FA82M;S_Nf<#1_I%jL&g=0 zuo9GjKcf0#0Y&Z`3j1ThNLaphDG-+ZzEB8}*DeJ^0a*=%m4FK5lznn6FfbTG2Cst^ z)9nk(7XtE76p4{nFC^M7_XR_M1_GE^$Q6x6wJeAGkTNtZ_x5Vd^aidnnDI9E%E71{ z4g{2d(oW^FYC5Ul&fY=vwkI#OS1wRo_-as%gsH2&R2nNGr$jlgw4B6R1HE4PDq0R$ z_!P9Fvs2#Y-R#}WiXqUQ3;+WDKomXjb3p6eMs?KNY&?TOZ?Bi-Z8ZZyY3#bxi|HaQ zYr2??T@ULTM(D1n)??&z=Yos9)6%QWcuPEKlrVo(__9{0k?&VG&sH~&cFju_3r^SQ z^9(cpm!jRl*({~Ee4#TmM)t->PDp7 zg};1MYM-rc|KEv9wNFB&gE=rPOuaz4*ccQ2`#YdszXoy0L7wF!n(ZeilvyIdN7R{< zyYPUP@Bz&hq;_B|pU)Z3GDaHOW~TD~@g z^=nfU1#Do2?20Mi=%*ET$)#{nNm9Tl8TGn|Vd6kCM=td9CDvFbQ35eYY>C~D0G3#q z1nf$Pil}pjsw*KDT5?Yb!$Pa+1Os`iDP45Q7xl%!G0>dCZ?iuXRW~6Vr5a_K&n+8c z3(=T(sZQX%dem7;yau;X;WKC1#I{sT%e=F7p}gvTdDCopQ_9u!&{M8)Fm81<5~`G1 zt-~!X1;RrEX~{Pfi>T`h#>WTF?TPIuJZW}%N z&{C2yNtTM_mW+VMROx%QcWS4P%+~Mvf_^WW1#9UeO2C;Sswr>%q48j2asYumwufSu zTnV9{#&F5?zBY~`*dk(u;!VeW>Sc|=(U})8JUSN!7K7N5R6k-sGHv@CI zlsvlhZ1i3wZO8@uMM-SIz)7X|rOH{Ua>94Bf3kmGs?RR73>)(LN^NI-r8;gxiv|6Z zFd&YIq7WnYm|Y1WVc;TqWA^30gFhCNG`NIBy>}M7DF8V0OU?0!u z1^3DqhGKFk5&>Al5R6pLxUkCnIh-Dfmi*fDc{J zD7Mjl`KnJ1`YwdPG|2KHr7{S;;*n zF4$a;%m{Jb6e*0$Xzw{h<;)iWdRP(qT+@J=<_@TW-N<7E^ko6>#eSy|Z3MFKY1#0} z7_B2D*UFazfx#@X0E%I5L}kM4oRyaVq{yMbb;tv3)&-)#QkCN%6MCW~M*-t`p)@1I z%`y3s?0=Flhp7PrD52bbYrM6kAZC>hFkV@`LRkKpn&!ieYC7i*5 z!H61TdVsVw3h^}@^Am>Y7qK*Kc6^4wP10P73E`@sRsp}X6-G}=PomyB&v1@rk!i#n zZc@xf9x7|erI_E>N;-$P$RQz*Gne-3?@tLaXk7V~^WLOLij**46yK+{1XseWx8an~ zD8#4_?26IC&#pexdO@|)EQpG)3*QokrE9`<^S6X+BCtM*<{V~lVKZJ^SuXfAsof_- zCxWT2uPe0HL<4<8Asx9ia?UUnZ)6T*EKRXXC@>1_Rt7;dVo_QKqEI|>$`K6?1VcU* z#dd+ru=-gZqUWqEXbz%-0e`SBh!rjXIulT_Rsrc_q>;eN=3^R(mfqg$10iqJcb)#Y zJ}MCP`vwEOy{)VuRLjT|7LZ5?dI+>h>!cD0p%oyLa)DAhjZ(6@37QSP9B-H^;ndqMNGFH2D};z^!BB`4AH63c;Q-R{C7bt=wW!ZWS~I>tK~SZvof-^CRl?SGmhiFI z$tK)m(Mu{UOLQ<4jHMmwpihkjsr#hM;sryORfIW7{Ak*Fn8EX)sz%gwaTlV3pauc< z8|?83Acgt@ZfPsmgYjkOAY!7#gU}kMF|Tf|aE=2i@vCo9vNv%X6*5&0OWA_6c%p6A zS+`KzbicN3wzh4$d!}@*cH8*Tu|t#H3+|GMqqFXH3w15`>$c6-ZJX(yt9xqv#Mq&U zuF2?U<#ox+bLAUTu8j{oRX>PNZJ1s^Bh5r-0&~@S?)m3D`%||4zj)xPerIjU+46;8 zvXp(|sa$ZCJ~9g>RT(pWKV|~z>-)NDg^$D(47AV393xtEsE)j-~4 zr|H8cJM}7$?aUh(lyat} z$Y3B0TKWpwsnXh+M@x(8ZBMYThgYCpK!SHE(R$pVH?j$?;v2ihciq@GzAp)pq;bJh z{+ZJ=VN0%`bFNEC>-a*QOA-xeQaQv}i~=T!93AG6po+t$m_ZV=&>Io4JX8K9mtwx$ zg4TQR*1F^se*REUq#v11(b8TZFWy?7kWT_zZH-Us<3b}qSRzMq+3RM=574-4d?=AF zTC*b;!@+n!VPir{`A{GR_J&b`EQDMK5*zQ;A>faowp^ZTWt-9g!AyA zgwvWHO3w86>Ln!k9ZL31+%Ur(g3USl+5#q>-Sq?8___tps?Qw7W6|%mj&?sRa=iKN z?|wU3`*Bg@LRsa__R02%waIHKPjkxF{IIz6MtD4&a@QqaOh#`fZY7f8>E}|;?I~&d za_k|jU~_RT0y%7+C}OKR0X))Y8i_-3FW@(TIRgGfqvS(05{B+}5DQk!I|!&ERj*g2 z`3$C{NQ;4}ZXIN4RNDO1p+n(Z=&+aU_94CT;5I7!ztY-INmBpbo|IJ0`r&&P#k0|T zmEBv|ok(cQrC4k*`b_7hO^IvQuATF?%5tL|1uIF2hDGVxwQSOsSI%8)>NwwqRBf%# zu!KVwl*j;tv1}qEM5Vvt>xiF!ZEO3^Z6lN%3wF>i$3h%2DM2DH`Sox|2h~AYc0A3p z1eGv!_BlEDdYR3qHHue4Ez4H4v}yjxKq4H7B>?yY_GS_nBUcj<^&)=vMG{!)S>N;9 zm{X4ds2mU(tbq#{wXA2E;uWu+JJt5=xoa3AZ^!wK=e*~xwXMfI#!gMT z80+^y&yX7GVeCrUtOi19YYZC#fmqs&6soU>qgB+OyG#-P$0pSuBKA%3rZ6skw_Gu0 zx0MugHrywTiG89Xz2O?MgiBUVrC8pOMl4w}UWoWA)~sGFyDat_oGIF+UD=8KzP6a? zyzGcIVNzEqMPHNOq~`;{xBbW*78UzQQNoOzj<3mS@ZmW*Z81YiOjz}j4+s;c^VpGN z9KLwQLHv5iu;LG^cTT%VOR(fp+`neKkRFmyaX)PqgMxIV z4Ead$x8zC~`C|3@t882xQ6uFTAva)AUMs}0AB?eZC(7BVxZm|B-FP75=}K zieEA1@2pU3rP1=H7^yGWRk)8z6~V+v@77vb4Lo9RSgR~()peyN;ev#HaD_To>19N> zuaKg~NYSX&qAXEe_jRq)bEpnwHG>J-WwdBhLi%n;LIS3M`5Xbv5*3%R5f&BSvKMYa zqCzhZX;v>E53OvB!CM<8A>qV0p|*tkhr*A{32VYm`s4}ITiYZ-vG=!XV9j}CDG`{T zHNM>-=G~DncA;bPnUlvzO$F`hbtrqnP%8ODL0D)&>j!mc__8i!G9@i3cOW)rd03u= z@-yBR1|CC9riM1_OcX{DAzH7P?$|-ACzkj@H2?#EXb=i4&RjuuZkMA&{!1iP`(#qO zE0JqZ$ObQ{K3ea<|N0;cLuTh3FE^^uWZ#z~q@#yO-rGwY02rm--gfOr)c6HH$;;!x z4TWNnPWnM?a)5rbra^tL2A~Q@%a2jFxxkNgF$gGJlm}@CfcH&q0b?ADD6l<1e+GQ? z3`K~0WCcO6hE52|zCg5<)d9_vvaAS_o>*jFYEAQ(6%nAi_J@X8b`mghTH%!sQrl&t z-CSiC3{!fpK)i&Cp_qX7BcuR^(Cy`oog%l8(4YwrTte*a)c~Xw`>giXi=IB?_wV&b z28VOwpdite5a_pWfT2;R{DK<17{oRa$111@V_-t5yA0caV}w~;F6q?rT1V7wxouk`5JmdCW4VJz_|qaqrw}gsR8f0kD}WhIfpF zd%it!Apk{hFoJCohFRIYVL$d^F6yQu>>ZVKn)NrYP3QuHZ-6vZ*Jy%~$;q!+-gAL4 z)c?>f^SQ;RlQ!cCbJ$?&T793^v0t%lYAagCWG)qURG4o8An4GbLe@gw98j_;nuF$4 zq0wcMfwXM}KHA3o)|(^0CeJ;h_O{junHEN!?L+Z``$d8KuqxBXlgN%6b2 zZGEe`)$~|wQE9J;LVHx=y|6bWQCaE;Rb*o_BNmBxk+yck?R$LkCD{G!ZD8r+(w09Lx8!Kkkf z2ANz@oVL?`JezZA3-k{DOKHnRH8M1qHbVuTw&4~fbjQX6c01@Tqb}I?fRSh{ZD9tc zX*0HE)0QAMU9YPooMBg*nhoVl+QHKEGVDEUW>K`%5A8Y{7(!}>Z)%uA5xNc1jYcft(KK2H3H7)(o)AT80d1GR8aQAmjh${$ky0p;hF_keb(tSda^WKF`h zIeMTTq;vp+(!-jMelk@@lx#NTUYdJLE*KGknBI>M zrrEWdW~_5-ccto{x+l(-b^f$r^yp{hYm#T?%3l^e$n zL9ym4yYbBUGpW^k=bif=R8-wOJb5^^cI(Wcxr*Im2S4>xEL5+#`P$@bZ;wn!3#-;m zd8V4)YrE6-`2nKP%GbVztuh!pR3(EcJ!gAHraPO zbSpId)ZE(bAA7bxEU5vAs#d?VE&1B?fe(({Ju-8BuKn4$)m?Ly`(dZyZkZ4l*2uSy z+&VIKeQwR>-`h5G{a@^zUGwaO{b5N}a(yyBWlz;^oGsZnVO^+Rojja8lB#Z=lpfiU zHB*Xqe7Qz&RWOb5hIwZ_REGCG@~lUms-5?=&sgto?wZ})^K?{59=;0KYrk$Zg~zWCwEd;Rm?!wc2& zRMnJi+BCg$rhcYjx^udHMoCrf9zT=;=9EnA96!ELQG36lX||$is&Brcp@;6;lpCbF8JiXEmqoy; zd{y!#V9vDle#_IdEl=Ou@Uxb#g>@~{RnxW^ai(Ra_TJHZdw(kabi+?;QZJrK)x9)% zC}W|#7~<;H6E7tXC7+r)FtsyPzH!Vl=KG#4^BoaLnAvaAl=KrjzPB$Waf{=$7{(lq z4TRKxNVCyA;JfaZ5YjI@0<_jGeh8&yj-FM*=Acw)k3$#lM=TeG5o=bZl3f)cDE$=# zr6R>VVpF8+;s~ioEF(_*xsb;lqdM7@&7GrWF=e+e-=|dzm;OY_p!-biQan;*7h;Au zov`R>pfZ8dgakCzoNz**6yK^y*wnIwv;T>T7R5SZOB83@p%f`LU0D!^;w)ijYdzF4 zBTU`HgndWCsW@23nU~iI)eGsEak0D(mKSL_G?2^9a}kW7dMKdaNjUW$iNae6h=Rq1 zR6Gf{o@&IC@bnX9U2-W7J%wsdcod7`sl_odrn>Nit5(Qklp3`l4{xg{VJ+BBLpgzV z{x!r|F`JxpKwUn4vi8Cv*BGmr`0Nzf$&wkgy&QbPUw{r9Z)QmB-r*HkXO8 zA#jBQGPX{JV0;AjlGsYaC|x&QC_VPV$%Dsx4u9j+nd3b#zi{%vsncwS;KZTNX=;2< zYRb=PIMvrEL|W9(Nr|R$F7oI916SPSaHt8y`Zc6QP!J%R3)}FwNL#E&VWUE<*Lmox zMsUg_%TgAyEri9FRuW??&Hq@uDFVdnV3lL~=Vt8Go8#s^gZqf78QgaQ{N>+673v$f z-8H36-p!n;qh@P+w~y_6EJT0h$mch0}kg75L-Q z?wKnS-NuqxKUdS9s_vLRJzutUwzT_~QKBrbH#Ui_?zA0pBA5Ye^Q-?1v5ZSnzfYmR zPd8#iRf101fvx#q3~YTIoRe=5lC+|}O>f8PMx9DqNsTZx*jl3g7RCLTZbZ)1cj?B8 z{{cdD5+(|pF3xzApsO)hhv=MPLMet`q<$BsO z*n>^(D4jZ4!lr0j;T45osQxRY_Yu^{2p)DQHo?;I&{cQe)i~>FoO3me9$avHMh|`F zCO-a~UkFW>I+#1HUYD}fEHrIM**1(hCeCAbbxh(nSMivLb-G%9*Ya*~#yoRsZo|`a za_3yt?k|LL`|9ySW8D*_3uRRgs_T*g#u}7YC%6CR9uzroV4-4F#x9gsKXM2qG8XBZ z-JnmNZPb7fLFU z=1J#-#FMI1Tjwe_%z8FV*M02SxzMpWRkC@)kvwlCTWD-XxeG2gW4um(|3s!4jm)$Q zr4_^uB}?CSj#(Z$OBh$sIPYAG7A6~$TPKc8mCshJA3wNIT6J^nrb2- zKQ?yop{@9ad)z${_?c}@=BNmeJvt!@t`e{mH(ncmExB{f(~zla}${a*aHxaCWJ zF^#Hc4?afQv(p&6+mx4GI{l9pH02oq8R$2RdGtJ3WsFIW6ebnNz_5V9tnYimjlWnvO?nS*LuE<>ucfINPQx2^iKa0(!!xxVdTT=EoxBSG5bjai)(B_;GR2%KM=bhXb=te)I3I97gz)3&wV9vY~o%b|8 zD1(*f+bv_=w7K3t-k+?VE3O|ie_B>EzAdSY9(Z7<*%h0!uOHq2X^|V0=f>Ibvq?)b zI_GX2Gd*;=M-TJ8cT{3rI$kdRA!b3=#$OR}jNTN0eZ3;#urap%aGZXvV#U*{m~p_B zNad0%U`ITyl}j$|2&qXaLT;yG`?f-l1lKiaP5l2sNad)#mYJyo|n#g z6j^bvkfV5ocrD$u}iY+w<$}u`+NK*l*NH|1F$M7o= zwj)eO@T;DXw{UMHg^uc1ub8i@FcjDbS(R$!tywWI$0j<^zlx3G_JX7ME01mAmSm3= z0|u*5*Xk$KRbV`6*Ah9&rNElMQO?!KS;unjDcHZ2>m)}6>;6VL$#sDo@SLrOF>`&| zcI@PtZn9gBH+0D`wj>jJM9D0Uj15CDLxF0atO&hn8yF{_KNuTks?ig9c5<`^vi0#* z1i;Y38mGtTR1hm$4-rasWzAG|t{rbFFT1|ZNPAdNuOT4_=%3&L&DQ|>Mxro%3dX<$6C7FUT*DnY$wBXNJh)Vc0uCbcC^{n>ZA3O`Gi&5A=`Hty zcQZX6G`Iiw8UjvYCyK|5e`e!W!+8w80gJ~dftdS#JeOVt+55cHx&?C)kG$jp^b8JT zg}O*QS#lwlQC7^5f^$a1FvM7)OgbB|dtX+6j}_3P$pIuq=IW(W_#H3H4xv8q|0j*%al9NA z9@eb6?Y!l@U(+^Q)5b=#qUPq&$)h)4n0x_0?ZgE`iFUubb+)<{5v~VSwQoaVhhfft z^L-az84X-U@dSH@`9}~~X|w@DgG)p*?Lw?Ea(WyYjK5=Mdj)sR3~SYYhj$E$>H`Wb z0RWv&hm8;9DoAcPS)YYOPV~PfVALZw2ZsBWdjT+^M^)|3%afNM6-gxyQl2_EFDxo~ zvzz+I`gj(BmHOCEDVAJW-W9r|g7&dG#)&xe!Dluda_&)reoW1@m2VfRG|2i){&R%$ zW-y}JrZ{BRCv1WZ=gTP9C?-NgH ztrz*2Eghs{Hb~(B+$UU&l1qa8VKQE%sGT$&(aw^Jo9;<>$^$vDfGw>tCIlPSE^6tL zt1#Z_N`#ecY70ss1#wj`iH;2vGTka9g`iCaZOJw_w(i^XiznVO7`}nQnbMB2}rUjehhI8C`-&Q+ot4(gdz4zAMd0Q*RLcqLl ztC_XcBr9&OzO{PZ*0kU$9kcT}WxgC3P8VrAzlDX%&8U%1l#p>au@~&D2A=%F`3wsH zZStGGg*V3O3^Be*2NgSu1+5l*j4-tpJ2`_Lb{wIDMAoa--Fp|FNsb1FnW;aB3|k-n zKh&ZA1#VG7EC@w>!e5X*K@KTZLN zlW_?dMPQeg{Va_!uQ>2dzu~ApgjD*2DAD`VJMSt5>qzy zzo0qlf5j~yYz|N!4chT?1A5uWPYH-#WCIXw(sCf05LL5o?7&3%_+buB3!-wMSyF4h zCDxkrC>5>ej8gp$0xMCf9Z)zHrV3Be?6W)uzkuSk>&ba=^eN}SG$_2-C~U#vea$4| zfRTuQ!=iS?$P_Q>rUPEtLBe4cN&N)%@cDdGQQ( zh4>YnMzanz<;)QOkV?iC5Fz5m@d&L)CbmP($8hPQSk!|PfMN8c#27s-<}b6I_za!c zesk~S-Z@Ww%2vO;6QnU_Xn%rrLJ@P7Z+eppbq6|hkd#6!*bhyL`9~IXQ#zr32c@dN zO}991I1GM~!mH`V7_%jvVxEEWL<;Wm=$F)^X5_-cURw5p?MdnF&imyXX3ICE%9^pu zS@A*L-MSRE{z_Ax-6`8{-p^d7(U{&Dl=ACOZ@!|8tk7eHtv3mgZIU(83RI8@FjSF@ zAkgesa^*36Sg92DPggpMd_^;sf2?R`A_Z?X>#Nx^0%6h!ggO3Co&$;J$BmaRabEd2 zqy~Pz21oS8eLIp%Oa=2tEGFjaM0Z|ClXa-*4z@H_w!I)tNpL%Mkpi&fe8(`DlZQ!Yv|& zTg?=1w{-0&N?X`Mn#TYbIQ=a8^hBH{>Y6(n(0#gK6U`~+atPhmh1an`}S9u z|E~(m{myHVt) zE|9k({Y$*bpQaX8Kn{z|ez(#1bRjXk+w9tX@4!!v{=w0?UC;k%>ERjk#I~eF+NCM~ zY|X}x%i2<?5|1LDqyqVUQ|G6s0AWnxrXqO3V;5c;`;y5eG8 z`OH&3ao~ILl#Sbv6&@*)xN@7EJz-WD-SrOXPhE)y6`+QiO4v; zFLsK*q~Zq$lk0D{-D;bw*f7V=Wi#MF3N1z&G9#jAya+x!Pr*Sf*U~mD^)v=yPKo%T zvo+(4kvfYUOlzyc>JF6VxVB3}vU1wo6&_Z9PAUEa{j{8BBm5afd`>qKaMUm8b_}<) zbRiN6ssD|B|AKBbsOo>G+y9`O2w0?T4BR-<#OACDPws+h&%S^c1r^@f1+|35kr+KV z3`mtx0R#!gd#is;A-a8lWKnX=^oH=M)ShukmQ_>bI&Qn zWCR4KeIEqw^5DHIKNGjl-^%^(BT8E`lPk|u8 z4v$QYWT`@*;*;^I`uCdeG*8!m&~&$Hru6qKf46eFeYRoOZ1qzFC#;)^cBJ@FZ7xr*gKcnO@XV+uM`%w>RF}IQ8OtXYQPVuMvV~d&VkR zS^y%DW8Mc?a8n&E5TQyczRQnCu(3~%Ik^(=j3D?*$ z4dT=nmoC6tkYho1w1KFV;SUJ%G^1pO!xGJ921p$D{j2$(gW`)6taKV~02|F@?Q;zW z5Mi$aeO6!a;*fTJC$E+u_gAGvm|j0{O4Y}7#X4RSxUoTt^^+Hpi<4~@* zIaVh3xvcv&I+*p1h0~G&xMYj<82!#3V}c7Uc`vM+47ai^*+hGnWy^PqupF=Vwlq_V zo7?4Pw6?jGpAjShkFMqDy_cLBWfQfw@^fnkHTQe^sBy1L7)GW;2Xx7!5|lRtF}Rn8 zzo+Z|z#!Hy5z$_1`_%3QT>#4Q*>~|8)VD1JxBkc^dPfclkgu zPf}cxXa4$#uV>&y@+^umjTeKWffO_^qwvZX0y{`vBGt%? zG6acyjK{EM3)TzJO2#zHdivH23Po^QRhv(~JX1d+0vfXM>85X0G)!jfJ!ZeQtpxq`VA;>|LJMlpY zx<6hS$9##+BMmh)dtAxl=RU_~W|!_1kCbx6jq@Ov$_E z>zmh3?iK&;Afd_ttXfaEzeU%>`CYGj`JQh|1Z&fBr)7HEk2~%+?3iuX zG1sswRsYod+NWphUjC)J9#y8@I^ko^1{s%~2MQ7eX?tPuI&S|+BK^{+X&eIolVxFM zNKAQ`T;tOF8XCdL7AYVKr7=97kRz^fm^HMTPn#%+dbNSVe}S-CNBt<( zXFr_K(;r9(_^?<>nJX+=5`nqDiCja0)Aza4HA?Oq0(Pq3&mNJa>@(L`|(0e z6SwS{tLYeXa}C|7o4mstDbzx@R@~T;S6S}um7jf<_p5YSU(_}v#HU5L!{on$%=HaX zsHwvYNbNs8zvj$b^_i4Z@c=P(FQ>X+ny-6#uIA;GRGE=%mg;xw-`jX+<8Pn3vxyk{ z>fckoq6Z6SDq#MLbgU!zB+1agU^H#L%q&duHY&-O%89?lKgSJ7B#xHE5aL%M#q)@m zwb3i&RgHVw>JwqtXL?ushhibOs!&-PZZ8YI&#^@>_}-#e^=+eq?{m&#>1YjPwfj=Q z>Qivv;G@$cq~_GTe}Ufn^hF1Y=aEw{oZyG{wU0UUgSdMc5PLa;gViAnqR&3nAU}Wl z__2M)riT zm!D_RS03h!1M7_MDo)ojR~@7|(AZ~0bH=&1HxY|a!-0U{wb3MP)j5q?`yymDL+d}; zx@!%_A$YBwN+-~E5BHg|k3Tl>M>DySXN{*~RAvZ)b(^!mWKY350(fH2m)uXFWdt7V zj``W=K^O#BepJAn7@`84`MwC(8&o9c{vcOTVR~-Ec>{Hgm_?2ES0Y2?sf1a;E4y_k zpJbHJ9qaKo#F;Z$0w4i%;}7t`=!eu;- zW-i0OaKb=M{UxaK>H;bTKI@+X!wsB)4@GvWBika5Z7Z`%Y!g0iJvX#@^EN*}x6gkB z9*Y}z{MMb1#bzzI3*SSM2*_$X5$eAON~iuGbo)cxpzPj6VfLznXgDo{Xf>zb_TT6&)T1m&W4g40moSJ83*pe<;w9ac3zX2q zLjs2mqyG7!)Bt^LPPag?X(f7x0(JV@Q`l3qk(yi5ylj z@GF-xY8ZNoI}RrN@9l*<`av&CO>>M~Uc-GbNkb$}$nb?74T5@8Dn>gO}WBM@AWLr(um^TBAFkM)T*Uf_?2D0CRYF=#RlQqh9}r6Hmy z{H##}He|vL@HRv~`*p`mm>0CZbX*{7XiPQ2&^D$#;PZy2+-prts8J)=xGf}f1ROps ztnhZ3m)t5hjTqB(5BxK;n)WtaKt@o%hJD6M6i6x&-X{XF-n*OvWO+|0s28E7eC;*a zXoQ!JTeh^yBO?v_5U-^e$+iHMV34VvoKp3g$q6pi%OIKaKEGB<^`tuK{nypFXVXw< zABUwz>zOhhDq#>K$P)ACF}e zG%FQuVHvspnknA>pgP7yM2Z->MQ$pIBh}8VofE!FqNRPEZ7pUGTablQ_7hYcq5!4xR`vurs#N+ynQ1tC(TH6>oG!9@H0 zM+6l*t&gP;r-&u?AjKDk|L7jT~;JPD#P{x zFSJXa0dc$ok{EL*K{Bi<{>>F2tgS&lPoDflk|n zFjd`6IK{w7!WD<=e?};GcBCaLAnw$_Nk38qOE1#tW)A1Z&%wkT7AwzBKA*fYdF7DZ8tKAm0(IT*O{YC5&{e#q^z@^~uuP zmACNe4g?qRZ66+)!LC^uwrv8FfkiMnWtozky%(y>k7|rdH|km>@GN0^it+Effgtje z1BD6Vek5OMCPnd4tb9UQcxG|!jw+)lH2478%DS+OG}2d(p!~&#a<=6>;y+N!>0}IA z4tvAl-x$WhqOk*S!D_vdBCd~LAMg*S)IJPpa3q#aH)QBb9vRxEM zw?CuW)+7HL!Y5MeBMBRR$!^-ltexJjZU0G@nq=dbKs$agk7dilDxGvJzKe2}U=>a> z7h;ZAVutaN4GTWQ%y3RA3KS_);r!TNBc|EL(%1{9(aLflogL*Afgz`J$c|x4t1E3k z0hx)NJ&%98i#efZKMc{876amGFM$IElX4*lDG*<7$%@oa_8*QxDKU&Co>4AMMGh5- zp^ztQ1jyu+5iASSQ@~__JboE`Pt=P~iQxc~N^+AnX8=Xxq8aPK-y*5f2st&gVi;O0 z0-XOsh{`f82?6>ek@QCiQ^xq>5I!VHTIoB+kA1nU1!NxzAkPO^?8HjiXM zT`9zCb0G;+TcCH_n!CoZdcDF;~7b<=UAsneAJk zkG;8Pa?g~+zg(vu8QSuoOrENkE88%AAm!RjM~AjNW_;H>#cjg-Rb8T4CG$}~L0rEm z%toLA0U#S$(dzGVp4^I7J6w2Ienba8!I?Yv7?sLQ&7q#87SbL-?vYnAfQjd! zHa}zV*VH&}^0ZL8CVBeyxm)K_Yucx~QXX&0=H+DAS&#rT1$dTSVDy;AotxM&i<>1x z`FVOvH*$j%y^JOie;`_(6*E?or2|$QmRrokq=VaA5Si|nVPv`^V=J<3nL3pb@Ze@6 zixkY1iI&DGIPt?{y6c03cMr1Qj6xP1jr8T@O+?%AU|nIga~?=M1fQBF^#TrT;A)jV zCrWf$C4I){3T|KkEkm)sj;9W_N}wA*MpW7iIXZ2|wl`aDP9NfSP0y*s#;aSXcdt_D zbxLc6-x6>T+?dIUPXy8SJQ;?lG|Jl9bNT{!WPo`vV!n*hcBn$QYhZq$*}}Y^sAOQC zcEPO&93XqiMQVUK2jPB=+^4_wje|Yi&mZhQdicb1=~7;Ct|^KshJ(_l;YZ~qadF@|{A&+mzOd&3nHu#y$_s zKJ3cA2AY-*!eOP_NJZ|UTQvb@KZR;2bcjO7>BdmzEQN^pr%i`nU|)=39}8h0$e=G4 z4-7&cPdg4jcLMIUy1PytOc%X$@Z|m%P90PyDC=+1t(*$JL!o~~w?D!yU92@%vm+z> zz>CnSV9WB4>9wQV7!tPK!qt7GwqqZJ=*o=;qM+E z^Mn1Zy;VEa&2fL~$n2_3^U~%~@hhuET=htxTZvG%_U*N!MPsEmD#t75gmnwTflpi7 z-nWdp$FAH+j3<)M&w85XgpP-H=Z)&|>QQUPS}eLJx^MzRbSLW<>5*xma4CC$`+&F}VY_ zcw+I?Huku;o;`jFfFLsC1)aSwmd}di_r*1{;+n5aCrub}f$osROm!I^5t4+CZgHVw z)55w&c-(qq-yv2l)U3Mgy5*WW1v|Tp84(Xx)!trnYYptUS8dE#5CJHxs>>8nh|XhV zC>P*pEqe3pch6#YYA3;wPp(Uq)K6_sl{C*mzVb*9-edVJ>U7LPukl91lr%P-c~+uC*)svQ*T0Tu(kw)^F$^SMCN3d z%1yXrx6G^VG(W*}gt}&!j{0NH)!5BsJriCRd4|ZsD@68C@63*kQh0aC?aWR1nWPsa zeV1Idxd5B8NAr_#nd_f@tUsj~X?PLs2RrD%9M$FqRAq7?le4CE?MUp=!vna` zpOKQY(iAlZW)y8kIy^9kcI!qgle2yCcoH0l$MZWkcoVD7!`UMyn*TCcgPx3nGlm3aR+U zO5w6^Y*~7jUZgO%eENgz`&k%V?fCTGkMF(V8*?<^!&~qDRaj}>`w6!9m=-CX?VW&U z0gk+9<{l7jX|i{ldH2@ya2|Yc9(@02oqo{i&jq4wb{n2@wllgR?S*~#fuzowEMKHa z6Y?u*iDpi-q%)9glw$6PxS?WgkHu70W9ehEgrty;xd5IgJghL4)#R8cjze;8ejqL7 zMCbg9bCQ~+rZ_*XB&WrB1@uo+rUtSc4xqfA#R;Y-AwmLA>vAl>q)tIr%QPirRg0Ov z`CSYxzzQ_W6yZpViNpaW7C(?khAVHnuszFLBB=~CF#5)(NGA6 zW=*h4(M*d<5NO;~2Rsn;^SiCscQc5alKSHpn{n!;4Pb<5gD}7LEOh6Ih2Y9s0ZNL6 zE6yEvskSnMiQUqEO@8Z=UG*X`MxyTgJKtx(x8-g-rC}O8V22PQ?Kmtd%^_nBp;Ju} zv+56Fd^J!mS+GkcWv{6P%85{8Cq%_;Xxbbw)Ngy7qc9qE+g{jB$+8Taw{jV3bb_N% zmw`aRLd$>9m2e%I)Fp2nIMdO(ta+gWlqKz8g}vWjyTcTox-Be%7zMq^Q1s#8hZs3wN_~C(*j@MUkFO&7`)-GN7p>J$?@Fk*w67dGx*Wb1I{MzumC(_$?vD=l1X<$3VWV z>Yjm>JpBseWdjgrVqk|po& z;;RI&<>>Gl8&vP{3df53sst{j({E?r%Cg~Q?gQa{fekhq=u{7y+JNeOF-iFKD9$68@W;sD^iL4U#_2=hQx7%n60M_K~t%kDRnI;V~^gk~53 z#h{)Uz;blp9~o6jLcKR&n1=exROqVgKoKjmScV;?jvnMHb%M~U6v{!p+Tdg8OP$Zu zUf?ihPd3uYfm-b-=7!D1#bny2-(HTNtsZo9Iv}5xEs` z3$#HulqsYwjxmZ>V_B@OX*yF=ivoTxiIy}A42eahx#%~FhJodO1Lk3kXPEaV*!Zu3 zd4DD3Cr}#}_ywVf0SH#3^4C8CjoB%(;3)`zlRpJ{Ze_#wlmbT>Koa?@Ld z&3>5NxnFJTiLl8NU%_{_-NN{@R^SSJJtAP;Uo8A0YOEA|bruC{e*>$aRvQQ_kjHJT zB%~Co%BCFvN(anO(vtAWsRE^R;1==K_RupH)nwZvWioj6%2Z{f#%nt4ChFg^R0~YE z?T74&Gs15NG&=7LO#9*Iw>Mce75WcZ1 zRuK=D__qUZ1(qKxi^ty^ye1yM{EZdycu}Zyi^V4^J^OC;_AQV6dGJQ>(Mr$$)t>&9 zp8jQeqh}D7D&hNA!;zJ6q(pCq4^=xrceRs<2bcVB^!_q&LI-*+>7xEcXZs{6@~ z@M7C${?TA@KZFpRcX$|#TH9tGw!k-?N`7-Ln(hLykul(Vz`wct&xQa#*D)VpeEnk% zkBbQ(4x$NvC^$%hUzC81&PN-A9Ng5}2N0vpfW=gU0s>epiKs!85c}}o4F}R3Fv7>8 zZl}&41h0%f=(eFPE@Q5h8wMC&$5DTNPwP2aUmF9Z<{)%uN!3U0xo>g&^@-OeihQ{} zRNE- z0ujVla|F7oo8!1UE*HnI`3TqbIoWmF&A&><|+U^n@|Ht bool: + return t.cast(bool, args[0].is_async) + + else: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].environment.is_async) + + # Take the doc and annotations from the sync function, but the + # name from the async function. Pallets-Sphinx-Themes + # build_function_directive expects __wrapped__ to point to the + # sync function. + async_func_attrs = ("__module__", "__name__", "__qualname__") + normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) + + @wraps(normal_func, assigned=normal_func_attrs) + @wraps(async_func, assigned=async_func_attrs, updated=()) + def wrapper(*args, **kwargs): # type: ignore + b = is_async(args) + + if need_eval_context: + args = args[1:] + + if b: + return async_func(*args, **kwargs) + + return normal_func(*args, **kwargs) + + if need_eval_context: + wrapper = pass_eval_context(wrapper) + + wrapper.jinja_async_variant = True # type: ignore[attr-defined] + return wrapper + + return decorator + + +_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} + + +async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": + # Avoid a costly call to isawaitable + if type(value) in _common_primitives: + return t.cast("V", value) + + if inspect.isawaitable(value): + return await t.cast("t.Awaitable[V]", value) + + return value + + +class _IteratorToAsyncIterator(t.Generic[V]): + def __init__(self, iterator: "t.Iterator[V]"): + self._iterator = iterator + + def __aiter__(self) -> "te.Self": + return self + + async def __anext__(self) -> V: + try: + return next(self._iterator) + except StopIteration as e: + raise StopAsyncIteration(e.value) from e + + +def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + return iterable.__aiter__() + else: + return _IteratorToAsyncIterator(iter(iterable)) + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/venv/lib/python3.12/site-packages/jinja2/bccache.py b/venv/lib/python3.12/site-packages/jinja2/bccache.py new file mode 100644 index 0000000..ada8b09 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/bccache.py @@ -0,0 +1,408 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" + +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: ... + + def set( + self, key: str, value: bytes, timeout: t.Optional[int] = None + ) -> None: ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib `_ + - `python-memcached `_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/venv/lib/python3.12/site-packages/jinja2/compiler.py b/venv/lib/python3.12/site-packages/jinja2/compiler.py new file mode 100644 index 0000000..a4ff6a1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/compiler.py @@ -0,0 +1,1998 @@ +"""Compiles nodes from the parser into Python code.""" + +import typing as t +from contextlib import contextmanager +from functools import update_wrapper +from io import StringIO +from itertools import chain +from keyword import iskeyword as is_python_keyword + +from markupsafe import escape +from markupsafe import Markup + +from . import nodes +from .exceptions import TemplateAssertionError +from .idtracking import Symbols +from .idtracking import VAR_LOAD_ALIAS +from .idtracking import VAR_LOAD_PARAMETER +from .idtracking import VAR_LOAD_RESOLVE +from .idtracking import VAR_LOAD_UNDEFINED +from .nodes import EvalContext +from .optimizer import Optimizer +from .utils import _PassArg +from .utils import concat +from .visitor import NodeVisitor + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .environment import Environment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +operators = { + "eq": "==", + "ne": "!=", + "gt": ">", + "gteq": ">=", + "lt": "<", + "lteq": "<=", + "in": "in", + "notin": "not in", +} + + +def optimizeconst(f: F) -> F: + def new_func( + self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any + ) -> t.Any: + # Only optimize if the frame is not volatile + if self.optimizer is not None and not frame.eval_ctx.volatile: + new_node = self.optimizer.visit(node, frame.eval_ctx) + + if new_node != node: + return self.visit(new_node, frame) + + return f(self, node, frame, **kwargs) + + return update_wrapper(new_func, f) # type: ignore[return-value] + + +def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed and op in self.environment.intercepted_binops # type: ignore + ): + self.write(f"environment.call_binop(context, {op!r}, ") + self.visit(node.left, frame) + self.write(", ") + self.visit(node.right, frame) + else: + self.write("(") + self.visit(node.left, frame) + self.write(f" {op} ") + self.visit(node.right, frame) + + self.write(")") + + return visitor + + +def _make_unop( + op: str, +) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed and op in self.environment.intercepted_unops # type: ignore + ): + self.write(f"environment.call_unop(context, {op!r}, ") + self.visit(node.node, frame) + else: + self.write("(" + op) + self.visit(node.node, frame) + + self.write(")") + + return visitor + + +def generate( + node: nodes.Template, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, +) -> t.Optional[str]: + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError("Can't compile non template nodes") + + generator = environment.code_generator_class( + environment, name, filename, stream, defer_init, optimized + ) + generator.visit(node) + + if stream is None: + return generator.stream.getvalue() # type: ignore + + return None + + +def has_safe_repr(value: t.Any) -> bool: + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + + if type(value) in {bool, int, float, complex, range, str, Markup}: + return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: # noqa E721 + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + + return False + + +def find_undeclared( + nodes: t.Iterable[nodes.Node], names: t.Iterable[str] +) -> t.Set[str]: + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class MacroRef: + def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: + self.node = node + self.accesses_caller = False + self.accesses_kwargs = False + self.accesses_varargs = False + + +class Frame: + """Holds compile time information for us.""" + + def __init__( + self, + eval_ctx: EvalContext, + parent: t.Optional["Frame"] = None, + level: t.Optional[int] = None, + ) -> None: + self.eval_ctx = eval_ctx + + # the parent of this frame + self.parent = parent + + if parent is None: + self.symbols = Symbols(level=level) + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = False + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer: t.Optional[str] = None + + # the name of the block we're in, otherwise None. + self.block: t.Optional[str] = None + + else: + self.symbols = Symbols(parent.symbols, level=level) + self.require_output_check = parent.require_output_check + self.buffer = parent.buffer + self.block = parent.block + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # variables set inside of loops and blocks should not affect outer frames, + # but they still needs to be kept track of as part of the active context. + self.loop_frame = False + self.block_frame = False + + # track whether the frame is being used in an if-statement or conditional + # expression as it determines which errors should be raised during runtime + # or compile time. + self.soft_frame = False + + def copy(self) -> "te.Self": + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.symbols = self.symbols.copy() + return rv + + def inner(self, isolated: bool = False) -> "Frame": + """Return an inner frame.""" + if isolated: + return Frame(self.eval_ctx, level=self.symbols.level + 1) + return Frame(self.eval_ctx, self) + + def soft(self) -> "te.Self": + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + + This is only used to implement if-statements and conditional + expressions. + """ + rv = self.copy() + rv.rootlevel = False + rv.soft_frame = True + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self) -> None: + self.filters: t.Set[str] = set() + self.tests: t.Set[str] = set() + + def visit_Filter(self, node: nodes.Filter) -> None: + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node: nodes.Test) -> None: + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names: t.Iterable[str]) -> None: + self.names = set(names) + self.undeclared: t.Set[str] = set() + + def visit_Name(self, node: nodes.Name) -> None: + if node.ctx == "load" and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting a blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + def __init__( + self, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, + ) -> None: + if stream is None: + stream = StringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + self.optimizer: t.Optional[Optimizer] = None + + if optimized: + self.optimizer = Optimizer(environment) + + # aliases for imports + self.import_aliases: t.Dict[str, str] = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks: t.Dict[str, nodes.Block] = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests: t.Dict[str, str] = {} + self.filters: t.Dict[str, str] = {} + + # the debug information + self.debug_info: t.List[t.Tuple[int, int]] = [] + self._write_debug_info: t.Optional[int] = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # Tracks toplevel assignments + self._assign_stack: t.List[t.Set[str]] = [] + + # Tracks parameter definition blocks + self._param_def_block: t.List[t.Set[str]] = [] + + # Tracks the current context. + self._context_reference_stack = ["context"] + + @property + def optimized(self) -> bool: + return self.optimizer is not None + + # -- Various compilation helpers + + def fail(self, msg: str, lineno: int) -> "te.NoReturn": + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self) -> str: + """Get a new unique identifier.""" + self._last_identifier += 1 + return f"t_{self._last_identifier}" + + def buffer(self, frame: Frame) -> None: + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline(f"{frame.buffer} = []") + + def return_buffer_contents( + self, frame: Frame, force_unescaped: bool = False + ) -> None: + """Return the buffer contents of the frame.""" + if not force_unescaped: + if frame.eval_ctx.volatile: + self.writeline("if context.eval_ctx.autoescape:") + self.indent() + self.writeline(f"return Markup(concat({frame.buffer}))") + self.outdent() + self.writeline("else:") + self.indent() + self.writeline(f"return concat({frame.buffer})") + self.outdent() + return + elif frame.eval_ctx.autoescape: + self.writeline(f"return Markup(concat({frame.buffer}))") + return + self.writeline(f"return concat({frame.buffer})") + + def indent(self) -> None: + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step: int = 1) -> None: + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline("yield ", node) + else: + self.writeline(f"{frame.buffer}.append(", node) + + def end_write(self, frame: Frame) -> None: + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(")") + + def simple_write( + self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None + ) -> None: + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically. + """ + try: + self.writeline("pass") + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x: str) -> None: + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write("\n" * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(" " * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline( + self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 + ) -> None: + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature( + self, + node: t.Union[nodes.Call, nodes.Filter, nodes.Test], + frame: Frame, + extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> None: + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occur. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = any( + is_python_keyword(t.cast(str, k)) + for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) + ) + + for arg in node.args: + self.write(", ") + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(", ") + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f", {key}={value}") + if node.dyn_args: + self.write(", *") + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(", **dict({") + else: + self.write(", **{") + for kwarg in node.kwargs: + self.write(f"{kwarg.key!r}: ") + self.visit(kwarg.value, frame) + self.write(", ") + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f"{key!r}: {value}, ") + if node.dyn_kwargs is not None: + self.write("}, **") + self.visit(node.dyn_kwargs, frame) + self.write(")") + else: + self.write("}") + + elif node.dyn_kwargs is not None: + self.write(", **") + self.visit(node.dyn_kwargs, frame) + + def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: + """Find all filter and test names used in the template and + assign them to variables in the compiled namespace. Checking + that the names are registered with the environment is done when + compiling the Filter and Test nodes. If the node is in an If or + CondExpr node, the check is done at runtime instead. + + .. versionchanged:: 3.0 + Filters and tests in If and CondExpr nodes are checked at + runtime instead of compile time. + """ + visitor = DependencyFinderVisitor() + + for node in nodes: + visitor.visit(node) + + for id_map, names, dependency in ( + (self.filters, visitor.filters, "filters"), + ( + self.tests, + visitor.tests, + "tests", + ), + ): + for name in sorted(names): + if name not in id_map: + id_map[name] = self.temporary_identifier() + + # add check during runtime that dependencies used inside of executed + # blocks are defined, as this step may be skipped during compile time + self.writeline("try:") + self.indent() + self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") + self.outdent() + self.writeline("except KeyError:") + self.indent() + self.writeline("@internalcode") + self.writeline(f"def {id_map[name]}(*unused):") + self.indent() + self.writeline( + f'raise TemplateRuntimeError("No {dependency[:-1]}' + f' named {name!r} found.")' + ) + self.outdent() + self.outdent() + + def enter_frame(self, frame: Frame) -> None: + undefs = [] + for target, (action, param) in frame.symbols.loads.items(): + if action == VAR_LOAD_PARAMETER: + pass + elif action == VAR_LOAD_RESOLVE: + self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") + elif action == VAR_LOAD_ALIAS: + self.writeline(f"{target} = {param}") + elif action == VAR_LOAD_UNDEFINED: + undefs.append(target) + else: + raise NotImplementedError("unknown load instruction") + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: + if not with_python_scope: + undefs = [] + for target in frame.symbols.loads: + undefs.append(target) + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: + return async_value if self.environment.is_async else sync_value + + def func(self, name: str) -> str: + return f"{self.choose_async()}def {name}" + + def macro_body( + self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame + ) -> t.Tuple[Frame, MacroRef]: + """Dump the function def of a macro or call block.""" + frame = frame.inner() + frame.symbols.analyze_node(node) + macro_ref = MacroRef(node) + + explicit_caller = None + skip_special_params = set() + args = [] + + for idx, arg in enumerate(node.args): + if arg.name == "caller": + explicit_caller = idx + if arg.name in ("kwargs", "varargs"): + skip_special_params.add(arg.name) + args.append(frame.symbols.ref(arg.name)) + + undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) + + if "caller" in undeclared: + # In older Jinja versions there was a bug that allowed caller + # to retain the special behavior even if it was mentioned in + # the argument list. However thankfully this was only really + # working if it was the last argument. So we are explicitly + # checking this now and error out if it is anywhere else in + # the argument list. + if explicit_caller is not None: + try: + node.defaults[explicit_caller - len(node.args)] + except IndexError: + self.fail( + "When defining macros or call blocks the " + 'special "caller" argument must be omitted ' + "or be given a default.", + node.lineno, + ) + else: + args.append(frame.symbols.declare_parameter("caller")) + macro_ref.accesses_caller = True + if "kwargs" in undeclared and "kwargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("kwargs")) + macro_ref.accesses_kwargs = True + if "varargs" in undeclared and "varargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("varargs")) + macro_ref.accesses_varargs = True + + # macros are delayed, they never require output checks + frame.require_output_check = False + frame.symbols.analyze_node(node) + self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) + self.indent() + + self.buffer(frame) + self.enter_frame(frame) + + self.push_parameter_definitions(frame) + for idx, arg in enumerate(node.args): + ref = frame.symbols.ref(arg.name) + self.writeline(f"if {ref} is missing:") + self.indent() + try: + default = node.defaults[idx - len(node.args)] + except IndexError: + self.writeline( + f'{ref} = undefined("parameter {arg.name!r} was not provided",' + f" name={arg.name!r})" + ) + else: + self.writeline(f"{ref} = ") + self.visit(default, frame) + self.mark_parameter_stored(ref) + self.outdent() + self.pop_parameter_definitions() + + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame, force_unescaped=True) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + return frame, macro_ref + + def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) + name = getattr(macro_ref.node, "name", None) + if len(macro_ref.node.args) == 1: + arg_tuple += "," + self.write( + f"Macro(environment, macro, {name!r}, ({arg_tuple})," + f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," + f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" + ) + + def position(self, node: nodes.Node) -> str: + """Return a human readable position for the node.""" + rv = f"line {node.lineno}" + if self.name is not None: + rv = f"{rv} in {self.name!r}" + return rv + + def dump_local_context(self, frame: Frame) -> str: + items_kv = ", ".join( + f"{name!r}: {target}" + for name, target in frame.symbols.dump_stores().items() + ) + return f"{{{items_kv}}}" + + def write_commons(self) -> None: + """Writes a common preamble that is used by root and block functions. + Primarily this sets up common local helpers and enforces a generator + through a dead branch. + """ + self.writeline("resolve = context.resolve_or_missing") + self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") + # always use the standard Undefined class for the implicit else of + # conditional expressions + self.writeline("cond_expr_undefined = Undefined") + self.writeline("if 0: yield None") + + def push_parameter_definitions(self, frame: Frame) -> None: + """Pushes all parameter targets from the given frame into a local + stack that permits tracking of yet to be assigned parameters. In + particular this enables the optimization from `visit_Name` to skip + undefined expressions for parameters in macros as macros can reference + otherwise unbound parameters. + """ + self._param_def_block.append(frame.symbols.dump_param_targets()) + + def pop_parameter_definitions(self) -> None: + """Pops the current parameter definitions set.""" + self._param_def_block.pop() + + def mark_parameter_stored(self, target: str) -> None: + """Marks a parameter in the current parameter definitions as stored. + This will skip the enforced undefined checks. + """ + if self._param_def_block: + self._param_def_block[-1].discard(target) + + def push_context_reference(self, target: str) -> None: + self._context_reference_stack.append(target) + + def pop_context_reference(self) -> None: + self._context_reference_stack.pop() + + def get_context_ref(self) -> str: + return self._context_reference_stack[-1] + + def get_resolve_func(self) -> str: + target = self._context_reference_stack[-1] + if target == "context": + return "resolve" + return f"{target}.resolve" + + def derive_context(self, frame: Frame) -> str: + return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" + + def parameter_is_undeclared(self, target: str) -> bool: + """Checks if a given target is an undeclared parameter.""" + if not self._param_def_block: + return False + return target in self._param_def_block[-1] + + def push_assign_tracking(self) -> None: + """Pushes a new layer for assignment tracking.""" + self._assign_stack.append(set()) + + def pop_assign_tracking(self, frame: Frame) -> None: + """Pops the topmost level for assignment tracking and updates the + context variables if necessary. + """ + vars = self._assign_stack.pop() + if ( + not frame.block_frame + and not frame.loop_frame + and not frame.toplevel + or not vars + ): + return + public_names = [x for x in vars if x[:1] != "_"] + if len(vars) == 1: + name = next(iter(vars)) + ref = frame.symbols.ref(name) + if frame.loop_frame: + self.writeline(f"_loop_vars[{name!r}] = {ref}") + return + if frame.block_frame: + self.writeline(f"_block_vars[{name!r}] = {ref}") + return + self.writeline(f"context.vars[{name!r}] = {ref}") + else: + if frame.loop_frame: + self.writeline("_loop_vars.update({") + elif frame.block_frame: + self.writeline("_block_vars.update({") + else: + self.writeline("context.vars.update({") + for idx, name in enumerate(sorted(vars)): + if idx: + self.write(", ") + ref = frame.symbols.ref(name) + self.write(f"{name!r}: {ref}") + self.write("})") + if not frame.block_frame and not frame.loop_frame and public_names: + if len(public_names) == 1: + self.writeline(f"context.exported_vars.add({public_names[0]!r})") + else: + names_str = ", ".join(map(repr, sorted(public_names))) + self.writeline(f"context.exported_vars.update(({names_str}))") + + # -- Statement Visitors + + def visit_Template( + self, node: nodes.Template, frame: t.Optional[Frame] = None + ) -> None: + assert frame is None, "no root frame allowed" + eval_ctx = EvalContext(self.environment, self.name) + + from .runtime import async_exported + from .runtime import exported + + if self.environment.is_async: + exported_names = sorted(exported + async_exported) + else: + exported_names = sorted(exported) + + self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = "" if self.defer_init else ", environment=environment" + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail(f"block {block.name!r} defined twice", block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if "." in imp: + module, obj = imp.rsplit(".", 1) + self.writeline(f"from {module} import {obj} as {alias}") + else: + self.writeline(f"import {imp} as {alias}") + + # add the load name + self.writeline(f"name = {self.name!r}") + + # generate the root render function. + self.writeline( + f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 + ) + self.indent() + self.write_commons() + + # process the root + frame = Frame(eval_ctx) + if "self" in find_undeclared(node.body, ("self",)): + ref = frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + frame.symbols.analyze_node(node) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + if have_extends: + self.writeline("parent_template = None") + self.enter_frame(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline("if parent_template is not None:") + self.indent() + if not self.environment.is_async: + self.writeline("yield from parent_template.root_render_func(context)") + else: + self.writeline("agen = parent_template.root_render_func(context)") + self.writeline("try:") + self.indent() + self.writeline("async for event in agen:") + self.indent() + self.writeline("yield event") + self.outdent() + self.outdent() + self.writeline("finally: await agen.aclose()") + self.outdent(1 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in self.blocks.items(): + self.writeline( + f"{self.func('block_' + name)}(context, missing=missing{envenv}):", + block, + 1, + ) + self.indent() + self.write_commons() + # It's important that we do not make this frame a child of the + # toplevel template. This would cause a variety of + # interesting issues with identifier tracking. + block_frame = Frame(eval_ctx) + block_frame.block_frame = True + undeclared = find_undeclared(block.body, ("self", "super")) + if "self" in undeclared: + ref = block_frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + if "super" in undeclared: + ref = block_frame.symbols.declare_parameter("super") + self.writeline(f"{ref} = context.super({name!r}, block_{name})") + block_frame.symbols.analyze_node(block) + block_frame.block = name + self.writeline("_block_vars = {}") + self.enter_frame(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.leave_frame(block_frame, with_python_scope=True) + self.outdent() + + blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) + self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) + debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) + self.writeline(f"debug_info = {debug_kv_str!r}") + + def visit_Block(self, node: nodes.Block, frame: Frame) -> None: + """Call a block and register it for the template.""" + level = 0 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline("if parent_template is None:") + self.indent() + level += 1 + + if node.scoped: + context = self.derive_context(frame) + else: + context = self.get_context_ref() + + if node.required: + self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) + self.indent() + self.writeline( + f'raise TemplateRuntimeError("Required block {node.name!r} not found")', + node, + ) + self.outdent() + + if not self.environment.is_async and frame.buffer is None: + self.writeline( + f"yield from context.blocks[{node.name!r}][0]({context})", node + ) + else: + self.writeline(f"gen = context.blocks[{node.name!r}][0]({context})") + self.writeline("try:") + self.indent() + self.writeline( + f"{self.choose_async()}for event in gen:", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + self.outdent() + self.writeline( + f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" + ) + + self.outdent(level) + + def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: + """Calls the extender.""" + if not frame.toplevel: + self.fail("cannot use extend from a non top-level scope", node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline("if parent_template is not None:") + self.indent() + self.writeline('raise TemplateRuntimeError("extended multiple times")') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline("parent_template = environment.get_template(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + self.writeline("for name, parent_block in parent_template.blocks.items():") + self.indent() + self.writeline("context.blocks.setdefault(name, []).append(parent_block)") + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node: nodes.Include, frame: Frame) -> None: + """Handles includes.""" + if node.ignore_missing: + self.writeline("try:") + self.indent() + + func_name = "get_or_select_template" + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, str): + func_name = "get_template" + elif isinstance(node.template.value, (tuple, list)): + func_name = "select_template" + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = "select_template" + + self.writeline(f"template = environment.{func_name}(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + if node.ignore_missing: + self.outdent() + self.writeline("except TemplateNotFound:") + self.indent() + self.writeline("pass") + self.outdent() + self.writeline("else:") + self.indent() + + def loop_body() -> None: + self.indent() + self.simple_write("event", frame) + self.outdent() + + if node.with_context: + self.writeline( + f"gen = template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)}))" + ) + self.writeline("try:") + self.indent() + self.writeline(f"{self.choose_async()}for event in gen:") + loop_body() + self.outdent() + self.writeline( + f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + loop_body() + else: + self.writeline("yield from template._get_default_module()._body_stream") + + if node.ignore_missing: + self.outdent() + + def _import_common( + self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame + ) -> None: + self.write(f"{self.choose_async('await ')}environment.get_template(") + self.visit(node.template, frame) + self.write(f", {self.name!r}).") + + if node.with_context: + f_name = f"make_module{self.choose_async('_async')}" + self.write( + f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" + ) + else: + self.write(f"_get_default_module{self.choose_async('_async')}(context)") + + def visit_Import(self, node: nodes.Import, frame: Frame) -> None: + """Visit regular imports.""" + self.writeline(f"{frame.symbols.ref(node.target)} = ", node) + if frame.toplevel: + self.write(f"context.vars[{node.target!r}] = ") + + self._import_common(node, frame) + + if frame.toplevel and not node.target.startswith("_"): + self.writeline(f"context.exported_vars.discard({node.target!r})") + + def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: + """Visit named imports.""" + self.newline(node) + self.write("included_template = ") + self._import_common(node, frame) + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline( + f"{frame.symbols.ref(alias)} =" + f" getattr(included_template, {name!r}, missing)" + ) + self.writeline(f"if {frame.symbols.ref(alias)} is missing:") + self.indent() + # The position will contain the template name, and will be formatted + # into a string that will be compiled into an f-string. Curly braces + # in the name must be replaced with escapes so that they will not be + # executed as part of the f-string. + position = self.position(node).replace("{", "{{").replace("}", "}}") + message = ( + "the template {included_template.__name__!r}" + f" (imported on {position})" + f" does not export the requested name {name!r}" + ) + self.writeline( + f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" + ) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith("_"): + discarded_names.append(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") + else: + names_kv = ", ".join( + f"{name!r}: {frame.symbols.ref(name)}" for name in var_names + ) + self.writeline(f"context.vars.update({{{names_kv}}})") + if discarded_names: + if len(discarded_names) == 1: + self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") + else: + names_str = ", ".join(map(repr, discarded_names)) + self.writeline( + f"context.exported_vars.difference_update(({names_str}))" + ) + + def visit_For(self, node: nodes.For, frame: Frame) -> None: + loop_frame = frame.inner() + loop_frame.loop_frame = True + test_frame = frame.inner() + else_frame = frame.inner() + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body if the body is a scoped block. + extended_loop = ( + node.recursive + or "loop" + in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) + or any(block.scoped for block in node.find_all(nodes.Block)) + ) + + loop_ref = None + if extended_loop: + loop_ref = loop_frame.symbols.declare_parameter("loop") + + loop_frame.symbols.analyze_node(node, for_branch="body") + if node.else_: + else_frame.symbols.analyze_node(node, for_branch="else") + + if node.test: + loop_filter_func = self.temporary_identifier() + test_frame.symbols.analyze_node(node, for_branch="test") + self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) + self.indent() + self.enter_frame(test_frame) + self.writeline(self.choose_async("async for ", "for ")) + self.visit(node.target, loop_frame) + self.write(" in ") + self.write(self.choose_async("auto_aiter(fiter)", "fiter")) + self.write(":") + self.indent() + self.writeline("if ", node.test) + self.visit(node.test, test_frame) + self.write(":") + self.indent() + self.writeline("yield ") + self.visit(node.target, loop_frame) + self.outdent(3) + self.leave_frame(test_frame, with_python_scope=True) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if node.recursive: + self.writeline( + f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node + ) + self.indent() + self.buffer(loop_frame) + + # Use the same buffer for the else frame + else_frame.buffer = loop_frame.buffer + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline(f"{loop_ref} = missing") + + for name in node.find_all(nodes.Name): + if name.ctx == "store" and name.name == "loop": + self.fail( + "Can't assign to special loop variable in for-loop target", + name.lineno, + ) + + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline(f"{iteration_indicator} = 1") + + self.writeline(self.choose_async("async for ", "for "), node) + self.visit(node.target, loop_frame) + if extended_loop: + self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") + else: + self.write(" in ") + + if node.test: + self.write(f"{loop_filter_func}(") + if node.recursive: + self.write("reciter") + else: + if self.environment.is_async and not extended_loop: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async and not extended_loop: + self.write(")") + if node.test: + self.write(")") + + if node.recursive: + self.write(", undefined, loop_render_func, depth):") + else: + self.write(", undefined):" if extended_loop else ":") + + self.indent() + self.enter_frame(loop_frame) + + self.writeline("_loop_vars = {}") + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline(f"{iteration_indicator} = 0") + self.outdent() + self.leave_frame( + loop_frame, with_python_scope=node.recursive and not node.else_ + ) + + if node.else_: + self.writeline(f"if {iteration_indicator}:") + self.indent() + self.enter_frame(else_frame) + self.blockvisit(node.else_, else_frame) + self.leave_frame(else_frame) + self.outdent() + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write(f"{self.choose_async('await ')}loop(") + if self.environment.is_async: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async: + self.write(")") + self.write(", loop)") + self.end_write(frame) + + # at the end of the iteration, clear any assignments made in the + # loop from the top level + if self._assign_stack: + self._assign_stack[-1].difference_update(loop_frame.symbols.stores) + + def visit_If(self, node: nodes.If, frame: Frame) -> None: + if_frame = frame.soft() + self.writeline("if ", node) + self.visit(node.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + for elif_ in node.elif_: + self.writeline("elif ", elif_) + self.visit(elif_.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(elif_.body, if_frame) + self.outdent() + if node.else_: + self.writeline("else:") + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: + macro_frame, macro_ref = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith("_"): + self.write(f"context.exported_vars.add({node.name!r})") + self.writeline(f"context.vars[{node.name!r}] = ") + self.write(f"{frame.symbols.ref(node.name)} = ") + self.macro_def(macro_ref, macro_frame) + + def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: + call_frame, macro_ref = self.macro_body(node, frame) + self.writeline("caller = ") + self.macro_def(macro_ref, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: + filter_frame = frame.inner() + filter_frame.symbols.analyze_node(node) + self.enter_frame(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.leave_frame(filter_frame) + + def visit_With(self, node: nodes.With, frame: Frame) -> None: + with_frame = frame.inner() + with_frame.symbols.analyze_node(node) + self.enter_frame(with_frame) + for target, expr in zip(node.targets, node.values): + self.newline() + self.visit(target, with_frame) + self.write(" = ") + self.visit(expr, frame) + self.blockvisit(node.body, with_frame) + self.leave_frame(with_frame) + + def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: + self.newline(node) + self.visit(node.node, frame) + + class _FinalizeInfo(t.NamedTuple): + const: t.Optional[t.Callable[..., str]] + src: t.Optional[str] + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + """The default finalize function if the environment isn't + configured with one. Or, if the environment has one, this is + called on that function's output for constants. + """ + return str(value) + + _finalize: t.Optional[_FinalizeInfo] = None + + def _make_finalize(self) -> _FinalizeInfo: + """Build the finalize function to be used on constants and at + runtime. Cached so it's only created once for all output nodes. + + Returns a ``namedtuple`` with the following attributes: + + ``const`` + A function to finalize constant data at compile time. + + ``src`` + Source code to output around nodes to be evaluated at + runtime. + """ + if self._finalize is not None: + return self._finalize + + finalize: t.Optional[t.Callable[..., t.Any]] + finalize = default = self._default_finalize + src = None + + if self.environment.finalize: + src = "environment.finalize(" + env_finalize = self.environment.finalize + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(env_finalize) # type: ignore + ) + finalize = None + + if pass_arg is None: + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(value)) + + else: + src = f"{src}{pass_arg}, " + + if pass_arg == "environment": + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(self.environment, value)) + + self._finalize = self._FinalizeInfo(finalize, src) + return self._finalize + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + """Given a group of constant values converted from ``Output`` + child nodes, produce a string to write to the template module + source. + """ + return repr(concat(group)) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> str: + """Try to optimize a child of an ``Output`` node by trying to + convert it to constant, finalized data at compile time. + + If :exc:`Impossible` is raised, the node is not constant and + will be evaluated at runtime. Any other exception will also be + evaluated at runtime for easier debugging. + """ + const = node.as_const(frame.eval_ctx) + + if frame.eval_ctx.autoescape: + const = escape(const) + + # Template data doesn't go through finalize. + if isinstance(node, nodes.TemplateData): + return str(const) + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code before visiting a child of an + ``Output`` node. + """ + if frame.eval_ctx.volatile: + self.write("(escape if context.eval_ctx.autoescape else str)(") + elif frame.eval_ctx.autoescape: + self.write("escape(") + else: + self.write("str(") + + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code after visiting a child of an + ``Output`` node. + """ + self.write(")") + + if finalize.src is not None: + self.write(")") + + def visit_Output(self, node: nodes.Output, frame: Frame) -> None: + # If an extends is active, don't render outside a block. + if frame.require_output_check: + # A top-level extends is known to exist at compile time. + if self.has_known_extends: + return + + self.writeline("if parent_template is None:") + self.indent() + + finalize = self._make_finalize() + body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + + # Evaluate constants at compile time if possible. Each item in + # body will be either a list of static data or a node to be + # evaluated at runtime. + for child in node.nodes: + try: + if not ( + # If the finalize function requires runtime context, + # constants can't be evaluated at compile time. + finalize.const + # Unless it's basic template data that won't be + # finalized anyway. + or isinstance(child, nodes.TemplateData) + ): + raise nodes.Impossible() + + const = self._output_child_to_const(child, frame, finalize) + except (nodes.Impossible, Exception): + # The node was not constant and needs to be evaluated at + # runtime. Or another error was raised, which is easier + # to debug at runtime. + body.append(child) + continue + + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + if frame.buffer is not None: + if len(body) == 1: + self.writeline(f"{frame.buffer}.append(") + else: + self.writeline(f"{frame.buffer}.extend((") + + self.indent() + + for item in body: + if isinstance(item, list): + # A group of constant data to join and output. + val = self._output_const_repr(item) + + if frame.buffer is None: + self.writeline("yield " + val) + else: + self.writeline(val + ",") + else: + if frame.buffer is None: + self.writeline("yield ", item) + else: + self.newline(item) + + # A node to be evaluated at runtime. + self._output_child_pre(item, frame, finalize) + self.visit(item, frame) + self._output_child_post(item, frame, finalize) + + if frame.buffer is not None: + self.write(",") + + if frame.buffer is not None: + self.outdent() + self.writeline(")" if len(body) == 1 else "))") + + if frame.require_output_check: + self.outdent() + + def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: + self.push_assign_tracking() + + # ``a.b`` is allowed for assignment, and is parsed as an NSRef. However, + # it is only valid if it references a Namespace object. Emit a check for + # that for each ref here, before assignment code is emitted. This can't + # be done in visit_NSRef as the ref could be in the middle of a tuple. + seen_refs: t.Set[str] = set() + + for nsref in node.find_all(nodes.NSRef): + if nsref.name in seen_refs: + # Only emit the check for each reference once, in case the same + # ref is used multiple times in a tuple, `ns.a, ns.b = c, d`. + continue + + seen_refs.add(nsref.name) + ref = frame.symbols.ref(nsref.name) + self.writeline(f"if not isinstance({ref}, Namespace):") + self.indent() + self.writeline( + "raise TemplateRuntimeError" + '("cannot assign attribute on non-namespace object")' + ) + self.outdent() + + self.newline(node) + self.visit(node.target, frame) + self.write(" = ") + self.visit(node.node, frame) + self.pop_assign_tracking(frame) + + def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: + self.push_assign_tracking() + block_frame = frame.inner() + # This is a special case. Since a set block always captures we + # will disable output checks. This way one can use set blocks + # toplevel even in extended templates. + block_frame.require_output_check = False + block_frame.symbols.analyze_node(node) + self.enter_frame(block_frame) + self.buffer(block_frame) + self.blockvisit(node.body, block_frame) + self.newline(node) + self.visit(node.target, frame) + self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") + if node.filter is not None: + self.visit_Filter(node.filter, block_frame) + else: + self.write(f"concat({block_frame.buffer})") + self.write(")") + self.pop_assign_tracking(frame) + self.leave_frame(block_frame) + + # -- Expression Visitors + + def visit_Name(self, node: nodes.Name, frame: Frame) -> None: + if node.ctx == "store" and ( + frame.toplevel or frame.loop_frame or frame.block_frame + ): + if self._assign_stack: + self._assign_stack[-1].add(node.name) + ref = frame.symbols.ref(node.name) + + # If we are looking up a variable we might have to deal with the + # case where it's undefined. We can skip that case if the load + # instruction indicates a parameter which are always defined. + if node.ctx == "load": + load = frame.symbols.find_load(ref) + if not ( + load is not None + and load[0] == VAR_LOAD_PARAMETER + and not self.parameter_is_undeclared(ref) + ): + self.write( + f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" + ) + return + + self.write(ref) + + def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: + # NSRef is a dotted assignment target a.b=c, but uses a[b]=c internally. + # visit_Assign emits code to validate that each ref is to a Namespace + # object only. That can't be emitted here as the ref could be in the + # middle of a tuple assignment. + ref = frame.symbols.ref(node.name) + self.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/venv/lib/python3.12/site-packages/jinja2/constants.py b/venv/lib/python3.12/site-packages/jinja2/constants.py new file mode 100644 index 0000000..41a1c23 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/venv/lib/python3.12/site-packages/jinja2/debug.py b/venv/lib/python3.12/site-packages/jinja2/debug.py new file mode 100644 index 0000000..eeeeee7 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: t.Optional[Context] = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/venv/lib/python3.12/site-packages/jinja2/defaults.py b/venv/lib/python3.12/site-packages/jinja2/defaults.py new file mode 100644 index 0000000..638cad3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/venv/lib/python3.12/site-packages/jinja2/environment.py b/venv/lib/python3.12/site-packages/jinja2/environment.py new file mode 100644 index 0000000..0fc6e5b --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/environment.py @@ -0,0 +1,1672 @@ +"""Classes for managing templates and their runtime and compile time +options. +""" + +import os +import typing +import typing as t +import weakref +from collections import ChainMap +from functools import lru_cache +from functools import partial +from functools import reduce +from types import CodeType + +from markupsafe import Markup + +from . import nodes +from .compiler import CodeGenerator +from .compiler import generate +from .defaults import BLOCK_END_STRING +from .defaults import BLOCK_START_STRING +from .defaults import COMMENT_END_STRING +from .defaults import COMMENT_START_STRING +from .defaults import DEFAULT_FILTERS # type: ignore[attr-defined] +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS # type: ignore[attr-defined] +from .defaults import KEEP_TRAILING_NEWLINE +from .defaults import LINE_COMMENT_PREFIX +from .defaults import LINE_STATEMENT_PREFIX +from .defaults import LSTRIP_BLOCKS +from .defaults import NEWLINE_SEQUENCE +from .defaults import TRIM_BLOCKS +from .defaults import VARIABLE_END_STRING +from .defaults import VARIABLE_START_STRING +from .exceptions import TemplateNotFound +from .exceptions import TemplateRuntimeError +from .exceptions import TemplatesNotFound +from .exceptions import TemplateSyntaxError +from .exceptions import UndefinedError +from .lexer import get_lexer +from .lexer import Lexer +from .lexer import TokenStream +from .nodes import EvalContext +from .parser import Parser +from .runtime import Context +from .runtime import new_context +from .runtime import Undefined +from .utils import _PassArg +from .utils import concat +from .utils import consume +from .utils import import_string +from .utils import internalcode +from .utils import LRUCache +from .utils import missing + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .bccache import BytecodeCache + from .ext import Extension + from .loaders import BaseLoader + +_env_bound = t.TypeVar("_env_bound", bound="Environment") + + +# for direct template usage we have up to ten living environments +@lru_cache(maxsize=10) +def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: + """Return a new spontaneous environment. A spontaneous environment + is used for templates created directly rather than through an + existing environment. + + :param cls: Environment class to create. + :param args: Positional arguments passed to environment. + """ + env = cls(*args) + env.shared = True + return env + + +def create_cache( + size: int, +) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: + """Return the cache class for the given size.""" + if size == 0: + return None + + if size < 0: + return {} + + return LRUCache(size) # type: ignore + + +def copy_cache( + cache: t.Optional[t.MutableMapping[t.Any, t.Any]], +) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: # noqa E721 + return {} + + return LRUCache(cache.capacity) # type: ignore + + +def load_extensions( + environment: "Environment", + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], +) -> t.Dict[str, "Extension"]: + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated extensions. + """ + result = {} + + for extension in extensions: + if isinstance(extension, str): + extension = t.cast(t.Type["Extension"], import_string(extension)) + + result[extension.identifier] = extension(environment) + + return result + + +def _environment_config_check(environment: _env_bound) -> _env_bound: + """Perform a sanity check on the environment.""" + assert issubclass( + environment.undefined, Undefined + ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert ( + environment.block_start_string + != environment.variable_start_string + != environment.comment_start_string + ), "block, variable and comment start strings must be different." + assert environment.newline_sequence in { + "\r", + "\r\n", + "\n", + }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." + return environment + + +class Environment: + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here are the possible initialization parameters: + + `block_start_string` + The string marking the beginning of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the beginning of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the beginning of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation `. + + `optimized` + should the optimizer be enabled? Default is ``True``. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + ``None`` implicitly into an empty string here. + + `autoescape` + If set to ``True`` the XML/HTML autoescaping feature is enabled by + default. For more details about autoescaping see + :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return ``True`` or ``False`` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``400`` which means + that if more than 400 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + .. versionchanged:: 2.8 + The cache size was increased to 400 from a low 50. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + ``auto_reload`` is set to ``True`` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + + `enable_async` + If set to true this enables async template execution which + allows using async functions and generators. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to: t.Optional["Environment"] = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: the class that is used for code generation. See + #: :class:`~jinja2.compiler.CodeGenerator` for more information. + code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + + concat = "".join + + #: the context class that is used for templates. See + #: :class:`~jinja2.runtime.Context` for more information. + context_class: t.Type[Context] = Context + + template_class: t.Type["Template"] + + def __init__( + self, + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + loader: t.Optional["BaseLoader"] = None, + cache_size: int = 400, + auto_reload: bool = True, + bytecode_cache: t.Optional["BytecodeCache"] = None, + enable_async: bool = False, + ): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined: t.Type[Undefined] = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + + # load extensions + self.extensions = load_extensions(self, extensions) + + self.is_async = enable_async + _environment_config_check(self) + + def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes: t.Any) -> None: + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.items(): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay( + self, + block_start_string: str = missing, + block_end_string: str = missing, + variable_start_string: str = missing, + variable_end_string: str = missing, + comment_start_string: str = missing, + comment_end_string: str = missing, + line_statement_prefix: t.Optional[str] = missing, + line_comment_prefix: t.Optional[str] = missing, + trim_blocks: bool = missing, + lstrip_blocks: bool = missing, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, + keep_trailing_newline: bool = missing, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + optimized: bool = missing, + undefined: t.Type[Undefined] = missing, + finalize: t.Optional[t.Callable[..., t.Any]] = missing, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, + loader: t.Optional["BaseLoader"] = missing, + cache_size: int = missing, + auto_reload: bool = missing, + bytecode_cache: t.Optional["BytecodeCache"] = missing, + enable_async: bool = missing, + ) -> "te.Self": + """Create a new overlay environment that shares all the data with the + current environment except for cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + + .. versionchanged:: 3.1.5 + ``enable_async`` is applied correctly. + + .. versionchanged:: 3.1.2 + Added the ``newline_sequence``, ``keep_trailing_newline``, + and ``enable_async`` parameters to match ``__init__``. + """ + args = dict(locals()) + del args["self"], args["cache_size"], args["extensions"], args["enable_async"] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in args.items(): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in self.extensions.items(): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + if enable_async is not missing: + rv.is_async = enable_async + + return _environment_config_check(rv) + + @property + def lexer(self) -> Lexer: + """The lexer for this environment.""" + return get_lexer(self) + + def iter_extensions(self) -> t.Iterator["Extension"]: + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (AttributeError, TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Any: + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a string. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def _filter_test_common( + self, + name: t.Union[str, Undefined], + value: t.Any, + args: t.Optional[t.Sequence[t.Any]], + kwargs: t.Optional[t.Mapping[str, t.Any]], + context: t.Optional[Context], + eval_ctx: t.Optional[EvalContext], + is_filter: bool, + ) -> t.Any: + if is_filter: + env_map = self.filters + type_name = "filter" + else: + env_map = self.tests + type_name = "test" + + func = env_map.get(name) # type: ignore + + if func is None: + msg = f"No {type_name} named {name!r}." + + if isinstance(name, Undefined): + try: + name._fail_with_undefined_error() + except Exception as e: + msg = f"{msg} ({e}; did you forget to quote the callable name?)" + + raise TemplateRuntimeError(msg) + + args = [value, *(args if args is not None else ())] + kwargs = kwargs if kwargs is not None else {} + pass_arg = _PassArg.from_obj(func) + + if pass_arg is _PassArg.context: + if context is None: + raise TemplateRuntimeError( + f"Attempted to invoke a context {type_name} without context." + ) + + args.insert(0, context) + elif pass_arg is _PassArg.eval_context: + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, self) + + return func(*args, **kwargs) + + def call_filter( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a filter on a value the same way the compiler does. + + This might return a coroutine if the filter is running from an + environment in async mode and the filter supports async + execution. It's your responsibility to await this if needed. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, True + ) + + def call_test( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a test on a value the same way the compiler does. + + This might return a coroutine if the test is running from an + environment in async mode and the test supports async execution. + It's your responsibility to await this if needed. + + .. versionchanged:: 3.0 + Tests support ``@pass_context``, etc. decorators. Added + the ``context`` and ``eval_ctx`` parameters. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, False + ) + + @internalcode + def parse( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> nodes.Template: + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja extensions ` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def _parse( + self, source: str, name: t.Optional[str], filename: t.Optional[str] + ) -> nodes.Template: + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, filename).parse() + + def lex( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development ` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = str(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def preprocess( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> str: + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce( + lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), + str(source), + ) + + def _tokenize( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) # type: ignore + + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) + + return stream + + def _generate( + self, + source: nodes.Template, + name: t.Optional[str], + filename: t.Optional[str], + defer_init: bool = False, + ) -> str: + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate( # type: ignore + source, + self, + name, + filename, + defer_init=defer_init, + optimized=self.optimized, + ) + + def _compile(self, source: str, filename: str) -> CodeType: + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, "exec") + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[False]" = False, + defer_init: bool = False, + ) -> CodeType: ... + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[True]" = ..., + defer_init: bool = False, + ) -> str: ... + + @internalcode + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: bool = False, + defer_init: bool = False, + ) -> t.Union[str, CodeType]: + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, str): + source_hint = source + source = self._parse(source, name, filename) + source = self._generate(source, name, filename, defer_init=defer_init) + if raw: + return source + if filename is None: + filename = "

-ai|>(EGu zud8sqeq=pgSL3>Mq?NC0l5OJ~MmF$uZF1xIrjd5Ou1j`|caC)8y549=ZXVwn*rG zHgb%wyKsGc|pB+Cra+0rmlBdQ`kDTV~T3l}$+2nS`eV5);U}ya` z*J9nbCeMtY9XX5gE@K<6KQryV&*g85zA+ z)cMR$>9W(E^T#G8QkhsLk(x*k;CERjF&;PK$xIACY7^d`0()A{ujsMld_fC6BC)ZIT1?^#my^mQUl+_N#jf5HJ#;OLn`xoprdk3eI)XAnqI$};uOe7{QM9!P3@rW5url{L^ z<{ONsCov~f&UYc6iCj#jGe32UN%M>)6S!ZJxi*P+-*M;4`z9w3r_kRQGx$|0yCLtO zWNBpVN+dQpiAz6Snqv6$b8N~q;}aSA)O~?U+aAly$XMn@dXkQ((_#@SsZ&OLbP9b> z#^|*=x`XTV#kdg}N5R;II4wYs?$f{`1{P=H3U1Y=;}eD$vzV!rc@4Kc7zX~7Mevx` zJc%ExhvMjB{BSCDIT0Tc&GX8f$I|0@mBYP840TLQMMDUu{e@IU4L=gM zEq9d~>G{M&f`)*?L3J;kiJ2L`Ri|zh)a&n`xRNka6XWPP-Ygx|Gh8u5FWZ(g`25hZ z6Sm^-U=@yH+AbeXCh#_XR;r(afDQ(SfQ0AgV#%p^Zq;xEJxnGeYLJs=Y7A4ufLuJ9 znwl_j<-KR$$u z+pZbc%T*cue8!cLsLth5NY5;qaSgdLa?`u;#(VB}#uat~l5Jb5h_jEu)F$0HiunEhzyS^P_f z@b!{wsWkA?^*77!?0T>Be$&pSVBKusC;qy*bNBsi^WL_{DB~KVFZHPs7w*Si4EZ-O zMRC`N+i;B(odcgU;sG}GCcxzwp0B$NuThNe6230wZy$e`p;WO^{+?e=6iNlSYz05B z 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..972cc0ca3ece5dae96751cde3192e8c6efc73584 GIT binary patch literal 4994 zcmcIoOKcp+5$)L@_eU=OOUn98sP8J`QkE=#Xju|%Q6EI19g{ZfHG+a zk|Eh${j097uBunfzjk&e34DM5%eMKa9zwpvhW|x9LfQE}5T6i(7>Y$IN zNY>#(1nRIAt;7m37>gKDtD_Px#3dcG5|v~jDd`R?RY@1pl8#%Qm99cY(g~ou3*C}V zT0NECLa#z-WZ{S}N~>lu;GeSkD+7fAg@njuVx(^oqmyPHguPjXuH{g!>uYS}6gQ>Y zwj*?5IyRqzc0!mHYEVn)Un|~>_(ZjOnK`v8&Mws$qqflWDmME#wGFMzoQh_cjFyDM zmXXKHR*hDfX$zbaG^VMjRi|MuigPqrD@>bO(1^cIc@+epB~L`JjC+-`^9vw81PxPC zPz(ZERoZ`OxExQA|Mka+t&*~0gl=`ht#laSTaiN4h#L{8V+mp;cJnckM)X#+(6LHx zD24bm$)#8VgqbR(JlSNKh7xqE?0f{oZf~dvle$t5)x-5jJz9^|JL>Uz zqMm#pEeqBW(X=E&9yC|hiPpR=SW6a~nh4ke0ll&Iwnu9bzi$~XcPbZkqr6t7%#CZB zX`4dR7_M@|CChXpwqBvRv>V~nDzjefPnngf!-R$-ZYM{(C~0NKGJr*<*{m^3tLkFj z%?MhlT5z5IjHDc5v~1pR6TCKSI2GNr-86O^w5-=G!QBLN9N{rYfE3ysniiOYR)z)|OyEn(?oeCYR=})iBLbW)0{mf|DWR)eI(NS&+I<`pd#WBmA9jh*jdB;AT zfBMuI4vbdy(sg}~^06{7zdknW+a=FemsvM#w9*@xXWmy)AN2EUP<(rnJl;bRUAH^d z<3pS2?#*;|Gd;YSeoFohZl(t|)6fs)z~g~bBKdfP^zZ%E_-f>r@kX2s@B1wAX<{{U zCw@Erapw;3Bc%|Q%@40in$0aB+KpzReO7a_p$r4{UZ@_rsVs+D22&4-zziNV*Rf%N zMk>F0XrbLyo4vl7JwO+SZ<^FYVBBHd1{QB{YN)fz>UgNbOzoCJGi$%4hm*#2GzqdslRIQdBrt0dP3HPIxfrW~8qnc&a6zY=B?V|#E zIP8~C1}k4)hE1fcoPa${t}+N4%;xI2p$mPyI6XOaQM+{Y+NAc=iMOEKsC|}93%jR5-$?&E+WuM3U(j4+_!K|29XK*v$Oj~RmIOUXM!x2xYOY>%F zUKP}`xIF(XbCx(|sF)g;+ZiTCQr!Zn->p$Dc)-ZCxuCj%Qs}A-vYyI(uCRHH*L2HT zR;%DblwqxJ`h0qR~y58 zUR|V&gSe%6-JYYy__%s1e=?YlS2+WWn<{xinIMF(7uYU1+S8}hd8fws_wJ(`hTP?3 z{)J!{clZY{bSf8P9blbq%)3W7X>#03w@Z|v_qbtz7`IaZepvt~Fw5Y%Fhl=!<7jU( zj76m_a&R>QCt~|?bYPAO1Rww}n5H$Yc;!GV7<})9=U^?r00jhw5z@2wVfV;-_sH78 zbL-vbSEJjh?$wtz`?6o92JX_|zWqh&=%c>DyS0beZeWPpX(d|tCYMLDY zCcB~mdNGKo?EC?UPcXbg{p80}0*@g-LwV5j-VYR*9YBabj-cbucrPSSk@9QBhJ_{o z`6E~hjK1;%o?SlOs{I&)fcAOFPbp;Vm;iCmUKUNdq+;wqPe8vg&_BRU79k*jw)t*9 z9oL0m5N6u32E1`X1zZ5@Mq{rD01`kV=^TvCnP6@V*g|*->_~cs+*%jvZk|416*2Pc z9`c|K23mf~sc19a|D)Hnyx~kM`mLNgx=RyB)k=*Ebr$@aik2SzIjGJ&Bv2hq3(m#e zo_U>X{DOzJYE|eYV-91-;5Hd%6s{uNNJ;0y4RgWR0CY9IhaJH=$D!EmHr>)? zeCDwE%AS_TJUR9{E`JS*o1`&By89ny4*xB4_)+ivwFA=|y)$d+834(??8Dv@>%AxL zzqQf(>}toO%*dm3=bcNpFa7%Ty~x9%!4Vc76IHs zwioheOq1RH_3-DBHs^`z6oh)U3NWbya&U;CCC^!)1sN6qDBgY3c7p^85Dx&B0jikx z90FJie}hbCG++RLWI`x}tlNhSNaBwIt|DlR7vIlIxX3#oh33mp4E)POmNw5Auj)*% z1k#SHujzp8ASHs4zy80ApAWb@&dRyR2)o~;7f0aUGjLs%M1h7nRB*-@$1QDv!<=HW$&b|knnvt4H@n({u79- zQuD>4FBP0tUJ+(&t;3x|0C5%OhS)6piIp6@y`;Ty$VcE5s9*>;cp5Ln`s&WJ)36j@ zYyJ+on45ePbu0sm8*;cCkuQVDf@9k3DcmW7jB?Q?DEoHdMo=T{49sB9L&4F5@#32J z+=;6KD_qI8qRg&=d0aXJ1%w!tq`TL$$JSHF9`){B+jnK7_v%{u>Q|YbJ4?5h?$mGB z?_KeH$FS2i+dRwLV~%-v@`I{Tdx!21eUUk}7C$A! zOm0v#D=^X!_U8>+~Jy`8jl9zQ_h~PSTqrJF>X^92P@Z zoW}yQdXL%z)JoPcO9Ht-?wg;mmjh;~OK;v@pK@bfX6#0gdoJPyZOQcl@=8K-)Re^^ zl(OR>LzvHn*m<@;nr!6BWo1ffgomQ1H;10`>VrqT`h{0yy`9MZD+=S%w&b~TgQ&N1 z4c<7QH-_HHFwJyhVz~<8gpFb&4sRcd5H9mx2LFj7-b21)&T?jTi+hQ3$2_&*wa-0x z@8P-)>3u%H0xoxSGt;s^@F|9QAUyBA*}SBeF)fmp=624!{o17V%9Y7iesXo{vKwDw z02;Uh8qn{EcMeRczl)#sF8>_+88q<ScwZ1niG)Ogx@FU{E>f2zQL;o|v=s_sff6YaWD1}Tgmfs! ziAYZP`gC?wR>!0g(=2SlMN!mD$ep&Ms{+9Y^Wi zo!|e}0g!@hfAj6PCGpim)w}Dx|NGzX-#Z*u4%g4$pX=UsndAO}eyEpQj_~(xnK|wX zCvqa+%k}Z?JWp|5udZFk?)pBV-Jm=(wwu^9bGw<{E$tR|x3*i^-PUencYC{?-5u=? zc6YYBaM$?EzMvyLV;Zs`gbpr{i{WqUU8!^o9$1p3Rh~ z#@^P;vGxY>tmu1LXb+0##C+Tv#kg32`)ctkVj=Ep&@xfYmAP9uamd1D{}YGB;+G9? zD@oedJv85o*||{8SH;rod^t)U5zAgSw67D-i{)t1dL4&8^<>(j#>9#fyjUsv!|TN& zvFOIKw~g|f_Kj>bsxTVWZ|jt2n^-9WYTnE}ya{=0v~-UmovSC7d9TLA<#>Kt{gt_k zC3t=|^IMH|>537(u|g~Paq%Uw7X8`6T33hG1<9e;Z47pZFN>>@xA~!Y*I@M4B3JW`b#DuD?d>g#zZJgC*TnTGW#>an z*&uE_p<{0^W_qB;s8u&MsUsjh!dkiW#-my*ceAl*!dN^O-lp|?kN9m)r}QOILYvy-a4UX4b>r!`4RS9Y+TLeGo%k$TtH6_orh5+Q+P^@$=h2cE zzCgO8BF(acTK~Tkw)DK28F4k%^CxO7bN`-B?07?eLn3%B+BX=W_cSkDjDSmrKr;TCmf(~g2QGMRa+#zavJXI4OXi}Nrj^Bh~Y2UYj!zYg?^gT3Lla|2<# za~%pvp}sI)9qAvGI_Z&B8jN&AyZZ)u=~q#Av;z+!-H{U=T~dEvhZOGZ4~eWO2NLy5 zv5sg=!s}ntkRgYyb5N4Pkyr=n$4@6}?hwPr2a&%wbOKLY^n?oO5c^}{$Z0%s9EpXb z*x_(=0KH)CdgjRPz1s%{db>MW*C-o3+8H_BE%itGQ2twd+OVrP6g|}`e=0dtz8ilp z55KQ)VXmDQIbe2tyB?#aPdi)tQS8pMo#6o*viQ2gq3&o{^mljpLlHlktk&r7WCQCz z9`<+j4@N|PzvO2<7lW+jb z)VTWx8&CH4g&PM$YvRXoJKb<(usmPrHAz~6DtM5kba0)r)!kI zSU#lh)bZRAPC%X>AlFN;9^29<9H&m_7VeVJsXM`S>W%_I9~QD|5f;^wHzZuvUGxgv zumP#4FYFpJXiJr6i^VWx5DkPF9pN65ss)3#BIZ&G0P2la(`;FCeUB4O4}D{PL#y{C zUbJBJ9{&n)08Tq&fGK^0y|He9Q9lDy*>y(IWVP|NadU0Z|5P;WuZ>qV5$LF; z#zzOjo!wpMSkpTD0Z}_+{{Bcfh?=dPQkXzIHNe~#I>lmfk5+G2s590tokMw!+C>$u zsjc@PAB_1s`v-ePKei13x!zuXcg%mL8}J5iLehyr0lTw zy@TOsTHhOv$e@tsYTAUP7`qtd>Kcr65|~e0XusPjN&Ql~u!A}s7CWfV*e3h2v#}1E z(?)p?$hBLjY6j$`3M!XBoi_D_Vx1>ZC4Ke|rB7)-93`Mf(~2&sj8Z#j@^#R}qt7I* z!?OVXqTd5V9^rmt<_tyiMy{a#6HYJ`j#}wq+@A z!7ES9Taaen$(1g<)_ApXwq$j(Wc75(+Mhf3jX(JpJ-6Jqc7Cw&iC4ayaPAw~jo_}y zI=bm=L*rk*Z7NE+3dX-Y7EhRq?^x`k&%9bT!QZwN-*J}B>v)GdKl-)c+*n&vtFu~qYWonzHKz2LIWbArW+$_rM1!g&nEXlg^ptq`n%rpiO$IlGu}X|wBp-O%tH@_VS5mC%b;of4x7kd?V`LREqj7rKsO#MEwTi?>^bibFTgTrwc1N zU->7T#Zi2xFgW#=E9 z%0y9M%02by)G8Fdv0>hz&u_S=Hxzp2tz1#@yv^V){{6fKh2D?W;3K_ja<@2zcZ&st zKX&lIO&q%0am^8 z+8+hl1JH~j6o3*5+czT5R7mOd7Ra8scfw5)rtu| zX(<`mF)ug_u9P!xG?H?;FMVa~E3>X;N!PN;Cx6g>y*=q_oGUE**uyzo^DfTgyHaww zWOT>8jdQujBJ+7%p6_Eb-hDc@<9?Lbm{)7Id$@NwCxssU_I%)9c&c7BJJ@Xe6U?YA zJP*6Nh0EY~Ip-GNV^NFA+_f32zagl2U(PwEk10%6!VzQIeD0wgbIGNaBe{q4xiF$( z;RG3kgL_5inYsjS54s5uXVZ$brOFPt(3+0+Sb=`zn zKZ0`2L*^d;k|g+fer4|GpVJC+Pt}8EsV)1C?qU;KW*jz0vd7QB#?P2NewdH7YB``c zwAnRmi8ZLtdxB~#b05+$M9IpqWy=ue%8>C*{#*R8EutH;4BN71fNe;p%?#a;4U|C! z`_BVBU70CajRAvoqrG5xXJf{|hwW+#;KN|;XO;9o|3qM~DwI`lYSS5f4~AWv8FpRs z(9*0+XIpk@Xh&UE&Z=Q+Ry%A%0_G`U*}3{fGgzZthOEG^O~cj~tr`3pWv|XEJBYFg zdtp~*+@t&=oZrD(>wIXPuFtMB;EjJv-h&jteS#tQGGoCHoId0~9g@03K;Qj@ArnfO z*`0#^W?*z|*T_61d=&U2+XjGvX*5DT<(2mf_D(BT>?Rz$_uNucKP`lTXo3MD06PrF z^D^izb|_%&@mfE&BVrx^U+e~YooS-BYtgltnrQoAzKvx({5|Au?gP={oWC;0X zo(t<=lm9*+j5jQ;O2fLT#$NCRq);yghOpo!f4n%8oKZfR_QVC+c;j}qlPbhP+?GWe z#Mfrg1Za$mAv3Cg4U$ZZbOX!Rnh=by*-mwLiw}}FY=b89qW^d-)Ez-KVjcNwB?208 zU2QN>B2^j+u zV!AkR(>UYWH0#=&bZs6L7VMnaGhXw${+ju!dB(IX!SGj?WF0Pcan?Hx1Tv3SQ@ zUa!7ZceQTDQhnD|JW+Eka5eDeksmyJ{n;5;@Q%ly@@#(R*?0E8&nNPpxTn{7oj|D_ z&UrJ?5vuyq(AdzZFmJS5ic%XM{j2Bx{JEcdw@!7w);#O0N&0Fgk9^<@B)nTkTM&TM zDXqNLaJAu|4MKr)&R3A~=3m)(d1J!6eBQvhy;qEvjj!uxi|Ud^byJ=n6}?q7U9>it zw{~8S8TxSo-g2BUJzR*_jvXA;Ebs}qz-_z@fCea&=pDsXZW-t5%aUTe(2U|Ah^3EG{7T>%cDgNb?I?lI^ z|J^4#bmh|pE0Qr9-UHY(W5J3yA@}+zwR}Nl2nDDN^&)PcBUG6&2UHI5$&X*6$(~%F-2u0kF zhA|IE8+X-mKQ=mdJGmeG%61FFk5}g*{uA!;-4@{|kLwWsX`X%eD((Ynwdw!fWs+N#FF05zZy#kNa@S?1Af;xV{cC^Pi zM_EVrf?c(9 zuos*=wx`N0e*ZuycCy|d5+QST_B5r zCt)jMyhj;{iR&RHAVRh~(hZJT+@{7zctBm1wj*f$_5X`2U{CA%qiKQKlQx6F*el1P zkch-U{HD#vLs8bTvb?%Pk(nr+K8glMlj>TQY>JQ zj?zy<7t5!o@@z7*P2Nb`@RkWM*q$iwht2^h46GpBA&Z%$9;A7n()}|6(AZ|q?!2^V zY}2f*G-)fHXqmPx8)>L{w%z1nx`>=P}TzB#duRL@4nJY&x zADvu3onJR*9Ti5!l-WCLE=ih8Cf3iG{dbl8FOI$V`tfTguAaEod$o6J{mt^}imfxQ zZ7I7O6ur&0;N;A<3un)t9p}$~Wn8>%D!F5}T{4fEFS*8C6Fe(w&gQ)I$k-#}`>qR< zRg*%}w|v^RA|b3`lAX3rz{5osgO36pUE$7gZ}F`Xk(qDlrEc7$!wAwI#%by3?&<(q z*1-f?Q7Q$)Ef2P}w;z%=#z~g?@#0tbixNB>;V=M>JXUk?vul=mk)G8p^-=ch3Rs~m z_@_lB`wCgfiwf2l7+XMSUm>Q2#!$-uJ^&-?F}re!Z-zL=UW2G=#Fi1h3~9tWh(Hpb zu`64kb%cZ-3K-xx5P9vWN!wO(F-_i9N|70QxtMcOO-uvgqHc%-d8W?@r+S=90a-V- z%>g|it55wp84Z64eF>XwORNn6>ht>(6^hM~b#laEa{0zFz=d8e{&wsKvv za@}<0hD60iV1({RfDr;)GIBm(YkEf!ICV}xvL&k5-+cb&!CPw*%XUtCcD>({upjy* z(7Hm@bw5h-#+Pi5a(}(uzoSh5UMY_-_Zry9)&Rac5%kEl^pf~bilJ1Q#&1 zV#6VMdD?s?ES-vn2T$BL9b%Gof81o11yymY^%>=*A4I;Pv%j}r3Ru%_DID$Y?IuMA zB2BSm(iVBvLp~3&8$?skvk0Y4r^9#)5t9Kzc}#L4+<6l0Oq=WRr!P=`PPUorZR-Y{0BWTYw|#+>*?HGjKI>bN^sSin1(Uwu)R}4DrjY}83jMQ%fn;G|ws1|daLvt?(}j;G z1m9i3a^Z>dPo%8w*Xm|Hfutue?OBy@*JBYhKx$Mm?n2BD;-Q97a5_sZ762&H?y>IQ zSPTZ^yqzPs$I0*;NtIXMz~n@LsgIx4QecN2R^5V(w`uj zL;-3y2B?Xc)7B%M;6udrLNpNi&lu7@Xcr_S{l|NNUJ;5W0zs1bBXTc*0;!rKkexzi z0b~sS2cy8$de4!pl_7VLaA!Cg4axXmcLW?9h(f}0LE!0h$7(4L7$)ppgymIaCSrFK z7+EKYQCLxgP|}P;ZF?gSkU#11P0VE_4kIU{pSXtc|$E{O_Bx9;QkE8`T@a}SI3!jn&ofm#5#*M9b<#BTk0Pi zfN%)%y7sN`$7?UH00t)?o62N0CK9xZ+`@=6A|n*2zaP-%7`m6p{Oa^SsI z6I4(sw*l|V|sZ~jYL!^DVI-RyLWh)50Q5>zY zXt=ja`Zm(D@}$=&_FV)^V2jj_XK`<4Ap}+GVGY5UX1vATo5%SZM}--482~`(@=@WU z3z5JoL@cR_dU{iOw`N^p{hsNXz4U9@yv}H`BiqX0sPKWgNXGuOfkdGi!T+!E6vLi# z*E|1^-S7z1njq@rauJB<-FU8j7SyC%>Yg#oM`B1p2*;93YRRZ2<-+d>r^}U3B!QVy zqsX7&<0uzuSB4Ufk=#1$y&7H!5rr}ei`1L2E2?`Q+E*hQHASt@&54>!H_U4NBmf@a zFIMtggomOQVZ|D;FKXfxh_rGlLrJa-4y}&Y5Z_@{2WrXU;6V~w<5T;geH4p*jw#@ujWye%}YuwsYw{_X`FTBurG{BU6fC)ge<}9Oc83G;9 z#Z70TCrIrsPV_GBy8=AJQ{&e%n6gYo`9qlwtGj}%P(ux@#U2(ttMTnofk<%l%i>Fa5GS1A0Kg zfKB=Xd?(bV- ztqI$Tl&9cIf5gByS{=edoJ&pI6BobTfZ$?zwP}sGrj|fC!b0j zdOGQQI_2?=uK_Q#qTsT1To@OD-B&hDwM|#79k<;n@K2UbiPHt^F6-yY)_@HQgr?mNx~ zR;QK+=4~a0;9PO_ya9JW`~0=@CW@K4;_`V5#jIRqHA@9N(CWPBz_W!%Y7JhwE~)|R z%NUMCfwH7|tfREyIO*6fV*C;u2JGbTkr?Fyc7ho0@|6p^i@H&+ix>Hq?J9g4<}-Br z5I?3d_W+ypp-<7pXP_cYqD2+Kgq{i@2r<$K4LdOiQ~?+oVHEu&p$nf4cS5=+%GerK zG6O16hA1LEro6h=AxuNYvoQs2X$Fvj_^Y$O4;T;tVjW>U$lncwlCAz|06^&kcxR9a zihc|PX2Y>#w77u;0cq)%SXIZ49f#m*0Ls=erXaF&mJkIIt8y( zQ9ZTjsEp>ZX@>95F2cj0`3$o_M83;sPqXNb+z3O4@$|M*N>2_FTbqW!26JiEfZMKZ z;jASrP;;pzlbHnalf-bzH71h{PF>Fuwp9%x;e;rAseH1)J0owwIveE$lh|D>(XcH=4#R|rJQ0M<< z+7El9TY_4eS5(mQ=?M2LS4ql~KkKPZdaB=iV%pO<>v<&Ud1TttG}@f9yJqd>NoWRk zUhBWwKV8u{V_!YzDjtnqijT!7mL*&b6XI=G!(>;|)sQeZ$iUUiT7BOk6GqMQDrB9w zZ-@oAN6yK8`7`R!bqXjJ&`Tq@rR_wBKvD`rLH9%m2M)% z5Ou8{5p)e~D5GuGP?$6nF6az~;5|KOgj^9Zuz&3(6M@Mmr){+fp_a9~6PdINFpn<& z-X4Sm_p)smGGr^r27y65-OKiNVbOB~d#=ZG#Ln{VMnF7c+Pr;WfKg^4h&MP!ph7l& zDoT0>01^s2j^3v?rFhzloIo znvN+;@|e2R2`*@GmI0E*R3#a%$OWqE6F>?h{wDg>bZp7MA5-8|E8v(6rSbi`7zIr! z{b~oY=+Z10zy=xtksLsVY%9{-jjZQzzO60+c0+mu!TS&28`3xGIRr`_S zJNV@R(_q|Z43<{hV5App2zj3aUx9WA(GPN-Rsb=Fk1ZYN$9G{FL$OjGJObQo%C{}r zv1u5+G>nH3`K|%OXOL{Uc=y8qYB6P=gFx0Ot})@8pkv3Nv^J(EfR^F*tDsF_)k5$z z2zHG0Kcb$rNts~4c4)DtEzsK}W<*Cv7W5)4Hf^Vog78D?0NX7}t@V%4C1XFd$m7-O zA_*#`1|I}re?sd#h}2l;AG%8K_^KzjPy1Gk^C|E4*EYOfG`T+MU464A;obhuille@ zt!2|*Fn?QQ2qmya#tW9>c?>!oWk4yefiH$H06WqT^beqW3>D8nWNNVV4h4UOfc57X zkcDkZfBqF7#`Bi;=M8H7O1%0PVBk)!sNzceay(JB?q=I`VbiGnw}RfXlmD2b5NKRp zaUvIqPJ1R>FRh5so;mc8b&_E%tLr6Om@{yzpNUSC&bp`3F24* z=3&}oV;1VFQwK3?`h#`b8-*R16?_<_C^j9Xzr>KF4Xi*&G?sia_MvFHV*x3j>2L8X z?o?|CvW!2Zj}*WQ%rJZ;i)+?goHQ3tEPu0T#=P>5%QtprYGs-ibHnk-i zU3^{EgnK?K&WH?o@*S;L7>dm@qIwilj?K1Q<*mso7*XSxCJfj520bOJD=m;p`eMl!r1-?~3&ED;JtTRDMxYjv z5iVu2j|@Y@3o_$bTNxx*ueVRz>PA{prT&qY8KEd;%NyCxdKlL=Y>yil-yv<>d*IN) z!)@{35VEatXEXu^o3yHe=BWy56~c8*p=uh@it(tL^rin^fP1ngkLDHR<(b^Pa>;`*^HWN zi8YaBx5RkN8Qn#&K}{sVf%2#H3Jv?WD0r2EiwJVhg1^8U#*fVL{b6*Wv44?Fxl|;c z5Q6j7i&Wxi_gQjf_Q6~{#xC7yj%0n11VRBR0u&^sao=*02cn*K!y(K%upH9-nl!&U zZIgLSEjxESwHy3p9|?~%hIofe4loXnMD$GB)UtEe_NVr@rEN;2hJeFhlc~7|Z~0Mo4UD9m^rEoeck==X%eyV-3k|9SP{}b=@%+ z&YCNe=1LZ+PMX1X&3`6%q2*x`yleo7FGxAd%JRa8fAGn)05823BihLqnur zj>cU_z?rvX)7$ba!Ep^Wf_S- z2@k$#zKqEQ&%Wjo?F4v(8Pc6E&Tu+%X($kXdWgTFS9!s*mcYf3rX^rdY!}zd!pa8O zFk912X2y49GpE7;;xk|du+lbvf^O8K6QJ=G&9PjNl}cFLTT*?iHB4{Oj-{D zm9ewZHaV+o6}}WIN=f8jGOauvXhjFX6lT;%QbOqiB>S&4y-p)S)5~fo`pBF=U&NU) zrHUq+ukF6Nd$#P6+hvd3F?+{%PI-S+_*UU;U}rM0^8@p)IRclTE|fF905h}Fv%3?v zvOAu_Sx-&UQ8bn=CPX}DA4Kl7X{SNw{R&?n>`_W2J6yH_2jx-wg z8MTD{C%aF;=n)pQT3tc^=S-9!37TTCxy%V((QEAzC^vlSpTFD5M{X)f zW|WUDAvJWZz5U_)Xa5hoB$!ajTEWH+=Cu{G0vOY;VLeFO~@QEn*0 ziczg}WvaFtlJIC4i~v|WfDgd9pbav=G^!HrikTnuA5|$WI50Awv`Mz&11^C7WYk|l zicNk7BB;O!6hvuNHW55%Iz~(V7+dP<19ib4(}ssq5`n{(efBa}jbQM>o*{)*Ca#xx zJFM}Rb!8FWkHSnn7dCCY!Fi(5(!!uiklYH zP7?^6B9yPLrF!t(v}thc*tVr?G+4|M@Bo4jwF+o~s3HMc`tp{dmh>4zvnIG&t79+l zc=F0XSVR4i-9lZKj7^6LMDsiMuBR2p?1$8e{qUKtem#N(o!KZh#cf2&{X1X=jLWYf z@k7R3N&$rAsXU9bd=xf&;Q1+ehD}4JT$Tngt;U#!6lRe0E=~0mD4Sl&M;SS^@?%bQ zXH;uL&H5qZXW8HCtGPZmWz~Zz$yZB< zM}01<_!$`m6J^58be_V#CvqbO7!*x=h`UT^B4Atx;6Yb6H0~H3v@76E3%!uKNq>zJ zNqZgMh{SYW2B(xkKNM)Nppvd)sj|bT4X@irI7RyHIcEXNT-w55M2tNO4bJ2MXC!73DUHI)`9Si{x8S?X4Qg+ z3p7kU^`qzBdhX`gTfXUrUAG(dzh5<7cVN^AcA~{~$uZ`bDXhIw`WJnPf|eQc&R^Qf zQ+Cg#17inX56;*FbGGuyr;@gnsk)V;I}^aS?aSwYwmbbv^RiiUebQW?XxM&h(~NoF zU9)4%lr$G5&8sJk3G?cy<+shN=SpDvbUyW zM`!G-GQYkwW3Qj9h1${w<{DWtqk#!@kl3D#68tZSJWMm`^Yw9IJ_H(CGGQU=d*N-A z956)${Nj2Iq@|M!EQrDlgSud#0aOoDB%&d~gk5@p6`KPnysad|TW$Gda%RBA#h}0( zB4rfa*dhz)evOWEzb1|YGaP~H%ZrG|oowe+ndMPDCRQHlH~gBCZbXo_tMiUkQ>X19UJO%fvqRrjI@d7(1Cm%&`V}P;XwoyT1n6|ePi47v;eka42I+j+r`VFU z5to@;%9N#|mad*>Y5sPhCa}_Mu31~{ZD^y|J$H$n#tci&+_tUwU+pXJSvkkrIZw%~ zrxxaeiQpDk5>9)ze!}sVHKRMUIW%$j+A~+5`QCF=x*wU|GJRlQO=g2@z~rdQo>nxP z>P5Q-n^yl;*_-fTv!|VsPW^;{=^CqP3?7}niNy-_D@`KBm`z|k9>LRGa_P+8q)w<| zh!2N^&yq$D8#4A(QbERWqNhOZMCPuxbI35rOO&Ahb&Bx=sXK(r?f&Sy;eyxD^BJY2Tvi>Q(hNz-DV3yYo<21L?Q=N2L zdY97B-Ypv^GuTh43&DL{3h4hAJc$=%fqqt-yeW0l>iH=W0Q#rQ_E~dP(p)uTu7MVm z(>wM|(&3-WX0pKp1KuHRy^?#jQ|hXY|Xl=lCG-BbyLDL(+2o-A)m{u_ynfG zMR)A(OZ&$5P1H^>d=J^7ow z9o5`>)s|+z{=NE@&87Muml_aX!-X?18gFPGHRmxnP6Z!p~T9!iz%gHefyC-5EYcnr-YtOPbK)&umFd!)SB)QCZX;Y}rd; zK<<{PtX1i^Xhy)zmOFe7g=6xXcM#s0!O^CWhzW$!M%jI*te?kWT4X?g^nX*T{|7(0@B2bvX=Lvw!KUX{2!5J z$pXLY$a^jSa$(ZFVlq1IUN!BgAJsw4aml*2SoZNLm}%}E+dD2^>AT$bo&MQ^K(Zh( zTd*lvu<0HBbiw8s`{N6+R4*7m{wg^t`*gv})~?>t$^(ixJfFFIXYB`)_5*NupymJl zf{mHI>ru6q|Mf>_OB<7=jnk!T5+!SIRwaryytDq+&Y#<#xa-PSDxSAdmitkHhwpNa z?9g-X=`Afb{d@M6%?ACC4UZ!J6DyCfQ(;;np^O#Uh_t+o9|Q_Sp1z5E<&p}Cy3KeA zqD}x&_c-o3b;t3pF{5>kGz6EITzIO`7l4j(+w(Y$}JG>r;?mLadAJp5h6(nOL0kpo@w z0=@VT6x^YJR6ny4GYaG{@hoj;VmyU-Q)V#it$;Af_QCroqm3r>|3R^w^Vm-FxG-xT zXP0@Erf~#$F^%VaT>aXMx=YqEYrq>m+$mk2g42qv zSGPj#b+&SCvT`kyUuTzZNG{(1)_<9Ebm#c;vHdjl^2g33UDcC&r(#Lh{&#jIT>Ec@ z5lfh5x$7cvq5*AS*xp@4WZjAALyQ@sH5nzDjCp|KeV_$?2y}#6;d4`&ORfyuhS)He z;Y{SzM1=mu2~HIb0a|L4>Ida)i=F2kH1p|n0CirIBQ>(w6B_KzUjGnc*g$7 zT~gd2r*GAh@KRErFxSgEL54P{gtrBp(tn{oO;X^e;2H)0M8PBlY_+i1YuYom8vcxa zUZ>#u2;NdOz$uQE#D?OB^s)^Bwjg+-p|o+ItV`A`<8g|Hxhl_P87SF(3+)EaBiB*c zEXgW4Fn-b>QHgAX^XVro&HGx3OoLL@SzppbDtS?}GKElm5)}u71tKh@LJF2BuK$Lf z{R;)OZ%MT1CHkV$|4h&R4nY*ZRF#nr=^+JP`m%qE2vZp;hswwfo?Ee!l-jFnVQ_#o zKJTbDG|W|0%^PqB!A5%R6f<+>%jPW z6THh%|C_2}L-02ny@rzcwIKfHEndR`e$HDyZ=eXucfnwoMa`Uhx%?V6pfnqM3f1|- z-#94x+m%*B!^a!~Sy6@hvj`g{X+47}e~3u726L|MCnvPPn$6y9RP0jZOLFQi$54-a z<=TMM+$vjPi1|x_6ipZZqc##K9y`_#Hov6s-=%OLnDdPB56>AVptT86+OcB_BcE}8 z$tb9ec--V!0#Ya|p)cSZtEqy1;x{wB5t1MDOWoj)K_J5{NQob>6b2?YX~;vq1&w@C zRAmKe&4Ficqr7DuMen3A1q?bFd$9oEmkJ2n0K~TRHf>;iU~0jt69qRw6nx48u&Gr@ zrI?KWhUVTQ$dl!?f-KD^go*H*%~Qf3@15M2s8~H)u_;-x>2Gv@XZ&j;h@NTNwp%-s zw!H~qugr=iABgVe4+z3TzO+%X{0A@l}C>1clJ~KRo8-hjhRmSdA zHE~G1%3KPOOpnHo-ZH40B^B)={yxdqm}r!Z5`kLvt7XgAays2bb9%$@=SQx}nT8Og zF3hh8RYo#+R%9-@YPKLZTdumO4`>#UHK_JsK44lrFy*oYzFONC34Yle`HWVq%@Sc^ z!|^|0OsRfs#Q8f@$OODGFLBbKOd(@b$W#1i*)WW7e zcXuIyVg~zaGngEq^}aw$?!HA6!N>RbSNhw!2bkYySwqE7N#rr04-DNCpaXkl>GBfM zGH?RYTS2?}f@$M9XoK{hX~T~Fdw^BxK7w8N0i8KcDn~$8h)CXfMvNNpVk9vF}2_az0Aub!3;`xk5G&%bP3dL3vV;z%NlRh z%ST#%Y4WAW%2lxJO4HA^$_0>$SC4HeKFyWy|F)lPlm{{>I@S zJ@eKxKl;*JUwUWXOv4_9-3u3vZvULOH03LTLlTGcV<)Kec`r)1A0;m3OTvz=+lCk*st>X7UVNzyljZ zaI~BuY_4aExBEl{NV1}%qaNua?;Wl20<6Fz$V2ZLnaoT)Ywz>5aTi{-&|yAIbGFG3 zpK%c=aCUWp2}D9;d0CuC4D0NB^x)eF79q)=DEz-bK2L4xIF3VhAQNf802?vj(E~`$ zuw=8J{Fa)XbEblXsp^i|!MHW~tELVnR&9P~d&0YA#=LdTgvkikPweG*$6HTbZ+pj( zsM!LKqaT>J;lu%Rv5Y#SRP9pGX#U=MJX&mBC+eU;NbX>uK)6&%P;n1qJZAt8!_f?< zc86#uB5(Nd|Dl;#%gHJMeo}j6I&%aaNfoFQiLrAjie&!n1eD;a4>$n6ilRBkT<6h% z6L2AGU1*Gf(1?NNNJfbmni$GZa^!4DXl>i|mR=H3lJs)~X*(I1 z_MRrTP3$D5#|S+X4iQMR(4!6-CkTwM;5j4N{j!w@Q#2@8G{Bm!K^e`F0%REB?i5#C zE4f-Swf>#u?~60VM@C^gCVy-J@6}7AjQ*G>26v1` zja|9u9jID^hEnsBqP2=ygHF&|mMbSD6)!C+UE{*3^~s#IOzUzKay$5dhFwJb&>@Q65*)Lis9o18F7}5JFo#SyanG|tm8hfXa0yi*i7Z~D?Z_T7SA1D z@s<6T_fO_e8K$DszIC&{N0Yusr+tr&?woV^CQP?o@V{(w`|tQ_KfO~}MGiOocSWv5Ke_>3en}|dE_k+be^|9y|96i!`}FTVF6_|h-s5@1 z-_up?s4=`(W1#q|C`QT;GPG-?XB7D8i#>|xWYVSwe-iFdJR>dl1m4gFZef+d z!%W!dUj692p6=V)*nQ68Trl9bTq>2-semt(mIdS|@aAD!OSx4b-$o9)NToz}R!piQ zBm(W#K_!HME4u(947ub}>hc~o!baswLxNP8v4P3u^^(;4Ah=Lk4_`#a&&>e^m_<4C z(a);`YLJU_4C%T^mrCtS)?MU@^+PsPP}nRT5~9UJ#?LL^vZQ?E2GG@jIlw%fE^Qb# zKF3|WsBRAMmh`PQ1ziBXuVD+C2~NfXKhyQiLMs?^g0Kd8mxl!&z#6G}v*HxogHg>y ztO8PofKt@a^Ljt33NV@)u1LVyh``y2swkfpD2YVwCuK@)S3JmQQwC%?5EfXu4pJEtnj-MI(>d2mX!C=_< zk=X-x#_&rdOm_Ytay>GgzhTrWW49mLyjfs*+pX$bgBfT1Fn+TaWW7F+4YfG|bPuGH zJ}p6F`R@0It(R-v}?ppziGMk^LW=Kzdy*y563ZujN+f z`x~Y`@Vft`Vj#7Nkz~A~6kzEUE0o*}rLx`A_k|sgaqm55YqscrY~~SmVi2@TS=%!9 z{cv+18T%IX%oK-txL~F@2C`;MyN{4xXbd)t$YLiM2L3-ih=DVMn@}em^hxYH5@Qi} zhKU5ofJG^S?4+<%7#e->2+R%$H&tH)-L5-!tV!10e~eaT1O^fj5%_x`=-(NFNen9w z^PUx;&H~tQP@O7TuI?eQOkmW3yiylw5s-8rW5eHzA@XpAqKsG<>NOhr&C~! zd#PGvY?Wk?74jFAb}*j|v_=RofekY_AF`mH`o>TfP345jiWfid8Nm=`nZJyYh(3l~ zpA!1Qx$|f9YLj`jQ- z5!#L^g8lfn28w*lQ7CWAR1~xT2P5&~!(_As9v(B?qQe$3+lUwr0>!j~IL3*(BnXci z8-S=rV=x;$8MmxiyD7LD|JKBdX`jg0b`eZx=Un#F(U2yEk;KgIs01=MLkR=jqd>;v zKFUjv*jAuqqhthW<8{oY4QEb6?&HCc+*NRAtHFJPr0`WTyBI}!T8=n!9eY2>jbBP7$F*@pBZI35hxuE6fu#|+bPw$7!cfgh-H zlNOP|fVLLk!~%o7rXe$!CQ57R^zJ1jcoPoTGN>i1ZIP-o*mX|KTFC%@qV*MfHm?fq zi0rZ-ykSd3KV%hk~953s>X5zWwfPD@+@uD(OgkhHSO-Iw1hc?qUvjvg-iA)U=I3 z1ZEf?P3I{~l^AhsF<~>Lc1vU@A|0ZYO$q|4R#518XK*jl5mbEs_&KmgjzW>|4N768 zw2aM5SPIy9Hj)UWs=6fP*QX!lySjF`O%cU58v%5-f(vJMoYKl;D#I z5U)c4fDG}Lo}yZwrhtY`R$OJQWRl;oaZ->8cH1V?(f^r}QV^%X{98n5Fc0b6h6KAG_N9nY^Y-A_=ON_jjauxzAVE=8Yd|x(-qGfHLGP$Z72|Lvx;O1+_c{0Se>UJZ)P}rJG{YIV3vT@U{k#iB$%^P-%iEsE zy_;v*;nlxeyn2UI|DMx;I7|V^%sE~uuUgsW8EP>!wK1E>aGW`x?8G2wmxf>d4W_kv zDCjU~`3x4BOM(IEMHZf!i*1P%hKxx`E_EQJFlMCyR=V_pl*2p>B}5!Quff=y3hG#n zOD|D75R$`sE!9s$iJvIA4T$997uC zi`Ij(7HBsK$&zXY=QXL8>RJen6=*-f@=>42hzcC9Wln5THWF3>bA3EOzWY%$)4-7H z1;L2}2MNOk#@r3c6D?qF9N;ydv@=*{RjCAky=$vXn1M?j8KmNH-2uLVgqv zudy)oVUz-$NX&{*5JhtKpj4LeuCF?dP$7caB}EKG`&z3MM~HJFfeXfs*6jn3x5sT( zCRE4n3&Eb_&~t5j4z?a?+kUw1sY7&PMYt1&MmS1J8}XC<{iixQK($z)M2d6n@d6}> zQI_cu3mpCs0wrK1q0#c$FkeNb(n}N&6p&s=kajTr0#wQbMOhl-+i446(sB}Prv-Sq zh)7#03%UFwW`9~ByqWlEuqI^M-s~f&+n`iKiRmmW5#GeZu(j=_jI5#3amwU?Mg?uj z^0TyAi$+;awXYz1!_=5g3W!&fHYsvf+2vrKnh=g}J7`p-Q!T&{D z)hZ+!;qLi3Lmo(7o9DIaE2}QA8ZVy^-(2^D&DS?i265EJn!G!Cr7{tmaMj^KApcIj ze>Oju%nv4fjbyyE2I5YG4P4{$%8_O;lW-VS&sfi;$XH~eW7^p;vin1mGfQ+{JL6q> z$Kf8Yef21cvouYF?%4BQE1Ym&E4W(ly`srYQ@f_!>uw&Iu|N7-7%(=WZ8*^b4wf$B zX}HmU)ngaU6xS8mN7U%<7am27_bHDETewgC`42vO!EW1EXUkl2pb|9FTo? zVu@1`I5dOow1H~|$sZZ$pIV~)Xg>xl0OiHVFd61B@<%3#lw6E5&N|!!fQrOX&`{Or zY({+%u}#DtphE)`ps0!Q3f99tJGZwmjjn@-+V*0}LK%R)CeKXYq{&8E7ooNqHjoxT zFIg`*vvnLYJ4h~!phx5Sqfq5iVgK709J=U`#Are0;EP;XLFNP^+6$nvYR$+7)bb+C z3Xc(>LIR)u>De&s9H*cvtU zs1$YJl`j@LMz9AdRwksuL1rOWB{2_ZBdnyzuW-yinm}TeSn$?Ps_^QG6qVkc3fXdDvGWFGx=?3S_ts<`;MfD&&lpwDzlD z9fEw~G^qahgRqAqh?_Pk;Fhog?IJh@?3cfH7?JPt`+(Py%=IYN=P*A;r?~MwTH;Iu zYdEI|$v@z)@K|4d^q>2o{tPeM;OL}hQD@o$-(&I~70{=3!PU}fdg>s0yMt{pzzi4h zA?{l?p9n|jxauwOW%3|A$dJ&IY{K3U^`niS{v#37w|!5)FI;aJZ@co`x1YP&_E%r} z^Dj;3H{-00-!WGE*J^6{xUSwW(fUf8cWT?IyjMoq&MA?K5r&UA0+u6c>!m^V^f0zr z)&(d9)!_*fJ1!brVw17KZ9*h#Z~?G!*aNc27Y=)1mT~HIR0h$vco0zul7ojcOttH! z{xfO5d(m)7U&Wg*Fi=m^Koz4fWuV-_$?Dgt$2%vMUGBQFD(Ma?BUDt%GfTMpd_!CZ z2Sr+gk=2Ml)-_rT+N{Y_3>t9kFb;_#T|%fQA=JHLP&(y7r}Q*40>XX%D{)=Z=KK7x zd;qA@HR%HNk3XYyP1YazqFsBIx>kiI$y1bj!fz%*T9zT@avVy zqTO;IUn(f#1Etdch8(hM0@I+>i^(_u`6qUeF)z93A>Wb zZa|lEY_>2DJ8Zs7*~sn4w^L(vWm6@=uEH9`6Y6<|6E z+5+eQfhB_mMdhJ3p6M3BOqVWF3Nxf&bQWNk^)gC~HpaGM!7+pi|LPy9{S;uSgDM6X z`5p8iD>#SywbEI4P10R6>uyZC8>iiCrtND-;5R2vRf_aB&X}Qs>-=Tq%GWwy3*Rhw zr#P{?dF0?7U*)W?HtDOK^=(M{HsG*7w{P0_bmGucGrp&%-A|7^k+L~PTITY=zOovM zp{#4qBS$=NWkUAauXRm`bb{^eighN|Jr%G@WA_PXY8$WIM|ki%j>T^dil{Ab2&I^muzFU@n#(S zHJ^_<;gmD4Wa80;bNR^bl%sH>7^nZBZzgxj?7HL}b6zjMeER0T8S}OjbUf{2_VH(D z%oTHj?LzDM*71!qLP-h-74AR3f4l&Wj=^R#IH(HCnB}#e$^0LbUN6OwKg-tQq@PjC zjCnoe@CM6;edqU$^W&Rlgwi{YJpMPGw`%`Q@AM=4W*z%)uDRGb?G8@)X57IKoWX=+ z|Hv)`DbOb@&*alT_tsDH9-(v=GbWydAq2p>1cSH1 z7~`v}-Uf+B{{XLp80g!XCpncdK)ed#%WB#tvQB?C!yF`&c2<@33!PQPa(~u=RaS*( z`GAc@&*uVIG<> zFO!iOgUC7W+vSNP>$`nMe%2$o?cb+X%4e`hKct3z1HpZls{WuD?qsRhu^xXPiIky} z-lSaYDa9Tv%PyC7kon}43t}U{vQX@SEYh23l$>%>Ej(_cBeYbLXQRwyVuM{mi8I4a zIRd)YHheJpAn|hOWFs5w#127Tx*tb*Fw1Dw)R|dzP#(Dp6hlrXyI@bhO|LTTWgTBS zT+$zF?fo-K&U!|%fKPgt9*k2!_@CU)=MYQl!GNNJsufFd*dQvg7qr+m#Ny41^~2F_ z*bYFw}rdQ@KE zBb3!D&pdEdFO+WHhZ zg<_7UWWO=%=oP_AcEmP2?hieMvI&8E`QX1X%4k$p)LlwSGc4_8{8V-%l6H7gI*1q!<~uGplLYxQQ%7(iWzEOEoc7S*Bmdlyjtih16-IEW%|=G;M;E^CWZ_m@rUw zX-H@xW4NY`%_sZ2q3go1E!qkgz?W5nN?64dlp(lp-YlPNutoYQ(&0ZB{Zk;E*ra*> z7hKgpaMoXN6(4cMA92o)ILk+zi-p#YxV(=z&o8)|UvQPb;L84iv;Try!QvZ!!PWhW z^Z$aY#@ji)aAE69TR#$|IJKQ)`bJej|Ify0k`=C!=>UJqZ$ zyY8(&z$1Q4SHjoMH*q@sg_83nbBCXv*X#Jal-noY{VV1Bwu9_GXRv-^!25f8PG_Ij zAqEbylJyA7TBu|#OvzabQ`-(v*1|c1o3a*aSqs6*-NWza=k_it+p_WtYoRhP;sjDN7YZt|>^;ACv=c09*nLbkPq}}T|5pCw6Uky? zM33y{_zy=z=N{$Wuqr2gvnEhM~=+!ZHpg@i8Z@t_&wUglwkkRQt)bJ z%Ce3=uEn6!VaDj3ayco%wy5*(h%=Vvl!Fbc|nxHF%crU%d!QV1-X2j&NHuT;*BXQRwC|mR>!;ncM|G2 z=S>tdgPNPSP|V7?yz@4S**S0Fyn|v+&eqD$yC|B+d8+2!6!UO}wewzz`8cEXlYGQz zJ$mltqtbg`wD+D3UA^bP7|DSP11ZOlZZA)%pJL&b`5vAMibK|FpXEGB&NIsuC%NK@ zWfMndxK(JVHVMuos#|9Gohd%=6J0%DPldQC*u~Ea_&xt6980K9n6rtR9W#7$_A~&= zl(OVwqL+=8B?|UTTlS`4e}ZwZU2rIarF@vt{>fNk?co{z2&*f|uhi;l``_G=5uO{Gnj}`YwpVgc7Dd^WOm9nsfgE literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..47f9556721b818949b5d9623d60e7c7268488ec7 GIT binary patch literal 16246 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bd5e19eca734c260642d452811d692f9be7adda8 GIT binary patch literal 20427 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..25b9ec9e541bfe0f1e6f95da59e9c323e7d3dad0 GIT binary patch literal 9144 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 E0`jTZSO5S3 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6a6cb5090e3e48cf1142629b973af97202eb470 GIT binary patch literal 3261 zcmZuz-)kJl9iQ3zsrzY3mWo}~9vaEgxz=6N;5=M~)7H_+CaPnw+O$`~-RgGkZl%55 z>&%>_6LNB-2HPdz_92lI0`603Foiz$Pbl=oiquMM5>QD34fH`+E~I|ycV=&OvZaCD z`R>g3_ssY6-M=T3F$CkEf7>;$_966z{P0J}Bk=xzfLKQcGO&djxQMZ&HA^dMY7P_w zY7Q1dFbAw~BT|e2PtXWi(MDgf4l{7S8nKe2OL?VvjDKpeGhy@Yj2@k{s=Q`;^h=OZqeTn>1ozZLqCnQeR8P z40hwXZ9762repJK@Ex0VD!O%@IV@3pFGieYo8&8&&UwBJ%4?=w z%id7VUD0jBq70Nvv4-9z%epPVy3!`ih&p)Yhu}q|yqEks7-(_OMyjSo3B+lb6>(r) zg-XDJQdZIJaY4*R(_vshYBfwoE5d4f#$g{4Ql*eAhnSF0uEfe^x+3zqTov43%=+HT z%#^&$lsuD8s(mMIp4cx+Z{OS zAxncb`EUZS4*Ks&6it7Y9=`YX-M8=G+(=J8icWqRPu98BrU;Od8$>$I{+%&M#bxG(aale%~9h-s_J=;n=7 z>bhFd1z9#NtIH-?)X~diV?J zVF&F+QF3rQF}jf$-AtV8Oz)&lc4qz+>;EjC+DsMx^2YYX>5YriTdBfUys$I)t=;tS zcA9*WCOe6K5QSF=4W3@l{yuvr@;Hs+1A7Cos48Ri;YZFKP6O{h26v%R98}YB%>kp%RZN zDM*BsT?%T;JAH}W2WSqZ3-DbfHl+qNy8UJjNEy zy$(=P>{A}9E6Z8AB19clzLa{t;1Xfop0635=N-4&s)^EKzKKRt|RIq_$@4N z=tA#xy;rAy^0OI`uBu=-f!_=%-s_&=xCc_UbAVEQ_w)2acAkTr3q&^zqAS1sHhTa< z&-Pi_Nj<)5%dX_h-O!|F*_4kqjWVQE)B!T*b#7LqctZzwWr{K}H_{b!`=H8a72LT& znMXII@}#QPjY5R868PMZieHtf8w01WcsT5)4O-P(mhgcmqX9_3|ID}H)^PcwM2J`O z$qM|^2wL(|!6slUFL|!RtAn1LMya9g_s?*Du%J__sG(Ni1IQy=BFqUU$x{hgnxItNd}jEWYs zSEC|32mbPnRxVnZEqm z)oU|ujO#WxovcinGAhf{%X9LX8^F#MMS4OB)i03 zh7E~PoWpA`fHD3YefJBL`V_@JMFU@L5 z>dXn;zjq!DPW*0sdtiKHVEoZUeskc5o%9Y$Z=;b7G_n&M>db5hhc<#kkA|;p248;? O(6II-HiQS1Q~w8GYf7>J literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e703fba22e1b78da9808e4aa9a4373bccfd67064 GIT binary patch literal 16362 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be69b982e042f09edd0f8e7a303f4c43b2401cca GIT binary patch literal 1216 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 Ox(7-dT|kX_PX7xE^y>xy literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6f95350095456d2d2bb3a7179c5251c58d375716 GIT binary patch literal 13606 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 HA^HCS5V7Z! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3994823ff4286db811dbc95088d41d6e24eb44a GIT binary patch literal 4124 zcmbVOO-vix6`rxLjeju4_y;h=I4?i~1Uo=@B=CR$$xDE~mz0nf)f+U}*N(~H@tYZk zz^0*_kX7)?W`(ng(W?}?YP#ySQa5v@sD~9D|UgkSJTzk zP7uM;U)N|7MCnGv4b_+{nrD5*&U0+7sts)n*8Mf98mDhl5xBalIoh!^ z)>PpbH>xom`Y|y}!@4_aHI8Zw>njEXT=h`$S5f@>DA))7KJ2e%ROGI+GFViWF>BnU zvh6k~^O&sTX;RD^3`)z zx%M^8-GBbQtHxi3c%8ehpS1zAD+;RweSZJXj|J=J&1L{RKbtRf__MkIIlp8+pUC+? zGaA&-A8P`=&P!UI%+UW8b+uvCa5Zm8-vds|C+bQVv-12IFN4|t3oPl%MsAojyX6WFKZW{)g|D!yp z1GH>sQYlVk#3YvzzK6Z@@x!}|bLljjjH*gdHQmEZ4D$krmK7|d!4val2oLcl`0@xo zvO}{hu#BL%n%22YDmE}C+t$|N88O4-wKd+TxH_X8%i^dC8DiF>vQhb8|PBna?^KATBTxH6fw_;94|ZO zgzZ#R-LA8^Uh)qNo58Y4%%nkUuXL-TvpmEqP=D|%xxCCYBCWh)p+rz)1F zRjBd@hUc4vuU zm8RUfiWxq}ZKY}s!BxDOW*HGTOySc!zD=^gycSv0-(|UVhOOz*I>)iHM~hlLTV~s% zm0#V)aVEpoOYa7q+S&&^wC>{qJa>4WX()96K)fS zGt9`&IxNqIpNKz*UUYvXH=Z5e+aRd31iGc& zr9ENyz9wb}@oFLJkF@!eB~j2@up%!`y$EACkO%#Mw{K<+90O z8aOqgR>OsKJ*}8#Kb(3c$+aN(hCFCtzk*WRE zXl^%1l)LPsT>gDJXU$sk;bZ^bTEBVW_~7y8maG-xeH_ zbC{seSrz@({>EPXjszzq=OjT>Fbvc5snOU0AfB>?3iKR4K6tDZ#qVF=drnYC{^H@_ z!C+yf=z7<6)OEZ{1}3GxN#dW9(A25X5P)Dmbg9#S*mM9Rs|rL$f4!OQJ56+@9P-c0#L?&e^iI{4{ADkeq|X+miDdK_mLcxp&J)%kL4n zIxRV;37S!$Zz<3ofNllo-oCdJZ?w#N(2cw?|Lem?2aobL;=Uv~FA>!HaZO@j0ovp} z@)njzPnfu`RTwC_#~^htqz*!Af7hY^z<&XhInZAl$Nl5>cl ztM!(u`aFGTKd?)^6QtvY ZMm*Og=XHX{l@t?@!e!WX@HgNA`7Z|(doKV0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e8779ed7e91b9be1184ebd306b65a25422611fcc GIT binary patch literal 7015 zcmb_hU2GJ`9iRQU^ZDaA6B}$kOa_xsUt*teNYd1DPzVM>k~(c5RCPr5*0*!^!g}{Q zyJyG7C~ifIL9_*>5um2R>4!>0rS_>+rAmFR)E7HWin~fAs;CcrsAS?qsnVDJ|1-OH zhjH3GbWfh0kN^H>=KuMd@t@P_1_IAt{&d@ZWE&wLVk3T%vZAcM3zaLxB9`Kiab;Lh zu&z4lux4qN?&#y{a02=?E8!%^>xSz@Jqh*Ha7rO6VcN<2Vy4x%RR{g8)plI7QqaFS zZdKn!bqh3pRew{JeZx(_IXz0OhMy`om8frnN)8jN@hq{LDs&mqmxjI#EOS$fD4VC$ zY~~->$SPr@>AGHE2Daz=L;pZ#(3uRTO13+S!-X>E%nb~)RDxz5XWuF_KM0jWIcO$E zys~R$Q=vA>f>1AcFrtq!(+canl3*DoE#|O*g<7c`go%Kg1r{bsW>6R_$mPf~TAQ*O zK>G?|WLUAtu=)~69%QW!>z2k6mOcQZ&`MefXeF^VN`~t|o(U@@#_EStRs*yeMQelA zbXFg(XASk_?w^&h(r5LXa&9u*2oh-y_2V|1G?O|ZN6RAx$Mk&~jM+YwRnxVoH^Df! zEk^stSuob0w`^Z*#fZd`r-9c%;VE!t28^0?l(~%C1<9jl#Ppd(Ct#W!JzzRc%*XT% z?8MJ2p9((MON(Wj$P=VALzZ7>gD05kj4hF1RG9pou)&9kUrW4crHr5B%E~(D z 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 T^5Z~zO!@Mq)=vn$#QgsO$;K6Y literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c12170698a71a60667f25cfd6dd8279d4e85f650 GIT binary patch literal 10047 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/app.py b/venv/lib/python3.12/site-packages/flask/app.py new file mode 100644 index 0000000..cc326db --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/app.py @@ -0,0 +1,1536 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import sys +import typing as t +import weakref +from datetime import timedelta +from inspect import iscoroutinefunction +from itertools import chain +from types import TracebackType +from urllib.parse import quote as _url_quote + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import MapAdapter +from werkzeug.routing import RequestRedirect +from werkzeug.routing import RoutingException +from werkzeug.routing import Rule +from werkzeug.serving import is_running_from_reloader +from werkzeug.wrappers import Response as BaseResponse +from werkzeug.wsgi import get_host + +from . import cli +from . import typing as ft +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import send_from_directory +from .sansio.app import App +from .sansio.scaffold import _sentinel +from .sessions import SecureCookieSessionInterface +from .sessions import SessionInterface +from .signals import appcontext_tearing_down +from .signals import got_request_exception +from .signals import request_finished +from .signals import request_started +from .signals import request_tearing_down +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + + from .testing import FlaskClient + from .testing import FlaskCliRunner + from .typing import HeadersValue + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(App): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + default_config = ImmutableDict( + { + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "SECRET_KEY_FALLBACKS": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "TRUSTED_HOSTS": None, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_PARTITIONED": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "MAX_FORM_MEMORY_SIZE": 500_000, + "MAX_FORM_PARTS": 1_000, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + "PROVIDE_AUTOMATIC_OPTIONS": True, + } + ) + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class: type[Request] = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class: type[Response] = Response + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface: SessionInterface = SecureCookieSessionInterface() + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_url_path=static_url_path, + static_folder=static_folder, + static_host=static_host, + host_matching=host_matching, + subdomain_matching=subdomain_matching, + template_folder=template_folder, + instance_path=instance_path, + instance_relative_config=instance_relative_config, + root_path=root_path, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = cli.AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert bool(static_host) == host_matching, ( + "Invalid static_host/host_matching combination" + ) + # Use a weakref to avoid creating a reference cycle between the app + # and the view function (see #3761). + self_ref = weakref.ref(self) + self.add_url_rule( + f"{self.static_url_path}/", + endpoint="static", + host=static_host, + view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore + ) + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = None + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) + + def open_instance_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to the application's instance folder + :attr:`instance_path`. Unlike :meth:`open_resource`, files in the + instance folder can be opened for writing. + + :param resource: Path to the resource relative to :attr:`instance_path`. + :param mode: Open the file in this mode. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + path = os.path.join(self.instance_path, resource) + + if "b" in mode: + return open(path, mode) + + return open(path, mode, encoding=encoding) + + def create_jinja_environment(self) -> Environment: + """Create the Jinja environment based on :attr:`jinja_options` + and the various Jinja-related methods of the app. Changing + :attr:`jinja_options` after this will have no effect. Also adds + Flask-related globals and filters to the environment. + + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + + if "autoescape" not in options: + options["autoescape"] = self.select_jinja_autoescape + + if "auto_reload" not in options: + auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] + + if auto_reload is None: + auto_reload = self.debug + + options["auto_reload"] = auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=self.url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g, + ) + rv.policies["json.dumps_function"] = self.json.dumps + return rv + + def create_url_adapter(self, request: Request | None) -> MapAdapter | None: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionchanged:: 3.1 + If :data:`SERVER_NAME` is set, it does not restrict requests to + only that domain, for both ``subdomain_matching`` and + ``host_matching``. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + + .. versionchanged:: 0.9 + This can be called outside a request when the URL adapter is created + for an application context. + + .. versionadded:: 0.6 + """ + if request is not None: + if (trusted_hosts := self.config["TRUSTED_HOSTS"]) is not None: + request.trusted_hosts = trusted_hosts + + # Check trusted_hosts here until bind_to_environ does. + request.host = get_host(request.environ, request.trusted_hosts) # pyright: ignore + subdomain = None + server_name = self.config["SERVER_NAME"] + + if self.url_map.host_matching: + # Don't pass SERVER_NAME, otherwise it's used and the actual + # host is ignored, which breaks host matching. + server_name = None + elif not self.subdomain_matching: + # Werkzeug doesn't implement subdomain matching yet. Until then, + # disable it by forcing the current subdomain to the default, or + # the empty string. + subdomain = self.url_map.default_subdomain or "" + + return self.url_map.bind_to_environ( + request.environ, server_name=server_name, subdomain=subdomain + ) + + # Need at least SERVER_NAME to match/build outside a request. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def raise_routing_exception(self, request: Request) -> t.NoReturn: + """Intercept routing exceptions and possibly do something else. + + In debug mode, intercept a routing redirect and replace it with + an error if the body will be discarded. + + With modern Werkzeug this shouldn't occur, since it now uses a + 308 status which tells the browser to resend the method and + body. + + .. versionchanged:: 2.1 + Don't intercept 307 and 308 redirects. + + :meta private: + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.routing_exception.code in {307, 308} + or request.method in {"GET", "HEAD", "OPTIONS"} + ): + raise request.routing_exception # type: ignore[misc] + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def update_template_context(self, context: dict[str, t.Any]) -> None: + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + names: t.Iterable[str | None] = (None,) + + # A template may be rendered outside a request context. + if request: + names = chain(names, reversed(request.blueprints)) + + # The values passed to render_template take precedence. Keep a + # copy to re-apply after all context functions. + orig_ctx = context.copy() + + for name in names: + if name in self.template_context_processors: + for func in self.template_context_processors[name]: + context.update(self.ensure_sync(func)()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict[str, t.Any]: + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {"app": self, "g": g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + def run( + self, + host: str | None = None, + port: int | None = None, + debug: bool | None = None, + load_dotenv: bool = True, + **options: t.Any, + ) -> None: + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :doc:`/deploying/index` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Ignore this call so that it doesn't start another server if + # the 'flask run' command is used. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + if not is_running_from_reloader(): + click.secho( + " * Ignoring a call to 'app.run()' that would block" + " the current 'flask' CLI command.\n" + " Only call 'app.run()' in an 'if __name__ ==" + ' "__main__"\' guard.', + fg="red", + ) + + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, env var overrides existing value + if "FLASK_DEBUG" in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + server_name = self.config.get("SERVER_NAME") + sn_host = sn_port = None + + if server_name: + sn_host, _, sn_port = server_name.partition(":") + + if not host: + if sn_host: + host = sn_host + else: + host = "127.0.0.1" + + if port or port == 0: + port = int(port) + elif sn_port: + port = int(sn_port) + else: + port = 5000 + + options.setdefault("use_reloader", self.debug) + options.setdefault("use_debugger", self.debug) + options.setdefault("threaded", True) + + cli.show_server_banner(self.debug, self.name) + + from werkzeug.serving import run_simple + + try: + run_simple(t.cast(str, host), port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: + """Creates a test client for this application. For information + about unit testing head over to :doc:`/testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from .testing import FlaskClient as cls + return cls( # type: ignore + self, self.response_class, use_cookies=use_cookies, **kwargs + ) + + def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from .testing import FlaskCliRunner as cls + + return cls(self, **kwargs) # type: ignore + + def handle_http_exception( + self, e: HTTPException + ) -> HTTPException | ft.ResponseReturnValue: + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPException`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. + if isinstance(e, RoutingException): + return e + + handler = self._find_error_handler(e, request.blueprints) + if handler is None: + return e + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_user_exception( + self, e: Exception + ) -> HTTPException | ft.ResponseReturnValue: + """This method is called whenever an exception occurs that + should be handled. A special case is :class:`~werkzeug + .exceptions.HTTPException` which is forwarded to the + :meth:`handle_http_exception` method. This function will either + return a response value or reraise the exception with the same + traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the + bad key in debug mode rather than a generic bad request + message. + + .. versionadded:: 0.7 + """ + if isinstance(e, BadRequestKeyError) and ( + self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] + ): + e.show_exception = True + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e, request.blueprints) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_exception(self, e: Exception) -> Response: + """Handle an exception that did not have an error handler + associated with it, or that was raised from an error handler. + This always causes a 500 ``InternalServerError``. + + Always sends the :data:`got_request_exception` signal. + + If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug + mode, the error will be re-raised so that the debugger can + display it. Otherwise, the original exception is logged, and + an :exc:`~werkzeug.exceptions.InternalServerError` is returned. + + If an error handler is registered for ``InternalServerError`` or + ``500``, it will be used. For consistency, the handler will + always receive the ``InternalServerError``. The original + unhandled exception is available as ``e.original_exception``. + + .. versionchanged:: 1.1.0 + Always passes the ``InternalServerError`` instance to the + handler, setting ``original_exception`` to the unhandled + error. + + .. versionchanged:: 1.1.0 + ``after_request`` functions and other finalization is done + even for the default 500 response when there is no handler. + + .. versionadded:: 0.3 + """ + exc_info = sys.exc_info() + got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) + propagate = self.config["PROPAGATE_EXCEPTIONS"] + + if propagate is None: + propagate = self.testing or self.debug + + if propagate: + # Re-raise if called with an active exception, otherwise + # raise the passed in exception. + if exc_info[1] is e: + raise + + raise e + + self.log_exception(exc_info) + server_error: InternalServerError | ft.ResponseReturnValue + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error, request.blueprints) + + if handler is not None: + server_error = self.ensure_sync(handler)(server_error) + + return self.finalize_request(server_error, from_error_handler=True) + + def log_exception( + self, + exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), + ) -> None: + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error( + f"Exception on {request.path} [{request.method}]", exc_info=exc_info + ) + + def dispatch_request(self) -> ft.ResponseReturnValue: + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = request_ctx.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule: Rule = req.url_rule # type: ignore[assignment] + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if ( + getattr(rule, "provide_automatic_options", False) + and req.method == "OPTIONS" + ): + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] + + def full_dispatch_request(self) -> Response: + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self._got_first_request = True + + try: + request_started.send(self, _async_wrapper=self.ensure_sync) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request( + self, + rv: ft.ResponseReturnValue | HTTPException, + from_error_handler: bool = False, + ) -> Response: + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) + except Exception: + if not from_error_handler: + raise + self.logger.exception( + "Request finalizing failed with an error while handling an error" + ) + return response + + def make_default_options_response(self) -> Response: + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = request_ctx.url_adapter + methods = adapter.allowed_methods() # type: ignore[union-attr] + rv = self.response_class() + rv.allow.update(methods) + return rv + + def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Ensure that the function is synchronous for WSGI workers. + Plain ``def`` functions are returned as-is. ``async def`` + functions are wrapped to run and wait for the response. + + Override this method to change how the app runs async views. + + .. versionadded:: 2.0 + """ + if iscoroutinefunction(func): + return self.async_to_sync(func) + + return func + + def async_to_sync( + self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]] + ) -> t.Callable[..., t.Any]: + """Return a sync function that will run the coroutine function. + + .. code-block:: python + + result = app.async_to_sync(func)(*args, **kwargs) + + Override this method to change how the app converts async code + to be synchronously callable. + + .. versionadded:: 2.0 + """ + try: + from asgiref.sync import async_to_sync as asgiref_async_to_sync + except ImportError: + raise RuntimeError( + "Install Flask with the 'async' extra in order to use async views." + ) from None + + return asgiref_async_to_sync(func) + + def url_for( + self, + /, + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, + ) -> str: + """Generate a URL to the given endpoint with the given values. + + This is called by :func:`flask.url_for`, and can be called + directly as well. + + An *endpoint* is the name of a URL rule, usually added with + :meth:`@app.route() `, and usually the same name as the + view function. A route defined in a :class:`~flask.Blueprint` + will prepend the blueprint's name separated by a ``.`` to the + endpoint. + + In some cases, such as email messages, you want URLs to include + the scheme and domain, like ``https://example.com/hello``. When + not in an active request, URLs will be external by default, but + this requires setting :data:`SERVER_NAME` so Flask knows what + domain to use. :data:`APPLICATION_ROOT` and + :data:`PREFERRED_URL_SCHEME` should also be configured as + needed. This config is only used when not in an active request. + + Functions can be decorated with :meth:`url_defaults` to modify + keyword arguments before the URL is built. + + If building fails for some reason, such as an unknown endpoint + or incorrect values, the app's :meth:`handle_url_build_error` + method is called. If that returns a string, that is returned, + otherwise a :exc:`~werkzeug.routing.BuildError` is raised. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it + is external. + :param _external: If given, prefer the URL to be internal + (False) or require it to be external (True). External URLs + include the scheme and domain. When not in an active + request, URLs are external by default. + :param values: Values to use for the variable parts of the URL + rule. Unknown keys are appended as query string arguments, + like ``?a=b&c=d``. + + .. versionadded:: 2.2 + Moved from ``flask.url_for``, which calls this method. + """ + req_ctx = _cv_request.get(None) + + if req_ctx is not None: + url_adapter = req_ctx.url_adapter + blueprint_name = req_ctx.request.blueprint + + # If the endpoint starts with "." and the request matches a + # blueprint, the endpoint is relative to the blueprint. + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + # When in a request, generate a URL without scheme and + # domain by default, unless a scheme is given. + if _external is None: + _external = _scheme is not None + else: + app_ctx = _cv_app.get(None) + + # If called by helpers.url_for, an app context is active, + # use its url_adapter. Otherwise, app.url_for was called + # directly, build an adapter. + if app_ctx is not None: + url_adapter = app_ctx.url_adapter + else: + url_adapter = self.create_url_adapter(None) + + if url_adapter is None: + raise RuntimeError( + "Unable to build URLs outside an active request" + " without 'SERVER_NAME' configured. Also configure" + " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" + " needed." + ) + + # When outside a request, generate a URL with scheme and + # domain by default. + if _external is None: + _external = True + + # It is an error to set _scheme when _external=False, in order + # to avoid accidental insecure URLs. + if _scheme is not None and not _external: + raise ValueError("When specifying '_scheme', '_external' must be True.") + + self.inject_url_defaults(endpoint, values) + + try: + rv = url_adapter.build( # type: ignore[union-attr] + endpoint, + values, + method=_method, + url_scheme=_scheme, + force_external=_external, + ) + except BuildError as error: + values.update( + _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external + ) + return self.handle_url_build_error(error, endpoint, values) + + if _anchor is not None: + _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") + rv = f"{rv}#{_anchor}" + + return rv + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status: int | None = None + headers: HeadersValue | None = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv # pyright: ignore + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, # pyright: ignore + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, # type: ignore[arg-type] + request.environ, + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) + + return rv + + def preprocess_request(self) -> ft.ResponseReturnValue | None: + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + names = (None, *reversed(request.blueprints)) + + for name in names: + if name in self.url_value_preprocessors: + for url_func in self.url_value_preprocessors[name]: + url_func(request.endpoint, request.view_args) + + for name in names: + if name in self.before_request_funcs: + for before_func in self.before_request_funcs[name]: + rv = self.ensure_sync(before_func)() + + if rv is not None: + return rv # type: ignore[no-any-return] + + return None + + def process_response(self, response: Response) -> Response: + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = request_ctx._get_current_object() # type: ignore[attr-defined] + + for func in ctx._after_request_functions: + response = self.ensure_sync(func)(response) + + for name in chain(request.blueprints, (None,)): + if name in self.after_request_funcs: + for func in reversed(self.after_request_funcs[name]): + response = self.ensure_sync(func)(response) + + if not self.session_interface.is_null_session(ctx._session): + self.session_interface.save_session(self, ctx._session, response) + + return response + + def do_teardown_request( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for name in chain(request.blueprints, (None,)): + if name in self.teardown_request_funcs: + for func in reversed(self.teardown_request_funcs[name]): + self.ensure_sync(func)(exc) + + request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def do_teardown_appcontext( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for func in reversed(self.teardown_appcontext_funcs): + self.ensure_sync(func)(exc) + + appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def app_context(self) -> AppContext: + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ: WSGIEnvironment) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` representing a + WSGI environment. Use a ``with`` block to push the context, + which will make :data:`request` point at this request. + + See :doc:`/reqcontext`. + + Typically you should not call this from your own code. A request + context is automatically pushed by the :meth:`wsgi_app` when + handling a request. Use :meth:`test_request_context` to create + an environment and context instead of this method. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` for a WSGI + environment created from the given values. This is mostly useful + during testing, where you may want to run a function that uses + request data without dispatching a full request. + + See :doc:`/reqcontext`. + + Use a ``with`` block to push the context, which will make + :data:`request` point at the request for the created + environment. :: + + with app.test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from .testing import EnvironBuilder + + builder = EnvironBuilder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The actual WSGI application. This is not implemented in + :meth:`__call__` so that middlewares can be applied without + losing a reference to the app object. Instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + Teardown events for the request and app contexts are called + even if an unhandled error occurs. Other events may not be + called depending on when an error occurs during dispatch. + See :ref:`callbacks-and-errors`. + + :param environ: A WSGI environment. + :param start_response: A callable accepting a status code, + a list of headers, and an optional exception context to + start the response. + """ + ctx = self.request_context(environ) + error: BaseException | None = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if "werkzeug.debug.preserve_context" in environ: + environ["werkzeug.debug.preserve_context"](_cv_app.get()) + environ["werkzeug.debug.preserve_context"](_cv_request.get()) + + if error is not None and self.should_ignore_error(error): + error = None + + ctx.pop(error) + + def __call__( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The WSGI server calls the Flask application object as the + WSGI application. This calls :meth:`wsgi_app`, which can be + wrapped to apply middleware. + """ + return self.wsgi_app(environ, start_response) diff --git a/venv/lib/python3.12/site-packages/flask/blueprints.py b/venv/lib/python3.12/site-packages/flask/blueprints.py new file mode 100644 index 0000000..b6d4e43 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/blueprints.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +import os +import typing as t +from datetime import timedelta + +from .cli import AppGroup +from .globals import current_app +from .helpers import send_from_directory +from .sansio.blueprints import Blueprint as SansioBlueprint +from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa +from .sansio.scaffold import _sentinel + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +class Blueprint(SansioBlueprint): + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore + ) -> None: + super().__init__( + name, + import_name, + static_folder, + static_url_path, + template_folder, + url_prefix, + subdomain, + url_defaults, + root_path, + cli_group, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. The + blueprint-relative equivalent of the app's :meth:`~.Flask.open_resource` + method. + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) diff --git a/venv/lib/python3.12/site-packages/flask/cli.py b/venv/lib/python3.12/site-packages/flask/cli.py new file mode 100644 index 0000000..ed11f25 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/cli.py @@ -0,0 +1,1135 @@ +from __future__ import annotations + +import ast +import collections.abc as cabc +import importlib.metadata +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import itemgetter +from types import ModuleType + +import click +from click.core import ParameterSource +from werkzeug import run_simple +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_load_dotenv + +if t.TYPE_CHECKING: + import ssl + + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module: ModuleType) -> Flask: + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ("app", "application"): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + "Detected multiple Flask applications in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify the correct one." + ) + + # Search for app factory functions. + for attr_name in ("create_app", "make_app"): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = app_factory() + + if isinstance(app, Flask): + return app + except TypeError as e: + if not _called_with_wrong_args(app_factory): + raise + + raise NoAppException( + f"Detected factory '{attr_name}' in module '{module.__name__}'," + " but could not call it without arguments. Use" + f" '{module.__name__}:{attr_name}(args)'" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify one." + ) + + +def _called_with_wrong_args(f: t.Callable[..., Flask]) -> bool: + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param f: The function that was called. + :return: ``True`` if the call failed. + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is f.__code__: + # In the function, it was called successfully. + return False + + tb = tb.tb_next + + # Didn't reach the function. + return True + finally: + # Delete tb to break a circular reference. + # https://docs.python.org/2/library/sys.html#sys.exc_info + del tb + + +def find_app_by_string(module: ModuleType, app_name: str) -> Flask: + """Check if the given string is a variable name or a function. Call + a function to get the app instance, or return the variable directly. + """ + from . import Flask + + # Parse app_name as a single expression to determine if it's a valid + # attribute name or function call. + try: + expr = ast.parse(app_name.strip(), mode="eval").body + except SyntaxError: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) from None + + if isinstance(expr, ast.Name): + name = expr.id + args = [] + kwargs = {} + elif isinstance(expr, ast.Call): + # Ensure the function name is an attribute name only. + if not isinstance(expr.func, ast.Name): + raise NoAppException( + f"Function reference must be a simple name: {app_name!r}." + ) + + name = expr.func.id + + # Parse the positional and keyword arguments as literals. + try: + args = [ast.literal_eval(arg) for arg in expr.args] + kwargs = { + kw.arg: ast.literal_eval(kw.value) + for kw in expr.keywords + if kw.arg is not None + } + except ValueError: + # literal_eval gives cryptic error messages, show a generic + # message with the full expression instead. + raise NoAppException( + f"Failed to parse arguments as literal values: {app_name!r}." + ) from None + else: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException( + f"Failed to find attribute {name!r} in {module.__name__!r}." + ) from e + + # If the attribute is a function, call it with any args and kwargs + # to get the real application. + if inspect.isfunction(attr): + try: + app = attr(*args, **kwargs) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + f"The factory {app_name!r} in module" + f" {module.__name__!r} could not be called with the" + " specified arguments." + ) from e + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + "A valid Flask application was not obtained from" + f" '{module.__name__}:{app_name}'." + ) + + +def prepare_import(path: str) -> str: + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + fname, ext = os.path.splitext(path) + if ext == ".py": + path = fname + + if os.path.basename(path) == "__init__": + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, "__init__.py")): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return ".".join(module_name[::-1]) + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True +) -> Flask: ... + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ... +) -> Flask | None: ... + + +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: bool = True +) -> Flask | None: + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[2].tb_next: # type: ignore[union-attr] + raise NoAppException( + f"While importing {module_name!r}, an ImportError was" + f" raised:\n\n{traceback.format_exc()}" + ) from None + elif raise_if_not_found: + raise NoAppException(f"Could not import {module_name!r}.") from None + else: + return None + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(module) + else: + return find_app_by_string(module, app_name) + + +def get_version(ctx: click.Context, param: click.Parameter, value: t.Any) -> None: + if not value or ctx.resilient_parsing: + return + + flask_version = importlib.metadata.version("flask") + werkzeug_version = importlib.metadata.version("werkzeug") + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {flask_version}\n" + f"Werkzeug {werkzeug_version}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + + .. versionchanged:: 3.1 + Added the ``load_dotenv_defaults`` parameter and attribute. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + load_dotenv_defaults: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + + self.load_dotenv_defaults = get_load_dotenv(load_dotenv_defaults) + """Whether default ``.flaskenv`` and ``.env`` files should be loaded. + + ``ScriptInfo`` doesn't load anything, this is for reference when doing + the load elsewhere during processing. + + .. versionadded:: 3.1 + """ + + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + app: Flask | None = None + if self.create_app is not None: + app = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, maxsplit=1) + [None] + )[:2] + import_name = prepare_import(path) + app = locate_app(import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(import_name, None, raise_if_not_found=False) + + if app is not None: + break + + if app is None: + raise NoAppException( + "Could not locate a Flask application. Use the" + " 'flask --app' option, 'FLASK_APP' environment" + " variable, or a 'wsgi.py' or 'app.py' file in the" + " current directory." + ) + + if self.set_debug_flag: + # Update the app's debug flag through the descriptor so that + # other values repopulate as well. + app.debug = get_debug_flag() + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def with_appcontext(f: F) -> F: + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. + + Custom commands (and their options) registered under ``app.cli`` or + ``blueprint.cli`` will always have an app context available, this + decorator is not required in that case. + + .. versionchanged:: 2.2 + The app context is active for subcommands as well as the + decorated callback. The app context is always available to + ``app.cli`` command and parameter callbacks. + """ + + @click.pass_context + def decorator(ctx: click.Context, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + if not current_app: + app = ctx.ensure_object(ScriptInfo).load_app() + ctx.with_resource(app.app_context()) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper(decorator, f) # type: ignore[return-value] + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Command]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop("with_appcontext", True) + + def decorator(f: t.Callable[..., t.Any]) -> click.Command: + if wrap_for_ctx: + f = with_appcontext(f) + return super(AppGroup, self).command(*args, **kwargs)(f) # type: ignore[no-any-return] + + return decorator + + def group( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Group]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault("cls", AppGroup) + return super().group(*args, **kwargs) # type: ignore[no-any-return] + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + try: + import dotenv # noqa: F401 + except ImportError: + # Only show an error if a value was passed, otherwise we still want to + # call load_dotenv and show a message without exiting. + if value is not None: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Load if a value was passed, or we want to load default files, or both. + if value is not None or ctx.obj.load_dotenv_defaults: + load_dotenv(value, load_defaults=ctx.obj.load_dotenv_defaults) + + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help=( + "Load environment variables from this file, taking precedence over" + " those set by '.env' and '.flaskenv'. Variables set directly in the" + " environment take highest precedence. python-dotenv must be installed." + ), + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 3.1 + ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params: list[click.Parameter] = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self) -> None: + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata # pyright: ignore + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx: click.Context, name: str) -> click.Command | None: + self._load_plugin_commands() + # Look up built-in and plugin commands, which should be + # available even if the app fails to load. + rv = super().get_command(ctx, name) + + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + + # Look up commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + app = info.load_app() + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + return None + + # Push an app context for the loaded app unless it is already + # active somehow. This makes the context available to parameter + # and command callbacks without needing @with_appcontext. + if not current_app or current_app._get_current_object() is not app: # type: ignore[attr-defined] + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx: click.Context) -> list[str]: + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, + set_debug_flag=self.set_debug_flag, + load_dotenv_defaults=self.load_dotenv, + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if (not args and self.no_args_is_help) or ( + len(args) == 1 and args[0] in self.get_help_option_names(ctx) + ): + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path: str, other: str) -> bool: + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other + + +def load_dotenv( + path: str | os.PathLike[str] | None = None, load_defaults: bool = True +) -> bool: + """Load "dotenv" files to set environment variables. A given path takes + precedence over ``.env``, which takes precedence over ``.flaskenv``. After + loading and combining these files, values are only set if the key is not + already set in ``os.environ``. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location. + :param load_defaults: Search for and load the default ``.flaskenv`` and + ``.env`` files. + :return: ``True`` if at least one env var was loaded. + + .. versionchanged:: 3.1 + Added the ``load_defaults`` parameter. A given path takes precedence + over default files. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env files present. Install python-dotenv" + " to use them.", + fg="yellow", + err=True, + ) + + return False + + data: dict[str, str | None] = {} + + if load_defaults: + for default_name in (".flaskenv", ".env"): + if not (default_path := dotenv.find_dotenv(default_name, usecwd=True)): + continue + + data |= dotenv.dotenv_values(default_path, encoding="utf-8") + + if path is not None and os.path.isfile(path): + data |= dotenv.dotenv_values(path, encoding="utf-8") + + for key, value in data.items(): + if key in os.environ or value is None: + continue + + os.environ[key] = value + + return bool(data) # True if at least one env var was loaded. + + +def show_server_banner(debug: bool, app_import_path: str | None) -> None: + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if is_running_from_reloader(): + return + + if app_import_path is not None: + click.echo(f" * Serving Flask app '{app_import_path}'") + + if debug is not None: + click.echo(f" * Debug mode: {'on' if debug else 'off'}") + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = "path" + + def __init__(self) -> None: + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + try: + import ssl + except ImportError: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) from None + + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == "adhoc": + try: + import cryptography # noqa: F401 + except ImportError: + raise click.BadParameter( + "Using ad-hoc certificates requires the cryptography library.", + ctx, + param, + ) from None + + return value + + obj = import_string(value, silent=True) + + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any: + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get("cert") + is_adhoc = cert == "adhoc" + + try: + import ssl + except ImportError: + is_context = False + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', ctx, param + ) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key" is not used.', + ctx, + param, + ) + + if not cert: + raise click.BadParameter('"--cert" must also be specified.', ctx, param) + + ctx.params["cert"] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter('Required when using "--cert".', ctx, param) + + return value + + +class SeparatedPathType(click.Path): + """Click option type that accepts a list of values separated by the + OS's path separator (``:``, ``;`` on Windows). Each value is + validated as a :class:`click.Path` type. + """ + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + items = self.split_envvar_value(value) + # can't call no-arg super() inside list comprehension until Python 3.12 + super_convert = super().convert + return [super_convert(item, param, ctx) for item in items] + + +@click.command("run", short_help="Run a development server.") +@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") +@click.option("--port", "-p", default=5000, help="The port to bind to.") +@click.option( + "--cert", + type=CertParamType(), + help="Specify a certificate file to use HTTPS.", + is_eager=True, +) +@click.option( + "--key", + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, + expose_value=False, + help="The key file to use when specifying a certificate.", +) +@click.option( + "--reload/--no-reload", + default=None, + help="Enable or disable the reloader. By default the reloader " + "is active if debug is enabled.", +) +@click.option( + "--debugger/--no-debugger", + default=None, + help="Enable or disable the debugger. By default the debugger " + "is active if debug is enabled.", +) +@click.option( + "--with-threads/--without-threads", + default=True, + help="Enable or disable multithreading.", +) +@click.option( + "--extra-files", + default=None, + type=SeparatedPathType(), + help=( + "Extra files that trigger a reload on change. Multiple paths" + f" are separated by {os.path.pathsep!r}." + ), +) +@click.option( + "--exclude-patterns", + default=None, + type=SeparatedPathType(), + help=( + "Files matching these fnmatch patterns will not trigger a reload" + " on change. Multiple patterns are separated by" + f" {os.path.pathsep!r}." + ), +) +@pass_script_info +def run_command( + info: ScriptInfo, + host: str, + port: int, + reload: bool, + debugger: bool, + with_threads: bool, + cert: ssl.SSLContext | tuple[str, str | None] | t.Literal["adhoc"] | None, + extra_files: list[str] | None, + exclude_patterns: list[str] | None, +) -> None: + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default with the '--debug' + option. + """ + try: + app: WSGIApplication = info.load_app() # pyright: ignore + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app( + environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict[str, t.Any] = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.12/site-packages/flask/config.py b/venv/lib/python3.12/site-packages/flask/config.py new file mode 100644 index 0000000..34ef1a5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/config.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .sansio.app import App + + +T = t.TypeVar("T") + + +class ConfigAttribute(t.Generic[T]): + """Makes an attribute forward to the config""" + + def __init__( + self, name: str, get_converter: t.Callable[[t.Any], T] | None = None + ) -> None: + self.__name__ = name + self.get_converter = get_converter + + @t.overload + def __get__(self, obj: None, owner: None) -> te.Self: ... + + @t.overload + def __get__(self, obj: App, owner: type[App]) -> T: ... + + def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self: + if obj is None: + return self + + rv = obj.config[self.__name__] + + if self.get_converter is not None: + rv = self.get_converter(rv) + + return rv # type: ignore[no-any-return] + + def __set__(self, obj: App, value: t.Any) -> None: + obj.config[self.__name__] = value + + +class Config(dict): # type: ignore[type-arg] + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__( + self, + root_path: str | os.PathLike[str], + defaults: dict[str, t.Any] | None = None, + ) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + key = key.removeprefix(prefix) + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile( + self, filename: str | os.PathLike[str], silent: bool = False + ) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str | os.PathLike[str], + load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/venv/lib/python3.12/site-packages/flask/ctx.py b/venv/lib/python3.12/site-packages/flask/ctx.py new file mode 100644 index 0000000..5f7b1f1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/ctx.py @@ -0,0 +1,459 @@ +from __future__ import annotations + +import contextvars +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from . import typing as ft +from .globals import _cv_app +from .globals import _cv_request +from .signals import appcontext_popped +from .signals import appcontext_pushed + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + from .sessions import SessionMixin + from .wrappers import Request + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals: + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + # Define attr methods to let mypy know this is a namespace object + # that has arbitrary attributes. + + def __getattr__(self, name: str) -> t.Any: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def __setattr__(self, name: str, value: t.Any) -> None: + self.__dict__[name] = value + + def __delattr__(self, name: str) -> None: + try: + del self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def get(self, name: str, default: t.Any | None = None) -> t.Any: + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raising a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name: str, default: t.Any = None) -> t.Any: + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item: str) -> bool: + return item in self.__dict__ + + def __iter__(self) -> t.Iterator[str]: + return iter(self.__dict__) + + def __repr__(self) -> str: + ctx = _cv_app.get(None) + if ctx is not None: + return f"" + return object.__repr__(self) + + +def after_this_request( + f: ft.AfterRequestCallable[t.Any], +) -> ft.AfterRequestCallable[t.Any]: + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'after_this_request' can only be used when a request" + " context is active, such as in a view function." + ) + + ctx._after_request_functions.append(f) + return f + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def copy_current_request_context(f: F) -> F: + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. The current session is also + included in the copied request context. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request or + # flask.session like you would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'copy_current_request_context' can only be used when a" + " request context is active, such as in a view function." + ) + + ctx = ctx.copy() + + def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any: + with ctx: + return ctx.app.ensure_sync(f)(*args, **kwargs) + + return update_wrapper(wrapper, f) # type: ignore[return-value] + + +def has_request_context() -> bool: + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g`) for truthness:: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _cv_request.get(None) is not None + + +def has_app_context() -> bool: + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _cv_app.get(None) is not None + + +class AppContext: + """The app context contains application-specific information. An app + context is created and pushed at the beginning of each request if + one is not already active. An app context is also pushed when + running CLI commands. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g: _AppCtxGlobals = app.app_ctx_globals_class() + self._cv_tokens: list[contextvars.Token[AppContext]] = [] + + def push(self) -> None: + """Binds the app context to the current context.""" + self._cv_tokens.append(_cv_app.set(self)) + appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + if len(self._cv_tokens) == 1: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + ctx = _cv_app.get() + _cv_app.reset(self._cv_tokens.pop()) + + if ctx is not self: + raise AssertionError( + f"Popped wrong app context. ({ctx!r} instead of {self!r})" + ) + + appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) + + def __enter__(self) -> AppContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains per-request information. The Flask + app creates and pushes it at the beginning of the request, then pops + it at the end of the request. It will create the URL adapter and + request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the + request. When using the interactive debugger, the context will be + restored so ``request`` is still accessible. Similarly, the test + client can preserve the context after the request ends. However, + teardown functions may already have closed some resources such as + database connections. + """ + + def __init__( + self, + app: Flask, + environ: WSGIEnvironment, + request: Request | None = None, + session: SessionMixin | None = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json + self.request: Request = request + self.url_adapter = None + try: + self.url_adapter = app.create_url_adapter(self.request) + except HTTPException as e: + self.request.routing_exception = e + self.flashes: list[tuple[str, str]] | None = None + self._session: SessionMixin | None = session + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = [] + + self._cv_tokens: list[ + tuple[contextvars.Token[RequestContext], AppContext | None] + ] = [] + + def copy(self) -> RequestContext: + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + + .. versionchanged:: 1.1 + The current session object is used instead of reloading the original + data. This prevents `flask.session` pointing to an out-of-date object. + """ + return self.__class__( + self.app, + environ=self.request.environ, + request=self.request, + session=self._session, + ) + + def match_request(self) -> None: + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + result = self.url_adapter.match(return_rule=True) # type: ignore + self.request.url_rule, self.request.view_args = result # type: ignore + except HTTPException as e: + self.request.routing_exception = e + + @property + def session(self) -> SessionMixin: + """The session data associated with this request. Not available until + this context has been pushed. Accessing this property, also accessed by + the :data:`~flask.session` proxy, sets :attr:`.SessionMixin.accessed`. + """ + assert self._session is not None, "The session has not yet been opened." + self._session.accessed = True + return self._session + + def push(self) -> None: + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _cv_app.get(None) + + if app_ctx is None or app_ctx.app is not self.app: + app_ctx = self.app.app_context() + app_ctx.push() + else: + app_ctx = None + + self._cv_tokens.append((_cv_request.set(self), app_ctx)) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self._session is None: + session_interface = self.app.session_interface + self._session = session_interface.open_session(self.app, self.request) + + if self._session is None: + self._session = session_interface.make_null_session(self.app) + + # Match the request URL after loading the session, so that the + # session is available in custom URL converters. + if self.url_adapter is not None: + self.match_request() + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + clear_request = len(self._cv_tokens) == 1 + + try: + if clear_request: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + request_close = getattr(self.request, "close", None) + if request_close is not None: + request_close() + finally: + ctx = _cv_request.get() + token, app_ctx = self._cv_tokens.pop() + _cv_request.reset(token) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + ctx.request.environ["werkzeug.request"] = None + + if app_ctx is not None: + app_ctx.pop(exc) + + if ctx is not self: + raise AssertionError( + f"Popped wrong request context. ({ctx!r} instead of {self!r})" + ) + + def __enter__(self) -> RequestContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + def __repr__(self) -> str: + return ( + f"<{type(self).__name__} {self.request.url!r}" + f" [{self.request.method}] of {self.app.name}>" + ) diff --git a/venv/lib/python3.12/site-packages/flask/debughelpers.py b/venv/lib/python3.12/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..2c8c4c4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/debughelpers.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import typing as t + +from jinja2.loaders import BaseLoader +from werkzeug.routing import RequestRedirect + +from .blueprints import Blueprint +from .globals import request_ctx +from .sansio.app import App + +if t.TYPE_CHECKING: + from .sansio.scaffold import Scaffold + from .wrappers import Request + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request: Request, key: str) -> None: + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self) -> str: + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request: Request) -> None: + exc = request.routing_exception + assert isinstance(exc, RequestRedirect) + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request: Request) -> None: + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): # type: ignore[valid-type, misc] + def __getitem__(self, key: str) -> t.Any: + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts( + app: App, + template: str, + attempts: list[ + tuple[ + BaseLoader, + Scaffold, + tuple[str, str | None, t.Callable[[], bool] | None] | None, + ] + ], +) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, App): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/venv/lib/python3.12/site-packages/flask/globals.py b/venv/lib/python3.12/site-packages/flask/globals.py new file mode 100644 index 0000000..e2c410c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/globals.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) diff --git a/venv/lib/python3.12/site-packages/flask/helpers.py b/venv/lib/python3.12/site-packages/flask/helpers.py new file mode 100644 index 0000000..5d412c9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,641 @@ +from __future__ import annotations + +import importlib.util +import os +import sys +import typing as t +from datetime import datetime +from functools import cache +from functools import update_wrapper + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .globals import request_ctx +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +def get_debug_flag() -> bool: + """Get whether debug mode should be enabled for the app, indicated by the + :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. + """ + val = os.environ.get("FLASK_DEBUG") + return bool(val and val.lower() not in {"0", "false", "no"}) + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +@t.overload +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr], +) -> t.Iterator[t.AnyStr]: ... + + +@t.overload +def stream_with_context( + generator_or_function: t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: ... + + +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Iterator[t.AnyStr] | t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: + """Wrap a response generator function so that it runs inside the current + request context. This keeps :data:`request`, :data:`session`, and :data:`g` + available, even though at the point the generator runs the request context + will typically have ended. + + Use it as a decorator on a generator function: + + .. code-block:: python + + from flask import stream_with_context, request, Response + + @app.get("/stream") + def streamed_response(): + @stream_with_context + def generate(): + yield "Hello " + yield request.args["name"] + yield "!" + + return Response(generate()) + + Or use it as a wrapper around a created generator: + + .. code-block:: python + + from flask import stream_with_context, request, Response + + @app.get("/stream") + def streamed_response(): + def generate(): + yield "Hello " + yield request.args["name"] + yield "!" + + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) # type: ignore[arg-type] + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore[operator] + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore[arg-type] + + def generator() -> t.Iterator[t.AnyStr]: + if (req_ctx := _cv_request.get(None)) is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + + app_ctx = _cv_app.get() + # Setup code below will run the generator to this point, so that the + # current contexts are recorded. The contexts must be pushed after, + # otherwise their ContextVar will record the wrong event loop during + # async view functions. + yield None # type: ignore[misc] + + # Push the app context first, so that the request context does not + # automatically create and push a different app context. + with app_ctx, req_ctx: + try: + yield from gen + finally: + # Clean up in case the user wrapped a WSGI iterator. + if hasattr(gen, "close"): + gen.close() + + # Execute the generator to the sentinel value. This ensures the context is + # preserved in the generator's state. Further iteration will push the + # context and yield from the original iterator. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g + + +def make_response(*args: t.Any) -> Response: + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for( + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, +) -> str: + """Generate a URL to the given endpoint with the given values. + + This requires an active request or application context, and calls + :meth:`current_app.url_for() `. See that method + for full documentation. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it is + external. + :param _external: If given, prefer the URL to be internal (False) or + require it to be external (True). External URLs include the + scheme and domain. When not in an active request, URLs are + external by default. + :param values: Values to use for the variable parts of the URL rule. + Unknown keys are appended as query string arguments, like + ``?a=b&c=d``. + + .. versionchanged:: 2.2 + Calls ``current_app.url_for``, allowing an app to override the + behavior. + + .. versionchanged:: 0.10 + The ``_scheme`` parameter was added. + + .. versionchanged:: 0.9 + The ``_anchor`` and ``_method`` parameters were added. + + .. versionchanged:: 0.9 + Calls ``app.handle_url_build_error`` on build errors. + """ + return current_app.url_for( + endpoint, + _anchor=_anchor, + _method=_method, + _scheme=_scheme, + _external=_external, + **values, + ) + + +def redirect( + location: str, code: int = 302, Response: type[BaseResponse] | None = None +) -> BaseResponse: + """Create a redirect response object. + + If :data:`~flask.current_app` is available, it will use its + :meth:`~flask.Flask.redirect` method, otherwise it will use + :func:`werkzeug.utils.redirect`. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + :param Response: The response class to use. Not used when + ``current_app`` is active, which uses ``app.response_class``. + + .. versionadded:: 2.2 + Calls ``current_app.redirect`` if available instead of always + using Werkzeug's default ``redirect``. + """ + if current_app: + return current_app.redirect(location, code=code) + + return _wz_redirect(location, code=code, Response=Response) + + +def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given + status code. + + If :data:`~flask.current_app` is available, it will call its + :attr:`~flask.Flask.aborter` object, otherwise it will use + :func:`werkzeug.exceptions.abort`. + + :param code: The status code for the exception, which must be + registered in ``app.aborter``. + :param args: Passed to the exception. + :param kwargs: Passed to the exception. + + .. versionadded:: 2.2 + Calls ``current_app.aborter`` if available instead of always + using Werkzeug's default ``abort``. + """ + if current_app: + current_app.aborter(code, *args, **kwargs) + + _wz_abort(code, *args, **kwargs) + + +def get_template_attribute(template_name: str, attribute: str) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, attribute) + + +def flash(message: str, category: str = "message") -> None: + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get("_flashes", []) + flashes.append((category, message)) + session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore + message_flashed.send( + app, + _async_wrapper=app.ensure_sync, + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> list[str] | list[tuple[str, str]]: + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :doc:`/patterns/flashing` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: filter of categories to limit return values. Only + categories in the list will be returned. + """ + flashes = request_ctx.flashes + if flashes is None: + flashes = session.pop("_flashes") if "_flashes" in session else [] + request_ctx.flashes = flashes + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: + if kwargs.get("max_age") is None: + kwargs["max_age"] = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + use_x_sendfile=current_app.config["USE_X_SENDFILE"], + response_class=current_app.response_class, + _root_path=current_app.root_path, + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike[t.AnyStr] | str | t.IO[bytes], + mimetype: str | None = None, + as_attachment: bool = False, + download_name: str | None = None, + conditional: bool = True, + etag: bool | str = True, + last_modified: datetime | int | float | None = None, + max_age: None | (int | t.Callable[[str | None], int | None]) = None, +) -> Response: + """Send the contents of a file to the client. + + The first argument can be a file path or a file-like object. Paths + are preferred in most cases because Werkzeug can manage the file and + get extra information from the path. Passing a file-like object + requires that the file is opened in binary mode, and is mostly + useful when building a file in memory with :class:`io.BytesIO`. + + Never pass file paths provided by a user. The path is assumed to be + trusted, so a user could craft a path to access a file you didn't + intend. Use :func:`send_from_directory` to safely serve + user-requested paths from within a directory. + + If the WSGI server sets a ``file_wrapper`` in ``environ``, it is + used, otherwise Werkzeug's built-in wrapper is used. Alternatively, + if the HTTP server supports ``X-Sendfile``, configuring Flask with + ``USE_X_SENDFILE = True`` will tell the server to send the given + path, which is much more efficient than reading it in Python. + + :param path_or_file: The path to the file to send, relative to the + current working directory if a relative path is given. + Alternatively, a file-like object opened in binary mode. Make + sure the file pointer is seeked to the start of the data. + :param mimetype: The MIME type to send for the file. If not + provided, it will try to detect it from the file name. + :param as_attachment: Indicate to a browser that it should offer to + save the file instead of displaying it. + :param download_name: The default name browsers will use when saving + the file. Defaults to the passed file name. + :param conditional: Enable conditional and range responses based on + request headers. Requires passing a file path and ``environ``. + :param etag: Calculate an ETag for the file, which requires passing + a file path. Can also be a string to use instead. + :param last_modified: The last modified time to send for the file, + in seconds. If not provided, it will try to detect it from the + file path. + :param max_age: How long the client should cache the file, in + seconds. If set, ``Cache-Control`` will be ``public``, otherwise + it will be ``no-cache`` to prefer conditional caching. + + .. versionchanged:: 2.0 + ``download_name`` replaces the ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces the ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces the ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + Passing a file-like object that inherits from + :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather + than sending an empty file. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionchanged:: 1.1 + ``filename`` may be a :class:`~os.PathLike` object. + + .. versionchanged:: 1.1 + Passing a :class:`~io.BytesIO` object supports range requests. + + .. versionchanged:: 1.0.3 + Filenames are encoded with ASCII instead of Latin-1 for broader + compatibility with WSGI servers. + + .. versionchanged:: 1.0 + UTF-8 filenames as specified in :rfc:`2231` are supported. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file + objects. If you want to use automatic MIME and etag support, + pass a filename via ``filename_or_fp`` or + ``attachment_filename``. + + .. versionchanged:: 0.12 + ``attachment_filename`` is preferred over ``filename`` for MIME + detection. + + .. versionchanged:: 0.9 + ``cache_timeout`` defaults to + :meth:`Flask.get_send_file_max_age`. + + .. versionchanged:: 0.7 + MIME guessing and etag support for file-like objects was + removed because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. + + .. versionchanged:: 0.5 + The ``add_etags``, ``cache_timeout`` and ``conditional`` + parameters were added. The default behavior is to add etags. + + .. versionadded:: 0.2 + """ + return werkzeug.utils.send_file( # type: ignore[return-value] + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + conditional=conditional, + etag=etag, + last_modified=last_modified, + max_age=max_age, + ) + ) + + +def send_from_directory( + directory: os.PathLike[str] | str, + path: os.PathLike[str] | str, + **kwargs: t.Any, +) -> Response: + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. This *must not* + be a value provided by the client, otherwise it becomes insecure. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + try: + spec = importlib.util.find_spec(import_name) + + if spec is None: + raise ValueError + except (ImportError, ValueError): + loader = None + else: + loader = spec.loader + + # Loader does not exist or we're referring to an unloaded main + # module or a main module without path (interactive sessions), go + # with the current working directory. + if loader is None: + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) # pyright: ignore + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, "__file__", None) + + # If we don't have a file path it might be because it is a + # namespace package. In this case pick the root path from the + # first module that is contained in the package. + if filepath is None: + raise RuntimeError( + "No root path can be found for the provided module" + f" {import_name!r}. This can happen because the module" + " came from an import hook that does not provide file" + " name information or because it's a namespace package." + " In this case the root path needs to be explicitly" + " provided." + ) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] + + +@cache +def _split_blueprint_path(name: str) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/venv/lib/python3.12/site-packages/flask/json/__init__.py b/venv/lib/python3.12/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..c0941d0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..dd7836e975de49e8ddfdeefafdf86915cb424afe GIT binary patch literal 6687 zcmd5=&2JmW72l;OX)Ri!?Zk~^*YPBlin5hfACBFCF`O9wNZg`M5UC$gQIJFKP+DoZ z%gipRQZS032vE3(#<%$BgAuqW(7&TVE+P_C0BZwA(;j>)p!DKXe{Y7nq&}j`t`e94 zXJ>b2-psst?>E2qJ{uk$GVuG`Umv>vIBFPQ(o6hH>594W5h|Y;j^UV|Q8njHljG^)A&q;d&)xr5ewDmg!o>e_Cf50?E|I+iZxb9O9p#PwksUDm^i2lQl^-+3$ z*covS;5p)CogqB4&LJm*=OO2?a}dwN%~bBlBNCD`+ZpcrLBu0B@WbnmXrc76T$fV# zQGwTLk4*i|DmbFT>t2L*>pc4G5+pfSYM)`u3h8psT@}pX z5obJPKc0Q(x;-?+@Vi!FdHS3${A8Ng*MDGtPo&QOFfn z$?wjUuhji=zSxyt>?}TC^73Uwa z8V^I^FpR*wtXNb_Dq`E!nkT4>vYgIjw#^zshA^e_BKH@Blh3mm`;3}_G)W66k|H2L zO(-HE*$UJxMKx#$XID8hiJVK^^Fm1KIfx$B7K`Hy9fB3tUtrv4n2**E`BFm1i4@vU zNi6b)8^~QJp0c}B=gTmGFkf^;*{yQVzO0|h4#Ik^7RU(dDm7U-@G)UTYry23g^@&k z_j!_~6^p_z2Mz{6Q_7%9BGwUeeRh@X5UQQtMc%YM)uZ}Y?PVwgvO34=xKflOuQ|>n zhdSV=I5$l6LEWX*cC?o)3ww&hZz5I+B<-)_F4Qp&$E}U1Js2azfFvwvr^z1M{mN$A zL!pQ|?UH=C-Cv;QT&mp%>ue8b+Y8B!8GHQxs!vR7`|! zBqkfeZ%le_X|mRYXZUCA>6uAtn5gmcGG7qkr1Gyxnq;z2aD6u_6zp149>ff)7)B+0 z3&n@Vf6f`!bN92y*R!Wu*;DJ;u~v5MPPvtR_1@1>tXZ!0CR6l^x*T8zMi`fV}^Boapcu zvAPLiORmplQymE|02nCgd=rx5a#PpZc#Nrupw9iX1zYJHB(b{dIgMzNs6{(XfF=n& z6p+ag)N*|?OKqu2O&®zp$M{4k!9n42mlsp$#|K#on2V?DQS9cx*~)~%B*>*Ve7 zotc(3b?-Z$TT>6Mk#+0Emi6N8+}&S(VcGYs;g5%I4&6F)JJqs)IiFi&@(3iA6KaK* z1aMaIvI%hhZweMA1Z)qq%H$(Zz-5upjBkTjc>#C!MyyoNCk6{OY71I`EX~oC2;W!k zjjKNr;S-W7E%;d_Rh`xCH>pZ|Z6B(o*r4!^iy=4;&&8FZ=OHq$ zVW;7Wm6$BXA-ztA=%rA)27`1mjPZIDR54i@>4&CTMo^EKFNAjNfKdZzsSARjb~1-5 zhEupLuw!hn96=50lfZJYtezdv0?3rKN=Vku38r{Gdjhq%^Mx3suKCOnrTPNXhDv(G zE^62a)`}Ph8>AG6vRK!5;uH{tF;%`yX)m=k!9$l43IR659UE6ShF5tLshLm(JhT}Z zcphXST|(0&NieOPEARk;-IktK6&UeHD|c1Mml*Bzkja`ONscPBD4)03h4+T>V#()%Be^~@go=Kkl$ zrtInIM6nkg2X@m*xT(lH)~mWggW7~A8p6ZTOWq7S)<=oP9>OS)K6IldlP+>;NUCwa z?82H^Nd_yBhEcOZu)GwNd=Z&$)p>%lNwKGNPlD5OknD^zg@^_TFg4Y)V#OoXl_rzg z2HfpI66;o)@+FM=1ODO5C_Xg4debxxzObG-(aM}y&y2P*qj#LO%-MTLIGtTfpH<8b zp(#b4kNYG0qTf`qWC7jmN2_rX5958y6QDhjI3*nYLv#$9cd303Y9vLUK9!v z%up*(-FfW+;5E*+ZAR_E1urN8Ms$+VieW=%6^G~EfA>n^(%V-q{p8y9x7yZ<1cKr; z)f77Sr=oF1uhoS~I{%ZQbg7v4W9vMiukMKp@`q@mn=X6}#lQPZ(|lmO@}=?o-;E>x wGG2aQy!5ay{rfk5_r`5YL?=Jz%(nP+l3t~k>`~Uy| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b055a85a9d500c3ddbb59fa7d0a898e0f1dcd140 GIT binary patch literal 9254 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 I^yIwzZ{0OCo&W#< literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8f1a7825d44676a4d98d4ecc9221acd10749f47e GIT binary patch literal 13949 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 AcmMzZ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/json/provider.py b/venv/lib/python3.12/site-packages/flask/json/provider.py new file mode 100644 index 0000000..ea7e475 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/provider.py @@ -0,0 +1,215 @@ +from __future__ import annotations + +import dataclasses +import decimal +import json +import typing as t +import uuid +import weakref +from datetime import date + +from werkzeug.http import http_date + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.sansio.response import Response + + from ..sansio.app import App + + +class JSONProvider: + """A standard set of JSON operations for an application. Subclasses + of this can be used to customize JSON behavior or use different + JSON libraries. + + To implement a provider for a specific library, subclass this base + class and implement at least :meth:`dumps` and :meth:`loads`. All + other methods have default implementations. + + To use a different provider, either subclass ``Flask`` and set + :attr:`~flask.Flask.json_provider_class` to a provider class, or set + :attr:`app.json ` to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: App) -> None: + self._app: App = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) # type: ignore[arg-type] + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/venv/lib/python3.12/site-packages/flask/json/tag.py b/venv/lib/python3.12/site-packages/flask/json/tag.py new file mode 100644 index 0000000..8dc3629 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/tag.py @@ -0,0 +1,327 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" + +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If empty, this tag is + #: only used as an intermediate step during tagging. + key: str = "" + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> t.Any: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def _untag_scan(self, value: t.Any) -> t.Any: + if isinstance(value, dict): + # untag each item recursively + value = {k: self._untag_scan(v) for k, v in value.items()} + # untag the dict itself + value = self.untag(value) + elif isinstance(value, list): + # untag each item recursively + value = [self._untag_scan(item) for item in value] + + return value + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return self._untag_scan(loads(value)) diff --git a/venv/lib/python3.12/site-packages/flask/logging.py b/venv/lib/python3.12/site-packages/flask/logging.py new file mode 100644 index 0000000..0cb8f43 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/logging.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .sansio.app import App + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + if request: + return request.environ["wsgi.errors"] # type: ignore[no-any-return] + + return sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: App) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/venv/lib/python3.12/site-packages/flask/py.typed b/venv/lib/python3.12/site-packages/flask/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/README.md b/venv/lib/python3.12/site-packages/flask/sansio/README.md new file mode 100644 index 0000000..623ac19 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/README.md @@ -0,0 +1,6 @@ +# Sansio + +This folder contains code that can be used by alternative Flask +implementations, for example Quart. The code therefore cannot do any +IO, nor be part of a likely IO path. Finally this code cannot use the +Flask globals. diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c2d0b0f8117d70071db45ca2bb0366c9bb2c703c GIT binary patch literal 33706 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 es(xe2C)PqA6M=_ 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 timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class App(Scaffold): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + #: The class of the object assigned to :attr:`aborter`, created by + #: :meth:`create_aborter`. That object is called by + #: :func:`flask.abort` to raise HTTP errors, and can be + #: called directly as well. + #: + #: Defaults to :class:`werkzeug.exceptions.Aborter`. + #: + #: .. versionadded:: 2.2 + aborter_class = Aborter + + #: The class that is used for the Jinja environment. + #: + #: .. versionadded:: 0.11 + jinja_environment = Environment + + #: The class that is used for the :data:`~flask.g` instance. + #: + #: Example use cases for a custom class: + #: + #: 1. Store arbitrary attributes on flask.g. + #: 2. Add a property for lazy per-request database connectors. + #: 3. Return None instead of AttributeError on unexpected attributes. + #: 4. Raise exception if an unexpected attr is set, a "controlled" flask.g. + #: + #: In Flask 0.9 this property was called `request_globals_class` but it + #: was changed in 0.10 to :attr:`app_ctx_globals_class` because the + #: flask.g object is now application context scoped. + #: + #: .. versionadded:: 0.10 + app_ctx_globals_class = _AppCtxGlobals + + #: The class that is used for the ``config`` attribute of this app. + #: Defaults to :class:`~flask.Config`. + #: + #: Example use cases for a custom class: + #: + #: 1. Default values for certain config options. + #: 2. Access to config values through attributes in addition to keys. + #: + #: .. versionadded:: 0.11 + config_class = Config + + #: The testing flag. Set this to ``True`` to enable the test mode of + #: Flask extensions (and in the future probably also Flask itself). + #: For example this might activate test helpers that have an + #: additional runtime cost which should not be enabled by default. + #: + #: If this is enabled and PROPAGATE_EXCEPTIONS is not changed from the + #: default it's implicitly enabled. + #: + #: This attribute can also be configured from the config with the + #: ``TESTING`` configuration key. Defaults to ``False``. + testing = ConfigAttribute[bool]("TESTING") + + #: If a secret key is set, cryptographic components can use this to + #: sign cookies and other things. Set this to a complex random value + #: when you want to use the secure cookie for instance. + #: + #: This attribute can also be configured from the config with the + #: :data:`SECRET_KEY` configuration key. Defaults to ``None``. + secret_key = ConfigAttribute[t.Union[str, bytes, None]]("SECRET_KEY") + + #: A :class:`~datetime.timedelta` which is used to set the expiration + #: date of a permanent session. The default is 31 days which makes a + #: permanent session survive for roughly one month. + #: + #: This attribute can also be configured from the config with the + #: ``PERMANENT_SESSION_LIFETIME`` configuration key. Defaults to + #: ``timedelta(days=31)`` + permanent_session_lifetime = ConfigAttribute[timedelta]( + "PERMANENT_SESSION_LIFETIME", + get_converter=_make_timedelta, # type: ignore[arg-type] + ) + + json_provider_class: type[JSONProvider] = DefaultJSONProvider + """A subclass of :class:`~flask.json.provider.JSONProvider`. An + instance is created and assigned to :attr:`app.json` when creating + the app. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, uses + Python's built-in :mod:`json` library. A different provider can use + a different JSON library. + + .. versionadded:: 2.2 + """ + + #: Options that are passed to the Jinja environment in + #: :meth:`create_jinja_environment`. Changing these options after + #: the environment is created (accessing :attr:`jinja_env`) will + #: have no effect. + #: + #: .. versionchanged:: 1.1.0 + #: This is a ``dict`` instead of an ``ImmutableDict`` to allow + #: easier configuration. + #: + jinja_options: dict[str, t.Any] = {} + + #: The rule object to use for URL rules created. This is used by + #: :meth:`add_url_rule`. Defaults to :class:`werkzeug.routing.Rule`. + #: + #: .. versionadded:: 0.7 + url_rule_class = Rule + + #: The map object to use for storing the URL rules and routing + #: configuration parameters. Defaults to :class:`werkzeug.routing.Map`. + #: + #: .. versionadded:: 1.1.0 + url_map_class = Map + + #: The :meth:`test_client` method creates an instance of this test + #: client class. Defaults to :class:`~flask.testing.FlaskClient`. + #: + #: .. versionadded:: 0.7 + test_client_class: type[FlaskClient] | None = None + + #: The :class:`~click.testing.CliRunner` subclass, by default + #: :class:`~flask.testing.FlaskCliRunner` that is used by + #: :meth:`test_cli_runner`. Its ``__init__`` method should take a + #: Flask app object as the first argument. + #: + #: .. versionadded:: 1.0 + test_cli_runner_class: type[FlaskCliRunner] | None = None + + default_config: dict[str, t.Any] + response_class: type[Response] + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ) -> None: + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + "If an instance path is provided it must be absolute." + " A relative path was given instead." + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: An instance of :attr:`aborter_class` created by + #: :meth:`make_aborter`. This is called by :func:`flask.abort` + #: to raise HTTP errors, and can be called directly as well. + #: + #: .. versionadded:: 2.2 + #: Moved from ``flask.abort``, which calls this object. + self.aborter = self.make_aborter() + + self.json: JSONProvider = self.json_provider_class(self) + """Provides access to JSON methods. Functions in ``flask.json`` + will call methods on this provider when the application context + is active. Used for handling JSON requests and responses. + + An instance of :attr:`json_provider_class`. Can be customized by + changing that attribute on a subclass, or by assigning to this + attribute afterwards. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, + uses Python's built-in :mod:`json` library. A different provider + can use a different JSON library. + + .. versionadded:: 2.2 + """ + + #: A list of functions that are called by + #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function is called + #: with ``error``, ``endpoint`` and ``values``. If a function + #: returns ``None`` or raises a ``BuildError``, it is skipped. + #: Otherwise, its return value is returned by ``url_for``. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: list[ + t.Callable[[Exception, str, dict[str, t.Any]], str] + ] = [] + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] + + #: Maps registered blueprint names to blueprint objects. The + #: dict retains the order the blueprints were registered in. + #: Blueprints can be registered multiple times, this dict does + #: not track how often they were attached. + #: + #: .. versionadded:: 0.7 + self.blueprints: dict[str, Blueprint] = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions: dict[str, t.Any] = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = self.url_map_class(host_matching=host_matching) + + self.subdomain_matching = subdomain_matching + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_first_request: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called" + " on the application. It has already handled its first" + " request, any changes will not be applied" + " consistently.\n" + "Make sure all imports, decorators, functions, etc." + " needed to set up the application are done before" + " running it." + ) + + @cached_property + def name(self) -> str: + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == "__main__": + fn: str | None = getattr(sys.modules["__main__"], "__file__", None) + if fn is None: + return "__main__" + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @cached_property + def logger(self) -> logging.Logger: + """A standard Python :class:`~logging.Logger` for the app, with + the same name as :attr:`name`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will + be set to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be + added. See :doc:`/logging` for more information. + + .. versionchanged:: 1.1.0 + The logger takes the same name as :attr:`name` rather than + hard-coding ``"flask.app"``. + + .. versionchanged:: 1.0.0 + Behavior was simplified. The logger is always named + ``"flask.app"``. The level is only set during configuration, + it doesn't check ``app.debug`` each time. Only one format is + used, not different ones depending on ``app.debug``. No + handlers are removed, and a handler is only added if no + handlers are already configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @cached_property + def jinja_env(self) -> Environment: + """The Jinja environment used to load templates. + + The environment is created the first time this property is + accessed. Changing :attr:`jinja_options` after that will have no + effect. + """ + return self.create_jinja_environment() + + def create_jinja_environment(self) -> Environment: + raise NotImplementedError() + + def make_config(self, instance_relative: bool = False) -> Config: + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + defaults = dict(self.default_config) + defaults["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + def make_aborter(self) -> Aborter: + """Create the object to assign to :attr:`aborter`. That object + is called by :func:`flask.abort` to raise HTTP errors, and can + be called directly as well. + + By default, this creates an instance of :attr:`aborter_class`, + which defaults to :class:`werkzeug.exceptions.Aborter`. + + .. versionadded:: 2.2 + """ + return self.aborter_class() + + def auto_find_instance_path(self) -> str: + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, "instance") + return os.path.join(prefix, "var", f"{self.name}-instance") + + def create_global_jinja_loader(self) -> DispatchingJinjaLoader: + """Creates the loader for the Jinja environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename: str | None) -> bool: + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionchanged:: 2.2 + Autoescaping is now enabled by default for ``.svg`` files. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) + + @property + def debug(self) -> bool: + """Whether debug mode is enabled. When using ``flask run`` to start the + development server, an interactive debugger will be shown for unhandled + exceptions, and the server will be reloaded when code changes. This maps to the + :data:`DEBUG` config key. It may not behave as expected if set late. + + **Do not enable debug mode when deploying in production.** + + Default: ``False`` + """ + return self.config["DEBUG"] # type: ignore[no-any-return] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + + if self.config["TEMPLATES_AUTO_RELOAD"] is None: + self.jinja_env.auto_reload = value + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 0.7 + """ + blueprint.register(self, options) + + def iter_blueprints(self) -> t.ValuesView[Blueprint]: + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return self.blueprints.values() + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods: set[str] = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods and self.config["PROVIDE_AUTOMATIC_OPTIONS"]: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule_obj = self.url_rule_class(rule, methods=methods, **options) + rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] + + self.url_map.add(rule_obj) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError( + "View function mapping is overwriting an existing" + f" endpoint function: {endpoint}" + ) + self.view_functions[endpoint] = view_func + + @setupmethod + def template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler( + self, e: Exception, blueprints: list[str] + ) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*blueprints, None) + + for c in (code, None) if code is not None else (None,): + for name in names: + handler_map = self.error_handler_spec[name][c] + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + return None + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect( + location, + code=code, + Response=self.response_class, # type: ignore[arg-type] + ) + + def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + names: t.Iterable[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error diff --git a/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py new file mode 100644 index 0000000..4f912cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py @@ -0,0 +1,632 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .. import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import App + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: App, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore[assignment] + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: DeferredSetupFunction) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: DeferredSetupFunction) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: App, options: dict[str, t.Any], first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: App, options: dict[str, t.Any]) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, # type: ignore[attr-defined] + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + self._merge_blueprint_funcs(app, name) + + for deferred in self.deferred_functions: + deferred(state) + + cli_resolved_group = options.get("cli_group", self.cli_group) + + if self.cli.commands: + if cli_resolved_group is None: + app.cli.commands.update(self.cli.commands) + elif cli_resolved_group is _sentinel: + self.cli.name = name + app.cli.add_command(self.cli) + else: + self.cli.name = cli_resolved_group + app.cli.add_command(self.cli) + + for blueprint, bp_options in self._blueprints: + bp_options = bp_options.copy() + bp_url_prefix = bp_options.get("url_prefix") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + def _merge_blueprint_funcs(self, app: App, name: str) -> None: + def extend( + bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + ) -> None: + for key, values in bp_dict.items(): + key = name if key is None else f"{name}.{key}" + parent_dict[key].extend(values) + + for key, value in self.error_handler_spec.items(): + key = name if key is None else f"{name}.{key}" + value = defaultdict( + dict, + { + code: {exc_class: func for exc_class, func in code_values.items()} + for code, code_values in value.items() + }, + ) + app.error_handler_spec[key] = value + + for endpoint, func in self.view_functions.items(): + app.view_functions[endpoint] = func + + extend(self.before_request_funcs, app.before_request_funcs) + extend(self.after_request_funcs, app.after_request_funcs) + extend( + self.teardown_request_funcs, + app.teardown_request_funcs, + ) + extend(self.url_default_functions, app.url_default_functions) + extend(self.url_value_preprocessors, app.url_value_preprocessors) + extend(self.template_context_processors, app.template_context_processors) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + def from_blueprint(state: BlueprintSetupState) -> None: + state.app.errorhandler(code)(f) + + self.record_once(from_blueprint) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py new file mode 100644 index 0000000..0e96f15 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py @@ -0,0 +1,792 @@ +from __future__ import annotations + +import importlib.util +import os +import pathlib +import sys +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from jinja2 import BaseLoader +from jinja2 import FileSystemLoader +from werkzeug.exceptions import default_exceptions +from werkzeug.exceptions import HTTPException +from werkzeug.utils import cached_property + +from .. import typing as ft +from ..helpers import get_root_path +from ..templating import _default_template_ctx_processor + +if t.TYPE_CHECKING: # pragma: no cover + from click import Group + +# a singleton sentinel value for parameter defaults +_sentinel = object() + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) +T_route = t.TypeVar("T_route", bound=ft.RouteCallable) + + +def setupmethod(f: F) -> F: + f_name = f.__name__ + + def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: + self._check_setup_finished(f_name) + return f(self, *args, **kwargs) + + return t.cast(F, update_wrapper(wrapper_func, f)) + + +class Scaffold: + """Common behavior shared between :class:`~flask.Flask` and + :class:`~flask.blueprints.Blueprint`. + + :param import_name: The import name of the module where this object + is defined. Usually :attr:`__name__` should be used. + :param static_folder: Path to a folder of static files to serve. + If this is set, a static route will be added. + :param static_url_path: URL prefix for the static route. + :param template_folder: Path to a folder containing template files. + for rendering. If this is set, a Jinja loader will be added. + :param root_path: The path that static, template, and resource files + are relative to. Typically not set, it is discovered based on + the ``import_name``. + + .. versionadded:: 2.0 + """ + + cli: Group + name: str + _static_folder: str | None = None + _static_url_path: str | None = None + + def __init__( + self, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + root_path: str | None = None, + ): + #: The name of the package or module that this object belongs + #: to. Do not change this once it is set by the constructor. + self.import_name = import_name + + self.static_folder = static_folder + self.static_url_path = static_url_path + + #: The path to the templates folder, relative to + #: :attr:`root_path`, to add to the template loader. ``None`` if + #: templates should not be added. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Absolute path to the package on the filesystem. Used to look + #: up resources contained in the package. + self.root_path = root_path + + #: A dictionary mapping endpoint names to view functions. + #: + #: To register a view function, use the :meth:`route` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.view_functions: dict[str, ft.RouteCallable] = {} + + #: A data structure of registered error handlers, in the format + #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is + #: the name of a blueprint the handlers are active for, or + #: ``None`` for all requests. The ``code`` key is the HTTP + #: status code for ``HTTPException``, or ``None`` for + #: other exceptions. The innermost dictionary maps exception + #: classes to handler functions. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.error_handler_spec: dict[ + ft.AppOrBlueprintKey, + dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], + ] = defaultdict(lambda: defaultdict(dict)) + + #: A data structure of functions to call at the beginning of + #: each request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`before_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.before_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`after_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.after_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request even if an exception is raised, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`teardown_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.teardown_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.TeardownCallable] + ] = defaultdict(list) + + #: A data structure of functions to call to pass extra context + #: values when rendering templates, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`context_processor` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.template_context_processors: dict[ + ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] + ] = defaultdict(list, {None: [_default_template_ctx_processor]}) + + #: A data structure of functions to call to modify the keyword + #: arguments passed to the view function, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the + #: :meth:`url_value_preprocessor` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_value_preprocessors: dict[ + ft.AppOrBlueprintKey, + list[ft.URLValuePreprocessorCallable], + ] = defaultdict(list) + + #: A data structure of functions to call to modify the keyword + #: arguments when generating URLs, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`url_defaults` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_default_functions: dict[ + ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] + ] = defaultdict(list) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.name!r}>" + + def _check_setup_finished(self, f_name: str) -> None: + raise NotImplementedError + + @property + def static_folder(self) -> str | None: + """The absolute path to the configured static folder. ``None`` + if no static folder is set. + """ + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + else: + return None + + @static_folder.setter + def static_folder(self, value: str | os.PathLike[str] | None) -> None: + if value is not None: + value = os.fspath(value).rstrip(r"\/") + + self._static_folder = value + + @property + def has_static_folder(self) -> bool: + """``True`` if :attr:`static_folder` is set. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @property + def static_url_path(self) -> str | None: + """The URL prefix that the static route will be accessible from. + + If it was not configured during init, it is derived from + :attr:`static_folder`. + """ + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + basename = os.path.basename(self.static_folder) + return f"/{basename}".rstrip("/") + + return None + + @static_url_path.setter + def static_url_path(self, value: str | None) -> None: + if value is not None: + value = value.rstrip("/") + + self._static_url_path = value + + @cached_property + def jinja_loader(self) -> BaseLoader | None: + """The Jinja loader for this object's templates. By default this + is a class :class:`jinja2.loaders.FileSystemLoader` to + :attr:`template_folder` if it is set. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) + else: + return None + + def _method_route( + self, + method: str, + rule: str, + options: dict[str, t.Any], + ) -> t.Callable[[T_route], T_route]: + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + @setupmethod + def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + @setupmethod + def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + @setupmethod + def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + @setupmethod + def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + @setupmethod + def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + + @setupmethod + def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Decorate a view function to register it with the given URL + rule and options. Calls :meth:`add_url_rule`, which has more + details about the implementation. + + .. code-block:: python + + @app.route("/") + def index(): + return "Hello, World!" + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and + ``OPTIONS`` are added automatically. + + :param rule: The URL rule string. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + + def decorator(f: T_route) -> T_route: + endpoint = options.pop("endpoint", None) + self.add_url_rule(rule, endpoint, f, **options) + return f + + return decorator + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a rule for routing incoming requests and building + URLs. The :meth:`route` decorator is a shortcut to call this + with the ``view_func`` argument. These are equivalent: + + .. code-block:: python + + @app.route("/") + def index(): + ... + + .. code-block:: python + + def index(): + ... + + app.add_url_rule("/", view_func=index) + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. An error + will be raised if a function has already been registered for the + endpoint. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is + always added automatically, and ``OPTIONS`` is added + automatically by default. + + ``view_func`` does not necessarily need to be passed, but if the + rule should participate in routing an endpoint name must be + associated with a view function at some point with the + :meth:`endpoint` decorator. + + .. code-block:: python + + app.add_url_rule("/", endpoint="index") + + @app.endpoint("index") + def index(): + ... + + If ``view_func`` has a ``required_methods`` attribute, those + methods are added to the passed and automatic methods. If it + has a ``provide_automatic_methods`` attribute, it is used as the + default if the parameter is not passed. + + :param rule: The URL rule string. + :param endpoint: The endpoint name to associate with the rule + and view function. Used when routing and building URLs. + Defaults to ``view_func.__name__``. + :param view_func: The view function to associate with the + endpoint name. + :param provide_automatic_options: Add the ``OPTIONS`` method and + respond to ``OPTIONS`` requests automatically. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + raise NotImplementedError + + @setupmethod + def endpoint(self, endpoint: str) -> t.Callable[[F], F]: + """Decorate a view function to register it for the given + endpoint. Used if a rule is added without a ``view_func`` with + :meth:`add_url_rule`. + + .. code-block:: python + + app.add_url_rule("/ex", endpoint="example") + + @app.endpoint("example") + def example(): + ... + + :param endpoint: The endpoint name to associate with the view + function. + """ + + def decorator(f: F) -> F: + self.view_functions[endpoint] = f + return f + + return decorator + + @setupmethod + def before_request(self, f: T_before_request) -> T_before_request: + """Register a function to run before each request. + + For example, this can be used to open a database connection, or + to load the logged in user from the session. + + .. code-block:: python + + @app.before_request + def load_user(): + if "user_id" in session: + g.user = db.session.get(session["user_id"]) + + The function will be called without any arguments. If it returns + a non-``None`` value, the value is handled as if it was the + return value from the view, and further request handling is + stopped. + + This is available on both app and blueprint objects. When used on an app, this + executes before every request. When used on a blueprint, this executes before + every request that the blueprint handles. To register with a blueprint and + execute before every request, use :meth:`.Blueprint.before_app_request`. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def after_request(self, f: T_after_request) -> T_after_request: + """Register a function to run after each request to this object. + + The function is called with the response object, and must return + a response object. This allows the functions to modify or + replace the response before it is sent. + + If a function raises an exception, any remaining + ``after_request`` functions will not be called. Therefore, this + should not be used for actions that must execute, such as to + close resources. Use :meth:`teardown_request` for that. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.after_app_request`. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f: T_teardown) -> T_teardown: + """Register a function to be called when the request context is + popped. Typically this happens at the end of each request, but + contexts may be pushed manually as well during testing. + + .. code-block:: python + + with app.test_request_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the request context is + made inactive. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.teardown_app_request`. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def context_processor( + self, + f: T_template_context_processor, + ) -> T_template_context_processor: + """Registers a template context processor function. These functions run before + rendering a template. The keys of the returned dict are added as variables + available in the template. + + This is available on both app and blueprint objects. When used on an app, this + is called for every rendered template. When used on a blueprint, this is called + for templates rendered from the blueprint's views. To register with a blueprint + and affect every template, use :meth:`.Blueprint.app_context_processor`. + """ + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor( + self, + f: T_url_value_preprocessor, + ) -> T_url_value_preprocessor: + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_value_preprocessor`. + """ + self.url_value_preprocessors[None].append(f) + return f + + @setupmethod + def url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_defaults`. + """ + self.url_default_functions[None].append(f) + return f + + @setupmethod + def errorhandler( + self, code_or_exception: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + This is available on both app and blueprint objects. When used on an app, this + can handle errors from every request. When used on a blueprint, this can handle + errors from requests that the blueprint handles. To register with a blueprint + and affect every request, use :meth:`.Blueprint.app_errorhandler`. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.register_error_handler(code_or_exception, f) + return f + + return decorator + + @setupmethod + def register_error_handler( + self, + code_or_exception: type[Exception] | int, + f: ft.ErrorHandlerCallable, + ) -> None: + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + exc_class, code = self._get_exc_class_and_code(code_or_exception) + self.error_handler_spec[None][code][exc_class] = f + + @staticmethod + def _get_exc_class_and_code( + exc_class_or_code: type[Exception] | int, + ) -> tuple[type[Exception], int | None]: + """Get the exception class being handled. For HTTP status codes + or ``HTTPException`` subclasses, return both the exception and + status code. + + :param exc_class_or_code: Any exception class, or an HTTP status + code as an integer. + """ + exc_class: type[Exception] + + if isinstance(exc_class_or_code, int): + try: + exc_class = default_exceptions[exc_class_or_code] + except KeyError: + raise ValueError( + f"'{exc_class_or_code}' is not a recognized HTTP" + " error code. Use a subclass of HTTPException with" + " that code instead." + ) from None + else: + exc_class = exc_class_or_code + + if isinstance(exc_class, Exception): + raise TypeError( + f"{exc_class!r} is an instance, not a class. Handlers" + " can only be registered for Exception classes or HTTP" + " error codes." + ) + + if not issubclass(exc_class, Exception): + raise ValueError( + f"'{exc_class.__name__}' is not a subclass of Exception." + " Handlers can only be registered for Exception classes" + " or HTTP error codes." + ) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + +def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, "expected view func if endpoint is not provided." + return view_func.__name__ + + +def _find_package_path(import_name: str) -> str: + """Find the path that contains the package or module.""" + root_mod_name, _, _ = import_name.partition(".") + + try: + root_spec = importlib.util.find_spec(root_mod_name) + + if root_spec is None: + raise ValueError("not found") + except (ImportError, ValueError): + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - we raised `ValueError` due to `root_spec` being `None` + return os.getcwd() + + if root_spec.submodule_search_locations: + if root_spec.origin is None or root_spec.origin == "namespace": + # namespace package + package_spec = importlib.util.find_spec(import_name) + + if package_spec is not None and package_spec.submodule_search_locations: + # Pick the path in the namespace that contains the submodule. + package_path = pathlib.Path( + os.path.commonpath(package_spec.submodule_search_locations) + ) + search_location = next( + location + for location in root_spec.submodule_search_locations + if package_path.is_relative_to(location) + ) + else: + # Pick the first path. + search_location = root_spec.submodule_search_locations[0] + + return os.path.dirname(search_location) + else: + # package with __init__.py + return os.path.dirname(os.path.dirname(root_spec.origin)) + else: + # module + return os.path.dirname(root_spec.origin) # type: ignore[type-var, return-value] + + +def find_package(import_name: str) -> tuple[str | None, str]: + """Find the prefix that a package is installed under, and the path + that it would be imported from. + + The prefix is the directory containing the standard directory + hierarchy (lib, bin, etc.). If the package is not installed to the + system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), + ``None`` is returned. + + The path is the entry in :attr:`sys.path` that contains the package + for import. If the package is not installed, it's assumed that the + package was imported from the current working directory. + """ + package_path = _find_package_path(import_name) + py_prefix = os.path.abspath(sys.prefix) + + # installed to the system + if pathlib.PurePath(package_path).is_relative_to(py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/venv/lib/python3.12/site-packages/flask/sessions.py b/venv/lib/python3.12/site-packages/flask/sessions.py new file mode 100644 index 0000000..ad35770 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,385 @@ +from __future__ import annotations + +import collections.abc as c +import hashlib +import typing as t +from collections.abc import MutableMapping +from datetime import datetime +from datetime import timezone + +from itsdangerous import BadSignature +from itsdangerous import URLSafeTimedSerializer +from werkzeug.datastructures import CallbackDict + +from .json.tag import TaggedJSONSerializer + +if t.TYPE_CHECKING: # pragma: no cover + import typing_extensions as te + + from .app import Flask + from .wrappers import Request + from .wrappers import Response + + +class SessionMixin(MutableMapping[str, t.Any]): + """Expands a basic dictionary with session attributes.""" + + @property + def permanent(self) -> bool: + """This reflects the ``'_permanent'`` key in the dict.""" + return self.get("_permanent", False) # type: ignore[no-any-return] + + @permanent.setter + def permanent(self, value: bool) -> None: + self["_permanent"] = bool(value) + + #: Some implementations can detect whether a session is newly + #: created, but that is not guaranteed. Use with caution. The mixin + # default is hard-coded ``False``. + new = False + + #: Some implementations can detect changes to the session and set + #: this when that happens. The mixin default is hard coded to + #: ``True``. + modified = True + + accessed = False + """Indicates if the session was accessed, even if it was not modified. This + is set when the session object is accessed through the request context, + including the global :data:`.session` proxy. A ``Vary: cookie`` header will + be added if this is ``True``. + + .. versionchanged:: 3.1.3 + This is tracked by the request context. + """ + + +class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin): + """Base class for sessions based on signed cookies. + + This session backend will set the :attr:`modified` and + :attr:`accessed` attributes. It cannot reliably track whether a + session is new (vs. empty), so :attr:`new` remains hard coded to + ``False``. + """ + + #: When data is changed, this is set to ``True``. Only the session + #: dictionary itself is tracked; if the session contains mutable + #: data (for example a nested dict) then this must be set to + #: ``True`` manually when modifying that data. The session cookie + #: will only be written to the response if this is ``True``. + modified = False + + def __init__( + self, + initial: c.Mapping[str, t.Any] | None = None, + ) -> None: + def on_update(self: te.Self) -> None: + self.modified = True + + super().__init__(initial, on_update) + + +class NullSession(SecureCookieSession): + """Class used to generate nicer error messages if sessions are not + available. Will still allow read-only access to the empty session + but fail on setting. + """ + + def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + raise RuntimeError( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." + ) + + __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail + del _fail + + +class SessionInterface: + """The basic interface you have to implement in order to replace the + default session interface which uses werkzeug's securecookie + implementation. The only methods you have to implement are + :meth:`open_session` and :meth:`save_session`, the others have + useful defaults which you don't need to change. + + The session object returned by the :meth:`open_session` method has to + provide a dictionary like interface plus the properties and methods + from the :class:`SessionMixin`. We recommend just subclassing a dict + and adding that mixin:: + + class Session(dict, SessionMixin): + pass + + If :meth:`open_session` returns ``None`` Flask will call into + :meth:`make_null_session` to create a session that acts as replacement + if the session support cannot work because some requirement is not + fulfilled. The default :class:`NullSession` class that is created + will complain that the secret key was not set. + + To replace the session interface on an application all you have to do + is to assign :attr:`flask.Flask.session_interface`:: + + app = Flask(__name__) + app.session_interface = MySessionInterface() + + Multiple requests with the same session may be sent and handled + concurrently. When implementing a new session interface, consider + whether reads or writes to the backing store must be synchronized. + There is no guarantee on the order in which the session for each + request is opened or saved, it will occur in the order that requests + begin and end processing. + + .. versionadded:: 0.8 + """ + + #: :meth:`make_null_session` will look here for the class that should + #: be created when a null session is requested. Likewise the + #: :meth:`is_null_session` method will perform a typecheck against + #: this type. + null_session_class = NullSession + + #: A flag that indicates if the session interface is pickle based. + #: This can be used by Flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + + def make_null_session(self, app: Flask) -> NullSession: + """Creates a null session which acts as a replacement object if the + real session support could not be loaded due to a configuration + error. This mainly aids the user experience because the job of the + null session is to still support lookup without complaining but + modifications are answered with a helpful error message of what + failed. + + This creates an instance of :attr:`null_session_class` by default. + """ + return self.null_session_class() + + def is_null_session(self, obj: object) -> bool: + """Checks if a given object is a null session. Null sessions are + not asked to be saved. + + This checks if the object is an instance of :attr:`null_session_class` + by default. + """ + return isinstance(obj, self.null_session_class) + + def get_cookie_name(self, app: Flask) -> str: + """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" + return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return] + + def get_cookie_domain(self, app: Flask) -> str | None: + """The value of the ``Domain`` parameter on the session cookie. If not set, + browsers will only send the cookie to the exact domain it was set from. + Otherwise, they will send it to any subdomain of the given value as well. + + Uses the :data:`SESSION_COOKIE_DOMAIN` config. + + .. versionchanged:: 2.3 + Not set by default, does not fall back to ``SERVER_NAME``. + """ + return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return] + + def get_cookie_path(self, app: Flask) -> str: + """Returns the path for which the cookie should be valid. The + default implementation uses the value from the ``SESSION_COOKIE_PATH`` + config var if it's set, and falls back to ``APPLICATION_ROOT`` or + uses ``/`` if it's ``None``. + """ + return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return] + + def get_cookie_httponly(self, app: Flask) -> bool: + """Returns True if the session cookie should be httponly. This + currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` + config var. + """ + return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return] + + def get_cookie_secure(self, app: Flask) -> bool: + """Returns True if the cookie should be secure. This currently + just returns the value of the ``SESSION_COOKIE_SECURE`` setting. + """ + return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return] + + def get_cookie_samesite(self, app: Flask) -> str | None: + """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the + ``SameSite`` attribute. This currently just returns the value of + the :data:`SESSION_COOKIE_SAMESITE` setting. + """ + return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] + + def get_cookie_partitioned(self, app: Flask) -> bool: + """Returns True if the cookie should be partitioned. By default, uses + the value of :data:`SESSION_COOKIE_PARTITIONED`. + + .. versionadded:: 3.1 + """ + return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return] + + def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: + """A helper method that returns an expiration date for the session + or ``None`` if the session is linked to the browser session. The + default implementation returns now + the permanent session + lifetime configured on the application. + """ + if session.permanent: + return datetime.now(timezone.utc) + app.permanent_session_lifetime + return None + + def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: + """Used by session backends to determine if a ``Set-Cookie`` header + should be set for this session cookie for this response. If the session + has been modified, the cookie is set. If the session is permanent and + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is + always set. + + This check is usually skipped if the session was deleted. + + .. versionadded:: 0.11 + """ + + return session.modified or ( + session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] + ) + + def open_session(self, app: Flask, request: Request) -> SessionMixin | None: + """This is called at the beginning of each request, after + pushing the request context, before matching the URL. + + This must return an object which implements a dictionary-like + interface as well as the :class:`SessionMixin` interface. + + This will return ``None`` to indicate that loading failed in + some way that is not immediately an error. The request + context will fall back to using :meth:`make_null_session` + in this case. + """ + raise NotImplementedError() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + """This is called at the end of each request, after generating + a response, before removing the request context. It is skipped + if :meth:`is_null_session` returns ``True``. + """ + raise NotImplementedError() + + +session_json_serializer = TaggedJSONSerializer() + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. + salt = "cookie-session" + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(_lazy_sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = "hmac" + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. + serializer = session_json_serializer + session_class = SecureCookieSession + + def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: + if not app.secret_key: + return None + + keys: list[str | bytes] = [] + + if fallbacks := app.config["SECRET_KEY_FALLBACKS"]: + keys.extend(fallbacks) + + keys.append(app.secret_key) # itsdangerous expects current key at top + return URLSafeTimedSerializer( + keys, # type: ignore[arg-type] + salt=self.salt, + serializer=self.serializer, + signer_kwargs={ + "key_derivation": self.key_derivation, + "digest_method": self.digest_method, + }, + ) + + def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: + s = self.get_signing_serializer(app) + if s is None: + return None + val = request.cookies.get(self.get_cookie_name(app)) + if not val: + return self.session_class() + max_age = int(app.permanent_session_lifetime.total_seconds()) + try: + data = s.loads(val, max_age=max_age) + return self.session_class(data) + except BadSignature: + return self.session_class() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + name = self.get_cookie_name(app) + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + secure = self.get_cookie_secure(app) + partitioned = self.get_cookie_partitioned(app) + samesite = self.get_cookie_samesite(app) + httponly = self.get_cookie_httponly(app) + + # Add a "Vary: Cookie" header if the session was accessed at all. + if session.accessed: + response.vary.add("Cookie") + + # If the session is modified to be empty, remove the cookie. + # If the session is empty, return without setting the cookie. + if not session: + if session.modified: + response.delete_cookie( + name, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + httponly=httponly, + ) + response.vary.add("Cookie") + + return + + if not self.should_set_cookie(app, session): + return + + expires = self.get_expiration_time(app, session) + val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore[union-attr] + response.set_cookie( + name, + val, + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/venv/lib/python3.12/site-packages/flask/signals.py b/venv/lib/python3.12/site-packages/flask/signals.py new file mode 100644 index 0000000..444fda9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/signals.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") diff --git a/venv/lib/python3.12/site-packages/flask/templating.py b/venv/lib/python3.12/site-packages/flask/templating.py new file mode 100644 index 0000000..c5fb5b9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/templating.py @@ -0,0 +1,220 @@ +from __future__ import annotations + +import typing as t + +from jinja2 import BaseLoader +from jinja2 import Environment as BaseEnvironment +from jinja2 import Template +from jinja2 import TemplateNotFound + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .helpers import stream_with_context +from .signals import before_render_template +from .signals import template_rendered + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .sansio.app import App + from .sansio.scaffold import Scaffold + + +def _default_template_ctx_processor() -> dict[str, t.Any]: + """Default template context processor. Replaces the ``request`` and ``g`` + proxies with their concrete objects for faster access. + """ + appctx = _cv_app.get(None) + reqctx = _cv_request.get(None) + rv: dict[str, t.Any] = {} + if appctx is not None: + rv["g"] = appctx.g + if reqctx is not None: + rv["request"] = reqctx.request + # The session proxy cannot be replaced, accessing it gets + # RequestContext.session, which sets session.accessed. + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja environment but has some additional + knowledge of how Flask's blueprint works so that it can prepend the + name of the blueprint to referenced templates if necessary. + """ + + def __init__(self, app: App, **options: t.Any) -> None: + if "loader" not in options: + options["loader"] = app.create_global_jinja_loader() + BaseEnvironment.__init__(self, **options) + self.app = app + + +class DispatchingJinjaLoader(BaseLoader): + """A loader that looks for templates in the application and all + the blueprint folders. + """ + + def __init__(self, app: App) -> None: + self.app = app + + def get_source( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: + return self._get_source_explained(environment, template) + return self._get_source_fast(environment, template) + + def _get_source_explained( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + attempts = [] + rv: tuple[str, str | None, t.Callable[[], bool] | None] | None + trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None + + for srcobj, loader in self._iter_loaders(template): + try: + rv = loader.get_source(environment, template) + if trv is None: + trv = rv + except TemplateNotFound: + rv = None + attempts.append((loader, srcobj, rv)) + + from .debughelpers import explain_template_loading_attempts + + explain_template_loading_attempts(self.app, template, attempts) + + if trv is not None: + return trv + raise TemplateNotFound(template) + + def _get_source_fast( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + for _srcobj, loader in self._iter_loaders(template): + try: + return loader.get_source(environment, template) + except TemplateNotFound: + continue + raise TemplateNotFound(template) + + def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]: + loader = self.app.jinja_loader + if loader is not None: + yield self.app, loader + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + yield blueprint, loader + + def list_templates(self) -> list[str]: + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + result.add(template) + + return list(result) + + +def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + rv = template.render(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + return rv + + +def render_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> str: + """Render a template by name with the given context. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _render(app, template, context) + + +def render_template_string(source: str, **context: t.Any) -> str: + """Render a template from the given source string with the given + context. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _render(app, template, context) + + +def _stream( + app: Flask, template: Template, context: dict[str, t.Any] +) -> t.Iterator[str]: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + def generate() -> t.Iterator[str]: + yield from template.generate(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + rv = generate() + + # If a request context is active, keep it while generating. + if request: + rv = stream_with_context(rv) + + return rv + + +def stream_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> t.Iterator[str]: + """Render a template by name with the given context as a stream. + This returns an iterator of strings, which can be used as a + streaming response from a view. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _stream(app, template, context) + + +def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: + """Render a template from the given source string with the given + context as a stream. This returns an iterator of strings, which can + be used as a streaming response from a view. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _stream(app, template, context) diff --git a/venv/lib/python3.12/site-packages/flask/testing.py b/venv/lib/python3.12/site-packages/flask/testing.py new file mode 100644 index 0000000..55eb12f --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/testing.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import importlib.metadata +import typing as t +from contextlib import contextmanager +from contextlib import ExitStack +from copy import copy +from types import TracebackType +from urllib.parse import urlsplit + +import werkzeug.test +from click.testing import CliRunner +from click.testing import Result +from werkzeug.test import Client +from werkzeug.wrappers import Request as BaseRequest + +from .cli import ScriptInfo +from .sessions import SessionMixin + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + from werkzeug.test import TestResponse + + from .app import Flask + + +class EnvironBuilder(werkzeug.test.EnvironBuilder): + """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the + application. + + :param app: The Flask application to configure the environment from. + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + + def __init__( + self, + app: Flask, + path: str = "/", + base_url: str | None = None, + subdomain: str | None = None, + url_scheme: str | None = None, + *args: t.Any, + **kwargs: t.Any, + ) -> None: + assert not (base_url or subdomain or url_scheme) or ( + base_url is not None + ) != bool(subdomain or url_scheme), ( + 'Cannot pass "subdomain" or "url_scheme" with "base_url".' + ) + + if base_url is None: + http_host = app.config.get("SERVER_NAME") or "localhost" + app_root = app.config["APPLICATION_ROOT"] + + if subdomain: + http_host = f"{subdomain}.{http_host}" + + if url_scheme is None: + url_scheme = app.config["PREFERRED_URL_SCHEME"] + + url = urlsplit(path) + base_url = ( + f"{url.scheme or url_scheme}://{url.netloc or http_host}" + f"/{app_root.lstrip('/')}" + ) + path = url.path + + if url.query: + path = f"{path}?{url.query}" + + self.app = app + super().__init__(path, base_url, *args, **kwargs) + + def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize ``obj`` to a JSON-formatted string. + + The serialization will be configured according to the config associated + with this EnvironBuilder's ``app``. + """ + return self.app.json.dumps(obj, **kwargs) + + +_werkzeug_version = "" + + +def _get_werkzeug_version() -> str: + global _werkzeug_version + + if not _werkzeug_version: + _werkzeug_version = importlib.metadata.version("werkzeug") + + return _werkzeug_version + + +class FlaskClient(Client): + """Works like a regular Werkzeug test client but has knowledge about + Flask's contexts to defer the cleanup of the request context until + the end of a ``with`` block. For general information about how to + use this class refer to :class:`werkzeug.test.Client`. + + .. versionchanged:: 0.12 + `app.test_client()` includes preset default environment, which can be + set after instantiation of the `app.test_client()` object in + `client.environ_base`. + + Basic usage is outlined in the :doc:`/testing` chapter. + """ + + application: Flask + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.preserve_context = False + self._new_contexts: list[t.ContextManager[t.Any]] = [] + self._context_stack = ExitStack() + self.environ_base = { + "REMOTE_ADDR": "127.0.0.1", + "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}", + } + + @contextmanager + def session_transaction( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Iterator[SessionMixin]: + """When used in combination with a ``with`` statement this opens a + session transaction. This can be used to modify the session that + the test client uses. Once the ``with`` block is left the session is + stored back. + + :: + + with client.session_transaction() as session: + session['value'] = 42 + + Internally this is implemented by going through a temporary test + request context and since session handling could depend on + request variables this function accepts the same arguments as + :meth:`~flask.Flask.test_request_context` which are directly + passed through. + """ + if self._cookies is None: + raise TypeError( + "Cookies are disabled. Create a client with 'use_cookies=True'." + ) + + app = self.application + ctx = app.test_request_context(*args, **kwargs) + self._add_cookies_to_wsgi(ctx.request.environ) + + with ctx: + sess = app.session_interface.open_session(app, ctx.request) + + if sess is None: + raise RuntimeError("Session backend did not open a session.") + + yield sess + resp = app.response_class() + + if app.session_interface.is_null_session(sess): + return + + with ctx: + app.session_interface.save_session(app, sess, resp) + + self._update_cookies_from_response( + ctx.request.host.partition(":")[0], + ctx.request.path, + resp.headers.getlist("Set-Cookie"), + ) + + def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment: + out = {**self.environ_base, **other} + + if self.preserve_context: + out["werkzeug.debug.preserve_context"] = self._new_contexts.append + + return out + + def _request_from_builder_args( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> BaseRequest: + kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) + builder = EnvironBuilder(self.application, *args, **kwargs) + + try: + return builder.get_request() + finally: + builder.close() + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> TestResponse: + if args and isinstance( + args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) + ): + if isinstance(args[0], werkzeug.test.EnvironBuilder): + builder = copy(args[0]) + builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type] + request = builder.get_request() + elif isinstance(args[0], dict): + request = EnvironBuilder.from_environ( + args[0], app=self.application, environ_base=self._copy_environ({}) + ).get_request() + else: + # isinstance(args[0], BaseRequest) + request = copy(args[0]) + request.environ = self._copy_environ(request.environ) + else: + # request is None + request = self._request_from_builder_args(args, kwargs) + + # Pop any previously preserved contexts. This prevents contexts + # from being preserved across redirects or multiple requests + # within a single block. + self._context_stack.close() + + response = super().open( + request, + buffered=buffered, + follow_redirects=follow_redirects, + ) + response.json_module = self.application.json # type: ignore[assignment] + + # Re-push contexts that were preserved during the request. + for cm in self._new_contexts: + self._context_stack.enter_context(cm) + + self._new_contexts.clear() + return response + + def __enter__(self) -> FlaskClient: + if self.preserve_context: + raise RuntimeError("Cannot nest client invocations") + self.preserve_context = True + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.preserve_context = False + self._context_stack.close() + + +class FlaskCliRunner(CliRunner): + """A :class:`~click.testing.CliRunner` for testing a Flask app's + CLI commands. Typically created using + :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. + """ + + def __init__(self, app: Flask, **kwargs: t.Any) -> None: + self.app = app + super().__init__(**kwargs) + + def invoke( # type: ignore + self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any + ) -> Result: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/venv/lib/python3.12/site-packages/flask/typing.py b/venv/lib/python3.12/site-packages/flask/typing.py new file mode 100644 index 0000000..6b70c40 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/typing.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIApplication # noqa: F401 + from werkzeug.datastructures import Headers # noqa: F401 + from werkzeug.sansio.response import Response # noqa: F401 + +# The possible types that are directly convertible or are a Response object. +ResponseValue = t.Union[ + "Response", + str, + bytes, + list[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[bytes], + cabc.AsyncIterable[str], # for Quart, until App is generic. + cabc.AsyncIterable[bytes], +] + +# the possible types for an individual HTTP header +# This should be a Union, but mypy doesn't pass unless it's a TypeVar. +HeaderValue = t.Union[str, list[str], tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + tuple[ResponseValue, HeadersValue], + tuple[ResponseValue, int], + tuple[ResponseValue, int, HeadersValue], + "WSGIApplication", +] + +# Allow any subclass of werkzeug.Response, such as the one from Flask, +# as a callback argument. Using werkzeug.Response directly makes a +# callback annotated with flask.Response fail type checking. +ResponseClass = t.TypeVar("ResponseClass", bound="Response") + +AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named +AfterRequestCallable = t.Union[ + t.Callable[[ResponseClass], ResponseClass], + t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], +] +BeforeFirstRequestCallable = t.Union[ + t.Callable[[], None], t.Callable[[], t.Awaitable[None]] +] +BeforeRequestCallable = t.Union[ + t.Callable[[], t.Optional[ResponseReturnValue]], + t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], +] +ShellContextProcessorCallable = t.Callable[[], dict[str, t.Any]] +TeardownCallable = t.Union[ + t.Callable[[t.Optional[BaseException]], None], + t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], +] +TemplateContextProcessorCallable = t.Union[ + t.Callable[[], dict[str, t.Any]], + t.Callable[[], t.Awaitable[dict[str, t.Any]]], +] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, dict[str, t.Any]], None] +URLValuePreprocessorCallable = t.Callable[ + [t.Optional[str], t.Optional[dict[str, t.Any]]], None +] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Union[ + t.Callable[[t.Any], ResponseReturnValue], + t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], +] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/venv/lib/python3.12/site-packages/flask/views.py b/venv/lib/python3.12/site-packages/flask/views.py new file mode 100644 index 0000000..53fe976 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/views.py @@ -0,0 +1,191 @@ +from __future__ import annotations + +import typing as t + +from . import typing as ft +from .globals import current_app +from .globals import request + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +http_method_funcs = frozenset( + ["get", "post", "head", "options", "delete", "put", "trace", "patch"] +) + + +class View: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class Hello(View): + init_every_request = False + + def dispatch_request(self, name): + return f"Hello, {name}!" + + app.add_url_rule( + "/hello/", view_func=Hello.as_view("hello") + ) + + Set :attr:`methods` on the class to change what methods the view + accepts. + + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! + + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. + """ + + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Collection[str] | None] = None + + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[bool | None] = None + + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. + #: + #: .. versionadded:: 0.8 + decorators: t.ClassVar[list[t.Callable[..., t.Any]]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True + + def dispatch_request(self) -> ft.ResponseReturnValue: + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. + """ + raise NotImplementedError() + + @classmethod + def as_view( + cls, name: str, *class_args: t.Any, **class_kwargs: t.Any + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. + """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + else: + self = cls(*class_args, **class_kwargs) # pyright: ignore + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/venv/lib/python3.12/site-packages/flask/wrappers.py b/venv/lib/python3.12/site-packages/flask/wrappers.py new file mode 100644 index 0000000..bab6102 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/wrappers.py @@ -0,0 +1,257 @@ +from __future__ import annotations + +import typing as t + +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import HTTPException +from werkzeug.wrappers import Request as RequestBase +from werkzeug.wrappers import Response as ResponseBase + +from . import json +from .globals import current_app +from .helpers import _split_blueprint_path + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.routing import Rule + + +class Request(RequestBase): + """The request object used by default in Flask. Remembers the + matched endpoint and view arguments. + + It is what ends up as :class:`~flask.request`. If you want to replace + the request object used you can subclass this and set + :attr:`~flask.Flask.request_class` to your subclass. + + The request object is a :class:`~werkzeug.wrappers.Request` subclass and + provides all of the attributes Werkzeug defines plus a few Flask + specific ones. + """ + + json_module: t.Any = json + + #: The internal URL rule that matched the request. This can be + #: useful to inspect which methods are allowed for the URL from + #: a before/after handler (``request.url_rule.methods``) etc. + #: Though if the request's method was invalid for the URL rule, + #: the valid list is available in ``routing_exception.valid_methods`` + #: instead (an attribute of the Werkzeug exception + #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) + #: because the request was never internally bound. + #: + #: .. versionadded:: 0.6 + url_rule: Rule | None = None + + #: A dict of view arguments that matched the request. If an exception + #: happened when matching, this will be ``None``. + view_args: dict[str, t.Any] | None = None + + #: If matching the URL failed, this is the exception that will be + #: raised / was raised as part of the request handling. This is + #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or + #: something similar. + routing_exception: HTTPException | None = None + + _max_content_length: int | None = None + _max_form_memory_size: int | None = None + _max_form_parts: int | None = None + + @property + def max_content_length(self) -> int | None: + """The maximum number of bytes that will be read during this request. If + this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` + error is raised. If it is set to ``None``, no limit is enforced at the + Flask application level. However, if it is ``None`` and the request has + no ``Content-Length`` header and the WSGI server does not indicate that + it terminates the stream, then no data is read to avoid an infinite + stream. + + Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which + defaults to ``None``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This can be set per-request. + + .. versionchanged:: 0.6 + This is configurable through Flask config. + """ + if self._max_content_length is not None: + return self._max_content_length + + if not current_app: + return super().max_content_length + + return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] + + @max_content_length.setter + def max_content_length(self, value: int | None) -> None: + self._max_content_length = value + + @property + def max_form_memory_size(self) -> int | None: + """The maximum size in bytes any non-file form field may be in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which + defaults to ``500_000``. It can be set on a specific ``request`` to + apply the limit to that specific view. This should be set appropriately + based on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_memory_size is not None: + return self._max_form_memory_size + + if not current_app: + return super().max_form_memory_size + + return current_app.config["MAX_FORM_MEMORY_SIZE"] # type: ignore[no-any-return] + + @max_form_memory_size.setter + def max_form_memory_size(self, value: int | None) -> None: + self._max_form_memory_size = value + + @property # type: ignore[override] + def max_form_parts(self) -> int | None: + """The maximum number of fields that may be present in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_PARTS` config, which + defaults to ``1_000``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_parts is not None: + return self._max_form_parts + + if not current_app: + return super().max_form_parts + + return current_app.config["MAX_FORM_PARTS"] # type: ignore[no-any-return] + + @max_form_parts.setter + def max_form_parts(self, value: int | None) -> None: + self._max_form_parts = value + + @property + def endpoint(self) -> str | None: + """The endpoint that matched the request URL. + + This will be ``None`` if matching failed or has not been + performed yet. + + This in combination with :attr:`view_args` can be used to + reconstruct the same URL or a modified URL. + """ + if self.url_rule is not None: + return self.url_rule.endpoint # type: ignore[no-any-return] + + return None + + @property + def blueprint(self) -> str | None: + """The registered name of the current blueprint. + + This will be ``None`` if the endpoint is not part of a + blueprint, or if URL matching failed or has not been performed + yet. + + This does not necessarily match the name the blueprint was + created with. It may have been nested, or registered with a + different name. + """ + endpoint = self.endpoint + + if endpoint is not None and "." in endpoint: + return endpoint.rpartition(".")[0] + + return None + + @property + def blueprints(self) -> list[str]: + """The registered names of the current blueprint upwards through + parent blueprints. + + This will be an empty list if there is no current blueprint, or + if URL matching failed. + + .. versionadded:: 2.0.1 + """ + name = self.blueprint + + if name is None: + return [] + + return _split_blueprint_path(name) + + def _load_form_data(self) -> None: + super()._load_form_data() + + # In debug mode we're replacing the files multidict with an ad-hoc + # subclass that raises a different error for key errors. + if ( + current_app + and current_app.debug + and self.mimetype != "multipart/form-data" + and not self.files + ): + from .debughelpers import attach_enctype_error_multidict + + attach_enctype_error_multidict(self) + + def on_json_loading_failed(self, e: ValueError | None) -> t.Any: + try: + return super().on_json_loading_failed(e) + except BadRequest as ebr: + if current_app and current_app.debug: + raise + + raise BadRequest() from ebr + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..7b190ca --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2011 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA new file mode 100644 index 0000000..ddf5464 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: itsdangerous +Version: 2.2.0 +Summary: Safely pass data to untrusted environments and back. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/itsdangerous/ + +# ItsDangerous + +... so better sign this + +Various helpers to pass data to untrusted environments and to get it +back safe and sound. Data is cryptographically signed to ensure that a +token has not been tampered with. + +It's possible to customize how data is serialized. Data is compressed as +needed. A timestamp can be added and verified automatically while +loading a token. + + +## A Simple Example + +Here's how you could generate a token for transmitting a user's id and +name between web requests. + +```python +from itsdangerous import URLSafeSerializer +auth_s = URLSafeSerializer("secret key", "auth") +token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) + +print(token) +# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg + +data = auth_s.loads(token) +print(data["name"]) +# itsdangerous +``` + + +## Donate + +The Pallets organization develops and supports ItsDangerous and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +[please donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD new file mode 100644 index 0000000..245f43e --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD @@ -0,0 +1,22 @@ +itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 +itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 +itsdangerous-2.2.0.dist-info/RECORD,, +itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 +itsdangerous/__pycache__/__init__.cpython-312.pyc,, +itsdangerous/__pycache__/_json.cpython-312.pyc,, +itsdangerous/__pycache__/encoding.cpython-312.pyc,, +itsdangerous/__pycache__/exc.cpython-312.pyc,, +itsdangerous/__pycache__/serializer.cpython-312.pyc,, +itsdangerous/__pycache__/signer.cpython-312.pyc,, +itsdangerous/__pycache__/timed.cpython-312.pyc,, +itsdangerous/__pycache__/url_safe.cpython-312.pyc,, +itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 +itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 +itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 +itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 +itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 +itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 +itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__init__.py b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py new file mode 100644 index 0000000..ea55256 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import typing as t + +from .encoding import base64_decode as base64_decode +from .encoding import base64_encode as base64_encode +from .encoding import want_bytes as want_bytes +from .exc import BadData as BadData +from .exc import BadHeader as BadHeader +from .exc import BadPayload as BadPayload +from .exc import BadSignature as BadSignature +from .exc import BadTimeSignature as BadTimeSignature +from .exc import SignatureExpired as SignatureExpired +from .serializer import Serializer as Serializer +from .signer import HMACAlgorithm as HMACAlgorithm +from .signer import NoneAlgorithm as NoneAlgorithm +from .signer import Signer as Signer +from .timed import TimedSerializer as TimedSerializer +from .timed import TimestampSigner as TimestampSigner +from .url_safe import URLSafeSerializer as URLSafeSerializer +from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " ItsDangerous 2.3. Use feature detection or" + " 'importlib.metadata.version(\"itsdangerous\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("itsdangerous") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bc341258424ace3d06f518278bea0f101cb71f8f GIT binary patch literal 1626 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 CHeD3} literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8483c929ad38576f045122269dc7f03bdc678836 GIT binary patch literal 3940 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ad8a2254cfeeec7ee02d96214f3d9f88c8dcd49 GIT binary patch literal 11286 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 Rc>bm79S0BHOgSUyzX2SIrPlxe literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a3db6d1463e5ac6b59497684d9c5f3a0ae47ec38 GIT binary patch literal 8734 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..150fecede2827e9eb5d9e6f05e58c4e63a7be95b GIT binary patch literal 3530 zcmbtWZ)_Y#6`#G`z5jpw@6L7-<7u3#xe%YpUxX8&PC`Q~;#Rm-;G(cz-;V9I_im5b zy*NIdX@r8fr~)+~P+U)@6FqpH}Ci6{V|b<5@>(^{R8t45klU>Nvnl?LfUu-h#SNphGdbVl$Ru= z16Cj}i&4odhHNO7S`6lcAd?N%3Khfou%LrLNAeLthpcEZmX8TKY{iR-d_vF>pp*He zprcl**pcs$NPwIrM(ipv;w;HJ`(Y2aWPeBbE+I>REXlgIq)JoTEu<-sc7U{_xwa+k zSqx-5KS0&2Yp3mESueOROuRS_N{K1mVaJbZ1}oSG+s0s} zCL?-EH(t^gEn7E0+@Za6MtAiI#!cNatBeCL`ot{tvRPzCn^o|4?)S}&N*mvR`S-!` zjN~PQ|L>U~)p#Dbm!*7U zf@Gs!=9RC1Z9<=B?QNVhFPo+6J1{VVnkBkmy0cWLoXu1$ol|G)K-6?WXjxQuT~;i+ z)U|2VGN+;xS^=ELnd4A*mQly$W@!fHMSY&(I%n4AF5}dkrX^MYJ)JM+=<_XumSYPm zzR#)e;_ap!8)mwTrV4tAI&cDOkxnsMw)BF(Z=J%?a>7hCz4J0Iz?Lq0T?U)hE0(LZ z4~179ZBGk<=A~d%sPLa6MB3O3vmZ$S25CvHNpmRM(Tu>YCYOh55`cm1B1@8?EU6LV zHUpTDn$*%-3f5Gf0U5y0Z*u~Yt(ia8f^B^_(UM&Y*T@g{fVJR^RFi)y{UT_Rn({O0 zhtdQYB5pI12-!z?_fp7h0ve)5t%ZIbywyBmE%e=hL6$<_2`xwqd=2$ zoehsaw}D>Baooep)f1=fie*s18f{*z4<>Q3Wgj_khXuXjFltXzxL9_%z{&_rxR#{N z%^9<#TN>ls=GC#bISf0B#^+l5j5DYJiah8YZuu_ML$%Xg5lEe{ITI_lNZ4V8+J^Wja*`-OCzwYk@BKD zYnP7X4jmpr!7${jd3}aCBc|&ZdTEAnyW)&gxTPUNa^*$d2cN1AeKP2C+fURBiq3DK zdvt{~k|eXc9(@q&`b%u!Zfs!L_)~0XJu|SZFHgNbUq8FvKTv<6p#&r8d);)Ucda{H zKl3n2;+aMunCQRPyZgqg*I!+6*Ln}Wu52brNBY{r-PF*^nbp+j&7<$8MsFX#n;KmW zk3QNQBpv-95(Nx(?OE?Qw?0TWRk=Ia2$G(3BP1u%A2(!>e!SU5dImrdtY_$Y&-wMC zeW2Le1&V$BpxD`uii!TmP7aRnlh{}{xs@I}Ozw0?#zy2jdy-=ZbT5OR|WIbI!q&c`3` z1ZFnK@n*faQ7M*N(aY1w3b)|n$rdYd%oEuV$0yg5?Ws9FfKjV-w^-kL zX4mrh>!teH2dPXwxdC5*7m)9Q!BeLeUFPuJKtER9+*oN*0Js_#G_BEbyTmvoS;9Yy z`a#az3NMLCR^d;#1pFXU2cUzuHLPhRy~s4pi)vcYHYyg{MgtZ<)~Xy%Lpvn)-^O1`Tx$3E*j86O3X9i|`W0(6hQM;-=bHQb1j zLtk7~GOK;VYs$$+ob22GF!CAo#DmUELxmBL(*Y1eDooN(HBbg?y89Y2q~au+`X~X^ zKc1D6YVSh=9nZGD_C)E@eE6h|4iL8s7c5(#>XNin9;5BtUkqDsylQ6+>GPob?rZ2IAu?`4F$h*Fo`r<;Pa(wxf)!{_c~UxkKsGJSyA( zcl3XHRG2~6|BoK!$IxHLu@iAdk@`Zbdl3oD6uuDo*)-y8x&puioN>t7fKzv|3{l`o zuAk#n4WC~DHZLs7N|1_&U*tPahJr)9`vU$PA7+k)n5Vi}taD7do(#pK0GWTKVoy)* z^Ktm3kM}R}Q?LRNA;8#>B}uwZ_P$5D{z_thCxiFNkofJsPxb>Jew)GLQtxv9ru>Gs qNr2qsk|Kpy`*OFVzdrKI)Fy%1W)fKgM{a9xPuxBB{71+We)uP0lbg~2 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/_json.py b/venv/lib/python3.12/site-packages/itsdangerous/_json.py new file mode 100644 index 0000000..fc23fea --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/_json.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import json as _json +import typing as t + + +class _CompactJSON: + """Wrapper around json module that strips whitespace.""" + + @staticmethod + def loads(payload: str | bytes) -> t.Any: + return _json.loads(payload) + + @staticmethod + def dumps(obj: t.Any, **kwargs: t.Any) -> str: + kwargs.setdefault("ensure_ascii", False) + kwargs.setdefault("separators", (",", ":")) + return _json.dumps(obj, **kwargs) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/encoding.py b/venv/lib/python3.12/site-packages/itsdangerous/encoding.py new file mode 100644 index 0000000..f5ca80f --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/encoding.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import base64 +import string +import struct +import typing as t + +from .exc import BadData + + +def want_bytes( + s: str | bytes, encoding: str = "utf-8", errors: str = "strict" +) -> bytes: + if isinstance(s, str): + s = s.encode(encoding, errors) + + return s + + +def base64_encode(string: str | bytes) -> bytes: + """Base64 encode a string of bytes or text. The resulting bytes are + safe to use in URLs. + """ + string = want_bytes(string) + return base64.urlsafe_b64encode(string).rstrip(b"=") + + +def base64_decode(string: str | bytes) -> bytes: + """Base64 decode a URL-safe string of bytes or text. The result is + bytes. + """ + string = want_bytes(string, encoding="ascii", errors="ignore") + string += b"=" * (-len(string) % 4) + + try: + return base64.urlsafe_b64decode(string) + except (TypeError, ValueError) as e: + raise BadData("Invalid base64-encoded data") from e + + +# The alphabet used by base64.urlsafe_* +_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") + +_int64_struct = struct.Struct(">Q") +_int_to_bytes = _int64_struct.pack +_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) + + +def int_to_bytes(num: int) -> bytes: + return _int_to_bytes(num).lstrip(b"\x00") + + +def bytes_to_int(bytestr: bytes) -> int: + return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/venv/lib/python3.12/site-packages/itsdangerous/exc.py b/venv/lib/python3.12/site-packages/itsdangerous/exc.py new file mode 100644 index 0000000..a75adcd --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/exc.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import typing as t +from datetime import datetime + + +class BadData(Exception): + """Raised if bad data of any sort was encountered. This is the base + for all exceptions that ItsDangerous defines. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + def __str__(self) -> str: + return self.message + + +class BadSignature(BadData): + """Raised if a signature does not match.""" + + def __init__(self, message: str, payload: t.Any | None = None): + super().__init__(message) + + #: The payload that failed the signature test. In some + #: situations you might still want to inspect this, even if + #: you know it was tampered with. + #: + #: .. versionadded:: 0.14 + self.payload: t.Any | None = payload + + +class BadTimeSignature(BadSignature): + """Raised if a time-based signature is invalid. This is a subclass + of :class:`BadSignature`. + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + date_signed: datetime | None = None, + ): + super().__init__(message, payload) + + #: If the signature expired this exposes the date of when the + #: signature was created. This can be helpful in order to + #: tell the user how long a link has been gone stale. + #: + #: .. versionchanged:: 2.0 + #: The datetime value is timezone-aware rather than naive. + #: + #: .. versionadded:: 0.14 + self.date_signed = date_signed + + +class SignatureExpired(BadTimeSignature): + """Raised if a signature timestamp is older than ``max_age``. This + is a subclass of :exc:`BadTimeSignature`. + """ + + +class BadHeader(BadSignature): + """Raised if a signed header is invalid in some form. This only + happens for serializers that have a header that goes with the + signature. + + .. versionadded:: 0.24 + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + header: t.Any | None = None, + original_error: Exception | None = None, + ): + super().__init__(message, payload) + + #: If the header is actually available but just malformed it + #: might be stored here. + self.header: t.Any | None = header + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error + + +class BadPayload(BadData): + """Raised if a payload is invalid. This could happen if the payload + is loaded despite an invalid signature, or if there is a mismatch + between the serializer and deserializer. The original exception + that occurred during loading is stored on as :attr:`original_error`. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str, original_error: Exception | None = None): + super().__init__(message) + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error diff --git a/venv/lib/python3.12/site-packages/itsdangerous/py.typed b/venv/lib/python3.12/site-packages/itsdangerous/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/serializer.py b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py new file mode 100644 index 0000000..5ddf387 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py @@ -0,0 +1,406 @@ +from __future__ import annotations + +import collections.abc as cabc +import json +import typing as t + +from .encoding import want_bytes +from .exc import BadPayload +from .exc import BadSignature +from .signer import _make_keys_list +from .signer import Signer + +if t.TYPE_CHECKING: + import typing_extensions as te + + # This should be either be str or bytes. To avoid having to specify the + # bound type, it falls back to a union if structural matching fails. + _TSerialized = te.TypeVar( + "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes] + ) +else: + # Still available at runtime on Python < 3.13, but without the default. + _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes]) + + +class _PDataSerializer(t.Protocol[_TSerialized]): + def loads(self, payload: _TSerialized, /) -> t.Any: ... + # A signature with additional arguments is not handled correctly by type + # checkers right now, so an overload is used below for serializers that + # don't match this strict protocol. + def dumps(self, obj: t.Any, /) -> _TSerialized: ... + + +# Use TypeIs once it's available in typing_extensions or 3.13. +def is_text_serializer( + serializer: _PDataSerializer[t.Any], +) -> te.TypeGuard[_PDataSerializer[str]]: + """Checks whether a serializer generates text or binary.""" + return isinstance(serializer.dumps({}), str) + + +class Serializer(t.Generic[_TSerialized]): + """A serializer wraps a :class:`~itsdangerous.signer.Signer` to + enable serializing and securely signing data other than bytes. It + can unsign to verify that the data hasn't been changed. + + The serializer provides :meth:`dumps` and :meth:`loads`, similar to + :mod:`json`, and by default uses :mod:`json` internally to serialize + the data to bytes. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param serializer: An object that provides ``dumps`` and ``loads`` + methods for serializing data to a string. Defaults to + :attr:`default_serializer`, which defaults to :mod:`json`. + :param serializer_kwargs: Keyword arguments to pass when calling + ``serializer.dumps``. + :param signer: A ``Signer`` class to instantiate when signing data. + Defaults to :attr:`default_signer`, which defaults to + :class:`~itsdangerous.signer.Signer`. + :param signer_kwargs: Keyword arguments to pass when instantiating + the ``Signer`` class. + :param fallback_signers: List of signer parameters to try when + unsigning with the default signer fails. Each item can be a dict + of ``signer_kwargs``, a ``Signer`` class, or a tuple of + ``(signer, signer_kwargs)``. Defaults to + :attr:`default_fallback_signers`. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 2.0 + Removed the default SHA-512 fallback signer from + ``default_fallback_signers``. + + .. versionchanged:: 1.1 + Added support for ``fallback_signers`` and configured a default + SHA-512 fallback. This fallback is for users who used the yanked + 1.0.0 release which defaulted to SHA-512. + + .. versionchanged:: 0.14 + The ``signer`` and ``signer_kwargs`` parameters were added to + the constructor. + """ + + #: The default serialization module to use to serialize data to a + #: string internally. The default is :mod:`json`, but can be changed + #: to any object that provides ``dumps`` and ``loads`` methods. + default_serializer: _PDataSerializer[t.Any] = json + + #: The default ``Signer`` class to instantiate when signing data. + #: The default is :class:`itsdangerous.signer.Signer`. + default_signer: type[Signer] = Signer + + #: The default fallback signers to try when unsigning fails. + default_fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = [] + + # Serializer[str] if no data serializer is provided, or if it returns str. + @t.overload + def __init__( + self: Serializer[str], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: None | _PDataSerializer[str] = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer positional argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer keyword argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a positional argument. If the strict signature of + # _PDataSerializer doesn't match, fall back to a union, requiring the user + # to specify the type. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a keyword argument. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: t.Any | None = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + + if salt is not None: + salt = want_bytes(salt) + # if salt is None then the signer's default is used + + self.salt = salt + + if serializer is None: + serializer = self.default_serializer + + self.serializer: _PDataSerializer[_TSerialized] = serializer + self.is_text_serializer: bool = is_text_serializer(serializer) + + if signer is None: + signer = self.default_signer + + self.signer: type[Signer] = signer + self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {} + + if fallback_signers is None: + fallback_signers = list(self.default_fallback_signers) + + self.fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = fallback_signers + self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {} + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def load_payload( + self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None + ) -> t.Any: + """Loads the encoded object. This function raises + :class:`.BadPayload` if the payload is not valid. The + ``serializer`` parameter can be used to override the serializer + stored on the class. The encoded ``payload`` should always be + bytes. + """ + if serializer is None: + use_serializer = self.serializer + is_text = self.is_text_serializer + else: + use_serializer = serializer + is_text = is_text_serializer(serializer) + + try: + if is_text: + return use_serializer.loads(payload.decode("utf-8")) # type: ignore[arg-type] + + return use_serializer.loads(payload) # type: ignore[arg-type] + except Exception as e: + raise BadPayload( + "Could not load the payload because an exception" + " occurred on unserializing the data.", + original_error=e, + ) from e + + def dump_payload(self, obj: t.Any) -> bytes: + """Dumps the encoded object. The return value is always bytes. + If the internal serializer returns text, the value will be + encoded as UTF-8. + """ + return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) + + def make_signer(self, salt: str | bytes | None = None) -> Signer: + """Creates a new instance of the signer to be used. The default + implementation uses the :class:`.Signer` base class. + """ + if salt is None: + salt = self.salt + + return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) + + def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]: + """Iterates over all signers to be tried for unsigning. Starts + with the configured signer, then constructs each signer + specified in ``fallback_signers``. + """ + if salt is None: + salt = self.salt + + yield self.make_signer(salt) + + for fallback in self.fallback_signers: + if isinstance(fallback, dict): + kwargs = fallback + fallback = self.signer + elif isinstance(fallback, tuple): + fallback, kwargs = fallback + else: + kwargs = self.signer_kwargs + + for secret_key in self.secret_keys: + yield fallback(secret_key, salt=salt, **kwargs) + + def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized: + """Returns a signed string serialized with the internal + serializer. The return value can be either a byte or unicode + string depending on the format of the internal serializer. + """ + payload = want_bytes(self.dump_payload(obj)) + rv = self.make_signer(salt).sign(payload) + + if self.is_text_serializer: + return rv.decode("utf-8") # type: ignore[return-value] + + return rv # type: ignore[return-value] + + def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None: + """Like :meth:`dumps` but dumps into a file. The file handle has + to be compatible with what the internal serializer expects. + """ + f.write(self.dumps(obj, salt)) + + def loads( + self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any + ) -> t.Any: + """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the + signature validation fails. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + return self.load_payload(signer.unsign(s)) + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any: + """Like :meth:`loads` but loads from a file.""" + return self.loads(f.read(), salt) + + def loads_unsafe( + self, s: str | bytes, salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads` but without verifying the signature. This + is potentially very dangerous to use depending on how your + serializer works. The return value is ``(signature_valid, + payload)`` instead of just the payload. The first item will be a + boolean that indicates if the signature is valid. This function + never fails. + + Use it for debugging only and if you know that your serializer + module is not exploitable (for example, do not use it with a + pickle serializer). + + .. versionadded:: 0.15 + """ + return self._loads_unsafe_impl(s, salt) + + def _loads_unsafe_impl( + self, + s: str | bytes, + salt: str | bytes | None, + load_kwargs: dict[str, t.Any] | None = None, + load_payload_kwargs: dict[str, t.Any] | None = None, + ) -> tuple[bool, t.Any]: + """Low level helper function to implement :meth:`loads_unsafe` + in serializer subclasses. + """ + if load_kwargs is None: + load_kwargs = {} + + try: + return True, self.loads(s, salt=salt, **load_kwargs) + except BadSignature as e: + if e.payload is None: + return False, None + + if load_payload_kwargs is None: + load_payload_kwargs = {} + + try: + return ( + False, + self.load_payload(e.payload, **load_payload_kwargs), + ) + except BadPayload: + return False, None + + def load_unsafe( + self, f: t.IO[t.Any], salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads_unsafe` but loads from a file. + + .. versionadded:: 0.15 + """ + return self.loads_unsafe(f.read(), salt=salt) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/signer.py b/venv/lib/python3.12/site-packages/itsdangerous/signer.py new file mode 100644 index 0000000..e324dc0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/signer.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +import collections.abc as cabc +import hashlib +import hmac +import typing as t + +from .encoding import _base64_alphabet +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import want_bytes +from .exc import BadSignature + + +class SigningAlgorithm: + """Subclasses must implement :meth:`get_signature` to provide + signature generation functionality. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + """Returns the signature for the given key and value.""" + raise NotImplementedError() + + def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: + """Verifies the given signature matches the expected + signature. + """ + return hmac.compare_digest(sig, self.get_signature(key, value)) + + +class NoneAlgorithm(SigningAlgorithm): + """Provides an algorithm that does not perform any signing and + returns an empty signature. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + return b"" + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class HMACAlgorithm(SigningAlgorithm): + """Provides signature generation using HMACs.""" + + #: The digest method to use with the MAC algorithm. This defaults to + #: SHA1, but can be changed to any other function in the hashlib + #: module. + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + def __init__(self, digest_method: t.Any = None): + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + def get_signature(self, key: bytes, value: bytes) -> bytes: + mac = hmac.new(key, msg=value, digestmod=self.digest_method) + return mac.digest() + + +def _make_keys_list( + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], +) -> list[bytes]: + if isinstance(secret_key, (str, bytes)): + return [want_bytes(secret_key)] + + return [want_bytes(s) for s in secret_key] # pyright: ignore + + +class Signer: + """A signer securely signs bytes, then unsigns them to verify that + the value hasn't been changed. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param sep: Separator between the signature and value. + :param key_derivation: How to derive the signing key from the secret + key and salt. Possible values are ``concat``, ``django-concat``, + or ``hmac``. Defaults to :attr:`default_key_derivation`, which + defaults to ``django-concat``. + :param digest_method: Hash function to use when generating the HMAC + signature. Defaults to :attr:`default_digest_method`, which + defaults to :func:`hashlib.sha1`. Note that the security of the + hash alone doesn't apply when used intermediately in HMAC. + :param algorithm: A :class:`SigningAlgorithm` instance to use + instead of building a default :class:`HMACAlgorithm` with the + ``digest_method``. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 0.18 + ``algorithm`` was added as an argument to the class constructor. + + .. versionchanged:: 0.14 + ``key_derivation`` and ``digest_method`` were added as arguments + to the class constructor. + """ + + #: The default digest method to use for the signer. The default is + #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or + #: compatible object. Note that the security of the hash alone + #: doesn't apply when used intermediately in HMAC. + #: + #: .. versionadded:: 0.14 + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + #: The default scheme to use to derive the signing key from the + #: secret key and salt. The default is ``django-concat``. Possible + #: values are ``concat``, ``django-concat``, and ``hmac``. + #: + #: .. versionadded:: 0.14 + default_key_derivation: str = "django-concat" + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous.Signer", + sep: str | bytes = b".", + key_derivation: str | None = None, + digest_method: t.Any | None = None, + algorithm: SigningAlgorithm | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + self.sep: bytes = want_bytes(sep) + + if self.sep in _base64_alphabet: + raise ValueError( + "The given separator cannot be used because it may be" + " contained in the signature itself. ASCII letters," + " digits, and '-_=' must not be used." + ) + + if salt is not None: + salt = want_bytes(salt) + else: + salt = b"itsdangerous.Signer" + + self.salt = salt + + if key_derivation is None: + key_derivation = self.default_key_derivation + + self.key_derivation: str = key_derivation + + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + if algorithm is None: + algorithm = HMACAlgorithm(self.digest_method) + + self.algorithm: SigningAlgorithm = algorithm + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def derive_key(self, secret_key: str | bytes | None = None) -> bytes: + """This method is called to derive the key. The default key + derivation choices can be overridden here. Key derivation is not + intended to be used as a security method to make a complex key + out of a short password. Instead you should use large random + secret keys. + + :param secret_key: A specific secret key to derive from. + Defaults to the last item in :attr:`secret_keys`. + + .. versionchanged:: 2.0 + Added the ``secret_key`` parameter. + """ + if secret_key is None: + secret_key = self.secret_keys[-1] + else: + secret_key = want_bytes(secret_key) + + if self.key_derivation == "concat": + return t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) + elif self.key_derivation == "django-concat": + return t.cast( + bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() + ) + elif self.key_derivation == "hmac": + mac = hmac.new(secret_key, digestmod=self.digest_method) + mac.update(self.salt) + return mac.digest() + elif self.key_derivation == "none": + return secret_key + else: + raise TypeError("Unknown key derivation method") + + def get_signature(self, value: str | bytes) -> bytes: + """Returns the signature for the given value.""" + value = want_bytes(value) + key = self.derive_key() + sig = self.algorithm.get_signature(key, value) + return base64_encode(sig) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string.""" + value = want_bytes(value) + return value + self.sep + self.get_signature(value) + + def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool: + """Verifies the signature for the given value.""" + try: + sig = base64_decode(sig) + except Exception: + return False + + value = want_bytes(value) + + for secret_key in reversed(self.secret_keys): + key = self.derive_key(secret_key) + + if self.algorithm.verify_signature(key, value, sig): + return True + + return False + + def unsign(self, signed_value: str | bytes) -> bytes: + """Unsigns the given string.""" + signed_value = want_bytes(signed_value) + + if self.sep not in signed_value: + raise BadSignature(f"No {self.sep!r} found in value") + + value, sig = signed_value.rsplit(self.sep, 1) + + if self.verify_signature(value, sig): + return value + + raise BadSignature(f"Signature {sig!r} does not match", payload=value) + + def validate(self, signed_value: str | bytes) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid. + """ + try: + self.unsign(signed_value) + return True + except BadSignature: + return False diff --git a/venv/lib/python3.12/site-packages/itsdangerous/timed.py b/venv/lib/python3.12/site-packages/itsdangerous/timed.py new file mode 100644 index 0000000..7384375 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/timed.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +import collections.abc as cabc +import time +import typing as t +from datetime import datetime +from datetime import timezone + +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import bytes_to_int +from .encoding import int_to_bytes +from .encoding import want_bytes +from .exc import BadSignature +from .exc import BadTimeSignature +from .exc import SignatureExpired +from .serializer import _TSerialized +from .serializer import Serializer +from .signer import Signer + + +class TimestampSigner(Signer): + """Works like the regular :class:`.Signer` but also records the time + of the signing and can be used to expire signatures. The + :meth:`unsign` method can raise :exc:`.SignatureExpired` if the + unsigning failed because the signature is expired. + """ + + def get_timestamp(self) -> int: + """Returns the current timestamp. The function must return an + integer. + """ + return int(time.time()) + + def timestamp_to_datetime(self, ts: int) -> datetime: + """Convert the timestamp from :meth:`get_timestamp` into an + aware :class`datetime.datetime` in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + return datetime.fromtimestamp(ts, tz=timezone.utc) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string and also attaches time information.""" + value = want_bytes(value) + timestamp = base64_encode(int_to_bytes(self.get_timestamp())) + sep = want_bytes(self.sep) + value = value + sep + timestamp + return value + sep + self.get_signature(value) + + # Ignore overlapping signatures check, return_timestamp is the only + # parameter that affects the return type. + + @t.overload + def unsign( # type: ignore[overload-overlap] + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[False] = False, + ) -> bytes: ... + + @t.overload + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[True] = True, + ) -> tuple[bytes, datetime]: ... + + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + ) -> tuple[bytes, datetime] | bytes: + """Works like the regular :meth:`.Signer.unsign` but can also + validate the time. See the base docstring of the class for + the general behavior. If ``return_timestamp`` is ``True`` the + timestamp of the signature will be returned as an aware + :class:`datetime.datetime` object in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + try: + result = super().unsign(signed_value) + sig_error = None + except BadSignature as e: + sig_error = e + result = e.payload or b"" + + sep = want_bytes(self.sep) + + # If there is no timestamp in the result there is something + # seriously wrong. In case there was a signature error, we raise + # that one directly, otherwise we have a weird situation in + # which we shouldn't have come except someone uses a time-based + # serializer on non-timestamp data, so catch that. + if sep not in result: + if sig_error: + raise sig_error + + raise BadTimeSignature("timestamp missing", payload=result) + + value, ts_bytes = result.rsplit(sep, 1) + ts_int: int | None = None + ts_dt: datetime | None = None + + try: + ts_int = bytes_to_int(base64_decode(ts_bytes)) + except Exception: + pass + + # Signature is *not* okay. Raise a proper error now that we have + # split the value and the timestamp. + if sig_error is not None: + if ts_int is not None: + try: + ts_dt = self.timestamp_to_datetime(ts_int) + except (ValueError, OSError, OverflowError) as exc: + # Windows raises OSError + # 32-bit raises OverflowError + raise BadTimeSignature( + "Malformed timestamp", payload=value + ) from exc + + raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) + + # Signature was okay but the timestamp is actually not there or + # malformed. Should not happen, but we handle it anyway. + if ts_int is None: + raise BadTimeSignature("Malformed timestamp", payload=value) + + # Check timestamp is not older than max_age + if max_age is not None: + age = self.get_timestamp() - ts_int + + if age > max_age: + raise SignatureExpired( + f"Signature age {age} > {max_age} seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if age < 0: + raise SignatureExpired( + f"Signature age {age} < 0 seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if return_timestamp: + return value, self.timestamp_to_datetime(ts_int) + + return value + + def validate(self, signed_value: str | bytes, max_age: int | None = None) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid.""" + try: + self.unsign(signed_value, max_age=max_age) + return True + except BadSignature: + return False + + +class TimedSerializer(Serializer[_TSerialized]): + """Uses :class:`TimestampSigner` instead of the default + :class:`.Signer`. + """ + + default_signer: type[TimestampSigner] = TimestampSigner + + def iter_unsigners( + self, salt: str | bytes | None = None + ) -> cabc.Iterator[TimestampSigner]: + return t.cast("cabc.Iterator[TimestampSigner]", super().iter_unsigners(salt)) + + # TODO: Signature is incompatible because parameters were added + # before salt. + + def loads( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + salt: str | bytes | None = None, + ) -> t.Any: + """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the + signature validation fails. If a ``max_age`` is provided it will + ensure the signature is not older than that time in seconds. In + case the signature is outdated, :exc:`.SignatureExpired` is + raised. All arguments are forwarded to the signer's + :meth:`~TimestampSigner.unsign` method. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + base64d, timestamp = signer.unsign( + s, max_age=max_age, return_timestamp=True + ) + payload = self.load_payload(base64d) + + if return_timestamp: + return payload, timestamp + + return payload + except SignatureExpired: + # The signature was unsigned successfully but was + # expired. Do not try the next signer. + raise + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def loads_unsafe( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + salt: str | bytes | None = None, + ) -> tuple[bool, t.Any]: + return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py new file mode 100644 index 0000000..56a0793 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import typing as t +import zlib + +from ._json import _CompactJSON +from .encoding import base64_decode +from .encoding import base64_encode +from .exc import BadPayload +from .serializer import _PDataSerializer +from .serializer import Serializer +from .timed import TimedSerializer + + +class URLSafeSerializerMixin(Serializer[str]): + """Mixed in with a regular serializer it will attempt to zlib + compress the string to make it shorter if necessary. It will also + base64 encode the string so that it can safely be placed in a URL. + """ + + default_serializer: _PDataSerializer[str] = _CompactJSON + + def load_payload( + self, + payload: bytes, + *args: t.Any, + serializer: t.Any | None = None, + **kwargs: t.Any, + ) -> t.Any: + decompress = False + + if payload.startswith(b"."): + payload = payload[1:] + decompress = True + + try: + json = base64_decode(payload) + except Exception as e: + raise BadPayload( + "Could not base64 decode the payload because of an exception", + original_error=e, + ) from e + + if decompress: + try: + json = zlib.decompress(json) + except Exception as e: + raise BadPayload( + "Could not zlib decompress the payload before decoding the payload", + original_error=e, + ) from e + + return super().load_payload(json, *args, **kwargs) + + def dump_payload(self, obj: t.Any) -> bytes: + json = super().dump_payload(obj) + is_compressed = False + compressed = zlib.compress(json) + + if len(compressed) < (len(json) - 1): + json = compressed + is_compressed = True + + base64d = base64_encode(json) + + if is_compressed: + base64d = b"." + base64d + + return base64d + + +class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): + """Works like :class:`.Serializer` but dumps and loads into a URL + safe string consisting of the upper and lowercase character of the + alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ + + +class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): + """Works like :class:`.TimedSerializer` but dumps and loads into a + URL safe string consisting of the upper and lowercase character of + the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA new file mode 100644 index 0000000..ffef2ff --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA @@ -0,0 +1,84 @@ +Metadata-Version: 2.4 +Name: Jinja2 +Version: 3.1.6 +Summary: A very fast and expressive template engine. +Maintainer-email: Pallets +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: MarkupSafe>=2.0 +Requires-Dist: Babel>=2.7 ; extra == "i18n" +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/jinja/ +Provides-Extra: i18n + +# Jinja + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +## In A Nutshell + +```jinja +{% extends "base.html" %} +{% block title %}Members{% endblock %} +{% block content %} +