From d07585bcfd62f227d88fe8482ebc5178b089ec33 Mon Sep 17 00:00:00 2001 From: noisygrace Date: Sat, 14 Jun 2025 15:43:20 +0100 Subject: [PATCH] =?UTF-8?q?=D0=93=D0=BE=D1=82=D0=BE=D0=B2=D0=B0=D1=8F=20?= =?UTF-8?q?=D0=B4=D0=BE=D0=BC=D0=B0=D1=88=D0=BD=D1=8F=D1=8F=20=D1=80=D0=B0?= =?UTF-8?q?=D0=B1=D0=BE=D1=82=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .DS_Store | Bin 0 -> 6148 bytes for_challenges.py | 21 +- for_dict_challenges.py | 94 +- todo.txt | 3 + 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/pip | 8 + venv/bin/pip3 | 8 + venv/bin/pip3.12 | 8 + venv/bin/python | 1 + venv/bin/python3 | 1 + venv/bin/python3.12 | 1 + .../MarkupSafe-3.0.2.dist-info/INSTALLER | 1 + .../MarkupSafe-3.0.2.dist-info/LICENSE.txt | 28 + .../MarkupSafe-3.0.2.dist-info/METADATA | 92 + .../MarkupSafe-3.0.2.dist-info/RECORD | 14 + .../MarkupSafe-3.0.2.dist-info/WHEEL | 5 + .../MarkupSafe-3.0.2.dist-info/top_level.txt | 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 -> 505 bytes .../__pycache__/_utilities.cpython-312.pyc | Bin 0 -> 2732 bytes .../blinker/__pycache__/base.cpython-312.pyc | Bin 0 -> 22009 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.2.1.dist-info/INSTALLER | 1 + .../click-8.2.1.dist-info/METADATA | 82 + .../click-8.2.1.dist-info/RECORD | 38 + .../site-packages/click-8.2.1.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + .../site-packages/click/__init__.py | 123 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4077 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 24199 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 31538 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2430 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11775 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 127675 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 22142 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14781 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 13677 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 2970 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 20210 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 23177 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 34528 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 26904 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 48964 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 24884 bytes .../python3.12/site-packages/click/_compat.py | 622 ++ .../site-packages/click/_termui_impl.py | 839 ++ .../site-packages/click/_textwrap.py | 51 + .../site-packages/click/_winconsole.py | 296 + .../python3.12/site-packages/click/core.py | 3135 ++++++ .../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 | 644 ++ .../python3.12/site-packages/click/termui.py | 877 ++ .../python3.12/site-packages/click/testing.py | 565 ++ .../python3.12/site-packages/click/types.py | 1165 +++ .../python3.12/site-packages/click/utils.py | 627 ++ .../flask-3.1.1.dist-info/INSTALLER | 1 + .../flask-3.1.1.dist-info/METADATA | 89 + .../flask-3.1.1.dist-info/RECORD | 58 + .../flask-3.1.1.dist-info/REQUESTED | 0 .../site-packages/flask-3.1.1.dist-info/WHEEL | 4 + .../flask-3.1.1.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 -> 2537 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 245 bytes .../flask/__pycache__/app.cpython-312.pyc | Bin 0 -> 62492 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 5004 bytes .../flask/__pycache__/cli.cpython-312.pyc | Bin 0 -> 43548 bytes .../flask/__pycache__/config.cpython-312.pyc | Bin 0 -> 16256 bytes .../flask/__pycache__/ctx.cpython-312.pyc | Bin 0 -> 19842 bytes .../__pycache__/debughelpers.cpython-312.pyc | Bin 0 -> 9154 bytes .../flask/__pycache__/globals.cpython-312.pyc | Bin 0 -> 1869 bytes .../flask/__pycache__/helpers.cpython-312.pyc | Bin 0 -> 25449 bytes .../flask/__pycache__/logging.cpython-312.pyc | Bin 0 -> 3271 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 17186 bytes .../flask/__pycache__/signals.cpython-312.pyc | Bin 0 -> 1226 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9936 bytes .../flask/__pycache__/testing.cpython-312.pyc | Bin 0 -> 13631 bytes .../flask/__pycache__/typing.cpython-312.pyc | Bin 0 -> 4134 bytes .../flask/__pycache__/views.cpython-312.pyc | Bin 0 -> 7025 bytes .../__pycache__/wrappers.cpython-312.pyc | Bin 0 -> 10057 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 | 449 + .../site-packages/flask/debughelpers.py | 178 + .../python3.12/site-packages/flask/globals.py | 51 + .../python3.12/site-packages/flask/helpers.py | 634 ++ .../site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6697 bytes .../json/__pycache__/provider.cpython-312.pyc | Bin 0 -> 9264 bytes .../json/__pycache__/tag.cpython-312.pyc | Bin 0 -> 13959 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 -> 33717 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 31217 bytes .../__pycache__/scaffold.cpython-312.pyc | Bin 0 -> 30230 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 | 399 + .../python3.12/site-packages/flask/signals.py | 17 + .../site-packages/flask/templating.py | 219 + .../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 -> 1636 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 1190 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2690 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 3950 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 15431 bytes .../__pycache__/signer.cpython-312.pyc | Bin 0 -> 11296 bytes .../__pycache__/timed.cpython-312.pyc | Bin 0 -> 8744 bytes .../__pycache__/url_safe.cpython-312.pyc | Bin 0 -> 3540 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 -> 1661 bytes .../__pycache__/_identifier.cpython-312.pyc | Bin 0 -> 2142 bytes .../__pycache__/async_utils.cpython-312.pyc | Bin 0 -> 4982 bytes .../__pycache__/bccache.cpython-312.pyc | Bin 0 -> 19353 bytes .../__pycache__/compiler.cpython-312.pyc | Bin 0 -> 104068 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 1564 bytes .../jinja2/__pycache__/debug.cpython-312.pyc | Bin 0 -> 6589 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1614 bytes .../__pycache__/environment.cpython-312.pyc | Bin 0 -> 76690 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7728 bytes .../jinja2/__pycache__/ext.cpython-312.pyc | Bin 0 -> 41921 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 72338 bytes .../__pycache__/idtracking.cpython-312.pyc | Bin 0 -> 19203 bytes .../jinja2/__pycache__/lexer.cpython-312.pyc | Bin 0 -> 32084 bytes .../__pycache__/loaders.cpython-312.pyc | Bin 0 -> 32363 bytes .../jinja2/__pycache__/meta.cpython-312.pyc | Bin 0 -> 5498 bytes .../__pycache__/nativetypes.cpython-312.pyc | Bin 0 -> 7019 bytes .../jinja2/__pycache__/nodes.cpython-312.pyc | Bin 0 -> 58281 bytes .../__pycache__/optimizer.cpython-312.pyc | Bin 0 -> 2697 bytes .../jinja2/__pycache__/parser.cpython-312.pyc | Bin 0 -> 61211 bytes .../__pycache__/runtime.cpython-312.pyc | Bin 0 -> 48899 bytes .../__pycache__/sandbox.cpython-312.pyc | Bin 0 -> 18115 bytes .../jinja2/__pycache__/tests.cpython-312.pyc | Bin 0 -> 9058 bytes .../jinja2/__pycache__/utils.cpython-312.pyc | Bin 0 -> 34871 bytes .../__pycache__/visitor.cpython-312.pyc | Bin 0 -> 5373 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 + .../site-packages/markupsafe/__init__.py | 395 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 20936 bytes .../__pycache__/_native.cpython-312.pyc | Bin 0 -> 623 bytes .../site-packages/markupsafe/_native.py | 8 + .../site-packages/markupsafe/_speedups.c | 204 + .../_speedups.cpython-312-darwin.so | Bin 0 -> 50624 bytes .../site-packages/markupsafe/_speedups.pyi | 1 + .../site-packages/markupsafe/py.typed | 0 .../pip-25.1.1.dist-info/INSTALLER | 1 + .../pip-25.1.1.dist-info/METADATA | 90 + .../site-packages/pip-25.1.1.dist-info/RECORD | 856 ++ .../pip-25.1.1.dist-info/REQUESTED | 0 .../site-packages/pip-25.1.1.dist-info/WHEEL | 5 + .../pip-25.1.1.dist-info/entry_points.txt | 3 + .../pip-25.1.1.dist-info/licenses/AUTHORS.txt | 821 ++ .../pip-25.1.1.dist-info/licenses/LICENSE.txt | 20 + .../pip-25.1.1.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 -> 700 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 854 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2217 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 800 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14844 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12673 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17678 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 39219 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 683 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 5142 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10430 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13248 bytes .../site-packages/pip/_internal/build_env.py | 325 + .../site-packages/pip/_internal/cache.py | 289 + .../pip/_internal/cli/__init__.py | 3 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 288 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8640 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10282 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 32221 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1794 bytes .../__pycache__/index_command.cpython-312.pyc | Bin 0 -> 7274 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2308 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4913 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15106 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 5764 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 12900 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7853 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 388 bytes .../pip/_internal/cli/autocompletion.py | 175 + .../pip/_internal/cli/base_command.py | 233 + .../pip/_internal/cli/cmdoptions.py | 1133 +++ .../pip/_internal/cli/command_context.py | 27 + .../pip/_internal/cli/index_command.py | 173 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 133 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 144 + .../pip/_internal/cli/req_command.py | 347 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 137 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4139 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9951 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2629 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5473 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13225 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10127 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7521 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4356 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2996 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1686 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 7020 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3989 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 29447 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 16697 bytes .../commands/__pycache__/lock.cpython-312.pyc | Bin 0 -> 8023 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7804 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 11304 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4746 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8810 bytes .../pip/_internal/commands/cache.py | 228 + .../pip/_internal/commands/check.py | 67 + .../pip/_internal/commands/completion.py | 136 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 146 + .../pip/_internal/commands/freeze.py | 108 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 153 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 793 ++ .../pip/_internal/commands/list.py | 391 + .../pip/_internal/commands/lock.py | 171 + .../pip/_internal/commands/search.py | 176 + .../pip/_internal/commands/show.py | 228 + .../pip/_internal/commands/uninstall.py | 114 + .../pip/_internal/commands/wheel.py | 182 + .../pip/_internal/configuration.py | 383 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 954 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2906 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1713 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8495 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2294 bytes .../pip/_internal/distributions/base.py | 53 + .../pip/_internal/distributions/installed.py | 29 + .../pip/_internal/distributions/sdist.py | 158 + .../pip/_internal/distributions/wheel.py | 42 + .../site-packages/pip/_internal/exceptions.py | 862 ++ .../pip/_internal/index/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 242 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21638 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 41411 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12553 bytes .../pip/_internal/index/collector.py | 494 + .../pip/_internal/index/package_finder.py | 1050 ++ .../pip/_internal/index/sources.py | 284 + .../pip/_internal/locations/__init__.py | 439 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 15702 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6808 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8046 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3794 bytes .../pip/_internal/locations/_distutils.py | 172 + .../pip/_internal/locations/_sysconfig.py | 214 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 162 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6698 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2984 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35295 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 16118 bytes .../pip/_internal/metadata/_json.py | 86 + .../pip/_internal/metadata/base.py | 690 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 371 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 4504 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 12900 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 8142 bytes .../_internal/metadata/importlib/_compat.py | 85 + .../_internal/metadata/importlib/_dists.py | 228 + .../pip/_internal/metadata/importlib/_envs.py | 140 + .../pip/_internal/metadata/pkg_resources.py | 301 + .../pip/_internal/models/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 276 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1617 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 10850 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4240 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1707 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2285 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 27129 bytes .../models/__pycache__/pylock.cpython-312.pyc | Bin 0 -> 8059 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1036 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 5009 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1864 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4967 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 7520 bytes .../pip/_internal/models/candidate.py | 25 + .../pip/_internal/models/direct_url.py | 224 + .../pip/_internal/models/format_control.py | 78 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 56 + .../pip/_internal/models/link.py | 608 ++ .../pip/_internal/models/pylock.py | 183 + .../pip/_internal/models/scheme.py | 25 + .../pip/_internal/models/search_scope.py | 127 + .../pip/_internal/models/selection_prefs.py | 53 + .../pip/_internal/models/target_python.py | 121 + .../pip/_internal/models/wheel.py | 139 + .../pip/_internal/network/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 264 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 22121 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 7125 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 12656 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11676 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18927 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2273 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2957 bytes .../pip/_internal/network/auth.py | 566 ++ .../pip/_internal/network/cache.py | 117 + .../pip/_internal/network/download.py | 314 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 523 + .../pip/_internal/network/utils.py | 98 + .../pip/_internal/network/xmlrpc.py | 61 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 210 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7161 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10314 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 26001 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 216 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7732 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1888 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1942 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3035 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1697 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2038 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 4383 bytes .../operations/build/build_tracker.py | 138 + .../_internal/operations/build/metadata.py | 38 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 73 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 118 + .../pip/_internal/operations/check.py | 180 + .../pip/_internal/operations/freeze.py | 256 + .../_internal/operations/install/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 276 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1827 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 34223 bytes .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 738 ++ .../pip/_internal/operations/prepare.py | 737 ++ .../site-packages/pip/_internal/pyproject.py | 185 + .../pip/_internal/req/__init__.py | 103 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4037 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21289 bytes .../req_dependency_group.cpython-312.pyc | Bin 0 -> 4121 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 24310 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38552 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 5488 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 32266 bytes .../pip/_internal/req/constructors.py | 560 ++ .../pip/_internal/req/req_dependency_group.py | 79 + .../pip/_internal/req/req_file.py | 623 ++ .../pip/_internal/req/req_install.py | 934 ++ .../pip/_internal/req/req_set.py | 82 + .../pip/_internal/req/req_uninstall.py | 636 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 210 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1198 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 217 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22630 bytes .../_internal/resolution/legacy/resolver.py | 597 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 221 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8161 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 29702 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32596 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6783 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 11324 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 5153 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 15363 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12523 bytes .../_internal/resolution/resolvelib/base.py | 139 + .../resolution/resolvelib/candidates.py | 579 ++ .../resolution/resolvelib/factory.py | 823 ++ .../resolution/resolvelib/found_candidates.py | 164 + .../resolution/resolvelib/provider.py | 281 + .../resolution/resolvelib/reporter.py | 83 + .../resolution/resolvelib/requirements.py | 245 + .../resolution/resolvelib/resolver.py | 320 + .../pip/_internal/self_outdated_check.py | 252 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4545 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1876 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2495 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2917 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 6896 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 689 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4200 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3546 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3236 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 4111 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7362 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1169 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2429 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7659 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 14214 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 33244 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 1917 bytes .../utils/__pycache__/retry.cpython-312.pyc | Bin 0 -> 2118 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4607 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8674 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12072 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 13519 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2087 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4490 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5904 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 53 + .../pip/_internal/utils/compat.py | 79 + .../pip/_internal/utils/compatibility_tags.py | 200 + .../pip/_internal/utils/datetime.py | 10 + .../pip/_internal/utils/deprecation.py | 124 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/entrypoints.py | 87 + .../pip/_internal/utils/filesystem.py | 149 + .../pip/_internal/utils/filetypes.py | 26 + .../pip/_internal/utils/glibc.py | 101 + .../pip/_internal/utils/hashes.py | 147 + .../pip/_internal/utils/logging.py | 361 + .../site-packages/pip/_internal/utils/misc.py | 773 ++ .../pip/_internal/utils/packaging.py | 43 + .../pip/_internal/utils/retry.py | 42 + .../pip/_internal/utils/setuptools_build.py | 147 + .../pip/_internal/utils/subprocess.py | 245 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 335 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 133 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 544 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5074 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19631 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7625 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12538 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29021 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 536 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 688 ++ .../pip/_internal/wheel_builder.py | 332 + .../site-packages/pip/_vendor/__init__.py | 117 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4607 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 173535 bytes .../pip/_vendor/cachecontrol/__init__.py | 29 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 916 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2660 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6725 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3823 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16467 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4361 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6711 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 5279 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1688 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 168 + .../pip/_vendor/cachecontrol/cache.py | 75 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 449 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7066 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2752 bytes .../_vendor/cachecontrol/caches/file_cache.py | 145 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 511 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 157 + .../pip/_vendor/cachecontrol/py.typed | 0 .../pip/_vendor/cachecontrol/serialize.py | 146 + .../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 -> 332 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 659 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3234 bytes .../pip/_vendor/certifi/cacert.pem | 4897 ++++++++++ .../site-packages/pip/_vendor/certifi/core.py | 114 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/dependency_groups/__init__.py | 13 + .../pip/_vendor/dependency_groups/__main__.py | 65 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 391 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 2713 bytes .../_implementation.cpython-312.pyc | Bin 0 -> 9665 bytes .../_lint_dependency_groups.cpython-312.pyc | Bin 0 -> 2878 bytes .../__pycache__/_pip_wrapper.cpython-312.pyc | Bin 0 -> 3445 bytes .../__pycache__/_toml_compat.cpython-312.pyc | Bin 0 -> 492 bytes .../dependency_groups/_implementation.py | 209 + .../_lint_dependency_groups.py | 59 + .../_vendor/dependency_groups/_pip_wrapper.py | 62 + .../_vendor/dependency_groups/_toml_compat.py | 9 + .../pip/_vendor/dependency_groups/py.typed | 0 .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1283 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45614 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 65939 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24380 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 60103 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15139 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7672 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41711 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17339 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19790 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88288 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30379 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 52969 bytes .../pip/_vendor/distlib/compat.py | 1137 +++ .../pip/_vendor/distlib/database.py | 1329 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1295 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 162 + .../pip/_vendor/distlib/metadata.py | 1031 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 447 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 97792 bytes .../pip/_vendor/distlib/t64-arm.exe | Bin 0 -> 182784 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 108032 bytes .../site-packages/pip/_vendor/distlib/util.py | 1984 ++++ .../pip/_vendor/distlib/version.py | 750 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 91648 bytes .../pip/_vendor/distlib/w64-arm.exe | Bin 0 -> 168448 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 101888 bytes .../pip/_vendor/distlib/wheel.py | 1100 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 974 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 306 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53859 bytes .../pip/_vendor/distro/distro.py | 1403 +++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 45 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 900 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 5000 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 904 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16190 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99490 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2652 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 231 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158860 bytes .../site-packages/pip/_vendor/idna/codec.py | 122 + .../site-packages/pip/_vendor/idna/compat.py | 15 + .../site-packages/pip/_vendor/idna/core.py | 437 + .../pip/_vendor/idna/idnadata.py | 4243 ++++++++ .../pip/_vendor/idna/intranges.py | 57 + .../pip/_vendor/idna/package_data.py | 1 + .../site-packages/pip/_vendor/idna/py.typed | 0 .../pip/_vendor/idna/uts46data.py | 8681 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1753 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2039 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8307 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 41533 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 170 + .../pip/_vendor/msgpack/fallback.py | 929 ++ .../pip/_vendor/packaging/__init__.py | 15 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 572 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 5037 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9765 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4583 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 14012 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3255 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7962 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 12779 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 27264 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4424 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 39078 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 24830 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 6649 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 20494 bytes .../pip/_vendor/packaging/_elffile.py | 109 + .../pip/_vendor/packaging/_manylinux.py | 262 + .../pip/_vendor/packaging/_musllinux.py | 85 + .../pip/_vendor/packaging/_parser.py | 353 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/_tokenizer.py | 195 + .../_vendor/packaging/licenses/__init__.py | 145 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4143 bytes .../__pycache__/_spdx.cpython-312.pyc | Bin 0 -> 47378 bytes .../pip/_vendor/packaging/licenses/_spdx.py | 759 ++ .../pip/_vendor/packaging/markers.py | 362 + .../pip/_vendor/packaging/metadata.py | 862 ++ .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 91 + .../pip/_vendor/packaging/specifiers.py | 1019 ++ .../pip/_vendor/packaging/tags.py | 656 ++ .../pip/_vendor/packaging/utils.py | 163 + .../pip/_vendor/packaging/version.py | 582 ++ .../pip/_vendor/pkg_resources/__init__.py | 3676 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161539 bytes .../pip/_vendor/platformdirs/__init__.py | 631 ++ .../pip/_vendor/platformdirs/__main__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 19861 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1982 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 10709 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 13368 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 8838 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 14760 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 670 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13687 bytes .../pip/_vendor/platformdirs/android.py | 249 + .../pip/_vendor/platformdirs/api.py | 299 + .../pip/_vendor/platformdirs/macos.py | 144 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 272 + .../pip/_vendor/platformdirs/version.py | 21 + .../pip/_vendor/platformdirs/windows.py | 272 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3503 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 749 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2648 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3241 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4735 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38480 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1584 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 2643 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4096 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4771 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 12156 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6732 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8209 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 33026 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 14098 bytes .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 70 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37994 bytes .../pip/_vendor/pygments/formatter.py | 129 + .../_vendor/pygments/formatters/__init__.py | 157 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6968 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4230 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/lexer.py | 963 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14750 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 69859 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42989 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 602 ++ .../pip/_vendor/pygments/lexers/python.py | 1201 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 72 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 247 + .../pip/_vendor/pygments/style.py | 203 + .../pip/_vendor/pygments/styles/__init__.py | 61 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2686 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 3663 bytes .../pip/_vendor/pygments/styles/_mapping.py | 54 + .../pip/_vendor/pygments/token.py | 214 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 324 + .../pip/_vendor/pyproject_hooks/__init__.py | 31 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 762 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 18094 bytes .../pip/_vendor/pyproject_hooks/_impl.py | 410 + .../pyproject_hooks/_in_process/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1091 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 15373 bytes .../_in_process/_in_process.py | 389 + .../pip/_vendor/pyproject_hooks/py.typed | 0 .../pip/_vendor/requests/__init__.py | 179 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5268 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 599 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2039 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28452 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7219 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13938 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 693 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1692 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25291 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7613 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4243 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1067 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35493 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1302 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27897 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6046 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5632 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36457 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 719 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 314 + .../pip/_vendor/requests/certs.py | 17 + .../pip/_vendor/requests/compat.py | 78 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 151 + .../pip/_vendor/requests/help.py | 127 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1037 ++ .../pip/_vendor/requests/packages.py | 25 + .../pip/_vendor/requests/sessions.py | 831 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1096 +++ .../pip/_vendor/resolvelib/__init__.py | 27 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 649 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 10138 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 3305 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 12465 bytes .../pip/_vendor/resolvelib/providers.py | 196 + .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 55 + .../_vendor/resolvelib/resolvers/__init__.py | 27 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 754 bytes .../__pycache__/abstract.cpython-312.pyc | Bin 0 -> 2484 bytes .../__pycache__/criterion.cpython-312.pyc | Bin 0 -> 3285 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 4095 bytes .../__pycache__/resolution.cpython-312.pyc | Bin 0 -> 22826 bytes .../_vendor/resolvelib/resolvers/abstract.py | 47 + .../_vendor/resolvelib/resolvers/criterion.py | 48 + .../resolvelib/resolvers/exceptions.py | 57 + .../resolvelib/resolvers/resolution.py | 541 + .../pip/_vendor/resolvelib/structs.py | 209 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 273 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7030 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10319 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7887 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205991 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1744 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2364 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 552 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 870 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12041 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4162 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1900 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3644 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5175 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 741 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6592 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13194 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 980 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 880 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28826 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2505 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3588 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 3351 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1623 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12441 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9136 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4287 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11873 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5593 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26568 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1716 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8602 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 115038 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2273 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9246 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10944 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10543 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1518 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4224 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1860 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3592 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3072 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9915 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6050 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5224 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20235 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19157 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4909 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 14079 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9605 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6391 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 6958 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1835 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5329 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12780 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40648 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 75933 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10404 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 16012 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1807 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 582 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6639 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6583 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3845 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2499 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28598 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6105 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6083 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33496 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2154 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 40228 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43897 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3363 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 61269 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6347 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 329 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 35943 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11811 bytes .../pip/_vendor/rich/_cell_widths.py | 454 + .../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 | 268 + .../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 | 159 + .../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 | 661 ++ .../pip/_vendor/rich/_windows.py | 71 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 93 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 312 + .../site-packages/pip/_vendor/rich/ansi.py | 241 + .../site-packages/pip/_vendor/rich/bar.py | 93 + .../site-packages/pip/_vendor/rich/box.py | 480 + .../site-packages/pip/_vendor/rich/cells.py | 174 + .../site-packages/pip/_vendor/rich/color.py | 621 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2675 +++++ .../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 | 193 + .../pip/_vendor/rich/diagnose.py | 38 + .../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 | 88 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 139 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 442 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 112 + .../site-packages/pip/_vendor/rich/logging.py | 297 + .../site-packages/pip/_vendor/rich/markup.py | 251 + .../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 | 318 + .../site-packages/pip/_vendor/rich/pretty.py | 1016 ++ .../pip/_vendor/rich/progress.py | 1715 ++++ .../pip/_vendor/rich/progress_bar.py | 223 + .../site-packages/pip/_vendor/rich/prompt.py | 400 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/py.typed | 0 .../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 | 752 ++ .../site-packages/pip/_vendor/rich/spinner.py | 138 + .../site-packages/pip/_vendor/rich/status.py | 131 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 966 ++ .../site-packages/pip/_vendor/rich/table.py | 1006 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1361 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 884 ++ .../site-packages/pip/_vendor/rich/tree.py | 257 + .../pip/_vendor/tomli/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 353 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 29395 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 4054 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 381 bytes .../pip/_vendor/tomli/_parser.py | 770 ++ .../site-packages/pip/_vendor/tomli/_re.py | 112 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../site-packages/pip/_vendor/tomli/py.typed | 1 + .../pip/_vendor/tomli_w/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 342 bytes .../__pycache__/_writer.cpython-312.pyc | Bin 0 -> 10384 bytes .../pip/_vendor/tomli_w/_writer.py | 229 + .../pip/_vendor/tomli_w/py.typed | 1 + .../pip/_vendor/truststore/__init__.py | 36 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1467 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 17178 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 19007 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2230 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1114 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15790 bytes .../pip/_vendor/truststore/_api.py | 333 + .../pip/_vendor/truststore/_macos.py | 571 ++ .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 567 ++ .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/typing_extensions.py | 4584 +++++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3420 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 16503 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 233 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20422 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36558 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13508 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10428 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4033 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20487 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7309 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33983 bytes .../pip/_vendor/urllib3/_collections.py | 355 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1140 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 213 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1863 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11579 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5734 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24465 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35568 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7526 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 230 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17442 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14816 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 | 920 ++ .../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 -> 214 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41334 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 224 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1840 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7346 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 | 540 + .../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 -> 1161 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4771 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1567 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1367 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4198 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 3004 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21733 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15392 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5086 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10787 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11154 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15810 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4418 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 | 504 + .../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 | 20 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../werkzeug-3.1.3.dist-info/INSTALLER | 1 + .../werkzeug-3.1.3.dist-info/LICENSE.txt | 28 + .../werkzeug-3.1.3.dist-info/METADATA | 99 + .../werkzeug-3.1.3.dist-info/RECORD | 116 + .../werkzeug-3.1.3.dist-info/WHEEL | 4 + .../site-packages/werkzeug/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 348 bytes .../__pycache__/_internal.cpython-312.pyc | Bin 0 -> 9768 bytes .../__pycache__/_reloader.cpython-312.pyc | Bin 0 -> 20619 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33334 bytes .../__pycache__/formparser.cpython-312.pyc | Bin 0 -> 17034 bytes .../werkzeug/__pycache__/http.cpython-312.pyc | Bin 0 -> 50259 bytes .../__pycache__/local.cpython-312.pyc | Bin 0 -> 28489 bytes .../__pycache__/security.cpython-312.pyc | Bin 0 -> 7142 bytes .../__pycache__/serving.cpython-312.pyc | Bin 0 -> 46136 bytes .../werkzeug/__pycache__/test.cpython-312.pyc | Bin 0 -> 59878 bytes .../__pycache__/testapp.cpython-312.pyc | Bin 0 -> 8899 bytes .../werkzeug/__pycache__/urls.cpython-312.pyc | Bin 0 -> 8278 bytes .../__pycache__/user_agent.cpython-312.pyc | Bin 0 -> 2161 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 28152 bytes .../werkzeug/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 25224 bytes .../site-packages/werkzeug/_internal.py | 211 + .../site-packages/werkzeug/_reloader.py | 471 + .../werkzeug/datastructures/__init__.py | 64 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2425 bytes .../__pycache__/accept.cpython-312.pyc | Bin 0 -> 15952 bytes .../__pycache__/auth.cpython-312.pyc | Bin 0 -> 14467 bytes .../__pycache__/cache_control.cpython-312.pyc | Bin 0 -> 12234 bytes .../__pycache__/csp.cpython-312.pyc | Bin 0 -> 6195 bytes .../__pycache__/etag.cpython-312.pyc | Bin 0 -> 5410 bytes .../__pycache__/file_storage.cpython-312.pyc | Bin 0 -> 8832 bytes .../__pycache__/headers.cpython-312.pyc | Bin 0 -> 30528 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 16408 bytes .../__pycache__/range.cpython-312.pyc | Bin 0 -> 10063 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 59099 bytes .../werkzeug/datastructures/accept.py | 350 + .../werkzeug/datastructures/auth.py | 317 + .../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 | 565 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 23484 bytes .../debug/__pycache__/console.cpython-312.pyc | Bin 0 -> 11645 bytes .../debug/__pycache__/repr.cpython-312.pyc | Bin 0 -> 13818 bytes .../debug/__pycache__/tbtools.cpython-312.pyc | Bin 0 -> 17017 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 | 450 + .../site-packages/werkzeug/exceptions.py | 894 ++ .../site-packages/werkzeug/formparser.py | 430 + .../python3.12/site-packages/werkzeug/http.py | 1405 +++ .../site-packages/werkzeug/local.py | 653 ++ .../werkzeug/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 205 bytes .../__pycache__/dispatcher.cpython-312.pyc | Bin 0 -> 3323 bytes .../__pycache__/http_proxy.cpython-312.pyc | Bin 0 -> 9415 bytes .../__pycache__/lint.cpython-312.pyc | Bin 0 -> 17785 bytes .../__pycache__/profiler.cpython-312.pyc | Bin 0 -> 7209 bytes .../__pycache__/proxy_fix.cpython-312.pyc | Bin 0 -> 7206 bytes .../__pycache__/shared_data.cpython-312.pyc | Bin 0 -> 12761 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 -> 4678 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 10918 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7921 bytes .../routing/__pycache__/map.cpython-312.pyc | Bin 0 -> 39846 bytes .../__pycache__/matcher.cpython-312.pyc | Bin 0 -> 8289 bytes .../routing/__pycache__/rules.cpython-312.pyc | Bin 0 -> 39180 bytes .../werkzeug/routing/converters.py | 261 + .../werkzeug/routing/exceptions.py | 152 + .../site-packages/werkzeug/routing/map.py | 951 ++ .../site-packages/werkzeug/routing/matcher.py | 202 + .../site-packages/werkzeug/routing/rules.py | 928 ++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 201 bytes .../sansio/__pycache__/http.cpython-312.pyc | Bin 0 -> 5652 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 14060 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 21894 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 31749 bytes .../sansio/__pycache__/utils.cpython-312.pyc | Bin 0 -> 6191 bytes .../site-packages/werkzeug/sansio/http.py | 170 + .../werkzeug/sansio/multipart.py | 323 + .../site-packages/werkzeug/sansio/request.py | 534 + .../site-packages/werkzeug/sansio/response.py | 763 ++ .../site-packages/werkzeug/sansio/utils.py | 167 + .../site-packages/werkzeug/security.py | 166 + .../site-packages/werkzeug/serving.py | 1125 +++ .../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 | 691 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 325 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 26155 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34580 bytes .../werkzeug/wrappers/request.py | 650 ++ .../werkzeug/wrappers/response.py | 831 ++ .../python3.12/site-packages/werkzeug/wsgi.py | 595 ++ venv/pyvenv.cfg | 5 + 1185 files changed, 198116 insertions(+), 10 deletions(-) create mode 100644 .DS_Store create mode 100644 todo.txt 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/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/MarkupSafe-3.0.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt 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.2.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.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__/_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/_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.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.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/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-darwin.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-25.1.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/licenses/AUTHORS.txt create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/pip-25.1.1.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__/index_command.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/index_command.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__/lock.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/lock.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__/pylock.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/pylock.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_dependency_group.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_dependency_group.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__/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__/packaging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.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/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/packaging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/retry.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__/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/py.typed 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/certifi/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/_implementation.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/_lint_dependency_groups.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/_pip_wrapper.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/__pycache__/_toml_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/_implementation.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/_lint_dependency_groups.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/_pip_wrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/_toml_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/dependency_groups/py.typed 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/t32.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/t64-arm.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/t64.exe 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/w32.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/w64-arm.exe create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/w64.exe 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/distro/py.typed 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/py.typed 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/__init__.py 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__/_elffile.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__/_parser.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__/_tokenizer.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__/metadata.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/_elffile.py 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/_parser.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/_tokenizer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/licenses/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/licenses/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/licenses/__pycache__/_spdx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/licenses/_spdx.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/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/py.typed 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/py.typed 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__/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/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/_mapping.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/styles/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/_mapping.py 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/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__/_impl.cpython-312.pyc 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/pyproject_hooks/py.typed 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__/structs.cpython-312.pyc 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/py.typed 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/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/__pycache__/abstract.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/__pycache__/criterion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/__pycache__/resolution.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/abstract.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/criterion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers/resolution.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/py.typed 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/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/tomli/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli_w/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli_w/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli_w/__pycache__/_writer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli_w/_writer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli_w/py.typed 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/truststore/py.typed 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/py.typed create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/WHEEL 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 100644 venv/pyvenv.cfg diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000000000000000000000000000000000000..5008ddfcf53c02e82d7eee2e57c38e5672ef89f6 GIT binary patch literal 6148 zcmeH~Jr2S!425mzP>H1@V-^m;4Wg<&0T*E43hX&L&p$$qDprKhvt+--jT7}7np#A3 zem<@ulZcFPQ@L2!n>{z**++&mCkOWA81W14cNZlEfg7;MkzE(HCqgga^y>{tEnwC%0;vJ&^%eQ zLs35+`xjp>T0 max_count: + max_name = name + max_count = counts[name] + + print(f'Самое частое имя: {max_name} ({max_count})') + +find_most_common_name(counts) # Задание 3 @@ -51,8 +77,26 @@ {'first_name': 'Саша'}, ], ] -# ??? +for i in range(len(school_students)): + class_students = school_students[i] + name_counts = {} + + for student in class_students: + name = student['first_name'] + if name in name_counts: + name_counts[name] += 1 + else: + name_counts[name] = 1 + + most_common_name = '' + max_count = 0 + for name in name_counts: + if name_counts[name] > max_count: + max_count = name_counts[name] + most_common_name = name + + print(f'Самое частое имя в классе {i + 1}: {most_common_name}') # Задание 4 # Для каждого класса нужно вывести количество девочек и мальчиков в нём. @@ -72,7 +116,20 @@ 'Миша': True, 'Даша': False, } -# ??? +for class_info in school: + class_name = class_info['class'] + students = class_info['students'] + boys = 0 + girls = 0 + + for student in students: + name = student['first_name'] + if is_male[name]: + boys += 1 + else: + girls += 1 + + print(f'Класс {class_name}: девочки {girls}, мальчики {boys}') # Задание 5 @@ -91,5 +148,32 @@ 'Олег': True, 'Миша': True, } -# ??? + +max_boys = 0 +class_with_most_boys = '' +max_girls = 0 +class_with_most_girls = '' + +for class_info in school: + class_name = class_info['class'] + boys = 0 + girls = 0 + + for student in class_info['students']: + name = student['first_name'] + if is_male[name]: + boys += 1 + else: + girls += 1 + + if boys > max_boys: + max_boys = boys + class_with_most_boys = class_name + + if girls > max_girls: + max_girls = girls + class_with_most_girls = class_name + +print(f'Больше всего мальчиков в классе {class_with_most_boys}') +print(f'Больше всего девочек в классе {class_with_most_girls}') diff --git a/todo.txt b/todo.txt new file mode 100644 index 00000000..b9de96f3 --- /dev/null +++ b/todo.txt @@ -0,0 +1,3 @@ +buy bread +learn python +take a walk diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 00000000..b49d77ba --- /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 00000000..9a71ebe7 --- /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 "/Users/ilyapolyak/Projects/basic_exercises/venv") +else + # use the path as-is + export VIRTUAL_ENV="/Users/ilyapolyak/Projects/basic_exercises/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 00000000..d9679f16 --- /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 "/Users/ilyapolyak/Projects/basic_exercises/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 00000000..e42aaeeb --- /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 "/Users/ilyapolyak/Projects/basic_exercises/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 00000000..63dad478 --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,8 @@ +#!/Users/ilyapolyak/Projects/basic_exercises/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/pip b/venv/bin/pip new file mode 100755 index 00000000..2d67490c --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/Users/ilyapolyak/Projects/basic_exercises/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 00000000..2d67490c --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/Users/ilyapolyak/Projects/basic_exercises/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 00000000..2d67490c --- /dev/null +++ b/venv/bin/pip3.12 @@ -0,0 +1,8 @@ +#!/Users/ilyapolyak/Projects/basic_exercises/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 00000000..b8a0adbb --- /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 00000000..72a9981a --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/Users/ilyapolyak/.pyenv/versions/3.12.3/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 00000000..b8a0adbb --- /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/MarkupSafe-3.0.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt new file mode 100644 index 00000000..9d227a0c --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/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/MarkupSafe-3.0.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA new file mode 100644 index 00000000..82261f2a --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA @@ -0,0 +1,92 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 3.0.2 +Summary: Safely add untrusted strings to HTML/XML markup. +Maintainer-email: Pallets +License: 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. + +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source, https://github.com/pallets/markupsafe/ +Project-URL: Chat, https://discord.gg/pallets +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 +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE.txt + +# MarkupSafe + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +## Examples + +```pycon +>>> from markupsafe import Markup, escape + +>>> # escape replaces special characters and wraps in Markup +>>> escape("") +Markup('<script>alert(document.cookie);</script>') + +>>> # wrap in Markup to mark text "safe" and prevent escaping +>>> Markup("Hello") +Markup('hello') + +>>> escape(Markup("Hello")) +Markup('hello') + +>>> # Markup is a str subclass +>>> # methods and operators escape their arguments +>>> template = Markup("Hello {name}") +>>> template.format(name='"World"') +Markup('Hello "World"') +``` + +## Donate + +The Pallets organization develops and supports MarkupSafe 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/MarkupSafe-3.0.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD new file mode 100644 index 00000000..6393e1d6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-3.0.2.dist-info/METADATA,sha256=aAwbZhSmXdfFuMM-rEHpeiHRkBOGESyVLJIuwzHP-nw,3975 +MarkupSafe-3.0.2.dist-info/RECORD,, +MarkupSafe-3.0.2.dist-info/WHEEL,sha256=T94HOVPNbYE6jyG6QmiIglWJ01nwJvHIWFgubY8hhjc,109 +MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=sr-U6_27DfaSrj5jnHYxWN-pvhM27sjlDplMDPZKm7k,13214 +markupsafe/__pycache__/__init__.cpython-312.pyc,, +markupsafe/__pycache__/_native.cpython-312.pyc,, +markupsafe/_native.py,sha256=hSLs8Jmz5aqayuengJJ3kdT5PwNpBWpKrmQSdipndC8,210 +markupsafe/_speedups.c,sha256=O7XulmTo-epI6n2FtMVOrJXl8EAaIwD2iNYmBI5SEoQ,4149 +markupsafe/_speedups.cpython-312-darwin.so,sha256=LAX7ul6PQsfO_zZxF631eSzN6U7PoGVTR_Wwd2pGav8,50624 +markupsafe/_speedups.pyi,sha256=ENd1bYe7gbBUf2ywyYWOGUpnXOHNJ-cgTNqetlW8h5k,41 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL new file mode 100644 index 00000000..edd13a08 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.2.0) +Root-Is-Purelib: false +Tag: cp312-cp312-macosx_11_0_arm64 + diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt new file mode 100644 index 00000000..75bf7292 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe 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 00000000..a1b589e3 --- /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 00000000..79c9825a --- /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 00000000..6d343f57 --- /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 00000000..7cfb7148 --- /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 00000000..e3c6feef --- /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 00000000..1772fa4a --- /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..e96ee0824a11465bf706c70699847e79189eb194 GIT binary patch literal 505 zcmaKozfS@&6vtn==u7kM=e@okZ9nSuDxi56x5Fy}@adebl{P?D9fVg%AR!9IBqjus zQsSx7*o(b_ePloO3oav<<8r|Pau5dvhsa?Z791f*aYSGMN#%{im3g&UTe@*gvZ!&b z(~M^_)pm(@axw3w{fJv55q&;Y8Pj|$?1cA(%WtET+{=OH3f+oxw`aj$IIx?9z?8A2 z37mvZA}19m?kC#K>Y~b6f0|8=V9a67SXmSQ{EW8ztup0vW!nb0$;WS36n*)Y}Tt&FjkrI*m`VAd}I CtbkGg literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc b/venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6d8a31ac5f603cb38f2aeacc1d58f89d1ab1b7c6 GIT binary patch literal 2732 zcmb7G-)j^{9G|(}yWRVdyO^lan&|q2nv?X-RA`}wv|>R88`?%&xHN3`cIVrL?MAu1QBg!d;9R`vlG36!&M;_K_`$CTR@I>Bhr#}ISEH!Pzz}% z>7<@?)9}s@7>;(9X9iA0ZC7kg3 zX<#nFhY?i34k|>>!Uq-<7Zp?|LZXf`0(wVpq7ru0g;XKt#GNPr(Ev~kW*q=&Fvpwd zA}%DxQ8pFC#%puMvRD7*m|+7TZu#6`QZ!`vu1%=H&sn}PHB~Oo5StHXr>1ho$D~3m zP8`FwJdYWa@GAAekR%Kk%$g&HE6=h?E+J*3qoYRnron@ya`|A^aM@;oG&@79;Tiw3 zmulE4=lTH89rrB8KC$S89xtN?ZlD>d z+Dy(Pnt8dVfp>!GIN}@UE-DRlC5})7-Dsu67m-HfRl7xe8j*2y9gk%d3foW+Wz`Cy zfo7UMxnP=EHBfAi1*#8D3>0vB5I0R*e5+|Pk>B9p`DexaSw<+!yI#$zl!46VKcr<5 zAeJv$%(YE&kx<)Zgyqi@|9swai}^|olFL7m8-6p-Tu$DoSoW+n4HiYu^=Apqn^o?5 zE_VsbRcf>gURFd~9Y-M4$U3vPwq>^-oWI&eST zyEwgAUa{BG`HVAf&fA%uW?~(VK%1f?JSwBp156kjQy9rnLo^A@ zbxbobWg~&gh*y#eCN>%d725*cG+p22rdiKy;0^@_sF`p$;NH5Usa}cGURc?!paBb+ z0gr_68ZZFirO7cKLZREh2JndPz{JMq2q>x0O$b84eqosc0thm_-_;gttNM=r0MQSo zuL4oRoiM0K%1#hz)0`$8^2wspkT&&g8_wtyzbL7GAA*WP<08`L!VndawJ%WG+%7M!wenqh%tOtYh5f>h)s?Gr@Ai3&djU9B3iiRVEPVY&sR z(k1W7%#he65fNZnAWy$R4 z91X<9C(6M^bmb^T+P4#h<^=W~7~1E+b%5(rCkQtz1MY#M2Tj}|K6gtl+ybRC1vw=) zanHjNR*d)#fv(HTMv)j*2G@bbz((}r1av85mehou>x%;k&q-lc4>Y(ND$uF|-DPv( zg%@!hks76{4{;ZqsBe)ZE^A*TGPeT7^*MyM8@{SD z_)`6rw(kKL_cjx-CzWp6m*1Wr3(K`LzM>;5;!^nxnE#Olsm=&Aa638>84V7SqX8Gx zbGdAQP<;nMM+XHFA*AB{P;kN@fi7<2A~f~QJyE&_{xRq<7>&TggoEbMT`k?=nY)>t zEBjY2u4M*S^}+kebdxQeTuTnDssrtYAm0%Se*^~MG$ODPXsYutGNDjfO()@fFCIFox&&5JArnlRw3|@5F!#aBojn>;yMZoTU;E^ z^pUU^jZ)ztQOfKcAP*Fb@jbNfFSP3pO5Z^}_fX$GwEGXWYyQ}!Q(v8G+Fy^&<0r9Q Uxc?ynvObc*y^jy5c(*+JABVwWlK=n! literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc b/venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c32ed41738b1b3efec37abcb45078276874ac2d8 GIT binary patch literal 22009 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�Xwt1|Fo*u@1I5^(ikr^KuTuMy1z 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 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 00000000..d051b94a --- /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 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA new file mode 100644 index 00000000..e6c05af4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA @@ -0,0 +1,82 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.2.1 +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.2.1.dist-info/RECORD b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD new file mode 100644 index 00000000..61f4cd2b --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD @@ -0,0 +1,38 @@ +click-8.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.2.1.dist-info/METADATA,sha256=dI1MbhHTLoKD2tNCCGnx9rK2gok23HDNylFeLKdLSik,2471 +click-8.2.1.dist-info/RECORD,, +click-8.2.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.2.1.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__/_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=ASXhLi9IQIc0Js9KQSS-3-SLZcPet3VqysBf9WgbbpI,26712 +click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 +click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 +click/core.py,sha256=gUhpNS9cFBGdEXXdisGVG-eRvGf49RTyFagxulqwdFw,117343 +click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 +click/exceptions.py,sha256=1rdtXgHJ1b3OjGkN-UpXB9t_HCBihJvh_DtpmLmwn9s,9891 +click/formatting.py,sha256=Bhqx4QXdKQ9W4WKknIwj5KPKFmtduGOuGq1yw_THLZ8,9726 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=nU1Ah2p11q29ul1vNdU9swPo_PUuKrxU6YXToi71q1c,18979 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=CQSGdjgun4ORbOZrXP0CVhEtPx4knsufOkRsDiK64cM,19857 +click/termui.py,sha256=vAYrKC2a7f_NfEIhAThEVYfa__ib5XQbTSCGtJlABRA,30847 +click/testing.py,sha256=2eLdAaCJCGToP5Tw-XN8JjrDb3wbJIfARxg3d0crW5M,18702 +click/types.py,sha256=KBTRxN28cR1VZ5mb9iJX98MQSw_p9SGzljqfEI8z5Tw,38389 +click/utils.py,sha256=b1Mm-usEDBHtEwcPltPIn3zSK4nw2KTp5GC7_oSTlLo,20245 diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL new file mode 100644 index 00000000..d8b9936d --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.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.2.1.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..d12a8491 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.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 00000000..1aa547c5 --- /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..9767dad4faed138251df399315bc60defb83484b GIT binary patch literal 4077 zcmbW4TW=f36~~tn?-x-QUu0XCm1LWuEs>IJ%a$!)bhVWxl3>XQIt98|a#zw?%iYE7 zQnHLFD2hI`Pkrb^`w?2C-=sj{Bo8TQ5D1X;!EY|?zT~O@b4W@A8W%_j`_JE;nK?6a zW_ix)Z<$O|!KZWf$=*?qqI^e<)~BNZp?BdK40k<{mkdV z7sLhTe(*(ck@*7nlDNct5j-FUm@k0`#US$lct{K}4}yoqF!K;t6)N+vJyIDJqs%IJ zOpGy)*q19;#1-aI`)Va8a?E4kaWT$(8Jrh+<}2W9;u`Z+@O5#WIR~B)6U^h_NioTs z2Ny(v`5L$=ipBRaH<^pzTjCb;6nIw5GEakVi`&dI z;5*_D^9}Hvm}9;PzANrB-vZwg_n2qF^J1R)Hu%1{&wK~`Ks;cc13wfGneT!hiAT)$ zzzbr5dEQ>EEQuxN``~4<%=`enB376mf>*^V^CR$M@tAo5{6stfFB^-$35&I(rTogv zT5`#@%KNJ2tGeo270))+&7)w?b<~P$RMD~=-?OA?sHGz{*fUi>Fl?)&x?bSv(l^z> zRV(_wnLLzMU^%;L*{xJ`$53s{!QisAyuep?s!ld&rs{#^I{uqb!xmqVyVZ*61n7?~HFgZ_Y2uP=+h&<&H2R&ud_hAakFi4! z5Z&;ay@^d->J>9ECCqWX%`Nsqfq=QM>^eJ^tneN*M6TgDvfK2Q+B0qM)ZRz&)I8ny zHNz~sQV(2m9zB_u<~}%WZY$1hxAYvNvc!k3G*10>9hlO`lBbr)LdlhMpzcN8XocdL zukV_$b-~s+Udxh(rTv&){LHMpD4VULBvvikT#=GD+Wm>;`*;-Er=-{2E!@^g*plqK zH6!x`0a$e@LXAKs4yEpC&Exg$nt@iXN{Rc@PEQ>v+on!|i8aGZdpFB_u6AJQ2;VMW zN!Tn#t1Yk9^bf69%-l_9N9E9R&`n! zUfkID7^djbo@TXS8<1ODosj z{ON0Mqwu-5p?d6}tL1@i*;HsKOgXn%4ReKBO4C~TR(tsenwV>|?7TCA^XKm={`pY{36~Rtg>dl zFlE{DO}}_xItN9>qUiB^%#FhIOwqRjbJD{TimKoj`TRvqvm7hXw1Rg;mxk;|SEFfC zVBL@K-~SHsE9G^#@7q}Fx5r<_2I}#v-^ROtpZQ(pZAU0G`h9xnALskuCX~dv_evy@ ze4AFf2VTW5(eTf|iVfD|xwhfzj}0Gu6(2Yqo^KmI`@e?MW?sifUdPX$%;?BG3cZgi znPJ*einkQSmb#Sg3*Tf%zRZq%lg)pb&Hp*~b#~@eeCGRP|DVo$og8`<9(spkD(m^M z{1o4{P85V%RGN6q9K3UsD9HJbYB5bS+_I+ClA5+trDqV4qNFW1NT?)8x-dz}UQ%wC z2@?8qOr{{UIVjqTcQNw1(HP)dRYIW$X^iu9P&eazVYJzKw4;0`SAY^dD|HZh5pqM35EaN zrG&=*sa&lqm+Q(MR<*8-)|K(PGErBq)s@9M_0BNBc$4jSc`)qr3@~DDft%o|x-!en zhwKW&V1(PoDsYaGSPp=HFb>z1vAU9D7^y4Q>&hTE^Q|rzCz&zw7V{iK{(W>hG|cDy E4_BmW@c;k- 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..cdd8542203087b9a877f5e818b27bd161c838daa GIT binary patch literal 24199 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 Jl*MGu{|U9{iUj}w 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..e2a44daac99b4148175bcd3e0cd50bb65c094e22 GIT binary patch literal 31538 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 E3!$7l3;+NC literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fd2ec94b5e203b1bb052b62fcaf8e68c07e178dc GIT binary patch literal 11775 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21ccdfcacde3f1803a8fae5d7a5ddb2b16e98daa GIT binary patch literal 127675 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 AW&i*H 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..bed1e0e1ce730cefe02bb99abbbecff7956d7d02 GIT binary patch literal 22142 zcmdUXeQ+GdmEX+Heqt9`d=Vf4ehf&Ez>?rn{18b&q$mm$MOqTg6M1q3nFTC&2Ec-g zUASjK67bRnb#e)-*hlcr3aMBsAy@Z7mYgf5k~*s@m&CcaQmN#hg#Z^UiZxG>|#Oja&jdZi8H-3-LGH2e*M1sHU3*|ZH%Tl!&L z9#N22M%(twI+5zQo zskK$o8t}f?`c--kxi;WO|K>FzH)>5kZvN0ETJ&$x_Gs(gboZ;;6Iu(N9RW$(8<4F3 zw0&CZo1XrynoC>%o@~8Eo&DN|H@*Ga*6gKC4?2431g>8z;b@h#16uo=?hnnM{X44H zD)lN#+LPMG$7!VG7<#9rWndj%z!> zRT1z{my>^Zo9DD{@X*ex-}z=c7f}$-b$Uf#a#kzF0CDyO`9~tXk^Nb1^-U z(&DCo;j0D$R8k~KULk4q770_=j5H)`@|&S+a>lNim2;A{~7 zU5v#qsWC&n5=&(gsbMvfR+%2x6PI;0Goq^|+Nz0mjfyLMaa50IsL@b@87P_Ooj`Ih98a;_3;)_NS4v(lf)|I(X~vhttGe<+^=;m@#ow7IJk-GFZt zy_c@=r#xg}%#x~3KOEfi`-aYpJ&ELGY&?zIr9Ed^ns77rT#Ols_<(*@XYqug8+$J6 zsmptkiHm#2Co?1I)c)w+eS3^VM&CV-@yCWyBc4peFYVFvc$&pBX=X&nCyV}+eq~^2 zA{C$7JRUO)Yx1H;l4;P+cqVFn?*K~1M%;coEqxNMUu@`HXxNbtAHLK4arp4Pmih4E zy#MeDzDsw#jOtB!&qirHY!m(PpN*Qs^D;d%!BVUluNh77T^HL-WfeDr1oxoIKvAg} za$>}`;}yX*T5$sszpjxzPkrH)LT$IZ=Z-G~cjVnW7-9L9aL`|$ON=FwF-F|dOZ4d- zbYe5uqh6fIsOeO4QlNi{J92r+=?Y{(%oeVpkAmY3+tzyjCR^blA)r5hPtQ;kVH#va9>&w@5< zGw7(PGEvFCRx>SY!^en=HQ-THfFEl|$>LW&ZG0Z5+BmgPVKpc1rWRXqb8^!ChMn^b zJM-Zqcg}wtK63BX`S6jv{|KK?Ms+!-uuf{~WD&pB4U6DY7k#$aBP4r{R%H+8Kxv`j zpS-djg}0=)uzn$8WC$4-7c#D_iv&t6ib^j)Vx-hq%90M5$#Ie(n6^06F&!jt?8PM} z@Jb??RIjAjB|e8nb(SI~;M|l*VG3g!O)CwH%PI&c!3FfzW-B3SEs@ouCNe7TYABJ? zsFs>YrF1ryhUhZI8gCASIU*)Q3%~<3j=^XR|H2t@SV!YE286K~DwM(S2sl5PxFjgh z+bf!r>>Oh0F_l(KCY?@#tH;LEETfhyp;B#4A1V>8dnnS&(I7ZWyV z`9gGc$1_)Z)SV=3@YpHjOa&xrhw-XMRaA}=od(44yB$=Blyy!`gskFi5~<7SOM3TE z55Za8U0GAJS^1#5Eqr^_p;Av~Rhw}HX?n*=yP8waXQ-FYE9W`E2^L>KKoOP1$~W8T zDPw}^y(CBsJwq~V@I0H)A+<3HDc*6JnjE@(Mj2AROq-vHqmg~t`u0EL z)jP^9X|=As=E}KQW7ai_MO%60ydRo~T~ksGsAGC-&U(%|S!H@d#%F!iXN>frQXhjjCTw7-ZcENBq^Gyfyp@S7_C*m#{C~QCQVh0FAV(LMRSr{t;dq7h= z9&g|;5fIW=|8rXUjjKLz=!;INe)H{-JMuz!XWqY)V{upXJ+&v-2 zg@3P~?@`ZQ=uuy}z_tO{!+J-}v-J8d6d1=?;Ql0aODkj0va_11;LDyu4H~OKHYzau z`+ZHGUCTSA(7L?4nWF|LAgrb11DbBcS%Uiow&_J{jQYSod4=3~zT~~O@$SmX(_YP$ zldy7>_myk1=FZALLfqqhCF>eMeQ|N^>x+FG;QF|XQdg;1;xDdxFX@w9_izbj+F9J< zC1Q~u6NR@D8ziHiG-SD9Ps@(pnvQzsaC}yg4OCn#?N$c}5X+5?qhGC#HGV&6say-)v!WZC;45PIVz(cW#B-w~* zbt{dh3&?iaa4ZtR=_*lVt2w%8RJ{ye1H+AJny&Tss)wUb@TT^x(xlj;T=+YdQ#Ru= zEv84fWorm>4N%{4RTtzCqfT>8a0SFD1%a+9T+9+e6<5w(P0R}0RT1LRP4mU}q9Ft( zxfNX6F^Xq#X(yzd0*V=4yc5#RA>8(Hxkf++Q0KA4S_W_oT73?&R%l#ztNUj6?fo}* z&-4|VHa)&fQXDer7(wPsS~UeQbu-2JXy6ez8r05|K!5L2Ac1ODOQ0z?G1640YID!p zi)*UogymggIl+T5SLf8;$6R*8aHJ*24gxud7~jAEt)BtNFd8N!VZur>4Au$v6>H1p zgB?dL;wz&MH_-dno4t@;^^(6e@7rA1sLnOb`SM*a=G$JH2`_u4V8`5+yt;Q;lK1Vv zEwE!*kvw&a?sdz4hrmN{WK25`gRT_D-F{P6CH8*{B{G?R!Bup zOUpIVuBhmSP@>CvuF(xUg*s~hzKu^7;E)aYG4X#C;6I^0O^m%&0TVqq#(#+d`E74O zfN1hHrDP2vBxH__wd5cyH2G~QCtvq{4IZ8qm3c$Xxfs1s9B<_5whS#MevML36_@7D zkWAp06?S@C*1R*qb5t}B!c!1I*ZmMscv^Uz!!LM~z8J%l3w=gDBN^nq@g(#Z1qOKZ z4O$A09HIe2SJ_(0ULIIZLNuH4Eh~n=EqcUl(rRoXlO979kRo7{D)=K7A5l@RP;r(k z$kq4YH-Qg2HebS_;$cDl+Q3>i1Abh+kWesL+4dcEmAKtfY35gQ)oi6it(_C09VVTEeMWYhSH1zM8f<(T%86vUOY)c`G7+Uig*8)?htDc1!%aBL};%Kh6jgC*1~L=GYhs#CO{?2 zO9jUvOo_#)BPPMymMlx>K%H=_va;0y#30t6X;`465=+~dIar$yY86`(JM`YjRe; z4sRvaqxqr#5ew3M?O zI4~r~w4wsdSM+do$Zbbh-Q3FbTTt06sLPGpNJFtEfgrUI_>7`m#Q<5yBC4c}r^k!+ z0|VRzM-&LQgFzuCIO15HML*NY+tjsU9mc^D*iEq-VlRJ@LP~>RPQe{t21rN6oiayg2DAq9alS%L$%8(hSf`}OYzv7Xm*#MP}A+;9r6K# z>tYl*TPCuXnS>9}`tzV5_FI&L#cp{13^ zIiq|(SU}*e=C@z$h41+*IA0B)gzA?SJRce)TK+0@qDJ~zP2fa}^0Rd^?q)cy7;^3; zvu&u#p2H2FH7Z}kt>}gUnc=({@$h*QGe~n;bd&NIt|ST9L0D0huG1a7H^y*#2;b=? zSvuG|ed04;c-H;qcM9RA8Mk>u+%fNeCBN~N1^+8E-~Oa&ecpdA-*#@ne{N=S$yYP| z?FV(?8$-FF*?~VDUZ{)CD8F%cc$$_^%91~n_qBc!UVpp!pME#*-@FuTwxVlA-wSN~ zAL4AX6ND^@C36)21Vu(SBp2CUX7{dtke6A-OS8cu2T5WtQYRg_+3JljpbM&`n&0{; zi0cRF#1^EKpOftw@Lw(cVGsV`RIy!-kLvFp3g*XT!X^_LwR{-!hQ&?Gou%nUl39oV3b8zj-$)P} z6o$v@UN8BB&V{Nk)b-3L_G0h;{+0PK;&l0N_uO`r?ldoiqj`VyvtZ-wf!j^Y(5q}reL3`q>kPX9To5kp$AimMp-{cT`Y!rLVg_kjQB5Ru6g@)o6FE%jS_}%k zi@@Yqnq~2!m!_c)1?WUy!)(V7zp?1sRPYCG_;dan;avE(=jZ;-pM_gyzm;$6Sq$$k zbZnbBz8KoPpWFpnA(p;ZRdVsi(@49aFnZFi z$h~}X31Pc}yTPT!goS`i6Opk+Agv{J+={y@P=zxQp;xGnnk7Q*#2e!lLle#w&*1|cuesPKu~ z?$_xPH|6;r0!alj{KO`L-@<}@5ARQqSfYN(`0F&)Lkk&iE>8n2@6t}_S0-rwYlWam zb6&QV*6&Enh?LI3{~JQa?D}^uVoW;nfKC+wW1;a?ix+3N{|Mn?qF1)~9qY*{0;=ks zs#4(pH_^hrODlI8w`%fZgCKPk=`n#-%-*239d!Exx=}=ny@{L1;jq`gS3qGi_%v8; z^*29q^`n(Ub{01?9-x3NsSvW8+}DuuV<1K78qE7qz^%OC8n_+Ow0a#+*7c=zyqfPz z>-e?6m)5D#f~7j8&9JOgN?(rD#&%;U$2F)lXq4T%Cw1C~Fj@Y}NCMkU#z^`KEEE;7 zQ3R?G-iMMVYl-r(C%D-lG#sUm@ttDCc~A2+N2`f&6KJ16>*1yrKn+u79N*|d(v!7i zVQTiWW$|_FEfkUsY{12X{ z-K#!-HN#@I^&%`WF$!+HP;{YpQ1oj8h%1hnCzF`#+MOuC@pKstu+6J*hZU?O8{gbr z#=f`*yAmvOR}m=--v*4LhvRKfC%{%DE4+puQ`&aXc`B z8U9JQxeyB9IGsEFgBP(CUcb&XtEW7iB1K=q7#K>%hR-vCUkvG2A$arw-v3F282Nlp ztv``gC({!=@t#OxPP~4Mo#R;b39R_M#>DQDy@|jfU{<1c{bGdh(IrO1WLRDj`vGo6 z_eG?baz$TspGl|myRKpl+)~qE?Af%6ntkPrxFtsZqGp<$N!@=Bz}Dan!i3gZ$< z2e1qr6!HbIM8%qn4abmmML?VrS8m;Zp25&cQWwEoO{u|-R8%9 z%dR`;7v1~p7qiK^6N~OhRsM`9bUuThED^Eu0EuQ%^g+lP$YzbBdw!8fqCgwhjLUc{ z9Pqc`VdRwQU@72+)C{xD+X|fX%Q<;EQ{ud8aS=;8Uh`(X*F#zFsGXW2x~6*yCx);= z7*sYWp?d zgdKBaAKr984rD!A!x3PZv9|-WZdeN*ao8!+6uW|nDai>l)v!`bB*w;cjht^fSA(2J z^SFyyn~RCm1m&W0IYIhgWXKTj!7MNZ0c?oD!BP(}BDjSic4%Qp^wB{mVM1isB*_^K zQB559LKtI$YyqL}g$5S~7;vzP=Z{iCN7MpMEwNiA1b^B>cMQ|Q&m2dOihLmqeT>4s zFcM(7k;LVR5aw9}9u`R^`R+R(QMt%90g0Rl^M`6q6lg?tAh+zQ43QIxtSgRd<#d!8 zUSGLjH!-c0>&~eWLo(k8l9bqm>m_U6VX@E{?eSC@>*I{k5~8cqS^8c&O>;=Zgu~3I z$dt1dZSB6X94Hw9tZtnQLTZiRaZDjUp+mS^0R`U9v~Eq1qI>g))oqmLqzEe$D{Ol= zExQQJ{!*$ke=C@tf8gtsUYfL~m#~?!?Ql7U^L5zDEwje$5y1Gi!1q{r$*KcN<(!E_ zKmR92c`u96eu(o(L~oh+h^Hr#8eg3bBAWbPeWOF9O%qd-z#~dmN&;9wW@xgMtX4rf zn-s$GA)CjXjz{O!lsc!pm0sjK^$xCoNO5D zveS2_V6D94Chv`f;JsPj9Zx1tN;&Uz8@@Urm^CcxrJ7~)wm0XS-kS4VS2bCalFBt4 z2+u0j?3Zd5ORi*v_y8xIu`LKq$$4<>!tFe;RMOfxcg~yhQWST{S#RjY=WHw?I(0&)8Q4H`ySS+2+6a$IWP+C~ajjLB@(N9_XWNWZL1AU6k zX9YW+NoP*dA$gu+!}j14qsd`^L6zKO4n<6NnS09INe$%@{V7~3Zy>BkGJvZxHu9HGd zGshk@ZZ0$)yqC=%Jo(dfzW&t}#nn`|EV*jyzVJ(d+Cr%5_T;^9{+HqTmRILPuhL11 z$j!*FJxZVk!TCUlb`O70^V{VuQuC(!P21<2w%>2+op0*>mE^A7h+|@f)@}I~%J%Qt zgWI}2D~f{CVP0wd#$}(%h%0)B1}KpW zY%?&NOkYG=H;YmA0QgB{Ik9)}Tf{kP_;fmEmrwR}`cAQrqKCs||C(O>8@f^C#-Od> zL0rTEmM2+f4$pEVe}X!HMzc)`AO8z`A+I8DB|QDz2aQen=KTwe2WEUrzPjn}-ae9V z-}9ip^?rTle0}Fa{f-$=p<_qBW8dt$TO0pq<45ipZ=pMy@9v#FdB3^y)_-zObeDBVe!d<7stTb! zEZiq+#Z+_gepm5c!r-g3E#pp=?*^q2UX@o!Y;cpIue!-#94t)|YEba6;^UK8Z*cI4kiS5<#<$t?sd_l*c*k9vwn1*o$1&S-X zJ*}UIxU}l{M@y@t3!9%=bRR3pu+g~)qR*dIi!CEXlK$e#RK#&qxZ+STV)Jxnw(Mvz zJA_8&xxACe13Ex3d_2kh`~`8i_>ZW@HryWeIbgr;C|C4jA6~`@W=Ac4aQOoII0jfq z#zj^U9sGM(gA)E|5C!{rH|*cxEr#Rcpz`o-J-Kri^-|5+;0-v2{SCW^m8 zBoK9;tbW~@QVNW$+t2B z&U;)y=9LBQ;RZ2&Cz=*HXoyqIWk(LIPZgaW>NAhjWSt~mqkH-jP2$w!h1GN>`+fC5 ziM>UR#ZRfk+2K)Cw(|KbNF@SSfyDk()jq2cx5L3um80Y7iWjUN|Az2%5YWPC4Fc}x zt?}{8IzSZ*6nL4hxfVy8Xf#S(4_3V3*xKT3MB@Q=*9ozIZ)3NPPp_41bfG$W51Sob zyneC|e2m*_U`-s@*ZIci8lc$E2o0|T4YDOm{42iK3Dc8vdI@3fXYhC2+2AE^lk!qE zI8PL72JpA2aKa3KjDjiD)4#&4=mny1pF~D?fFIeSKP^M2C?!VvPgv1zIvdDH+lk~v zGTlWoXdRWv|HYp^GYx5qQWrgR_RJ72RGeNkh@S9QwQxv*j=~#7S4KDg*4a4(TUir_ zavsMVUX3yFH>}9{E&54)QaG!qkYwSah$kOy$5;NxiTGbs;0Kd=ntIWXLuD+Pj%oa$ z1^X7&<5apRj>d&x`@e@{pz^sryr@bxCo*b?l8}zi@9| z@;A@8ZiI57StPJ;m_EMbuAM&q*6Hh~XX1ZwW?C*({0!IMn95Dv-gf(2A56SEaeL={ zc>8py;HjJby|-Sw{@P3?-@bp*b70!F;`Pg2D=h)JYq?F@xo264%IgXZ>&0^`4qW5+ zlIPTl2hU|qmYz89xw08m0-) zlBfGu9=tc3qJ%$D(zUCgb}oCqA%hGx+m;n7ECn`+Hzwxvj!-|k65vIg9dnT7_ZMq+ zm62taNtRvzPm!gEPm4?LG0D zptQ2nCr6fBq$i*HT-g9ZHex2}xpA*}_MPI-CC`Qx58f~LO8XC0)C99qi{mHDYOWk! zC+}Q&qE6n4t+FABA-;>!{`_LxM?hbszcw 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..471ffeda1498100fb54239bc68417627a7a3883e GIT binary patch literal 14781 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 ZW%uFo&JhcLXD4srr~aOwz-1GMe*=aB*kAwv 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..d16d3372be27353a22cb62b1fb6ab907f59d2ac4 GIT binary patch literal 20210 zcmc(HYj9iFo!`9xF5V8K!x3re6sfVmfx zL>k;uj?;jSQjw9ff+oqB+O!o_JGH#iZoD(wu9NM|X4)?xDTN4D>TtW>ndVbzQ`;n( z>9oK9xetIeiH(UNF`O6~6GuWyG9nJj ziD5B$o)Sy3=s<_!OpGK)Lb4LkOSu$Ho@XfrBcbG|98p9$GMu=Ga+BvnN%2xdloDb* zkrd+*gi(2gA_gMi&?t&RqUi8QEHWI4C#kGqF&Y<-#-ia1Vj_+PosXV7ACbjaN`7>Hy-Yb=Xpi7A=dYt$GK(GgipMu#I>PB{`%(4-^{BmRd(DLOcaglM-ms#GI& z*BGaDL+GS>X=Kn(R1m_SUPc&$hmP+GTxLz#P45Ak9h!iMEGJ}fIHD+_a}mXPE)tK( zA(}p_(5MXADX}_RBF0t`&qb2S$mJxB3K}M!OC%)pn!4entiu@Fq^QorD0NC1jVS1? zI{d5z%y&`|6N80nF3C|88W#t~#1nGlTtXfbUkZp{56NnChC|VK5`PiNi4@eJm&TIk zF>a?5gUL(O<>QIbxD-l86Y+q^)+9zH79EaKhcGMQgoGs#$0Ec^lLI4T)F7-%nKgFT zjvYI$Zu#v`uV&o6vyECQgrr&#Qq*;balV zXyU0*y#V-aM-y?HRCujMa>q*{IW!zeM&vyIYFGmh1|wFuW{%@mfhOE{Y&W>122vcC z;&i~8C=TU~Q2rb@VUqZFY?3u?8w6y(?Vd2Fc=?WrOW|##v!pDO{ME9QMKWL5!f|q4 z$~1&J*FP+mQKz1p=i-0Fa`qtS^GQL^m9pq5dbn#s*mRByo6dsBObBbsnK4~;Teu19 zgfL~h;!RnHYCXi?^*gY2q@7m2LBW_Iy?Y~U(+)N&&v74 zXiO3ZA^@Yff<8;EIDlyX_MQC%QfL!(5;RDKb3oWgLW$Cj7PZ_UiQ?#psP|HBvlNjD zU};!h0Nhd+Fv7za835y8G#0}!u)*o?O~fPp0hY2iY;0LfA8}Jvw4u+#^8@|{c#A21 z(wpLjic@LxtS|i2*zBdYWFdYNm(=()j%(v&Gta%wjd7Q_%jVa)OZ*+a*Kf|-MiQ94 z!DQYHPu_WoCPsxQQ=Sj!Eegg!A@C6=AAh6k6=1N^6^)IBMiOu?biE`eh9cpl(lroL zqTyiVazqYCL8iK})-HB|#poJgq+)kq=dLacW@I}p3?g}5VPXin43dzy1_vX_@cHq^ zpt^d3wE6-EV~KDmrW^{WvB%I7g&4KpO>!$HtD`RGsY<7EwRJbfX2!0+nf10V!#_GR zdi~OL`R^Wh>ObdrN8PWhYFEs7KUTcR`mKs~?gyTB?q550n(y*E%`%~jOnn@$Kg!4f zIFO522baL1EmlxPZ$ve(~$6-U9H^(CJyj_cz@|IXsN&4-13sstTvbuw`{qiRHqTE1b z3oJ0t2lM=8xeg(U9S*HMJkQGYl*U~=fO02-_E18wxio5z>Nt1BwC}qICVL)K)J%^r zRkm4%&AsxI)UUjIW?N=zGL|1SX1#mT-EdayoY$B2Y|MEp zZa8Kf@4A-N65fquy04$V@7}1DfVo7f2Q?eB;(^7QgIVvvPpfLCM~ zz8#HQ*~8i0SzGOcs=AEt`hm15y=Tgv^HiiQ59(WHTW8PAb>Dhzwr@7DSih4Zr(33; zPVY~be~K4Qd*mrP99qmR`0b^W1M}Q4)U;RYEa9 zo8Oc-gE!0z3`Ny#DXNq1#6pQhlR-qwJCSPyf65s+lU&a2nKn&Vq)$v9%h}xDnYc3X z_CLo^P47-$N|)zs&h*ao%afO<_b%A5n<}SwO?Rg+Wz3oG%#n-@^O3c0%wg0vO^2oj zraRJyvX=T)lndfQuJ+KvXTwAYhGF8bxG_L_Y|(oX!*ZHS8mvTtVfhBin=nm)oc|E{ zOAT%z?GL#hV`ybyCWkTcB@-7S@nD?fgjjSu5*!?jhuJ9j&2ksg7%)FU-~sY#hkKOvpZY8C+pgqwd|F5p^Py8j7RG>zxq`K-QXfz9}m&lq>7S~P!K7L zeUcSin$TyCSRmG#-?r!g-zP|R$pV4UI>!4Qd0S9r9ecyY+>*g7u3-D$0MC))f<|-L zmqB6*e41VZ(iSGl)We`&7W3!&_Ev)n* zYSX%B$l$aJ5h=T5CP35k^2OYeT@M8pNBn7L5hvwX7uSe73&k3~A%k-=g1D5?Bc8i@ z8TpDAxt8n?<@=}fP;V(}`_RIH=Qc^ggaw>97cB6v7JPwAR-crBFPHIU#h2Uo!srH# zksRav*52{9Q}K(~6_TnS5X0voRfNF-G651Rp4gi$k9j{MfGX|?N|L1O^1Leu#z$tL z0(umTCF17@V3fRBi6rxObw5QEw$<{^S3|K;ov?)@Np3;2A%{}SME2QEmWlS~1@s7FEsY5_vi7L^*&Ymn zjZ6lE<6dn)1oV(ANUr=H9Iy_RTw`$uh?)&bWnb3k~Oscw|blr4E%=DjVmo9}!5D^+OEN)6|(OdrZsH>Qs-`|8kC zN3MpN?#fj+;N{d`RW)hL_v|Y47+V{iriF~n%&#`XLxile`!AZ)Tf!W<5Kz_MK`A z4R}Es5))YqO>m#wLblyEqm9A1BF1Vs+{AN{=zEmw0`Fq)7JCZ3S_2tRZfuA(AlGJtgOf8=`%& z?kS88z}wl&_F&${;5f(tQ^ixaDq*NW1f`?#WC6d&y`%99@x&zv`wVc!j>mk5->Jgs zNz|yKD`9Hh2_TmugQ3w_QZ3pHRhQgNQ9?q7Xv;tuY!q#M`4kI>sx}!}%SG8npWy?(b!^`O+0BP#zU(-b|f42K57fzzangkJm&B`Kd})Ara2uO@J+GulTp!)U4* zYFb7rAG?!*?)aE4mzv}aG;x-JL?Y(5vRQmAuoUtu6j2t0s*w~Ir)g%j#7v^Kt2^ zIB#<+ZmzjCS6!29Ze8(g6l#~tYF7ljSFD_;WyMB5JLjoiagfi+Rcu&sk=3rS|+rsO`wXy_%j}j@bIgh2r6*ml0_0Ep1AEV zaNw3c3l3gvc}K8Y(@=$rDUCs21FXOlyEN-Ik2sAx`Ly zMcs7dFGML+CviOLsM64nR~jucc%7diTp@)8_MOHpXlz0;f1nKll5w0BfB5ECKS4Xc zg!=ZNHIWoQX?l)>g48GhA_}Co9!?h>bR>gv*<27T3JPY1@n(se;NyozFuF$Y%H?D{Eg9$|*Mj4NobIzhX=A zl8xmuQLh+(QUc*oVu|(=y#aml8C4jbA)3T>Pw7_aec~a%`t2&dtWjmqirY;yycwS7 zIiAh(S@0dy+AI83tHl2?e}ji8;F{9d$s!(ef!eKavtB0%$Z|9bS`*Wb9Id~ zLaw4F)AId>2Q`}?_^PuthZlX%F8NN(`%dJVTHbs8=Ie9PheLOUR?J-WNq&_xRoASV zEwz;^oTZ`?fT>klx!~F`Yq@Q|WxwsY<$;>*6XBPYzitLxLpmc{n8aLqa8oZfTe znVDzi?M+`o!g}xUY-xa?uz_!FH36n$k$7l_k>LPM;jv~nUGyEwu*>7`?OlG1ZwL<%{XYY!DH#+WZ zTCtJO&N<5;Ip9+Zp{!Jc@o0F>uhPmbA{b_n3rnAQ%mfWFwRVkKj4}Zt`BmEBH@N7R zXkXS61*VxnPW91AgoQ23yg+CB3h9^eVv7{w+6g3;iO((Gn{0f>Yu3_IG z9xqi%R!p5u@<}$l?ReYqcIff?TdI~E2zN>~k`r&29~aqt%pfGfj-5h-r07ANY9=~s8<4^0DXgTBsNjemYe^h{QNl$S zh@dJ2L61BbMTOljonj^Gr(dd#LJWz>AOa_8)GSt#6qRuZM8+oSi5(euXyzTN-2v+v zj2AA+p%FSfB;$p##He;`#u}~Kl!Rop6dZ;};!2cGDN&};17yRR*Lnl%h9s;}P%QGY zb`-2m4C@tkm`5jZMjU#E8CY+HqTr++Rk32o2nChOq9z$BWN1QTzaKS+hD9io_iHnN zqd?UnVn6HR{{BB=$6A4->Vba0c!`;XFas0TY?&2Ah3SuWwsic_y$!KV8(&iftwXg#MImBnC9bE|Z8CH8@i`v?y?< z;0juyi7zfo%U7HSDToTLdy30puxEf7`!aIi5X5qxY8CVX81xZ0${z4CLhqU5kNNG7 zP20EoZSr0O=W8+UiA&J*VSVF(3|mZM$A$Tt=s6q%L~sJeBw*53V!x5{($Hjrf!7t8 z*riAi)b*Hoffb^IDb-X8OkZSWzNFf+=*q?aNr{O#fyP@oUoCLd4q_kJMOwx-__j0O zre#-o`fzS*U}@{|`K`y(JCD`y3 zv!b|K1--ew6idD)e<@bn$UkP%tR-x)mN19L(XehwBHM;|P&h=r>XA;2i3zh6}xsfmh} zNd5hUcm4fLmDCR-1tSmjtRGtXei)Up`ZQuBqA~GgbWnvqb)TW1%wmISj$i<$sIW{( z$8Z>^7BW@x3+Nge9)@4Ux6^h>A0*Ptl}s`gOTyNHAFp7h_PYC zC^wNAyT6s&f9O}9Lw7g5Tb@y7dv2e+b@IM~2*_v}A9Yw?pZFyX#ihJ^QX)RsB*``+QY988P5QBDcw(?z#5j)Qg#;3vQ7t z8akILN!xr?8zu20N$VCQ>7DA$>|Sth{0vF_zyI9Dc@HbJoxk05WP@dm)`HkD1|466 z=Sfn3DJzrp@Bm;yIrO}5Y-=z==JAiTouu2+fX@L5XGTX~wx#}mEErf$ z4bR?(Y2YrTStChU5WptNjw04r{22=W37jJXDYa=pdgCcruK{bhAp_Zs1W-N{rVWaS z5-JLWmcrnY3hzPlX%5Cm26ce((PmaNQL1&%l^V3DM0hERq400Pgz4(bx(Sn?5A|U< z7%47TYZa|9l|j}`)%yFlsH%c(v;>uHfIMip{r&w0_7Goc;5xIzCGJ7BjnlboVn{E6 zzt)*uvYsNlVxtg!vcaDYQfXj5i2(&pYlK3DM}Q$rnSqha6nB7`QE6osP@gaw3_2KA zYF0QgJWNbHjH4sOny<0nQ&SF;*g*DpWaZ4b@j_vjG{$il7Tq%JBw#JPHnr9>m5C%A z1cZ`Ymahko#1#CDK?-7+49=?Ni%~SVGM!DS%vuFZccZZ=s6~*l9`c8Z#$%L%R4n@O zLK_8;*uVC0!O18Dt9d;F7h<;1&LRmF7EYC1MRP`4^lnNED<;8FgG1UScjvsjb8hcF z_fGcJG4Jk}6YjYKko&#W*T$#DGkf1VaPz>N@S*FDE9=>vweSAjBOB*!_?$DL1RP#o zp1KTcnAzm*%eO8sb#yOubmzR)pP9KWNB9*p(mYnkp5S|}-Id(WE4Llt&A;GyxNCN? z0k_Rx*u|x|veK+I^%8r=*j@P49`JqOWSCVg_UeQQd$z>R0*~jlkZq_*=lYoShIztL zu-qtJzK#*#tQt6uDCS=vg(JYMoQAw2)3dvUByVII8Nr)wx)=oyhgpsgvoW(^W9f zV&w>#@J;9JvHR{$qU>8CMbvIc3pn4esY?srbN&8v54YtQ&*=CERY#o8H4DpvRx$Dr zV+#ul2LbCJd9HMLDUwkzXPz(>(RzbSK(B9-)N^xw4CDi5am=W#)Uv!t=HsN}@4*CC zVQCSYweEq4QM6Fv$B?Ro$RIbO2PKHpkYPq$D7KiS#haecbK0`&9!SK-#vomK>6|d| zzCA{ob{Ol?`j#ijp~VHvWGl6r0$Rvn+-jMDli)QK`3gm_W!(s0-ijMAI6Q-vt+0sy zm_=aW!Af*3!y*4mM2&a+p*5>9wZ~}L{s1|k=PR$ecHx~1xysrbTW7Z3=$h%8ZCR{r zgRx6B*wX8-rH_+Fv}#&<=gpkACRgE`{u<2wYBN1cje&XmuL#`T_i^{1?q{Yft@Ga2 z+1+!(eQzLFQN2{LeW7AIAn}H4#CBky}Vme+*roDJXecB1T+4V=e!?ZWpisH_gH zU;QCqV{7^Q+FHh1(Bq2U7kPOnOe@))vk42`;UZ`$omPjS388SpgtRcFDg}@qm~~$E zN#{c;o}i6EU#V5PD`mRUm@@xkSL)gohc=a1m1wOsWwdL;7Wbo$_9R(AvM0qSX~D6l z=)|nl=@E}}FpMlc`nbFWGeij5)*|Ggt{hk}8ADKtU#uVW&K@Og=^qC z=ifGNp9{mn;Lt~h78{SGUwBa2oKfy>|K!YHzxMOj?p5|?-Mz~d)i;`FnrF@P6>Sg} zT@_2NrUh3MbV}altjE80%k7+v-}CN;h1ilWFz*Y@DR+;5d~DHoWa`***@kRc$Ad~S z=dF78X$*Ss>)Y5Q&~C6W(Pv{@@wT&<Yp6D=&Y)1AeXFJ)Hvt9e|N;=#0)#7TKq$|`rEAsR`!n<%qi&leM^ecO0|(ZA64y6J?quVrto>yEVY0Zw3amf zl3uD+s#gOHLkT_JToN&i`0o&8?0^HB?eV28Id@r_CwlzyObsvqMysCX%4*dl|8uV1 zQIkG`ojrSe_UXAJb9-ht-fjEYmXEe9Rvv&#sJi|}a3;7^y=A_7%UsoB_4f2}6gOQl zbv)huw^jAIs@kQhz(Q3Z=i9X8>zwy>&h5JA!&f7iT+sKP4^Q4Xd9P+~*1I?7sb2E5 zEWkDgD(>ocmCWwzm%o27=c~W*{LJ%9zRmN#&9mQ}+cX!N8<^|3=i8OruyML)xvp`k zZr6O>uDiQGwtgZk)*YV_kiWiZT3B{hGF{c)*>>o`|GTH^*WT)t-RRBAA)Ht*xi&Aj zHs3j{G1^P+=6QGX?B?0Jxz-Om?sVMkTI@WM^&ib{?78nghJ){I2ePisUt}i??KtjK zlZwk!ikX1yV*ncncL}i37iCJlHFzB5l#swmu@kaAX-HucLQ25(2Lo_Gwhh^dm>JxV z)Y?&!rNzbvb3(fSkNyVW&|StYw3JJ?U1E|Lp!gr(=BJ9F%9=EwNv~7xNLj)1Tj(B3 zDYF%@{53@*YTUp?JA2U1FN{d(c9#OQ!u?EbEDazlU4{gW<~=npSO=>YCr$ zx!R_g!P%{MUzr|UtU0h+W+Q7B8?0HpTzS=W=$$?!eb05%HQRl&Jbg;7-8ti2@@`x3 zZhPQs&WwGqiQ!mNW+3y;=@(|tEVVy1kN>`>U~H3dT<@KIdBL}tCb;^W5~z@r!j71xAaSYU8RKRB3;9aCS7?uzk@NfT4~m-(-$wUdbHKdN(ZtuH7mM z8Hj?>B%Le1aq|a*ML(DURtaWTv`-*lB5eIbXrS*lrfIQEnBx$V*B}*chLprA4Iw6Q zqX;Qzde=P=eIUT=SVM#s`dR~}ps#(2ZZR7|eF-54;+GF)8|YQ20PKm;a`nn7(v{F1 zlQtKKRLWr55NnD{)e(5@HC71VkNK~t`)WIq<2H%FuEG^D2DcEdasniZ%X8!~7GaEh z#3#Tw=>+)=$}i92GjA`P6w~c8gQI7+1=Ss+ZkP;Gk8fDFVRR)DcA|10Q>@%ZDiHMg zrgS;3Mfs`s7S}xwavF@iD+;Pz;zPEZ=)nci{HKY8>y=kQhWj$6%a{RNZZYTG1=e8r8%s+p63*29{ z@^ICAcNWHmJucTw9dxrT!zxJrI!f@D%LHrkYvi0H=XG+9lG8^HsDb9|ARifuskeQ; zLB2v^qxkgO)xs`PRH2AMMk6`&C~cJJO}&uur`YA&H*m$9Subr9nf>$GZA=5t?3pw# znX$d3|MJ4wvnYw-CaJ*-%|S~@hLk@bXOY8FHOU2vepBg1GF7g@rT$l2n zAq+zqqNo9K!f4#ctP%Vx`-{x9YXv_u)5aT^OJ>^SQ_Zx=r?mIq@P71FzFAOh@L7M? z7|0qJ{a-KuB+g1)jErM(gAq8r4LA)1U;jWH;~>^perzsWwwHtttOaZ>sGQ!{GE1<+ zAVG&%7j{F~&bT*Ga!AgYWmuSi7W@gdxt>%@3KwDvykz03>|4CwttxB|F&=_|Sa!q7 zJB%B{dAG{PVBJFtnRnA$zYdTuE8MFEkd50rpjJn!!1y;h$bhY2ro@iP^fRWC#!1Xf zB7vV_P>W#pZx=%_K_fda*ba1{0v6Q~kQtWaM^m88314786{MQ%dev5guY#V3jM-GB zD=+^A`ZPXrYIp=U77;A!?OdOJU8}c|6&Y)FA`V-w0UXq=X_A89Ad111f_~75Y>ALv z|1l%7x59-0JAML(ez`))TgaEM?9nW@kQ%?CLs9rOnOI@~zhjX1t}l`B`Y*3JVyRIQl!}|9~*M3o|%MKaYj+CrrqD!U`veIKtxj&rFrP zn*WBYe8@FDa%~T})@8HhJBQyo{Lm73XlZ(A>3nF}v1}=u?EcQF zE2q-oZ}m>{pFtV9;rhueSFvJ!hHuF^8&}Nq?mWoe%feSz1$?hw=B<3gYNdtW_uKN_ reEVk{oZrUyCi24h?X$eVZ~u&g^IPvL7QXE>j@(Bh_GW$~TdV&U@}t6I literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be9c9750e1bfaab97f1d3889a12da22e07fe1293 GIT binary patch literal 23177 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ff8f89d1fe0ebae146deb85868a3e97dca237902 GIT binary patch literal 26904 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 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..7e32df2bc8d7cfddf2a09ec90449afd51ebef497 GIT binary patch literal 48964 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%0Ah7& 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 DsL>L8 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..103a4689f9a9a6070a64c3a21bea89e23e3c8654 GIT binary patch literal 24884 zcmc(Hd2k%pnP2zZ7w(GyL9%%QLjnUyq$CQasDKA}m;x!0vLr}apgBDt1{}=5-2;+< z2U92WtqZ`gk#Xz?J~peZa2qyx;^~$c6<5j>-OX8Oauml-9gUlN`wYWx=T3h zM!2-Q6k(6%O_U9mcb9Y6hj2xA1&93zS9Vu&IDl|fcNK?&2v>Jkb2x->O?M54OAxN@ zuH|qk!gbws94^$4FX07@)SNC=;tkvMVL))#@;=5DZqqS&tuerN- zIizEfw&68NtN#EqPfvFf$2A~sqaD}mm#lwUs})-P)gsy^)EL&GM1tjY7B zwgq|i$$9}LqjngIRa0nwBbbT+{jQ2ze>*OYBY9Ujb5aPU(i}1wz@})^{K;&bWb{VCEa7B zwU|z2*T<)Z(}=I?>5C_|p7Zgfs*j+pc$%B4REN_kZn~#0rT3^wBaY0aW;P?O$J9Xs zF~QVOEQwa=H-1(a{i)%EMiKELt5jgsuaMad6G=My7pAXCk3uXu0Yja4FmFKJ!c68m7 zTf@$*YakU*X5Ge6BA(8=6RFEQL$0Jc7&EAC<=zWz&loY?Xp1LC)S(n!7u(M0sexED zZM2h=w+)S?`%}rikp~}YGcfC|Ls&`m0&+wX@#w|2 z;dDG`sB5fZ=YHSZoM6Bnh!QD z1jBQ#@Cx!s#iyoWR&1j zF;YspUrj6Vv|?OV6POc2iCu}th8TJyQEJ+HXp*kYLp7DX2$2NEfKje`+0sR{XvR=j>QF6A6ff5j(Nbu-m-Rn4=t^Ht4r zq2}K#m2LQyB>O8CL*{Ud+eO7mMS|h5zk3bYKdvGF%k004-lA^3KmsLn>ZIRZie(7e%dKTc0t;U z;`|KwtWf@I?GbAqot4rhR%%Ad$6{HT3R4=E6?Ck4YnrS%tUg5@&r4_Rr3disJe*2i zis@;Bze{RjIHtst>6G{p*A&7n$qSKt?%{M_>;9})j}0Y&7Q^0bAa2ByMp{iqV_En4 zk#r0Iqs5{rEtYi}BSyC7LM+`EPs9*T#|C3bq@bp3=$T}kG9A_Rl#ZNf!k%t!S?qRm zp$659F~V~?f%Sv81UVru8RHMhK52&ncgR&AI*aP7eR&fCgk^U7lj%I6lU z4$OrP-1SJIvWek0+vi+0zq#v{${PvPtn9Pi>-7s&dvAvJ=A4MVXH=l>Ki<|MNgqoa zJ2pE%-X!B4wO16Wv|_ySwTPXjnYK4HQp`t_t<@QGWE`5~;-dgUcLtnH#?c^+-3M=u zIWtZ}9&u%yn!6q~YMzULQj~XUUd@T}h#zyMZFtH!t=2T}C?H|XorkM@+7aocE=hV3 zy&m(7c{7FOy;k{*M{{31f{le%M*(YNu8b=qQ;hDArDR9Ot2wwwKJHPy<{$7|W6pok zPbX^fQY{TOoJLW@S&8ezXbkzS;~7uJO*4aV7izC`NuO4q)jukqAGa2;;?2IAz1N!y zb7jyM>a&%1)flnq%`rA$jB+x_{iaxtl~0%7YW}o-(Kz!X)B-eOpz`48o~Icd(PoOK zl3FZj#54ul%OI?t>Qnk-i6LuGjXDB>U;J-8U0F;sYPcu+bV3LB+JELPP{@4vQx=ICtGY{zx^8%Jll7OM8#4DF%p?F+%3*SB6D{h$qnay4in zw?Qhex_V{u%8dKX-=FhsMo--pUp+kIe*5ISYxDRi{0@dD)HimDP8^-x`p)sMm0Yj5 z{?v_{`3-IJzBbX3_M5?-i|B~YKk?M0XF|@EaJe^k=E{Mhn87$Yvu)M1rrDBExW*iJpA~B*6j~gJMOZUgt z=L2sJ7I_dn(O^trZcmB!$D(KARscM>&A4M z6_=6Gk~8D_z|2i#0rkDt83q<5q^#Wn8 zsyXcH(y4e>*3X4QSw{-YL!U9Eru+4c6zv)$KEh{n4IW5YDIJ;AbZRgj)k`Upqo*$$ zG9{vDB4xy~E&`>jn}38oS(gz@^ksb(Jm^oNln!Dj>Cjn7`Wd_ono5E2Ova-JI5D2? z=^3rCpgUqk5f^Q|j@P(!w_Ivye6RkU`q}*p^(_;wxBQFM8~C$9!KY-gwh^D8`T4{b z!hhhRtB*}SHsib*+_)6p_u+FNrN95&4=*i*zc3%#HF4yvV^imTT(fJrta3`5{L)>Y zR8cea+)R3*e8=tb-Sg$UZ&Oq52-8GFmnv{F;!LVC@3Uy{(;F0xg z86hn-4e?(fBc3{jz#B5p<=khFWup*b~I!ao=ogBQ7^avfk5Yg-{pBt15JjQhbo( zxT9eggMQYbU&_icPBdulsV|Iv8QF}M*m#8Y*)%ekST`4tLgnTbSgfj>e)QU-6J0rn z*Z;)Qj<&_}>S_Nq|IEJk9((7pS?$jUzcKjXx$nL3-4}jX{iBV4zwxfqv9okOv~}Xp zlF4Ox zi&p^(;>gibd*Ydd-k?0B0~wcyb_vu2ZOzqVlgF+;Ir-#QPUoCbXv=!sVh^13-k&yb zy#fQbu{biCPo9S`2RX^Snynm5CBdX||JLp^<+5t<4g+dF56%$mWCC2Ny%A_y6jMEg z-P8%5&r)HC-NgGS8H2zk8i1$>BPurWZGOIg)KP%I>ENb9i|atC5~AqzWV<|@ACbqn8h1djFFR3RMtg`e6gK+(N4imqH$2-8e%S@zE62cmdA|yLRbBh{z!&9OOOBM%68@+2~KWj&;Si>5on0sRYzxL1qcP;{n@$Qkg;ryydzfS8vA zXZsLxFlN3-CIL$y%B=1fB@w@yb)8S85?C36I-N^2A#~53j&vkPz~<2}jt8i7N-!Nc zary;Le#uPFx=7P%X3&qL#0{TL%<*UgE%OV9R3moOQYXJ;b!3<_RIf_2k}h%5Duaua z#Qk}Vnh^aNt&6JXqmdJsVaNiy=-64zLAZowp5(rso@}6}2NDE~IS7Y(dcHWUCd?FX zPmh+0g5P=;b?PtBOQjcaxnf%r=;}lCx=b(9?dU0b5hfH=iiXVNro6^Gc)ce5(&2LZ za+OlehQ%%07dP!(tZU4b)Vp^sS2pL|_(ES$R+;ls$R|~8%K0f2kSaFjf)omY-Cv>n zE04(T-76la`$>5vQ0}f=+2M3It_0lf`jt}IU7hoI+}oEcTXJrEQD=2?&PySmRI)Ya zr%*r&l&%C3x?ApW3-rN#jiQ_OW3v15ir6K#I>85Pg{#}C`85Z=E-e7{0n`TT)B!nj0)Ac(qT=Ln=mH>~NLEe-uWWv{}^l7>dFjl$ee);#AcVs7{}OfTTEm+GP{ zChtTrJ6gM@WfT4X1Jd*_(u-{xE`$mnMwk>i4a1PW6#>zNfzWC+&6{G~88-r2;RSbV9bU=Pi_N zne!E4UH+eYID&SH_mD8jx*iI;kflOjr57zv7w|uc&HAhKvN53k`}k>L-M1*|59sv@ zz5bAr{QBz@o}kwxz4ACNkI!hHiXt_xkzW4+e?})>uSqKo+1<3_k=G4d%fkxz+@ zd`fKOQ(_~Zl9h7Vt=vT+g@>e5#pj~78VkROdttcCVAByY7;nfp^6@Y7T;KWSU7mA8}iIV}Os2o+dMY<0nyI|&uQm^m1b-Sdn)--1<_4vU87WNU;w=|VtRCgR)+mURUsZRpKHDlc{fR~z#ryhVI*_*lCl$4YTQpj@ zPjGOE>!~D6s%ePwT;gzQ5V~$O4Q2SMCR>DD!|HF=uBXVE03u?$DAIf_giD9Fk=iZujb4A6k%(mqjzWodA*QvrE007TuuGd8$lgEZJ_M}Nu3Wo~%-&i+Xx9R{ z2fj?STq8!rTCx^$DJqPDmkyS!IgEv(ZP6=G6#cd<;(0LOCY9jrZ|*{?cP5+`8`Hjm zF?DDffgbwb+siA325qz4x;j+Kjak|IDK!Yl`tw4XUr9aIU+ zu`(zDSQ7x&r9TR4bWaYf5UC4*`3>&3jr8QnZ_A zStqKgm(i=7UL^eJA-v#4<2AvY`MsexNAasc!a&m z6^p_q|4l^y6o1ARbQRopw=DTWgfsRQm|$! z`tIIa!7YoSvZ;NOpPxLujKIT_rzQ^nELch!jlg8!t)6aRChbHX+E@RCVDG`X!F;t5E`kx3jul8Y;2*t zWy1aQVB^fW*@tfh!%LNoGiTp!n>>7{q$YFc zt1=7>vc>DMv)_k#4-w%RMQ9z~olNx!iikCcf&~HcT1^W`fzi%eiH+OfE@)esrHK|m z;)Yi93u*#>Ta*P@Pp5s?#9GXz-rg2_Zwm;*TciTakZfWC$_^Mr1ZTfj|4i~?GIbeV ziE#GPRGpo|sK-tBVk?lP+Ma}yxDx9!>i$!&kCEa3mX<^l$qW_<@w#=gx ztgY#SFl<0K1%uKbWsNQwNFnC@?x3H-?|wF?be&mh+7=qzKBC0+ShU^ZW>@hJC;_j6^<~+^+qA8bCxR%XzYj>#{|#P%dXhTy zKcm;5Q-rBd?V^a&^tz7MYRyTujFzRqJzFQl@Dzdl=MVtcZ#NsFV2-$Myz-nB8Sb$9^ur?AbMvXXE{uNIG zUl(HdxWEm}68 zP#dt=)EyE}X^ghDjf~PD4~iO%Vsj{Zt>ucx9rfl@U5mJ;Z5LpD;Ift%Nh^CD!A|!Kj_f1iT zmbXRBshE1;IlF3mp4;;CzY0Cj))%4?g=mH^_s66C_Oe+mttw<88d1>tMP-C{H1&pK z$vcilZCNbiNxNra4Q<3@;W`sr(V!V~<$VG2NXpDhc2CG?4Fv zJ}TqVFOL(OzEoCz_0r^}#Zdjb`)7||*FHS{QQr^0aBJha6{n*-kdqw#0Gz?+NhbH9ZU}*ffAPS~3 z4$T$VJ$9fAq;LgR;{C=1u33eZjE>3*GCx;0sVh zO`2DC4v^@y=CK%SxZRuMBo}))i%SExqB37ZgXfQxuUK11UsF%mHT*XqKTs{ekHXxo zjBS9T2<_3)2vb{!(@W|I=_)K;n($=h+{A8~`avzu8HF}O05IdwDB( z0yXKW3m{-h%!sN(gsX)nfGTA$XB0}?+T04H5`=Rsyk5cj5FPpNfBQG2uHnol?q9#q ze2DFAIuQZmfld*1ObdFYa%Cn1${pzK6>QYw+h|6j>1}9I=tj9dkU)@OVsZQFpdBhB z#Gl8wVkFcGjf4*o0o58HaB$s)3(^JQNsLyKJ;x43o;laqy5AnulPYG;h=OwH@sy$L zhQPC%{dfuMF-^};BWXBO!x#En6b+|bkbdUq8Rg-<`$_EKPVn!2542#OqlsbC9u;Uw zpEY%lD93%rn2A6Of&i*%AljM-Iy7j2C+IiVg=U0XAT=prZ&UK?2ORbGp6cj2_V{6I zU@eF_Of@qjaOU*c6VK6np5fDMjCJ$aRWJ>vmXc&PYi_NM*dQbzXjMPRgiqvBbfE3j z;hx;iPx))OEZ!UFFFC_i>FZCs1h;H~@23Fz9*-CF>) zLQWF8Q?AeIp8d7RDQ|IT{lGhklTF-3VwuRP4?whvJAi@`bCe`G9y6BW1AV+X%mf0` z0@Q(8X;TfEd`;1wkk>Ry0YfD~PT|o$M8Ivadiow1AQ@o36$ok-0 z&m5S3ib}A8i*#E$S;_S_dOd(w)+3k~NciNDlJ#00FA(u{B5(YfCSpgH9h29=rC~%ySD>yC!^ezN`7&qqn@<7OOT+KXL7e_xIl3 zeqet4frae{zwckDIyvEkuSBSN{B+JQRX0+O*+=JE9$%||CAZ6T|Cx7mW&KHeu zDX77=?B$CL1oL4l1R`b1La?lvWDVrGSm`1JlMV}5L=J?|p&$Rhuj4)?iuKu*C)9bO z|266B4r?sd_pFq*3HbmiLf1Svht>?(dHgrADTL#ht4MfQtAc7S`tn9?$6nxi5!BTmSJ z-!i)jdxGG9o>ZgC>9fjnmT1}A`*Pc<_<4vkBW)e|DX`3#ZD!-97St-OG&4yK7uFK# zOQl-RtKbK?TQGlKS(PlNy={H2-=Z?h>eH;JRG1Ji6f}Ie{l#bKSp16zz<%flU&J7e zz*hX?(<0}Ks|R3LM5f%|zOqwvsJoyl9%0_-V;OA7+`>tg1UEFqu6ROUja9WEjHPu3 zGe8bVhq+b+JmkEL#UF}8#}FTl7FO?bZbTeA8x5;zwv|^41|iw^uceAIHJ7!Ld39^L!M!0fYKw$iJ(IJb*bG6W0o~ z3!50PLaObNVneL@3ItCt_h4s4TV+2|Sl;o2K7p_nET>j2m!)#9lE4gMK<9 zXXgM{pfXDUu=&*bGz^){UL=T{x|8RQ9J4S5SBQy$)*oiorab4lwrhneY#9ngN5sTr zy&Y%H9O*dMkqw7ACPaNwxe)`Fy zqka??+Y8JL+toe~{G0WfJ`zGf`je%cm%@-%Q8nFgtzmlewav56g^C>$p2c9r#KEPSy6I=HJ$t*RX}+fEx^tnXWukMb ztm5kB$;($WlbM-La7<;bbH3J3yp;vD#FWd)Hk{N}6RpP%^KLVDlO-OJ zHwe0ccZ81dz@>p~^aYKf@2YSLF$rKQ$@M_mEHLEri0ml9G6{!gabE*dXQ;zt@Y6}g z2URHe;1fhB3RE>IRJOtaA__4f2_b>BvqIxdgMiWtXCr{kghFl2VG^2I!j90n^Bi!` zXdX}j`~#@R=suaKaAGhHTN6Y^5+#Axuf#2T`tRZjY+f{?na;rae*)ALS`*pDadhK) z;IKV{|Cu%+DWBjGT(=n>!65;ZCX>y8No*U71K&h|ZczE1j^s$Vkb`RC2WQQi$8h(H zCMBG>3_>n;?l9vh#@6$t5%R0JqeYX(rYLd z5}4x0AqBU$)c#6x`D=d?+OP}_CUDfu&iD4bv*%{nP8{RE>y*lO;lLC!+%u|C&8rQY zq_6usN}YeUxx?@L*zZPg6+qZ)K=Njxy%uX>i$O>-pHKD5rWrAz1^3th99Mx0duMMh zGU$SHtX?#?%11kMEi-#=p=|e@Z#TmZ`RDS)zlydB{ByrdO}q3TQ7rq0G*M`rV!dl! zbKjsO_Rr4)#Re3qL*p!MpKE~k1U=-%GK^h$}AI({h(3n(U3zRh%)Th`)^l0u&k`c}O-xfRE zY2I#)q=^|Xz_tW;zFgkvh((vH$<>gj=%YEu7qG--bz>s!r z-`HZuN%Nkt#b?2i=EfZN=><7ktaI50o{j1#gw(3%zi z3Zq-I);yZus)2L>kVS)PJ3!+Ikw1_pL1Ln*L6|9F5HcyYJ}gwgpc%NjWKhV2NF?r- zZX98nLzc0K0$ZwOJ0oLSS|5QC6FN9P0EoN5;L;G&3T#(GM<>`<%V~mZf!~`@thNq9 zB}vBzt=^cmpdDy2agd1Q1JF~tLQJ^P6clBl2IWB{?b?Mn#M}wF=p~!L`lFj*|G~DW zA=rW$pc~6XFE6BsU^5LTQx;kUS4+t}Xzo5q$b5Z_n1W8&x&)2o^N^5dE`!js`Y;Yj zhHRpwXeT|SB~Or=F9N1R3|aKIpfEKc#%lWA5?eqwbYR@1VH5^%!F!0=A-_yf4eMQ9Sb=xm!922=hl z?p-jUv8U%Ckw@XI2oJ(Edo7N-BA8(PF{F$JY#3LXq~Hz%mv%#Ty0F+=|Vn0JKRAb z)@DmDBvR*bT|{&kw@O`#MNL#q{HtV>{DX+4%Nudssx*kJu4L%~9cqzq85no~IM>J^ zYy>v^{MO2CTVaYC9QUokw)k4@;4EE14RlW-)YYDh^INuE78jIxjmnIBfV^ebJo&P+ z^p=J^#SVVhSDGQuC6|=JogIbO;d^ zc`m8CVcBw-tT3X4Er}eg33n5z%xka6G-(NQqT80II4(o7B|>{BpoTc%p^mVW7rO$% z5%MYQWssri@&FK|f(f|HYCA1u;VW@gfskA~4uwD)4B6L0eSCZdNw6Z~yb94jG2~SW zGlK4R|rOJeoL{z6;U#+Ap%=NDiwb8E$~v*W@MI@w zfu6;OD4HC4gkmg&gZ-p@>md-)e}VKvgyW|XfM#sJ7jPBZr{~AsBq&OpEgLODr0W)~$&)Pqx2=VtY}H zCw*WOH|Qo$Ktv^(^lqaWur|^Q|-US1GEp;M~5I z@O7&4WqSQw^d)amC_rxGA_TZ;GKU*T zM-K6A$0ttXieLRpRF6;a75|kQ?V=Z%goU3hhp5F-UpjIQ0Ec33ar*(6?d-(43$irp z8G1cQFP@ZQ^?Zj?d3r#j zLhoM^yOGDrTarURUDfEQKLKRSxx)|9l?Z*qxGNV|BIv{`WXo{I1n2X`mBP4F0oxca zc)y*G3Ow!SwH)R0$vQA_>HWaoLmi^{J(TBMR;+^G<1*Yg5xq| z&*UR7d|E*G)e(so2V&Tlx{`|$=7R49ADO`w+|Qpm+H?5$(ZioV(RD0aA$kF10<1*z z7f36OOGVDmHGgM^Vo|-C>o|x0d;y1XNc0wJe$qAbMY4J)g^ttfEqZ;EUN`9V0lmmS zPdG1-`d%m93$vt*v(~6*?)eS~Cimf(2to%~KE4NSDw3RNVD64{YZn1t-E~v?J#bQZ)&PjpgKx58L0WhillAM== zKHMac^K%dvFV%@6@V@W_R!S&#rOWA;t8No|y7@pDeYO>*^OX-Ce9?=mvcZ&c>-uXqu 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 00000000..51fd9bf3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_termui_impl.py @@ -0,0 +1,839 @@ +""" +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 shutil import which +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: + import shutil + + 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: + 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 + cmd = cmd_parts[0] + cmd_params = cmd_parts[1:] + + cmd_filepath = which(cmd) + if not cmd_filepath: + return False + # Resolves symlinks and produces a normalized absolute path string. + cmd_path = Path(cmd_filepath).resolve() + 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=True, + 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 + cmd = cmd_parts[0] + + cmd_filepath = which(cmd) + if not cmd_filepath: + return False + # Resolves symlinks and produces a normalized absolute path string. + cmd_path = Path(cmd_filepath).resolve() + + 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" + 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 = 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 00000000..97fbee3d --- /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/_winconsole.py b/venv/lib/python3.12/site-packages/click/_winconsole.py new file mode 100644 index 00000000..e56c7c6a --- /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 00000000..f57ada62 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/core.py @@ -0,0 +1,3135 @@ +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 .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 _flag_needs_value +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, + ) -> None: + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @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._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @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: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # 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)): + value, args = param.handle_parse_result(ctx, opts, args) + + 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: a string or list of strings that are environment variables + that should be checked. + :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, + default: t.Any | t.Callable[[], t.Any] | None = None, + 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 = 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}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={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. + + .. 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, + "default": self.default, + "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. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + 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]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + 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 option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + 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 + + 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: + if value is None: + 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: + 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: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> str | None: + if self.envvar is None: + 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) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any | None: + rv: t.Any | None = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = 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]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + if ( + self.deprecated + and value is not None + 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) + + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + 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 | None = None, + 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) + + default_is_missing = "default" not in attrs + 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 + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + self.default: t.Any | t.Callable[[], t.Any] + + if is_flag and default_is_missing and not self.required: + if multiple: + self.default = () + else: + self.default = False + + if is_flag and flag_value is None: + flag_value = not self.default + + self.type: types.ParamType + if is_flag and type is None: + # Re-guess the type from the flag value instead of the + # default. + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = is_flag + self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + 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 self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + 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]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def get_error_hint(self, ctx: Context) -> str: + result = super().get_error_hint(ctx) + if self.show_envvar: + 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 is not None)): + 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 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 + + @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: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return t.cast(Option, param).flag_value + + return None + + return super().get_default(ctx, call=call) + + 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 be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + 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, + default=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: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + if self.is_flag and self.flag_value: + return str(self.flag_value) + 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 | None: + rv: t.Any | None = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, Parameter] + ) -> tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + 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 if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + 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 + + +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: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @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 00000000..21f4c342 --- /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 00000000..f141a832 --- /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: 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: 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: 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 00000000..9891f880 --- /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: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + 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 00000000..a2f91723 --- /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 00000000..a8b7d263 --- /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 .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + 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") + +# Sentinel value that indicates 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. +_flag_needs_value = object() + + +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 `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: list[str | tuple[str | None, ...] | None] = [] + spos: int | None = None + + def _fetch(c: deque[V]) -> V | None: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + 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(None) + + # 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, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + 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 = None + + 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 = None + + 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 + ) -> t.Any: + nargs = option.nargs + + 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 00000000..e69de29b 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 00000000..6c39d5eb --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/shell_completion.py @@ -0,0 +1,644 @@ +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; +""" + +_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: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +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"] + 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 + + 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 00000000..dcbb2221 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/termui.py @@ -0,0 +1,877 @@ +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): ". + + .. 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.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + 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.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.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").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 00000000..7c0e8741 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/testing.py @@ -0,0 +1,565 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +import shlex +import shutil +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 + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + def __next__(self) -> str: # type: ignore + try: + line = super().__next__() + except StopIteration as e: + raise EOFError() from e + return line + + +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 "") + val = next(text_input).rstrip("\r\n") + 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() + return next(text_input).rstrip("\r\n") + + @_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: + 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 00000000..684cb3b1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/types.py @@ -0,0 +1,1165 @@ +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" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + 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 00000000..ab2fe588 --- /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 | 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.1.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA new file mode 100644 index 00000000..42ce2131 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA @@ -0,0 +1,89 @@ +Metadata-Version: 2.4 +Name: Flask +Version: 3.1.1 +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.1.dist-info/RECORD b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD new file mode 100644 index 00000000..f09032d3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD @@ -0,0 +1,58 @@ +../../../bin/flask,sha256=7bRdYjJagfMey2U9CaXcvsPTqxtij3oXiaBLTv8_rK0,251 +flask-3.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.1.1.dist-info/METADATA,sha256=EsnOyVfBXjw1BkGn-9lrI5mcv1NwYyB4_CfdW2FSDZQ,3014 +flask-3.1.1.dist-info/RECORD,, +flask-3.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask-3.1.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +flask-3.1.1.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask-3.1.1.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=XGqgFRsLgBhzIoB2HSftoMTIM3hjDiH6rdV7c3g3IKc,61744 +flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541 +flask/cli.py,sha256=Pfh72-BxlvoH0QHCDOc1HvXG7Kq5Xetf3zzNz2kNSHk,37184 +flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219 +flask/ctx.py,sha256=4atDhJJ_cpV1VMq4qsfU4E_61M1oN93jlS2H9gjrl58,15120 +flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 +flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 +flask/helpers.py,sha256=7njmzkFJvrPSQudsgONsgQzaGrGppeBINevKgWescPk,23521 +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=Wj9NVGtiR1jvkZ9gSFd91usUlM8H0g06aPVz2sMh4bw,38116 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=q6wM4Y4aYMGGN_Litsj3PYKpBS3Zvut0xhDmpBEHFdo,30387 +flask/sessions.py,sha256=ED_OV3Jl1emsy7Zntb7aFWxyoynt-PzNY0eFUH-Syo0,15495 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=2TcXLT85Asflm2W9WOSFxKCmYn5e49w_Jkg9-NaaJWo,7537 +flask/testing.py,sha256=JT9fi_-_qsAXIpC1NSWcp1VrO-QSXgmdq95extfCwEw,10136 +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.1.dist-info/REQUESTED b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/REQUESTED new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL new file mode 100644 index 00000000..d8b9936d --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.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.1.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt new file mode 100644 index 00000000..eec6733e --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.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.1.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..9d227a0c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.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 00000000..1fdc50ce --- /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 00000000..4e28416e --- /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..bdb08d9a24046d843206559fb9f3671abcc70222 GIT binary patch literal 2537 zcmZXWTW=Fb6vt(ACB}jyKs`XV*!L zf~ZiXst;9L^#MLYEBa0P0_6d;XeA`t2i_vV6Hh&7>?KjUTK)Z-|CyaRbCv(fWV#7F z(ba2>pMYLrA$%fjkltj09uSRal0i&~N)mF!h|s7O)nZ1>jMF%HQ7vvH%p^?;P8cb( zi*^Z48r^1^rUj>r9y3ETg1dmTG%L6pI7f4W)4;v7S8$KfXZF*6!5QE@%?r)~7id9n z4tRhL2<|lo%^^A@xDR-k4h!xF9-$+G^T4BYRB!=!jE)H&03N5~f(L;o=!D=Q;8XOJ z;9=lNIw^PrSf;YzQ6p|n(J8@WM$w$6(}Kr=XXuRJ3E){eEBF-f9Gw$930$Hj!7}hX zofkX>T&88gMc@UxAb1*hkuD0J0X|Jn3!XKW%nGdto&&DZs^Ajv8G1(WJn&h1R&d!^ zHdpA1;054w^qfRkbbCA80!P1YTsy5TejlT&tw<|UUV4q8vgD^#%d$Py({0P$crCTf z*tTn15R89jsO}Cx*QZ94Ib63qC?wWwtFCVW^{aJ{am8!suEN>3P3B^Jyka=joPKS*^ZTL{aK9ffsC0*vakT|$;b<^h9c)SiN zHvkG-%u_^xX^III)h*_NKZw4^Ovg|?rl_9B_06WoAd)fF9R^vr4$K7_Db6&Vvl_PB zbik}e7nGHQ)ySQc}v(HXR4{}>0aa5D3VQXD0Q1djU-O2UdPIPFs9C&D30wo zOgm{d-G(rSj@9&-3ahZCX!afsdvKFM!m6c^^+!ZpnS;lzavfi-x- zI;xz!`F^LRZgv){h8s70;s8-Xq&E)%9*_gL_jcw9;TN@tMhtRS62H>j$U$Tq>z;VD zsFw&WE%s;p5wwMmL=L3wRGW|McKUd!&06A7C!<@$%Y^X*61w-La&p5@E6Oh8xPuji z<86KCx7!USmyX#b`TY)+bywEl5V9I4u$9+cDTKGuo$Yr=0Zr|KF6K+Ecj&3+wtZB)|VkCu`{bt9Hmwg&q6JPS1Y!a(EWk zIfv5{^<$Q5GQaD67kn8qadA0hS$_9T6$Z%Ns&2GY#|GJ{-r)8&4AZS{s;*vB*goSm z9WIILF0*#4Fy5-u@*1|aQaQU^b#;#|IWQ!=7^-5}RYidl;3-PQY2oU?Re{qFt8)=L ztzz%DK)xf-)45+h`a3PZ=$U=dGxoBl@bmQ_uOCJteOIKn3DP(Hd~EzMO){fzNg|Uy z%#y;yv;6Fn{Oq&*(v$qs?^{pvtB-qD|H+O&y!|v=e4Hx2fo4fL#y@}`KMH%_PjCh+ zXWfZ=mCIJEeBSR?lzI~v6Vkys@DpCkfob+7&nFx=vLA(;g5&1(yEnrN+vQ178SWam zv^j2IKU(wlc^44Je-9itFz>-Ya?7wcRm0`DXL%MShtey84Q4nnBu7-a-y6lDy=PrCY+g^iD+HGy&pWfDb3nL;U|Ory-8%!2scotpuM%jeK7p}?Ug zyo~YG9*3c0ZVTuwqL;b-^^J99?b`a<7oTrj6)X4$;g>Le0pwlkl4)yAgMG|5poquS z{T1XeDoIj6imyojzhpEZlL4s&WF{aV2IP7`RswP{Ak~131*9b2>43m{IUwsIS`Nr! zKt2&KRDchmKD<{&g|&d37fpe}C*WTQ$hA=C1G4Zknfl@0{d;d?+4%HfoTP?C%Krhl C;?wB> 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..ada417b7917d7872112afa203acafb6b3bf63393 GIT binary patch literal 245 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%0DB|#Z=JK7jA4u8{z~OGBku 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 A>;M1& 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..74a0cc0c18042bdb585c3deb45e4452d0ad82d3c GIT binary patch literal 16256 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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..93bb4520a05c6342c9c181eb673d0590e7e22ae1 GIT binary patch literal 9154 zcmb7KYitx(mcG?h{qFX&?QXCk#lvx$M|XJSf#X03Ui#GNsBg`gQIwB~J6m5u-S+T2?Ha}!PZW~{@HVG zRka^6Bh3Zhx>fhwb6@A2@7#0ycfp{KK;oZ0HuT#tA-~5LJGsmPx9|`OH;7DRP9+(x zpX0FXP#yg|Jb6{fIQyOKo1nTf?tV9vow7^yWW4=eR(7ktjKAN{${sb43HAp$qVU6= zc2`SJ8i2N5wK3Dw-^A#BYICNgzl9?Xa+Jvat3(bctxD)i!EDpt#=ZyPdxO%hwAR0e z+4n~H-UMHHi#j5Q4xf?Inj(wote97&q@sxJuRq>a3y2c#A+ckj_eUOq3;EiZQa2QNi#e5?LvuBoc-%k;vraf{NupBJp-X zQmqFM=WcG zg64+oDtYK|I6bu0u353%4)_X*TM!{%x!fR?4v-5$cF8rLy|70bulSr*~;c= z?lRPg(#oC6D4GUyM)IsUT+nnN7*w(fO(#Wr6!DiO*^(!7my$eA%t}sp!aKL{KTx`eGFh8+-vbI2{xw^N#I;r8Y5B9$>N4La|KbS zY0wQlCrU|B4P1Cd#2pfgzd((_*Hs&rPNMRo;13ko9?3b_PcRCiGMd)(7~988I-}@g zdEfAXbsIM8NxqBeDdil&o8Vn&g&mMmm*=CG2v ztgd8rP-4_!odQ874Z15szeq9)y+I$QB9FlYwV_-=l|@^Clxz~m_2T9=y4{R3hBg#O zorx74JH({5$86bfZ}*_A?1sV#!lAs73yp+~b9$Yw#MvwU58MrahxeKVGDd#Gk8odb zXfOq^F7ykB;fOtLaHATknJCf_JRW&_QFcf3bbm4SQ*DYR66tJOPb6Z!YAz|M+WuIb zz8jir$m74s4-@2@4ZXKFeJs!H`ed-Wq4!4($9<(O%oUINe5hmtG&chFroIcyR?)PE zOaRbUX}FuPoFkGZYJ~xFrF%q!L|uk}i)6S56B+!@1}NQrZk{;ybUf(TJlCNDF8b(ohA~+^=qyKtBYY9KV+~Fjjh*4r$#3mnVCNsby1WRik0*!$P6A@7%r;l z1)4R4lew%CbTB>dHrWn#I7t?=pH)riASk`xE16X+Kv$tc(FJWBv;!+jt?hrwW+ z$rTW;9$1OLH72S2zGNZrJj5Z3=we1RuBL81^jxW|pDG1UDX9GXHrc4b%&_ z9@BOheUep4cG~7scA+9%0wJZ%C4Lwsa8;7sHZ2F>xh92Yi9$#5Wob$%kza#)$==~M z``gm9#M^D`CkF;R>N{BsAGER1G>Cvhh@9QU=el<=FtjBpt!V{7RS+#pq>v0Z7~Gj0 z_>Yn*zH#PNXz1vUJ>uezxC0cop*X>?6RXhR%1SDo1vVpTeF%7gl}@YZGil)84aLMh zbn~E6Re#bAgK;Ty>Y%Z>*Ny!`UEUi)NeFfJ%V>^ zDZ1fHYv@}@*`z{IGYq~!Rl}WCMiN-?fH$qMk{3OWG#Uqr2FGw}1@M$j!?p$4J1JUT zW-SdKI-uK-%$rCgVcj(_!pI&i#RP*W*0Lx*#vs+Pdml8?eghf6bgiLnuA#fy&^^iD zYg|{}^6@Wc8{-vEywVtd(9ktA`1z$zFU?$-C)}Q0wOxDvt>d3N?gYO+1CSFu$j$RS zBGtT)G`7z*Y^*kHtOTDZzg_WfnmPOV`A^T!b@f!cdcNLsx9h-fxoX$T-}qmygO{Uu z=OQlvWCe&faLqU6n|JWR7Z!P^*S83t8m8P;Po&)PN%*7iOzX|gZ#_>kll_IT3_2J< z?1Fjx8GtZ?)?y_URZS!S(hlJ45zAgO*9@E~LNP;!N<%350pUV$dj1q>b9R4EAT!|t ziB^DV-R%7f)F50;tqG^Y%S|OvVjAc0ILrWryXrx&-98eJKgNSEITCd~Ya2+QSY}?= z9!mme&e9kk6^j3K8XX_;;>8vIHAo70RB)clBoY@dqW&@90{xd2ElJaWXO|Vzz4f8= zNdu_67cbg=?HX?F#fvc?qwN8im+A+x9%gK;&atCBj>klp9sn%~eCG6JNmqJUI&MIqLWh!>rg$*tK(XX`pCwz!62xsKv~fpE_0N- zLiG9>3&4T1L2($}q*V!EFtF+qyxLG9lPeCHj643uF~W_IQT|Ob!kG@8o4yEihJV@q z8Xo(MN=2w+&XduA<~{+&KB)}Ai5``x{sKy5nI-1BaSGEYrk1ujny}1KA22NT{AEkN zT=vdGdkr%%RPzo`u=8HH^ZH0NyzTa$yWx1HDgMK~){ck773{3FwwDJ#Q9n|vt=np$ zb>Fo=bvt}#%iZ>8=h}}{+mF;jZ8uI`KefO+!YvQN9rI2{bLaofd!gYYc4GP4h8FVo z-h*xY&1Via@&DfBgkn@+zA5uSnJ-#&>al~_F_`@-Zxp9V4?+e`D_R$GEl_k`G8e*d znc_qb!?%9;)6nVo@hbU~!|UyQNFXyU%nA66@f#cU)bYc;raqVInNpR;qieUZRpK0?A9Zse}# zCi~w?>mQoH|hiO!=J9)AIQ5MHfqbwTt-oX+F^LO5In6pBv z3t$r36CWm&!jA+1bal#+bHYJjZvdpyv6y7 z9VfupjGK8GJ>nxSW^joWdyKXa;E-GBg+e_F0jIB(Q3$3DZXMM% zG>>e^hEp%(RmBik_<@&Hl}*CnA<7I|48zq8VIY@NL8)El;LQ`S^RfidXhUFZQMM6B z%{W8zPo_!-fZ!7RY2QG`CRYozesH+l{{E|Tq3zYs_DbuH+Xugr?>zgZIu|=sjUB4& zJY4Y|`9?T$uf4PUvriHqCFVBlu5Q?Ucf;Ph?aw?U0q5o^@ZBcgsQDYN?Vs9T-ZJao zSPO*i`P-(IkCo5Pl`qWtx8G}RhjqL2%xwF<+17ovrbw+VGJT}nJRSWNn1l@v2^ZWt zEz}~N<#Xk}>CD}xE$A6;eE@u#JIY5sJM>lSSIWPht8D3+ZGHi`*P27q&gnB{=k!>m zVbfjDrtjCmKz?MQmMe!Mht_i|;-Yv61Ovw{%ZNg!2{;aZFz3#|2p!cP?Qt z-Mds?%eJf)7ky{_U)~1#T(URy=qKpv?=1V_dJD!o?jHAydzUc1%p&a$=)Ko%D$U|>@WGi8r5wfM|4y=mP+;GFsuhyrE&k-{NzB%zcP0GUPK@z z?*uOg#{=0GxuN8hy?FQ@=p=^LFA)8q9hBfVJK_>ZwG)u>|C+;=Mv2VgC5a5zrg*2*)_!N zSY(n#Q&_L{8wHzVtoW*VcVvHH;SDvHy9A92d68W{!SxWtHS!RchL8;|*#N9%cCa4c zSXvBv8djmWPZVF1#$beag&?P87Q18DhayB`?A5g|NYaBtunFKBfQG^(ZA`a<# zUh9dQw{fvNz>}hDa0|h1^wLUA#{o!2#ahm07C#A98@TP9>6!<0+rDQg9m{yJa*TH2V7W~ znXXZlan|9US52@jqJ#K_Ps^h;fhCtllevLm!v))p80>*}<{2OwXBERG!}&3-8h%Xy z=uV{4+R&JWCe#uS>tTZKCb;rYrF1r7kA%4zAPtH7fJUKd3I4SI1iu!X=Ll)sG!vN# z+&)+d#47&y#Nk>?>%@s#Q)uFq`|g$x{(3IF4bCca;l0)H-b(nTd!Z-hLfzF+_grXK zHMDEe`(1SRo#*dHdmoY(=k}_nYm%=9yCzf9sd5ToIQ4OI*1x&7u4^VW_vG`{C!eo$ zy-*4FP93`!43}M>d1r&$YU{Sl^nHHf(-SiX?rgsEv$wlQ zan`fH*1mqqU-O2h-~QDT^@=mIp0iLf>3`sEs<=Bp?XYU#0wlPpwrSf;@b>HIbvzAM zAYLC_fp~*B*GlNrtmkx{%h_4axd(##-Q({ZfA`cor=}0%y-Hbr|J1j_R`cxj5^OD; z`B1bdI%MXVuThV^0r?PGKpDV;1!*-n-Dnt2XNRTTG0S+d$rw#=Re7nX6b55fywZ$JE*W6WR9yFSWivK{=iWShBys52kwYh5IeFA*wCXkMXA=}X9K$n0@&18o?1sl^ zIHAFvL{DEw`PsIDA;{h+cd*I4}`$F`-uxZi7bDr{F-F|D4Kw&Wu z;UeY8%>G3Jg~ew(x$bgyk-%eNf0*l9*xSHup5Oc|*H!Zd=6QHNXlR~y!gJo`YIM!J Pu@oXM-(nk-m>m5-E8Wru literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..be1312c4380730f6ebcada741c0b9457d95fcf5b GIT binary patch literal 1869 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 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..392a3185a6f7b32ddf19c652326f288666be323b GIT binary patch literal 3271 zcmZuz&2JmW6`xstik}u`sj#csgGRDM*CyKr@qrbbwvH$pQ5^$TnwEt@uDC;TrR6R= zGqglOPKeZits;QiLn0>#;GT*GMu8stKlEZnDkN+Yz(o?E0eTQD7f5~Tn^~?XTN+?@ z-p;)5nfH79k7P22U<58)Zd@5a=u7$GkB~>;z5f8QjtpdA3pH^GV@Ye4R?^fQCdW~QO+LgPT{=dOExhEf_h%(J*8lb?W5Ad6XYe;^#K786N6V(Zk&IdF z#&z3vgf2|S=2zi6HtSS%>l$;GJKsptuoPkRw{6M=kb$4IT2G0V~&$2>KffVV~;H*HKo}-v>X6rfm?>prq+=LG)IOIW1=Df)dJ@ z!w46Q>P=DuQgQ)-7YTq=OW4i&!nH%(FIrpO<=ea59`IcT?)a$^Z{LK4) zwmNR+u&*o)cICqfyt?SW$5Ax>d3xmDJ8SRUzqOG*|0sI?t9a^OVXg2eILwm3RPB`< zkO;}^sV?}Rfw-fsqgAwUa9{Gk@Jssl+A6w*S23FsAmxp_S`8ccc61dl>|b_&524rg zWgqtRGThOC_lR=f+5qYVU@zL2_bFu+zcXoU24$kA~9>S8sO&08&4YE1tg}e zYNVGpQf=sJMHghrw5%SRWKoA)hdQxkozy9t;H1!`qEV>OS`7{jwunV^{lnD%*QCCkO$rFky9GDj~<_?QCXef&DY03xgC#t>3jT=0WCFt2HgClUGpuVakf z8xEol`fFebXR!pYka8v)aJAeI-AFH9mH}xlEfLaXDVU!POx3APms{-O%2-3^WhGYb z@#m&234#1#Zl7yHY5=R~+kc~PyXezY@h=m1m+swKyY;8gKhxtIsp9{*Jlfx#7{znN zY{(rv6uukK?T#Dm+2HPgL@>P$28(_8D_-0g z`p)C@$ab21nkGAmK@f#k2o0TF&;2oXH}WKn;+fqHEUL;_x$v9uNu9&NH))pNAmfuN zbG9x&<-Ho8Y&u5Ug0F(4Dd$kAS$^ou;WY5x6L1$=#(p&&)h3|Yj;I;GQsB;`qw0kH z;OH9Rr(rz~W?vWwT2~*{`6sywjH`zK`orx&Y)gVpD2Rqt|)nK(5CtQ}31SyzC#8aJkUK^MWn} zD^x&v&g%tb#XjZXyRw{(D`<~B4LEu`n*MrbA2>4hdW%l3S@X;dJkq5+VpdXf}x>fo+SQ8wmAdV=l%RQare zJ2xov=!R6DRMomsh;UW{pBqx~t1@+C;Phn=huyS6YkJ!fKJa8U015cB`7YcVE`ON_ z@oGLd6Ba$EV{vY$FYDz0ws&cmt1CN;gvn^#>(Yd8?@1K znMoXG60Mm0EqBAB(}FW_v2asMlr65%b{+ma0DqaRdpArZWmxXy3I`|CzGa(%JTH`oP6#EurpFu0#2l;j#5zO4(yXEp-dLO3f^lG(J2qf zF0u=-Au)<`c#&!VBpKTK?ACN?q?k0uM7nV)piJ1D)4MmNytPH?z8vmG4X2o66Qxw;vA Q<7q&{+SAxD&M2q;570eLp8x;= 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..7e7ed2ead19d1ee222a8f8832f9ccce53b4eb03e GIT binary patch literal 17186 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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..eb518e9e42428a687c205ca428a2c0dcabac9c93 GIT binary patch literal 1226 zcmZ{jO>fgM7=WFobX~iWeRS(KK!bq%eK_!le?5(#Gwwrb)2fvG%~m znNv^IPCKLB_#0d-kHZ43UnAYz#3T5fd>)CL(e%L^dKW#t;(`p|x|xi@(I- z6&02>UDqQfu{{^_>G-DEgxEK$urozq(|1e)O9;9aM9}KYRbb6SGEkC0M?>&k3u02j z#6*OHlQK}VT^n!nNM1$=G?DGrOP2TE?abCa!qX2H!@Vl>#YQ>>)Ay^MOW+>iMMn6k zkr#fepZHA3^L<`R;|kcU!&1#L1+!V4WEsP#wMYv=!$9I9vayO|yA6m?Qq0l@w(G9x zV3ryTSfp=AeKyn|1`Mgsq`ooKXHwsg`b_HcMSUGZ=rf_uv-S0jNS}@9pXEnfje$Np z6YA?Tsc#JRKZ6tTu}|OXZ!knyx1F}>d%SDtuaUO{s|4#66Wdk31&FFPhFIT)?ym0G z72R)>ZO>g@xpP;?Hopt}YBc!KVqGL}@L2!UR{Zv9`f<~(OcZ=S55ab_HFcmIbJ6bwiqQz&y!gC7d!s*4H-qq>y zYA}88KnrIs^)|X2^!oi^W{rZ$u&~tI@9xu^PlCca1^ICP>XCM+(OVnA{8I{M!^Pzz b{ZOa3Uj&OUDJX>J%blN(miwroJm2;|Pm)ou literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eedf0b204236d58caf987fccbec9c67d9e2be3b9 GIT binary patch literal 9936 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 Dl>p^v 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..0f00e6990471c255fe48d44957da73d45fcb5eb2 GIT binary patch literal 13631 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 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..9e8a87532283c05cdb5d0e7a55ab15104c868803 GIT binary patch literal 4134 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 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..9c9e17352768b077138758d809387de04bcd3fc6 GIT binary patch literal 7025 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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 00000000..1232b03d --- /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 # noqa: B950 + ) + + 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: # noqa: B001 + 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 00000000..b6d4e433 --- /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 00000000..ed11f256 --- /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 00000000..34ef1a57 --- /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 00000000..9b164d39 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/ctx.py @@ -0,0 +1,449 @@ +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: # type: ignore[union-attr] + return ctx.app.ensure_sync(f)(*args, **kwargs) # type: ignore[union-attr] + + 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 + + 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 00000000..2c8c4c48 --- /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 00000000..e2c410cc --- /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 00000000..a6b7e150 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,634 @@ +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_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]]: + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/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 | None]: + ctx = _cv_request.get(None) + if ctx is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + yield from gen + finally: + if hasattr(gen, "close"): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g # type: ignore[return-value] + + +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, # type: ignore + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike[t.AnyStr] | str | t.BinaryIO, + 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 00000000..c0941d04 --- /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..e8aec72e5cc13ce48cb17d3930bd739d12979361 GIT binary patch literal 6697 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 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..9f877b9b31c96114954a6cd11de88041970604f3 GIT binary patch literal 9264 zcmeHNTZ|jmd7dGM*X1tvrbxS%ozW%IQd)5w=l}onU%uIY?d^?ANWuNb=Kt$)N%{@Fcqt?b^4dS3a7EH3 zT`ovPd0LjK94G{)1N<4B4)Uimt?*}PI?SJu=?H&Dr=xfV3$bE+I?l%`g`Q$!Iw4C& zcwy9AuJvRI^bZyKipl9D`iJ#Mp}#mVJs?W~=_N^zzAfpon*q^(dQk7x<8Ld|L%gjA zZ3$!WX3%XNt_D(lpVLc9ZuV%UlI3WQX_f3ryeqoq7H-Ie9FDZF2i3~5@{CD1|!9pZWbdr|ZrJ&0#WPv{DsVeB!4XGHJQ!+1tx zQtO|d)FY^i>HRpFG99nRQUlGzw@$q>d6HR6rfx9pU$EpM)poR!t}$J;4M(+RRqCQz zWwi4Xsk0VSwUVlp%LOyf>(c6}%1pkX*|uTFRV0jZ=1p78qu-37R%}C89ZStuY{x2^ zHABofW6WzyCT7EbbWwG4cGh4<$>DSGWeesE)0k=4={T>PvQ)EJE*M4hQZ=>g?p*9i zwaZ4{oHg^R7*-uuZFgT{J2RSX@M-v7aR|MAHb*TOn(e5WqT$SEa(bm$wsX9bTT`$! z-Oi=eLxqAkr893Zm3mvct>P>=f-$RA3QlWUL9^EG>6}{Yr2YxURm0@d`8&?#j)J0# zIk5%sg0Gp;9EW9c=Vz%c&3mL5Y^#*@NRj1d%MrQT=))_=iO?Mrfs1^+da!fGXT=;P z)hv-j3xF7 z?)~AHDTo|DdF?5FmmHbbB3o$hD&hs`?;5aoWb-Cd@)rD_h7GCr&bJ!N@!I1VquyXN_|P%bU106H7*EX#!$9 zQLaLqN>8Tu?whbp$JkTW@{8IWdT{W>hwS=p58 z!4KrW^aV|ps&Xoz4P%<_MCN+vEQ3Udn>}k5yesfOBm6AgSe2$B-ChFGNw3oiL~h48 z=Rm8^Ta|*&bu+Q!^wiNkPx%a_WsOqa(s_T2xVHr1&|R6JW=gJx_}}q)689^_PtVAX zrxea#wh85CV7AOgP_Pwbw4&g!LfotkJjCF=)Kx{cEZy&yVm%k5??f++UK+kKdU^Ef z;gx}1*Y+d(b#%Aj`d7al7mpaenE#gh0ePPSfk_>6nyNEZhfEypp3?sb&DaJU(z^+= zEoij<5^#goaS3?cGZ@Mqql}AwI}ylR)!1f{Ed>`mnC)F2^*^ljGknnNtC_4X0`CdEQClX1)byMQXF>%r zE951^&k|;OoSP74I2DH0macJqFV~~=q7rytGvukjZ*%6k8DkZMEqz^=j^R=BzL$8Zn4hycMv3?tfca?3v~9mjzp!BN3CgfR$5 zzLNVi)f%Lm;9B=V5BfV<2nQy;gBZK{YLP`$Z?i*X_8@oPyeQC9C|ApY4RQZ6AAjWxn%?Z_&%TLf%(#_$^`L`V7uLG7AI+5tbIo7tg@weD|CUyhNvCVcJCx1qCIo zXk@d^cs5(K^h$xsiEQ?}6|La5M6y}k%4f5Tf&vm-Ycl64pEcjEYUwzzRPx#-)FK}7+v<|zJ0+f)h1K&FYF)bN_C2+J6wS!f z0trq>ayUpul?#cECcMu2iWe(Ue8JPYl}I9aV!IrQGk97c0(Yd=D7K-k=Ws_iytaDc zBpbc8P3TAgD=-D?FydS@q65DvYK3Ox zh+9x96;p32r%xY0!VXZE9*R7n}U;_3$O-%7zQ=u)f z42l5SWXmSmaN~q%*2Qet2~-yFvww&T(Q;(q(v}}j-HMFfO>Vk6@NT^kee6?SH+RLl zY<=K-Sbe|R*s%9jWZ&K7;HACqE?wyTEHe1xKfS$iVrApRNAj(WXc)bn+_I9~a&60M za(g4X{nJR_h3{V4bu02XA9E#hIrF1~t4XyHRX>dnU9vvVukZbvx!XJTuk6_0_{M?8 zfs>8lKVFT$+E88XnTco02flFp$) z(({VkFwusvno$f(xLXQC?Ot_$DF95|Jy!TZ@sbq8Lh(Nj89Wd>ixQ{?L2uKth zZ$k_#WDwPp9NE}ut1}g|;OsF=K-w%llOwl4coJTGulf!R`2`02fkMGLOLG9^@r*o& zAc(JaM)(4IU_3n}35|vWpCs)STp-VNcD!2Nj3y>vK{CI-t>!31hRwo%d1~Lj9Dpl^ z9oR0M1=*&Z+0e3NtEqf!YU-qK$!P`hV~Uz1T#WYJkx-{eraL?e5!#D|9v+1$J;|qi zi!z_VM@{_YUB}DshUikzUd*Xu@Zq&mb)6Ha!4LATd%Nq$ z@z0b1_{f*z#Axs8LZo!MIY7#qOG>em+NhI0j8UW*&ImjBrf2g=A#gl(YO>ZdV_5|l zU$XGcNZu*}7;{(}^1KegB0bVWcjDjpo#>9t=yG?5+|#HO@pN)UVddS+$UGq<7#TeZ8dIUk;X|NO1!{=4v+2{G8Vk{rACHDrzGn6MYV zmxOivyFs_6-J9wTg0GV~x%O9&1ZiA+M(8aHzFauVr?AVx-x2oe&OMG#xmt{*1Nh5n z97njVTToihgKenk&I3Nt-_rns5joo1Kg_8JgT3P_5SJZ|=ng?e*Ox>;NuuzahyUL~ z?N}We4jki1A4HfWlDpO=%whPRafG{zr(6$m*-;4KgVz}TDd|lLD?8H9Bi^cjGNRh|A*?N}MoQ)P0A-lKwWlz( z7muo5`0Gon_oZrUXRy4LBPcG8ke}B|b3n}rAMuB}8qJ#$V(K>mUT|Ao+r=$6KJsY= zo1g_;8{L?x%&G8+404@~5}8CDws5|sfvt*Dt`I0AKBfr=!x3Lh0Knt>r3vi}LrZ96 z+v@+1k-&C*C5+@~Gi>6sQ^{d;(Mk7{)x$?iI~8~!k3Wzz59BzTKpRkmaXi>b$~b5e z;v8i3y`Ir`24NWf0Hst&e6iqxJCE7lHYsP)XCf?N6n57(ce5Ry;QkYO z*jJFje5hT3lpSLiV)qjL7f-x%qLENxR9=7o^$)Xuo&Ck|uQva3^FMD`d3y3rV#Do( zx`NhC*Z2N9vFD!uzWI9XRw4rwv<1f8NshR6giTIn zvu%G$0jR<^yn^UNSwUk`^PFbvSt=1UA<&9RDp6L)&(0zHGoTecq39Q*((VHvom<`Y z{PIhU-kqz;^Y;V6Q1pIW8s4;g!YdDKSU!F~prAe>ZC00Gx^QMy`MTHGzjgW89c5xo z=?$gUo(P9_e%U`7a?edm0-|~u4*@fAc!q$Q)CK}&W-Gv90m?86;@DBjUZ9L@Su>2V z2C+s{cGwZBBo*6?Qb<8D4G)-`y=M)!STibfY5J=Y5kL1%y?*k=?BQcC9)9`w zeivIS;S;%!+H;r)qAhBn<~WKbkew5>Ag9`TNF?aJ>DHZ?)W9qGG(qLQq;-PF^(0*W^B2VD5rE~+6m<(rJ~#|Z)eJe_wqAT9)?Ck8!oA){M-qXLgwgx0z?&H5bbFyEOenJncNR1>dksfGL&kcXy^4-)H^0RWXUCcTGHEIl=R>mE&<&{ zCvOX(t=;H+!)>>A@zxHsc2=}@^VTl3c2~6S;;p;Ty1SxvH*f7h>wOiiJ-l@fTJNuD zy^pu{qIGXY>mJ_v09yMhTJPtrDq8oI*3i4)4)523KzQJsHa%_V>Qm#-j0IjOUxC0$ zHJ(Y$X>m(s#vC(DBW-C`B9m69GE7ZoOfzYirfM22p(PVJ@hUT=rZefIrlqBIjoG7G z3v-4UQHSG6%`}H&FHGS+8!_=UMl&PhMm)=m)0xa{!Wb8gqiM@vQ(D}Jsaf<>t(k-w zurj5|473<{;v=ZKW@$&%$*iR&EH$MqsFMbLHkD1PiL{zQSEkM-F&cmvwE}T1O+Adu zmXX%6avC=~HPmbEeh>|s?PitsdUui0P$71waeNKG2d9IpF>I^(n2 zUS|z!kT7Sc0L8ehrRI{fBF$1YUB?R>8sIrlLRvhNOd4^*zZrRk=>{|Okwn~zMO3<( zs-8&?TI!5;i4U5g9<+Lb;D~Bw2zxUi3ZE!ps`G|ApGYQEJ)4^2$V^y9%2YM{smX*1 zR7|O{*!fvw;fQ)kOJPPROREWBf)UqT8Snc6;cTnGp51Y20K(ujw1k1H!eT^v2fsBQs-g0(5$7?8KLjY zv72(iKY9F^ZV)rzB|R8v`@skGV_1olfnJ{Ho*Ny(-TSo0X0vnj-Hc_;MX3uOAVADC z_|v;&O~P_PAptb0lFVqj85h<>l(uP+i)Zn?DjCv*43p@34u){Tt-D|d-4lxLF}%9+ z7<%X}y7xuTM3dgCH{tHn+jJl9e%$@I2lSvGz`c2)IUFi9*&LV~Ii;C~DwvcMJJ>0a zPNb(*l1vqJG&vC+Jp{zTTF}SiC2Geaw6-$!3sS*tTCCs(zs7B=$yY>mEJ`kR@C7Z( zi&B)opkhG|yK>>v%mA*SgfR0oQ~-fQl1y49UDp3BGRC^`QP@@R5bv>Fcra;vRsHZw zL(c&ib10Eq(B?8IW`~|-nTyb#=Fp^OCgM@!vccjBD3&3NdTA(`m>d$k_i*H)j}MvP z(xWhZv)VLza1kFOSr`ILk-3F}FADBTSkY)MWMeVnw45O@{3w>B+k5(#JzonJ@gP-U z0ec&Pg*H@HC5t-n>nn0t&K*BZvaBYiDwfTKRW)Za*(7Nxfg99Fg+iATSfD`XSjHM9 zQ<8#yHS{x#W!Oy@yB}j06h4HFAlA#9xYEeAI!oY>qj+QbP%KG5ZQGak?PCw%;nx6v z>U1W3$x+SEa&@U@CJFasXJPJ~2eNj6T_fv~5E})~a*>j@Bcp(&2|I;V!#2WNC&3;p z!c>68_M@m;Q*fZB&u`bc{Swh4h6?K&Ipp}aoX@^y5 zQM!nG?S)qKsl68EH;7GfCFF7FsoZ$w>IFX%J!`4QcK{$1M*9|gk9`D%)ky(QAbNRKF>9m)~ii_9^Fi0-6iRcS8DHG^|p1^XCU zcr&kIWa?gS{V+tkh4WbF5tR>dA>2Y5BCVy2XtWTBMpGF*o1}V6H2Qp2OWJRmqES5) zN3*|V`Z+oZ!DzI?_(Y>@FHP7_1;^thCPqR*x5FZ$dl0w{J+3~|Kq0pj?!bdgHMB^L<|WgApwfqc3L zcEzjvbp`h(+{q647Mj9=LK7%J8`RuQRJb;O=qPOh>>b_wOa|5`lTI%1ePT+ppoT~* zIF_3B=TL9LzVl;2T1zIeDJ3Z*%=7P{NX+ciRN^wa&nK)IH5QG=j&NqAe&QXe8(Y#i zGtSSzqUbo+h+PY8p3psP7)#B$X>@z_gaL^Tr*6W;pQ8e`ZOexwEy`A@pL4*vEVE%* zvg`vb^>O4$muC-265b!i`z9KgE{kjizsfzGFCd}($n5kG_lqsn&-8Rjf~>m6-X+k& zO@%;tzgO@Ot_tp?kuG@BIQkSkv>g*t;sJ)uIsxPymut1@7vbh%8UvdrQNTR3>{`jb zrf;?!cwch04!<4hTsdcwr zYs!sJZMO9-ySF=ctqiQNmB8A_H=cR*nXTTTjozVK%B}eK0-L>`$_F3I`yTrx$T@)_ ze;wrLK+YbppIEZJ)OY{q7r*!gv~PK>pC)jtRz+GS*IuzIVQv_896(XGE-=99mCvsD z)&|zyuO7|^2lBoFp^e!P`m>Ltxantv6ZQ!zj#KeTDjuPNn}U9-m9-p6qEJj6)1=xM z6&LU`_oH}Gde7xie0N%;_Rgiz?LctpbkUTcW>Lz(a{cpy){XW_pfWyUo`m2&W46rfKo5>S=&X`~#+rJM2?(EkMb zvfrYDzN*~F2-$0M<`cq~L#JX81yCQnZ*Ab)U7Nv!d7oHe6*RPgdv~EGa8A z*w-8OeMGwEy5^3%6WHcm*e6L}1Zu9huDBOTq--=f-_ZSHNvV}v7u}99-Eh5pz$3-o zSKL=z;}}u4>+=#DL;tY5pzt$bS-K!|v_<98Rgh;3@+Fh73Gu3wuTTjWwt!thACp*! z?*=~k*x%27Z}x9fTfvc=`s>=Q_7!>M*y>D}zO^TR9`& z2}sQyUp_6qqP~q;@d)13up%Aungko_j+yldGrQmo`wKn@=(#NR{K9CtRI7>+2$8=A zTM7~h#w;inANMY->C7uw^D5@4V$JT&;9%Z2$X8qik=KFfOMJ15GO=IWHBHQieGc?_ z!(D2_J*vxLy6di&`@nRr63d}xGaL>;4fQy;f2nGfM>NibN-MJ&?PXe<(0JR&KlP*F zW3THgp4H&>;8y6sM(Du$$XlWC54qa@0JkEc{Hyy9d#Y9q8VEY{pi-?KoHdNw0wS|7 zpijL<;QF|u5;&oduc5cuf`YU{*UED*E#`gqbG%n_wyz;){|YMia|8?(U!{3SP;K_! z4z!W3m6bz9uMAy_qE|3D^={1IBuO<4{!4Z3SvYHcV_jRt)E@F})+3hy%W-u}QwpB` zGqka1sHi(w{eLqtJ5OMI5k(`0CC$jewi)(S>P+Ir$hlI%1?(I(*4R{{6rekSo} zwf+KaaoQ@YFY4Nux*t(}om#LA(@|fORboT35t_ zh@NGWc2oj>FYz*>o=nbb3nm|>d=8~>7x$DozIqD9{1R9qj_jnWIDig5-~zcwu7FC$ ztvpU4k}5e7%(5ZE5t2L@VlD8n`r?c(p3_)kD%4b=R<)IhcUBNj9H>FQKp*4^?np*S7aZS{P?6EmHlYtjtZJo zaNa*t$HvB+jzXMrdr;wrBiw5*XI{DBo-r=hPsy2x*qu*lv(Ud_6q|C}!LDlyR~PcW zp5KUdd>FBQa?U!$!OrA@asI75{o6r!V_y2byl)SmzLIeoY32o*hKe815REo@ILOG# zeZ(+gZ^?WApD|1`)-nRW{y9X^9H!C#&zOcZVLcK#({TTWJ+WY%4Z=X>A-iWYcsTDn z{2P&xq`4jf&O@XDoTW!>K6;b7XQ;UQcI4h_r>)_noOilwCKdd%g%3=}w8Ou!8C3H= zVTkX=K)+9OQSl!%Mk5A#kQhiM1`;79-n)u{h}Ut+MGIxkDFMe|LovKYli@S`M!;w` zTBdyytw`D-4^5k2@+105W%(bXpvsHNL=e$W@xPsQ2O0u;dqx)wJ=Ge{Cb*PuDg!*c;W1 z^+GnA&?BU&>b`XX=MkqOdSI740y-3w3?;F|Nnblx$#&>yS(OrqX+@oP(lkAldN=k5 zk4P6f;blPJxv^*X4f}gpdb!&pE!byr4+n_7h^Y!K2#{;o%tb9Y%?my!P642a?F;UB z(lp6hGvVXh(AZ~%%ox8U>`!_oK-6 z-}340me94QuRgtY;H{Pi-gBc#X!kgw#kt5k$IY9BrK}=Qs=&*Aa2cG`!k@r)!;PDF`#^t>!_wj_~!3?oxR zgOF>}QIY<|BheyD0+R1gJ)(Y|lBf`z7Mpd8WY`Wt@tidp%el%E*}daNIoNGah;)az zF{~mQ%;qUsh9c(1W%wlcp#*_2b#zLd(vk?89kLlQj5rsUIcJ_><8pjB_B+M`&j5(= zu$P8p2fc1Kp7k;;l3z%nHOQ($-VW&~LKzpwh>F|_%B-X4S=F@Ejq<&yD-Z0Ob4DDg zfohx*OmK#2w3JwkVz5XpbAYFN#mbzyX~4O;QobHFvyp7^eUZa7Z|$p`43UI6~PK6w4{+Fx+6SXRz^jk+HB>1T{v$ znFXH%jZhr6%z>6d%nb5fV^|@Y5gR`7R2^SsbYX zlg#Rp^xi=UE(Fg@8APJm+OJJtonChTS99BsJA2l~*GIlH`pwaey+_~P^}u@fy18!T zA3UA!8`<1-CLcO;d#}1Ya&7eL=t}(R*zM-f^5dkAp1S(fR?FUvmc487w_5h!u4*yX z$KPrR*KcA-U2zp9B7G2VG}KvD&)Bg zk2tvuJbfVx?xsuzV4m_|OQu{Tw1RWeMjT0q8e52j-JEzlI>RY~1|l1eUGRo#{~W~& zay?*^dfkuN_7PRct%O{m&fTlS*M|{F^&fN%emhgI1rc-mvW&qR)u9F&AN?>|LexK)HSN$MDFcUfI70cUQ z6U(D>P|Z~px4X}SjS-LhNsY-?VhNeEkIhm%0fKxS{Bo=>dw_>_5C-9)9olr!{-6;I zC0ma$4mMqY!9(L$#twPib;aXE5xo_$)6ZbuLUWW;EovgUoBb(Tn1KRJQ5H|0C^b&6 zc=VXC$knLOqOagF*D%F9QZe)=h%1)S6;7gN_-0-^_h$3{+mAf{gXVv1{(kFL*OTA# z+>&oSwDOrX&sNW&jh;iVw{P}5xY7M!zU#^5GaFq`-tOvIed_vCYuU}Nf#oxZ3z8)7 z_@%a&H7wz>y4x(C+vx9IB=%V$vB4t6cKe1Je(_ow9#-VaFK zPnfg``gZRrulJu0_nc~}jyjd}0r`olSnD1+U%LEVmqSQMr#tsB1ch5#k@-cIk|&N+ znm6fA=RXSYv^WGaX5$yZ6 zvTl5oxX3Z^(pqm#oo?0Rx6>|NX0#Pg$zG+q7z!xIiai0;dhARTk($V13h(84FO(cOm8IlJB>BMxATR_{ zL3RqVRq!HH**JcTkr4B!5hLAM@X&FZ(UGYTD90rjsewZ4yuoI3Ms_+vN$0GUz9d&x z!9&^0Lhd-Oy6DZXN&t?@YV3aKdrTxXo?w58p-7_4zd~`xEz9zIuCVO+@6XASeBdWi z$2(Fl|J(bH)crFF<$-sk{+~%b??^pA_dXyGy(gjAIVJCw4=zvdNVx4BYnD5f=XWIB zc6yuTUQzGe>Gg|t+;)1JWmUARJH0`9?@H5-gxgMkvwS~|gByLjZ)K3``+nY=l;z0# J5|vz5{ugqjFl7J$ 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 00000000..ea7e4753 --- /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 00000000..8dc3629b --- /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 00000000..0cb8f437 --- /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 00000000..e69de29b 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 00000000..623ac198 --- /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..f10190668c752eb3a0c6e7cccc71e5c115a68462 GIT binary patch literal 33717 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
{P4 zWg1i-skI7z#-y7ld7)ip5Py#v`=o`blI?7TI`tVkFDhoL&Sdm|Q)wt1<6>i=#mtHL z5*(G;tAdYJk{<)RnAn&ij`ORfzY7qNTOcjLZQ4-E>Y$=kQlL(xyFl%KO?mwoQLBqmTj}x&T}ar) zUps;C_LaC**f>mq2FFAo)j2!Z!In`h5_Ad;BQkzOz3!pc>uiCpM2_q&`dA`#h3R99 zU9w0N+<{Nbsu|tb2rjU1H$Hq6JS^ml=dEq%6#mBnoVa4=oyYS)>-saT?oYJPpJ-Ko zqBT9xHa*bR|48e3pzU~|?R!88{eiaSfwqg^JoO`OJu*Ddy7~Q1PV9c5^*+$HKG2ZB z`v_n%oGlN1{x2T+!jT95{vY|bJ@EHF@Nav#VcYG2-#-1-(|P~qJJxc~$z0FL4}IQ^ z-bJkg^slaM;ib1;z47YJ`Mdj;cRrun`TV`wBiF0)EgNqR+&caC>BUWZ-)~xe=6vp% z^Y>bY7q!MGd}&&LbIYyp+u_9xyWTs$eBey(z?pkZXRp^kuJC)hKdd`l=V@8!{d0}( HJXrr1Cp$zg literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..acc7c591c70484e720be4c439472d7536edf478f GIT binary patch literal 31217 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 Qeg|JR@A!nHCtHsH3mMB(^8f$< literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7b7a8fcc76376965fd6ef4bf2b376d6481e2c1ef GIT binary patch literal 30230 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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: # type: ignore + """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 Jinja2 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) -> 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 00000000..4f912cca --- /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 00000000..3a839f5a --- /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 # type: ignore + 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 00000000..4ffde713 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,399 @@ +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) + + @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 + + #: Some implementations can detect when session data is read or + #: written and set this when that happens. The mixin default is hard + #: coded to ``True``. + accessed = True + + +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 + + #: When data is read or written, this is set to ``True``. Used by + # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` + #: header, which allows caching proxies to cache different pages for + #: different users. + accessed = False + + def __init__( + self, + initial: c.Mapping[str, t.Any] | c.Iterable[tuple[str, t.Any]] | None = None, + ) -> None: + def on_update(self: te.Self) -> None: + self.modified = True + self.accessed = True + + super().__init__(initial, on_update) + + def __getitem__(self, key: str) -> t.Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().setdefault(key, default) + + +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 # type: ignore # noqa: B950 + 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 00000000..444fda99 --- /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 00000000..618a3b35 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/templating.py @@ -0,0 +1,219 @@ +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. Injects `request`, + `session` and `g`. + """ + 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 + rv["session"] = reqctx.session + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja2 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 00000000..da156cc1 --- /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: # type: ignore + """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. + while self._new_contexts: + cm = self._new_contexts.pop() + self._context_stack.enter_context(cm) + + 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 00000000..6b70c409 --- /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 00000000..53fe976d --- /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 00000000..bab61029 --- /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 00000000..a1b589e3 --- /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 00000000..7b190ca6 --- /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 00000000..ddf54648 --- /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 00000000..245f43e8 --- /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 00000000..3b5e64b5 --- /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 00000000..ea55256e --- /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..4613c2325a09ff3099024c6bc99ece292cb150c3 GIT binary patch literal 1636 zcmZXU&rcgi6vt=%W4&H`ZDYVdijsw?vEYVZtZVSiXN zV}lV$RnY<0^+FPsiKj|fD4v99hR4MHNsRtxD<&-yrjZ8XPz5TrJ&c1y!^WOex zStf#!zPY;fOBSKm(ix7_8E7Z}0X#wk5iLNW=4zVcRFHDhBuz3wCd|57(9$Feth>5m z9XRLa6z2jX%)5ET2C(Uxiu1q)x1iVrF1kg<1z^jy6c>R@Zb`8fl*5W!QCtef!m3+U zTm~L@#}!wAC)^3eW5Hxtb8CvLz*Fv&;_+ZQoN;FqPXJ$XF9FxcB`wam3e-v@_A#z?|N^;St)5358ihfkp$t+{KabHhO|`c%1tjlNBs5U>
    COG$SFNiS#uL$0{--@v4Fd4K0{sTXx7qoNd?q1txRK91fQ|9Bq-&ZlM)o+&X zEC;Qa`C==C$JSaL(NRH{G1T0$3{Nh+t|TsS*gl^%_VE7K>v)r1m{%K!??h|8^LeM(XU1?W&yckM8BklL1W-x(w=^r1vDe`KFPEIBlEplusx zJZiTKquv=4{mCGsbtJ6e^8++gzt^1HT2k=5E@d3f*z=ey`u$%YY*Bk*L|(A55X|4` z2x|M>CbZ3H6AMag91(lh4+49G+Kh&A7c@VzzY=@}M=i?Y4!0NUOLhApr}idQrwi{3 z+LT3Q$IM>v!*;BVAJDlmacsSonGHt!2ghH>Vd1qjUr)KC3L<|$7f4y(Bn&@K&< z;^<^2msI~BI5BoHi~Oj?lZ>RKx-wV_B=harqr@1dk>mz>B&Fry^6xShGbf#7A{^2r zfBp$J3kh*~Mz(Fgp$%9r;|)LP;dTsWr*V(P+puWffbQ{|9^Ip?>2t~(T^e;8u=+;3 zC${2fss8a|gZqMBZ^O!P3ucV2tKoTmJ;K>6A!((~qV2~}oZl;@t6=U$YZ zXJzNN`t$Owr^c;+%<0Dy&&|tEGnY>wEOIhz9&SmR3zq1NLbFEuSy5k(dd_TOdfsM7 z_AjI(w<6I+uMNAMXd*Gx-vJyZi=D~ZW;qp#?lqY#XqJ~o{*RfgWmc3%RxOt6<(3x5Jop0{R(S z0#`N+zXRqtt!Y{x&A&#~f6bg2qZuij_r+P`d HqCWB#9NflQ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3795f1777903aef9a7fbc6ff7590ee4ec462da19 GIT binary patch literal 1190 zcmZ`&&1=*^6raggW4E<*tzr*Cs2`A8H)=&eiXeiDhgB#d>?O=*rfs&nNt~IjrtQH) zFJAQ69zA%d^iT1kSWu%vp%3X%yFVW>AxAYsOaBzGi~Pf-r{~D>dAKY{v=PAjJECUfKhk&ci&Ooa1fA(Tvj8><9RdVi^m;KK(~ z0M?Q0-!;0W^(_IcqOI=zEYw+bwaoNYz|3sMgbFBqAR%dvm7UY6dk+QU!V8-zNn#L- z-UA*tSRjR0Cn5}d_LT7;6ij$aEL!rKVcknoxe!Owl}ndB0ZCtgq!-CNScFng63sKH zRCsydN|JILA}yEyB&CvPpjs_PK|Dj>N5)>RJYU(k_F?4oJNxtjDA8Xmn4l;r7M1|4 zqgCAK^Pp^tMKRTS4afhp(GQ0LBiZdYLXGZt_1;qZDw@L~yz?5rz`&1?G_%SfyCzKfLqvL=w9o%55ZQqYb zi}`*w==;U|0v_`H$8FN=-VFFYjRU0?>hB6#3a2IUzQHLI3#B@{>EJcu>) z*_hceNB1>so;lEwRo+u*&jPfs>E>jv`>9azj`D`oAfdT7R0GLz)zHjPGhc9T$utS0 x`3%cE7C!~|he>qonWB^%d;%`iOo@{q_H>N#H#D(}#=fBPFRO$n_YsKP^EcJt7w7;0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00c122be047000b7f12ffd82ad3096eb26e259ee GIT binary patch literal 2690 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

    Xag`S zvn<7LC#F)#i?BCE+DEOkHbS&`c*=5-I6B2?+c5_LBx`CCjQ`0$RYtW0g?mwpVGY=lXt5jU6o3gkjF8Mymiu#&{Wo5LYKe3$1-m%^yFES9Urgfvlk>m#vL^+9 z5Z^|5SbU7y%@?IHkO=f37G}Z8sAmu{oM}nDARuY@0ww;p3&Ji-%p4$PIP07DvAK}g zR3$bS8N*H2_E1=Y$`cbOso+~`?wO&VO6 zmdCa96fvKjp@a-N(YWogxHqr(Q3=AIB0u14e1yg2?sUw+Ii|~^p3?)T;RKSpW5$Ok z-^eDFq~sh{$cJb~`wX#`y;xFdRqAIjcyo46A4TO{i_1~j%66|1$9xz4z%g|~MdMPa zb+vid;W{lbX5PG1?v>EGy^-q&)O)M^`y06rMVFcL%)PY58d#!w zFKbs+Yrj@oSUjVT0bPBBZb{sX5`)MYgsYR1{0-w3UjG(twTz+I>M&CdaxNm@sQzKY zdkx>)fv__oFGr3o1&=W;5%sT=B4<4ecv7g!X&aU4Y)$g|uxo=IgS z8GD+N6!`j)b=y+Ox?W&w+^8uXJ&?r*E$u*JZWk3Xbj!B{Y-UP3ZZvN5T>t|>8L*97 z_s0PM#9EG^MW;L=%R+3N`<;GXU`-PBxrtU?l*RMb!s!4?&(MuUf>|oDHE;cJ!Wu!# zn z1e?^f2??v6*@;VA+c#=h9_>82W%k!HQ4d78oFSoa8j>OiOdKYh5?kvGUO|g{qQTmm z^;R0ie#If9ln*2l_zD)kzwptw!tAgeKhR0Ie&dr!=(HXD;QbJlUZ#OTN@kMYV&9+S zgZQcw7TKKTe9Ww*lUmVVpkeIi94}FcnN*cZOk0ux)YEjUrW=JpJW4x2CAuBNf1?0h z`X|B{o*pS!NQ*-6@g-lw(vGfW-$O`rw;#MbaP{o6FN#CpvJei=rIv!=+3jB!JW>dC z{=m0}UK^s0y{o;)SC2isy8qy6&oNZgG!z;uq|j=(rQpSLt?t=^geT72BYO$~Dg}l5 zo$#SkuR%JTK5Y6s)C2=TJ4!Dgool==iGgt zIXnN~bJA)Hfl7vM$?RV=p>j2h+3{p6rcQjtR4NzhI}0HyRnUqnsT8IaN2pXqE3T$e z4XwBqC2Pf0*M7ehZ%^Ik-}6ehUt#lazd|rk+kwqY)G0kHvYDu05t9|cKYI#gtjHON z6*&j7B4;61BpzC?X2q99!5{w80fiv*61B{BZW8DW@@o>_*U@D zw4$r$x0oPuIxa+8=tpLw)AZ9rC^GWK@{wdVokn_*e!v)m>y!7=4QZv3q&`a>{BT1M zwOV?P9j($U1!Q?I(o4+!=OF>J?G(*09ht8@_tNuECQd!|lK{Y(gbCe-{wkUtl8elE0pF0_3vG_QGm-+KJ@ z$3OG!#V*ygUOjRx{&svd*l=BWckG?98_Ao;ZcOA_dv5pqWHc;f0S*XG`yyV03z x?7A!9y-?#5dseFs6ufw@NgeAFo_E7(Nqp#P^|hwAo31~atM2%fKoxB3{|}~F+l&AJ 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..5e29bf13342db4ef6d093ca7cb96c2c139691df9 GIT binary patch literal 11296 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 Y>u%iFJgplZ-2c+{u8W6lrjil#-)T&!!~g&Q 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..fe557816d963d6ddaebce07ddb8f109a368b3e8c GIT binary patch literal 8744 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 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 00000000..f5ca80f9 --- /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 00000000..a75adcd5 --- /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 00000000..e69de29b 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 00000000..5ddf3871 --- /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 00000000..e324dc03 --- /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 00000000..73843755 --- /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 00000000..56a07933 --- /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 00000000..a1b589e3 --- /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 00000000..ffef2ff3 --- /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 %} +

    +{% 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 00000000..ffa3866a --- /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 00000000..23d2d7e9 --- /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 00000000..abc3eae3 --- /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 00000000..c37cae49 --- /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 00000000..1a423a3e --- /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..80e85baf0419aa5c7db33f4bad262b6d05e23e69 GIT binary patch literal 1661 zcmZ9MTW=dh6vxN6*je8b$GIn)qyPVKB_y7B1692Ai8GU~W4f~c`knurx$c?$yi z$-jrUKjskn1%(KsFc;>dT%5=GoZ$j+0T(P6fs43kxfGS+89ZZo2DpsNmdjBkp2f44 zE5HtREYAX0an-T|T*EcXRp2_VTdn~&aKmyPxQUyV8&NB6_wjw;E&S1Fdw1u}uU|8M zMO>y_;%XWv5z*A8{E~6%{veswl)H?($v{%~e5Ct=@4H`VH<99og%o-@T=2c`&R)7| z#5EbZx=*yL21z2MR?syvBhg_ZsZvaE=)ptyyCTsLlE_hD^u&;cFzpSKg2$BWedjNz z544*b*AGXU1|pJ4=c-UyyhYO9u6wZ z9OsZI`cjaPnuXMk`ho>_v2)Ac7CN0gI~~-5 zh!W}BH>S)snfhP4J>Q^0t8FqOq2YEE`!dvI;UT4K$0C zTr5$5RDXP31*u59Ao|o9$4#)P$Q%uvnIKN8#e+vmD=ls4CNF0d=nO4H6>+e*1m%pN}*D*(I@m zd*hAohVWVV*{|NOKMIBJT zlGMmhBTJ1v3>0b_QZB3e=7=YA30U=}wY5nC@h$gXxY!o#)iaQ>Q{5ox0epo1m^wT}0g^ zxrn-1auIbEa-Wl%C$~bbP9B!@66B4@^T|WHm!uxjy)5;R?kUtOP_IHgo%(U=Cup!s zg9Ao`XEeyu;27?l23;DsH0;pOV>G;`E8K^xPw2Ws*CVRUT_V zY#!@CJRXlT9#?q$fX7eZN?a*1uAK9;L&ndZ@v|<(v`iQ*JzG+$eJcbB522DK{}~j(ID}cq_?USj|py z8x7kozeMpe&Mz+@Hh1cbJ1%cm8E+4`n`7KPM5aXkdDx&qFQI7YKvNi ziQ18FV_z7GFh)!mV_~+1*=54?ggFrAP?!^8PK6Z{ zmc@kS2&*TozHqR!V+yAw9Q(diz8^-}{qW#^s6m|jp?g2{?ynSfe|2#0PlH@$9OU-2 zAgA;hF4sX0|5aQPAO+H3UltC)P#PJ*_pBPI2RW~bqSpv=<21}T7pT!F!zB)oS7T`~ zg^8mQZ%cC>s7aYgqLOS#;{|Fe1&~d-ftr@HY0Rcwm`oJxNV6ZP*%nN8049ODcaFiH z8L0d63;PK$0zR0apd>*CWWk;+D4+l;KnHbMYysJqf-Z7B7!_@(24ON@FK%S;~1xC`~00z1GB*;$=U?zvbX}1K*K`B*ZxER2erVDV2 z5}r~ioswn`n9|rmX(tY|lMG5tJeX3m4`kSAfnHEDF=L*hV4i~uX`G-ee>df58f2w8 z2FR477eEJ9fCpBNnn795!RYy*TuZ{#b{{nSq8_x2^M@b3x$wpOX84Oo%j+L*L{?!o zmbSOUn`=hsLB3nRe!TeGt?=g7Vr2E{(#AS2A1wZ6bNxwpd3$T|@zPdg`MvO8!kf#H zt?<_3$Kkb)7gr;X7dM`6zrVir)3<-}&f->NJIpqgmOohf6B17%YfqNmS$r?D5?ZWMxgNfpFLCMAmp#uDHLM{I_sw>A+tm#GL4h4+0rlv zeJ;)q31NZa7!R}<7J(LIF>V>MhOGu|0ooR}QKE2zRRz(dmI;R3vao|gj%}rx0wr6o z!TwmnPT4k1!Y;+FR4A27mEuvVl^R%AE7Jnc8C%#Z+d=ecFAS1_Rzg+ z&0S%q3gCQTf(EL-M5e9))jcO(40U&RyeNfwdX9B=J>SvQ+XKVm7>f+6U!pFcXOp@k zsv2Uafvy||Qc^}EaVeTiXv(;z)4ph4X~xzZ)OgHwynz|G%rqIGGM%Hcd5_MJ8F9ukOSGcMK@@mbxlp_(6e^Pu@|Gnz=YP0Rd8KpN-@52;&3fB16>aOlK(^Mf3^V^94R2)tC9N|TY!na~ zB9|d(StV4u1N0SR$;6P7&x(kqbhK6wQLWATkj#E0gVH3XF}}fP+tw7)jBO=+D8sLEo~m z58jTUSk?elz-pjWx4brHSQ72m%S;3fj3lCl;`GXdqR5;5t0R$QL*Q?bNwtC;pU-y| zilJ`ZimrNCVUzp*b1>$YJP5MX!%%&5mV9L)m34E~zjUQTU$}iM-uk)F+|i5U7lkj} z6@T$I&bMZ~Eerb>y)BuFmM=Uz=Y@-2AC|MI$h%gmh|0z(T@5qt78tp}!o%G#Lk!TI-pP>2< zpz5h#_V^b){`r$x&%U&6rNO@-WEvjL*y`3Co?neGdmmYZf5#&^fjakp`1<9MOCvb~ zlRLwkJ`cb3KR|Vy&`mC_WO72yp1+4^_9AaFq8CO8Deb^^-bX4|l6oF;&o=jYWZ$a+i!Nvr!-`%78Pm{EG9eAK*icN1jVfx%yXw|hLLG(> zr8{D3q_8|d*pf2e+(_bjSHOmTLDbTKBBFE8ZEs zFnTdM*OqlRW^9eOtgdD2_C@RVxwa*1<7!RqY~Q@d3yS@*@U(eR=pofQThxnj}p&e&6oR1(qMd7AivMELo{*Obb8D+s8dX z#*D)_BKkf!A^?IN1k$u5$_@d&@%rqN1kg|zoTBO9oFdQjJg!EE2*+@H(hkF@wl<_` z;4%%#z9D%|k*(6_LPYB!yGSV;^Fx9>MK#>cC@H#ShLBIpQ}i4>%ckg0=olR%h1dc1SOW!EKF*0VcPzWbY1cf;3&!g!T`{)LZETse`gdhEu&OnK{f zIUa`psbUUrj)n-GuC60~CxLC!sWqElmSkw_oZ;#w zt(wx@14x93kNGXbrzYEu6`CtMf))A-hM9%|71RA13Df}`!|E9PR9reu);TIRty`#A zowEpH+kEA10*$!{S?@foHNTVqO`ZhjQ?w`30X^!=pV92Tx(Pq%QVsm}1FiZ*63weh|xzi-dJzj_cf*A$y1^O=cb~(fW>wcJ@f;2G7QG*&I zC6l1WsR1E-VI!T6ZvuI_;nl&h$78C-eheI^;HRQjHGm9XxO2~fnBCF5>KCrq0yH47 z=kHF7s2U(-e7O=RSLX71+f zeWklYdivRpr;i`&>eMSu3Gn99l!OWpRdr5NbZalf#J&hK?ErHLosT6nT^xufBbu2k z@}LV{K$Yl%9E)mfHy*hKtH*JHXh2@K7sIU)5p`>)l2BMIY8a8BbzOL_px3*s?T+n` z`GRc l6YJJRXmeFO-Mivw&+*W%iI$nZH~Z30zj^Yu2z>+V{{k>YSQG#N 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..e0d519f161221f71a1bfcdb16800df1aa6e66c66 GIT binary patch literal 19353 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 CqNE`J 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..04d3c72a9bb8b674a909fe3996f75e4bf8c85823 GIT binary patch literal 104068 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 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..47de3fb967622b251b03184bfef5d0b70f798d03 GIT binary patch literal 1564 zcmX|>&8{3Z5QS$*Kv7F~5hS+A+bqb4AhAG*6-Xcv5+#a|*jzmBnwh$B+kO4h$~+0; z5qK6>Y}xVxk+RE*uX-+wda6#l%jM%!W&e3~HEj6Z`||tK?;mb9|JciazwI4(_Wo6+pM-8^t#nlElCaqO%h|nBiKISCB zja}_uogAe$mclnDQS`u$2EZL}iEK*}DWpJDN+y=n7Ts)3={#E5usiqw-KzhC3Yw%2 z2UIhb?m#-TK5J0Jm zxnqYVqU3_h`&=4}BCJe9q&EnkyaY%YI3~YZLM9)jcF(3Jdc^U_t@3d`nwdNt0ZVB}%$KVJHPAx|GwvzfaQ{TpQF=H?>zw zzMg{1qh^;&P)zbg-0TZ$sCEA=BkvL;FH%`&nAu@lYl_xxJ~6@40xDrpn2~aA89)=h zpwz`S6OZ@G86Z)%^QCSsUh29QnUwO(MJEK9OQwo*kBh)m!UdGq&$?%8Akq zMd|)-1d!EiZ-r#lA9dBca$Y1k^oummI>N!datF8y&^A+C_~2dCjviGcoKU%q;J{qwUI-@g1~^UiMD_rLC5RVj6+ z@$Bb}dA)mH@(t?M-QHIX*YZYas48^_jb+Cn+Rf)islIsp`I8+2%V)C>uRWL0?ncv% xf3mYn(T;q5JfGh`_?mmANBO3F#DaFm*DK81d)w{y?fs8G`Sh>N!*ZXIe*xn3I!OQk literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2c08927a65a58bced22da928f7d3c196fa7c0833 GIT binary patch literal 6589 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9efb01e7012914eaf3548fc368f27191cb9ca0bc GIT binary patch literal 76690 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9bb68537a82bd81a49aa3f4af6e937cd13333569 GIT binary patch literal 7728 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..926e5da30e6e8350e77727ce56b73aee9da68e8d GIT binary patch literal 19203 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f9b69e15ebaf388cc537f0ba7ef6af84802a8825 GIT binary patch literal 32363 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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..2707f26b4842e548b7389849b4723716d2958985 GIT binary patch literal 5498 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 IzVl4xKd%8vMgRZ+ 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..ad506aab5cb067effaab1aa592374fc6eaaba42a GIT binary patch literal 7019 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7465fcb3a418f9e42711a7d456f4b1b0d292b420 GIT binary patch literal 61211 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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..458424f101dbb4c5c0324ed364d1c9634c5ad297 GIT binary patch literal 18115 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fb95a9dc4210391719cf1380240b385cb181073 GIT binary patch literal 34871 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 dtav2g_Eku9iZzb}+`d{_R!Z8cO~?~(C7pD- zqwkKAsZxMb1c(9{joKG8Xp1ndfyi--1Vw>5Pl-_!agc{l{(;!59}F~k$eSFwD3GVl z?2!~jNktyI0QZ)=b8|DZJKubFpEfs#2sH2GC&#~NCgflEr`n{-V08fo7l=ZJi6ST- zO&InlUPaWrQ{u2F5ayZSI;yw1S92$q^$q(yn8Oraw=zM3|sGOET*D(gyUirF$%b=x$o3`^Upp(jFL;-d$?6rhg_jyM3C(yldb zAE^9UO~K#-VPsf<(0CMqc@+;6Hw%X1-C|zce10?l0TYLPIbYoGG{2}?s(nJ%GZPwV2gC&GhMRO&#gZZD@*ri+S(n^Kdc(a54h_XPrUN8O(*^O->V@cfK=*Des1T z_>rtlT0C>)5eqUcZBr|!+wxgRJH{}JC~hdN>@gk9>O7Gwo|+62GZ(^>g~t}AvbvI> zbO_RP;|)`Cj=CqAPRm-BS#)MxO^?$V74(lVt_JcQ&b+dg&nd1aMIn{P4J8rcQl}xm z6*ekoHJh8h@mU->o6!OjAQ< z?ip1F=W{97J$`>J0(8d6Y6@300_t7mb@%W%s1|rOE>Ej~V`*83KQuiq>tn8i287R4 z6+kww2GK1w#_VLppH%HxpzG8q7_lL$l$}*A+uaPATgf#&QXglU8ZdO0igOP^zs^j^ zbN-A}O(7VXwZJM>w`?Xupm9@O7(w`--DxMjpFsqbwV%FNk616QgC)cr1pL*L&|M%l z!YprjC@waxxc`L9m6Zuh?1uIm@;i^>sg{F568Fx&`$Gk zE{a$Z}j@~-ZsUEMc!J@yq5f<5!kmBZWT``&o&_2(95OW`BMzU$#5i_hE$AGzy= zWggpsc!(#7*#T?JtnUhDiU_DSp>4&59?Q_}FOHKb+OR^NqgGlIdS z31l)2O%b=4mzW6T!3Txj&&h*#3%RZDmo{VXOxy_;fM!3Z5P^8miQw)JnX+y{k)2|u z{3!s(H=q%4e2p240>4v7)wGPY#KOAEk7K2Suiz%9@Q!&JwRwz$TqdWB{2x~3akO(hEW=0t6I5*QMXN`29<6%7;1|2oXW z8qYEB&#>{|0Q3Gv$j_iQ%!zYS9RrZ;TIH|44w{o=WX_kD04HAtd4HX>-$tb6ttR~> z$5Ax2q2>LJI6CLg`_BpI5B_hBR%_lj(bS*}{^tFc!BcF2#{(dPuO1C;olHt3dGJGl zm+E$M{*}6?N*n#Kg!8}N(i3TeCxLw6T(gbw=PfVf#cD*ry1&}^MpRqL2dXRz*8UDw zL9I3sRv?d?cu5#lnWk7y2q+yeKUq)1%clmE(uG^ZSI5WB+Dum*pPb3y)vqv(lN!I} zvYU8t(^4&Q-A)j)E6EAJ6Vlm?JG30hoeJO-hX6!GUe;@+-K{pe8}I<=P#uGP3huH# zhwdCH)4j{|(Ixum4SM)1(i%Jh^?ts8;n?lS&O-d+(9Ot!^6rNgLgn52z9NB^Lks=4 zcXSqGe~jMTktovxMe&``+o8p8mFV&Jd#=;tR~}!Y#|u)qofe)dckI30*|pgJm!6xQ zN6Q`imOBnDbsSn`H#>S@sT_T9IT~Av#)|A#^x#Sh=w4|h^uR*!&CXwiZ@07;PF=Kb zwHz$B#|k}fJ@MufMYYu4`~KeR?Y&p_Ew%S91j=pgrM5k{qwR&hV(eD*kapy7hE0&qsF$8hs}v~r&8RQixYw=o2f!<{3%V_6i^rU9|NNau%Y1MP;$p_oT*SCK zzJm105x%Y{`hgW{^;R_$Uz=t25`FQ&3^fl#b{vHas^aP(74|9_pAH1r-8!5Ni zk$7slUtgMsesa1$dE#XMiRVuZJnOW$a`3?j(80oL?s#nG1mJs;ZKMs&{UU?Jhr86^ z>(_zrxLM{xX~z(YdMT>{;`KH-4Sx-j`~0vGPoe*uW(E~Nkf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/_identifier.py b/venv/lib/python3.12/site-packages/jinja2/_identifier.py new file mode 100644 index 00000000..928c1503 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/_identifier.py @@ -0,0 +1,6 @@ +import re + +# generated by scripts/generate_identifier_pattern.py +pattern = re.compile( + r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 +) diff --git a/venv/lib/python3.12/site-packages/jinja2/async_utils.py b/venv/lib/python3.12/site-packages/jinja2/async_utils.py new file mode 100644 index 00000000..f0c14020 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/async_utils.py @@ -0,0 +1,99 @@ +import inspect +import typing as t +from functools import WRAPPER_ASSIGNMENTS +from functools import wraps + +from .utils import _PassArg +from .utils import pass_eval_context + +if t.TYPE_CHECKING: + import typing_extensions as te + +V = t.TypeVar("V") + + +def async_variant(normal_func): # type: ignore + def decorator(async_func): # type: ignore + pass_arg = _PassArg.from_obj(normal_func) + need_eval_context = pass_arg is None + + if pass_arg is _PassArg.environment: + + def is_async(args: t.Any) -> 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 00000000..ada8b099 --- /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 00000000..a4ff6a1b --- /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 00000000..41a1c23b --- /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 00000000..eeeeee78 --- /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 00000000..638cad3d --- /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 00000000..0fc6e5be --- /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 = "