From b7ecc892c73ce70da69e9e17d827ee24397a507d Mon Sep 17 00:00:00 2001 From: Regine Cyrille Date: Fri, 4 Oct 2024 00:25:07 -0700 Subject: [PATCH 01/26] Updated CI/CD pipeline file with secrets and configurations --- .github/workflows/ci-cd.yml | 37 + Dockerfile | 20 +- deployment.yaml | 19 + service.yaml | 11 + 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-2.1.5.dist-info/INSTALLER | 1 + .../MarkupSafe-2.1.5.dist-info/LICENSE.rst | 28 + .../MarkupSafe-2.1.5.dist-info/METADATA | 93 + .../MarkupSafe-2.1.5.dist-info/RECORD | 14 + .../MarkupSafe-2.1.5.dist-info/WHEEL | 5 + .../MarkupSafe-2.1.5.dist-info/top_level.txt | 1 + .../blinker-1.8.2.dist-info/INSTALLER | 1 + .../blinker-1.8.2.dist-info/LICENSE.txt | 20 + .../blinker-1.8.2.dist-info/METADATA | 60 + .../blinker-1.8.2.dist-info/RECORD | 12 + .../blinker-1.8.2.dist-info/WHEEL | 4 + .../site-packages/blinker/__init__.py | 60 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1811 bytes .../__pycache__/_utilities.cpython-312.pyc | Bin 0 -> 2733 bytes .../blinker/__pycache__/base.cpython-312.pyc | Bin 0 -> 25425 bytes .../site-packages/blinker/_utilities.py | 64 + .../python3.12/site-packages/blinker/base.py | 621 ++ .../python3.12/site-packages/blinker/py.typed | 0 .../click-8.1.7.dist-info/INSTALLER | 1 + .../click-8.1.7.dist-info/LICENSE.rst | 28 + .../click-8.1.7.dist-info/METADATA | 103 + .../click-8.1.7.dist-info/RECORD | 39 + .../site-packages/click-8.1.7.dist-info/WHEEL | 5 + .../click-8.1.7.dist-info/top_level.txt | 1 + .../site-packages/click/__init__.py | 73 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2711 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 27456 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 30539 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2452 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11991 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 135536 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 23984 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14747 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 14066 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 3131 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 21496 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 22768 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 32801 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 24573 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 49453 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 26303 bytes .../python3.12/site-packages/click/_compat.py | 623 ++ .../site-packages/click/_termui_impl.py | 739 ++ .../site-packages/click/_textwrap.py | 49 + .../site-packages/click/_winconsole.py | 279 + .../python3.12/site-packages/click/core.py | 3042 ++++++ .../site-packages/click/decorators.py | 561 ++ .../site-packages/click/exceptions.py | 288 + .../site-packages/click/formatting.py | 301 + .../python3.12/site-packages/click/globals.py | 68 + .../python3.12/site-packages/click/parser.py | 529 + .../python3.12/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 596 ++ .../python3.12/site-packages/click/termui.py | 784 ++ .../python3.12/site-packages/click/testing.py | 479 + .../python3.12/site-packages/click/types.py | 1089 +++ .../python3.12/site-packages/click/utils.py | 624 ++ .../flask-3.0.3.dist-info/INSTALLER | 1 + .../flask-3.0.3.dist-info/LICENSE.txt | 28 + .../flask-3.0.3.dist-info/METADATA | 101 + .../flask-3.0.3.dist-info/RECORD | 58 + .../flask-3.0.3.dist-info/REQUESTED | 0 .../site-packages/flask-3.0.3.dist-info/WHEEL | 4 + .../flask-3.0.3.dist-info/entry_points.txt | 3 + .../site-packages/flask/__init__.py | 60 + .../site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2485 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 246 bytes .../flask/__pycache__/app.cpython-312.pyc | Bin 0 -> 61111 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 4900 bytes .../flask/__pycache__/cli.cpython-312.pyc | Bin 0 -> 42261 bytes .../flask/__pycache__/config.cpython-312.pyc | Bin 0 -> 16223 bytes .../flask/__pycache__/ctx.cpython-312.pyc | Bin 0 -> 19837 bytes .../__pycache__/debughelpers.cpython-312.pyc | Bin 0 -> 9137 bytes .../flask/__pycache__/globals.cpython-312.pyc | Bin 0 -> 1870 bytes .../flask/__pycache__/helpers.cpython-312.pyc | Bin 0 -> 24814 bytes .../flask/__pycache__/logging.cpython-312.pyc | Bin 0 -> 3275 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 16319 bytes .../flask/__pycache__/signals.cpython-312.pyc | Bin 0 -> 1227 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9912 bytes .../flask/__pycache__/testing.cpython-312.pyc | Bin 0 -> 13685 bytes .../flask/__pycache__/typing.cpython-312.pyc | Bin 0 -> 4282 bytes .../flask/__pycache__/views.cpython-312.pyc | Bin 0 -> 7007 bytes .../__pycache__/wrappers.cpython-312.pyc | Bin 0 -> 6128 bytes .../lib/python3.12/site-packages/flask/app.py | 1498 +++ .../site-packages/flask/blueprints.py | 129 + .../lib/python3.12/site-packages/flask/cli.py | 1109 +++ .../python3.12/site-packages/flask/config.py | 370 + .../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 | 621 ++ .../site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6698 bytes .../json/__pycache__/provider.cpython-312.pyc | Bin 0 -> 9265 bytes .../json/__pycache__/tag.cpython-312.pyc | Bin 0 -> 13960 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 -> 33592 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 31189 bytes .../__pycache__/scaffold.cpython-312.pyc | Bin 0 -> 30494 bytes .../site-packages/flask/sansio/app.py | 964 ++ .../site-packages/flask/sansio/blueprints.py | 632 ++ .../site-packages/flask/sansio/scaffold.py | 801 ++ .../site-packages/flask/sessions.py | 379 + .../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 | 90 + .../python3.12/site-packages/flask/views.py | 191 + .../site-packages/flask/wrappers.py | 174 + .../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 -> 1637 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 1191 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2691 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 3951 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 15419 bytes .../__pycache__/signer.cpython-312.pyc | Bin 0 -> 11296 bytes .../__pycache__/timed.cpython-312.pyc | Bin 0 -> 8740 bytes .../__pycache__/url_safe.cpython-312.pyc | Bin 0 -> 3541 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.4.dist-info/INSTALLER | 1 + .../jinja2-3.1.4.dist-info/LICENSE.txt | 28 + .../jinja2-3.1.4.dist-info/METADATA | 76 + .../jinja2-3.1.4.dist-info/RECORD | 57 + .../jinja2-3.1.4.dist-info/WHEEL | 4 + .../jinja2-3.1.4.dist-info/entry_points.txt | 3 + .../site-packages/jinja2/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1662 bytes .../__pycache__/_identifier.cpython-312.pyc | Bin 0 -> 2143 bytes .../__pycache__/async_utils.cpython-312.pyc | Bin 0 -> 4087 bytes .../__pycache__/bccache.cpython-312.pyc | Bin 0 -> 19334 bytes .../__pycache__/compiler.cpython-312.pyc | Bin 0 -> 102267 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 1565 bytes .../jinja2/__pycache__/debug.cpython-312.pyc | Bin 0 -> 6575 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1615 bytes .../__pycache__/environment.cpython-312.pyc | Bin 0 -> 76711 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7724 bytes .../jinja2/__pycache__/ext.cpython-312.pyc | Bin 0 -> 41877 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 72029 bytes .../__pycache__/idtracking.cpython-312.pyc | Bin 0 -> 19158 bytes .../jinja2/__pycache__/lexer.cpython-312.pyc | Bin 0 -> 32046 bytes .../__pycache__/loaders.cpython-312.pyc | Bin 0 -> 30972 bytes .../jinja2/__pycache__/meta.cpython-312.pyc | Bin 0 -> 5479 bytes .../__pycache__/nativetypes.cpython-312.pyc | Bin 0 -> 7028 bytes .../jinja2/__pycache__/nodes.cpython-312.pyc | Bin 0 -> 58228 bytes .../__pycache__/optimizer.cpython-312.pyc | Bin 0 -> 2698 bytes .../jinja2/__pycache__/parser.cpython-312.pyc | Bin 0 -> 60820 bytes .../__pycache__/runtime.cpython-312.pyc | Bin 0 -> 48501 bytes .../__pycache__/sandbox.cpython-312.pyc | Bin 0 -> 17899 bytes .../jinja2/__pycache__/tests.cpython-312.pyc | Bin 0 -> 9059 bytes .../jinja2/__pycache__/utils.cpython-312.pyc | Bin 0 -> 34480 bytes .../__pycache__/visitor.cpython-312.pyc | Bin 0 -> 5362 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 84 + .../site-packages/jinja2/bccache.py | 408 + .../site-packages/jinja2/compiler.py | 1960 ++++ .../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 | 1675 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.12/site-packages/jinja2/ext.py | 870 ++ .../site-packages/jinja2/filters.py | 1866 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.12/site-packages/jinja2/lexer.py | 868 ++ .../site-packages/jinja2/loaders.py | 667 ++ .../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 | 1041 ++ .../python3.12/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1056 ++ .../site-packages/jinja2/sandbox.py | 429 + .../python3.12/site-packages/jinja2/tests.py | 256 + .../python3.12/site-packages/jinja2/utils.py | 755 ++ .../site-packages/jinja2/visitor.py | 92 + .../site-packages/markupsafe/__init__.py | 332 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 17465 bytes .../__pycache__/_native.cpython-312.pyc | Bin 0 -> 2554 bytes .../site-packages/markupsafe/_native.py | 63 + .../site-packages/markupsafe/_speedups.c | 320 + .../_speedups.cpython-312-darwin.so | Bin 0 -> 35208 bytes .../site-packages/markupsafe/_speedups.pyi | 9 + .../site-packages/markupsafe/py.typed | 0 .../pip-24.2.dist-info/AUTHORS.txt | 796 ++ .../pip-24.2.dist-info/INSTALLER | 1 + .../pip-24.2.dist-info/LICENSE.txt | 20 + .../site-packages/pip-24.2.dist-info/METADATA | 89 + .../site-packages/pip-24.2.dist-info/RECORD | 853 ++ .../pip-24.2.dist-info/REQUESTED | 0 .../site-packages/pip-24.2.dist-info/WHEEL | 5 + .../pip-24.2.dist-info/entry_points.txt | 3 + .../pip-24.2.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 -> 699 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 855 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2219 bytes .../site-packages/pip/_internal/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 801 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14486 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12681 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17646 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 35567 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 684 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 5132 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10222 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13633 bytes .../site-packages/pip/_internal/build_env.py | 315 + .../site-packages/pip/_internal/cache.py | 290 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 292 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8620 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10210 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30409 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1788 bytes .../__pycache__/index_command.cpython-312.pyc | Bin 0 -> 7138 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2314 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4920 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15027 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 3848 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 12255 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7847 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 389 bytes .../pip/_internal/cli/autocompletion.py | 176 + .../pip/_internal/cli/base_command.py | 231 + .../pip/_internal/cli/cmdoptions.py | 1075 +++ .../pip/_internal/cli/command_context.py | 27 + .../pip/_internal/cli/index_command.py | 170 + .../site-packages/pip/_internal/cli/main.py | 80 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 94 + .../pip/_internal/cli/req_command.py | 329 + .../pip/_internal/cli/spinners.py | 159 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 132 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4016 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9715 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2606 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 5207 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13177 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10082 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7517 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4399 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2982 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1687 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6685 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3994 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 29128 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15771 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7532 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 10491 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4723 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8879 bytes .../pip/_internal/commands/cache.py | 225 + .../pip/_internal/commands/check.py | 67 + .../pip/_internal/commands/completion.py | 130 + .../pip/_internal/commands/configuration.py | 280 + .../pip/_internal/commands/debug.py | 201 + .../pip/_internal/commands/download.py | 146 + .../pip/_internal/commands/freeze.py | 109 + .../pip/_internal/commands/hash.py | 59 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/inspect.py | 92 + .../pip/_internal/commands/install.py | 783 ++ .../pip/_internal/commands/list.py | 375 + .../pip/_internal/commands/search.py | 172 + .../pip/_internal/commands/show.py | 217 + .../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 -> 955 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2907 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1714 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8453 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 2295 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 | 777 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 246 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21631 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 40662 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 12602 bytes .../pip/_internal/index/collector.py | 494 + .../pip/_internal/index/package_finder.py | 1020 ++ .../pip/_internal/index/sources.py | 285 + .../pip/_internal/locations/__init__.py | 456 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16454 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6866 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8042 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3795 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 | 128 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5890 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2940 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35212 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 16098 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 6 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 372 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 4505 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 12579 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11093 bytes .../_internal/metadata/importlib/_compat.py | 85 + .../_internal/metadata/importlib/_dists.py | 221 + .../pip/_internal/metadata/importlib/_envs.py | 189 + .../pip/_internal/metadata/pkg_resources.py | 301 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 280 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1618 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 10858 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4237 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1708 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2291 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26631 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1037 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 5001 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1865 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4967 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5774 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 | 590 ++ .../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 | 93 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 268 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 22113 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 6474 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8493 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11631 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18888 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2269 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2963 bytes .../pip/_internal/network/auth.py | 566 ++ .../pip/_internal/network/cache.py | 106 + .../pip/_internal/network/download.py | 187 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 522 + .../pip/_internal/network/utils.py | 98 + .../pip/_internal/network/xmlrpc.py | 62 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 211 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7118 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10142 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25805 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 217 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7681 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1871 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1905 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3025 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1691 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2032 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3864 bytes .../operations/build/build_tracker.py | 138 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 181 + .../pip/_internal/operations/freeze.py | 258 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 280 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1812 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 34119 bytes .../operations/install/editable_legacy.py | 47 + .../pip/_internal/operations/install/wheel.py | 741 ++ .../pip/_internal/operations/prepare.py | 732 ++ .../site-packages/pip/_internal/pyproject.py | 185 + .../pip/_internal/req/__init__.py | 90 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3459 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 21234 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 21446 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 38498 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 5497 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 32108 bytes .../pip/_internal/req/constructors.py | 560 ++ .../pip/_internal/req/req_file.py | 551 ++ .../pip/_internal/req/req_install.py | 934 ++ .../pip/_internal/req/req_set.py | 82 + .../pip/_internal/req/req_uninstall.py | 633 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 211 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1199 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 218 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22593 bytes .../_internal/resolution/legacy/resolver.py | 597 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 222 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8163 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 29186 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 32300 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6807 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10537 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 5054 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 15370 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 12328 bytes .../_internal/resolution/resolvelib/base.py | 139 + .../resolution/resolvelib/candidates.py | 569 ++ .../resolution/resolvelib/factory.py | 817 ++ .../resolution/resolvelib/found_candidates.py | 174 + .../resolution/resolvelib/provider.py | 258 + .../resolution/resolvelib/reporter.py | 81 + .../resolution/resolvelib/requirements.py | 245 + .../resolution/resolvelib/resolver.py | 317 + .../pip/_internal/self_outdated_check.py | 244 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 206 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4541 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1877 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2421 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2918 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 5574 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 695 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4202 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3547 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 3217 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2159 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 4004 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7340 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1175 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2430 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7619 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13569 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 33562 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2594 bytes .../utils/__pycache__/retry.cpython-312.pyc | Bin 0 -> 2119 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4561 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8650 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 12035 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 13509 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2088 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4482 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5914 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 79 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 124 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 80 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 149 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 101 + .../pip/_internal/utils/hashes.py | 147 + .../pip/_internal/utils/logging.py | 347 + .../site-packages/pip/_internal/utils/misc.py | 777 ++ .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/retry.py | 42 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 245 + .../pip/_internal/utils/temp_dir.py | 296 + .../pip/_internal/utils/unpacking.py | 337 + .../site-packages/pip/_internal/utils/urls.py | 55 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 134 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 545 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5066 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19031 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7619 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12538 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29011 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 527 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 688 ++ .../pip/_internal/wheel_builder.py | 354 + .../site-packages/pip/_vendor/__init__.py | 116 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4564 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 139466 bytes .../pip/_vendor/cachecontrol/__init__.py | 28 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 917 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2661 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 6479 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3802 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 16239 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 4362 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6709 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 5276 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 1689 bytes .../pip/_vendor/cachecontrol/_cmd.py | 70 + .../pip/_vendor/cachecontrol/adapter.py | 161 + .../pip/_vendor/cachecontrol/cache.py | 74 + .../_vendor/cachecontrol/caches/__init__.py | 8 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 450 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7783 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2748 bytes .../_vendor/cachecontrol/caches/file_cache.py | 182 + .../cachecontrol/caches/redis_cache.py | 48 + .../pip/_vendor/cachecontrol/controller.py | 499 + .../pip/_vendor/cachecontrol/filewrapper.py | 119 + .../pip/_vendor/cachecontrol/heuristics.py | 154 + .../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 -> 333 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 660 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 3231 bytes .../pip/_vendor/certifi/cacert.pem | 4798 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 114 + .../pip/_vendor/certifi/py.typed | 0 .../pip/_vendor/distlib/__init__.py | 33 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1284 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45546 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 65700 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24331 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 59945 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15091 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7693 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41681 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17332 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19789 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 88032 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30360 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 51469 bytes .../pip/_vendor/distlib/compat.py | 1138 +++ .../pip/_vendor/distlib/database.py | 1359 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1303 +++ .../pip/_vendor/distlib/manifest.py | 384 + .../pip/_vendor/distlib/markers.py | 167 + .../pip/_vendor/distlib/metadata.py | 1068 ++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 466 + .../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 | 2025 ++++ .../pip/_vendor/distlib/version.py | 751 ++ .../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 | 1099 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 975 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 307 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53823 bytes .../pip/_vendor/distro/distro.py | 1403 +++ .../site-packages/pip/_vendor/distro/py.typed | 0 .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 896 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4991 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 902 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 15806 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 99491 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2648 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 231 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158863 bytes .../site-packages/pip/_vendor/idna/codec.py | 118 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 395 + .../pip/_vendor/idna/idnadata.py | 4245 ++++++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../site-packages/pip/_vendor/idna/py.typed | 0 .../pip/_vendor/idna/uts46data.py | 8598 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1756 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2040 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8185 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 42058 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 168 + .../pip/_vendor/msgpack/fallback.py | 951 ++ .../pip/_vendor/packaging/__init__.py | 15 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 573 bytes .../__pycache__/_elffile.cpython-312.pyc | Bin 0 -> 4982 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 9710 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 4569 bytes .../__pycache__/_parser.cpython-312.pyc | Bin 0 -> 14000 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3256 bytes .../__pycache__/_tokenizer.cpython-312.pyc | Bin 0 -> 7930 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 11026 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 24968 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 4425 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 38754 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 21359 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 7356 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 19522 bytes .../pip/_vendor/packaging/_elffile.py | 110 + .../pip/_vendor/packaging/_manylinux.py | 262 + .../pip/_vendor/packaging/_musllinux.py | 85 + .../pip/_vendor/packaging/_parser.py | 354 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/_tokenizer.py | 194 + .../pip/_vendor/packaging/markers.py | 325 + .../pip/_vendor/packaging/metadata.py | 804 ++ .../pip/_vendor/packaging/py.typed | 0 .../pip/_vendor/packaging/requirements.py | 91 + .../pip/_vendor/packaging/specifiers.py | 1009 ++ .../pip/_vendor/packaging/tags.py | 568 ++ .../pip/_vendor/packaging/utils.py | 174 + .../pip/_vendor/packaging/version.py | 563 ++ .../pip/_vendor/pkg_resources/__init__.py | 3676 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 161296 bytes .../pip/_vendor/platformdirs/__init__.py | 627 ++ .../pip/_vendor/platformdirs/__main__.py | 55 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 19844 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1963 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 10712 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 12926 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 8022 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 15052 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 612 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 13689 bytes .../pip/_vendor/platformdirs/android.py | 249 + .../pip/_vendor/platformdirs/api.py | 292 + .../pip/_vendor/platformdirs/macos.py | 130 + .../pip/_vendor/platformdirs/py.typed | 0 .../pip/_vendor/platformdirs/unix.py | 275 + .../pip/_vendor/platformdirs/version.py | 16 + .../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 -> 3504 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 750 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26600 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2644 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3237 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4736 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38377 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1575 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 2624 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4093 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4772 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 12114 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6709 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8205 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 32988 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 14085 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../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 -> 37927 bytes .../pip/_vendor/pygments/formatter.py | 129 + .../_vendor/pygments/formatters/__init__.py | 157 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6918 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4231 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4238 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7309 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 41042 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 28564 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6071 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 20141 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6893 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2974 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 13789 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9155 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5835 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15134 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 987 ++ .../pip/_vendor/pygments/formatters/img.py | 685 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 518 + .../pip/_vendor/pygments/formatters/other.py | 160 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 349 + .../pip/_vendor/pygments/formatters/svg.py | 185 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 963 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14637 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 68279 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42983 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 589 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../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 -> 2680 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 3664 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 | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 629 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 390 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 14716 bytes .../pip/_vendor/pyproject_hooks/_compat.py | 8 + .../pip/_vendor/pyproject_hooks/_impl.py | 330 + .../pyproject_hooks/_in_process/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1096 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 14374 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 179 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5269 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 600 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2040 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 28447 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7214 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13937 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 938 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1693 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25214 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7614 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4244 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1067 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35444 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 1282 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27862 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 6039 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5639 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36382 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 | 24 + .../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 | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 650 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6867 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2670 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25896 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10516 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 216 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 436 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/py.typed | 0 .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 ++ .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 273 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7031 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10308 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7888 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205992 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1745 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2365 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 553 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 871 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12089 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4163 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1886 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3636 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5176 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 737 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6586 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13195 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 981 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 881 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28992 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2506 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3579 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 3342 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1624 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12303 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9082 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4288 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11854 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5826 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26585 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1717 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8600 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 113457 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2274 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9226 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10957 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10382 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1504 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4228 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1861 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3587 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3088 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9903 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6051 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5224 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20174 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19031 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4905 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13570 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9583 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6394 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 7140 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1827 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5313 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12199 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40163 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 74989 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10393 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 14803 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1808 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 583 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6629 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6584 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3841 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2495 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28131 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6080 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6077 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33516 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2155 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 39964 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43555 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3364 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 60865 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6358 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 330 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 31527 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11452 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 | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_null_file.py | 69 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 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 | 662 ++ .../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 | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 93 + .../site-packages/pip/_vendor/rich/box.py | 480 + .../site-packages/pip/_vendor/rich/cells.py | 167 + .../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 | 2633 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 190 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 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 | 289 + .../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 | 312 + .../site-packages/pip/_vendor/rich/pretty.py | 995 ++ .../pip/_vendor/rich/progress.py | 1699 ++++ .../pip/_vendor/rich/progress_bar.py | 223 + .../site-packages/pip/_vendor/rich/prompt.py | 375 + .../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 | 738 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../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 | 958 ++ .../site-packages/pip/_vendor/rich/table.py | 1000 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1357 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 753 ++ .../site-packages/pip/_vendor/rich/tree.py | 249 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 400 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 26915 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 3924 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 382 bytes .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../site-packages/pip/_vendor/tomli/py.typed | 1 + .../pip/_vendor/truststore/__init__.py | 13 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 634 bytes .../__pycache__/_api.cpython-312.pyc | Bin 0 -> 16556 bytes .../__pycache__/_macos.cpython-312.pyc | Bin 0 -> 16588 bytes .../__pycache__/_openssl.cpython-312.pyc | Bin 0 -> 2221 bytes .../_ssl_constants.cpython-312.pyc | Bin 0 -> 1115 bytes .../__pycache__/_windows.cpython-312.pyc | Bin 0 -> 15756 bytes .../pip/_vendor/truststore/_api.py | 313 + .../pip/_vendor/truststore/_macos.py | 499 + .../pip/_vendor/truststore/_openssl.py | 66 + .../pip/_vendor/truststore/_ssl_constants.py | 31 + .../pip/_vendor/truststore/_windows.py | 564 ++ .../pip/_vendor/truststore/py.typed | 0 .../pip/_vendor/typing_extensions.py | 3641 +++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3421 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 16395 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 234 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20419 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36453 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13509 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10418 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4028 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20448 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 7310 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33963 bytes .../pip/_vendor/urllib3/_collections.py | 355 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1137 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 214 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1864 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11580 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5730 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24464 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35521 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7527 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 231 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17443 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14779 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 -> 215 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41271 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 225 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1841 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7352 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 -> 1162 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4763 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1568 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1368 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4199 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 3008 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21717 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15102 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5067 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10769 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11155 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15801 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4419 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 | 620 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../urllib3/util/ssl_match_hostname.py | 159 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 271 + .../pip/_vendor/urllib3/util/url.py | 435 + .../pip/_vendor/urllib3/util/wait.py | 152 + .../site-packages/pip/_vendor/vendor.txt | 18 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../werkzeug-3.0.4.dist-info/INSTALLER | 1 + .../werkzeug-3.0.4.dist-info/LICENSE.txt | 28 + .../werkzeug-3.0.4.dist-info/METADATA | 99 + .../werkzeug-3.0.4.dist-info/RECORD | 125 + .../werkzeug-3.0.4.dist-info/WHEEL | 4 + .../site-packages/werkzeug/__init__.py | 25 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1096 bytes .../__pycache__/_internal.cpython-312.pyc | Bin 0 -> 9772 bytes .../__pycache__/_reloader.cpython-312.pyc | Bin 0 -> 20230 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 32950 bytes .../__pycache__/formparser.cpython-312.pyc | Bin 0 -> 16811 bytes .../werkzeug/__pycache__/http.cpython-312.pyc | Bin 0 -> 49602 bytes .../__pycache__/local.cpython-312.pyc | Bin 0 -> 28473 bytes .../__pycache__/security.cpython-312.pyc | Bin 0 -> 6987 bytes .../__pycache__/serving.cpython-312.pyc | Bin 0 -> 46040 bytes .../werkzeug/__pycache__/test.cpython-312.pyc | Bin 0 -> 59851 bytes .../__pycache__/testapp.cpython-312.pyc | Bin 0 -> 8872 bytes .../werkzeug/__pycache__/urls.cpython-312.pyc | Bin 0 -> 8273 bytes .../__pycache__/user_agent.cpython-312.pyc | Bin 0 -> 2162 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 28141 bytes .../werkzeug/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 25218 bytes .../site-packages/werkzeug/_internal.py | 211 + .../site-packages/werkzeug/_reloader.py | 460 + .../werkzeug/datastructures/__init__.py | 34 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1611 bytes .../__pycache__/accept.cpython-312.pyc | Bin 0 -> 13801 bytes .../__pycache__/auth.cpython-312.pyc | Bin 0 -> 14416 bytes .../__pycache__/cache_control.cpython-312.pyc | Bin 0 -> 7895 bytes .../__pycache__/csp.cpython-312.pyc | Bin 0 -> 5268 bytes .../__pycache__/etag.cpython-312.pyc | Bin 0 -> 5061 bytes .../__pycache__/file_storage.cpython-312.pyc | Bin 0 -> 7929 bytes .../__pycache__/headers.cpython-312.pyc | Bin 0 -> 23204 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 11402 bytes .../__pycache__/range.cpython-312.pyc | Bin 0 -> 8247 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 48375 bytes .../werkzeug/datastructures/accept.py | 326 + .../werkzeug/datastructures/accept.pyi | 54 + .../werkzeug/datastructures/auth.py | 316 + .../werkzeug/datastructures/cache_control.py | 175 + .../werkzeug/datastructures/cache_control.pyi | 115 + .../werkzeug/datastructures/csp.py | 94 + .../werkzeug/datastructures/csp.pyi | 169 + .../werkzeug/datastructures/etag.py | 95 + .../werkzeug/datastructures/etag.pyi | 30 + .../werkzeug/datastructures/file_storage.py | 196 + .../werkzeug/datastructures/file_storage.pyi | 49 + .../werkzeug/datastructures/headers.py | 515 + .../werkzeug/datastructures/headers.pyi | 109 + .../werkzeug/datastructures/mixins.py | 242 + .../werkzeug/datastructures/mixins.pyi | 97 + .../werkzeug/datastructures/range.py | 180 + .../werkzeug/datastructures/range.pyi | 57 + .../werkzeug/datastructures/structures.py | 1010 ++ .../werkzeug/datastructures/structures.pyi | 206 + .../site-packages/werkzeug/debug/__init__.py | 564 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 23406 bytes .../debug/__pycache__/console.cpython-312.pyc | Bin 0 -> 11641 bytes .../debug/__pycache__/repr.cpython-312.pyc | Bin 0 -> 13783 bytes .../debug/__pycache__/tbtools.cpython-312.pyc | Bin 0 -> 16958 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 | 881 ++ .../site-packages/werkzeug/formparser.py | 419 + .../python3.12/site-packages/werkzeug/http.py | 1387 +++ .../site-packages/werkzeug/local.py | 653 ++ .../werkzeug/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 206 bytes .../__pycache__/dispatcher.cpython-312.pyc | Bin 0 -> 3324 bytes .../__pycache__/http_proxy.cpython-312.pyc | Bin 0 -> 9420 bytes .../__pycache__/lint.cpython-312.pyc | Bin 0 -> 17792 bytes .../__pycache__/profiler.cpython-312.pyc | Bin 0 -> 7210 bytes .../__pycache__/proxy_fix.cpython-312.pyc | Bin 0 -> 7207 bytes .../__pycache__/shared_data.cpython-312.pyc | Bin 0 -> 12709 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 | 282 + .../site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 134 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4679 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 10926 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7922 bytes .../routing/__pycache__/map.cpython-312.pyc | Bin 0 -> 39809 bytes .../__pycache__/matcher.cpython-312.pyc | Bin 0 -> 8245 bytes .../routing/__pycache__/rules.cpython-312.pyc | Bin 0 -> 39091 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 -> 202 bytes .../sansio/__pycache__/http.cpython-312.pyc | Bin 0 -> 5726 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 14049 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 21895 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 31407 bytes .../sansio/__pycache__/utils.cpython-312.pyc | Bin 0 -> 6021 bytes .../site-packages/werkzeug/sansio/http.py | 171 + .../werkzeug/sansio/multipart.py | 321 + .../site-packages/werkzeug/sansio/request.py | 536 + .../site-packages/werkzeug/sansio/response.py | 754 ++ .../site-packages/werkzeug/sansio/utils.py | 159 + .../site-packages/werkzeug/security.py | 161 + .../site-packages/werkzeug/serving.py | 1123 +++ .../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 -> 326 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 26133 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34567 bytes .../werkzeug/wrappers/request.py | 647 ++ .../werkzeug/wrappers/response.py | 831 ++ .../python3.12/site-packages/werkzeug/wsgi.py | 595 ++ venv/pyvenv.cfg | 5 + 1192 files changed, 197434 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/ci-cd.yml create mode 100644 deployment.yaml create mode 100644 service.yaml 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-2.1.5.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/blinker-1.8.2.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.1.7.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst create mode 100644 venv/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.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.0.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.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.4.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.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-24.2.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/pip-24.2.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__/search.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/completion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/debug.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/hash.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/list.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/search.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/show.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/installed.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/sdist.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/collector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/sources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_distutils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/_json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/candidate.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/direct_url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/format_control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/installation_report.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/scheme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/search_scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/target_python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/session.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/prepare.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/pyproject.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/constructors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_set.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/self_outdated_check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/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/encoding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filesystem.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filetypes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/glibc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/hashes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/misc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/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/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/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__/cmdline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/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__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__version__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/certs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/hooks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/packages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/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.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/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.0.4.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.0.4.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.0.4.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.0.4.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.0.4.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/accept.pyi 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/cache_control.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/csp.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/csp.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/etag.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/etag.pyi 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/file_storage.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/headers.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/headers.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/mixins.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/mixins.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/range.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/range.pyi create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/structures.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/structures.pyi 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/.github/workflows/ci-cd.yml b/.github/workflows/ci-cd.yml new file mode 100644 index 0000000..b6464f0 --- /dev/null +++ b/.github/workflows/ci-cd.yml @@ -0,0 +1,37 @@ +name: CI/CD Pipeline + +on: + push: + branches: + - main + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v2 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v1 + + - name: Log in to Docker Hub + uses: docker/login-action@v2 + with: + username: ${{ secrets.REGINECYRILLE }} # Replace with your Docker Hub username + password: ${{ secrets.xW4zQXF_FY6Z }} # Replace with your Docker Hub password + + - name: Build and push Docker image + uses: docker/build-push-action@v2 + with: + context: . + push: true + tags: your_docker_username/your_image_name:latest + + - name: Trivy scan + uses: aquasecurity/trivy-action@master + with: + image-ref: your_docker_username/your_image_name:latest + format: 'table' + exit-code: '1' diff --git a/Dockerfile b/Dockerfile index c110804..9f18f3a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,17 @@ -FROM ubuntu:20.04 -RUN apt-get update && apt-get install -y python3 python3-pip -RUN pip3 install flask +# Use an official Python runtime as a parent image +FROM python:3.8-slim + +# Set the working directory inside the container +WORKDIR /opt + +# Copy app.py into the container COPY app.py /opt/ -ENTRYPOINT FLASK_APP=/opt/app.py flask run --host=0.0.0.0 --port=8080 + +# Install Flask using pip +RUN pip install flask + +# Expose port 8080 to allow external access +EXPOSE 8080 + +# Run the Flask application +CMD ["flask", "run", "--host=0.0.0.0", "--port=8080"] diff --git a/deployment.yaml b/deployment.yaml new file mode 100644 index 0000000..c48a139 --- /dev/null +++ b/deployment.yaml @@ -0,0 +1,19 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: flask-app +spec: + replicas: 1 + selector: + matchLabels: + app: flask-app + template: + metadata: + labels: + app: flask-app + spec: + containers: + - name: flask-app + image: reginecyrille/flask-app:latest + ports: + - containerPort: 8080 diff --git a/service.yaml b/service.yaml new file mode 100644 index 0000000..7797ed3 --- /dev/null +++ b/service.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Service +metadata: + name: flask-app-service +spec: + type: LoadBalancer + ports: + - port: 80 + targetPort: 8080 + selector: + app: flask-app diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 0000000..b49d77b --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 0000000..f8aa6fd --- /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/cbt/Desktop/CGQ2/simple-webapp-flask/venv") +else + # use the path as-is + export VIRTUAL_ENV="/Users/cbt/Desktop/CGQ2/simple-webapp-flask/venv" +fi + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(venv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 0000000..55cfe4b --- /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/cbt/Desktop/CGQ2/simple-webapp-flask/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(venv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 0000000..29d052a --- /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/cbt/Desktop/CGQ2/simple-webapp-flask/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(venv) " +end diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 0000000..e7d6407 --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,8 @@ +#!/Users/cbt/Desktop/CGQ2/simple-webapp-flask/venv/bin/python3.12 +# -*- 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 0000000..8b78956 --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/Users/cbt/Desktop/CGQ2/simple-webapp-flask/venv/bin/python3.12 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 0000000..8b78956 --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/Users/cbt/Desktop/CGQ2/simple-webapp-flask/venv/bin/python3.12 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.12 b/venv/bin/pip3.12 new file mode 100755 index 0000000..8b78956 --- /dev/null +++ b/venv/bin/pip3.12 @@ -0,0 +1,8 @@ +#!/Users/cbt/Desktop/CGQ2/simple-webapp-flask/venv/bin/python3.12 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 0000000..11b9d88 --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3.12 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 0000000..11b9d88 --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +python3.12 \ No newline at end of file diff --git a/venv/bin/python3.12 b/venv/bin/python3.12 new file mode 120000 index 0000000..f3d5d0b --- /dev/null +++ b/venv/bin/python3.12 @@ -0,0 +1 @@ +/usr/local/opt/python@3.12/bin/python3.12 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/LICENSE.rst @@ -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-2.1.5.dist-info/METADATA b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/METADATA new file mode 100644 index 0000000..dfe37d5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/METADATA @@ -0,0 +1,93 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.1.5 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +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 Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +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 +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +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. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +Examples +-------- + +.. code-block:: 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 + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Chat: https://discord.gg/pallets diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/RECORD b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/RECORD new file mode 100644 index 0000000..2f91c3e --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.1.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.1.5.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-2.1.5.dist-info/METADATA,sha256=2dRDPam6OZLfpX0wg1JN5P3u9arqACxVSfdGmsJU7o8,3003 +MarkupSafe-2.1.5.dist-info/RECORD,, +MarkupSafe-2.1.5.dist-info/WHEEL,sha256=1_erwh2TCU3TrYzgBQGCtZskLEmw2vbfn7Xu2mHHvyU,111 +MarkupSafe-2.1.5.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=r7VOTjUq7EMQ4v3p4R1LoVOGJg6ysfYRncLr34laRBs,10958 +markupsafe/__pycache__/__init__.cpython-312.pyc,, +markupsafe/__pycache__/_native.cpython-312.pyc,, +markupsafe/_native.py,sha256=GR86Qvo_GcgKmKreA1WmYN9ud17OFwkww8E-fiW-57s,1713 +markupsafe/_speedups.c,sha256=X2XvQVtIdcK4Usz70BvkzoOfjTCmQlDkkjYSn-swE0g,7083 +markupsafe/_speedups.cpython-312-darwin.so,sha256=zO55W2sOSohVnMko0CD2bITP4v6UpfeRj-x2I_8pGkA,35208 +markupsafe/_speedups.pyi,sha256=vfMCsOgbAXRNLUXkyuyonG8uEWKYU4PDqNuMaDELAYw,229 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL new file mode 100644 index 0000000..0271fd6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.42.0) +Root-Is-Purelib: false +Tag: cp312-cp312-macosx_10_9_x86_64 + diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-2.1.5.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/LICENSE.txt new file mode 100644 index 0000000..79c9825 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.8.2.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.8.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/METADATA new file mode 100644 index 0000000..efa45f5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: blinker +Version: 1.8.2 +Summary: Fast, simple object-to-object and broadcast signaling +Author: Jason Kirtland +Maintainer-email: Pallets Ecosystem +Requires-Python: >=3.8 +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.8.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/RECORD new file mode 100644 index 0000000..46b35c6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/RECORD @@ -0,0 +1,12 @@ +blinker-1.8.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.8.2.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.8.2.dist-info/METADATA,sha256=3tEx40hm9IEofyFqDPJsDPE9MAIEhtifapoSp7FqzuA,1633 +blinker-1.8.2.dist-info/RECORD,, +blinker-1.8.2.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +blinker/__init__.py,sha256=ymyJY_PoTgBzaPgdr4dq-RRsGh7D-sYQIGMNp8Rx4qc,1577 +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=nIZJEtXQ8LLZZJrwVp2wQcdfCzDixvAHR9VpSWiyVcQ,22574 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/blinker-1.8.2.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.8.2.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/blinker/__init__.py b/venv/lib/python3.12/site-packages/blinker/__init__.py new file mode 100644 index 0000000..c93527e --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/__init__.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import typing as t + +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", +] + + +def __getattr__(name: str) -> t.Any: + import warnings + + if name == "__version__": + import importlib.metadata + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Blinker 1.9.0. Use feature detection or" + " 'importlib.metadata.version(\"blinker\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("blinker") + + if name == "receiver_connected": + from .base import _receiver_connected + + warnings.warn( + "The global 'receiver_connected' signal is deprecated and will be" + " removed in Blinker 1.9. Use 'Signal.receiver_connected' and" + " 'Signal.receiver_disconnected' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _receiver_connected + + if name == "WeakNamespace": + from .base import _WeakNamespace + + warnings.warn( + "'WeakNamespace' is deprecated and will be removed in Blinker 1.9." + " Use 'Namespace' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _WeakNamespace + + raise AttributeError(name) 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..73b3f811c1a6545249225e021e44e4ee8ffba8c5 GIT binary patch literal 1811 zcmb7E&2Jk;6rZuzyX&<#PLogqw9Y1x>a5h*6e?9n2q~qATO<@v#a>op&&1t$y=%>m z9XX0cK^)-35x61_pmO9d;L62K4@Fy9s?>7GEh0Jf0&mtIN%Mi!CwunId-Hz3H}l@i zpQdRbkUzfschgo8dL}1hNevZz*aGEyL=nY4YGMatsi*vulcs5^_)0V5WWbiD8PHWn zO>`A>&CwEF16_CYMAt#jI@v_ef^IklMs-AupRkjod7ArLaq``iZSG5Y8^<{k1fd|p z3xjBV9}kV`we`=zcZsr1()NWLkS2>-q{d{xI!x$>R}Y8})2y71ed@%lM#BXv&j2Kc z%_FYKL6<{T4)SPfl5i|?Wf~!Tcpa>8BA6l{_3$p7Mq>p6ZY37nOYPz(w>s7+$jT0srq1)(FOuuE#bAOPP4w+)Ou;aI-lFPkUO0q=Hmmf)QHYm&ro!7?B{ghR-_8kG0Xd zcm|SU9)!EKFbIHzQLYTv&$?%QJ3q^9*8Q+be5-WUU$Tas`06`O_FEcuboo4Bd1`0; z)Qcv0AMZFe?=sRjc~z#|mn=I@>7_Y@zG{Vr`A#^F$!#Onw+RotpdQ6DXKNKJ(i_j* z88rk{_3m(atdHv%Yomh3N|i*6UxJEo*^Kej+PJAc;ymPbCRPG?68M~SW+!aN5s|#R zmXsHy0zJi}O06m?cUaUAVXN}t$Dh1Yi6G8rtJ|zfTCLShpG1vHhXtJq^jM|U75Bp6 z-SQ2&POw#Ym>Q(cqROa+Dz57Vo^aiAt1GWW9eNUSbX~px%$MOG{SL!@^hB9`s^z}v z?P*t@=!;MF>F>;M&4X0Ryp4}kWG?*m`usr-WiKBgHESG9q3Jgs7Zx8D79SVvhXwl= z`%&R$U%v?u{lfB|wmi^RPhi|SA7Z($FGgT}V+I)WXu8y2STKXZ0)MmJBJv@IrsT8Pc}TKH%^e!>bC%Xv1)j#uyLK(la#k gH+pS=mIvtS0KGLp^YHse(Q>K#+R@xKypTZs2MF%xV*mgE 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..adf7a870cee6d213f4e1cbe3cd5981adfc5ba568 GIT binary patch literal 2733 zcmb6bO>YxNbjG{(u0LXjgwGOS`A~^but_;oDu@<=1eItc8fYb_(Pq6n4x6mk?#vjl zsb~SIQt6>LP(UCq?VDLUaVS*kNc-l^dv9jn zywCZyrze46{Cw%}($yG3e~3kAs3C%vzX4<(Imp2tD&qpi0*`o+vQkjnc(f3ev{*rd zS@HC8ybzZ>74SqMfl&kzZE9oZ@YUIg-p1jokcyxa$cbG>j&?iJru8@pN58BV(oWJz zIq}QULZ%+c_WUK-SsWxS->-0syA_{}z*?cC1XJQuVoiTU__>M`;4^l3RtS}F!po-s zxdIm>sDK?*h@6EB78Dm1R3}2Bj&d0Ij^08g?5LMhg_sj}qM(Qd3dLa7K_Lz1cne*` zg~TYzrh?dLyD z8h1UHyM*Pcb=m`eYotT3<=Xmf1{!-Gz>67lFPWJ;IDhEIp*zX#_xd*qY=PhD-?Nz7 z^C;avJ2_ifu$R)iTFSkF9WCX0ayB`4{EoimUZ$^=ScW6e8utj3O84{u5<15eLUPm* zO#*TY(+o`6NT4#}mE?knjfO$Rwm>&c*LS&THZm)EhXe!IOjsQBUcb4eUW?OySlMl_ z0Sci3pH$&3KtP4pM#pHV3f%xQppPgIOl(}$fRZX*qd`d6EhJL_K!Z&G_4;gmQQ!O@ zN(_MLo0KTwZZ)Wg%5Ejnra4JC1e8T5A#NHQR*cb2ep~EHhYIzspO4>&x0;LkR;f}} zmBtMeNUR_hCOFkWw#}g10H@ml1nNk|C)tQxNOBu*tm8F^#W9{c>eq*iTrM}BO$rZ* z&^FB=VVdQNQ}YC#GR@Cxme=M$GB_36G{X$Zm}XbS1geNjx=8@xCo1d|^t6-2CY}db zgy}k z0cjAqcTKcJ;S3oqzW_3i_(~*AtyBkKw8v_Fp!>MkDF;Ltw6Ir4r;@CZ6SjY4bmU4< zQMgDCIhu%zE6TxzcjYKWI_-%ZJ<=4 zK&Qke?s-_kiV@!-PkMZq*&}TG^T=rt8ogF!l-NX#g|m zsgCr_Z`!6i+NK5Nt~T&AhI;$vcFzyp7+T8g_@VE+V?Uny{?yXW;l<4GqCWgcTQ|4+ zrgC$1u5nk}^%#WvTM5{cO1JE*@6L>b>DujIQIZwWRXzjce?&p5+XGG9@eX)KgM;K~ zLWf$V%K`}5w-M|UGq|V^K1!xrZ0_Vza@(T1ty2)>KVsoKKxTU*VdqX-?3@UdP`#K`go>c1 z2LLp7+PPz(l#m!310BZBjE@f)qGF62O*w}rL5UH(Y_BK_r5d~^pe#@@EDADq#q%Iq z#Cs`c741L~0Nc_ML5$a{u0I)I9%vWf1tsn&Y$B}_XlLqG0*{1HBauTgK%^yZp)j#U z<9Mkb4r|d7Dhwo2nY{<#v4Syvh<5#nw%$kS`>5|B+Vl`@|6T2wIeO*8OCPrEuSRC@ X^Vn8A@B{%^KAge*&-SQzyFB|Jt=MB> 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..f45104032dfdb51b4243580ef2d279846ab3117a GIT binary patch literal 25425 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 ZyQe(3bLXb8d&S`tU2Fbwv4Mf%{{@{Kf6f2^ literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/blinker/_utilities.py b/venv/lib/python3.12/site-packages/blinker/_utilities.py new file mode 100644 index 0000000..000c902 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/_utilities.py @@ -0,0 +1,64 @@ +from __future__ import annotations + +import collections.abc as c +import inspect +import typing as t +from weakref import ref +from weakref import WeakMethod + +T = t.TypeVar("T") + + +class Symbol: + """A constant symbol, nicer than ``object()``. Repeated calls return the + same instance. + + >>> Symbol('foo') is Symbol('foo') + True + >>> Symbol('foo') + foo + """ + + symbols: t.ClassVar[dict[str, Symbol]] = {} + + def __new__(cls, name: str) -> Symbol: + if name in cls.symbols: + return cls.symbols[name] + + obj = super().__new__(cls) + cls.symbols[name] = obj + return obj + + def __init__(self, name: str) -> None: + self.name = name + + def __repr__(self) -> str: + return self.name + + def __getnewargs__(self) -> tuple[t.Any, ...]: + return (self.name,) + + +def make_id(obj: object) -> c.Hashable: + """Get a stable identifier for a receiver or sender, to be used as a dict + key or in a set. + """ + if inspect.ismethod(obj): + # The id of a bound method is not stable, but the id of the unbound + # function and instance are. + return id(obj.__func__), id(obj.__self__) + + if isinstance(obj, (str, int)): + # Instances with the same value always compare equal and have the same + # hash, even if the id may change. + return obj + + # Assume other types are not hashable but will always be the same instance. + return id(obj) + + +def make_ref(obj: T, callback: c.Callable[[ref[T]], None] | None = None) -> ref[T]: + if inspect.ismethod(obj): + return WeakMethod(obj, callback) # type: ignore[arg-type, return-value] + + return ref(obj, callback) diff --git a/venv/lib/python3.12/site-packages/blinker/base.py b/venv/lib/python3.12/site-packages/blinker/base.py new file mode 100644 index 0000000..ec494b1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/base.py @@ -0,0 +1,621 @@ +from __future__ import annotations + +import collections.abc as c +import typing as t +import warnings +import weakref +from collections import defaultdict +from contextlib import AbstractContextManager +from contextlib import contextmanager +from functools import cached_property +from inspect import iscoroutinefunction +from weakref import WeakValueDictionary + +from ._utilities import make_id +from ._utilities import make_ref +from ._utilities import Symbol + +if t.TYPE_CHECKING: + 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 + + if _receiver_connected.receivers and self is not _receiver_connected: + try: + _receiver_connected.send( + self, receiver_arg=receiver, sender_arg=sender, weak_arg=weak + ) + except TypeError: + 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 temporarily_connected_to( + self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY + ) -> AbstractContextManager[None]: + """Deprecated alias for :meth:`connected_to`. + + .. deprecated:: 1.1 + Renamed to ``connected_to``. Will be removed in Blinker 1.9. + + .. versionadded:: 0.9 + """ + warnings.warn( + "'temporarily_connected_to' is renamed to 'connected_to'. The old name is" + " deprecated and will be removed in Blinker 1.9.", + DeprecationWarning, + stacklevel=2, + ) + return self.connected_to(receiver, sender) + + 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: + 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() + + +_receiver_connected = Signal( + """\ +Sent by a :class:`Signal` after a receiver connects. + +:argument: the Signal that was connected to +:keyword receiver_arg: the connected receiver +:keyword sender_arg: the sender to connect to +:keyword weak_arg: true if the connection to receiver_arg is a weak reference + +.. deprecated:: 1.2 + Individual signals have their own :attr:`~Signal.receiver_connected` and + :attr:`~Signal.receiver_disconnected` signals with a slightly simplified + call signature. This global signal will be removed in Blinker 1.9. +""" +) + + +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 + + +if t.TYPE_CHECKING: + + class PNamespaceSignal(t.Protocol): + def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... + + # Python < 3.9 + _NamespaceBase = dict[str, NamedSignal] # type: ignore[misc] +else: + _NamespaceBase = dict + + +class Namespace(_NamespaceBase): + """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 _WeakNamespace(WeakValueDictionary): # type: ignore[type-arg] + """A weak mapping of names to signals. + + Automatically cleans up unused signals when the last reference goes out + of scope. This namespace implementation provides similar behavior to Blinker + <= 1.2. + + .. deprecated:: 1.3 + Will be removed in Blinker 1.9. + + .. versionadded:: 1.3 + """ + + def __init__(self) -> None: + warnings.warn( + "'WeakNamespace' is deprecated and will be removed in Blinker 1.9." + " Use 'Namespace' instead.", + DeprecationWarning, + stacklevel=2, + ) + super().__init__() + + 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] # type: ignore[no-any-return] + + +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. +""" + + +def __getattr__(name: str) -> t.Any: + if name == "receiver_connected": + warnings.warn( + "The global 'receiver_connected' signal is deprecated and will be" + " removed in Blinker 1.9. Use 'Signal.receiver_connected' and" + " 'Signal.receiver_disconnected' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _receiver_connected + + if name == "WeakNamespace": + warnings.warn( + "'WeakNamespace' is deprecated and will be removed in Blinker 1.9." + " Use 'Namespace' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _WeakNamespace + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/blinker/py.typed b/venv/lib/python3.12/site-packages/blinker/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/LICENSE.rst @@ -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-8.1.7.dist-info/METADATA b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA new file mode 100644 index 0000000..7a6bbb2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/METADATA @@ -0,0 +1,103 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.7 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Chat, https://discord.gg/pallets +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 +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ 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 + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: 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() + +.. code-block:: text + + $ 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 + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Chat: https://discord.gg/pallets diff --git a/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD new file mode 100644 index 0000000..497ee45 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/RECORD @@ -0,0 +1,39 @@ +click-8.1.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.1.7.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.7.dist-info/METADATA,sha256=qIMevCxGA9yEmJOM_4WHuUJCwWpsIEVbCPOhs45YPN4,3014 +click-8.1.7.dist-info/RECORD,, +click-8.1.7.dist-info/WHEEL,sha256=5sUXSg9e4bi7lTLOHcm6QEYwO5TIF1TNbTSVFVjcJcc,92 +click-8.1.7.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=YDDbjm406dTOA0V8bTtdGnhN7zj5j-_dFRewZF_pLvw,3138 +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=5318agQpbt4kroKsbqDOYpTSWzL_YCZVUQiTT04yXmc,18744 +click/_termui_impl.py,sha256=3dFYv4445Nw-rFvZOTBMBPYwB1bxnmNk9Du6Dm_oBSU,24069 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=j6oEWtGgGna8JarD6WxhXmNnxLnfRjwXglbBc-8jr7U,114086 +click/decorators.py,sha256=-ZlbGYgV-oI8jr_oH4RpuL1PFS-5QmeuEAsLDAYgxtw,18719 +click/exceptions.py,sha256=fyROO-47HWFDjt2qupo7A3J32VlpM-ovJnfowu92K3s,9273 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=LKyYQE9ZLj5KgIDXkrcTHQRXIggfoivX14_UVIn56YA,19067 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=Ty3VM_ts0sQhj6u7eFTiLwHPoTgcXTGEAUg2OpLqYKw,18460 +click/termui.py,sha256=H7Q8FpmPelhJ2ovOhfCRhjMtCpNyjFXryAMLZODqsdc,28324 +click/testing.py,sha256=1Qd4kS5bucn1hsNIRryd0WtTMuCpkA93grkWxT8POsU,16084 +click/types.py,sha256=TZvz3hKvBztf-Hpa2enOmP4eznSPLzijjig5b_0XMxE,36391 +click/utils.py,sha256=1476UduUNY6UePGU4m18uzVHLt1sKM2PP3yWsQhbItM,20298 diff --git a/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL new file mode 100644 index 0000000..2c08da0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.41.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.1.7.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/venv/lib/python3.12/site-packages/click/__init__.py b/venv/lib/python3.12/site-packages/click/__init__.py new file mode 100644 index 0000000..9a1dab0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/__init__.py @@ -0,0 +1,73 @@ +""" +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 .core import Argument as Argument +from .core import BaseCommand as BaseCommand +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 MultiCommand as MultiCommand +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 .parser import OptionParser as OptionParser +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 + +__version__ = "8.1.7" 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..23297df46183646082390fc636a3481bbd802a0f GIT binary patch literal 2711 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 S&~`_!bLsAaDd?CS`o94eqaGgs 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..eb0fb8b4f6e321b57c3c2c6e551f7e7d6eea5180 GIT binary patch literal 30539 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 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..bab3637df1b59ac6e10be65a64856591b206e0ca GIT binary patch literal 11991 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 IP7dh*0C^(@Qvd(} 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..1971a96373645ce623288d6d3e95ada1aec499da GIT binary patch literal 135536 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 ?|^#35}if`Eizjx@b=*hth3A=n#~@GP{q01sJb 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 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..b864f936b647b1025cd3efcd81aa5d2e83e7b0c4 GIT binary patch literal 23984 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 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..9f627c6b64d6f3251ffcd58e3f481fa7e4ae4a41 GIT binary patch literal 14747 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 Q$H#A0yoWTy8r+H literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5481c90a6c8a73a815f770290423b0077379ec0f GIT binary patch literal 14066 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 aE(L#h`QyvWp}W1y;Y`=dkEx8Y!~X@bpR+mu literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ac4099ff2cb898f3cb6c61c63601cb95661842b8 GIT binary patch literal 3131 zcmbVOO>7&-6`ox#C5og(NtPT}O`LI)CSVeiwt^xB(KdBuJ5}P+iLD&WqM?SnLvf|$ z?sj%aih|Ngh59c>W*HI zm0}v<+G3(7et#56B^xgdSTW0R2J4AZLL)liv1?tS(hz((asP|n%*t4!R^n28M=tdZ za${DUr>y~aJJtL4{%8$;3l>$w8tT^sy8oANl9%G8lr?UpE*Yf}>wuMpF=I_w!~37b z(|Fc5SrWYkOGZHJXj{up-a#{qSuKn^p2?g$04;&l;Ed-=zAVFmz;?I`qu{b3ToH%& zCJObp7%VylbXQ25Y-q&|=)?f51C*rqUdg{4a1rFqip-zn!IJd+{LFJNP3HrLm(nB1_gc_*)P(#Mt!Oq#mNYE8R&L_ zfk!DY{s@yRWQfQes1|kD+S4peB5JBFB3^r%rK2;ib-z4M9wBlkyroJM{Gh5oO2na8 zwN(BYmw#H1=7;8adr_7IH%kjP+8-&izHPz z(=MJlO6O{JKuzY-3a5>LTa*Qq(H3h{=_M&NW|}z?2g!@)Lf8EJDQ7cP@_lfwbZvO=}tnuU3v1wqfx^VH&|Cz$j^Pag_N+jFTM zC`G=o>rB{A8?CN399s1Rt#QYPn503&tl>qvs<~P7=4q>D!*1PPs7bi2Qes0s2p&kd zw(U~0#@q$lU7)rMK%&N)Ht4J{LWxI?FZj_@M>l2$nhJQ>CMFSziy?ce*gSt>hUj$4uYR%CU1=&-hB8cH^yf^ z9NSDk--(gYgWCfnJ^JtMA(XfmV7a;YSe9&LPK?H`kDN%w-cQA0x{FYd9u%QeU~+{> z=%cnDoh%~#>}i&^utOk=y$aeVvr4XYX+k4yJsVqj;zbBgjv49lRxcWQ`PX9x1$0gv z1VzQHArPoAQ7&7yDa++B2_e@FjBo&mox2v4l$a@(`}j0WV;=OfSWr-L6rSJ+bZg`b zBYFAk`q`Vt;Vt9v?^;*&8^)72jp;38`kkjgHlB%?7bJHYI#2=iW0?FuK=n#Iz@TOI zmG7S8b*~9HV8TGXq7H9zU=HLj+=>t=W@GB|3W+f0dwx_qurR1#3RAGRbIC_wdm5f# z9J=U|XV%Z$G$yu;iI0tg>Q-Ug^c+v@iUPb?-{n@xy1q)z_Z1gQ|ML#rLm|-C)2rHk z5po_cXRQ2b7Rk(IPL~DIy--5c#d;YXv4dAto5~~#^?3m}cDCBh>>UC@K1N=Yj|W|H zffbN2k|ejDq8=b7T1W{>#PPf(6z~4FQg|d1XxU+!^>05zP7dY54QtzYv&Einp>_4#dzR zwNx*PU?>U{)lWrsEF6$+A8Lj;0Gr{EtO?F6T%&8l;kgSho+{7$^wi7?v&HAau}HQI z|6trjrVm10av(e?lhF}T(m{+0$77a)Cp0Ra=Y)x~K9)b`sH_qgbqa(%v3W1?gSuxm z9R4G53`CFyf_I_Yj%k|q85#eaeEW9HxcuzJXFoH(^SSZRKZZtr`@q@&u$UgZJheX6 z(KRgr#HOdWakic4?%&1Lo5nVQ;p#8{va+#qJ-d}Z`6aIJi{DL5YNIFx!#iVtoqBib z`s~*6(;ZxQj_KO>J4s!8;BImlq{iN!dTZ+HNnqP;0_*E9y;u5M=|f}dhd=uY*UC}< E0rOq&j{pDw 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..382694a5ab1ebf473d9b539c9c7628689b96eb1f GIT binary patch literal 21496 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 C0%dyu 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..38a2e6d06613ea607e0ca748776f468583f718a5 GIT binary patch literal 22768 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 DRQukG literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..604eb86aaeff5d3081e2befcf24bce79fa382e13 GIT binary patch literal 32801 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


8upDB%>DZ4&X>iFlz&y;naDfM@puD4En{lsUk z<~y#E$&RH z7j-KrUn%lcl&@CYRWm1ZHI%Pa+!Zs8xpkCZFP_&?euLt!o_R4>Px+0CyK?40ZWHA< zEAE<^{#*m)HSv54nT z%QS$DA}AVrpG=i;HO+b z@dvK%n%*_@>VmH!N3CH3ii+=-QBHHIRkJU=d;Z4xoPzA!8^1mB{gL~W1r&`tGV3;G zTG}!P4rh)WBXICPF2=6gbgw3=s!yp57U%AilokTv=Es1uq9*4Nd9Sje{@ryq*3DG| zsdWo=yK}|jh0lcWh3hY0dwKTNdG!bG_uc7Ddlzb27JRKazbF<^Dk`u0uK8y7zuSJJ z9c_f?U--fK_s`Eo7wX#<$`9sBM7dI>dR?weJ-Ttv9}QOZ~UL-}QZX;KMimc>IUs zf4cRDUrQhBTG)3s{X%!Tp?hK7`J5Bg?f|9j)9o|*g1Mf8O-8#mo+IPXyLPivK3y*Pbww&L9l zH#W?5+}N~Gx-;jbH+KRhSD&7KdL}V_Hs_`XG~N>KJv4nH=ix_Qy4t*$vlw|boe!Js zUZ`x$`T1FZUYBsTRH>=G{`9q{<%svw_IWG#{_*+N5BL9Z`w!bc3jOdzde_qn4bLo8 zKbtG#I^{}vRjz`wl}bf*u8OljVQsF4v$aZDWo{j3*DF{eb)4N`lhrHNURm&M&eikt zjVAm&dz<*#W@X)m9M1$+Y*Fp~E%fyMu*vDd6 zhJc}ptK-w-v)dNRz(@F5sZv(XbW^=hx;a0-~7YLSSRAf}bI3MUV_nc@;ma zHW?SMq#Ax!i+_NDFOk$2s)qG7XSclDbff9oFD>}C<=pg^=CLH_ z;jEVya4~0bd4Jw8xOJ>=OhI@$oGalXVv%zet^&XV3}ZQhan{rW)%QwvtL21a(YK^a zCm!C(UuXCY5F`#duAjMf2B-SkW-lyM?_4Nu%6aI$msnUa<$Sb0{FGy0XdPEg$8*#b zF&)oaJ#Y5RsMo#MybJES`(=21?7Cjl zA*JoOdah{RIp<%f*|Xr=yQmzzS5&WVnAw)YDd7!sZTIOb_n1>Hn+g87cE>{Pj=97_ i?QYuA%I*akP*P>?-FB@kr{L#&H-CMoe?h-k()hoN`L5^y 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..ca0ab27094a0e67d5e66fa936cfce166cbdf485e GIT binary patch literal 24573 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 VFMZ*X1<=D$leX8sXkmKe{{w9V+@Syf 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..1accd512e1416acc8f0b600c519d3c9a5cce9446 GIT binary patch literal 26303 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/_compat.py b/venv/lib/python3.12/site-packages/click/_compat.py new file mode 100644 index 0000000..23f8866 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_compat.py @@ -0,0 +1,623 @@ +import codecs +import io +import os +import re +import sys +import typing as t +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + 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("") # type: ignore + 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.Optional[t.BinaryIO]: + # 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.Optional[t.BinaryIO]: + # 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: t.Optional[str]) -> 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: t.Optional[str], errors: t.Optional[str] +) -> 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: t.Optional[str], + errors: t.Optional[str], + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.Optional[t.BinaryIO]], + 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: t.Optional[str], + errors: t.Optional[str], + 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: t.Optional[str], + errors: t.Optional[str], + 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: t.Optional[str] = None, errors: t.Optional[str] = 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: t.Optional[str] = None, errors: t.Optional[str] = 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: t.Optional[str] = None, errors: t.Optional[str] = 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: t.Union[str, "os.PathLike[str]", int], + mode: str, + encoding: t.Optional[str], + errors: t.Optional[str], +) -> 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: "t.Union[str, os.PathLike[str]]", + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, +) -> t.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: t.Optional[int] = 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: t.Optional[t.Type[BaseException]], *_: t.Any) -> 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.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = 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: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi( # noqa: F811 + stream: t.TextIO, color: t.Optional[bool] = 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): + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + + 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: t.Optional[str], errors: t.Optional[str] + ) -> t.Optional[t.TextIO]: + 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.Optional[t.TextIO]], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.Optional[t.TextIO]]: + cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.Optional[t.TextIO]: + 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: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: t.Mapping[ + str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] +] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/venv/lib/python3.12/site-packages/click/_termui_impl.py b/venv/lib/python3.12/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..f744657 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_termui_impl.py @@ -0,0 +1,739 @@ +""" +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. +""" +import contextlib +import math +import os +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +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: t.Optional[t.Iterable[V]], + length: t.Optional[int] = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + label: t.Optional[str] = None, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = 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.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(t.Iterable[V], range(length)) + self.iter: t.Iterable[V] = iter(iterable) + self.length = length + self.pos = 0 + self.avg: t.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: t.Optional[int] = None + self.entered: bool = False + self.current_item: t.Optional[V] = None + self.is_hidden: bool = not isatty(self.file) + self._last_line: t.Optional[str] = None + + def __enter__(self) -> "ProgressBar[V]": + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self.render_finish() + + def __iter__(self) -> t.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.is_hidden: + 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.is_hidden: + # Only output the label as it changes if the output is not a + # TTY. Use file=stderr if you expect to be piping stdout. + 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: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) # type: ignore + 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: t.Optional[V] = 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) -> t.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 self.is_hidden: + 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: t.Iterable[str], color: t.Optional[bool] = 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) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system(f'more "{filename}"') == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + stdin = t.cast(t.BinaryIO, c.stdin) + encoding = get_best_encoding(stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + stdin.write(text.encode(encoding, "replace")) + except (OSError, KeyboardInterrupt): + pass + else: + stdin.close() + + # 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 + + +def _tempfilepager( + generator: t.Iterable[str], cmd: str, color: t.Optional[bool] +) -> None: + """Page through text by invoking a program on a temporary file.""" + 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: + os.system(f'{cmd} "{filename}"') + finally: + os.close(fd) + os.unlink(filename) + + +def _nullpager( + stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] +) -> 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: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = 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 os.system(f"which {editor} >/dev/null 2>&1") == 0: + return editor + return "vi" + + def edit_file(self, filename: str) -> None: + import subprocess + + editor = self.get_editor() + environ: t.Optional[t.Dict[str, str]] = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + c = subprocess.Popen(f'{editor} "{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 + + def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: + import tempfile + + if not text: + 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_file(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") # type: ignore + 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.replace('"', "")) + args = f'explorer /select,"{url}"' + else: + url = url.replace('"', "") + wait_str = "/WAIT" if wait else "" + args = f'start {wait_str} "" "{url}"' + return os.system(args) + elif CYGWIN: + if locate: + url = os.path.dirname(_unquote_file(url).replace('"', "")) + args = f'cygstart "{url}"' + else: + url = url.replace('"', "") + wait_str = "-w" if wait else "" + args = f'cygstart {wait_str} "{url}"' + return os.system(args) + + 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) -> t.Optional[BaseException]: + 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 WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> t.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`. + func: t.Callable[[], str] + + if echo: + func = msvcrt.getwche # type: ignore + else: + func = msvcrt.getwch # type: ignore + + 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 tty + import termios + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + f: t.Optional[t.TextIO] + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/venv/lib/python3.12/site-packages/click/_textwrap.py b/venv/lib/python3.12/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_textwrap.py @@ -0,0 +1,49 @@ +import textwrap +import typing as t +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: t.List[str], + cur_line: t.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) -> t.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 0000000..6b20df3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_winconsole.py @@ -0,0 +1,279 @@ +# 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. +import io +import sys +import time +import typing as t +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 + +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_ = [ + ("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, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + 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): + return True + + @staticmethod + def _get_error_message(errno): + 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): + 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: t.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): + 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: t.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: t.Optional[str], errors: t.Optional[str] +) -> t.Optional[t.TextIO]: + if ( + get_buffer is not None + and encoding in {"utf-16-le", None} + and errors in {"strict", None} + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/venv/lib/python3.12/site-packages/click/core.py b/venv/lib/python3.12/site-packages/click/core.py new file mode 100644 index 0000000..cc65e89 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/core.py @@ -0,0 +1,3042 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +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 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: + import typing_extensions as te + 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 +) -> t.Iterator[t.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(MultiCommand, 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_multicommand( + base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + f"{hint}. Command {base_command.name!r} is set to chain and" + f" {cmd_name!r} was added as a subcommand but it in itself is a" + f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" + f" within a chained {type(base_command).__name__} named" + f" {base_command.name!r})." + ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( + ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.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: t.Sequence["Parameter"], + declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item: "Parameter") -> t.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.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: t.Type["HelpFormatter"] = HelpFormatter + + def __init__( + self, + command: "Command", + parent: t.Optional["Context"] = None, + info_name: t.Optional[str] = None, + obj: t.Optional[t.Any] = None, + auto_envvar_prefix: t.Optional[str] = None, + default_map: t.Optional[t.MutableMapping[str, t.Any]] = None, + terminal_width: t.Optional[int] = None, + max_content_width: t.Optional[int] = None, + resilient_parsing: bool = False, + allow_extra_args: t.Optional[bool] = None, + allow_interspersed_args: t.Optional[bool] = None, + ignore_unknown_options: t.Optional[bool] = None, + help_option_names: t.Optional[t.List[str]] = None, + token_normalize_func: t.Optional[t.Callable[[str], str]] = None, + color: t.Optional[bool] = None, + show_default: t.Optional[bool] = 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: t.Dict[str, t.Any] = {} + #: the leftover arguments. + self.args: t.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: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.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: t.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: t.Optional[t.MutableMapping[str, t.Any]] = 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: t.Optional[str] = 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: t.Optional[int] = 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: t.Optional[int] = 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: t.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.Optional[ + t.Callable[[str], str] + ] = 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: t.Optional[str] = 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: t.Optional[bool] = 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: t.Optional[bool] = show_default + + self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: t.Dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + def to_info_dict(self) -> t.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: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> t.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) -> t.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: t.ContextManager[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: t.Type[V]) -> t.Optional[V]: + """Finds the closest object of a given type.""" + node: t.Optional["Context"] = 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: t.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: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[False]" = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: + """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) -> "te.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) -> "te.NoReturn": + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> "te.NoReturn": + """Exits the application with a given exit code.""" + 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, # noqa: B902 + __callback: "t.Callable[..., V]", + *args: t.Any, + **kwargs: t.Any, + ) -> V: + ... + + @t.overload + def invoke( + __self, # noqa: B902 + __callback: "Command", + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + ... + + def invoke( + __self, # noqa: B902 + __callback: t.Union["Command", "t.Callable[..., V]"], + *args: t.Any, + **kwargs: t.Any, + ) -> t.Union[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. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + """ + 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 # noqa: B902 + ) -> 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) -> t.Optional[ParameterSource]: + """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 BaseCommand: + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :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. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: t.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: t.Optional[str], + context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, + ) -> 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: t.MutableMapping[str, t.Any] = context_settings + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire structure + below this command. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + :param ctx: A :class:`Context` representing this command. + + .. versionadded:: 8.0 + """ + return {"name": self.name} + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get help") + + def make_context( + self, + info_name: t.Optional[str], + args: t.List[str], + parent: t.Optional[Context] = 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 # type: ignore + ) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invocable by default") + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. Other + command classes will return more completions. + + :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: t.List["CompletionItem"] = [] + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, MultiCommand) 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: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: "te.Literal[True]" = True, + **extra: t.Any, + ) -> "te.NoReturn": + ... + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: + ... + + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = 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: t.MutableMapping[str, t.Any], + prog_name: str, + complete_var: t.Optional[str] = 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 Command(BaseCommand): + """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: issues a message indicating that + the command is deprecated. + + .. 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. + """ + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.MutableMapping[str, t.Any]] = None, + callback: t.Optional[t.Callable[..., t.Any]] = None, + params: t.Optional[t.List["Parameter"]] = None, + help: t.Optional[str] = None, + epilog: t.Optional[str] = None, + short_help: t.Optional[str] = None, + options_metavar: t.Optional[str] = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool = False, + ) -> None: + super().__init__(name, 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: t.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.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + info_dict.update( + 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, + ) + return info_dict + + 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) -> t.List["Parameter"]: + rv = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + rv = [*rv, help_option] + + return rv + + 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) -> t.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) -> t.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) -> t.Optional["Option"]: + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + + if not help_options or not self.add_help_option: + return None + + def show_help(ctx: Context, param: "Parameter", value: str) -> None: + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help=_("Show this message and exit."), + ) + + 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: + text = _("(Deprecated) {text}").format(text=text) + + 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: + text = _("(Deprecated) {text}").format(text=text) + + 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 parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + 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: + message = _( + "DeprecationWarning: The command {name!r} is deprecated." + ).format(name=self.name) + 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) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options 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: t.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) + ) + + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: The result callback to attach to this multi + command. This can be set or changed later with the + :meth:`result_callback` decorator. + :param attrs: Other command arguments described in :class:`Command`. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name: t.Optional[str] = None, + invoke_without_command: bool = False, + no_args_is_help: t.Optional[bool] = None, + subcommand_metavar: t.Optional[str] = None, + chain: bool = False, + result_callback: t.Optional[t.Callable[..., t.Any]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + 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( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> t.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 collect_usage_pieces(self, ctx: Context) -> t.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 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, *args, **kwargs): # type: ignore + inner = old_callback(__value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv + + return decorator + + 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: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + 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: t.List[str] + ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.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, 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 get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError + + def list_commands(self, ctx: Context) -> t.List[str]: + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + def shell_complete(self, ctx: Context, incomplete: str) -> t.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 Group(MultiCommand): + """A group allows a command to have subcommands attached. This is + the most common way to implement nesting in Click. + + :param name: The name of the group command. + :param commands: A dict mapping names to :class:`Command` objects. + Can also be a list of :class:`Command`, which will use + :attr:`Command.name` to create the dict. + :param attrs: Other command arguments described in + :class:`MultiCommand`, :class:`Command`, and + :class:`BaseCommand`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + """ + + #: 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: t.Optional[t.Type[Command]] = 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: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: t.Optional[str] = None, + commands: t.Optional[ + t.Union[t.MutableMapping[str, Command], t.Sequence[Command]] + ] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + 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: t.MutableMapping[str, Command] = commands + + def add_command(self, cmd: Command, name: t.Optional[str] = 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_multicommand(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.Union[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.Optional[t.Callable[..., t.Any]] = 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.Union[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.Optional[t.Callable[..., t.Any]] = 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 get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> t.List[str]: + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + + See :class:`MultiCommand` and :class:`Command` for the description of + ``name`` and ``attrs``. + """ + + def __init__( + self, + name: t.Optional[str] = None, + sources: t.Optional[t.List[MultiCommand]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + #: The list of registered multi commands. + self.sources: t.List[MultiCommand] = sources or [] + + def add_source(self, multi_cmd: MultiCommand) -> None: + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> t.List[str]: + rv: t.Set[str] = set() + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> t.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. + + .. 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: t.Optional[t.Sequence[str]] = None, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + required: bool = False, + default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, + callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, + nargs: t.Optional[int] = None, + multiple: bool = False, + metavar: t.Optional[str] = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, + shell_complete: t.Optional[ + t.Callable[ + [Context, "Parameter", str], + t.Union[t.List["CompletionItem"], t.List[str]], + ] + ] = None, + ) -> None: + self.name: t.Optional[str] + self.opts: t.List[str] + self.secondary_opts: t.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 + + 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}." + ) + + def to_info_dict(self) -> t.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: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.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) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(self) + + 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: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + """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: t.Mapping[str, t.Any] + ) -> t.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) -> t.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: # t.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: # t.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) -> t.Optional[str]: + 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.Optional[t.Any]: + rv: t.Optional[t.Any] = 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: t.Mapping[str, t.Any], args: t.List[str] + ) -> t.Tuple[t.Any, t.List[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + 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) -> t.Optional[t.Tuple[str, str]]: + pass + + def get_usage_pieces(self, ctx: Context) -> t.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) -> t.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(t.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. 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. + :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.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + 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: t.Optional[t.Sequence[str]] = None, + show_default: t.Union[bool, str, None] = None, + prompt: t.Union[bool, str] = False, + confirmation_prompt: t.Union[bool, str] = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: t.Optional[bool] = None, + flag_value: t.Optional[t.Any] = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + help: t.Optional[str] = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = 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, **attrs) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + 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.Union[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 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 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) -> t.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 _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.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("Could not determine name for option") + + 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) -> t.Optional[t.Tuple[str, str]]: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: t.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()}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + + 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: + var_str = ( + envvar + if isinstance(envvar, str) + else ", ".join(str(d) for d in envvar) + ) + extra.append(_("env var: {var}").format(var=var_str)) + + # 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 self.default else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + else: + default_string = str(default_value) + + if default_string: + extra.append(_("default: {default}").format(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.append(range_str) + + if self.required: + extra.append(_("required")) + + if extra: + extra_str = "; ".join(extra) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + # 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) + + 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), + ) + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = 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: t.Mapping[str, "Parameter"] + ) -> t.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: t.Sequence[str], + required: t.Optional[bool] = 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) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() # type: ignore + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + 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)}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [self.make_metavar()] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar()}'" + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/venv/lib/python3.12/site-packages/click/decorators.py b/venv/lib/python3.12/site-packages/click/decorators.py new file mode 100644 index 0000000..d9bba95 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/decorators.py @@ -0,0 +1,561 @@ +import inspect +import types +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=t.Union[_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.Any, 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: t.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.Optional[T] + 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 # type: ignore[return-value] + + +def pass_meta_key( + key: str, *, doc_description: t.Optional[str] = None +) -> "t.Callable[[t.Callable[te.Concatenate[t.Any, 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.Any, 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 # type: ignore[return-value] + + +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: t.Optional[str], + cls: t.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: t.Type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: + ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: + ... + + +def command( + name: t.Union[t.Optional[str], _AnyCallable] = None, + cls: t.Optional[t.Type[CmdType]] = None, + **attrs: t.Any, +) -> t.Union[Command, t.Callable[[_AnyCallable], t.Union[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 with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + 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. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + + .. 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.Optional[t.Callable[[_AnyCallable], t.Any]] = 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(t.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) + + cmd = cls( + name=name or f.__name__.lower().replace("_", "-"), + 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: t.Optional[str], + cls: t.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: t.Type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: + ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: t.Optional[str] = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: + ... + + +def group( + name: t.Union[str, _AnyCallable, None] = None, + cls: t.Optional[t.Type[GrpType]] = None, + **attrs: t.Any, +) -> t.Union[Group, t.Callable[[_AnyCallable], t.Union[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(t.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: t.Optional[t.Type[Argument]] = 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: t.Optional[t.Type[Option]] = 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: t.Optional[str] = None, + *param_decls: str, + package_name: t.Optional[str] = None, + prog_name: t.Optional[str] = None, + message: t.Optional[str] = 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``. On Python < 3.8, the ``importlib_metadata`` + backport must be installed. + + 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: + metadata: t.Optional[types.ModuleType] + + try: + from importlib import metadata # type: ignore + except ImportError: + # Python < 3.8 + import importlib_metadata as metadata # type: ignore + + try: + version = metadata.version(package_name) # type: ignore + except metadata.PackageNotFoundError: # type: ignore + 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]: + """Add a ``--help`` option which immediately prints the help page + and exits the program. + + This is usually unnecessary, as the ``--help`` option is added to + each command automatically unless ``add_help_option=False`` is + passed. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + 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["callback"] = callback + return option(*param_decls, **kwargs) diff --git a/venv/lib/python3.12/site-packages/click/exceptions.py b/venv/lib/python3.12/site-packages/click/exceptions.py new file mode 100644 index 0000000..fe68a36 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/exceptions.py @@ -0,0 +1,288 @@ +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +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: t.Optional[t.Union[t.Sequence[str], str]] +) -> t.Optional[str]: + 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) + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.Optional[t.IO[t.Any]] = None) -> None: + if file is None: + file = get_text_stderr() + + echo(_("Error: {message}").format(message=self.format_message()), file=file) + + +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: t.Optional["Context"] = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: t.Optional["Command"] = self.ctx.command if self.ctx else None + + def show(self, file: t.Optional[t.IO[t.Any]] = 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: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = 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: t.Optional[str] = None, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + param_type: t.Optional[str] = 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: t.Optional[str] = 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(self.param) + 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: t.Optional[str] = None, + possibilities: t.Optional[t.Sequence[str]] = None, + ctx: t.Optional["Context"] = 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: t.Optional["Context"] = 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 FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: str = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code: int = code diff --git a/venv/lib/python3.12/site-packages/click/formatting.py b/venv/lib/python3.12/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +import typing as t +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: t.Optional[int] = None + + +def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: + widths: t.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: t.Iterable[t.Tuple[str, str]], col_count: int +) -> t.Iterator[t.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: t.List[t.Tuple[int, bool, str]] = [] + buf: t.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: t.Optional[int] = None, + max_width: t.Optional[int] = 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 = 0 + self.buffer: t.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: t.Optional[str] = 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: t.Sequence[t.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) -> t.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) -> t.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: t.Sequence[str]) -> t.Tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/venv/lib/python3.12/site-packages/click/globals.py b/venv/lib/python3.12/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/globals.py @@ -0,0 +1,68 @@ +import typing as t +from threading import local + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: "te.Literal[False]" = False) -> "Context": + ... + + +@t.overload +def get_current_context(silent: bool = ...) -> t.Optional["Context"]: + ... + + +def get_current_context(silent: bool = False) -> t.Optional["Context"]: + """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: t.Optional[bool] = None) -> t.Optional[bool]: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/venv/lib/python3.12/site-packages/click/parser.py b/venv/lib/python3.12/site-packages/click/parser.py new file mode 100644 index 0000000..5fa7adf --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/parser.py @@ -0,0 +1,529 @@ +""" +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 +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: + import typing_extensions as te + 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: t.Sequence[str], nargs_spec: t.Sequence[int] +) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.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: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] + spos: t.Optional[int] = None + + def _fetch(c: "te.Deque[V]") -> t.Optional[V]: + 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) -> t.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: t.Optional["Context"]) -> 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)}" + + +def split_arg_string(string: str) -> t.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. + """ + 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 + + +class Option: + def __init__( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: t.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: t.Optional[str], nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], + 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: t.List[str]) -> None: + self.opts: t.Dict[str, t.Any] = {} + self.largs: t.List[str] = [] + self.rargs = rargs + self.order: t.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. + """ + + def __init__(self, ctx: t.Optional["Context"] = 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: t.Dict[str, Option] = {} + self._long_opt: t.Dict[str, Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: t.List[Argument] = [] + + def add_option( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = 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: t.Optional[str], 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: t.List[str] + ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.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: t.Optional[str], 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) diff --git a/venv/lib/python3.12/site-packages/click/py.typed b/venv/lib/python3.12/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/click/shell_completion.py b/venv/lib/python3.12/site-packages/click/shell_completion.py new file mode 100644 index 0000000..dc9e00b --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/shell_completion.py @@ -0,0 +1,596 @@ +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import BaseCommand +from .core import Context +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .parser import split_arg_string +from .utils import echo + + +def shell_complete( + cli: BaseCommand, + ctx_args: t.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: t.Optional[str] = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: t.Optional[str] = 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: BaseCommand, + ctx_args: t.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) -> t.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) -> t.Tuple[t.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: t.List[str], incomplete: str + ) -> t.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 subprocess + + output = subprocess.run( + ["bash", "-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) -> t.Tuple[t.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) -> t.Tuple[t.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) -> t.Tuple[t.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=t.Type[ShellComplete]) + + +_available_shells: t.Dict[str, t.Type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: t.Optional[str] = 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) -> t.Optional[t.Type[ShellComplete]]: + """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 _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: t.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: BaseCommand, + ctx_args: t.MutableMapping[str, t.Any], + prog_name: str, + args: t.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 + ctx = cli.make_context(prog_name, args.copy(), **ctx_args) + args = ctx.protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, MultiCommand): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) + 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 + + sub_ctx = cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + 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: t.List[str], incomplete: str +) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/venv/lib/python3.12/site-packages/click/termui.py b/venv/lib/python3.12/site-packages/click/termui.py new file mode 100644 index 0000000..db7a4b2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/termui.py @@ -0,0 +1,784 @@ +import inspect +import io +import itertools +import sys +import typing as t +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.Optional[t.Any] = None, + show_choices: bool = True, + type: t.Optional[ParamType] = 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.Optional[t.Any] = None, + hide_input: bool = False, + confirmation_prompt: t.Union[bool, str] = False, + type: t.Optional[t.Union[ParamType, t.Any]] = None, + value_proc: t.Optional[t.Callable[[str], t.Any]] = 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) # noqa: B306 + 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: t.Optional[bool] = 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: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], + color: t.Optional[bool] = 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[[], t.Iterable[str]], text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast(t.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) + + +def progressbar( + iterable: t.Optional[t.Iterable[V]] = None, + length: t.Optional[int] = None, + label: t.Optional[str] = None, + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = 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 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. + + .. 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 + Added the ``update_min_steps`` parameter. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. Added the ``update`` method to + the object. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + 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: t.Union[int, t.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: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bold: t.Optional[bool] = None, + dim: t.Optional[bool] = None, + underline: t.Optional[bool] = None, + overline: t.Optional[bool] = None, + italic: t.Optional[bool] = None, + blink: t.Optional[bool] = None, + reverse: t.Optional[bool] = None, + strikethrough: t.Optional[bool] = 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.Optional[t.Any] = None, + file: t.Optional[t.IO[t.AnyStr]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = 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) + + +def edit( + text: t.Optional[t.AnyStr] = None, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + filename: t.Optional[str] = None, +) -> t.Optional[t.AnyStr]: + 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. + """ + 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) + + ed.edit_file(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.Optional[t.Callable[[bool], str]] = 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() -> t.ContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: t.Optional[str] = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/venv/lib/python3.12/site-packages/click/testing.py b/venv/lib/python3.12/site-packages/click/testing.py new file mode 100644 index 0000000..e0df0d2 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/testing.py @@ -0,0 +1,479 @@ +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from .core import BaseCommand + + +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) -> t.List[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> t.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: t.Optional[EchoingStdin]) -> t.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +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 make_input_stream( + input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]], 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.""" + + def __init__( + self, + runner: "CliRunner", + stdout_bytes: bytes, + stderr_bytes: t.Optional[bytes], + return_value: t.Any, + exit_code: int, + exception: t.Optional[BaseException], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = None, + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The value returned from the invoked command. + #: + #: .. versionadded:: 8.0 + self.return_value = return_value + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self) -> str: + """The (standard) output as unicode string.""" + return self.stdout + + @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.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + 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 stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__( + self, + charset: str = "utf-8", + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + echo_stdin: bool = False, + mix_stderr: bool = True, + ) -> None: + self.charset = charset + self.env: t.Mapping[str, t.Optional[str]] = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli: "BaseCommand") -> 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: t.Optional[t.Mapping[str, t.Optional[str]]] = None + ) -> t.Mapping[str, t.Optional[str]]: + """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: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + color: bool = False, + ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin 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. + + .. versionchanged:: 8.0 + ``stderr`` 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) + + bytes_output = io.BytesIO() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, bytes_output) + ) + + 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( + bytes_output, encoding=self.charset, name="", mode="w" + ) + + bytes_error = None + if self.mix_stderr: + sys.stderr = sys.stdout + else: + bytes_error = io.BytesIO() + sys.stderr = _NamedTextIOWrapper( + bytes_error, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(prompt or "") + val = text_input.readline().rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return text_input.readline().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.Optional[t.IO[t.Any]] = None, color: t.Optional[bool] = 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 + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + + 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 (bytes_output, bytes_error) + 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 + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: "BaseCommand", + args: t.Optional[t.Union[str, t.Sequence[str]]] = None, + input: t.Optional[t.Union[str, bytes, t.IO[t.Any]]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + catch_exceptions: bool = True, + 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``. + :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. + + .. 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 + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: t.Optional[BaseException] = 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(t.Optional[t.Union[int, t.Any]], 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() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() # type: ignore + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: t.Optional[t.Union[str, "os.PathLike[str]"]] = None + ) -> t.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: # noqa: B014 + pass diff --git a/venv/lib/python3.12/site-packages/click/types.py b/venv/lib/python3.12/site-packages/click/types.py new file mode 100644 index 0000000..2b1d179 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/types.py @@ -0,0 +1,1089 @@ +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 + + +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[t.Optional[str]] = None + + def to_info_dict(self) -> t.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: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: "Parameter") -> t.Optional[str]: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: "Parameter") -> t.Optional[str]: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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) -> t.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: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = 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 + ) -> t.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) -> t.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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: + self.choices = choices + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> t.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 get_metavar(self, param: "Parameter") -> str: + choices_str = "|".join(self.choices) + + # 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") -> str: + return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + normed_value = normed_value.casefold() + normed_choices = { + normed_choice.casefold(): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + choices_str = ", ".join(map(repr, self.choices)) + self.fail( + 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), + param, + ctx, + ) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.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: t.Optional[t.Sequence[str]] = None): + self.formats: t.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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[t.Type[t.Any]] + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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: t.Optional[float] = None, + max: t.Optional[float] = 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) -> t.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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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: "te.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: "te.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: t.Optional[float] = None, + max: t.Optional[float] = 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: "te.Literal[1, -1]", open: bool) -> float: + if not open: + return bound + + # Could use Python 3.9's 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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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. + + Starting with Click 2.0, 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. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: t.Optional[bool] = 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) -> t.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: "t.Union[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: t.Union[str, "os.PathLike[str]", t.IO[t.Any]], + param: t.Optional["Parameter"], + ctx: t.Optional["Context"], + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("t.Union[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: # noqa: B014 + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.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: t.Optional[t.Type[t.Any]] = 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) -> t.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: "t.Union[str, os.PathLike[str]]" + ) -> "t.Union[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: "t.Union[str, os.PathLike[str]]", + param: t.Optional["Parameter"], + ctx: t.Optional["Context"], + ) -> "t.Union[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: + # os.path.realpath doesn't resolve symlinks on Windows + # until Python 3.8. Use pathlib for now. + import pathlib + + rv = os.fsdecode(pathlib.Path(rv).resolve()) + + 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}' 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 + ) -> t.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: t.Sequence[t.Union[t.Type[t.Any], ParamType]]) -> None: + self.types: t.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> t.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: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> 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)) + + +def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = 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() diff --git a/venv/lib/python3.12/site-packages/click/utils.py b/venv/lib/python3.12/site-packages/click/utils.py new file mode 100644 index 0000000..d536434 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/utils.py @@ -0,0 +1,624 @@ +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, t.Optional[R]]": + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: "P.args", **kwargs: "P.kwargs") -> t.Optional[R]: + 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: t.Union[str, "os.PathLike[str]"], + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "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.Optional[t.IO[t.Any]] + 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: # noqa: E402 + 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: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + self.close_intelligently() + + def __iter__(self) -> t.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: t.Optional[t.Type[BaseException]], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> t.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.Any]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = 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: t.Optional[t.Union[str, bytes]] = 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) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: "te.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: "te.Literal['stdin', 'stdout', 'stderr']", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "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, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "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 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: "t.Union[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: t.Optional[str] = None, _main: t.Optional[ModuleType] = 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: t.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> t.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.0.3.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/LICENSE.txt new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.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/flask-3.0.3.dist-info/METADATA b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA new file mode 100644 index 0000000..5a02107 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/METADATA @@ -0,0 +1,101 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 3.0.3 +Summary: A simple framework for building complex web applications. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +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 :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Typing :: Typed +Requires-Dist: Werkzeug>=3.0.0 +Requires-Dist: Jinja2>=3.1.2 +Requires-Dist: itsdangerous>=2.1.2 +Requires-Dist: click>=8.1.3 +Requires-Dist: blinker>=1.6.2 +Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10' +Requires-Dist: asgiref>=3.2 ; extra == "async" +Requires-Dist: python-dotenv ; extra == "dotenv" +Project-URL: Changes, https://flask.palletsprojects.com/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/ + + +## Installing + +Install and update from [PyPI][] using an installer such as [pip][]: + +``` +$ pip install -U Flask +``` + +[PyPI]: https://pypi.org/project/Flask/ +[pip]: https://pip.pypa.io/en/stable/getting-started/ + + +## 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) +``` + + +## Contributing + +For guidance on setting up a development environment and how to make a +contribution to Flask, see the [contributing guidelines][]. + +[contributing guidelines]: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst + + +## 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 + diff --git a/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD new file mode 100644 index 0000000..ffacb39 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/RECORD @@ -0,0 +1,58 @@ +../../../bin/flask,sha256=wfUM6RPg27LKv1zSgt87OeoApp3H3-HsorNFbPOVLD0,255 +flask-3.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.0.3.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask-3.0.3.dist-info/METADATA,sha256=exPahy4aahjV-mYqd9qb5HNP8haB_IxTuaotoSvCtag,3177 +flask-3.0.3.dist-info/RECORD,, +flask-3.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask-3.0.3.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +flask-3.0.3.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask/__init__.py,sha256=6xMqdVA0FIQ2U1KVaGX3lzNCdXPzoHPaa0hvQCNcfSk,2625 +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=7-lh6cIj27riTE1Q18Ok1p5nOZ8qYiMux4Btc6o6mNc,60143 +flask/blueprints.py,sha256=7INXPwTkUxfOQXOOv1yu52NpHPmPGI5fMTMFZ-BG9yY,4430 +flask/cli.py,sha256=OOaf_Efqih1i2in58j-5ZZZmQnPpaSfiUFbEjlL9bzw,35825 +flask/config.py,sha256=bLzLVAj-cq-Xotu9erqOFte0xSFaVXyfz0AkP4GbwmY,13312 +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=tYrcQ_73GuSZVEgwFr-eMmV69UriFQDBmt8wZJIAqvg,23084 +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=q6iB83lSiopy80DZPrU-9mGcWwrD0mvLjiv9fHrRZgc,7646 +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=YG5Gf7JVf1c0yccWDZ86q5VSfJUidOVp27HFxFNxC7U,38053 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=WLV9TRQMMhGlXz-1OKtQ3lv6mtIBQZxdW2HezYrGxoI,30633 +flask/sessions.py,sha256=RU4lzm9MQW9CtH8rVLRTDm8USMJyT4LbvYe7sxM2__k,14807 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=2TcXLT85Asflm2W9WOSFxKCmYn5e49w_Jkg9-NaaJWo,7537 +flask/testing.py,sha256=3BFXb3bP7R5r-XLBuobhczbxDu8-1LWRzYuhbr-lwaE,10163 +flask/typing.py,sha256=ZavK-wV28Yv8CQB7u73qZp_jLalpbWdrXS37QR1ftN0,3190 +flask/views.py,sha256=B66bTvYBBcHMYk4dA1ScZD0oTRTBl0I5smp1lRm9riI,6939 +flask/wrappers.py,sha256=m1j5tIJxIu8_sPPgTAB_G4TTh52Q-HoDuw_qHV5J59g,5831 diff --git a/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/REQUESTED b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.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/flask-3.0.3.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.txt new file mode 100644 index 0000000..eec6733 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.0.3.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask=flask.cli:main + diff --git a/venv/lib/python3.12/site-packages/flask/__init__.py b/venv/lib/python3.12/site-packages/flask/__init__.py new file mode 100644 index 0000000..e86eb43 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__init__.py @@ -0,0 +1,60 @@ +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 + + +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.1. Use feature detection or" + " 'importlib.metadata.version(\"flask\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("flask") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/flask/__main__.py b/venv/lib/python3.12/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..34a89f5dd4c45f1389fed8da868199ad04318cb0 GIT binary patch literal 2485 zcmZXW&u<$=6vt=%YyG2+6DM(gC!3#+lg4h7@~f?Y(3Wy(C0Y>DTvluEINoG`F*{D0 zDwP0%1Sbw0+CKpVe+5@AEj_f_Y9*w?p|?oQsTX)};%%d_T7CW5H*aR%%zHEPAH`yx z!1Mdp|F$=Qp5sUSB#uFOd880>pP0l{Y~m39 zV`rTl%}G}6yi=eB$yxi1Q=~=7Ip99pCpiyXq9w@%;C|XK`HVf_lxbOV5qOXeO6~(5 zqC=8Pz{7M{a=%@1M(Bv-0pL+OD!B|iM#m%%0*}*i$wR;sbVBkl@Fbm-Tmhb9QI@-*-gU6MQlT%}dX z8t^h*mOKkwqczEMz$m#h>bEKS)_$V4_5w?wri2BZ-Xz+OSSV2*Dag6W13+-i0OgO;LW>@bKT@L?~|kmby@IBVg!xq!K*-nMLP z7(D*qo}(W-czj=)1!sn%?^&XAVijta+j`sM;GyEiT5WV5fHn2@ME5=4XXa^RH|R*? z$O%uu49LQkZhCvT>`Iftz!5a2`>vg4N zZ}pPZ!orQ8G(eIN<>do_`{V#_x1D7|_$4!85}Vvpi|4?Ce&)_a3HV9KlVfkt=YMB0uy50z&gU#0VSQ8G;np{s~m$|zQ zSa8GN7ah-q{Xsv$)_hnK-VBXnKV63-AauR%?_+x4uE70=^jv~j>p1;wkgv#7webDD zKh?=++1Y2=k-xJ2KNf!|9wrjS50#?~Db73{89gkJT;+&la{0qP(m(d3H2bJD`=nHR zRI2@4eOy|9m|g!nKl)(kaen$?YWgJ%OKK_pF8qW^DE=_R8Klm=n-=v=cfa;_nAi1o z7qbcB;3k9_vG2n^hl&UZ$4U;9uwstY8|ItwjU8}RI>TiHw>HNL4wEf$hv$Ge{z>3i z!Tbz1s9UzzH0*$5(egf&5=y^p>@eGhE$0JhDx(ad45198R8U4xMp4F4#!)6fLN&0q zTpWB7O;ae-C^IM;$}Gwp$~?*f$|6XZ?_CYBT)u?XDhixx!fV)`-Q%!yjBN#Nt05zSS3{*487i4H znO`yjxtff(SaK6H^ZYcKZZRk4WEL?41y?eB2C4iNuOC{RT2!o`oK&Lkl3JWyl3$?j z>>g;OU!0j+kdvxgo|=?cP@tQZlUSUsUzVCzrk|6Uq+d{3l98WhtY-*PSCXn*keHmE zn4Vg!4^bB%53(;lUaz3?7l%!5eoARhs$CHW&_0lRig|&=2WCb_#=8un4;ffm*^1bJ FA^;V`KFR<9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7919d490b0f42c3025ebb79135e7bd004778db27 GIT binary patch literal 61111 zcmdqKdvqMvc_-M7ZU7CSfyNsk2#`g9Bpw7Bd{Y7+B1nP{kpyV~k}Sw_qk(FYO*YVQ zb%PXP&?7mX1a#yGjO8ITR*vb3c1=avn8{{0@=5lLY$uasv%7;9r~vNeoI{^zX4ZRV z&%&X+<5f;}_V<1FQPqtGrDQUH>=va$b=7^}?|%1t-@hy^Eq3Ah(JTMy!vFcdyIg-w zKh%{k9^8-qoyX<6?J`}aJLVd954+v;oEOU*_Y8aGbN+BXzbhCn;J<~#KK@%YT!g=# zSn+tta0#dN#{A=@!=?P3A1fOV3&6>~8~C{d&+CWR^Rpk%jl+%nTpDW{-!Qy^pUd#Pad;y?2k>kR z8~j|3=S{<#__+el&BM+7Tp4Q_-#omTpQ~b9#4{Z@7=2x8eEt z@Ns_b#Pf;a6a3s2J2`%8_!K_}V^5Et9zM;_Re0Vyyw&ZB_%6>YP_zG9^_c7K*xB*^ z;eModncMMvZulJM-4Q!K{<-1L@$*hR4-5~uU3pZ}e{Gkbp3Gg5j>~t|FZ=JiyWhzZ zzlNV#Gw&Yceb>&To*a3fTQl!oEwM`Mv=(Xk|6R2~VN1CcLHMH0!=k?Vby6}Kqa$)Tb1 zeJ_ngCS@&ErzVmSYa$#Qj96DAmP%KAWGWgn^{=zx$zC%&iIgZKAd4M{m{BXjm6Z>0 z^DjC}_6|(NsFC&2M97+&n21hX3|+9|;~^^&i&L}l%{LH9OkzwTKXZ$L@{Glzcwdmb zK8f^iyVJ$Jlaoi|XyZ#s{3?@G%Qr|_7#h183Qtbrv4kEi(PjEMHf33niKP7MzDTJZ zpXFm{Ecp_BNkkF}G4N#gj=xD+u%<47337@1Ux31&02i?G*q7XjQJjd{(aWH}=MvlhgSE7+YQ9aMb1xz=-m*;p_ zhpvu^;Rq!oVT%UUj9()#sks!ud3Cnta3~G zCay-U_{2C`j+})9dW1^{DYKeFD)qU+6Q>->-^MH)$FN;F8jB(~ewL}91AvH#m0mX# zLW^Rtkm}T=6(7S;FtFy2#-}FCbny^(mAaX(py%<)SU4F8U5Lg2kQuKo#^R&lSUTWH zmBa!VBj{3>7Y|sZ?ng)PaN9NGdZj$6zt6am5}mnR3b9#vGp<2bQZ8&4a=hz)N9GuG zwdc`-2Kb-{W}-bWT^vnBCorrNV-bt$!q@z(;TRSoaJ$ld6;Rb3i;i|rUQb?%PwWcrpmfPd*CfyZL1DK@ zhaADl>*+vfJbWb*(%8j1iYiay|Ac|t%dX`@|I0VtEWWen-S+$SyO#siv;L1ts^_1% zU(&MRZFz(=t}(i)i^&-pt7VMJuVJ(zu3@+78qRwL&9EW*OcD%yQf-_)R6>tITS=so|8h{HBiI)bsN?zI)7k z{A(~h=6bX7&4T|*&&Y5=gvh0)NRheW0QwOr9xgFA;+H|c&?5gkvUkI!<|e#vruRjw z{+Y*DzsvQ;JTdFK;5J*nRytf}o-{XOLkO6s%q{p^Za!_EHn)B)f4G95TJcnAo-y0- zt;#%Ww&QQL*>85>Z;g4*+=jok=6SOdf9q6T=I7K?=3jHb>_U0<=Ab!b2Jy7ce8%iX z&IXmveAe8K-|O}7=gb}W-DrN^+=;(U`u+3fF8tnL4x792ccb}&xd(rZBA59El?Kl* zntM^pCVbt8ug&Hc%_s1;MWp}^q|In!dDE-Dt^R9{nESt0FucVKn+K33l{@;SVZZuAxg2gV&T1AH9s-&EQo@$S+}p4MK1R7F#Sj z#=E%@o-mE@7=23^Nn{;ELMt3AHgJgof`)Mlr6i2Wa3T>gIn_jXJYvKz@bh@w#71ev zEhOMIEkAG(j;c`3Ip7o{%7u+t5#T_ReqD>kV$=p|LRdAxup$?uiKKPixDdCvC~Do+ zXylrqXpBTB*Z<7G8N)&g=%+-j25{Mh=*20^?&J8>*d=2;ZbgE{TpA6NvlpuE=;svo zGL9A`;<2j{{ySv>s~fca8$gaxGeT8!K`JBqPc6IlF!b$7xrBa_%- zvGE!42_wp5m{HJV*uv;yXHX5m#KbXAG(=P3m?1E!9_+TTs`FYjd5KFx+8%5!k)DxI z2wP?{6asD?G3b?SeLGE8*dQ!#hAk5V!*kenc`AWvFh)iwgUHb?2kba<(Dy~e*EWQY zfS<5hJ{LHlJ?Q`!O!vho0FRqNGq2KLyA)39W{rXjow&%UxsRDkZ3vwd0PcWj5KyL` zt%NQKaLAww_()t&U=ej1W2kjBB9_AFbpzCE1Yi$Jml}srvf^kT)0h`A;ku*@*dWXT zkVrb09gXK8N=UXQs2B`(cmfyz{bE?4a^>Q}N(JKK`7^=*yD3m57YSzZCnlC26(%6J z(*UT8nE~Jcjl`~nucNIPYp^Cn|JjpA?KdNsDuFH}Y*Q-740q$1 z)~K^aBXKD{6*JX>V$7Pn1T3Rbb@E!=K&Qn-68v0qt^;bD6V_X^>TGS-wPhz&gC9&_ zXGylT23y--*#4qiB$W8MOV_DiNlf%phCyq<(HXG=T#H**49v*{exlj-gc6z$Ph7F# zl}0~)%?4zKj~LhxjM&s9=J=$XT(!9nQE5Xf!=vuXB(TbbsTgt{jQ|>fQ5?Wd%YZWj zF-?s#&zUer!?Zz&MWc(6m_uzT*^`RmozqT$$*a3-@N;K+V`G;h%It8}MUr6RH*5d;^1Y#{(GT{ECd zF>KiIs7!)Zv698odTdb+K+l+Ly>Spq03!mRBcc@@nOtMGRui2&$Ja*0#+18n?^(x{MeF`mvRq) zf;PEx_7IItu#e(LM#Pe`A(D7v!gw}uxw`+3H$;X>CYKv3HfN?k?Or^l)sCXjRn<~C zZo1oImS_;59{FsgNu=z64hE}?5z<&upkf9EiS!u+bCf~DldxffnM%oJ5IINlMMJB% zR9?ZL_&_(eCh4mQLB<&5Jh~U*sU$XaP+i3TLr_3s8IT_|usjcd5Q0)692PaF^N;l% zdFDiax^Sp(aOhP3iR0<&^8@G3_nzn->I?OK{%GI%p;PDj2h+uaeMblShC-+No=-QN z?;AMV+uzqe6dLRs9K`p~nN!F6hEARB``JbaOd-|wn&1)BWzP)ug+7l&{l|`cT>lUa#hJeT6R3L~^)^J^4bj)$6Mdm$eaCyBIWv^@UP>k>qkk8` z2oBIa1_sUz45q9312x$>{`GyIKYs=t4h{94#RDei%(>oUm@t~J zzT?Q-cPs>PU1;#=$-c9F=^B-8Fx30Z&^c5>>C*wxVjkPUQ^S4JrO>8DUXXg57t^Im z(Zlkh=`#6MDB@mBmqFOXI=K*kw>oHMDx`W0@-SdUQc#VR;Jv#1c<_*(U>G`%Z@GW1 z-vFkzvj5JwRPL{rpsp(Wi+aM_YV~aY{WeTHek;%P&Uj}_pi#*Gn(y6$cVw&G zuIu>MUfADWoGuXzCsWDkfFx!VahER5pl;G7@+Z+N>Cz0UC0(gW3{8Wi18Sp{;8IjnS%#*foorzRjSikgy|3sJS*8Fhoy86S<(?i!z%F7H0TyRO?E1ykw6xzDC+`r*wJ>A=cwaQsR zs|E@987jNHE7#J#L?m_row|@9@G@Suj^NKHz5}uF_^25^G%e%}K`jwJ5Q_r`Ck_Qw ziZXyqq8^!k`Lb)F^~iT$`t9kZ)*~tU@8tUfAGDsdj^SgwC+!1|JsHPB0xQfbd7N&gl%k?eGjoX$RTIm7z zjXUJeEeDrtH?GvUiq?JXDk&=dxY<=*cl*Gt1K&I}>wVR?;&ZKQ`cBasMYG=5d^dfs zmade!{N+m}n?5Mn^ig^B+zX54o9?{$LHW)VPhRO$4+DoD<>T*i`Oc4huKJC)zkKV< zcXltnvMmTQdvwc+GSk*jpWFI@Sh zWh()fznQ0SOyeK)h}I`#zOUiIiS;f!Q{fw3rh6UkH}YokUUpy4v+>R5(GDicoDyUY>x$rg=%`1tQgo zB&RHhzct^o#s&)F9!etJ0-|OGk*JhWpt58cUtyg?&|&5Q#+FGeNp9OjDbudRIF3Lh zb?s6VL{k!02ZE^?wc^*nHq*cmM~do9)<-~BBzH=?AW2k`@*!-nnq3T;Diu9d^6p8j zz=%aM6UVsp!%jpD2odgvIVCiSTEd*b>NcRgx)f(!7j-{VnZkRrqd;3s26Lf_i!7$w zX-k`UfexV*#erlFCK@p^BF2TOXVA;kwH-SlAfB>7x$23q>tRV33j?3jU#($)Wq*5t zwE=(A1)>t`Fn+KJMA}2xt~3b~s2D6@XoM5(9_v>qu}@)rs~0~LSW7N6nz1iTT3}zJ zK^L18gX#2o9+F_rk1%<3B@UwyV47xEMdMO=bE>>~q2*Aj{HfXehb85+2eI5gDyf-^ zy!rh7lGX=RwR2NTbsed?j>Wpp#j36af7e5@i&(wXX^EnF?nl3m2QnPVwdEvAY(o)K z8zp?zjntaFL3Vk~=oB~dl7;H6z3_7pDoG-?_(GXw>e>FQ5D1Z5@8&6cG)4@)7#sqI z3^gzTJu{CiI+7x;j78W(!i}CRu}RSA1&c(YAcABkSAtbTs%Mg;6YkJJ!gzqIhNwNW zOhvsw`Gn=2t2)%83j)jJfXx4bOUefIJ@!hN-YMl=l0s@V#!2fdSvepPF^+0?W)6@n zge3H~`>d~EveJH7KoJ6A8$0Xkcx7#+_im5{V_}d59%%1*bCxT`x=CqX#VuozSP8tD zt`$ono3?@BtSfOI30`)s)Vs>7mjYWp2yA&!xnW`B;9}*_f`16RDR#fg&QxXR-On#p z?wu`s5NLkjFMaL!&Ev1{n)fc%cckh&7X91qe*V2{AA9o3i&tEEMa5!u&|+1WULCV| zgVm8|y05ye65F&21T%X$k`smS~)*Q&ruk{j+!o_b=K|1G>e z2OYW*23!g)y4b}O{YrRWf}EycNyKCWE=(;*KIwqD<6yU?3KCjQVaGvujD(A%j0y)6 zUy5Nn#nNyHcDP;*#Umq-HV8Wbu>H_}5V9W`;fX|6e5CBa+oZ`PU8)jjlSP0-B0yqI zhc+IFn$)UYqo7Z(08I;X2OE58M-Y-w)Sh8n(AI3Xy}6yG3O%~Dl#MRn?ulUJC0H)P zux`wXPA1zf1ZjZU+8ydjDdSWF-UCHG1nn4T>Z5v#ht+aTs$hTM zrv4ut-5jE|kakkK8_S>%{Fdx6a(D{@#Y~Zn#&!Sl#p9vBf~|g0J^6h=aCM zP|y-dxEz+4x%m0Zdb`X(4Y}k2xlw~V{5z=X9EOZ2F*Pv4nuUPMAqym93nc*-;#<8g z+9a^5??O4)4&nAW6k=VAf}$kNJe0ezozdBPh{juG+yjFRRgG$ofB`U?EZn8Z$l6t} zSs+$3kkhKgN4+7oQJKuBveC#PSVoP(G>ZsyfgGV81wx5V=%&(&$+#dj5QD&`UIdWW z$Ob9_>!VB1^g$Y#h>$uj8MoG0xT-F(aH&(I{vn9$)PyQla;r7kYM0QSZ~Ze&wRM|r zma8CbJIYT_oT$qmnp=dva@ z?X;J*{L6la(sIbclCY>0SMD|^wHz!-f)2itBt+rsUGF=xpKjXr8`OLI@8w4OSv{f6 z#D-*DW!_Y}Eyg1UHL!!i|o9Q4J4K%nj3I7(a^pj|JooD~@13!t9`qsZo+m%^|Yn}{0` zXs*X#BhpI<0pzJo6f<1ws)Zpu79$#n-4TU>*A?5ZqnnOx&F1fHK5~1|wtgTCFf!t> z?GF;oPeMT0EP`AiH3oKIAd|RdvZ{>Gi0&ol&MB@Yp+knXsTky(O>@%Y3MHkBsUe_6 z!jlpB+1QP;Mlj#lAq$DQ0Ftsc}3P**+*;A-+0BI$bDdBwa8y2^)!s_1jcEH_4zU-5TuL zXbnoD=A?a-aWa{Jw~1G<%Y_mKt$%@BAQ!GC2w%`(2$s2Cn1jmpIa)BiL14bMzDKbn z5`TiSfcxsf6U-%->e^Fv?TeKivxN^!>gKPdO13U-#vlbY~Hf3__gAj#Y?_*Dc`!~>UyFb9&FkJM*a5wTl*omt7&{tz5YR2 zV5Q1c)bO#ZxTtug))n0O{pa6){`;Y~L$i6WmE0^@sBTaBI+g_MBSH1|0f|uD>Vm;nFbIJs{@bXLUL>}Dd+&A(j!0rIM=FXXmQgP?P&&ZzxBb#}I z*TKwtY-av(DPQSZqa9kmVfXoQ<*f0|%dN@X(tP>`tp!G!u0hvzcY9&D1H&n>Em2xz zZypxTWK7Hw{v>nV36LP{u0}$zGOief1`S%66HNftl|g&fA1{eo@4 zb>Jr8CtVEe=72q^UX=j_OY8i|OUg#+Q!vn8o2AN)J8kJ07AK1(iJFJe6f6q_HAgyJ zY!iei$qYQKnV~5r=jb_x1Negb0 zT6+i=t<@%6Aoi3Yi?f+fX$#x7paDs=;^=fzt#1-$>R=yjIAV)nGpvwG!#t=+Q%snidDuvMAuBQj@`t@nx}O? zR5@3Qau(W9>Hg*Q8^5#vjr|L)2UF`0QIT65MfyPwug0ph_h7BNAN?7(MYwnb}uqFgeu0$Eq=fs^?U6wz0SzmR-Q^^}E7%#j5ES?7pYl~yQ>Tb^u zFJZ#iA(Px?S=dQzigv9O)YW7hexsuhHkgq7#fjwOL~QP*SHvl&vb>`lugn-zhJ;}}G%Btn>*#UD1GZa$Z#K)jQfhkE;dKVFjf=n3Q)9v52{R!6Pg2a7{_5@58 zRGW;4qzVJ%r!Irq`YE_*XHZ+)Qsa$dacZAETD!LIQoaloA$H_j}P!ygMHZfKW(m{G#2Z`VKG1#^a zi0K+ozRy1Edq}~mj&y~bOWXU_B9;j9TyVDO0x>3OKhubCdWD`hVf~287t$F)mePw% zBvWUFAw>wSDtx+0V45{P|A5fVvnUPd2AYtX+r__G{Gh67{^HVxeW?xm{&?g4s#D8> z+ND5SD$uqR=t>2;?lq(W`|<9zuiX5~!lwQB@vw5;QsuT(<+cU?wtwq;@~356?p$0f z3oiJAtC4|bei0r4$bbkU+X%#JaUcPQ>eEh=Br1=-Fu=uJt+L*75|NhZ{#lI!+qCvGH% zf08Z+#fzpu@+9S`=z?d2O-mT=BFZFNFnp}fWvs57z&OrvLsP)vlK+fFZCN#!Z@c^Zp*}JIUKa5) zX`e;20QFtEcob4#AU=4h61ssa_JX%dUIJ7F(WNY}x-|^?{#zTun#aEBUUP zhLvJhQTc0SH_PT;`p{epvs&6!GN@vU^t`*2^y4%)CV2Fdm3C?$Z*P*8sCCGWx0IFAwbCb2X9a|jZkQ0G$_n=~ytYBj!0ZY1mjTjFC z5Y_hgeM(wn*NIUlFcUCV$$MuVh$l8JIfUGiCZNppcRB1EB4C|Vf*6qE& zZtv`=Wq;Xgr*59Q75(Ow5B<$69#_M@hqmCrIb#IuB}C#ri}rk)fln?SzikCz=8-X> z)og3}6$~Wm9;Ey`6XVch8)UHRJdsa0^Jz$|#leWUP(Z>GSinJKsolfUfC zEK;ezfH^_hBBXXF3TFx}&rIPBH-s_8SeJQ;d}yIdc+CCDCRGYno?LMd+mz4vEax}7 z9VF86WBuk|CJ@fL%u=lS>a3UeY0uCa`O5x*`4A+-F55B7#_BfYt^seGSEsehL|~2z ziW7FD*zGDJW~eyXuF_xbP*3*XWT$#|YTltd@IZNxPs#&88K|s~hLP(9Em?1_xnA-- z@4Du0uL>^#uwW1&46+<}i+ruf2^yjjXojvr+B`|27(l>Kv?2#PaV*X*W*~zgrbf7- zwsum#Q)VC(bBZ@*5(2TVOa^2int{-$bV=4|Z#=>RBXC90B>cs|(tuP4+J%|^n2;HP zQxg#(7#U|)AsQz3N1@Pzctg7Mn{jybcO!y9EPfr7Q#T|Gk(b!mKtz@h-2!5kuF`BD z>qNe%gepNQ4VaTac0?&6Sr^IRdB5Pn5qu#@sI|WU3MO&A?kKgMeXxZ%NHDZu3?ZVz zXd?g;i+m=ahQ_cG@2R2+!Fzj>RgsPvK-1uT$^;)1Ra1gWb517agNv1_KDbK}(@GR8 zwOcofn1JG6t=p3n$0d+h&g3;Gw10q>?%MqmX5S#(Pdqx05 zi7TXv;oneJ!#GsfcR=~gD~gmn!f?XTLl6TQ0US=#SYn#b0ng){B&CP^STU7op^~qGR&qBrH>P>rv9w1Q;AB zNl|3PQb1`-JyF`Az)l!#f?frT7%;xBa1&;tLzdiK$F|ux;@DM$jL3U zd>|3ft~A^d2*Ovx(HLU`a^a_-bO39>IkB7>evHnZVrW`-?A*td?4U}dB%GQ_<3r_- zWH=-%g`;M%GKzyW7eOaB8GCYM&&g;=^qixdNVP89faPwK=YHM3HwDkfL{pi;3eut$=4i@@7d z81hqS2P#`hR5O~TfC0m-tnU%rfF-X%`i6`_po)+P_a-)f3JjD{h$AqBV+Go**V_6U zY{P8VLaL=sY5mtF!V?OLfHwfq9hzI`G-NbEPl+&zQWLxOOtUqQlUN}r8p4S6AP-7I zWTG>@gQwvt2XDj?XT5qQiWW*C4l)W$U8r;HrT z8+23#YAUx?W`$}Iag0zZ3BxJa1}fq>M+5;`=p>_AYSe5HOIM0+4?NQ!IzDjjZ0P8j zQ)zD!zUkB7GCGV?7bhTNp$#2m7BS{=qZKq0fk<0>E5H{LG7$iTEjk&VrOSiS%B!r^ zK#6MS=6c!qkxO$H1!M?9sTGJsg_|)B9yFRmP{tuhM5wvdxHtt!50dW?#fZ$iaIqip z8|^t`#oQQsSQs2;)w$dnf4{+Yz?8@VjKF8x7Q1Mt{D}V-ZNaBztdIzec}{ zfoSBE!rcv&E!+u+;0TQ(A}d6NEY&K{UZ2)qQ-Qxhx7X-4M@3bJD8MG85_FRVsqG~! zHM3r#?_L5K(Vl-#nSPgU(TC&vX$JOaujg zN5TxU&VXUYkvta!7dk%Xwn1E0 z-}H-;f{MzOa#v~9M&1BQuUIH)e6X%*KJxALv&UY2`eALu?JKvg+>YOh-x*)5-91|ZVcUYwm@S-Z{b@<< za&y;G^S)H`zV|$f%?DEcjWG83+)GpU;xaECV*F5L_X-Qyi_xz6EL}P2` zlHYvt=CPlYR@3vfZyvaL3|h|FV-J0SC0|3z*D!zR?(XmRyxnu(w|Dum?|SYe@B2DG z@|7(4Hl%zT=9Ax*||h?E7_h^F43M zfB3z^5B!HA|7-1>J@%o$<(GFN{P&XtnY{h!?v~>lUH@uh(eXA zOXo?Jb1xT|u(gZ1$MbG@Sik6*A=Lp1l(Mc1h@d&+jzVN1eHFdo*P%^0$`)!QRi+@O z2G#_zzQnXK^<`Qc)s7DgyQPs`2V$9WKT!j>L|U(;Kv{c?A)v zG_R5=5zg6)=5as{hCo;Zs1)*7*DT3xDWe7%mW&E9 zHtC$@$IL=8AT0F8Hja7`qzpu~F3u^dkS5SHa;kXY-77#(ERF0z63lA$2oS$AX6u=0 zxahL3A_U?XxvaIdc0YABZe9r=+`Tg^A{-?YYYKe6Foge6`lI?F-~LB&FB1_c(VXIM;G7pH{KO3)NUW~0aU0AmfP5Tydd9ZLX0 z00&IT`4+Cg%uc~q2{JaP!8hR}=^~Roa!g1u>7t=b#!%x;?~hxP5`&GFIE&QKOf{~#EHm4C zu=Pkd0qIH*7XVNf!Tbu3bI*u$t(7<+=oo67Uvcg>pGs-(*43b)tT$4^Bwk{f>lUjO zG9QKZWxsM(VQZjtU^*HJLOv`+8ROXM2}dk7@>rG)kdg&jv9$8Tqfx|Ov_tHn9PBQd z7oj9_gz;K2QP?c7gRub*5;!}#_Hwb2us!&>IJ<1~Yb+uRHr#8|sQz@$rv;FlxZ?oC$^v}9n0bfE+wYY);}W4K8( zX6q3ZP#_jn8bSXPS!T>7j>4uZ82+3)%}ZcAq?hl?1-C0uwN$n_RknH7vs_X(yZ_(# zcl{(#3HScF%}bSAQk7eN?t$Op@~%UO2!OvwPV#SuAEVRH%j6xo3#>`rkqf^~ z-YN4jhwB9U9^$MLqxb zF@t>Y0=OMs)^L3XxJqtFgQ|)eyvC9r;1;uEy$+}g&qNg)+m@8etwSy*A#qV#&STfE z(*RXK*ItY~;$+k)7|7^_^$UEp_Hh!yef?kb;y>b+X*PvOCITL1_UW2TFp{r-pFj!b zKBOzIW=LvFm9@=!9tud>`_n+>-0oDMd44Z$3%7v7J&5`z2fdX`4F&THRsda!xW4 zOrm*%q7&IfJ!mOArUP&XXeuV0qZ2FwcOpNBSphg~kO6|Sh6f6%(k_sYgAOwx>?$m8 z2yrPjWaQHg$H;;8(h+)T88b7` zfdTEHUuOr-LBp7V-qHVzvtB@H!}OUE0YtE*GIQ`eQt`qP|1L~WMl)pV^?pq8dsmm9 zvv2nPY|jl$v;PEO%qEjo1)kDXkgC8En+Gl=YqJbW^OtlZ+v2yS1FJidE>xrG!F$ZJ z5SrA8w;>9@W!qn>P!Tyl{+L$&7f}dSeuoP#?|X0VojtT%RXuz1<6@V;b}oE>UHko# z4u12nvUaJmBURaPcgMRImx6~=!NZG{y|abOC6%*Jaf;~O%BVvdab(ny3svaw6p0Gd7RYJ>emYSIQqXi}UFehc0eqav1S2l@SIP9iby*t? z*oCcuwme}nuIAlsFY=N?=GAS=t z9ySygm|dWOIWQFCgpSD2z=`*%80fNzas^T2FcmZ@c4AvI_W<%|Mfs#ljE5x`gQ7&Vtu^u&xWP|A{jM8KluCd%$$JXCbZi8+bcUk`r zerD1p3R__}vev{_nIHchVXLpBBo1sNu+z5tC7mF1UwiuNPtR`_4tP&}&~W(S#+KRM z`~F6Xaua^D31Z)S-lgp)Q`=AedBy$hr#akJSE{P(Zg{b3`+|S_TDa{Y<2HZA!_SP_ zNH)rt?RT>|E-J@>#_&B4f|$8TXXS0*0D#b2y(|xK5jvxm~vT9NMYl3BoMh zb(wq$vaT7g?f;z1Xii~j7^UaGQpY$lS7?;{cjR7TM=<0Xa~RRh;JhYy>dE~E1YlwK zf50|#k_o^}jLGsM6XEt`Mml(M8!}fZ~$TR~53-tq`FM7~S$PDH*dB>5?M=^)?SHrBP}!qRMm; z(A>jX9EcF!-dQqiZ5OYx5>cVCILx)6^2G$|LNLTVNCbh7+OwQnRj#q5lEhAu;YWmF z$(}Be(i!P#t?2;-=oXEPU>=DOXV)fT1;`!=b+G~i($@qVl8hm?Ee(y>6)om9bQuyd zU{e(#>t{;07GSU_NR5{+U}{2?OSblM=_&m7UJn zVtXTZuoijgvQU`(8A8|Sv=?Zei}Vazr+{;nKUd}I!6VglC5fgp8IkrfMB+l6V;>5F zJQ*Dz%U6n`Ibkwu!ir}hmG~ZgDaAsx0mdS-I*Teum&?H-eYsF13-=4_KT%?AN5T$X zsI}65sj}wTv#`~4}r6Cr&O5J@cXOS@Om|ee3jsu{Tw{Z?@=RNi}rC%k_=l@xS5!pnm6F@Ar$}E}lL0 z(~@dZDA&)sZ+>|`3>Ij)yyjtL)$ECfKEG7yK5^f-`J=jy_rmw<4$u0RH9vLWkL#A6 zJe_*-^kU_iSwtGBgkS9P`rY%pm)37ft>1R{#Nzth_r9>W{>bc^hY<7yHm3rc?|k8X zb0M&KF>rdpcX~C0Me-9SL%xQGwPbjgCFy`9`Z66-nOvj@LiFa@a+_Svs2s!>o@3bZ z<<<&o{d|NR!5Pi2Gx3YGWNfVC&`?R91pEUd*b{3Z}%^3+yCB< z1^>Z6_rW)$sNolO%sUjXFHP4rX2v{<#n2X^IY$seI+%cQmL6paj)g!VZ~IE=9Y=D*!lO@W zhdK5nHXs4TYIBiFVtqjZ4pAX^}25T?T!72}(&$|pkwFtK{O z6GhQkaUg?aoL=^2QYmt;C7T6z9LGc?0#nU)s0Qv34Wzw-xywKrL|YL$Aj>&W<$BOi z$T$>UEXJgq6F4nWVk2nJV3 zkG+YW4Z8i9ZhwYb+DB0mC`L8HD=aj%IRG!^4wSQ*6f0~d8*@R*LgtnkzscciKY!mC9 zmP(9NiLt;O`I5gaH8$TvLDh3%9;7>qQuw((1Wm3k`ejP2Kk&TrRJ=U3{x} zKKemhEm{s7)gndjlCdjgz=`n>&;H)olyPJ+ za5NP-|9%v=1>bqG2cl#8^5O}NbwBdqEqP*XgN18Q6h6+Cnx>{UzyxYw#Ydyq-IdPXQ9=zdx9)a|4 zGVnEBr1x7ZpHc^KbNXH~^_eB7%DL>7R6Xa%F{7XEv>WO`@W52h1dPSzkbPY zr2NL6>U-wW-s7pg$3OI+Sgxp9s%T49v@KS2%pRfWP1DOY>y~OdQZ*fmHJx*LL{}nk zEt7o%kgG5F+J5uQ-?-dG-JE?}s$$#S-o=XGH;(-6iU)5$;XwR1dp*5Pt{*lP z9dUbpxV579faiw?^6^Yf)R*4FX)Kvm#IR&vwwU{dr-%g9&Jtu|+XwQ7=N~B0@?;3K z5ULK)uZ3EG{$@}Dc?l9h9R5zP1y8sgi}?hHUJ@HFg=m*jW46(O z7rOJnV6kf`-o@TFoVzuvrg%4G;*?x4XcM$|Jz8h1G^Fpysh306V$wXOgGLt0Mo5;i ziI0Nq1dj-(JX>3pgJf_nO2>kO*SurF9nmf^*cHbkVfI4=0)UKST$0n0cBbOEGjy60 z@Pxg)Ux4olyy@{(=?xO$3y9?|t!pMT@Qkm$&ak&M1`Xth6BPFnXeP- zRIZi+lS{pOzS*%W&~i)CY4wBo=G;rAspio^-j5xI`UR7gm>z+^iNtTs3r~ zZB1E|e4i4*aTOu7am(D>8O^EfT*0nFj8j<02@1yzWQ9{E5Q=F_s%p!f(Z#CvS>H-t zaZ%ZF-TI}v&Qu*m$FAEud-8$5aml|4q3;kz>CVv7mOZI0d*1i`0!K}htyF>mo(=r+ z<5EUW`9)%qIDMhkR5+qCh=B{3!>xaJ9-d&y_?sVfm zhQ8}%u_oEn4QP+OSmFo~mqzN}6K!(Bop|HvB5BSSmGArN$zM zKtQBL9Gdc4;AUXH@V?JjBU++{wnHdBQ$ziZgi4FpR!Wz3*;^&Ck!)Dfjx2o~Yedjh zv|lLnPGSiX*kMj5D1s`X_U8sqoZ_I#jHL-3(RDrsHx*1DCO1(#lPj3OOdi(@`Nx-0=ZEWr#b-I6@i7IpVo| zmtdnA-vAqxF8{{)^NymqELFiK%#&SwZmJOIxbPWpSyxD*1YS*KQM$ODW(jNpKC zIJOeoPtLBHodJZ=@#0Eg=7bFPwF2?Koe)GXxpfsO@V$1guFah0$C8<(f39!FFxmk&Pj zg;MI%+$3%MFAVdF82@!d&b!!jBZ@5*O#%LvIvOG;cGn0Zb|j zjNxx@}LVru<0G~f9z=b8D?Lwiv}K90K~+J!H(Kku>e z!_|7c!sTByzn5X~l;8QD#WL%$g@F}l&k zO9|m&a#$ct9cgPf4)DVv*({Zr3g@6|Tmx7sywJsDu$uPiLfFFT02D%HVcP`j0)?vx z9#KKh>^+`$4w8VNSKJvL7!58gT&+BuK#XM=q(TtngqR!M7BwV}c{nv8BksZa5nd!p z^^db&;D#hEj__W)6+t+S{!zfYvDlPzE1)r;Gh&1YNgUDMsZ68Dd@<3}-7P(5f{4e_ zP0_#NXr}R;(_2RbuOVJa1_6`IZzqKamd3f*a})}6n0|Bc65UlMWhgK90S+O<&J6mP zHpe;cFj)|r%@sIBqXwq|o#+Pj7u!rwnNVb({>mW&bj{k%V)fCcY#cTf1D~owCCd=; zm^FvInvSO@(*eOHh){-rVLKoqYn0a-DaYg<$BGg*z;Xp4I$)fZt~6tjAWn--@)qzZ zL1)3;<4Aekqt&if4m})cE6}*nDTL#9R1IdHUhx6w#5@ZUm?Fu7stqF)ybWuZ>!}GE zd}t6Q`p{K_Xa%HU%SNC_A;JML(t5+HB&+IU5$lg*YyNe@*iV{%{~(0q&<8UV~UGSVUl7ma+V?Kb193KBEoEJ*c- zXP5fBdK?@v0IA_}RuyBTMsamz0xvl$Q)9|#RmN+f5flgvV-Zd2zEf5BrZCRx;?);t z1whrx>r>1fjVZ_Hfk-K%=r#`I)K2DP5?zse4vWx<<=V)17^m;_$pA8p3^R(6_?Sm; z6&@BimhIeVzfrg~qkv32OPr+YmjlPH>b%(3dyHr4xF+5hh#pr{qM}AngepL$)K_9a zGHb?8jCkr21pwIql1Spnkj0qMfSv-8N5vAwN9pltFHM>wI*17H_f+`c=+?1=IK0EL z>{d%Zb_RE5G~z5P2w6M~OJ3fF6%B&jUI{nF*_wa`0ekjv^s@!dC+^_%{4*jz6U`tY z1F>&`en=39t;e1x8=gG8Tq*KVt0OdhE2&;DL@z?{ifw=oMbR&e*6i)46{VU+Yp%1j z@d@OC*iMF~chgQQzV z)*j;7Dz~n&p!v>#!GF{39g(71A z6-evE*O3Q83(F0O*6r?F-FG%GR<>%ppoUFL4PB{*uG!PeO`E?HdLy*dv^UkXceWq# zE?|9>H(xP3GoSbXhmTZkTBzz;Zr;AIX~(^`dkqU458OKWaAWIT_uahtnYojce%(UA zSZ-{&yL+Lr`&Q9MwM`V|0`=9l&YnP6i1Io<#AM6Th8?L5J8qRc+|azVVNYtqo_prv zhW$9!gikqnP}@uaH#R=<J5{lKqvhoxOQ>xqjo_ zy7yZD{COC)l;Ru}5?U9q*gKf23f`T%cj^6t#i|p~%Khz15#{?Nu>tV#qo-<*cDa7s zRdlS)^W(j($67pp(&WbTpS0xTp5fX;+&N~^{b&x%6lt9i%M;-*GTcw32HB35X+3M} z%WUx>MevppQwwL@9O;wGns^HD1?$}HEZ5}N-S$xew!fV1RAXz?E@=BKs{o~=O*e4d z6ep=W58vrH{AHv7GLQguNn)9je@lH@j(!mjx;*@b3Z5K0th%>Evg;4(S6W?f0LPU8!u%2h&f zY+vbcj6~jNg#^n-2U>(^Q{ii(kbmo$fNR5g*m;qJKkK^OoAm-eZS6K$qph;b=)aL~ zkIzg#`d#$*8Y3-Wy4=0G?&J>j?($CcWdBu4E8(Q^j)WQ0{Z%@WDgP_^8Dg1N0IEmV zvewG2^M>|1!^c`vL(=Y1DXpZFwS$k$jf@=hzE}6b_9)j!JZW9HBxfVw zZ)F_5XNHb<*_NbK5?w-|1j~SogGT7f$jIn*xP$+LTfn&=TRz48&slu-fdEPoPp7;= zcF+oup0L#w5k19pWa#2W2PnX1&I;&*V8;KUMN5v7JZXr#8X1Yg+@Fr`%vqmKEh-fa zCWe-$SQH>fTX1KqW*rG5a5*GV4zpnzj%~T5=yP%kHpw{}(FfRtCFRIS8_hKYB(NEr zg1mzQTS0%)PW~lXANifb4}~hAODA*Yh1dvu6@Uh%V@$9vC_1X-%7nWEuZC4UlS>B; zu^=<0A)$uJBG62B9mfzeMoC5x8ZXmdN3@ArC7YwNI-rQMbGTKZ&29r9$mbY?@69n( zJcQ7QLJ*PB9~J9EjlINPV7<|1gt^XS8O2EH-hc(P=-gRpLKk_7kD!&7L&Re_+YgMf zYMh8KqNv*rWJy)z#;B`u6OPmYC?o;{G(m>Pdf4nz#e}W$-VI6@kwkDn;!#900zYfp zHL2OitZyt%XE(9lICp!qJ0-;RO5L{_2~zQth9eCD)}*8#iz6&l;ozwd4w3Eh1yaVO zkwP;|%tOs3S1MX{($K=*BjkWN+Gex*a@cTKcs8@&D|~GU7ifW()N_h@SR9DOOdEs( zC7ao&7WE2PRk$fD_tS&t`W+edROf0OT&whVQ8KNHwc7RfDS3M^%A(m+b+Sg_u9t+6;Ae}V&2WCGNz zu#2Wp8@zg@pHVAKtF&^+Fk(Cg$wy*87B{RMAjP6csT*et=ITC1VAa~W(Kol;FEJj} z)X!Ib^SRmMWZYakU-9)XFK=y2mAB00%^iQ^#KVd@#7SLGhqaB~sdyvu*2Q;|fAGv7 zA6wYcd%x<)a`Wa}r{|8mQTT9E%dMyJP=J!_jFr5+n*EPFUJ^oiA%wyikY%$y4=UF$ zSGK)dx77Y*s{P4@wgZTIb?_i=6$g>FN}Lx7>#_2N`Q~|3NV@I^c0LHKn{R$I@mAlv zPcCfOb3d^6k2~HU_@Ao(b<O&cUn%j-8mh=%hbYuj;NWNjrZ zwu@bx+ZM`O=L+7adr+}{{>WR^Zzb>e?^nPXV%_cMZ#}gKv+Y)%NI_r! zp#Ht)KWJPj@K+ph^I1Kesdb%8>-MGA?OU#Icu>FbJApR>kMcbYwYQFZ+`xVI*3`qV z0-j;-zs{zsdX;z^|GI1#;WL~pr>y>z2t97`EhvO zeg9S|UEA-f-}E=GLbUZkL(B5|#`zWu{Dx*Ur=|6d_1kSr&AU>~yB0R>zSoQ9tlNj? ztgro#eplU=TN7^$e(ww4{lag5@m_Cg%ihJ>eeVselor$+al?9@3j8ENh6;ajpyNc) z^=HANQ~91h+t*uk%H{bBS3Z7>0rd1maEa~2{V0aFByqdwkTKbkuUw`e@5plgh5NrL zAb$;XJ{FHa$b(GGc$SAWRw6Y3;T(A9Cd5?kZ!fh@l{*6+h3LR!+CNZ z%08-Fm&3PBw=Tyw-8us$c-f0BVArOe?4Susra<8qUUt9QIFmmH(>MBm5H>`w_Ic@G zXFn~v;U54#&DHTM-HYoQY;-)E~Ow z2R3WabjB)`rJ*#Gyz$Z5Eu@Q))d^NpSwHh(=Lwr2{ggTpsa2ja=b$3NR}gO`^~;&% zk0=Ljxw#WTI}xAgViJIR&1zTO7k)*03bkpo$}IXtU` zN^RP;Sid_}zGpVyc{<*%RNbx*0=t%t%}d6CltHKC8As+${-nC`&F7Yyx>8MD?_OK# zKAh@4{9$$P&pob9@>sk_#W)*JpRu<+Rk!_v!1m>q)}@vMsTL}w<;dLW<#l`KtC!Zb zr`EOK-L|-H@8Y^A=8in9TX*X#%NsYnS@iQF*JgFfUU|;*gEjI>qt~Bii>DVQ5L7O7 z1_S{dB%M@qShw3EOj~Gs!~N=duggAs%@$zibf48?S=7}>sDuw0)golfi@XFfvTfsl zP;;ab$Bim9{10#ct0!=9U`}O1PW!r?Zn>%ziPkkrBK)3p!A&q{Sr}hzNpuNeF;L|O z5JX2I_5j^Y(gSryr^7x~*wSPOge2#r5rkMgpsiuiLMOBkr%Pyo>2DDw0q!wJbdXDY z#DXW*Qx`$#P#=IOu~uey3mAY|*Oofs;v z94|9H3{i@G02awysomf^VU-}y`~=@YvC$!v5@;I&JJ=07Ftd_AOOB-n$TzpVVikYd zBhW16AP->8b4r;D8cl;vhI|mY5hu(x7>?LAf=U-lQ4=(L`v1oSNlXxK=a0^(Sy9 zk$TmhFLdJMRD>Y4I0Th!pc$nn$S#$;$>9gBHp1GqLYtlK!}K2rXaCPg54Cm!`wVxb z%DNWIx)Efwx^Ag@`~B+ez_fK;bed^vs;>2}cd@SP?xn@LeK$`+Q(LnG1b$7!o2^R? zovDV-yBGhedauUJ-Ko0n4+7l}8aI<_Q}-j(}-BXC+;@;9ga z%}f67lpp!Um-nBz??)Jpy4k>Lw*igJpJrqZ-5UBVE(Ff1v(JCdg}fDV7vT$UxNRo_ zTaTM7?kW5mNsfX`qGUn6=AZ#3O4f8A&|HpGf>Kn-FasrPLuXMR-E(azpjok{5K6W~ zfaQ#iKq$N1E=xTjc8JGDpVz%Oh<+!qDUpvPc%o1|y#8{MnTkHN7p+4`D3&$Fh*}jS zL=^_{ToS@rqLUEnoXI4O*@TrPlaqu*ZH#6kOd?fvdWl_$_oqPqiiD9i!Sd@7O;fH) zrwalN7`BN|O&tn?kntv>N0AF+Ohk>+8Ks4(>>SP~#+k|!7jc@^wFwpaizz~EB@V>N z{loxBlsjtMcgi*o2xNU!j1|X(hsCq7g#wm?WaUQQg<&ZK_goO?o=OI`}LD(uHVLG2r z0)>VmM^|#mezPRBMlZ)gCkQ~Cu9wE3CQ+hT$A&_2_IOu$Te_}#khC9%_K>FEAt)lm z<=8lCRpS)IO4^=z1m0;#N6k*D$^rEXFdpvtl*4*yA)%nffor+Xt%k0sQs@LV-4|b;Nc76Z>j@STcQ%PKw>&V;qHzFi@LPzD;*F-%Bp- zJCWLV;?D>F%J;d|$e#8;U?umX{|yfm^!gtM*#jl!5Ei_H;iXHW<2+{IOT;_p-S$Pb zDSUyBZR3QTbU2~n9AXHdVjWTkVVpee-tdQLibTb$kf=jXLw1R4B2u<4)GTROtv6wV z{MbS?5?Q?s$O?l7hmI$+%bt-O(B(At{Le+`XsWDL#D`~hJ>5i!eC7ZC>hmI@R;^!g;LqA+grwibI9G&c#}< z#}6l$KBEIUv7hg8;_-xsH#j}5aLqM20GMYIP{EK$NFDy6AxEDGG&z+J5sD?4Df?np zCX&!yIhrU&0pn$hvxI*YoD`S~#3!vpwe1YBRXRR6SFH|XL}Z0QEy4En>9hdSWddY2 zF@OYz>^8E4N-k7Daz6eDFIYauGVDAlf=5q}7xxc4D^BtiPFh;~E62@HR@K6U0Rx|i zCa0KT%%CB%tae!Nh~Ww1e`rh?p|#~WHiu8yF-M)pKQR&#CyODo%=`CPj095v)$xM*8ZSNSUH#>kj z7fff)F9~iTwIksKQC4<%5EfB5PCS+HuYn)*ZCsp*unOq)JPXQk74S=P4Ts#sK{6T& z;1v~T1G{5V@G-}vK%ECW1A=#QW0OJAiHf6_Vi_?dh_8@5zzvDiXzZ$&CB9H_2P%4v zb;K-;q^GaJ2|0vm#OcXS54Y9JLJXSbD{#Dr?4*KDcFGdauSX52$T9BBAnE4GW3qW! zpsmVTLFZLe^~BXE;uDZSBzqopQi~u-x#|A^&rUb}bRest>M)Y5*Uu9G6Q2nHZgiDz zm^bg7SPXP7_&Qf(Wum|U>+VPQ@IZeA%h^0QzI>4KxNgzjS|Gn|1fNU_2!t1@FzHkdlIW2E8T zxz;|xC+=i{bQ_Kt%duxDFE*@TIuX^mcRWYVH})Cz*mz?xju$O?W_U$LNd|(WABjGo zof5JNLMXbqYJuw=5sAZB<1nDXK_kG;(v~W_BVgWTl!!HZqN^YVmzaHO16of%)rB5s z{N`jhIL>j{+7O5rVf@Jc(298lx=iR(rCV*l(zKKg<4p|=_6fYizLXL20p}f?eMglu z5VP*OHN-Fj(P~17nFV?oi%!rH$Ir=wsu8_;OgN&_dXbiox)eK>m2Ni#Fyso>#j&q0 z;B+}1atCXUY(-Ewttkh{OWcZpl9zheZOoLryK7Og;)T5%OB({5~h_nuo%EVQN-hHBuTrS^w=aXDujbUMCgp%k8@jQ zo6o6H;SCKd)La=I?rTaEM);ypL0Lj)m zD_vDADLa+x=b-THM0vn$EWhW&V(oJ?sY#C;f>ot+=YW50BqNM=rC}Je01nGo;7b_w z#WO1e?jNUPL9jls+FAVz!ZmAj$fDZmTFPWGzyW{|rO@O6K~%bSJ+6m0?{4@nDhrO1gwJI&vSO z1HR*lh*Yqoy)-ZupW{a9(}nE72up6FRd@`=Ay3u0(DHPH;G1)OixNF`8il;<`o$L! zaisI7m54sMP`U4}_k+rP_X<*#`(_JQyq=;)j*Zlss%pJkxYV{k)wX}J?cie7p@;q| za-93dxnItn5D%XuNbvOfhF*{Bhn~vbn#^dDS_ksa!8UxBXp*Lz$TARSo?OAS6bZ&5 zNpcWw>idm+h{O;!1_Cgt4WR?2uez)rymt%F7(1LxF0F$q=^aVzF%hY9YTvNWmJ^|2 zsvuA!@oUy)Ti96So#REX>#~yIr=3a=l}Q>^zBaq8rW*w_1$?MU4q_DHS!DZfiI= z5C{zfU*kYwWIY7jiT`Lv)WP9_Lmh!8B_|dN5q}s8L8l^5H5reZI7=JnU4h7v5jD7M zWS3;IMsV_|XOe;<5CD99Xe(y!5IK};+MsAxVj}`+B6JqfL^kN-V+15hR52n`UBa5IN_H_n}=>Zq@xjvS>16^ELmc>T>$55|>GK!>dnowBU0velsz zP8v*h5t~4K3VR!NCOtGXaJK2oDNf4X>8KQDo%pC!DvwT5tIc>23aKHuJa!3C2qyq3>+yU zsaDcc3Ek)%1rcH3BVbw%MUbu%5}=R>4=ZBDq&?uZaD?NpP%090q|3N{dW@_~R1$gq zvthR|o+jx6w-?IABb3RfR@8Kv*uB;7@6wLF3%McZ-pj|aHmAy(@9bMF+lDCXTRUd+ zSMsWg*01FGN^2>Ey6=|n_2T9A8<*DaNv+?rxPIT9@8@N%>c;sKcfPn-wfkXU`@IvX z!2ad(p1Hz>`X^K6J%7CKU+(|G{y#c+zxeMdLDe$-NQbd%>t zomEG@o*zAxk2gQ|HsQ^WH+krJbMMx^;!Ntri~QIY+>f^6VQuQgrZPC(>pQfKI83m3 zi3sMF=Qby{s7>h~f+C($*4P8iKszjov1jrr&9Oe_ZWEco`Y zjIOddfqVlc$zboq^+7ZmqEODg zow9jZy*^zwAjM3w)10s3YT1MPv3ZC zf0w@HbJ?ON6q%&mJ%llMq!TgE@+uX@o!x^EXkgaced4V++=;SM+E2D-oD_=sFC?`m zqUh?g6e|eDamE&1$v3DStKRY~c^QvSA7!7N7l>2sWI0KnI%%iV7_!1+5!xjo?2iy= ziL^9qoeYZNE{4CBcjWc526?)gBwcz2 z6`*nzj_I+;J{OH(l(tJ3w4UA;Sl4xfvtUzxw{sCTw05fe)79j$6=a7kng;ghda-?{ z^*oXxeozQjyNF5^3Z?y_(3ikSP>?kIDh$EOYAh78$g0AkeI;EcWhq3HAY_wR-J|p+ z5JJ2((1$`HiA+2WW0bR6qT6@qc8_jGpHF{gQ5f zOE))lET3*n_0Ty{d@hC{hXVAILT|GPKgY1;5Jgriy(6Q1w(%5(0ps*@l5TMD65yWBb@Q87is-r6Roeb` z`+Jr5I}WUr&AsZR$aL}F#M zlBJ4MFVikjrJnkGyT)lRm8|!Ey!U22I~H%=%+9>o@yH>@VbTgavogY1Ck@*HWR!7? z<>zFaae}n+&ZZn@oMfBZa)fcpm8ThJNUOcMD6@=nq+th<%rh>KHugrBMaCr>tDB{& zIW}RI#?8^HnJxY~35AU#U8lBId`{f>|h=nW9-7GiNWFr7^SGz(EHYpB8~mG$92zIxAU{K1ThNn3jG< zD#dbgfYBf&Qc`0Spmbga8HFf$UJfw|Q=%XvjC368l2Jx6(lhV)8|*KXVG*^Px=@en z!?;)ExT%WEik&Enuzg)A3mr5mCheJ|$lEij2&2DJIYf$P8Ykw^fUgu$?*!0J254w- zSo$1@+*Bjd??5y)=~|+#`mod-X@Jy#9b|a?rDsN{_NEdPMOny;x;d1Q9`KHT(iY(I zvXWtGQhLB0DY*Tya#mbb0)O(Oe;~^edgByD zViKvH096X7Y=b9oVpDL%th#42|MSql zmCoq!89UlX&v1enuGN62fXlp(ye!z8i7o%F20V1z17h4{_wyQhcTUGkYwju7EiTiK zmFD%^DQeq?hnHW3K5oPG2-_KWbKW%#(@AYKq`JigaJazd=7^Zq+)Lh2vv4=)a`Qd+*OB+w_t#9;{bF9=)O5VcD%bw~ZsEkD>&X8y@ zy2ykV3jXe&b0ds-;}`s>_)u#J6t_GnibaJZ${dpakkms8A5y@gj71fTMl8x&RR4_z zEvi{`#-b^UCM-JZXkk!y{>)o6ZBg@xhAc{+luB8Yb3QSPTnt*YsA^HkqA|y;>{JMf zdd4jpbyP5bSsHEVc)Z^%e7#_K>z221S_epoTR*&XAcvb0xOI`;IX z`*vvjg-`?GR@n-6vHosS!f2%EQsivOZzVLeG)yi(>%&*~t*|ojdwYU1s zT^jlyO?YHG|GN6Bx|^E#dF^2O>fZF#x8ZABLHm?fDIEu{#FXaC#dpNq>F9p|!e`o% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2567893fabdcb1cc7569d3c74d680d8cbe38d9d2 GIT binary patch literal 4900 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 N%6t8v5eZ20{{mO{2=o8| literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c459593415642c408d89733a428f1bd9cf06874a GIT binary patch literal 42261 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
Mk7bw<{1y@P1(=0IubwTSj#J%0bX2_r?LZ6; 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 E028htivR!s 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..1869c965262059a1e0317ba2135934d3fb90d70a GIT binary patch literal 16223 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 bUluQ>?g@Ckw`;E??iC9|zY*928~uL(KRCeS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a03e6668c04e798930a2f0879bac7df418a2cc7 GIT binary patch literal 19837 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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..1d7c588ef7b43c21f4b0c9238576b45f4121fc4d GIT binary patch literal 9137 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 GqyGo)570*d 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..505e94731f654adfba74f612bf013fc520c8957f GIT binary patch literal 1870 zcmb_c&2Jk;6yNoCys@1R$Elq(nI@$)l-L5)TR((CNuxp)NCIN3cD445?IpWA%j~RU z`((HfapDHY9E-|@e}OBPNV&9I1tC=&dP|g^$^qW&+O;e7$Vxl==KbEx@6GSMoj)>} zv;@!Z-~LJ-@H>U2aRah!Ps*@;KZ<1CrMxocnpk|cRD{p-Y|NB~M|0Z#%tHAL}rfJgiI zEY1TyGlCah!_VPazzYJ$=hR}rU3|q|!X-fGUac;X;t2N~o(J^&5XB1tKH#3mi-0eT z;OI5{JiY)p5_l)Fvh-Y}ydwLGZrhaW+@Q957v||TYID-&U+7HCKA|<;++?)fc`hUZ zSNvmBcXz?aY9Bhz8gH+gw5pq~h!&1;xxhas-+093L(ljYaa|z#)My(vL?rtW-G9EM zY}c?GhFuWBBHnQTG0hILh;GBYsdLn!9@04{mct1~ zoFdO9sP5S{aWvgDcqfdr3Bd%Xd6S@;#~88sC{-D4Q{+;!MIhR6-$gFr$a9cxk46m= zO79uGDS$G(T0hInD`m7r#Cn1-t$7wugvY2;hAhemGHfudz*+8Q>O#e*PcKu^6v*cg|=s!6PJcQO>S&!W{p(9(#Y{f6s%?)!=mwI9sHE#@mDOa0^k8V>|^!}etg z%vKisw5HWP?lGciO#Fp@LNun`@MR9lhb`OEnag4V%I!1iJQ^SY=5v#F@FX1NWP5u4{U zZRF>MBy(c>Nij?bJXirI3|34FcU}xLVkp4yi*yE~^zuPv#|4^7t;#DO5qFnUr?R&G z+4~jOupE=D?vX0+t_I3iTEuQuOru(HI=o5k56bU}I8Ig_y|xRz>Q=(IMtEzKozBbD zHH%`;BsbV4pcB`OdkVuzRF>sGrKM-m)UmYmxAfLu(b)Glzq@%HD;>v{k7J9$c9U#T!AyO2`{0os6y9lTL58IwA(*OVf literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7e58fcf38e81fbdcd3aed17b9cf4baae35d0f03b GIT binary patch literal 24814 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 U(ABNrD^CI%)}F)%aldlv|4x)o-v9sr 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..4d556ef27fda5ed764a02363d9a8e8c6c7f47a4c GIT binary patch literal 16319 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 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..60f17c37e92b9f18d0b3c7e59fdb60171a88d897 GIT binary patch literal 13685 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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..230d3cc950d3243cf19b7d3f7144cf3f7c13d6e0 GIT binary patch literal 4282 zcmbVNO-$Qp8n$DHgpd#dA%wI8p)GCs%?1dxP)hk}DKMRO_?c=Wt&mB+q)APZ+71*h z+w7(ERB}pkBAf`?mB^m9ds=C(bMYt5A+l7d(wz2|YHoAceeL{!z+soMgypPsKwuRrPuB1QNKKgklCq?aV+Zw;&QQiuwJ@BG6x zgP&rxn|0ngC6;D&n|iNa`PQ=an+C6eBp}yzK9eB)b;yWJ;Jbd&2iA^@)^;#~$9d5M zNU9kDO*!X=TFxatlk5xVdZ*4Rt=*W*{aOy{_RCrt^#}OovqpGx41QmXumaFtn*{KqOxAQ98K{!j7F$d*t zsPOvFFqV0pSL20fwf@;p>wyTBUer=_8Qv*oS!>rN*mEjfzVs}YF>eB<+L=_XqK4XA zveF=V`Aja)1@HeiukNepRl5E=I|Dpdo8y&vF3k6~I;UR;c9mPaJi$A^E9-8}te!G% zuX==XTVJ`>pr*1N-o6^R>L;u6KS1r&QQ<4=P&V~cOFwA2%J!>F0d7Hisbe+kQqNM| zcy#6_DbHcxDjH!|E>)xKlFCU_;T_!3^cepwUn@PN)WAd{QGpRc(Fp$?{5HQ_nO~TW z#n_NfF@j0=6fu6p@$ji%Mtlq+5myK4gPa!L91SnYRPoHR3@?XjH=^-~zsDsR*4G1Z zAx7+HC=!%NK{BoW@x|ly*{6?ZmlnR8mm1f>h4@#Y#d42)p(3WQbVZ)C7XT)y@{iU4@t&yXG(S|6cMDBN*|UH zsEm|6x>YFa2ZrNxa{c<}F}d9gD_Nk?&$$^OigA#qCl6sc984oIko9sRlS#(PoTg1XL5kR*85LVnKN|vudAbqZP%yCifDHHLtXShwv(KtvhxA&O%6=p&F z_9xdGY%}ljZ3wP8#J?7zG1u(;_d_l|1T~_8ZL|S9G7x~Re(l;qku4V++Hl2ogjdnX z@St0c6VO16@x5k(hf+*z@hX zQ=X(}FO2DSIb<=hxW^}+S3cvIZY`R1+P1G$y+!lRRCEyLrjNl7!F^xaeK49C&ECvR z(OAJOMGR++ zqOl*-0|k&@Ps{S_+B723QnV2k$3B^=Pu8bhdB@L958j!+SX)zz$;C9Ed@d4}0uXK| zL9^0}ebe5bvnJ6zfa$@rCi1A^up##hJI6)yIHo6H6xzwJ6lDhzYf(>hbRN9Syewzz zar+~CZ!v98cOCR*db7(p%gMFlYxz~&GcI4!4?BbnX`^i4p2tNUo|u!0O7ai>O;qv@NVJ)ViD zdvQy*Xzs@J?TfW-Wwx@uocqLc?8%04=V=>c4i8Y=0tzQkIIbNyGLGylw72!RHM@x0 zT_RyCKs(jUFz4OmZuVwY$oAm2ewbUK)t2%mz1fy5a}+oXRu@j_TFIowE``INUQ`)3{v8Ty{hD?KaYYf}(iROElzAsk} z8&h64L-nke&#!2`BbqBmL^;v>)2XH8lIR@9))CP>f@zNoF$NG8O~S;Dz?Je}^PPCV 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..cc4ed42d69c91f406603ae69b68fc54fa2f70c91 GIT binary patch literal 7007 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 Z&A6g8-62?h=BW=Uk6dp0oWM)W|38QJ6o>!- literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..28f76dcb36867f7f929005393b9e5e7a515fb9e2 GIT binary patch literal 6128 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 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, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "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_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "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, + } + ) + + #: 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") -> 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". + + Note this is a duplicate of the same method in the Flask + class. + + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + return open(os.path.join(self.root_path, resource), mode) + + def open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + 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. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + """ + if request is not None: + # If subdomain matching is disabled (the default), use the + # default subdomain in all cases. This should be the default + # in Werkzeug but it currently does not have that feature. + if not self.subdomain_matching: + subdomain = self.url_map.default_subdomain or None + else: + subdomain = None + + return self.url_map.bind_to_environ( + request.environ, + server_name=self.config["SERVER_NAME"], + subdomain=subdomain, + ) + # We need at the very least the server name to be set for this + # to work. + 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 = headers = 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 + 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, + 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) # type: ignore[arg-type] + + 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 0000000..aa9eacf --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/blueprints.py @@ -0,0 +1,129 @@ +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") -> 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". + + Note this is a duplicate of the same method in the Flask + class. + + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + return open(os.path.join(self.root_path, resource), mode) diff --git a/venv/lib/python3.12/site-packages/flask/cli.py b/venv/lib/python3.12/site-packages/flask/cli.py new file mode 100644 index 0000000..ecb292a --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/cli.py @@ -0,0 +1,1109 @@ +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. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: 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._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 + + if self.create_app is not None: + app: Flask | None = 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: + if value is None: + return None + + import importlib + + try: + importlib.import_module("dotenv") + except ImportError: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Don't check FLASK_SKIP_DOTENV, that only disables automatically + # loading .env and .flaskenv files. + load_dotenv(value) + 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. 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:: 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(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 + + 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" + + # Attempt to load .env and .flask env files. The --env-file + # option can cause another file to be loaded. + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + 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 + ) + + 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: + # 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) -> bool: + """Load "dotenv" files in order of precedence to set environment variables. + + If an env var is already set it is not overwritten, so earlier files in the + list are preferred over later files. + + 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 instead of searching. + :return: ``True`` if a file was loaded. + + .. 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 or .flaskenv files present." + ' Do "pip install python-dotenv" to use them.', + fg="yellow", + err=True, + ) + + return False + + # Always return after attempting to load a given path, don't load + # the default files. + if path is not None: + if os.path.isfile(path): + return dotenv.load_dotenv(path, encoding="utf-8") + + return False + + loaded = False + + for name in (".env", ".flaskenv"): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + dotenv.load_dotenv(path, encoding="utf-8") + loaded = True + + return loaded # True if at least one file was located and 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() + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app( + environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict[str, t.Any] = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.12/site-packages/flask/config.py b/venv/lib/python3.12/site-packages/flask/config.py new file mode 100644 index 0000000..7e3ba17 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/config.py @@ -0,0 +1,370 @@ +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}_" + len_prefix = len(prefix) + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + # Change to key.removeprefix(prefix) on Python >= 3.9. + key = key[len_prefix:] + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile( + self, filename: str | os.PathLike[str], silent: bool = False + ) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str | os.PathLike[str], + load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/venv/lib/python3.12/site-packages/flask/ctx.py b/venv/lib/python3.12/site-packages/flask/ctx.py new file mode 100644 index 0000000..9b164d3 --- /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 0000000..2c8c4c4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/debughelpers.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import typing as t + +from jinja2.loaders import BaseLoader +from werkzeug.routing import RequestRedirect + +from .blueprints import Blueprint +from .globals import request_ctx +from .sansio.app import App + +if t.TYPE_CHECKING: + from .sansio.scaffold import Scaffold + from .wrappers import Request + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request: Request, key: str) -> None: + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self) -> str: + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request: Request) -> None: + exc = request.routing_exception + assert isinstance(exc, RequestRedirect) + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request: Request) -> None: + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): # type: ignore[valid-type, misc] + def __getitem__(self, key: str) -> t.Any: + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts( + app: App, + template: str, + attempts: list[ + tuple[ + BaseLoader, + Scaffold, + tuple[str, str | None, t.Callable[[], bool] | None] | None, + ] + ], +) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, App): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/venv/lib/python3.12/site-packages/flask/globals.py b/venv/lib/python3.12/site-packages/flask/globals.py new file mode 100644 index 0000000..e2c410c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/globals.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) diff --git a/venv/lib/python3.12/site-packages/flask/helpers.py b/venv/lib/python3.12/site-packages/flask/helpers.py new file mode 100644 index 0000000..359a842 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,621 @@ +from __future__ import annotations + +import importlib.util +import os +import sys +import typing as t +from datetime import datetime +from functools import lru_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") + + +def stream_with_context( + generator_or_function: 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. + :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) + 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] + + +@lru_cache(maxsize=None) +def _split_blueprint_path(name: str) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/venv/lib/python3.12/site-packages/flask/json/__init__.py b/venv/lib/python3.12/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..c0941d0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f7c6d1d85d1d12608f7051babcba8534b59acecd GIT binary patch literal 6698 zcmd5=&2JmW72l;OX)Ri!?Zk~^*YPBli?WrLvK+esV>mJV6}PC9MoK?a6y%UQlvY~q zGP6suG>jrG0u=6{@hv|3U<57-^pEH@7ZC{{fVBamX%D^?PiGPS*Pd(nT?u|7=C zjXGn_9z4gKtTTdV*4gJ|@Z9I@clP4Bzm>`zctk>SW+%gaKZtnb27Y+$5iOKHRvJ?&x7=KcUmh@w86jQnxz`1A zc*GeG*$-#lzGjb%F#N7oS%E$mO24UkJY2H-lv84E$oMjMJzn<21al+SbUlwXLVfv{D?5viizSU*0>^ef)H19j{i|To;^D zRq}gt6{-!tQYiK0m%58D)Vbs}7L*qYY<8i$zbIf~yklFhQFmKvaycIs*m*hMsNwuW zR_9?T9EK5?mz7FtNhNH%R`&#TQI^x4%(mIGkReQ|vcUa$;S>sN+CHUbAWhN&N~8z~ zP!ozsNY;e9rKknV!r4~NbRy>h_q-62`VOK`wWZPoLx-U0`tywY4D-?YAzw=9IFUjd zDvJfa>;`h%iKpz|)P)L6AS{#|QE_YBvoGqWvV*WuuLm-My2>q934BZ#(Hby0XJI5! z-+rECX{D0zD}jRn(3CQ$vWRuWT%TPgJA`UaZX@rcJ=LfBSnU-k1hTrv>bO!=BCj>U zB!@cSr#LrE^nSyo)poU)EDL*z#IGY(4J7Ta>drSX4#%yHs52ZR#E>K`=%mRWJA=w* zIwPToy6uvDxieU#=3J^X0PE}wY1<3QjTw9FA)raYk)%3x3`rs}1 z?xD}q-@BjL_tEP&U%wT$Gbe6WQLLm-tU;7f>4&-m9RGrrb>R5Q(}3d*vzh`trU)KQ zqm{am+C6~WC_6X6&94MW*oecL657^wUUfauwaTvpICqSjPX(J#hnm$o5R=iySx^@~ z{GS|zbfUZ;9%Hkag`nX%>Ruq+d2jaeSG&onmg zJ~Ssf{8_AS0^73dbJWf7ItNJv?^;fSn(Huo zv~3-|UAZ&ewx;fV>oaTWp*6N@z1X&1yq&xI^Up2&zBT&M$jy;kr*5a(7BJ^C>x4W2 zNtJ|U;Uxi_>v&lQIR7^rixMuj1BPYtF(?2S9y5+_f@66BcXr0HRL>^{3pHv3T7Wmr z((MS}SMCiK5Q*>!`IQ#@tn#bw>UNu7CBC=LMYrWWJu+Ksgb|@8Po!w7wdovG`&Jb7 zn`cV7v?53vLk5*rHFTspW~f0!^B|2GFTjH(6+gy5`~eDJ#`G36g}1ZQ_s*bLv8Mmg zr6upTGskaVMzNAU{w$-!;cZX?l$7IEl|c>Q{xvcTI*A=I4C?q)ps@inwx$lW+n73R zGGn@lcFYK9ozE;I(2Lt;FzJPAvs*`-6rOJ#O`X~%nwqw!5`1|=lv2bnMk$J)5<#`V zLCyg8MVGJ8JNQVnu=xU6hZt$nTo*7Ta!tl&$T&=2sqpZRA!BMiWQ@17<9FWO02zgw zgDYN{rNy0>M%@ui_%J(y9v^6y9+$1jpgI zxKi{yMCLW@EW4r^lf^i?*O?K$6w2ISkj{%S-iU%4CaWM5(NfC@8WHn_(2gB2Y5*;D zK@ikVW>Lj(io6AOj15*Is6l-aSPquew*y)LnUYos$=W*C6t8DTpcZ#N7lYJQpE;u3 zm}lBhNsrh?9UH+~5#wNkl-tWd4Wcln#+N7qrnV+{=u&PWz-G8( z6RLoRHX{SigDhlDXqqG+rj>IEJ^=~!08u^C4csGjEQwY#kWQbSbdwv(d?pyunyid; znPy-JMty_^Nn(r3uANOFFt`@@f?zW2<;CJ$R2OP7kn&rpT$>lPk&NAvBhK~)D7#!gK*`;T%uM$stG+T%7N7L)$76l7 z$G*Aysj?~idxy70k3hk9W&|-&wD``FrxE~Rty_D!8khmi+3&+FT8c>!jGHJTI(xqbFkFB$SzJ@2x$?v0yZo2R_6#p79P4j{A$`{7- ze=`pJ(|GxT@zTSA^zYyJ-5U?m$Jd6AncrEvXdXd%_S@$8+PNd<_?Ksyc}7Y8FNB>( Aw*UYD 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..35ed48c90b36eea6a67a5ad27149eec173bc2b98 GIT binary patch literal 9265 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 z zHCEVGq7Dtwe*uw*!T0Dc}~%-Xee))J*{rp>A%V zcfJWl5tgjlQ>ky5PJ>o(+IecD;+y#0Ta|o_REZ{33H6TRSGb&g$wxkx)TKcpZ7T->4CqFX+H(Y==D~P?&7rHiy!{>QB z5yue}VFnW+10H0egDApi>9`Y~fd5Op3~MLj^ZJ6tM=731DelERX0FqoVlux3mar>3 zi82nL0}!}C&XY@^lyOUsRS2m{ZYZ;8h;Wo7Pli|vT&-#pM{j*9ZszJ{OgP7FR?RP5 zgVJG0U`WW--(zZP2MS`Aov+rdE9;q?M>o43+YCOQRUfaGHsVDNG@TYofyP!A?Uk3i zl`VqqssLhpW>Hb40Jx0N0mp&V5wh>2v(Bxt*ZpwU-R{0dh=&_04zC*Kc6L|n#9moa96#zdKN8dv*M++C4# zXsX92)u`-6D|cAXq=NJQl{(fo-gG45l-q?0KP2H^dAak-Iq!M%QuUOaiHP0#lnx91 z8%A*`w-xNTx^QJ7t9JcHtfOMY>d86l5C^-H3`DC?;gxyu53=emK7A?U)Y8lg zGz}F$q#IO<0XY&NST5;Y=(T zXM-?Mdf4vT3?9m=hkhe6k~CLCz6;KMFt$~a*z zN?p-yZrF9C79ga|GctIf3z-zOV~58YSr@c9;34aTX~ZZ3>UyOS14YgR?Jr!@AG0k( zPa-&)N>lQT8*`_81?o1Ak*1L>lA5R82t2(E;8F&TMi4l;C8mL773zJcFf93pCo9_c z>A$j(@24vpYwV3G#(FNDju~OnR8`-)5%jQI5k0U=9tIt9N{X^sqNK0gt6)0}w5&=o z#I_>tJ86cV3cYLlg@>hc?eH`p0$tlf{JQhKEWOm}lNOvaxsL*f;gGo5V)%Nc_DcGKDt=MdP~yQ!9&Zwm+H5A58xKK z)4ua|d+)9G-sPdK#+Iv3UwL|M|C^0_-t|fyj*B%)7;&$HCtboSR*}O-k#=`Qmwk)A zT5-V3%A&%;iymwDqEg%OcTr-&VnoA`7ZrHkJ>Mv}{=OnF`f7i<$P*M6y-VGA?{~p0 z-Y<|nuecU{F2u65;JwFp4HX~ZanXw}-CYa54EgkD@%T9>^+VHnRuYIN0!2K4UKBP* zh)6UBk*%RazV(@iNCD%)Xpt!ap?3)$*1kZARESTDeY#EJ>qMb=-WrYNUd4%=-chp{ z?{+3c%0tu~)DRG6^OP_{L38sG+!6ddf>@X~GObPPam39IIy@LcsEdo6JI|nbDLOd$ zyXFE<0+{5HFFgibQ#BjUd>Ir8Fr>?BWL6<}htw0Hj7wrzLw*Hi*HHkiY+C9@IbYP3 z$M&r`Gm7*;ElNoyIKI?c%H$-4VUb?u0#EmnmAP}%fOB(&oIPsB1C2^m0hv&0G{7LE z^=d8(utL#~K%+b=8qEp7yObnNi~%PnIR$WbL((A)G z&wA&&wQgn~8p`$zZ|*pqZ8?2sx3)Zdb>zy(O7zO;orad>iRe635ZQS6 zf;W`A<|tf{=>nTnt9{J2m#FeEx*%Psedp@n%Y)GH!8STFtaZK_?AhA6YjytG{95|@ zb3bb7yQ@eYdnlIQx!hQd(t_6i9>yy_PrdF~GsK<|Z(|-pLh<-t)agZ(x?d3TYwO;N zvKXiKTM=%osn;u_ujCiY3>L{zn+B!1H7ORGi6IL>qzkbVSZ+vRCvhtYXp+D&+T^mT z&}L3aCoxNAS52z$cOjw+#j6nKZfIUkzc{$o`n4yv+Pjv|{H!dRd#9m!#aNA9i)}RY z@Yi>O?VNh;SDw2a?B59Xzoxtvy%E?9K9W@*sU{k2cDWqv!;Ixbt3Cv?({O*(;Bwdf zQ5MPDSrN&j(@(`!7PWi8hwTuL`$@IQR$vL4vya14JpF+@8~kz&FWbX|ItYI7pbl-d zXlqalhJu+#00&zwz~H0tOCyK8?z!x9V~GBe$mwS>Z>}N2sTQ%2+s*zAEzCp#rYK4# zPm>y>S3Gu1SmYX1DA1Sjn5miJ9WELA6T}r?Lsz(l8sL$6b^KPtzB`W{|6#)q8vd#2 zR>!A*(Da7yrhN0^mCvsEZg(Br=sNgX>t@$O8=Vh*ziIjOM#rb`babsgb?vFO^kzrj z@@a$wNtCzirRJ_R=u!&L`#f-wQ~cPgt}A`cC&LzyF^Pb)9M~k2V!F0{Mr^nCm_{UxxfWk4s9(r#JHm zM1`AKk@-btl4p)no;N8@_kRlTv^WG-uvI~J*9Y?959C24w<0-|HdA(rS=b-90vch= z$n#USNv2o#kV~E@dy*&s&L+7;kZXMPi`TxmW?qln+;!`Ii4($a4<;-yE{1WgqAsk~ zfZSZ1JcI09{vQn}!90N#m#mcU8cO`Ow2eS!rm!U<-O-|4H)1l@Mn%=Ssr4S~=6S)V zi|dAhxgG4;2=;tOSvSAkxEVZ>RgZARf+>#B=;Y`Pc|JWFQrXvO+$K8yoploF&apqG zK4f#)ReBr1u~S>rXb)EWoF{9zscw%@Up_MBfVr(y7p>%ia9gQf(zmlR+z9jIq=`5lVVbGJj<*}c`R-L3CY4&7Rq5H=r$lO7<(A`IdlkG~X3Kt;@+o5vhqBrqFJl_d>~m z(`ibMM3Nt@00KfF6=WwT+d2Of_RNnSWhBHrTEs|u=6rOFW^`W41&Z+qMrt6}G;gxm zjG3MZQ`R|aqA$sXmGe>dvXDEDs}6ees}g`?vK+e~sK-Q7;|cax7>Xpy`fC(-y|OI7 z>j}xe|M|Qu$@_mQwY@EM^S|A1OPxQLQ0{+Q>ixOY^|sXY3;!N@;9UvD_9=O%d|-KI zTf%MoXoK9gJijgBw%y$zcZ+)Wc6YsK$8Ec-LDodOw%r|+cdyiKOSo` 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) + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/venv/lib/python3.12/site-packages/flask/json/tag.py b/venv/lib/python3.12/site-packages/flask/json/tag.py new file mode 100644 index 0000000..8dc3629 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/tag.py @@ -0,0 +1,327 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" + +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If empty, this tag is + #: only used as an intermediate step during tagging. + key: str = "" + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> t.Any: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def _untag_scan(self, value: t.Any) -> t.Any: + if isinstance(value, dict): + # untag each item recursively + value = {k: self._untag_scan(v) for k, v in value.items()} + # untag the dict itself + value = self.untag(value) + elif isinstance(value, list): + # untag each item recursively + value = [self._untag_scan(item) for item in value] + + return value + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return self._untag_scan(loads(value)) diff --git a/venv/lib/python3.12/site-packages/flask/logging.py b/venv/lib/python3.12/site-packages/flask/logging.py new file mode 100644 index 0000000..0cb8f43 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/logging.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .sansio.app import App + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + if request: + return request.environ["wsgi.errors"] # type: ignore[no-any-return] + + return sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: App) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/venv/lib/python3.12/site-packages/flask/py.typed b/venv/lib/python3.12/site-packages/flask/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/README.md b/venv/lib/python3.12/site-packages/flask/sansio/README.md new file mode 100644 index 0000000..623ac19 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/README.md @@ -0,0 +1,6 @@ +# Sansio + +This folder contains code that can be used by alternative Flask +implementations, for example Quart. The code therefore cannot do any +IO, nor be part of a likely IO path. Finally this code cannot use the +Flask globals. diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fdaa8364ee9590aa7d733251c14007cab01569fe GIT binary patch literal 33592 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 P;LGM6pK|nM%kh5!^DR+W 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..3a2907c68c4a6d5d01aa77f9d76cdb9611d8ac70 GIT binary patch literal 30494 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 YhjkUMriTsNT)Q3(ySBPEF*D--1?i#O^Z)<= literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/app.py b/venv/lib/python3.12/site-packages/flask/sansio/app.py new file mode 100644 index 0000000..01fd5db --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/app.py @@ -0,0 +1,964 @@ +from __future__ import annotations + +import logging +import os +import sys +import typing as t +from datetime import timedelta +from itertools import chain + +from werkzeug.exceptions import Aborter +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.routing import BuildError +from werkzeug.routing import Map +from werkzeug.routing import Rule +from werkzeug.sansio.response import Response +from werkzeug.utils import cached_property +from werkzeug.utils import redirect as _wz_redirect + +from .. import typing as ft +from ..config import Config +from ..config import ConfigAttribute +from ..ctx import _AppCtxGlobals +from ..helpers import _split_blueprint_path +from ..helpers import get_debug_flag +from ..json.provider import DefaultJSONProvider +from ..json.provider import JSONProvider +from ..logging import create_logger +from ..templating import DispatchingJinjaLoader +from ..templating import Environment +from .scaffold import _endpoint_from_view_func +from .scaffold import find_package +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.wrappers import Response as BaseResponse + + from ..testing import FlaskClient + from ..testing import FlaskCliRunner + from .blueprints import Blueprint + +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 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, + ): + 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(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: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule_obj = self.url_rule_class(rule, methods=methods, **options) + rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] + + self.url_map.add(rule_obj) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError( + "View function mapping is overwriting an existing" + f" endpoint function: {endpoint}" + ) + self.view_functions[endpoint] = view_func + + @setupmethod + def template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler( + self, e: Exception, blueprints: list[str] + ) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*blueprints, None) + + for c in (code, None) if code is not None else (None,): + for name in names: + handler_map = self.error_handler_spec[name][c] + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + return None + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect( + location, + code=code, + Response=self.response_class, # type: ignore[arg-type] + ) + + def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + names: t.Iterable[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error diff --git a/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py new file mode 100644 index 0000000..4f912cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py @@ -0,0 +1,632 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .. import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import App + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: App, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore[assignment] + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: DeferredSetupFunction) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: DeferredSetupFunction) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: App, options: dict[str, t.Any], first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: App, options: dict[str, t.Any]) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, # type: ignore[attr-defined] + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + self._merge_blueprint_funcs(app, name) + + for deferred in self.deferred_functions: + deferred(state) + + cli_resolved_group = options.get("cli_group", self.cli_group) + + if self.cli.commands: + if cli_resolved_group is None: + app.cli.commands.update(self.cli.commands) + elif cli_resolved_group is _sentinel: + self.cli.name = name + app.cli.add_command(self.cli) + else: + self.cli.name = cli_resolved_group + app.cli.add_command(self.cli) + + for blueprint, bp_options in self._blueprints: + bp_options = bp_options.copy() + bp_url_prefix = bp_options.get("url_prefix") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + def _merge_blueprint_funcs(self, app: App, name: str) -> None: + def extend( + bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + ) -> None: + for key, values in bp_dict.items(): + key = name if key is None else f"{name}.{key}" + parent_dict[key].extend(values) + + for key, value in self.error_handler_spec.items(): + key = name if key is None else f"{name}.{key}" + value = defaultdict( + dict, + { + code: {exc_class: func for exc_class, func in code_values.items()} + for code, code_values in value.items() + }, + ) + app.error_handler_spec[key] = value + + for endpoint, func in self.view_functions.items(): + app.view_functions[endpoint] = func + + extend(self.before_request_funcs, app.before_request_funcs) + extend(self.after_request_funcs, app.after_request_funcs) + extend( + self.teardown_request_funcs, + app.teardown_request_funcs, + ) + extend(self.url_default_functions, app.url_default_functions) + extend(self.url_value_preprocessors, app.url_value_preprocessors) + extend(self.template_context_processors, app.template_context_processors) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + def from_blueprint(state: BlueprintSetupState) -> None: + state.app.errorhandler(code)(f) + + self.record_once(from_blueprint) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py new file mode 100644 index 0000000..69e33a0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py @@ -0,0 +1,801 @@ +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 _path_is_relative_to(path: pathlib.PurePath, base: str) -> bool: + # Path.is_relative_to doesn't exist until Python 3.9 + try: + path.relative_to(base) + return True + except ValueError: + return False + + +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 _path_is_relative_to(package_path, 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 _path_is_relative_to(pathlib.PurePath(package_path), py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/venv/lib/python3.12/site-packages/flask/sessions.py b/venv/lib/python3.12/site-packages/flask/sessions.py new file mode 100644 index 0000000..ee19ad6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,379 @@ +from __future__ import annotations + +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 + + +# TODO generic when Python > 3.8 +class SessionMixin(MutableMapping): # type: ignore[type-arg] + """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 + + +# TODO generic when Python > 3.8 +class SecureCookieSession(CallbackDict, SessionMixin): # type: ignore[type-arg] + """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: t.Any = 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_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 + signer_kwargs = dict( + key_derivation=self.key_derivation, digest_method=self.digest_method + ) + return URLSafeTimedSerializer( + app.secret_key, + salt=self.salt, + serializer=self.serializer, + signer_kwargs=signer_kwargs, + ) + + 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) + 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, + 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 + response.set_cookie( + name, + val, # type: ignore + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/venv/lib/python3.12/site-packages/flask/signals.py b/venv/lib/python3.12/site-packages/flask/signals.py new file mode 100644 index 0000000..444fda9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/signals.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") diff --git a/venv/lib/python3.12/site-packages/flask/templating.py b/venv/lib/python3.12/site-packages/flask/templating.py new file mode 100644 index 0000000..618a3b3 --- /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 0000000..a27b7c8 --- /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 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: + sep = b"?" if isinstance(url.query, bytes) else "?" + path += sep + 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 + ) -> t.Any: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/venv/lib/python3.12/site-packages/flask/typing.py b/venv/lib/python3.12/site-packages/flask/typing.py new file mode 100644 index 0000000..cf6d4ae --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/typing.py @@ -0,0 +1,90 @@ +from __future__ import annotations + +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, + t.List[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[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, t.List[str], t.Tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[t.Tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + t.Tuple[ResponseValue, HeadersValue], + t.Tuple[ResponseValue, int], + t.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[[], t.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[[], t.Dict[str, t.Any]], + t.Callable[[], t.Awaitable[t.Dict[str, t.Any]]], +] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, t.Dict[str, t.Any]], None] +URLValuePreprocessorCallable = t.Callable[ + [t.Optional[str], t.Optional[t.Dict[str, t.Any]]], None +] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Union[ + t.Callable[[t.Any], ResponseReturnValue], + t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], +] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/venv/lib/python3.12/site-packages/flask/views.py b/venv/lib/python3.12/site-packages/flask/views.py new file mode 100644 index 0000000..794fdc0 --- /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[[F], F]]] = [] + + #: 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) + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/venv/lib/python3.12/site-packages/flask/wrappers.py b/venv/lib/python3.12/site-packages/flask/wrappers.py new file mode 100644 index 0000000..c1eca80 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/wrappers.py @@ -0,0 +1,174 @@ +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 + + @property + def max_content_length(self) -> int | None: # type: ignore[override] + """Read-only view of the ``MAX_CONTENT_LENGTH`` config key.""" + if current_app: + return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] + else: + return None + + @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 + + 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 e: + if current_app and current_app.debug: + raise + + raise BadRequest() from e + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt new file mode 100644 index 0000000..7b190ca --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2011 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA new file mode 100644 index 0000000..ddf5464 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: itsdangerous +Version: 2.2.0 +Summary: Safely pass data to untrusted environments and back. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/itsdangerous/ + +# ItsDangerous + +... so better sign this + +Various helpers to pass data to untrusted environments and to get it +back safe and sound. Data is cryptographically signed to ensure that a +token has not been tampered with. + +It's possible to customize how data is serialized. Data is compressed as +needed. A timestamp can be added and verified automatically while +loading a token. + + +## A Simple Example + +Here's how you could generate a token for transmitting a user's id and +name between web requests. + +```python +from itsdangerous import URLSafeSerializer +auth_s = URLSafeSerializer("secret key", "auth") +token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) + +print(token) +# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg + +data = auth_s.loads(token) +print(data["name"]) +# itsdangerous +``` + + +## Donate + +The Pallets organization develops and supports ItsDangerous and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +[please donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD new file mode 100644 index 0000000..245f43e --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD @@ -0,0 +1,22 @@ +itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 +itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 +itsdangerous-2.2.0.dist-info/RECORD,, +itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 +itsdangerous/__pycache__/__init__.cpython-312.pyc,, +itsdangerous/__pycache__/_json.cpython-312.pyc,, +itsdangerous/__pycache__/encoding.cpython-312.pyc,, +itsdangerous/__pycache__/exc.cpython-312.pyc,, +itsdangerous/__pycache__/serializer.cpython-312.pyc,, +itsdangerous/__pycache__/signer.cpython-312.pyc,, +itsdangerous/__pycache__/timed.cpython-312.pyc,, +itsdangerous/__pycache__/url_safe.cpython-312.pyc,, +itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 +itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 +itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 +itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 +itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 +itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 +itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__init__.py b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py new file mode 100644 index 0000000..ea55256 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import typing as t + +from .encoding import base64_decode as base64_decode +from .encoding import base64_encode as base64_encode +from .encoding import want_bytes as want_bytes +from .exc import BadData as BadData +from .exc import BadHeader as BadHeader +from .exc import BadPayload as BadPayload +from .exc import BadSignature as BadSignature +from .exc import BadTimeSignature as BadTimeSignature +from .exc import SignatureExpired as SignatureExpired +from .serializer import Serializer as Serializer +from .signer import HMACAlgorithm as HMACAlgorithm +from .signer import NoneAlgorithm as NoneAlgorithm +from .signer import Signer as Signer +from .timed import TimedSerializer as TimedSerializer +from .timed import TimestampSigner as TimestampSigner +from .url_safe import URLSafeSerializer as URLSafeSerializer +from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " ItsDangerous 2.3. Use feature detection or" + " 'importlib.metadata.version(\"itsdangerous\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("itsdangerous") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c0e7b055f8bf05a485ead3aff591ac2dc21d7eeb GIT binary patch literal 1637 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6502216f98515df2b50dd942b157cce435b23773 GIT binary patch literal 3951 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 I8QS;%0K`vdBme*a literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..562c2ce4866c9860b8302c42f35e7489319be74e GIT binary patch literal 3541 zcmbtWU2Ggz6~41Gv;RN-$*%1r#Up1QDCbu9`D?>C!XC| z?#$NlYE1(Q>P86EJfNhaNEYHDRX_?74?Ll!5)X(zBsCJ&kVru-4}IIzu87hHIOoo; z*D<9CxL)5m_ndRj+&Slb=bk?%5>W!{t_DJX_)D3)3d7J?v?4b=*j!-cS*gFr_L5kZHnXgOAh2|8@W%ZWll&=H`M zg`}XPR;t`n=#fZ(oFqo6MD@>aJ;5oT(2apBdLq*yXBTbf24kehQQlv%15M9M%k0v<D)pjSW=5A)^iS^3?So3|--Pw6 z;CMy~l0gcA(-44y%#?y^1X$3JkAd7!4D}5uLbm@I;U+0bM(|>?5Hccy4qc2FfO}pl zM5akL>Sa!U<7?A;iFJ>0$~hHjV8Pu%MMbn+9I^}GxX6c+dn;%3?7lf8Yb=PI( zs!Ls))-7{3N?{bid7L>8b>|s%Ty9q8P+ry-818fCZSFEo%@VD!BIxOSDMz2}7_=N) zSn+*MeHU*v<=C*&T{KnHE7XB6u$Jg7qg6{U`sdaud|FPJsi(IG<0UxKS+CDvCB0_3 zTKA(c)Y0y;7-$CtvqFXc6d}_39$5WE0x(F+YC}4QvTef%TyJxEs38Fu$WF2>8OpL6 zA#OW?328_jt>s`tJ&6$uIA`2lQ+p=sJV(seObuh_!5KieuzS4Om z593-v+g`M5+*6%em2oeQK-W5!BA((ftK@~+3=W9`n{__tc)^85eDaK7opbDpCowOg zX+=wS98GgD=m;7d7ao@Kry&8Id~w#zPcmo0wX69PC%=9$@0jJP#l{xdtX{2-m0#|?m@^E;RxTp+C^$?R%I@5TE592>qJ8@_7%DK@&68NRAtoqcVgd2(%NxcOX5 z2}aU)`svERYJavlc|S?wnN}c}7`ijC>&h#aUs-Wi2M)ZZY$Qof`qJX<)ac6Ot*9a(}WFBs$~1@kSrn zF${`eJww-aoLL*)3yK4Mpg1@LioHXqm>7EKCgHZ_ev9SXw&fR-x_WjSET@RnG|@D__|L*}ZXG}Jl> zp-ibz?$xPhd?@l>U}l3HBkRSDTDjUuWS&M=xPv55wpfK@$;gH{-oBn}&z|GMNF_{1 z>*z7Vi*BJqKE4e;0*Vf97r9L@a0)cv1Jl3FysfACJSaNfh6yt7PHKmrD<@V{`Cp~oK?B%m7hgZ}4n$h=T$!7hBUw)&wviGOvwZ~pBzZ*NS)<4{wT-!~Xr{3=y zSy5K|9&d*J8XH{8?7VvBa;16lUMkZ}uEQJPGUPkq;i5b8`iXnUS^u+MK!H#8#N2*xTbxl zrdw@ENYf0vsA(LNh9_b2Qku4`;pJ6NALA!S}HsNIXwU|q{1ZqSPNya zr+=^&Ln=<9sgDvs{rzbvsSeyHF!5~XZI5&@?K@Cf?*VbQhrtd88Zg=G{g>)ff9s6R z7aVGt&?tH7n_;` zeE4kyk4OVo3)ke=wG9H~2A32md}}awBl_DzzfNrsSZyScHGJrX_SW?6r=I-?dBP9> E1Wfy%jQ{`u literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/_json.py b/venv/lib/python3.12/site-packages/itsdangerous/_json.py new file mode 100644 index 0000000..fc23fea --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/_json.py @@ -0,0 +1,18 @@ +from __future__ import annotations + +import json as _json +import typing as t + + +class _CompactJSON: + """Wrapper around json module that strips whitespace.""" + + @staticmethod + def loads(payload: str | bytes) -> t.Any: + return _json.loads(payload) + + @staticmethod + def dumps(obj: t.Any, **kwargs: t.Any) -> str: + kwargs.setdefault("ensure_ascii", False) + kwargs.setdefault("separators", (",", ":")) + return _json.dumps(obj, **kwargs) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/encoding.py b/venv/lib/python3.12/site-packages/itsdangerous/encoding.py new file mode 100644 index 0000000..f5ca80f --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/encoding.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import base64 +import string +import struct +import typing as t + +from .exc import BadData + + +def want_bytes( + s: str | bytes, encoding: str = "utf-8", errors: str = "strict" +) -> bytes: + if isinstance(s, str): + s = s.encode(encoding, errors) + + return s + + +def base64_encode(string: str | bytes) -> bytes: + """Base64 encode a string of bytes or text. The resulting bytes are + safe to use in URLs. + """ + string = want_bytes(string) + return base64.urlsafe_b64encode(string).rstrip(b"=") + + +def base64_decode(string: str | bytes) -> bytes: + """Base64 decode a URL-safe string of bytes or text. The result is + bytes. + """ + string = want_bytes(string, encoding="ascii", errors="ignore") + string += b"=" * (-len(string) % 4) + + try: + return base64.urlsafe_b64decode(string) + except (TypeError, ValueError) as e: + raise BadData("Invalid base64-encoded data") from e + + +# The alphabet used by base64.urlsafe_* +_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") + +_int64_struct = struct.Struct(">Q") +_int_to_bytes = _int64_struct.pack +_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) + + +def int_to_bytes(num: int) -> bytes: + return _int_to_bytes(num).lstrip(b"\x00") + + +def bytes_to_int(bytestr: bytes) -> int: + return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/venv/lib/python3.12/site-packages/itsdangerous/exc.py b/venv/lib/python3.12/site-packages/itsdangerous/exc.py new file mode 100644 index 0000000..a75adcd --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/exc.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import typing as t +from datetime import datetime + + +class BadData(Exception): + """Raised if bad data of any sort was encountered. This is the base + for all exceptions that ItsDangerous defines. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + def __str__(self) -> str: + return self.message + + +class BadSignature(BadData): + """Raised if a signature does not match.""" + + def __init__(self, message: str, payload: t.Any | None = None): + super().__init__(message) + + #: The payload that failed the signature test. In some + #: situations you might still want to inspect this, even if + #: you know it was tampered with. + #: + #: .. versionadded:: 0.14 + self.payload: t.Any | None = payload + + +class BadTimeSignature(BadSignature): + """Raised if a time-based signature is invalid. This is a subclass + of :class:`BadSignature`. + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + date_signed: datetime | None = None, + ): + super().__init__(message, payload) + + #: If the signature expired this exposes the date of when the + #: signature was created. This can be helpful in order to + #: tell the user how long a link has been gone stale. + #: + #: .. versionchanged:: 2.0 + #: The datetime value is timezone-aware rather than naive. + #: + #: .. versionadded:: 0.14 + self.date_signed = date_signed + + +class SignatureExpired(BadTimeSignature): + """Raised if a signature timestamp is older than ``max_age``. This + is a subclass of :exc:`BadTimeSignature`. + """ + + +class BadHeader(BadSignature): + """Raised if a signed header is invalid in some form. This only + happens for serializers that have a header that goes with the + signature. + + .. versionadded:: 0.24 + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + header: t.Any | None = None, + original_error: Exception | None = None, + ): + super().__init__(message, payload) + + #: If the header is actually available but just malformed it + #: might be stored here. + self.header: t.Any | None = header + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error + + +class BadPayload(BadData): + """Raised if a payload is invalid. This could happen if the payload + is loaded despite an invalid signature, or if there is a mismatch + between the serializer and deserializer. The original exception + that occurred during loading is stored on as :attr:`original_error`. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str, original_error: Exception | None = None): + super().__init__(message) + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error diff --git a/venv/lib/python3.12/site-packages/itsdangerous/py.typed b/venv/lib/python3.12/site-packages/itsdangerous/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/serializer.py b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py new file mode 100644 index 0000000..5ddf387 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py @@ -0,0 +1,406 @@ +from __future__ import annotations + +import collections.abc as cabc +import json +import typing as t + +from .encoding import want_bytes +from .exc import BadPayload +from .exc import BadSignature +from .signer import _make_keys_list +from .signer import Signer + +if t.TYPE_CHECKING: + import typing_extensions as te + + # This should be either be str or bytes. To avoid having to specify the + # bound type, it falls back to a union if structural matching fails. + _TSerialized = te.TypeVar( + "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes] + ) +else: + # Still available at runtime on Python < 3.13, but without the default. + _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes]) + + +class _PDataSerializer(t.Protocol[_TSerialized]): + def loads(self, payload: _TSerialized, /) -> t.Any: ... + # A signature with additional arguments is not handled correctly by type + # checkers right now, so an overload is used below for serializers that + # don't match this strict protocol. + def dumps(self, obj: t.Any, /) -> _TSerialized: ... + + +# Use TypeIs once it's available in typing_extensions or 3.13. +def is_text_serializer( + serializer: _PDataSerializer[t.Any], +) -> te.TypeGuard[_PDataSerializer[str]]: + """Checks whether a serializer generates text or binary.""" + return isinstance(serializer.dumps({}), str) + + +class Serializer(t.Generic[_TSerialized]): + """A serializer wraps a :class:`~itsdangerous.signer.Signer` to + enable serializing and securely signing data other than bytes. It + can unsign to verify that the data hasn't been changed. + + The serializer provides :meth:`dumps` and :meth:`loads`, similar to + :mod:`json`, and by default uses :mod:`json` internally to serialize + the data to bytes. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param serializer: An object that provides ``dumps`` and ``loads`` + methods for serializing data to a string. Defaults to + :attr:`default_serializer`, which defaults to :mod:`json`. + :param serializer_kwargs: Keyword arguments to pass when calling + ``serializer.dumps``. + :param signer: A ``Signer`` class to instantiate when signing data. + Defaults to :attr:`default_signer`, which defaults to + :class:`~itsdangerous.signer.Signer`. + :param signer_kwargs: Keyword arguments to pass when instantiating + the ``Signer`` class. + :param fallback_signers: List of signer parameters to try when + unsigning with the default signer fails. Each item can be a dict + of ``signer_kwargs``, a ``Signer`` class, or a tuple of + ``(signer, signer_kwargs)``. Defaults to + :attr:`default_fallback_signers`. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 2.0 + Removed the default SHA-512 fallback signer from + ``default_fallback_signers``. + + .. versionchanged:: 1.1 + Added support for ``fallback_signers`` and configured a default + SHA-512 fallback. This fallback is for users who used the yanked + 1.0.0 release which defaulted to SHA-512. + + .. versionchanged:: 0.14 + The ``signer`` and ``signer_kwargs`` parameters were added to + the constructor. + """ + + #: The default serialization module to use to serialize data to a + #: string internally. The default is :mod:`json`, but can be changed + #: to any object that provides ``dumps`` and ``loads`` methods. + default_serializer: _PDataSerializer[t.Any] = json + + #: The default ``Signer`` class to instantiate when signing data. + #: The default is :class:`itsdangerous.signer.Signer`. + default_signer: type[Signer] = Signer + + #: The default fallback signers to try when unsigning fails. + default_fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = [] + + # Serializer[str] if no data serializer is provided, or if it returns str. + @t.overload + def __init__( + self: Serializer[str], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: None | _PDataSerializer[str] = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer positional argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer keyword argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a positional argument. If the strict signature of + # _PDataSerializer doesn't match, fall back to a union, requiring the user + # to specify the type. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a keyword argument. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: t.Any | None = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + + if salt is not None: + salt = want_bytes(salt) + # if salt is None then the signer's default is used + + self.salt = salt + + if serializer is None: + serializer = self.default_serializer + + self.serializer: _PDataSerializer[_TSerialized] = serializer + self.is_text_serializer: bool = is_text_serializer(serializer) + + if signer is None: + signer = self.default_signer + + self.signer: type[Signer] = signer + self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {} + + if fallback_signers is None: + fallback_signers = list(self.default_fallback_signers) + + self.fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = fallback_signers + self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {} + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def load_payload( + self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None + ) -> t.Any: + """Loads the encoded object. This function raises + :class:`.BadPayload` if the payload is not valid. The + ``serializer`` parameter can be used to override the serializer + stored on the class. The encoded ``payload`` should always be + bytes. + """ + if serializer is None: + use_serializer = self.serializer + is_text = self.is_text_serializer + else: + use_serializer = serializer + is_text = is_text_serializer(serializer) + + try: + if is_text: + return use_serializer.loads(payload.decode("utf-8")) # type: ignore[arg-type] + + return use_serializer.loads(payload) # type: ignore[arg-type] + except Exception as e: + raise BadPayload( + "Could not load the payload because an exception" + " occurred on unserializing the data.", + original_error=e, + ) from e + + def dump_payload(self, obj: t.Any) -> bytes: + """Dumps the encoded object. The return value is always bytes. + If the internal serializer returns text, the value will be + encoded as UTF-8. + """ + return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) + + def make_signer(self, salt: str | bytes | None = None) -> Signer: + """Creates a new instance of the signer to be used. The default + implementation uses the :class:`.Signer` base class. + """ + if salt is None: + salt = self.salt + + return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) + + def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]: + """Iterates over all signers to be tried for unsigning. Starts + with the configured signer, then constructs each signer + specified in ``fallback_signers``. + """ + if salt is None: + salt = self.salt + + yield self.make_signer(salt) + + for fallback in self.fallback_signers: + if isinstance(fallback, dict): + kwargs = fallback + fallback = self.signer + elif isinstance(fallback, tuple): + fallback, kwargs = fallback + else: + kwargs = self.signer_kwargs + + for secret_key in self.secret_keys: + yield fallback(secret_key, salt=salt, **kwargs) + + def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized: + """Returns a signed string serialized with the internal + serializer. The return value can be either a byte or unicode + string depending on the format of the internal serializer. + """ + payload = want_bytes(self.dump_payload(obj)) + rv = self.make_signer(salt).sign(payload) + + if self.is_text_serializer: + return rv.decode("utf-8") # type: ignore[return-value] + + return rv # type: ignore[return-value] + + def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None: + """Like :meth:`dumps` but dumps into a file. The file handle has + to be compatible with what the internal serializer expects. + """ + f.write(self.dumps(obj, salt)) + + def loads( + self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any + ) -> t.Any: + """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the + signature validation fails. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + return self.load_payload(signer.unsign(s)) + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any: + """Like :meth:`loads` but loads from a file.""" + return self.loads(f.read(), salt) + + def loads_unsafe( + self, s: str | bytes, salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads` but without verifying the signature. This + is potentially very dangerous to use depending on how your + serializer works. The return value is ``(signature_valid, + payload)`` instead of just the payload. The first item will be a + boolean that indicates if the signature is valid. This function + never fails. + + Use it for debugging only and if you know that your serializer + module is not exploitable (for example, do not use it with a + pickle serializer). + + .. versionadded:: 0.15 + """ + return self._loads_unsafe_impl(s, salt) + + def _loads_unsafe_impl( + self, + s: str | bytes, + salt: str | bytes | None, + load_kwargs: dict[str, t.Any] | None = None, + load_payload_kwargs: dict[str, t.Any] | None = None, + ) -> tuple[bool, t.Any]: + """Low level helper function to implement :meth:`loads_unsafe` + in serializer subclasses. + """ + if load_kwargs is None: + load_kwargs = {} + + try: + return True, self.loads(s, salt=salt, **load_kwargs) + except BadSignature as e: + if e.payload is None: + return False, None + + if load_payload_kwargs is None: + load_payload_kwargs = {} + + try: + return ( + False, + self.load_payload(e.payload, **load_payload_kwargs), + ) + except BadPayload: + return False, None + + def load_unsafe( + self, f: t.IO[t.Any], salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads_unsafe` but loads from a file. + + .. versionadded:: 0.15 + """ + return self.loads_unsafe(f.read(), salt=salt) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/signer.py b/venv/lib/python3.12/site-packages/itsdangerous/signer.py new file mode 100644 index 0000000..e324dc0 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/signer.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +import collections.abc as cabc +import hashlib +import hmac +import typing as t + +from .encoding import _base64_alphabet +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import want_bytes +from .exc import BadSignature + + +class SigningAlgorithm: + """Subclasses must implement :meth:`get_signature` to provide + signature generation functionality. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + """Returns the signature for the given key and value.""" + raise NotImplementedError() + + def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: + """Verifies the given signature matches the expected + signature. + """ + return hmac.compare_digest(sig, self.get_signature(key, value)) + + +class NoneAlgorithm(SigningAlgorithm): + """Provides an algorithm that does not perform any signing and + returns an empty signature. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + return b"" + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class HMACAlgorithm(SigningAlgorithm): + """Provides signature generation using HMACs.""" + + #: The digest method to use with the MAC algorithm. This defaults to + #: SHA1, but can be changed to any other function in the hashlib + #: module. + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + def __init__(self, digest_method: t.Any = None): + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + def get_signature(self, key: bytes, value: bytes) -> bytes: + mac = hmac.new(key, msg=value, digestmod=self.digest_method) + return mac.digest() + + +def _make_keys_list( + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], +) -> list[bytes]: + if isinstance(secret_key, (str, bytes)): + return [want_bytes(secret_key)] + + return [want_bytes(s) for s in secret_key] # pyright: ignore + + +class Signer: + """A signer securely signs bytes, then unsigns them to verify that + the value hasn't been changed. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param sep: Separator between the signature and value. + :param key_derivation: How to derive the signing key from the secret + key and salt. Possible values are ``concat``, ``django-concat``, + or ``hmac``. Defaults to :attr:`default_key_derivation`, which + defaults to ``django-concat``. + :param digest_method: Hash function to use when generating the HMAC + signature. Defaults to :attr:`default_digest_method`, which + defaults to :func:`hashlib.sha1`. Note that the security of the + hash alone doesn't apply when used intermediately in HMAC. + :param algorithm: A :class:`SigningAlgorithm` instance to use + instead of building a default :class:`HMACAlgorithm` with the + ``digest_method``. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 0.18 + ``algorithm`` was added as an argument to the class constructor. + + .. versionchanged:: 0.14 + ``key_derivation`` and ``digest_method`` were added as arguments + to the class constructor. + """ + + #: The default digest method to use for the signer. The default is + #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or + #: compatible object. Note that the security of the hash alone + #: doesn't apply when used intermediately in HMAC. + #: + #: .. versionadded:: 0.14 + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + #: The default scheme to use to derive the signing key from the + #: secret key and salt. The default is ``django-concat``. Possible + #: values are ``concat``, ``django-concat``, and ``hmac``. + #: + #: .. versionadded:: 0.14 + default_key_derivation: str = "django-concat" + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous.Signer", + sep: str | bytes = b".", + key_derivation: str | None = None, + digest_method: t.Any | None = None, + algorithm: SigningAlgorithm | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + self.sep: bytes = want_bytes(sep) + + if self.sep in _base64_alphabet: + raise ValueError( + "The given separator cannot be used because it may be" + " contained in the signature itself. ASCII letters," + " digits, and '-_=' must not be used." + ) + + if salt is not None: + salt = want_bytes(salt) + else: + salt = b"itsdangerous.Signer" + + self.salt = salt + + if key_derivation is None: + key_derivation = self.default_key_derivation + + self.key_derivation: str = key_derivation + + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + if algorithm is None: + algorithm = HMACAlgorithm(self.digest_method) + + self.algorithm: SigningAlgorithm = algorithm + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def derive_key(self, secret_key: str | bytes | None = None) -> bytes: + """This method is called to derive the key. The default key + derivation choices can be overridden here. Key derivation is not + intended to be used as a security method to make a complex key + out of a short password. Instead you should use large random + secret keys. + + :param secret_key: A specific secret key to derive from. + Defaults to the last item in :attr:`secret_keys`. + + .. versionchanged:: 2.0 + Added the ``secret_key`` parameter. + """ + if secret_key is None: + secret_key = self.secret_keys[-1] + else: + secret_key = want_bytes(secret_key) + + if self.key_derivation == "concat": + return t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) + elif self.key_derivation == "django-concat": + return t.cast( + bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() + ) + elif self.key_derivation == "hmac": + mac = hmac.new(secret_key, digestmod=self.digest_method) + mac.update(self.salt) + return mac.digest() + elif self.key_derivation == "none": + return secret_key + else: + raise TypeError("Unknown key derivation method") + + def get_signature(self, value: str | bytes) -> bytes: + """Returns the signature for the given value.""" + value = want_bytes(value) + key = self.derive_key() + sig = self.algorithm.get_signature(key, value) + return base64_encode(sig) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string.""" + value = want_bytes(value) + return value + self.sep + self.get_signature(value) + + def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool: + """Verifies the signature for the given value.""" + try: + sig = base64_decode(sig) + except Exception: + return False + + value = want_bytes(value) + + for secret_key in reversed(self.secret_keys): + key = self.derive_key(secret_key) + + if self.algorithm.verify_signature(key, value, sig): + return True + + return False + + def unsign(self, signed_value: str | bytes) -> bytes: + """Unsigns the given string.""" + signed_value = want_bytes(signed_value) + + if self.sep not in signed_value: + raise BadSignature(f"No {self.sep!r} found in value") + + value, sig = signed_value.rsplit(self.sep, 1) + + if self.verify_signature(value, sig): + return value + + raise BadSignature(f"Signature {sig!r} does not match", payload=value) + + def validate(self, signed_value: str | bytes) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid. + """ + try: + self.unsign(signed_value) + return True + except BadSignature: + return False diff --git a/venv/lib/python3.12/site-packages/itsdangerous/timed.py b/venv/lib/python3.12/site-packages/itsdangerous/timed.py new file mode 100644 index 0000000..7384375 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/timed.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +import collections.abc as cabc +import time +import typing as t +from datetime import datetime +from datetime import timezone + +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import bytes_to_int +from .encoding import int_to_bytes +from .encoding import want_bytes +from .exc import BadSignature +from .exc import BadTimeSignature +from .exc import SignatureExpired +from .serializer import _TSerialized +from .serializer import Serializer +from .signer import Signer + + +class TimestampSigner(Signer): + """Works like the regular :class:`.Signer` but also records the time + of the signing and can be used to expire signatures. The + :meth:`unsign` method can raise :exc:`.SignatureExpired` if the + unsigning failed because the signature is expired. + """ + + def get_timestamp(self) -> int: + """Returns the current timestamp. The function must return an + integer. + """ + return int(time.time()) + + def timestamp_to_datetime(self, ts: int) -> datetime: + """Convert the timestamp from :meth:`get_timestamp` into an + aware :class`datetime.datetime` in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + return datetime.fromtimestamp(ts, tz=timezone.utc) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string and also attaches time information.""" + value = want_bytes(value) + timestamp = base64_encode(int_to_bytes(self.get_timestamp())) + sep = want_bytes(self.sep) + value = value + sep + timestamp + return value + sep + self.get_signature(value) + + # Ignore overlapping signatures check, return_timestamp is the only + # parameter that affects the return type. + + @t.overload + def unsign( # type: ignore[overload-overlap] + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[False] = False, + ) -> bytes: ... + + @t.overload + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[True] = True, + ) -> tuple[bytes, datetime]: ... + + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + ) -> tuple[bytes, datetime] | bytes: + """Works like the regular :meth:`.Signer.unsign` but can also + validate the time. See the base docstring of the class for + the general behavior. If ``return_timestamp`` is ``True`` the + timestamp of the signature will be returned as an aware + :class:`datetime.datetime` object in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + try: + result = super().unsign(signed_value) + sig_error = None + except BadSignature as e: + sig_error = e + result = e.payload or b"" + + sep = want_bytes(self.sep) + + # If there is no timestamp in the result there is something + # seriously wrong. In case there was a signature error, we raise + # that one directly, otherwise we have a weird situation in + # which we shouldn't have come except someone uses a time-based + # serializer on non-timestamp data, so catch that. + if sep not in result: + if sig_error: + raise sig_error + + raise BadTimeSignature("timestamp missing", payload=result) + + value, ts_bytes = result.rsplit(sep, 1) + ts_int: int | None = None + ts_dt: datetime | None = None + + try: + ts_int = bytes_to_int(base64_decode(ts_bytes)) + except Exception: + pass + + # Signature is *not* okay. Raise a proper error now that we have + # split the value and the timestamp. + if sig_error is not None: + if ts_int is not None: + try: + ts_dt = self.timestamp_to_datetime(ts_int) + except (ValueError, OSError, OverflowError) as exc: + # Windows raises OSError + # 32-bit raises OverflowError + raise BadTimeSignature( + "Malformed timestamp", payload=value + ) from exc + + raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) + + # Signature was okay but the timestamp is actually not there or + # malformed. Should not happen, but we handle it anyway. + if ts_int is None: + raise BadTimeSignature("Malformed timestamp", payload=value) + + # Check timestamp is not older than max_age + if max_age is not None: + age = self.get_timestamp() - ts_int + + if age > max_age: + raise SignatureExpired( + f"Signature age {age} > {max_age} seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if age < 0: + raise SignatureExpired( + f"Signature age {age} < 0 seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if return_timestamp: + return value, self.timestamp_to_datetime(ts_int) + + return value + + def validate(self, signed_value: str | bytes, max_age: int | None = None) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid.""" + try: + self.unsign(signed_value, max_age=max_age) + return True + except BadSignature: + return False + + +class TimedSerializer(Serializer[_TSerialized]): + """Uses :class:`TimestampSigner` instead of the default + :class:`.Signer`. + """ + + default_signer: type[TimestampSigner] = TimestampSigner + + def iter_unsigners( + self, salt: str | bytes | None = None + ) -> cabc.Iterator[TimestampSigner]: + return t.cast("cabc.Iterator[TimestampSigner]", super().iter_unsigners(salt)) + + # TODO: Signature is incompatible because parameters were added + # before salt. + + def loads( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + salt: str | bytes | None = None, + ) -> t.Any: + """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the + signature validation fails. If a ``max_age`` is provided it will + ensure the signature is not older than that time in seconds. In + case the signature is outdated, :exc:`.SignatureExpired` is + raised. All arguments are forwarded to the signer's + :meth:`~TimestampSigner.unsign` method. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + base64d, timestamp = signer.unsign( + s, max_age=max_age, return_timestamp=True + ) + payload = self.load_payload(base64d) + + if return_timestamp: + return payload, timestamp + + return payload + except SignatureExpired: + # The signature was unsigned successfully but was + # expired. Do not try the next signer. + raise + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def loads_unsafe( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + salt: str | bytes | None = None, + ) -> tuple[bool, t.Any]: + return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py new file mode 100644 index 0000000..56a0793 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import typing as t +import zlib + +from ._json import _CompactJSON +from .encoding import base64_decode +from .encoding import base64_encode +from .exc import BadPayload +from .serializer import _PDataSerializer +from .serializer import Serializer +from .timed import TimedSerializer + + +class URLSafeSerializerMixin(Serializer[str]): + """Mixed in with a regular serializer it will attempt to zlib + compress the string to make it shorter if necessary. It will also + base64 encode the string so that it can safely be placed in a URL. + """ + + default_serializer: _PDataSerializer[str] = _CompactJSON + + def load_payload( + self, + payload: bytes, + *args: t.Any, + serializer: t.Any | None = None, + **kwargs: t.Any, + ) -> t.Any: + decompress = False + + if payload.startswith(b"."): + payload = payload[1:] + decompress = True + + try: + json = base64_decode(payload) + except Exception as e: + raise BadPayload( + "Could not base64 decode the payload because of an exception", + original_error=e, + ) from e + + if decompress: + try: + json = zlib.decompress(json) + except Exception as e: + raise BadPayload( + "Could not zlib decompress the payload before decoding the payload", + original_error=e, + ) from e + + return super().load_payload(json, *args, **kwargs) + + def dump_payload(self, obj: t.Any) -> bytes: + json = super().dump_payload(obj) + is_compressed = False + compressed = zlib.compress(json) + + if len(compressed) < (len(json) - 1): + json = compressed + is_compressed = True + + base64d = base64_encode(json) + + if is_compressed: + base64d = b"." + base64d + + return base64d + + +class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): + """Works like :class:`.Serializer` but dumps and loads into a URL + safe string consisting of the upper and lowercase character of the + alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ + + +class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): + """Works like :class:`.TimedSerializer` but dumps and loads into a + URL safe string consisting of the upper and lowercase character of + the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/LICENSE.txt new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/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-3.1.4.dist-info/METADATA b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA new file mode 100644 index 0000000..265cc32 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/METADATA @@ -0,0 +1,76 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.4 +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 +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 + +.. code-block:: 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 + diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD new file mode 100644 index 0000000..df3acaf --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/RECORD @@ -0,0 +1,57 @@ +jinja2-3.1.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2-3.1.4.dist-info/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +jinja2-3.1.4.dist-info/METADATA,sha256=R_brzpPQVBvpGcsm-WbrtgotO7suQ1D0F-qkhTzeEfY,2640 +jinja2-3.1.4.dist-info/RECORD,, +jinja2-3.1.4.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +jinja2-3.1.4.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 +jinja2/__init__.py,sha256=wIl45IM20KGw-kfr7jJhaBxxX5g4-kihlBYjxopX7Pw,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=JXKWCAXmTx0iZB4-hAsF50vgjxw_RJTjiLOlGGTBso0,2477 +jinja2/bccache.py,sha256=gh0qs9rulnXo0PhX5jTJy2UHzI8wFnQ63o_vw7nhzRg,14061 +jinja2/compiler.py,sha256=dpV-n6_iQUP4uSwlXwGUavJmwjvXdyxKzJ-AonFjPBk,72271 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=xhFkmxO0CESA76Ki5tz4XWq9yzGu-t0p93JCCVBVNps,61538 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=igsBH7c6C0byHaOtMbE-ugpt4GjLGgR-ywskyXtKgq8,31877 +jinja2/filters.py,sha256=bKeqjFjjz88TkHVLSyyMIEB75CzAN6b3Airgx0phJDg,54611 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=xnWWXhPndHFsoqzpc5VTjheDE9JuKk9MUo9DZkrM8Os,29754 +jinja2/loaders.py,sha256=ru0GIWHo5KiHJi7_MoI_LvGDoBBvP6rd0hiC1ReaTwk,23167 +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=DV1iF1FR2Rsaj_5zl8rmx7j6Bj4S8iLHoYsvJ0bfEis,39890 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=POXT3tKNKJRENx2CymwUsOOXH2JwGPjW702njB5__cQ,33435 +jinja2/sandbox.py,sha256=TJjBNS9qRJ2ZgBMWdAgRBpyDLOHea2kT-2mk4PrjYx0,14616 +jinja2/tests.py,sha256=VLsBhVFnWg-PxSBz1MhRnNWgP1ovXk3neO1FLQMeC9Q,5926 +jinja2/utils.py,sha256=nV7IpWLvRCMyHW1irBAK8CIPAnOFfkb2ukggDBjbBEY,23952 +jinja2/visitor.py,sha256=EcnL1PIwf_4RVCOMxsRNuR8AXHbS1qfAdMOE2ngKJz4,3557 diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/WHEEL new file mode 100644 index 0000000..3b5e64b --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.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/jinja2-3.1.4.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.4.dist-info/entry_points.txt new file mode 100644 index 0000000..abc3eae --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.4.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/__init__.py b/venv/lib/python3.12/site-packages/jinja2/__init__.py new file mode 100644 index 0000000..2f0b5b2 --- /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.4" 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..d84f4a29e65c6cc069d439bd6bd1336ae416140d GIT binary patch literal 1662 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 Z^-eG!`qszazgw7pb3S@+9k2b+e*lG61;GFS literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..673464bf004d9da4f1a7567d9881375438679284 GIT binary patch literal 4087 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5474ae77236cc1745c43f709438472ce8fb3fefe GIT binary patch literal 1615 zcmah}%WoS+7@zeke#DNSc{u4SAq`d=TP+BI)Ka<5CN*`OG;w$=Mcb`sl5VnIFSFwo zZ&gvaaBWU0Ql<9FzrmG@Q7@~3N=OKy-cprQFYwLQOUjAe^~`U6-|w66n{Q_PQ!*Jx z@cj7A-`g)k2>mVw{u3L5mp3GY4$v0D2ulW1Bpkp&BhU#dAqfEv8R1Su8S!w~h<0L1 z%)=4DaV75I5x@y0;o&IYQDsy@MA|L-!H#+w^5UeFF&tCUIId)HLdoJ$C5Mwr9;cK7 zmXvYuEg$*#h)hlaBvW|o0`#CO{*Ny0=`zYR&L}fDs~p2Q@Xim}cpOh)3EoNgP2q7}!WmqA6jf#+(z2h&QBNj;zj8G8(RN^%>9mN|mr66wg{k=* zYK=+~A6c$9TJpvwz;H|6YzYvl_1gxafbu)UBvfNWHM*2^RNbGHL0seWh3n?R*^>*`soyVr!P8Colh;$q*S6$lO)f=vm}=$@;UTQI8IKrV zo;=d_*1;pYUbZ}D`nk4v)a-UGvAE}9CrQ)0Px7MiF>hfl3o<~^U(#;(% zF+Q@b8&EBq!o@;-%oh(gmWLU!nN7WACViu~)jZr|x?$4@_|Xy3L`5U+BTu$ITbI?^ z6}fh`-dy3C*WpyijhHrMZu0;mJbSsZR=XUZX9^!zH|o{P4et;f z33LC_Z)o%Wf%wmyS)V;pQt^kvqidF^qh|0R>=GYSRn0WJOcSK7sx%=)2}o>J_0rnp z$%e>teK@2^At+px<#n~SQLV$dT2Y7Ri>AOv$Alo`*R5Gyl{eR`HJMHbKC~pxTd->O ze?TvRK(B68wrtpoO8X|OED?K;b*)Nm<=Xj*t#>SgEZ!kEHOpGuHZ*&$a+{d9D~5iv zV)faruK7;+oX|0{2={4E+aY#kS2uUH^A$|CwVuK3vekbTz0m36ot22*Fj`$Z=9HptQsP92=yKm9QGPao!e 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..c93d2293a770b1b090ae137e297aebe9c5833dd3 GIT binary patch literal 76711 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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..02c3b7979255c570991845acd672932f7a7775ef GIT binary patch literal 7724 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 RDR;v)XUgh*)5Lh?{|_sB_Tm5l literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8a792a4d9251c0220d3586f5d3b0ec91c5fda9bc GIT binary patch literal 72029 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

KKYPhWb)9(>@7Cn$u&1r=*^Nk>`AZh zwfez&HOs^lbeq|Pb2P&pDmMLubFpC@8Zh$+=WB*P>@x#|3mB%zEF@gSbk3R! z2rtwOh*Q>^i|8m;h)W2UD!7brxn|^tx0)4%D-{t{gcl34WHsR$D0m~`7DdA* z!kZPmh45AdZzGI7NGZ`)oi1#*NO|oL7tS;2nragl4mPA7c8O~@T)xm=vqM~XUrFj> zkGS^2#ah}YE-W@A-hOf6bWjT5pt!IBhPF$bVwY<`} Se^ESV!PKYebIm2EBL4##N+ku{V}nI@GP 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�S*p^D1`u>6=a|Po3^;Bc zm_9HQpoHe6eG4*+(YU+&ivyn@co0nPrc`6z`P5Q|RAb(muHs%ihGb<6`jj|tc1|P6 zPxZETN+rKvn`}GC8d!ha_-ogzCf@ywqw EAA~HBVgLXD literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7687f4fd6c9bc08b2ccdec717e34b5a247e4cc44 GIT binary patch literal 32046 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 U+lJJBwbBq`##f+Qm=s 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f0463ed16c1c9fec5e7502d901932ffb5e0236d4 GIT binary patch literal 2698 zcmaJ@Uu+!38K2qP+xzFUo%oEMgu+NMn4`&E5(sKB3QdAZlgcht+=pD%uGYJA_MZ24 zj+s55ZH_9fBH=s~VhLm-A(A2_g3_vaBu`O!_8-wbOSvDnt!I>2hHy~n`HQ~!?N~)F!q-aLyyyZ2m zfR?h^6V$evg2p0QdOO;rcVg^{b56tpIFLCV=j&&FT%;1KG2d zGP>%5ZOQ=F3=WVMCAQ^Dp$^-W*Y#Bi62OveftMxnD&yd#Rd0Co0Pz@WkfzU>=SkJl zHh(lAEym}-p~&#)nmUSEWLwJHS!wnJ)syLA1m-_MbOBDoWY!WB@0>gTSF84wF7}r~smG5{M~o`9h*ZIUME2 z{dt!&zYcbUx?~Jj4dOaLwe;3$OtrOIE~dBEHj1TR?^<&fTwMB%#7-s!T?ojm3z$MoWm-Y@078s3 zD3?A%QV_`4z_sIaRw2$37}J*Ig~XA7#t*V8gQKtQjiGHP^3MN6MReN{z)Zy}8>BO66-H z4#0FC-80axz3>0a#1)zVBXPm)SMv_7l(D&OQI7{`>~; zBU?`Kh{Ln73@2|vxGAb&c(ybrxwLyT?xpzbao`Zr+4E?9-_y(b*XdzC09zINP`CJu2#vXxTpzMa zrh6a!HV#37yoa|J%|*S9{s8IJ#xuCBeT4sPxTu}@7{86*#6c3iQKOCjf62rp!6!0k z8|MyjspVstTWcHFq;-#sw#Jif&B1%%+=rOQ-J{Z4p=JJ`Za-$tBl^^_O=<(GzR^GTXba-v( z@Ooi*bz)`W)2XW?S6}~V^hR*I@Y4FeC$EfM9$P0PcgUeNa;TF+!$&rdKD@hw^j*6< z{iwgNoV$N7g$jG_4D4SU*#A$2^MmXCg}Z$N%ehVpHV=dh;*I0ExDh5XI9R15|SQ$=9A_hn-Tq^AKyyeOe*?rruUt_7x(@<2|V8;n4&6{LW}t@WttAN z!E7T~l>aRv3nP=mlu9zjxr}?5pE~#2xOwuY<0pT1dh(RQNHxyLGl`{osXj%K0{Ox` zNWT=}a*Q8>t#nLGz|=`#jK9~?Sl=ihJn#=R@GTm-o6z5S`S&k>t3T5*bbR#E(bX4M jUW9Psqt_U_2XWz2-@gznO5J|}n1YGU 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..44b6d5ed70ab9e0dd06e73dcf8e35c26f7c2fb15 GIT binary patch literal 60820 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b90a9ac4e07e18a043d90c2f04d260b4f4d452f1 GIT binary patch literal 48501 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 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 0000000..928c150 --- /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 0000000..e65219e --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/async_utils.py @@ -0,0 +1,84 @@ +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 + +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 t.cast("V", value) + + +async def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + async for item in t.cast("t.AsyncIterable[V]", iterable): + yield item + else: + for item in iterable: + yield item + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/venv/lib/python3.12/site-packages/jinja2/bccache.py b/venv/lib/python3.12/site-packages/jinja2/bccache.py new file mode 100644 index 0000000..ada8b09 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/bccache.py @@ -0,0 +1,408 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" + +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: ... + + def set( + self, key: str, value: bytes, timeout: t.Optional[int] = None + ) -> None: ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib `_ + - `python-memcached `_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/venv/lib/python3.12/site-packages/jinja2/compiler.py b/venv/lib/python3.12/site-packages/jinja2/compiler.py new file mode 100644 index 0000000..2740717 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/compiler.py @@ -0,0 +1,1960 @@ +"""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(t.cast(F, new_func), f) + + +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) -> "Frame": + """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) -> "Frame": + """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(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, 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( + "async for event in parent_template.root_render_func(context):" + ) + self.indent() + self.writeline("yield event") + self.outdent() + 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"{self.choose_async()}for event in" + f" context.blocks[{node.name!r}][0]({context}):", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + + 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() + + skip_event_yield = False + if node.with_context: + self.writeline( + f"{self.choose_async()}for event in template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)})):" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + else: + self.writeline("yield from template._get_default_module()._body_stream") + skip_event_yield = True + + if not skip_event_yield: + self.indent() + self.simple_write("event", frame) + self.outdent() + + 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() + message = ( + "the template {included_template.__name__!r}" + f" (imported on {self.position(node)})" + 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() + 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: + # NSRefs can only be used to store values; since they use the normal + # `foo.bar` notation they will be parsed as a normal attribute access + # when used anywhere but in a `set` context + ref = frame.symbols.ref(node.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.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/venv/lib/python3.12/site-packages/jinja2/constants.py b/venv/lib/python3.12/site-packages/jinja2/constants.py new file mode 100644 index 0000000..41a1c23 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/venv/lib/python3.12/site-packages/jinja2/debug.py b/venv/lib/python3.12/site-packages/jinja2/debug.py new file mode 100644 index 0000000..7ed7e92 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: "t.Optional[Context]" = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/venv/lib/python3.12/site-packages/jinja2/defaults.py b/venv/lib/python3.12/site-packages/jinja2/defaults.py new file mode 100644 index 0000000..638cad3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/venv/lib/python3.12/site-packages/jinja2/environment.py b/venv/lib/python3.12/site-packages/jinja2/environment.py new file mode 100644 index 0000000..1d3be0b --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/environment.py @@ -0,0 +1,1675 @@ +"""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: "Environment") -> "Environment": + """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 = False, + ) -> "Environment": + """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.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( # type: ignore + 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 = "