From 8b50e3197cc5f080a8fd3b6754175e39cb4b904c Mon Sep 17 00:00:00 2001 From: Aufaajie Date: Sat, 28 Jun 2025 05:50:36 +0000 Subject: [PATCH 1/2] Menambahkan validasi login dan komentar --- sequence-login.puml | 17 + __pycache__/app.cpython-312.pyc | Bin 0 -> 728 bytes app.py | 49 +- classes_flask_app.puml | 3 + filelist.txt | 0 out/ sequence-login/sequence-login.png | Bin 0 -> 19713 bytes out/classes_flask_app/classes_flask_app.png | Bin 0 -> 377 bytes .../sequence-create-item.png | Bin 0 -> 14972 bytes sequence-create-item.puml | 13 + templates/create.html | 13 + templates/dashboard.html | 9 + templates/login.html | 12 + templates/logout.html | 8 + templates/success.html | 8 + venv/bin/Activate.ps1 | 247 + venv/bin/activate | 70 + venv/bin/activate.csh | 27 + venv/bin/activate.fish | 69 + venv/bin/flask | 8 + venv/bin/pip | 8 + venv/bin/pip3 | 8 + venv/bin/pip3.12 | 8 + venv/bin/python | 1 + venv/bin/python3 | 1 + venv/bin/python3.12 | 1 + .../MarkupSafe-3.0.2.dist-info/INSTALLER | 1 + .../MarkupSafe-3.0.2.dist-info/LICENSE.txt | 28 + .../MarkupSafe-3.0.2.dist-info/METADATA | 92 + .../MarkupSafe-3.0.2.dist-info/RECORD | 14 + .../MarkupSafe-3.0.2.dist-info/WHEEL | 6 + .../MarkupSafe-3.0.2.dist-info/top_level.txt | 1 + .../blinker-1.9.0.dist-info/INSTALLER | 1 + .../blinker-1.9.0.dist-info/LICENSE.txt | 20 + .../blinker-1.9.0.dist-info/METADATA | 60 + .../blinker-1.9.0.dist-info/RECORD | 12 + .../blinker-1.9.0.dist-info/WHEEL | 4 + .../site-packages/blinker/__init__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 485 bytes .../__pycache__/_utilities.cpython-312.pyc | Bin 0 -> 2712 bytes .../blinker/__pycache__/base.cpython-312.pyc | Bin 0 -> 21986 bytes .../site-packages/blinker/_utilities.py | 64 + .../python3.12/site-packages/blinker/base.py | 512 + .../python3.12/site-packages/blinker/py.typed | 0 .../click-8.2.1.dist-info/INSTALLER | 1 + .../click-8.2.1.dist-info/METADATA | 82 + .../click-8.2.1.dist-info/RECORD | 38 + .../site-packages/click-8.2.1.dist-info/WHEEL | 4 + .../licenses/LICENSE.txt | 28 + .../site-packages/click/__init__.py | 123 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4057 bytes .../click/__pycache__/_compat.cpython-312.pyc | Bin 0 -> 24179 bytes .../__pycache__/_termui_impl.cpython-312.pyc | Bin 0 -> 31515 bytes .../__pycache__/_textwrap.cpython-312.pyc | Bin 0 -> 2410 bytes .../__pycache__/_winconsole.cpython-312.pyc | Bin 0 -> 11752 bytes .../click/__pycache__/core.cpython-312.pyc | Bin 0 -> 127642 bytes .../__pycache__/decorators.cpython-312.pyc | Bin 0 -> 22113 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 14761 bytes .../__pycache__/formatting.cpython-312.pyc | Bin 0 -> 13657 bytes .../click/__pycache__/globals.cpython-312.pyc | Bin 0 -> 2950 bytes .../click/__pycache__/parser.cpython-312.pyc | Bin 0 -> 20187 bytes .../shell_completion.cpython-312.pyc | Bin 0 -> 23154 bytes .../click/__pycache__/termui.cpython-312.pyc | Bin 0 -> 34508 bytes .../click/__pycache__/testing.cpython-312.pyc | Bin 0 -> 26884 bytes .../click/__pycache__/types.cpython-312.pyc | Bin 0 -> 48944 bytes .../click/__pycache__/utils.cpython-312.pyc | Bin 0 -> 24864 bytes .../python3.12/site-packages/click/_compat.py | 622 ++ .../site-packages/click/_termui_impl.py | 839 ++ .../site-packages/click/_textwrap.py | 51 + .../site-packages/click/_winconsole.py | 296 + .../python3.12/site-packages/click/core.py | 3135 ++++++ .../site-packages/click/decorators.py | 551 ++ .../site-packages/click/exceptions.py | 308 + .../site-packages/click/formatting.py | 301 + .../python3.12/site-packages/click/globals.py | 67 + .../python3.12/site-packages/click/parser.py | 532 + .../python3.12/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 644 ++ .../python3.12/site-packages/click/termui.py | 877 ++ .../python3.12/site-packages/click/testing.py | 565 ++ .../python3.12/site-packages/click/types.py | 1165 +++ .../python3.12/site-packages/click/utils.py | 627 ++ .../flask-3.1.1.dist-info/INSTALLER | 1 + .../flask-3.1.1.dist-info/METADATA | 89 + .../flask-3.1.1.dist-info/RECORD | 58 + .../flask-3.1.1.dist-info/REQUESTED | 0 .../site-packages/flask-3.1.1.dist-info/WHEEL | 4 + .../flask-3.1.1.dist-info/entry_points.txt | 3 + .../licenses/LICENSE.txt | 28 + .../site-packages/flask/__init__.py | 61 + .../site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2517 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 225 bytes .../flask/__pycache__/app.cpython-312.pyc | Bin 0 -> 62469 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 4984 bytes .../flask/__pycache__/cli.cpython-312.pyc | Bin 0 -> 43528 bytes .../flask/__pycache__/config.cpython-312.pyc | Bin 0 -> 16236 bytes .../flask/__pycache__/ctx.cpython-312.pyc | Bin 0 -> 19822 bytes .../__pycache__/debughelpers.cpython-312.pyc | Bin 0 -> 9131 bytes .../flask/__pycache__/globals.cpython-312.pyc | Bin 0 -> 1849 bytes .../flask/__pycache__/helpers.cpython-312.pyc | Bin 0 -> 25429 bytes .../flask/__pycache__/logging.cpython-312.pyc | Bin 0 -> 3251 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 17166 bytes .../flask/__pycache__/signals.cpython-312.pyc | Bin 0 -> 1206 bytes .../__pycache__/templating.cpython-312.pyc | Bin 0 -> 9916 bytes .../flask/__pycache__/testing.cpython-312.pyc | Bin 0 -> 13606 bytes .../flask/__pycache__/typing.cpython-312.pyc | Bin 0 -> 4114 bytes .../flask/__pycache__/views.cpython-312.pyc | Bin 0 -> 7002 bytes .../__pycache__/wrappers.cpython-312.pyc | Bin 0 -> 10037 bytes .../lib/python3.12/site-packages/flask/app.py | 1536 +++ .../site-packages/flask/blueprints.py | 128 + .../lib/python3.12/site-packages/flask/cli.py | 1135 +++ .../python3.12/site-packages/flask/config.py | 367 + .../lib/python3.12/site-packages/flask/ctx.py | 449 + .../site-packages/flask/debughelpers.py | 178 + .../python3.12/site-packages/flask/globals.py | 51 + .../python3.12/site-packages/flask/helpers.py | 634 ++ .../site-packages/flask/json/__init__.py | 170 + .../json/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6677 bytes .../json/__pycache__/provider.cpython-312.pyc | Bin 0 -> 9244 bytes .../json/__pycache__/tag.cpython-312.pyc | Bin 0 -> 13939 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 -> 33697 bytes .../__pycache__/blueprints.cpython-312.pyc | Bin 0 -> 31197 bytes .../__pycache__/scaffold.cpython-312.pyc | Bin 0 -> 30207 bytes .../site-packages/flask/sansio/app.py | 964 ++ .../site-packages/flask/sansio/blueprints.py | 632 ++ .../site-packages/flask/sansio/scaffold.py | 792 ++ .../site-packages/flask/sessions.py | 399 + .../python3.12/site-packages/flask/signals.py | 17 + .../site-packages/flask/templating.py | 219 + .../python3.12/site-packages/flask/testing.py | 298 + .../python3.12/site-packages/flask/typing.py | 93 + .../python3.12/site-packages/flask/views.py | 191 + .../site-packages/flask/wrappers.py | 257 + .../itsdangerous-2.2.0.dist-info/INSTALLER | 1 + .../itsdangerous-2.2.0.dist-info/LICENSE.txt | 28 + .../itsdangerous-2.2.0.dist-info/METADATA | 60 + .../itsdangerous-2.2.0.dist-info/RECORD | 22 + .../itsdangerous-2.2.0.dist-info/WHEEL | 4 + .../site-packages/itsdangerous/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1616 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 1170 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2670 bytes .../__pycache__/exc.cpython-312.pyc | Bin 0 -> 3930 bytes .../__pycache__/serializer.cpython-312.pyc | Bin 0 -> 15411 bytes .../__pycache__/signer.cpython-312.pyc | Bin 0 -> 11276 bytes .../__pycache__/timed.cpython-312.pyc | Bin 0 -> 8724 bytes .../__pycache__/url_safe.cpython-312.pyc | Bin 0 -> 3520 bytes .../site-packages/itsdangerous/_json.py | 18 + .../site-packages/itsdangerous/encoding.py | 54 + .../site-packages/itsdangerous/exc.py | 106 + .../site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 406 + .../site-packages/itsdangerous/signer.py | 266 + .../site-packages/itsdangerous/timed.py | 228 + .../site-packages/itsdangerous/url_safe.py | 83 + .../jinja2-3.1.6.dist-info/INSTALLER | 1 + .../jinja2-3.1.6.dist-info/METADATA | 84 + .../jinja2-3.1.6.dist-info/RECORD | 57 + .../jinja2-3.1.6.dist-info/WHEEL | 4 + .../jinja2-3.1.6.dist-info/entry_points.txt | 3 + .../licenses/LICENSE.txt | 28 + .../site-packages/jinja2/__init__.py | 38 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1641 bytes .../__pycache__/_identifier.cpython-312.pyc | Bin 0 -> 2122 bytes .../__pycache__/async_utils.cpython-312.pyc | Bin 0 -> 4962 bytes .../__pycache__/bccache.cpython-312.pyc | Bin 0 -> 19333 bytes .../__pycache__/compiler.cpython-312.pyc | Bin 0 -> 104046 bytes .../__pycache__/constants.cpython-312.pyc | Bin 0 -> 1544 bytes .../jinja2/__pycache__/debug.cpython-312.pyc | Bin 0 -> 6569 bytes .../__pycache__/defaults.cpython-312.pyc | Bin 0 -> 1594 bytes .../__pycache__/environment.cpython-312.pyc | Bin 0 -> 76646 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7708 bytes .../jinja2/__pycache__/ext.cpython-312.pyc | Bin 0 -> 41901 bytes .../__pycache__/filters.cpython-312.pyc | Bin 0 -> 72313 bytes .../__pycache__/idtracking.cpython-312.pyc | Bin 0 -> 19180 bytes .../jinja2/__pycache__/lexer.cpython-312.pyc | Bin 0 -> 32058 bytes .../__pycache__/loaders.cpython-312.pyc | Bin 0 -> 32337 bytes .../jinja2/__pycache__/meta.cpython-312.pyc | Bin 0 -> 5478 bytes .../__pycache__/nativetypes.cpython-312.pyc | Bin 0 -> 6999 bytes .../jinja2/__pycache__/nodes.cpython-312.pyc | Bin 0 -> 58256 bytes .../__pycache__/optimizer.cpython-312.pyc | Bin 0 -> 2677 bytes .../jinja2/__pycache__/parser.cpython-312.pyc | Bin 0 -> 61191 bytes .../__pycache__/runtime.cpython-312.pyc | Bin 0 -> 48879 bytes .../__pycache__/sandbox.cpython-312.pyc | Bin 0 -> 18095 bytes .../jinja2/__pycache__/tests.cpython-312.pyc | Bin 0 -> 9038 bytes .../jinja2/__pycache__/utils.cpython-312.pyc | Bin 0 -> 34851 bytes .../__pycache__/visitor.cpython-312.pyc | Bin 0 -> 5353 bytes .../site-packages/jinja2/_identifier.py | 6 + .../site-packages/jinja2/async_utils.py | 99 + .../site-packages/jinja2/bccache.py | 408 + .../site-packages/jinja2/compiler.py | 1998 ++++ .../site-packages/jinja2/constants.py | 20 + .../python3.12/site-packages/jinja2/debug.py | 191 + .../site-packages/jinja2/defaults.py | 48 + .../site-packages/jinja2/environment.py | 1672 ++++ .../site-packages/jinja2/exceptions.py | 166 + .../python3.12/site-packages/jinja2/ext.py | 870 ++ .../site-packages/jinja2/filters.py | 1873 ++++ .../site-packages/jinja2/idtracking.py | 318 + .../python3.12/site-packages/jinja2/lexer.py | 868 ++ .../site-packages/jinja2/loaders.py | 693 ++ .../python3.12/site-packages/jinja2/meta.py | 112 + .../site-packages/jinja2/nativetypes.py | 130 + .../python3.12/site-packages/jinja2/nodes.py | 1206 +++ .../site-packages/jinja2/optimizer.py | 48 + .../python3.12/site-packages/jinja2/parser.py | 1049 ++ .../python3.12/site-packages/jinja2/py.typed | 0 .../site-packages/jinja2/runtime.py | 1062 ++ .../site-packages/jinja2/sandbox.py | 436 + .../python3.12/site-packages/jinja2/tests.py | 256 + .../python3.12/site-packages/jinja2/utils.py | 766 ++ .../site-packages/jinja2/visitor.py | 92 + .../site-packages/markupsafe/__init__.py | 395 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 20916 bytes .../__pycache__/_native.cpython-312.pyc | Bin 0 -> 603 bytes .../site-packages/markupsafe/_native.py | 8 + .../site-packages/markupsafe/_speedups.c | 204 + .../_speedups.cpython-312-x86_64-linux-gnu.so | Bin 0 -> 43432 bytes .../site-packages/markupsafe/_speedups.pyi | 1 + .../site-packages/markupsafe/py.typed | 0 .../pip-23.2.1.dist-info/AUTHORS.txt | 738 ++ .../pip-23.2.1.dist-info/INSTALLER | 1 + .../pip-23.2.1.dist-info/LICENSE.txt | 20 + .../pip-23.2.1.dist-info/METADATA | 90 + .../site-packages/pip-23.2.1.dist-info/RECORD | 1003 ++ .../pip-23.2.1.dist-info/REQUESTED | 0 .../site-packages/pip-23.2.1.dist-info/WHEEL | 5 + .../pip-23.2.1.dist-info/entry_points.txt | 4 + .../pip-23.2.1.dist-info/top_level.txt | 1 + .../python3.12/site-packages/pip/__init__.py | 13 + .../python3.12/site-packages/pip/__main__.py | 24 + .../site-packages/pip/__pip-runner__.py | 50 + .../pip/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 680 bytes .../pip/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 834 bytes .../__pip-runner__.cpython-312.pyc | Bin 0 -> 2192 bytes .../site-packages/pip/_internal/__init__.py | 19 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 840 bytes .../__pycache__/build_env.cpython-312.pyc | Bin 0 -> 14284 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 12680 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 17392 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33393 bytes .../__pycache__/main.cpython-312.pyc | Bin 0 -> 663 bytes .../__pycache__/pyproject.cpython-312.pyc | Bin 0 -> 4962 bytes .../self_outdated_check.cpython-312.pyc | Bin 0 -> 10089 bytes .../__pycache__/wheel_builder.cpython-312.pyc | Bin 0 -> 13686 bytes .../site-packages/pip/_internal/build_env.py | 311 + .../site-packages/pip/_internal/cache.py | 292 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 271 bytes .../autocompletion.cpython-312.pyc | Bin 0 -> 8445 bytes .../__pycache__/base_command.cpython-312.pyc | Bin 0 -> 10431 bytes .../__pycache__/cmdoptions.cpython-312.pyc | Bin 0 -> 30334 bytes .../command_context.cpython-312.pyc | Bin 0 -> 1768 bytes .../cli/__pycache__/main.cpython-312.pyc | Bin 0 -> 2291 bytes .../__pycache__/main_parser.cpython-312.pyc | Bin 0 -> 4898 bytes .../cli/__pycache__/parser.cpython-312.pyc | Bin 0 -> 15066 bytes .../__pycache__/progress_bars.cpython-312.pyc | Bin 0 -> 2610 bytes .../__pycache__/req_command.cpython-312.pyc | Bin 0 -> 18831 bytes .../cli/__pycache__/spinners.cpython-312.pyc | Bin 0 -> 7827 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 368 bytes .../pip/_internal/cli/autocompletion.py | 171 + .../pip/_internal/cli/base_command.py | 236 + .../pip/_internal/cli/cmdoptions.py | 1074 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 79 + .../pip/_internal/cli/main_parser.py | 134 + .../site-packages/pip/_internal/cli/parser.py | 294 + .../pip/_internal/cli/progress_bars.py | 68 + .../pip/_internal/cli/req_command.py | 508 + .../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 -> 3995 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 9372 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 2083 bytes .../__pycache__/completion.cpython-312.pyc | Bin 0 -> 4880 bytes .../__pycache__/configuration.cpython-312.pyc | Bin 0 -> 13247 bytes .../__pycache__/debug.cpython-312.pyc | Bin 0 -> 10058 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 7579 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 4349 bytes .../commands/__pycache__/hash.cpython-312.pyc | Bin 0 -> 2976 bytes .../commands/__pycache__/help.cpython-312.pyc | Bin 0 -> 1666 bytes .../__pycache__/index.cpython-312.pyc | Bin 0 -> 6765 bytes .../__pycache__/inspect.cpython-312.pyc | Bin 0 -> 3968 bytes .../__pycache__/install.cpython-312.pyc | Bin 0 -> 28959 bytes .../commands/__pycache__/list.cpython-312.pyc | Bin 0 -> 15368 bytes .../__pycache__/search.cpython-312.pyc | Bin 0 -> 7611 bytes .../commands/__pycache__/show.cpython-312.pyc | Bin 0 -> 9721 bytes .../__pycache__/uninstall.cpython-312.pyc | Bin 0 -> 4719 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 8943 bytes .../pip/_internal/commands/cache.py | 222 + .../pip/_internal/commands/check.py | 54 + .../pip/_internal/commands/completion.py | 121 + .../pip/_internal/commands/configuration.py | 282 + .../pip/_internal/commands/debug.py | 199 + .../pip/_internal/commands/download.py | 147 + .../pip/_internal/commands/freeze.py | 108 + .../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 | 778 ++ .../pip/_internal/commands/list.py | 368 + .../pip/_internal/commands/search.py | 174 + .../pip/_internal/commands/show.py | 189 + .../pip/_internal/commands/uninstall.py | 113 + .../pip/_internal/commands/wheel.py | 183 + .../pip/_internal/configuration.py | 381 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 934 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 2173 bytes .../__pycache__/installed.cpython-312.pyc | Bin 0 -> 1433 bytes .../__pycache__/sdist.cpython-312.pyc | Bin 0 -> 8020 bytes .../__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1981 bytes .../pip/_internal/distributions/base.py | 39 + .../pip/_internal/distributions/installed.py | 23 + .../pip/_internal/distributions/sdist.py | 150 + .../pip/_internal/distributions/wheel.py | 34 + .../site-packages/pip/_internal/exceptions.py | 733 ++ .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 225 bytes .../__pycache__/collector.cpython-312.pyc | Bin 0 -> 21848 bytes .../package_finder.cpython-312.pyc | Bin 0 -> 40761 bytes .../index/__pycache__/sources.cpython-312.pyc | Bin 0 -> 9856 bytes .../pip/_internal/index/collector.py | 505 + .../pip/_internal/index/package_finder.py | 1029 ++ .../pip/_internal/index/sources.py | 223 + .../pip/_internal/locations/__init__.py | 467 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 16769 bytes .../__pycache__/_distutils.cpython-312.pyc | Bin 0 -> 6865 bytes .../__pycache__/_sysconfig.cpython-312.pyc | Bin 0 -> 8004 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 3774 bytes .../pip/_internal/locations/_distutils.py | 173 + .../pip/_internal/locations/_sysconfig.py | 213 + .../pip/_internal/locations/base.py | 81 + .../site-packages/pip/_internal/main.py | 12 + .../pip/_internal/metadata/__init__.py | 127 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5793 bytes .../__pycache__/_json.cpython-312.pyc | Bin 0 -> 2868 bytes .../metadata/__pycache__/base.cpython-312.pyc | Bin 0 -> 35110 bytes .../__pycache__/pkg_resources.cpython-312.pyc | Bin 0 -> 15128 bytes .../pip/_internal/metadata/_json.py | 84 + .../pip/_internal/metadata/base.py | 688 ++ .../_internal/metadata/importlib/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 323 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 3326 bytes .../__pycache__/_dists.cpython-312.pyc | Bin 0 -> 13153 bytes .../__pycache__/_envs.cpython-312.pyc | Bin 0 -> 11156 bytes .../_internal/metadata/importlib/_compat.py | 55 + .../_internal/metadata/importlib/_dists.py | 224 + .../pip/_internal/metadata/importlib/_envs.py | 188 + .../pip/_internal/metadata/pkg_resources.py | 270 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 259 bytes .../__pycache__/candidate.cpython-312.pyc | Bin 0 -> 1916 bytes .../__pycache__/direct_url.cpython-312.pyc | Bin 0 -> 11215 bytes .../format_control.cpython-312.pyc | Bin 0 -> 4242 bytes .../models/__pycache__/index.cpython-312.pyc | Bin 0 -> 1687 bytes .../installation_report.cpython-312.pyc | Bin 0 -> 2175 bytes .../models/__pycache__/link.cpython-312.pyc | Bin 0 -> 26025 bytes .../models/__pycache__/scheme.cpython-312.pyc | Bin 0 -> 1162 bytes .../__pycache__/search_scope.cpython-312.pyc | Bin 0 -> 5081 bytes .../selection_prefs.cpython-312.pyc | Bin 0 -> 1844 bytes .../__pycache__/target_python.cpython-312.pyc | Bin 0 -> 4433 bytes .../models/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5773 bytes .../pip/_internal/models/candidate.py | 34 + .../pip/_internal/models/direct_url.py | 237 + .../pip/_internal/models/format_control.py | 80 + .../pip/_internal/models/index.py | 28 + .../_internal/models/installation_report.py | 53 + .../pip/_internal/models/link.py | 581 ++ .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 132 + .../pip/_internal/models/selection_prefs.py | 51 + .../pip/_internal/models/target_python.py | 110 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 247 bytes .../network/__pycache__/auth.cpython-312.pyc | Bin 0 -> 21981 bytes .../network/__pycache__/cache.cpython-312.pyc | Bin 0 -> 4147 bytes .../__pycache__/download.cpython-312.pyc | Bin 0 -> 8569 bytes .../__pycache__/lazy_wheel.cpython-312.pyc | Bin 0 -> 11653 bytes .../__pycache__/session.cpython-312.pyc | Bin 0 -> 18762 bytes .../network/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2246 bytes .../__pycache__/xmlrpc.cpython-312.pyc | Bin 0 -> 2893 bytes .../pip/_internal/network/auth.py | 561 ++ .../pip/_internal/network/cache.py | 69 + .../pip/_internal/network/download.py | 186 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 519 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 60 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../__pycache__/check.cpython-312.pyc | Bin 0 -> 7572 bytes .../__pycache__/freeze.cpython-312.pyc | Bin 0 -> 10107 bytes .../__pycache__/prepare.cpython-312.pyc | Bin 0 -> 25811 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 196 bytes .../__pycache__/build_tracker.cpython-312.pyc | Bin 0 -> 7112 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 1873 bytes .../metadata_editable.cpython-312.pyc | Bin 0 -> 1907 bytes .../metadata_legacy.cpython-312.pyc | Bin 0 -> 3058 bytes .../build/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 1674 bytes .../wheel_editable.cpython-312.pyc | Bin 0 -> 2015 bytes .../__pycache__/wheel_legacy.cpython-312.pyc | Bin 0 -> 3922 bytes .../operations/build/build_tracker.py | 124 + .../_internal/operations/build/metadata.py | 39 + .../operations/build/metadata_editable.py | 41 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 37 + .../operations/build/wheel_editable.py | 46 + .../operations/build/wheel_legacy.py | 102 + .../pip/_internal/operations/check.py | 187 + .../pip/_internal/operations/freeze.py | 255 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 259 bytes .../editable_legacy.cpython-312.pyc | Bin 0 -> 1810 bytes .../install/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 34006 bytes .../operations/install/editable_legacy.py | 46 + .../pip/_internal/operations/install/wheel.py | 740 ++ .../pip/_internal/operations/prepare.py | 743 ++ .../site-packages/pip/_internal/pyproject.py | 179 + .../pip/_internal/req/__init__.py | 92 + .../req/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3734 bytes .../__pycache__/constructors.cpython-312.pyc | Bin 0 -> 18842 bytes .../req/__pycache__/req_file.cpython-312.pyc | Bin 0 -> 21229 bytes .../__pycache__/req_install.cpython-312.pyc | Bin 0 -> 35924 bytes .../req/__pycache__/req_set.cpython-312.pyc | Bin 0 -> 7205 bytes .../__pycache__/req_uninstall.cpython-312.pyc | Bin 0 -> 33093 bytes .../pip/_internal/req/constructors.py | 506 + .../pip/_internal/req/req_file.py | 552 ++ .../pip/_internal/req/req_install.py | 874 ++ .../pip/_internal/req/req_set.py | 119 + .../pip/_internal/req/req_uninstall.py | 650 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 190 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 1178 bytes .../pip/_internal/resolution/base.py | 20 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 197 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 22523 bytes .../_internal/resolution/legacy/resolver.py | 600 ++ .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 201 bytes .../__pycache__/base.cpython-312.pyc | Bin 0 -> 8604 bytes .../__pycache__/candidates.cpython-312.pyc | Bin 0 -> 27984 bytes .../__pycache__/factory.cpython-312.pyc | Bin 0 -> 28506 bytes .../found_candidates.cpython-312.pyc | Bin 0 -> 6201 bytes .../__pycache__/provider.cpython-312.pyc | Bin 0 -> 10371 bytes .../__pycache__/reporter.cpython-312.pyc | Bin 0 -> 4928 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 10427 bytes .../__pycache__/resolver.cpython-312.pyc | Bin 0 -> 11416 bytes .../_internal/resolution/resolvelib/base.py | 141 + .../resolution/resolvelib/candidates.py | 555 ++ .../resolution/resolvelib/factory.py | 730 ++ .../resolution/resolvelib/found_candidates.py | 155 + .../resolution/resolvelib/provider.py | 255 + .../resolution/resolvelib/reporter.py | 80 + .../resolution/resolvelib/requirements.py | 165 + .../resolution/resolvelib/resolver.py | 299 + .../pip/_internal/self_outdated_check.py | 242 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 185 bytes .../__pycache__/_jaraco_text.cpython-312.pyc | Bin 0 -> 4526 bytes .../utils/__pycache__/_log.cpython-312.pyc | Bin 0 -> 1856 bytes .../utils/__pycache__/appdirs.cpython-312.pyc | Bin 0 -> 2400 bytes .../utils/__pycache__/compat.cpython-312.pyc | Bin 0 -> 2203 bytes .../compatibility_tags.cpython-312.pyc | Bin 0 -> 5551 bytes .../__pycache__/datetime.cpython-312.pyc | Bin 0 -> 674 bytes .../__pycache__/deprecation.cpython-312.pyc | Bin 0 -> 4176 bytes .../direct_url_helpers.cpython-312.pyc | Bin 0 -> 3543 bytes .../__pycache__/egg_link.cpython-312.pyc | Bin 0 -> 2918 bytes .../__pycache__/encoding.cpython-312.pyc | Bin 0 -> 2145 bytes .../__pycache__/entrypoints.cpython-312.pyc | Bin 0 -> 3983 bytes .../__pycache__/filesystem.cpython-312.pyc | Bin 0 -> 7445 bytes .../__pycache__/filetypes.cpython-312.pyc | Bin 0 -> 1154 bytes .../utils/__pycache__/glibc.cpython-312.pyc | Bin 0 -> 2332 bytes .../utils/__pycache__/hashes.cpython-312.pyc | Bin 0 -> 7544 bytes .../inject_securetransport.cpython-312.pyc | Bin 0 -> 1198 bytes .../utils/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13639 bytes .../utils/__pycache__/misc.cpython-312.pyc | Bin 0 -> 32744 bytes .../utils/__pycache__/models.cpython-312.pyc | Bin 0 -> 2702 bytes .../__pycache__/packaging.cpython-312.pyc | Bin 0 -> 2573 bytes .../setuptools_build.cpython-312.pyc | Bin 0 -> 4537 bytes .../__pycache__/subprocess.cpython-312.pyc | Bin 0 -> 8696 bytes .../__pycache__/temp_dir.cpython-312.pyc | Bin 0 -> 10301 bytes .../__pycache__/unpacking.cpython-312.pyc | Bin 0 -> 11096 bytes .../utils/__pycache__/urls.cpython-312.pyc | Bin 0 -> 2390 bytes .../__pycache__/virtualenv.cpython-312.pyc | Bin 0 -> 4470 bytes .../utils/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 5977 bytes .../pip/_internal/utils/_jaraco_text.py | 109 + .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 52 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 165 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 120 + .../pip/_internal/utils/direct_url_helpers.py | 87 + .../pip/_internal/utils/egg_link.py | 72 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 84 + .../pip/_internal/utils/filesystem.py | 153 + .../pip/_internal/utils/filetypes.py | 27 + .../pip/_internal/utils/glibc.py | 88 + .../pip/_internal/utils/hashes.py | 151 + .../_internal/utils/inject_securetransport.py | 35 + .../pip/_internal/utils/logging.py | 348 + .../site-packages/pip/_internal/utils/misc.py | 735 ++ .../pip/_internal/utils/models.py | 39 + .../pip/_internal/utils/packaging.py | 57 + .../pip/_internal/utils/setuptools_build.py | 146 + .../pip/_internal/utils/subprocess.py | 260 + .../pip/_internal/utils/temp_dir.py | 246 + .../pip/_internal/utils/unpacking.py | 257 + .../site-packages/pip/_internal/utils/urls.py | 62 + .../pip/_internal/utils/virtualenv.py | 104 + .../pip/_internal/utils/wheel.py | 136 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 524 bytes .../vcs/__pycache__/bazaar.cpython-312.pyc | Bin 0 -> 5016 bytes .../vcs/__pycache__/git.cpython-312.pyc | Bin 0 -> 19117 bytes .../vcs/__pycache__/mercurial.cpython-312.pyc | Bin 0 -> 7592 bytes .../__pycache__/subversion.cpython-312.pyc | Bin 0 -> 12471 bytes .../versioncontrol.cpython-312.pyc | Bin 0 -> 29089 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 112 + .../site-packages/pip/_internal/vcs/git.py | 526 + .../pip/_internal/vcs/mercurial.py | 163 + .../pip/_internal/vcs/subversion.py | 324 + .../pip/_internal/vcs/versioncontrol.py | 705 ++ .../pip/_internal/wheel_builder.py | 355 + .../site-packages/pip/_vendor/__init__.py | 120 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4650 bytes .../_vendor/__pycache__/six.cpython-312.pyc | Bin 0 -> 41263 bytes .../typing_extensions.cpython-312.pyc | Bin 0 -> 122031 bytes .../pip/_vendor/cachecontrol/__init__.py | 18 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 769 bytes .../__pycache__/_cmd.cpython-312.pyc | Bin 0 -> 2421 bytes .../__pycache__/adapter.cpython-312.pyc | Bin 0 -> 5047 bytes .../__pycache__/cache.cpython-312.pyc | Bin 0 -> 3233 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 915 bytes .../__pycache__/controller.cpython-312.pyc | Bin 0 -> 14632 bytes .../__pycache__/filewrapper.cpython-312.pyc | Bin 0 -> 3942 bytes .../__pycache__/heuristics.cpython-312.pyc | Bin 0 -> 6071 bytes .../__pycache__/serialize.cpython-312.pyc | Bin 0 -> 7262 bytes .../__pycache__/wrapper.cpython-312.pyc | Bin 0 -> 846 bytes .../pip/_vendor/cachecontrol/_cmd.py | 61 + .../pip/_vendor/cachecontrol/adapter.py | 137 + .../pip/_vendor/cachecontrol/cache.py | 65 + .../_vendor/cachecontrol/caches/__init__.py | 9 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 366 bytes .../__pycache__/file_cache.cpython-312.pyc | Bin 0 -> 7289 bytes .../__pycache__/redis_cache.cpython-312.pyc | Bin 0 -> 2211 bytes .../_vendor/cachecontrol/caches/file_cache.py | 188 + .../cachecontrol/caches/redis_cache.py | 39 + .../pip/_vendor/cachecontrol/compat.py | 32 + .../pip/_vendor/cachecontrol/controller.py | 439 + .../pip/_vendor/cachecontrol/filewrapper.py | 111 + .../pip/_vendor/cachecontrol/heuristics.py | 139 + .../pip/_vendor/cachecontrol/serialize.py | 190 + .../pip/_vendor/cachecontrol/wrapper.py | 33 + .../pip/_vendor/certifi/__init__.py | 4 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 312 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 639 bytes .../certifi/__pycache__/core.cpython-312.pyc | Bin 0 -> 2843 bytes .../pip/_vendor/certifi/cacert.pem | 4589 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 108 + .../pip/_vendor/chardet/__init__.py | 115 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4562 bytes .../__pycache__/big5freq.cpython-312.pyc | Bin 0 -> 27193 bytes .../__pycache__/big5prober.cpython-312.pyc | Bin 0 -> 1381 bytes .../chardistribution.cpython-312.pyc | Bin 0 -> 9632 bytes .../charsetgroupprober.cpython-312.pyc | Bin 0 -> 4116 bytes .../__pycache__/charsetprober.cpython-312.pyc | Bin 0 -> 5012 bytes .../codingstatemachine.cpython-312.pyc | Bin 0 -> 3872 bytes .../codingstatemachinedict.cpython-312.pyc | Bin 0 -> 783 bytes .../__pycache__/cp949prober.cpython-312.pyc | Bin 0 -> 1390 bytes .../chardet/__pycache__/enums.cpython-312.pyc | Bin 0 -> 2990 bytes .../__pycache__/escprober.cpython-312.pyc | Bin 0 -> 4560 bytes .../chardet/__pycache__/escsm.cpython-312.pyc | Bin 0 -> 15304 bytes .../__pycache__/eucjpprober.cpython-312.pyc | Bin 0 -> 4368 bytes .../__pycache__/euckrfreq.cpython-312.pyc | Bin 0 -> 12076 bytes .../__pycache__/euckrprober.cpython-312.pyc | Bin 0 -> 1384 bytes .../__pycache__/euctwfreq.cpython-312.pyc | Bin 0 -> 27198 bytes .../__pycache__/euctwprober.cpython-312.pyc | Bin 0 -> 1384 bytes .../__pycache__/gb2312freq.cpython-312.pyc | Bin 0 -> 19120 bytes .../__pycache__/gb2312prober.cpython-312.pyc | Bin 0 -> 1397 bytes .../__pycache__/hebrewprober.cpython-312.pyc | Bin 0 -> 5804 bytes .../__pycache__/jisfreq.cpython-312.pyc | Bin 0 -> 22149 bytes .../__pycache__/johabfreq.cpython-312.pyc | Bin 0 -> 82997 bytes .../__pycache__/johabprober.cpython-312.pyc | Bin 0 -> 1388 bytes .../__pycache__/jpcntx.cpython-312.pyc | Bin 0 -> 39543 bytes .../langbulgarianmodel.cpython-312.pyc | Bin 0 -> 83116 bytes .../langgreekmodel.cpython-312.pyc | Bin 0 -> 76982 bytes .../langhebrewmodel.cpython-312.pyc | Bin 0 -> 77493 bytes .../langhungarianmodel.cpython-312.pyc | Bin 0 -> 83070 bytes .../langrussianmodel.cpython-312.pyc | Bin 0 -> 105245 bytes .../__pycache__/langthaimodel.cpython-312.pyc | Bin 0 -> 77671 bytes .../langturkishmodel.cpython-312.pyc | Bin 0 -> 77510 bytes .../__pycache__/latin1prober.cpython-312.pyc | Bin 0 -> 6996 bytes .../macromanprober.cpython-312.pyc | Bin 0 -> 7176 bytes .../mbcharsetprober.cpython-312.pyc | Bin 0 -> 3888 bytes .../mbcsgroupprober.cpython-312.pyc | Bin 0 -> 1582 bytes .../__pycache__/mbcssm.cpython-312.pyc | Bin 0 -> 38639 bytes .../__pycache__/resultdict.cpython-312.pyc | Bin 0 -> 626 bytes .../sbcharsetprober.cpython-312.pyc | Bin 0 -> 6381 bytes .../sbcsgroupprober.cpython-312.pyc | Bin 0 -> 2351 bytes .../__pycache__/sjisprober.cpython-312.pyc | Bin 0 -> 4480 bytes .../universaldetector.cpython-312.pyc | Bin 0 -> 12260 bytes .../__pycache__/utf1632prober.cpython-312.pyc | Bin 0 -> 9973 bytes .../__pycache__/utf8prober.cpython-312.pyc | Bin 0 -> 3169 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 482 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 261 + .../pip/_vendor/chardet/charsetgroupprober.py | 106 + .../pip/_vendor/chardet/charsetprober.py | 147 + .../pip/_vendor/chardet/cli/__init__.py | 0 .../cli/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 189 bytes .../__pycache__/chardetect.cpython-312.pyc | Bin 0 -> 4006 bytes .../pip/_vendor/chardet/cli/chardetect.py | 112 + .../pip/_vendor/chardet/codingstatemachine.py | 90 + .../_vendor/chardet/codingstatemachinedict.py | 19 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 85 + .../pip/_vendor/chardet/escprober.py | 102 + .../pip/_vendor/chardet/escsm.py | 261 + .../pip/_vendor/chardet/eucjpprober.py | 102 + .../pip/_vendor/chardet/euckrfreq.py | 196 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 388 + .../pip/_vendor/chardet/euctwprober.py | 47 + .../pip/_vendor/chardet/gb2312freq.py | 284 + .../pip/_vendor/chardet/gb2312prober.py | 47 + .../pip/_vendor/chardet/hebrewprober.py | 316 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/johabfreq.py | 2382 +++++ .../pip/_vendor/chardet/johabprober.py | 47 + .../pip/_vendor/chardet/jpcntx.py | 238 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4397 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4649 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5725 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4380 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4380 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 147 + .../pip/_vendor/chardet/macromanprober.py | 162 + .../pip/_vendor/chardet/mbcharsetprober.py | 95 + .../pip/_vendor/chardet/mbcsgroupprober.py | 57 + .../pip/_vendor/chardet/mbcssm.py | 661 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 194 bytes .../__pycache__/languages.cpython-312.pyc | Bin 0 -> 9749 bytes .../pip/_vendor/chardet/metadata/languages.py | 352 + .../pip/_vendor/chardet/resultdict.py | 16 + .../pip/_vendor/chardet/sbcharsetprober.py | 162 + .../pip/_vendor/chardet/sbcsgroupprober.py | 88 + .../pip/_vendor/chardet/sjisprober.py | 105 + .../pip/_vendor/chardet/universaldetector.py | 362 + .../pip/_vendor/chardet/utf1632prober.py | 225 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 7 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 486 bytes .../colorama/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 3944 bytes .../__pycache__/ansitowin32.cpython-312.pyc | Bin 0 -> 16415 bytes .../__pycache__/initialise.cpython-312.pyc | Bin 0 -> 3544 bytes .../__pycache__/win32.cpython-312.pyc | Bin 0 -> 8120 bytes .../__pycache__/winterm.cpython-312.pyc | Bin 0 -> 9082 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 277 + .../pip/_vendor/colorama/initialise.py | 121 + .../pip/_vendor/colorama/tests/__init__.py | 1 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 192 bytes .../__pycache__/ansi_test.cpython-312.pyc | Bin 0 -> 5461 bytes .../ansitowin32_test.cpython-312.pyc | Bin 0 -> 18097 bytes .../initialise_test.cpython-312.pyc | Bin 0 -> 11742 bytes .../__pycache__/isatty_test.cpython-312.pyc | Bin 0 -> 4898 bytes .../tests/__pycache__/utils.cpython-312.pyc | Bin 0 -> 2482 bytes .../__pycache__/winterm_test.cpython-312.pyc | Bin 0 -> 6606 bytes .../pip/_vendor/colorama/tests/ansi_test.py | 76 + .../colorama/tests/ansitowin32_test.py | 294 + .../_vendor/colorama/tests/initialise_test.py | 189 + .../pip/_vendor/colorama/tests/isatty_test.py | 57 + .../pip/_vendor/colorama/tests/utils.py | 49 + .../_vendor/colorama/tests/winterm_test.py | 131 + .../pip/_vendor/colorama/win32.py | 180 + .../pip/_vendor/colorama/winterm.py | 195 + .../pip/_vendor/distlib/__init__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1253 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 45536 bytes .../__pycache__/database.cpython-312.pyc | Bin 0 -> 65967 bytes .../distlib/__pycache__/index.cpython-312.pyc | Bin 0 -> 24381 bytes .../__pycache__/locators.cpython-312.pyc | Bin 0 -> 60203 bytes .../__pycache__/manifest.cpython-312.pyc | Bin 0 -> 15127 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 7454 bytes .../__pycache__/metadata.cpython-312.pyc | Bin 0 -> 41601 bytes .../__pycache__/resources.cpython-312.pyc | Bin 0 -> 17319 bytes .../__pycache__/scripts.cpython-312.pyc | Bin 0 -> 19584 bytes .../distlib/__pycache__/util.cpython-312.pyc | Bin 0 -> 87571 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 30149 bytes .../distlib/__pycache__/wheel.cpython-312.pyc | Bin 0 -> 52539 bytes .../pip/_vendor/distlib/compat.py | 1116 +++ .../pip/_vendor/distlib/database.py | 1350 +++ .../pip/_vendor/distlib/index.py | 508 + .../pip/_vendor/distlib/locators.py | 1300 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 152 + .../pip/_vendor/distlib/metadata.py | 1076 +++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 437 + .../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 | 1932 ++++ .../pip/_vendor/distlib/version.py | 739 ++ .../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 | 1082 +++ .../pip/_vendor/distro/__init__.py | 54 + .../pip/_vendor/distro/__main__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 954 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 286 bytes .../distro/__pycache__/distro.cpython-312.pyc | Bin 0 -> 53746 bytes .../pip/_vendor/distro/distro.py | 1399 +++ .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 875 bytes .../idna/__pycache__/codec.cpython-312.pyc | Bin 0 -> 4627 bytes .../idna/__pycache__/compat.cpython-312.pyc | Bin 0 -> 881 bytes .../idna/__pycache__/core.cpython-312.pyc | Bin 0 -> 16276 bytes .../idna/__pycache__/idnadata.cpython-312.pyc | Bin 0 -> 38376 bytes .../__pycache__/intranges.cpython-312.pyc | Bin 0 -> 2632 bytes .../__pycache__/package_data.cpython-312.pyc | Bin 0 -> 210 bytes .../__pycache__/uts46data.cpython-312.pyc | Bin 0 -> 158864 bytes .../site-packages/pip/_vendor/idna/codec.py | 112 + .../site-packages/pip/_vendor/idna/compat.py | 13 + .../site-packages/pip/_vendor/idna/core.py | 400 + .../pip/_vendor/idna/idnadata.py | 2151 +++++ .../pip/_vendor/idna/intranges.py | 54 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8600 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 57 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1825 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 2019 bytes .../msgpack/__pycache__/ext.cpython-312.pyc | Bin 0 -> 8662 bytes .../__pycache__/fallback.cpython-312.pyc | Bin 0 -> 43556 bytes .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1010 ++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-312.pyc | Bin 0 -> 624 bytes .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 460 bytes .../__pycache__/_manylinux.cpython-312.pyc | Bin 0 -> 12067 bytes .../__pycache__/_musllinux.cpython-312.pyc | Bin 0 -> 6901 bytes .../__pycache__/_structures.cpython-312.pyc | Bin 0 -> 3235 bytes .../__pycache__/markers.cpython-312.pyc | Bin 0 -> 14043 bytes .../__pycache__/requirements.cpython-312.pyc | Bin 0 -> 6940 bytes .../__pycache__/specifiers.cpython-312.pyc | Bin 0 -> 31241 bytes .../__pycache__/tags.cpython-312.pyc | Bin 0 -> 18950 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 5862 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 19933 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 61 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 802 ++ .../pip/_vendor/packaging/tags.py | 487 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pkg_resources/__init__.py | 3361 +++++++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 146468 bytes .../pip/_vendor/platformdirs/__init__.py | 566 ++ .../pip/_vendor/platformdirs/__main__.py | 53 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 18023 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 1940 bytes .../__pycache__/android.cpython-312.pyc | Bin 0 -> 9438 bytes .../__pycache__/api.cpython-312.pyc | Bin 0 -> 9666 bytes .../__pycache__/macos.cpython-312.pyc | Bin 0 -> 5631 bytes .../__pycache__/unix.cpython-312.pyc | Bin 0 -> 12435 bytes .../__pycache__/version.cpython-312.pyc | Bin 0 -> 305 bytes .../__pycache__/windows.cpython-312.pyc | Bin 0 -> 12993 bytes .../pip/_vendor/platformdirs/android.py | 210 + .../pip/_vendor/platformdirs/api.py | 223 + .../pip/_vendor/platformdirs/macos.py | 91 + .../pip/_vendor/platformdirs/unix.py | 223 + .../pip/_vendor/platformdirs/version.py | 4 + .../pip/_vendor/platformdirs/windows.py | 255 + .../pip/_vendor/pygments/__init__.py | 82 + .../pip/_vendor/pygments/__main__.py | 17 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3483 bytes .../__pycache__/__main__.cpython-312.pyc | Bin 0 -> 729 bytes .../__pycache__/cmdline.cpython-312.pyc | Bin 0 -> 26600 bytes .../__pycache__/console.cpython-312.pyc | Bin 0 -> 2621 bytes .../__pycache__/filter.cpython-312.pyc | Bin 0 -> 3227 bytes .../__pycache__/formatter.cpython-312.pyc | Bin 0 -> 4564 bytes .../__pycache__/lexer.cpython-312.pyc | Bin 0 -> 38295 bytes .../__pycache__/modeline.cpython-312.pyc | Bin 0 -> 1563 bytes .../__pycache__/plugin.cpython-312.pyc | Bin 0 -> 3391 bytes .../__pycache__/regexopt.cpython-312.pyc | Bin 0 -> 4076 bytes .../__pycache__/scanner.cpython-312.pyc | Bin 0 -> 4751 bytes .../__pycache__/sphinxext.cpython-312.pyc | Bin 0 -> 11041 bytes .../__pycache__/style.cpython-312.pyc | Bin 0 -> 6667 bytes .../__pycache__/token.cpython-312.pyc | Bin 0 -> 8137 bytes .../__pycache__/unistring.cpython-312.pyc | Bin 0 -> 32983 bytes .../pygments/__pycache__/util.cpython-312.pyc | Bin 0 -> 13976 bytes .../pip/_vendor/pygments/cmdline.py | 668 ++ .../pip/_vendor/pygments/console.py | 70 + .../pip/_vendor/pygments/filter.py | 71 + .../pip/_vendor/pygments/filters/__init__.py | 940 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 37931 bytes .../pip/_vendor/pygments/formatter.py | 124 + .../_vendor/pygments/formatters/__init__.py | 158 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 6921 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 4210 bytes .../__pycache__/bbcode.cpython-312.pyc | Bin 0 -> 4189 bytes .../__pycache__/groff.cpython-312.pyc | Bin 0 -> 7259 bytes .../__pycache__/html.cpython-312.pyc | Bin 0 -> 40567 bytes .../__pycache__/img.cpython-312.pyc | Bin 0 -> 27038 bytes .../__pycache__/irc.cpython-312.pyc | Bin 0 -> 6060 bytes .../__pycache__/latex.cpython-312.pyc | Bin 0 -> 19949 bytes .../__pycache__/other.cpython-312.pyc | Bin 0 -> 6879 bytes .../__pycache__/pangomarkup.cpython-312.pyc | Bin 0 -> 2925 bytes .../__pycache__/rtf.cpython-312.pyc | Bin 0 -> 6121 bytes .../__pycache__/svg.cpython-312.pyc | Bin 0 -> 9061 bytes .../__pycache__/terminal.cpython-312.pyc | Bin 0 -> 5824 bytes .../__pycache__/terminal256.cpython-312.pyc | Bin 0 -> 15152 bytes .../_vendor/pygments/formatters/_mapping.py | 23 + .../pip/_vendor/pygments/formatters/bbcode.py | 108 + .../pip/_vendor/pygments/formatters/groff.py | 170 + .../pip/_vendor/pygments/formatters/html.py | 989 ++ .../pip/_vendor/pygments/formatters/img.py | 645 ++ .../pip/_vendor/pygments/formatters/irc.py | 154 + .../pip/_vendor/pygments/formatters/latex.py | 521 + .../pip/_vendor/pygments/formatters/other.py | 161 + .../pygments/formatters/pangomarkup.py | 83 + .../pip/_vendor/pygments/formatters/rtf.py | 146 + .../pip/_vendor/pygments/formatters/svg.py | 188 + .../_vendor/pygments/formatters/terminal.py | 127 + .../pygments/formatters/terminal256.py | 338 + .../pip/_vendor/pygments/lexer.py | 943 ++ .../pip/_vendor/pygments/lexers/__init__.py | 362 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 14647 bytes .../__pycache__/_mapping.cpython-312.pyc | Bin 0 -> 64399 bytes .../lexers/__pycache__/python.cpython-312.pyc | Bin 0 -> 42634 bytes .../pip/_vendor/pygments/lexers/_mapping.py | 559 ++ .../pip/_vendor/pygments/lexers/python.py | 1198 +++ .../pip/_vendor/pygments/modeline.py | 43 + .../pip/_vendor/pygments/plugin.py | 88 + .../pip/_vendor/pygments/regexopt.py | 91 + .../pip/_vendor/pygments/scanner.py | 104 + .../pip/_vendor/pygments/sphinxext.py | 217 + .../pip/_vendor/pygments/style.py | 197 + .../pip/_vendor/pygments/styles/__init__.py | 103 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4443 bytes .../pip/_vendor/pygments/token.py | 213 + .../pip/_vendor/pygments/unistring.py | 153 + .../pip/_vendor/pygments/util.py | 330 + .../pip/_vendor/pyparsing/__init__.py | 322 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7906 bytes .../__pycache__/actions.cpython-312.pyc | Bin 0 -> 8390 bytes .../__pycache__/common.cpython-312.pyc | Bin 0 -> 13409 bytes .../__pycache__/core.cpython-312.pyc | Bin 0 -> 267703 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 12989 bytes .../__pycache__/helpers.cpython-312.pyc | Bin 0 -> 48496 bytes .../__pycache__/results.cpython-312.pyc | Bin 0 -> 34105 bytes .../__pycache__/testing.cpython-312.pyc | Bin 0 -> 17183 bytes .../__pycache__/unicode.cpython-312.pyc | Bin 0 -> 13179 bytes .../__pycache__/util.cpython-312.pyc | Bin 0 -> 14899 bytes .../pip/_vendor/pyparsing/actions.py | 217 + .../pip/_vendor/pyparsing/common.py | 432 + .../pip/_vendor/pyparsing/core.py | 6115 ++++++++++++ .../pip/_vendor/pyparsing/diagram/__init__.py | 656 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 26808 bytes .../pip/_vendor/pyparsing/exceptions.py | 299 + .../pip/_vendor/pyparsing/helpers.py | 1100 +++ .../pip/_vendor/pyparsing/results.py | 796 ++ .../pip/_vendor/pyparsing/testing.py | 331 + .../pip/_vendor/pyparsing/unicode.py | 361 + .../pip/_vendor/pyparsing/util.py | 284 + .../pip/_vendor/pyproject_hooks/__init__.py | 23 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 608 bytes .../__pycache__/_compat.cpython-312.pyc | Bin 0 -> 369 bytes .../__pycache__/_impl.cpython-312.pyc | Bin 0 -> 14720 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 -> 1075 bytes .../__pycache__/_in_process.cpython-312.pyc | Bin 0 -> 14392 bytes .../_in_process/_in_process.py | 353 + .../pip/_vendor/requests/__init__.py | 182 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 5441 bytes .../__pycache__/__version__.cpython-312.pyc | Bin 0 -> 579 bytes .../_internal_utils.cpython-312.pyc | Bin 0 -> 2016 bytes .../__pycache__/adapters.cpython-312.pyc | Bin 0 -> 21275 bytes .../requests/__pycache__/api.cpython-312.pyc | Bin 0 -> 7199 bytes .../requests/__pycache__/auth.cpython-312.pyc | Bin 0 -> 13918 bytes .../__pycache__/certs.cpython-312.pyc | Bin 0 -> 917 bytes .../__pycache__/compat.cpython-312.pyc | Bin 0 -> 1502 bytes .../__pycache__/cookies.cpython-312.pyc | Bin 0 -> 25241 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7042 bytes .../requests/__pycache__/help.cpython-312.pyc | Bin 0 -> 4307 bytes .../__pycache__/hooks.cpython-312.pyc | Bin 0 -> 1047 bytes .../__pycache__/models.cpython-312.pyc | Bin 0 -> 35443 bytes .../__pycache__/packages.cpython-312.pyc | Bin 0 -> 767 bytes .../__pycache__/sessions.cpython-312.pyc | Bin 0 -> 27752 bytes .../__pycache__/status_codes.cpython-312.pyc | Bin 0 -> 5954 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 5612 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 36264 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 50 + .../pip/_vendor/requests/adapters.py | 538 ++ .../site-packages/pip/_vendor/requests/api.py | 157 + .../pip/_vendor/requests/auth.py | 315 + .../pip/_vendor/requests/certs.py | 24 + .../pip/_vendor/requests/compat.py | 67 + .../pip/_vendor/requests/cookies.py | 561 ++ .../pip/_vendor/requests/exceptions.py | 141 + .../pip/_vendor/requests/help.py | 131 + .../pip/_vendor/requests/hooks.py | 33 + .../pip/_vendor/requests/models.py | 1034 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 833 ++ .../pip/_vendor/requests/status_codes.py | 128 + .../pip/_vendor/requests/structures.py | 99 + .../pip/_vendor/requests/utils.py | 1094 +++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 629 bytes .../__pycache__/providers.cpython-312.pyc | Bin 0 -> 6846 bytes .../__pycache__/reporters.cpython-312.pyc | Bin 0 -> 2649 bytes .../__pycache__/resolvers.cpython-312.pyc | Bin 0 -> 25892 bytes .../__pycache__/structs.cpython-312.pyc | Bin 0 -> 10501 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 195 bytes .../collections_abc.cpython-312.pyc | Bin 0 -> 415 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 133 + .../pip/_vendor/resolvelib/reporters.py | 43 + .../pip/_vendor/resolvelib/resolvers.py | 547 ++ .../pip/_vendor/resolvelib/structs.py | 170 + .../pip/_vendor/rich/__init__.py | 177 + .../pip/_vendor/rich/__main__.py | 274 + .../rich/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 7010 bytes .../rich/__pycache__/__main__.cpython-312.pyc | Bin 0 -> 10299 bytes .../__pycache__/_cell_widths.cpython-312.pyc | Bin 0 -> 7816 bytes .../__pycache__/_emoji_codes.cpython-312.pyc | Bin 0 -> 205971 bytes .../_emoji_replace.cpython-312.pyc | Bin 0 -> 1724 bytes .../_export_format.cpython-312.pyc | Bin 0 -> 2316 bytes .../__pycache__/_extension.cpython-312.pyc | Bin 0 -> 532 bytes .../rich/__pycache__/_fileno.cpython-312.pyc | Bin 0 -> 850 bytes .../rich/__pycache__/_inspect.cpython-312.pyc | Bin 0 -> 12072 bytes .../__pycache__/_log_render.cpython-312.pyc | Bin 0 -> 4142 bytes .../rich/__pycache__/_loop.cpython-312.pyc | Bin 0 -> 1880 bytes .../__pycache__/_null_file.cpython-312.pyc | Bin 0 -> 3615 bytes .../__pycache__/_palettes.cpython-312.pyc | Bin 0 -> 5155 bytes .../rich/__pycache__/_pick.cpython-312.pyc | Bin 0 -> 719 bytes .../rich/__pycache__/_ratio.cpython-312.pyc | Bin 0 -> 6572 bytes .../__pycache__/_spinners.cpython-312.pyc | Bin 0 -> 13174 bytes .../rich/__pycache__/_stack.cpython-312.pyc | Bin 0 -> 960 bytes .../rich/__pycache__/_timer.cpython-312.pyc | Bin 0 -> 860 bytes .../_win32_console.cpython-312.pyc | Bin 0 -> 28962 bytes .../rich/__pycache__/_windows.cpython-312.pyc | Bin 0 -> 2485 bytes .../_windows_renderer.cpython-312.pyc | Bin 0 -> 3568 bytes .../rich/__pycache__/_wrap.cpython-312.pyc | Bin 0 -> 2355 bytes .../rich/__pycache__/abc.cpython-312.pyc | Bin 0 -> 1603 bytes .../rich/__pycache__/align.cpython-312.pyc | Bin 0 -> 12317 bytes .../rich/__pycache__/ansi.cpython-312.pyc | Bin 0 -> 9101 bytes .../rich/__pycache__/bar.cpython-312.pyc | Bin 0 -> 4267 bytes .../rich/__pycache__/box.cpython-312.pyc | Bin 0 -> 11853 bytes .../rich/__pycache__/cells.cpython-312.pyc | Bin 0 -> 5613 bytes .../rich/__pycache__/color.cpython-312.pyc | Bin 0 -> 26520 bytes .../__pycache__/color_triplet.cpython-312.pyc | Bin 0 -> 1696 bytes .../rich/__pycache__/columns.cpython-312.pyc | Bin 0 -> 8582 bytes .../rich/__pycache__/console.cpython-312.pyc | Bin 0 -> 113779 bytes .../__pycache__/constrain.cpython-312.pyc | Bin 0 -> 2253 bytes .../__pycache__/containers.cpython-312.pyc | Bin 0 -> 9221 bytes .../rich/__pycache__/control.cpython-312.pyc | Bin 0 -> 10924 bytes .../default_styles.cpython-312.pyc | Bin 0 -> 10368 bytes .../rich/__pycache__/diagnose.cpython-312.pyc | Bin 0 -> 1482 bytes .../rich/__pycache__/emoji.cpython-312.pyc | Bin 0 -> 4204 bytes .../rich/__pycache__/errors.cpython-312.pyc | Bin 0 -> 1840 bytes .../__pycache__/file_proxy.cpython-312.pyc | Bin 0 -> 3572 bytes .../rich/__pycache__/filesize.cpython-312.pyc | Bin 0 -> 3077 bytes .../__pycache__/highlighter.cpython-312.pyc | Bin 0 -> 9893 bytes .../rich/__pycache__/json.cpython-312.pyc | Bin 0 -> 6030 bytes .../rich/__pycache__/jupyter.cpython-312.pyc | Bin 0 -> 5204 bytes .../rich/__pycache__/layout.cpython-312.pyc | Bin 0 -> 20215 bytes .../rich/__pycache__/live.cpython-312.pyc | Bin 0 -> 19135 bytes .../__pycache__/live_render.cpython-312.pyc | Bin 0 -> 4889 bytes .../rich/__pycache__/logging.cpython-312.pyc | Bin 0 -> 13543 bytes .../rich/__pycache__/markup.cpython-312.pyc | Bin 0 -> 9293 bytes .../rich/__pycache__/measure.cpython-312.pyc | Bin 0 -> 6371 bytes .../rich/__pycache__/padding.cpython-312.pyc | Bin 0 -> 7129 bytes .../rich/__pycache__/pager.cpython-312.pyc | Bin 0 -> 1815 bytes .../rich/__pycache__/palette.cpython-312.pyc | Bin 0 -> 5309 bytes .../rich/__pycache__/panel.cpython-312.pyc | Bin 0 -> 12092 bytes .../rich/__pycache__/pretty.cpython-312.pyc | Bin 0 -> 40037 bytes .../rich/__pycache__/progress.cpython-312.pyc | Bin 0 -> 75070 bytes .../__pycache__/progress_bar.cpython-312.pyc | Bin 0 -> 10384 bytes .../rich/__pycache__/prompt.cpython-312.pyc | Bin 0 -> 14773 bytes .../rich/__pycache__/protocol.cpython-312.pyc | Bin 0 -> 1787 bytes .../rich/__pycache__/region.cpython-312.pyc | Bin 0 -> 562 bytes .../rich/__pycache__/repr.cpython-312.pyc | Bin 0 -> 6621 bytes .../rich/__pycache__/rule.cpython-312.pyc | Bin 0 -> 6563 bytes .../rich/__pycache__/scope.cpython-312.pyc | Bin 0 -> 3825 bytes .../rich/__pycache__/screen.cpython-312.pyc | Bin 0 -> 2479 bytes .../rich/__pycache__/segment.cpython-312.pyc | Bin 0 -> 28156 bytes .../rich/__pycache__/spinner.cpython-312.pyc | Bin 0 -> 6059 bytes .../rich/__pycache__/status.cpython-312.pyc | Bin 0 -> 6063 bytes .../rich/__pycache__/style.cpython-312.pyc | Bin 0 -> 33509 bytes .../rich/__pycache__/styled.cpython-312.pyc | Bin 0 -> 2134 bytes .../rich/__pycache__/syntax.cpython-312.pyc | Bin 0 -> 39605 bytes .../rich/__pycache__/table.cpython-312.pyc | Bin 0 -> 43579 bytes .../terminal_theme.cpython-312.pyc | Bin 0 -> 3343 bytes .../rich/__pycache__/text.cpython-312.pyc | Bin 0 -> 58944 bytes .../rich/__pycache__/theme.cpython-312.pyc | Bin 0 -> 6335 bytes .../rich/__pycache__/themes.cpython-312.pyc | Bin 0 -> 309 bytes .../__pycache__/traceback.cpython-312.pyc | Bin 0 -> 31539 bytes .../rich/__pycache__/tree.cpython-312.pyc | Bin 0 -> 11434 bytes .../pip/_vendor/rich/_cell_widths.py | 451 + .../pip/_vendor/rich/_emoji_codes.py | 3610 +++++++ .../pip/_vendor/rich/_emoji_replace.py | 32 + .../pip/_vendor/rich/_export_format.py | 76 + .../pip/_vendor/rich/_extension.py | 10 + .../site-packages/pip/_vendor/rich/_fileno.py | 24 + .../pip/_vendor/rich/_inspect.py | 270 + .../pip/_vendor/rich/_log_render.py | 94 + .../site-packages/pip/_vendor/rich/_loop.py | 43 + .../pip/_vendor/rich/_null_file.py | 69 + .../pip/_vendor/rich/_palettes.py | 309 + .../site-packages/pip/_vendor/rich/_pick.py | 17 + .../site-packages/pip/_vendor/rich/_ratio.py | 160 + .../pip/_vendor/rich/_spinners.py | 482 + .../site-packages/pip/_vendor/rich/_stack.py | 16 + .../site-packages/pip/_vendor/rich/_timer.py | 19 + .../pip/_vendor/rich/_win32_console.py | 662 ++ .../pip/_vendor/rich/_windows.py | 72 + .../pip/_vendor/rich/_windows_renderer.py | 56 + .../site-packages/pip/_vendor/rich/_wrap.py | 56 + .../site-packages/pip/_vendor/rich/abc.py | 33 + .../site-packages/pip/_vendor/rich/align.py | 311 + .../site-packages/pip/_vendor/rich/ansi.py | 240 + .../site-packages/pip/_vendor/rich/bar.py | 94 + .../site-packages/pip/_vendor/rich/box.py | 517 + .../site-packages/pip/_vendor/rich/cells.py | 154 + .../site-packages/pip/_vendor/rich/color.py | 622 ++ .../pip/_vendor/rich/color_triplet.py | 38 + .../site-packages/pip/_vendor/rich/columns.py | 187 + .../site-packages/pip/_vendor/rich/console.py | 2633 +++++ .../pip/_vendor/rich/constrain.py | 37 + .../pip/_vendor/rich/containers.py | 167 + .../site-packages/pip/_vendor/rich/control.py | 225 + .../pip/_vendor/rich/default_styles.py | 190 + .../pip/_vendor/rich/diagnose.py | 37 + .../site-packages/pip/_vendor/rich/emoji.py | 96 + .../site-packages/pip/_vendor/rich/errors.py | 34 + .../pip/_vendor/rich/file_proxy.py | 57 + .../pip/_vendor/rich/filesize.py | 89 + .../pip/_vendor/rich/highlighter.py | 232 + .../site-packages/pip/_vendor/rich/json.py | 140 + .../site-packages/pip/_vendor/rich/jupyter.py | 101 + .../site-packages/pip/_vendor/rich/layout.py | 443 + .../site-packages/pip/_vendor/rich/live.py | 375 + .../pip/_vendor/rich/live_render.py | 113 + .../site-packages/pip/_vendor/rich/logging.py | 289 + .../site-packages/pip/_vendor/rich/markup.py | 246 + .../site-packages/pip/_vendor/rich/measure.py | 151 + .../site-packages/pip/_vendor/rich/padding.py | 141 + .../site-packages/pip/_vendor/rich/pager.py | 34 + .../site-packages/pip/_vendor/rich/palette.py | 100 + .../site-packages/pip/_vendor/rich/panel.py | 308 + .../site-packages/pip/_vendor/rich/pretty.py | 994 ++ .../pip/_vendor/rich/progress.py | 1702 ++++ .../pip/_vendor/rich/progress_bar.py | 224 + .../site-packages/pip/_vendor/rich/prompt.py | 376 + .../pip/_vendor/rich/protocol.py | 42 + .../site-packages/pip/_vendor/rich/region.py | 10 + .../site-packages/pip/_vendor/rich/repr.py | 149 + .../site-packages/pip/_vendor/rich/rule.py | 130 + .../site-packages/pip/_vendor/rich/scope.py | 86 + .../site-packages/pip/_vendor/rich/screen.py | 54 + .../site-packages/pip/_vendor/rich/segment.py | 739 ++ .../site-packages/pip/_vendor/rich/spinner.py | 137 + .../site-packages/pip/_vendor/rich/status.py | 132 + .../site-packages/pip/_vendor/rich/style.py | 796 ++ .../site-packages/pip/_vendor/rich/styled.py | 42 + .../site-packages/pip/_vendor/rich/syntax.py | 948 ++ .../site-packages/pip/_vendor/rich/table.py | 1002 ++ .../pip/_vendor/rich/terminal_theme.py | 153 + .../site-packages/pip/_vendor/rich/text.py | 1307 +++ .../site-packages/pip/_vendor/rich/theme.py | 115 + .../site-packages/pip/_vendor/rich/themes.py | 5 + .../pip/_vendor/rich/traceback.py | 756 ++ .../site-packages/pip/_vendor/rich/tree.py | 251 + .../site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 608 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 27081 bytes .../__pycache__/_asyncio.cpython-312.pyc | Bin 0 -> 4801 bytes .../__pycache__/_utils.cpython-312.pyc | Bin 0 -> 2310 bytes .../__pycache__/after.cpython-312.pyc | Bin 0 -> 1619 bytes .../__pycache__/before.cpython-312.pyc | Bin 0 -> 1459 bytes .../__pycache__/before_sleep.cpython-312.pyc | Bin 0 -> 2297 bytes .../tenacity/__pycache__/nap.cpython-312.pyc | Bin 0 -> 1407 bytes .../__pycache__/retry.cpython-312.pyc | Bin 0 -> 14276 bytes .../tenacity/__pycache__/stop.cpython-312.pyc | Bin 0 -> 5563 bytes .../__pycache__/tornadoweb.cpython-312.pyc | Bin 0 -> 2581 bytes .../tenacity/__pycache__/wait.cpython-312.pyc | Bin 0 -> 12408 bytes .../pip/_vendor/tenacity/_asyncio.py | 94 + .../pip/_vendor/tenacity/_utils.py | 76 + .../pip/_vendor/tenacity/after.py | 51 + .../pip/_vendor/tenacity/before.py | 46 + .../pip/_vendor/tenacity/before_sleep.py | 71 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/retry.py | 272 + .../pip/_vendor/tenacity/stop.py | 103 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 228 + .../pip/_vendor/tomli/__init__.py | 11 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 379 bytes .../tomli/__pycache__/_parser.cpython-312.pyc | Bin 0 -> 26922 bytes .../tomli/__pycache__/_re.cpython-312.pyc | Bin 0 -> 3903 bytes .../tomli/__pycache__/_types.cpython-312.pyc | Bin 0 -> 361 bytes .../pip/_vendor/tomli/_parser.py | 691 ++ .../site-packages/pip/_vendor/tomli/_re.py | 107 + .../site-packages/pip/_vendor/tomli/_types.py | 10 + .../pip/_vendor/typing_extensions.py | 3072 ++++++ .../pip/_vendor/urllib3/__init__.py | 102 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 3400 bytes .../__pycache__/_collections.cpython-312.pyc | Bin 0 -> 15926 bytes .../__pycache__/_version.cpython-312.pyc | Bin 0 -> 213 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 20402 bytes .../connectionpool.cpython-312.pyc | Bin 0 -> 36274 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 13488 bytes .../__pycache__/fields.cpython-312.pyc | Bin 0 -> 10408 bytes .../__pycache__/filepost.cpython-312.pyc | Bin 0 -> 4013 bytes .../__pycache__/poolmanager.cpython-312.pyc | Bin 0 -> 20297 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 6350 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 33961 bytes .../pip/_vendor/urllib3/_collections.py | 337 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 572 ++ .../pip/_vendor/urllib3/connectionpool.py | 1132 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 193 bytes .../_appengine_environ.cpython-312.pyc | Bin 0 -> 1843 bytes .../__pycache__/appengine.cpython-312.pyc | Bin 0 -> 11559 bytes .../__pycache__/ntlmpool.cpython-312.pyc | Bin 0 -> 5714 bytes .../__pycache__/pyopenssl.cpython-312.pyc | Bin 0 -> 24445 bytes .../securetransport.cpython-312.pyc | Bin 0 -> 35539 bytes .../contrib/__pycache__/socks.cpython-312.pyc | Bin 0 -> 7506 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 210 bytes .../__pycache__/bindings.cpython-312.pyc | Bin 0 -> 17422 bytes .../__pycache__/low_level.cpython-312.pyc | Bin 0 -> 14796 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 397 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 518 + .../urllib3/contrib/securetransport.py | 921 ++ .../pip/_vendor/urllib3/contrib/socks.py | 216 + .../pip/_vendor/urllib3/exceptions.py | 323 + .../pip/_vendor/urllib3/fields.py | 274 + .../pip/_vendor/urllib3/filepost.py | 98 + .../pip/_vendor/urllib3/packages/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 194 bytes .../packages/__pycache__/six.cpython-312.pyc | Bin 0 -> 41314 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 204 bytes .../__pycache__/makefile.cpython-312.pyc | Bin 0 -> 1815 bytes .../weakref_finalize.cpython-312.pyc | Bin 0 -> 7323 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 | 537 + .../pip/_vendor/urllib3/request.py | 170 + .../pip/_vendor/urllib3/response.py | 879 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 1141 bytes .../__pycache__/connection.cpython-312.pyc | Bin 0 -> 4751 bytes .../util/__pycache__/proxy.cpython-312.pyc | Bin 0 -> 1547 bytes .../util/__pycache__/queue.cpython-312.pyc | Bin 0 -> 1347 bytes .../util/__pycache__/request.cpython-312.pyc | Bin 0 -> 4178 bytes .../util/__pycache__/response.cpython-312.pyc | Bin 0 -> 2984 bytes .../util/__pycache__/retry.cpython-312.pyc | Bin 0 -> 21680 bytes .../util/__pycache__/ssl_.cpython-312.pyc | Bin 0 -> 15098 bytes .../ssl_match_hostname.cpython-312.pyc | Bin 0 -> 5066 bytes .../__pycache__/ssltransport.cpython-312.pyc | Bin 0 -> 10762 bytes .../util/__pycache__/timeout.cpython-312.pyc | Bin 0 -> 11134 bytes .../util/__pycache__/url.cpython-312.pyc | Bin 0 -> 15790 bytes .../util/__pycache__/wait.cpython-312.pyc | Bin 0 -> 4398 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 | 23 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 11990 bytes .../__pycache__/labels.cpython-312.pyc | Bin 0 -> 7127 bytes .../__pycache__/mklabels.cpython-312.pyc | Bin 0 -> 2691 bytes .../__pycache__/tests.cpython-312.pyc | Bin 0 -> 9034 bytes .../x_user_defined.cpython-312.pyc | Bin 0 -> 3290 bytes .../pip/_vendor/webencodings/labels.py | 231 + .../pip/_vendor/webencodings/mklabels.py | 59 + .../pip/_vendor/webencodings/tests.py | 153 + .../_vendor/webencodings/x_user_defined.py | 325 + .../lib/python3.12/site-packages/pip/py.typed | 4 + .../werkzeug-3.1.3.dist-info/INSTALLER | 1 + .../werkzeug-3.1.3.dist-info/LICENSE.txt | 28 + .../werkzeug-3.1.3.dist-info/METADATA | 99 + .../werkzeug-3.1.3.dist-info/RECORD | 116 + .../werkzeug-3.1.3.dist-info/WHEEL | 4 + .../site-packages/werkzeug/__init__.py | 4 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 328 bytes .../__pycache__/_internal.cpython-312.pyc | Bin 0 -> 9743 bytes .../__pycache__/_reloader.cpython-312.pyc | Bin 0 -> 20599 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 33314 bytes .../__pycache__/formparser.cpython-312.pyc | Bin 0 -> 17014 bytes .../werkzeug/__pycache__/http.cpython-312.pyc | Bin 0 -> 50239 bytes .../__pycache__/local.cpython-312.pyc | Bin 0 -> 28469 bytes .../__pycache__/security.cpython-312.pyc | Bin 0 -> 7122 bytes .../__pycache__/serving.cpython-312.pyc | Bin 0 -> 46107 bytes .../werkzeug/__pycache__/test.cpython-312.pyc | Bin 0 -> 59858 bytes .../__pycache__/testapp.cpython-312.pyc | Bin 0 -> 8879 bytes .../werkzeug/__pycache__/urls.cpython-312.pyc | Bin 0 -> 8258 bytes .../__pycache__/user_agent.cpython-312.pyc | Bin 0 -> 2141 bytes .../__pycache__/utils.cpython-312.pyc | Bin 0 -> 28132 bytes .../werkzeug/__pycache__/wsgi.cpython-312.pyc | Bin 0 -> 25204 bytes .../site-packages/werkzeug/_internal.py | 211 + .../site-packages/werkzeug/_reloader.py | 471 + .../werkzeug/datastructures/__init__.py | 64 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 2405 bytes .../__pycache__/accept.cpython-312.pyc | Bin 0 -> 15932 bytes .../__pycache__/auth.cpython-312.pyc | Bin 0 -> 14447 bytes .../__pycache__/cache_control.cpython-312.pyc | Bin 0 -> 12214 bytes .../__pycache__/csp.cpython-312.pyc | Bin 0 -> 6175 bytes .../__pycache__/etag.cpython-312.pyc | Bin 0 -> 5390 bytes .../__pycache__/file_storage.cpython-312.pyc | Bin 0 -> 8812 bytes .../__pycache__/headers.cpython-312.pyc | Bin 0 -> 30508 bytes .../__pycache__/mixins.cpython-312.pyc | Bin 0 -> 16388 bytes .../__pycache__/range.cpython-312.pyc | Bin 0 -> 10040 bytes .../__pycache__/structures.cpython-312.pyc | Bin 0 -> 59079 bytes .../werkzeug/datastructures/accept.py | 350 + .../werkzeug/datastructures/auth.py | 317 + .../werkzeug/datastructures/cache_control.py | 273 + .../werkzeug/datastructures/csp.py | 100 + .../werkzeug/datastructures/etag.py | 106 + .../werkzeug/datastructures/file_storage.py | 209 + .../werkzeug/datastructures/headers.py | 662 ++ .../werkzeug/datastructures/mixins.py | 317 + .../werkzeug/datastructures/range.py | 214 + .../werkzeug/datastructures/structures.py | 1239 +++ .../site-packages/werkzeug/debug/__init__.py | 565 ++ .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 23464 bytes .../debug/__pycache__/console.cpython-312.pyc | Bin 0 -> 11625 bytes .../debug/__pycache__/repr.cpython-312.pyc | Bin 0 -> 13798 bytes .../debug/__pycache__/tbtools.cpython-312.pyc | Bin 0 -> 16997 bytes .../site-packages/werkzeug/debug/console.py | 219 + .../site-packages/werkzeug/debug/repr.py | 282 + .../werkzeug/debug/shared/ICON_LICENSE.md | 6 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 344 + .../werkzeug/debug/shared/less.png | Bin 0 -> 191 bytes .../werkzeug/debug/shared/more.png | Bin 0 -> 200 bytes .../werkzeug/debug/shared/style.css | 150 + .../site-packages/werkzeug/debug/tbtools.py | 450 + .../site-packages/werkzeug/exceptions.py | 894 ++ .../site-packages/werkzeug/formparser.py | 430 + .../python3.12/site-packages/werkzeug/http.py | 1405 +++ .../site-packages/werkzeug/local.py | 653 ++ .../werkzeug/middleware/__init__.py | 0 .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 185 bytes .../__pycache__/dispatcher.cpython-312.pyc | Bin 0 -> 3303 bytes .../__pycache__/http_proxy.cpython-312.pyc | Bin 0 -> 9395 bytes .../__pycache__/lint.cpython-312.pyc | Bin 0 -> 17765 bytes .../__pycache__/profiler.cpython-312.pyc | Bin 0 -> 7189 bytes .../__pycache__/proxy_fix.cpython-312.pyc | Bin 0 -> 7186 bytes .../__pycache__/shared_data.cpython-312.pyc | Bin 0 -> 12741 bytes .../werkzeug/middleware/dispatcher.py | 81 + .../werkzeug/middleware/http_proxy.py | 236 + .../site-packages/werkzeug/middleware/lint.py | 439 + .../werkzeug/middleware/profiler.py | 155 + .../werkzeug/middleware/proxy_fix.py | 183 + .../werkzeug/middleware/shared_data.py | 283 + .../site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 134 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 4658 bytes .../__pycache__/converters.cpython-312.pyc | Bin 0 -> 10898 bytes .../__pycache__/exceptions.cpython-312.pyc | Bin 0 -> 7901 bytes .../routing/__pycache__/map.cpython-312.pyc | Bin 0 -> 39821 bytes .../__pycache__/matcher.cpython-312.pyc | Bin 0 -> 8269 bytes .../routing/__pycache__/rules.cpython-312.pyc | Bin 0 -> 39157 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 -> 181 bytes .../sansio/__pycache__/http.cpython-312.pyc | Bin 0 -> 5632 bytes .../__pycache__/multipart.cpython-312.pyc | Bin 0 -> 14040 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 21874 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 31729 bytes .../sansio/__pycache__/utils.cpython-312.pyc | Bin 0 -> 6171 bytes .../site-packages/werkzeug/sansio/http.py | 170 + .../werkzeug/sansio/multipart.py | 323 + .../site-packages/werkzeug/sansio/request.py | 534 + .../site-packages/werkzeug/sansio/response.py | 763 ++ .../site-packages/werkzeug/sansio/utils.py | 167 + .../site-packages/werkzeug/security.py | 166 + .../site-packages/werkzeug/serving.py | 1125 +++ .../python3.12/site-packages/werkzeug/test.py | 1464 +++ .../site-packages/werkzeug/testapp.py | 194 + .../python3.12/site-packages/werkzeug/urls.py | 203 + .../site-packages/werkzeug/user_agent.py | 47 + .../site-packages/werkzeug/utils.py | 691 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-312.pyc | Bin 0 -> 305 bytes .../__pycache__/request.cpython-312.pyc | Bin 0 -> 26135 bytes .../__pycache__/response.cpython-312.pyc | Bin 0 -> 34560 bytes .../werkzeug/wrappers/request.py | 650 ++ .../werkzeug/wrappers/response.py | 831 ++ .../python3.12/site-packages/werkzeug/wsgi.py | 595 ++ venv/lib64 | 1 + venv/pyvenv.cfg | 5 + 1343 files changed, 247431 insertions(+), 8 deletions(-) create mode 100644 sequence-login.puml create mode 100644 __pycache__/app.cpython-312.pyc create mode 100644 classes_flask_app.puml create mode 100644 filelist.txt create mode 100644 out/ sequence-login/sequence-login.png create mode 100644 out/classes_flask_app/classes_flask_app.png create mode 100644 out/sequence-create-item/sequence-create-item.png create mode 100644 sequence-create-item.puml create mode 100644 templates/create.html create mode 100644 templates/dashboard.html create mode 100644 templates/login.html create mode 100644 templates/logout.html create mode 100644 templates/success.html create mode 100644 venv/bin/Activate.ps1 create mode 100644 venv/bin/activate create mode 100644 venv/bin/activate.csh create mode 100644 venv/bin/activate.fish create mode 100755 venv/bin/flask create mode 100755 venv/bin/pip create mode 100755 venv/bin/pip3 create mode 100755 venv/bin/pip3.12 create mode 120000 venv/bin/python create mode 120000 venv/bin/python3 create mode 120000 venv/bin/python3.12 create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/blinker/__init__.py create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/_utilities.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/blinker/_utilities.py create mode 100644 venv/lib/python3.12/site-packages/blinker/base.py create mode 100644 venv/lib/python3.12/site-packages/blinker/py.typed create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/click-8.2.1.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/click/__init__.py create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_termui_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_textwrap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/_winconsole.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/decorators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/formatting.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/globals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/shell_completion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/termui.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/click/_compat.py create mode 100644 venv/lib/python3.12/site-packages/click/_termui_impl.py create mode 100644 venv/lib/python3.12/site-packages/click/_textwrap.py create mode 100644 venv/lib/python3.12/site-packages/click/_winconsole.py create mode 100644 venv/lib/python3.12/site-packages/click/core.py create mode 100644 venv/lib/python3.12/site-packages/click/decorators.py create mode 100644 venv/lib/python3.12/site-packages/click/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/click/formatting.py create mode 100644 venv/lib/python3.12/site-packages/click/globals.py create mode 100644 venv/lib/python3.12/site-packages/click/parser.py create mode 100644 venv/lib/python3.12/site-packages/click/py.typed create mode 100644 venv/lib/python3.12/site-packages/click/shell_completion.py create mode 100644 venv/lib/python3.12/site-packages/click/termui.py create mode 100644 venv/lib/python3.12/site-packages/click/testing.py create mode 100644 venv/lib/python3.12/site-packages/click/types.py create mode 100644 venv/lib/python3.12/site-packages/click/utils.py create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/flask/__init__.py create mode 100644 venv/lib/python3.12/site-packages/flask/__main__.py create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/app.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/blueprints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/cli.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/config.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/ctx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/debughelpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/globals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/signals.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/templating.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/typing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/__pycache__/wrappers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/app.py create mode 100644 venv/lib/python3.12/site-packages/flask/blueprints.py create mode 100644 venv/lib/python3.12/site-packages/flask/cli.py create mode 100644 venv/lib/python3.12/site-packages/flask/config.py create mode 100644 venv/lib/python3.12/site-packages/flask/ctx.py create mode 100644 venv/lib/python3.12/site-packages/flask/debughelpers.py create mode 100644 venv/lib/python3.12/site-packages/flask/globals.py create mode 100644 venv/lib/python3.12/site-packages/flask/helpers.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/__init__.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/json/provider.py create mode 100644 venv/lib/python3.12/site-packages/flask/json/tag.py create mode 100644 venv/lib/python3.12/site-packages/flask/logging.py create mode 100644 venv/lib/python3.12/site-packages/flask/py.typed create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/README.md create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/__pycache__/scaffold.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/app.py create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/blueprints.py create mode 100644 venv/lib/python3.12/site-packages/flask/sansio/scaffold.py create mode 100644 venv/lib/python3.12/site-packages/flask/sessions.py create mode 100644 venv/lib/python3.12/site-packages/flask/signals.py create mode 100644 venv/lib/python3.12/site-packages/flask/templating.py create mode 100644 venv/lib/python3.12/site-packages/flask/testing.py create mode 100644 venv/lib/python3.12/site-packages/flask/typing.py create mode 100644 venv/lib/python3.12/site-packages/flask/views.py create mode 100644 venv/lib/python3.12/site-packages/flask/wrappers.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__init__.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/exc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/serializer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/signer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/__pycache__/url_safe.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/_json.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/encoding.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/exc.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/py.typed create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/serializer.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/signer.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/timed.py create mode 100644 venv/lib/python3.12/site-packages/itsdangerous/url_safe.py create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/jinja2/__init__.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/async_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/compiler.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/constants.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/debug.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/defaults.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/idtracking.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/nativetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/optimizer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/runtime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/sandbox.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/__pycache__/visitor.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/jinja2/_identifier.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/async_utils.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/bccache.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/compiler.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/constants.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/debug.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/defaults.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/environment.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/ext.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/filters.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/idtracking.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/lexer.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/loaders.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/meta.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/nativetypes.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/nodes.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/optimizer.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/parser.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/py.typed create mode 100644 venv/lib/python3.12/site-packages/jinja2/runtime.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/sandbox.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/tests.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/utils.py create mode 100644 venv/lib/python3.12/site-packages/jinja2/visitor.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__init__.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markupsafe/__pycache__/_native.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_native.py create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_speedups.c create mode 100755 venv/lib/python3.12/site-packages/markupsafe/_speedups.cpython-312-x86_64-linux-gnu.so create mode 100644 venv/lib/python3.12/site-packages/markupsafe/_speedups.pyi create mode 100644 venv/lib/python3.12/site-packages/markupsafe/py.typed create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/AUTHORS.txt create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/REQUESTED create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/entry_points.txt create mode 100644 venv/lib/python3.12/site-packages/pip-23.2.1.dist-info/top_level.txt create mode 100644 venv/lib/python3.12/site-packages/pip/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pip-runner__.py create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/build_env.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/base_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/command_context.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/main_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/req_command.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/cli/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/completion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/debug.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/hash.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/list.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/search.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/show.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/commands/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/configuration.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/installed.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/sdist.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/distributions/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/collector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/package_finder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/index/sources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_distutils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/locations/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/main.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/_json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_dists.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/_envs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/candidate.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/direct_url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/format_control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/installation_report.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/scheme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/search_scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/target_python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/models/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/cache.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/download.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/session.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/build_tracker.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_editable.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/freeze.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/operations/prepare.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/pyproject.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/constructors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_install.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_set.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/self_outdated_check.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/inject_securetransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_jaraco_text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/_log.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/appdirs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/datetime.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/deprecation.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/egg_link.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/encoding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filesystem.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/filetypes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/glibc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/hashes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/misc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/packaging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/subprocess.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/unpacking.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/urls.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/utils/wheel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/git.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/subversion.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_internal/wheel_builder.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.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/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/certifi/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachinedict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabfreq.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/johabprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/macromanprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/resultdict.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf1632prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/codingstatemachinedict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/enums.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabfreq.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/johabprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/macromanprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/resultdict.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf1632prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/chardet/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansi_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/ansitowin32_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/initialise_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/isatty_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/__pycache__/winterm_test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansi_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/initialise_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/isatty_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/tests/winterm_test.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/win32.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/database.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/index.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/locators.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/resources.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/distlib/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/idna/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/codec.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/intranges.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/package_data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/markers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/tags.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/packaging/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/android.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/macos.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/unix.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/cmdline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/bbcode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/groff.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/html.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/img.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/irc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/latex.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/other.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/rtf.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/svg.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/terminal256.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/_mapping.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/python.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/modeline.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/plugin.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/regexopt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/scanner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/sphinxext.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/token.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/unistring.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pygments/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/actions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/common.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/core.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/helpers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/results.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/testing.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/unicode.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/__pycache__/util.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/actions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/common.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/core.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/diagram/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/helpers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/results.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/testing.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/unicode.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyparsing/util.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_impl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/__version__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/adapters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/api.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/auth.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/certs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/compat.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/cookies.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/help.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/hooks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/models.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/packages.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/sessions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/structures.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/requests/utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__main__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_cell_widths.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_codes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_emoji_replace.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_export_format.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_extension.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_fileno.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_inspect.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_log_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_loop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_null_file.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_palettes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_pick.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_ratio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_spinners.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_stack.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_timer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_win32_console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_windows_renderer.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/_wrap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/abc.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/align.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/ansi.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/box.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/cells.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/color_triplet.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/columns.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/console.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/constrain.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/containers.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/control.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/default_styles.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/diagnose.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/emoji.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/errors.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/file_proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/filesize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/highlighter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/json.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/jupyter.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/layout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/live_render.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/logging.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/markup.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/measure.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/padding.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/palette.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/panel.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/pretty.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/progress_bar.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/prompt.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/protocol.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/region.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/repr.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/rule.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/scope.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/screen.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/segment.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/spinner.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/status.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/style.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/styled.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/syntax.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/table.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/terminal_theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/text.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/theme.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/themes.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/traceback.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/rich/tree.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/after.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_re.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/tomli/_types.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/typing_extensions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/vendor.txt create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 venv/lib/python3.12/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 venv/lib/python3.12/site-packages/pip/py.typed create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/INSTALLER create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/LICENSE.txt create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/METADATA create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/RECORD create mode 100644 venv/lib/python3.12/site-packages/werkzeug-3.1.3.dist-info/WHEEL create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/_internal.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/_reloader.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/formparser.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/local.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/security.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/serving.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/test.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/testapp.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/urls.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/user_agent.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/__pycache__/wsgi.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/_internal.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/_reloader.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/accept.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/auth.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/cache_control.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/csp.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/etag.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/file_storage.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/headers.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/mixins.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/range.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/__pycache__/structures.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/accept.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/auth.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/cache_control.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/csp.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/etag.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/file_storage.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/headers.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/mixins.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/range.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/datastructures/structures.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/console.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/repr.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/console.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/repr.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/console.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/less.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/more.png create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/shared/style.css create mode 100644 venv/lib/python3.12/site-packages/werkzeug/debug/tbtools.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/formparser.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/http.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/local.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/lint.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/lint.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/profiler.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/middleware/shared_data.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/py.typed create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/converters.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/map.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/matcher.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/__pycache__/rules.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/converters.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/exceptions.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/map.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/matcher.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/routing/rules.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/http.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/__pycache__/utils.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/http.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/multipart.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/request.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/response.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/sansio/utils.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/security.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/serving.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/test.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/testapp.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/urls.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/user_agent.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/utils.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__init__.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/request.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/__pycache__/response.cpython-312.pyc create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/request.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wrappers/response.py create mode 100644 venv/lib/python3.12/site-packages/werkzeug/wsgi.py create mode 120000 venv/lib64 create mode 100644 venv/pyvenv.cfg diff --git a/ sequence-login.puml b/ sequence-login.puml new file mode 100644 index 00000000..6f64e8eb --- /dev/null +++ b/ sequence-login.puml @@ -0,0 +1,17 @@ +@startuml sequence-login +actor User +participant "Login Page" as LoginPage +participant "routes.py" as Route +participant "models.py" as UserModel + +User -> LoginPage : open form +User -> LoginPage : input username & password +LoginPage -> Route : POST /login +Route -> UserModel : validate_user() +UserModel --> Route : user exists or not +alt valid + Route --> LoginPage : redirect to dashboard +else invalid + Route --> LoginPage : show error +end +@enduml \ No newline at end of file diff --git a/__pycache__/app.cpython-312.pyc b/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0050afc5f408688e53aad91292bfa9ed90cf9922 GIT binary patch literal 728 zcmah{O=}ZD7@n`qZkiSpT4gKhdTCvduHaQFxikt=L@7cp%bFQYo88PZn-G#yN`>aw zTd!Uvo;~;%yeWc?2nA2xBDv)t&b#ThB8ao>`@!=(@5eCjmzEZgIq!O5^Oy18At??! z4W@5RaEv(OI7W5wB*qD;6O0HFM9?vwGwV#Sy-FcJ_xy~(*-JD&1?r`Lu&tsVFa5!` z1?6_@CPHf2=q{dDFCy;n@|%S*ndcbwaUc7YACPYQSX*0hl(l9!XcU6NQxi;K*<+*e z$@ai`D&mGr#EsWTl>h|h>}t@Hs+FZtLuA2D^~vK$534&{)gVgKjkK>>679BC*)T2h zXJCftq_U!H6Ac!FrtEo<5?)_+|388Iz>5;^g_Qi3mkXcCZU?0I@`2_C3MkNs|24|YxtmDdjm4%~F(u$(WP8R;D8~3JDt|+lzmzJY`v-DJ zPcS=l_ubK*gKIwt#+RlPkqZ-uCM86y9NYYeR{>lH@CtzI24st)!3XMoX7*uizjoxl QS{~Luv9$?BY&Bo`H?sAVVgLXD literal 0 HcmV?d00001 diff --git a/app.py b/app.py index 36721a06..a50f26f0 100644 --- a/app.py +++ b/app.py @@ -1,14 +1,47 @@ -import os -from flask import Flask +from flask import Flask, render_template, request, redirect, url_for, session + app = Flask(__name__) +app.secret_key = 'rahasia' # untuk session + +# Data login dummy +USER_CREDENTIALS = { + 'admin': 'admin' +} @app.route("/") -def main(): - return "Welcome!" +def index(): + return render_template("login.html") + +@app.route("/login", methods=["POST"]) +def login(): + username = request.form["username"] + password = request.form["password"] + if username in USER_CREDENTIALS and USER_CREDENTIALS[username] == password: + session['user'] = username + return redirect(url_for('dashboard')) + return "Login gagal! Coba lagi" + +@app.route("/dashboard") +def dashboard(): + if 'user' not in session: + return redirect(url_for('index')) + return render_template("dashboard.html") + +@app.route("/create", methods=["GET", "POST"]) +def create(): + if 'user' not in session: + return redirect(url_for('index')) + if request.method == "POST": + nama = request.form["nama"] + jumlah = request.form["jumlah"] + print(f"Data disimpan: {nama}, jumlah: {jumlah}") + return render_template("success.html") + return render_template("create.html") -@app.route('/how are you') -def hello(): - return 'I am good, how about you?' +@app.route("/logout") +def logout(): + session.pop('user', None) + return render_template("logout.html") if __name__ == "__main__": - app.run(host="0.0.0.0", port=8080) + app.run(host="0.0.0.0", port=8080) \ No newline at end of file diff --git a/classes_flask_app.puml b/classes_flask_app.puml new file mode 100644 index 00000000..869cbf7d --- /dev/null +++ b/classes_flask_app.puml @@ -0,0 +1,3 @@ +@startuml classes_flask_app +set namespaceSeparator none +@enduml diff --git a/filelist.txt b/filelist.txt new file mode 100644 index 00000000..e69de29b diff --git a/out/ sequence-login/sequence-login.png b/out/ sequence-login/sequence-login.png new file mode 100644 index 0000000000000000000000000000000000000000..4d695a10ef67a82124aebc1d002f054da967b2b3 GIT binary patch literal 19713 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 literal 0 HcmV?d00001 diff --git a/out/classes_flask_app/classes_flask_app.png b/out/classes_flask_app/classes_flask_app.png new file mode 100644 index 0000000000000000000000000000000000000000..2850fb0d0769fce74ed0a513f17fe87a6cf7624f GIT binary patch literal 377 zcmeAS@N?(olHy`uVBq!ia0vp^Y#_|R1SIp}OaHd(YLz7%X`x$}dMFBt*5+uN7as2DRG;Op@^4;ZV?^x9Z`-TWg+7lwo}xu*P6bzQjNdRl8UdpEqg^he%iT6ZsBMauMD50*B{-q)Npq2pRvRMpgf@5TKCCV!du z>q%PUTHmgTe~DWM4fub7%7 literal 0 HcmV?d00001 diff --git a/out/sequence-create-item/sequence-create-item.png b/out/sequence-create-item/sequence-create-item.png new file mode 100644 index 0000000000000000000000000000000000000000..f8064c562c5d5a153b58602440b58a4e74adb11c GIT binary patch literal 14972 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 LxL+vt`1$_=3kg27 literal 0 HcmV?d00001 diff --git a/sequence-create-item.puml b/sequence-create-item.puml new file mode 100644 index 00000000..4494ab01 --- /dev/null +++ b/sequence-create-item.puml @@ -0,0 +1,13 @@ +@startuml sequence-create-item +actor User +participant "Create Item Page" as ItemPage +participant "routes.py" as Route +participant "models.py" as ItemModel + +User -> ItemPage : open form +User -> ItemPage : input item data +ItemPage -> Route : POST /create +Route -> ItemModel : save new item +ItemModel --> Route : success +Route --> ItemPage : show confirmation +@enduml \ No newline at end of file diff --git a/templates/create.html b/templates/create.html new file mode 100644 index 00000000..8abfb627 --- /dev/null +++ b/templates/create.html @@ -0,0 +1,13 @@ + + +Buat Item + +

Form Buat Item

+
+ Nama:

+ Jumlah:

+ +
+ Kembali + + \ No newline at end of file diff --git a/templates/dashboard.html b/templates/dashboard.html new file mode 100644 index 00000000..f0fdb416 --- /dev/null +++ b/templates/dashboard.html @@ -0,0 +1,9 @@ + + +Dashboard + +

Selamat datang, {{ session['user'] }}

+ Tambah Item
+ Logout + + \ No newline at end of file diff --git a/templates/login.html b/templates/login.html new file mode 100644 index 00000000..497c70a3 --- /dev/null +++ b/templates/login.html @@ -0,0 +1,12 @@ + + +Login + +

Login

+
+ Username:

+ Password:

+ +
+ + \ No newline at end of file diff --git a/templates/logout.html b/templates/logout.html new file mode 100644 index 00000000..2b47b996 --- /dev/null +++ b/templates/logout.html @@ -0,0 +1,8 @@ + + +Logout + +

Anda telah logout

+ Login kembali + + \ No newline at end of file diff --git a/templates/success.html b/templates/success.html new file mode 100644 index 00000000..1ec88f04 --- /dev/null +++ b/templates/success.html @@ -0,0 +1,8 @@ + + +Berhasil + +

Item berhasil disimpan!

+ Kembali ke Dashboard + + \ No newline at end of file diff --git a/venv/bin/Activate.ps1 b/venv/bin/Activate.ps1 new file mode 100644 index 00000000..b49d77ba --- /dev/null +++ b/venv/bin/Activate.ps1 @@ -0,0 +1,247 @@ +<# +.Synopsis +Activate a Python virtual environment for the current PowerShell session. + +.Description +Pushes the python executable for a virtual environment to the front of the +$Env:PATH environment variable and sets the prompt to signify that you are +in a Python virtual environment. Makes use of the command line switches as +well as the `pyvenv.cfg` file values present in the virtual environment. + +.Parameter VenvDir +Path to the directory that contains the virtual environment to activate. The +default value for this is the parent of the directory that the Activate.ps1 +script is located within. + +.Parameter Prompt +The prompt prefix to display when this virtual environment is activated. By +default, this prompt is the name of the virtual environment folder (VenvDir) +surrounded by parentheses and followed by a single space (ie. '(.venv) '). + +.Example +Activate.ps1 +Activates the Python virtual environment that contains the Activate.ps1 script. + +.Example +Activate.ps1 -Verbose +Activates the Python virtual environment that contains the Activate.ps1 script, +and shows extra information about the activation as it executes. + +.Example +Activate.ps1 -VenvDir C:\Users\MyUser\Common\.venv +Activates the Python virtual environment located in the specified location. + +.Example +Activate.ps1 -Prompt "MyPython" +Activates the Python virtual environment that contains the Activate.ps1 script, +and prefixes the current prompt with the specified string (surrounded in +parentheses) while the virtual environment is active. + +.Notes +On Windows, it may be required to enable this Activate.ps1 script by setting the +execution policy for the user. You can do this by issuing the following PowerShell +command: + +PS C:\> Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser + +For more information on Execution Policies: +https://go.microsoft.com/fwlink/?LinkID=135170 + +#> +Param( + [Parameter(Mandatory = $false)] + [String] + $VenvDir, + [Parameter(Mandatory = $false)] + [String] + $Prompt +) + +<# Function declarations --------------------------------------------------- #> + +<# +.Synopsis +Remove all shell session elements added by the Activate script, including the +addition of the virtual environment's Python executable from the beginning of +the PATH variable. + +.Parameter NonDestructive +If present, do not remove this function from the global namespace for the +session. + +#> +function global:deactivate ([switch]$NonDestructive) { + # Revert to original values + + # The prior prompt: + if (Test-Path -Path Function:_OLD_VIRTUAL_PROMPT) { + Copy-Item -Path Function:_OLD_VIRTUAL_PROMPT -Destination Function:prompt + Remove-Item -Path Function:_OLD_VIRTUAL_PROMPT + } + + # The prior PYTHONHOME: + if (Test-Path -Path Env:_OLD_VIRTUAL_PYTHONHOME) { + Copy-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME -Destination Env:PYTHONHOME + Remove-Item -Path Env:_OLD_VIRTUAL_PYTHONHOME + } + + # The prior PATH: + if (Test-Path -Path Env:_OLD_VIRTUAL_PATH) { + Copy-Item -Path Env:_OLD_VIRTUAL_PATH -Destination Env:PATH + Remove-Item -Path Env:_OLD_VIRTUAL_PATH + } + + # Just remove the VIRTUAL_ENV altogether: + if (Test-Path -Path Env:VIRTUAL_ENV) { + Remove-Item -Path env:VIRTUAL_ENV + } + + # Just remove VIRTUAL_ENV_PROMPT altogether. + if (Test-Path -Path Env:VIRTUAL_ENV_PROMPT) { + Remove-Item -Path env:VIRTUAL_ENV_PROMPT + } + + # Just remove the _PYTHON_VENV_PROMPT_PREFIX altogether: + if (Get-Variable -Name "_PYTHON_VENV_PROMPT_PREFIX" -ErrorAction SilentlyContinue) { + Remove-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Scope Global -Force + } + + # Leave deactivate function in the global namespace if requested: + if (-not $NonDestructive) { + Remove-Item -Path function:deactivate + } +} + +<# +.Description +Get-PyVenvConfig parses the values from the pyvenv.cfg file located in the +given folder, and returns them in a map. + +For each line in the pyvenv.cfg file, if that line can be parsed into exactly +two strings separated by `=` (with any amount of whitespace surrounding the =) +then it is considered a `key = value` line. The left hand string is the key, +the right hand is the value. + +If the value starts with a `'` or a `"` then the first and last character is +stripped from the value before being captured. + +.Parameter ConfigDir +Path to the directory that contains the `pyvenv.cfg` file. +#> +function Get-PyVenvConfig( + [String] + $ConfigDir +) { + Write-Verbose "Given ConfigDir=$ConfigDir, obtain values in pyvenv.cfg" + + # Ensure the file exists, and issue a warning if it doesn't (but still allow the function to continue). + $pyvenvConfigPath = Join-Path -Resolve -Path $ConfigDir -ChildPath 'pyvenv.cfg' -ErrorAction Continue + + # An empty map will be returned if no config file is found. + $pyvenvConfig = @{ } + + if ($pyvenvConfigPath) { + + Write-Verbose "File exists, parse `key = value` lines" + $pyvenvConfigContent = Get-Content -Path $pyvenvConfigPath + + $pyvenvConfigContent | ForEach-Object { + $keyval = $PSItem -split "\s*=\s*", 2 + if ($keyval[0] -and $keyval[1]) { + $val = $keyval[1] + + # Remove extraneous quotations around a string value. + if ("'""".Contains($val.Substring(0, 1))) { + $val = $val.Substring(1, $val.Length - 2) + } + + $pyvenvConfig[$keyval[0]] = $val + Write-Verbose "Adding Key: '$($keyval[0])'='$val'" + } + } + } + return $pyvenvConfig +} + + +<# Begin Activate script --------------------------------------------------- #> + +# Determine the containing directory of this script +$VenvExecPath = Split-Path -Parent $MyInvocation.MyCommand.Definition +$VenvExecDir = Get-Item -Path $VenvExecPath + +Write-Verbose "Activation script is located in path: '$VenvExecPath'" +Write-Verbose "VenvExecDir Fullname: '$($VenvExecDir.FullName)" +Write-Verbose "VenvExecDir Name: '$($VenvExecDir.Name)" + +# Set values required in priority: CmdLine, ConfigFile, Default +# First, get the location of the virtual environment, it might not be +# VenvExecDir if specified on the command line. +if ($VenvDir) { + Write-Verbose "VenvDir given as parameter, using '$VenvDir' to determine values" +} +else { + Write-Verbose "VenvDir not given as a parameter, using parent directory name as VenvDir." + $VenvDir = $VenvExecDir.Parent.FullName.TrimEnd("\\/") + Write-Verbose "VenvDir=$VenvDir" +} + +# Next, read the `pyvenv.cfg` file to determine any required value such +# as `prompt`. +$pyvenvCfg = Get-PyVenvConfig -ConfigDir $VenvDir + +# Next, set the prompt from the command line, or the config file, or +# just use the name of the virtual environment folder. +if ($Prompt) { + Write-Verbose "Prompt specified as argument, using '$Prompt'" +} +else { + Write-Verbose "Prompt not specified as argument to script, checking pyvenv.cfg value" + if ($pyvenvCfg -and $pyvenvCfg['prompt']) { + Write-Verbose " Setting based on value in pyvenv.cfg='$($pyvenvCfg['prompt'])'" + $Prompt = $pyvenvCfg['prompt']; + } + else { + Write-Verbose " Setting prompt based on parent's directory's name. (Is the directory name passed to venv module when creating the virtual environment)" + Write-Verbose " Got leaf-name of $VenvDir='$(Split-Path -Path $venvDir -Leaf)'" + $Prompt = Split-Path -Path $venvDir -Leaf + } +} + +Write-Verbose "Prompt = '$Prompt'" +Write-Verbose "VenvDir='$VenvDir'" + +# Deactivate any currently active virtual environment, but leave the +# deactivate function in place. +deactivate -nondestructive + +# Now set the environment variable VIRTUAL_ENV, used by many tools to determine +# that there is an activated venv. +$env:VIRTUAL_ENV = $VenvDir + +if (-not $Env:VIRTUAL_ENV_DISABLE_PROMPT) { + + Write-Verbose "Setting prompt to '$Prompt'" + + # Set the prompt to include the env name + # Make sure _OLD_VIRTUAL_PROMPT is global + function global:_OLD_VIRTUAL_PROMPT { "" } + Copy-Item -Path function:prompt -Destination function:_OLD_VIRTUAL_PROMPT + New-Variable -Name _PYTHON_VENV_PROMPT_PREFIX -Description "Python virtual environment prompt prefix" -Scope Global -Option ReadOnly -Visibility Public -Value $Prompt + + function global:prompt { + Write-Host -NoNewline -ForegroundColor Green "($_PYTHON_VENV_PROMPT_PREFIX) " + _OLD_VIRTUAL_PROMPT + } + $env:VIRTUAL_ENV_PROMPT = $Prompt +} + +# Clear PYTHONHOME +if (Test-Path -Path Env:PYTHONHOME) { + Copy-Item -Path Env:PYTHONHOME -Destination Env:_OLD_VIRTUAL_PYTHONHOME + Remove-Item -Path Env:PYTHONHOME +} + +# Add the venv to the PATH +Copy-Item -Path Env:PATH -Destination Env:_OLD_VIRTUAL_PATH +$Env:PATH = "$VenvExecDir$([System.IO.Path]::PathSeparator)$Env:PATH" diff --git a/venv/bin/activate b/venv/bin/activate new file mode 100644 index 00000000..7a749e2e --- /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 "/workspaces/UASRPLAUFA/venv") +else + # use the path as-is + export VIRTUAL_ENV="/workspaces/UASRPLAUFA/venv" +fi + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/bin:$PATH" +export PATH + +# unset PYTHONHOME if set +# this will fail if PYTHONHOME is set to the empty string (which is bad anyway) +# could use `if (set -u; : $PYTHONHOME) ;` in bash +if [ -n "${PYTHONHOME:-}" ] ; then + _OLD_VIRTUAL_PYTHONHOME="${PYTHONHOME:-}" + unset PYTHONHOME +fi + +if [ -z "${VIRTUAL_ENV_DISABLE_PROMPT:-}" ] ; then + _OLD_VIRTUAL_PS1="${PS1:-}" + PS1="(venv) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(venv) " + export VIRTUAL_ENV_PROMPT +fi + +# Call hash to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +hash -r 2> /dev/null diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh new file mode 100644 index 00000000..6f2ce1c0 --- /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 "/workspaces/UASRPLAUFA/venv" + +set _OLD_VIRTUAL_PATH="$PATH" +setenv PATH "$VIRTUAL_ENV/bin:$PATH" + + +set _OLD_VIRTUAL_PROMPT="$prompt" + +if (! "$?VIRTUAL_ENV_DISABLE_PROMPT") then + set prompt = "(venv) $prompt" + setenv VIRTUAL_ENV_PROMPT "(venv) " +endif + +alias pydoc python -m pydoc + +rehash diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish new file mode 100644 index 00000000..fe986a64 --- /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 "/workspaces/UASRPLAUFA/venv" + +set -gx _OLD_VIRTUAL_PATH $PATH +set -gx PATH "$VIRTUAL_ENV/bin" $PATH + +# Unset PYTHONHOME if set. +if set -q PYTHONHOME + set -gx _OLD_VIRTUAL_PYTHONHOME $PYTHONHOME + set -e PYTHONHOME +end + +if test -z "$VIRTUAL_ENV_DISABLE_PROMPT" + # fish uses a function instead of an env var to generate the prompt. + + # Save the current fish_prompt function as the function _old_fish_prompt. + functions -c fish_prompt _old_fish_prompt + + # With the original prompt function renamed, we can override with our own. + function fish_prompt + # Save the return status of the last command. + set -l old_status $status + + # Output the venv prompt; color taken from the blue of the Python logo. + printf "%s%s%s" (set_color 4B8BBE) "(venv) " (set_color normal) + + # Restore the return status of the previous command. + echo "exit $old_status" | . + # Output the original/"old" prompt. + _old_fish_prompt + end + + set -gx _OLD_FISH_PROMPT_OVERRIDE "$VIRTUAL_ENV" + set -gx VIRTUAL_ENV_PROMPT "(venv) " +end diff --git a/venv/bin/flask b/venv/bin/flask new file mode 100755 index 00000000..d0eded5f --- /dev/null +++ b/venv/bin/flask @@ -0,0 +1,8 @@ +#!/workspaces/UASRPLAUFA/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from flask.cli import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip b/venv/bin/pip new file mode 100755 index 00000000..d00480da --- /dev/null +++ b/venv/bin/pip @@ -0,0 +1,8 @@ +#!/workspaces/UASRPLAUFA/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3 b/venv/bin/pip3 new file mode 100755 index 00000000..d00480da --- /dev/null +++ b/venv/bin/pip3 @@ -0,0 +1,8 @@ +#!/workspaces/UASRPLAUFA/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/pip3.12 b/venv/bin/pip3.12 new file mode 100755 index 00000000..d00480da --- /dev/null +++ b/venv/bin/pip3.12 @@ -0,0 +1,8 @@ +#!/workspaces/UASRPLAUFA/venv/bin/python3 +# -*- coding: utf-8 -*- +import re +import sys +from pip._internal.cli.main import main +if __name__ == '__main__': + sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0]) + sys.exit(main()) diff --git a/venv/bin/python b/venv/bin/python new file mode 120000 index 00000000..b8a0adbb --- /dev/null +++ b/venv/bin/python @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/bin/python3 b/venv/bin/python3 new file mode 120000 index 00000000..eba85511 --- /dev/null +++ b/venv/bin/python3 @@ -0,0 +1 @@ +/home/codespace/.python/current/bin/python3 \ No newline at end of file diff --git a/venv/bin/python3.12 b/venv/bin/python3.12 new file mode 120000 index 00000000..b8a0adbb --- /dev/null +++ b/venv/bin/python3.12 @@ -0,0 +1 @@ +python3 \ No newline at end of file diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt new file mode 100644 index 00000000..9d227a0c --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA new file mode 100644 index 00000000..82261f2a --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/METADATA @@ -0,0 +1,92 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 3.0.2 +Summary: Safely add untrusted strings to HTML/XML markup. +Maintainer-email: Pallets +License: Copyright 2010 Pallets + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED + TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source, https://github.com/pallets/markupsafe/ +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Classifier: Typing :: Typed +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-File: LICENSE.txt + +# MarkupSafe + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +## Examples + +```pycon +>>> from markupsafe import Markup, escape + +>>> # escape replaces special characters and wraps in Markup +>>> escape("") +Markup('<script>alert(document.cookie);</script>') + +>>> # wrap in Markup to mark text "safe" and prevent escaping +>>> Markup("Hello") +Markup('hello') + +>>> escape(Markup("Hello")) +Markup('hello') + +>>> # Markup is a str subclass +>>> # methods and operators escape their arguments +>>> template = Markup("Hello {name}") +>>> template.format(name='"World"') +Markup('Hello "World"') +``` + +## Donate + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +[please donate today][]. + +[please donate today]: https://palletsprojects.com/donate diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD new file mode 100644 index 00000000..b7ba0b7b --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-3.0.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-3.0.2.dist-info/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +MarkupSafe-3.0.2.dist-info/METADATA,sha256=aAwbZhSmXdfFuMM-rEHpeiHRkBOGESyVLJIuwzHP-nw,3975 +MarkupSafe-3.0.2.dist-info/RECORD,, +MarkupSafe-3.0.2.dist-info/WHEEL,sha256=OVgtqZzfzIXXtylXP90gxCZ6CKBCwKYyHM8PpMEjN1M,151 +MarkupSafe-3.0.2.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=sr-U6_27DfaSrj5jnHYxWN-pvhM27sjlDplMDPZKm7k,13214 +markupsafe/__pycache__/__init__.cpython-312.pyc,, +markupsafe/__pycache__/_native.cpython-312.pyc,, +markupsafe/_native.py,sha256=hSLs8Jmz5aqayuengJJ3kdT5PwNpBWpKrmQSdipndC8,210 +markupsafe/_speedups.c,sha256=O7XulmTo-epI6n2FtMVOrJXl8EAaIwD2iNYmBI5SEoQ,4149 +markupsafe/_speedups.cpython-312-x86_64-linux-gnu.so,sha256=t1DBZlpsjFA30BOOvXfXfT1wvO_4cS16VbHz1-49q5U,43432 +markupsafe/_speedups.pyi,sha256=ENd1bYe7gbBUf2ywyYWOGUpnXOHNJ-cgTNqetlW8h5k,41 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL new file mode 100644 index 00000000..057fef67 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: setuptools (75.2.0) +Root-Is-Purelib: false +Tag: cp312-cp312-manylinux_2_17_x86_64 +Tag: cp312-cp312-manylinux2014_x86_64 + diff --git a/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt new file mode 100644 index 00000000..75bf7292 --- /dev/null +++ b/venv/lib/python3.12/site-packages/MarkupSafe-3.0.2.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt new file mode 100644 index 00000000..79c9825a --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/LICENSE.txt @@ -0,0 +1,20 @@ +Copyright 2010 Jason Kirtland + +Permission is hereby granted, free of charge, to any person obtaining a +copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be included +in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA new file mode 100644 index 00000000..6d343f57 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.3 +Name: blinker +Version: 1.9.0 +Summary: Fast, simple object-to-object and broadcast signaling +Author: Jason Kirtland +Maintainer-email: Pallets Ecosystem +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: License :: OSI Approved :: MIT License +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://blinker.readthedocs.io +Project-URL: Source, https://github.com/pallets-eco/blinker/ + +# Blinker + +Blinker provides a fast dispatching system that allows any number of +interested parties to subscribe to events, or "signals". + + +## Pallets Community Ecosystem + +> [!IMPORTANT]\ +> This project is part of the Pallets Community Ecosystem. Pallets is the open +> source organization that maintains Flask; Pallets-Eco enables community +> maintenance of related projects. If you are interested in helping maintain +> this project, please reach out on [the Pallets Discord server][discord]. +> +> [discord]: https://discord.gg/pallets + + +## Example + +Signal receivers can subscribe to specific senders or receive signals +sent by any sender. + +```pycon +>>> from blinker import signal +>>> started = signal('round-started') +>>> def each(round): +... print(f"Round {round}") +... +>>> started.connect(each) + +>>> def round_two(round): +... print("This is round two.") +... +>>> started.connect(round_two, sender=2) + +>>> for round in range(1, 4): +... started.send(round) +... +Round 1! +Round 2! +This is round two. +Round 3! +``` + diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD new file mode 100644 index 00000000..7cfb7148 --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/RECORD @@ -0,0 +1,12 @@ +blinker-1.9.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +blinker-1.9.0.dist-info/LICENSE.txt,sha256=nrc6HzhZekqhcCXSrhvjg5Ykx5XphdTw6Xac4p-spGc,1054 +blinker-1.9.0.dist-info/METADATA,sha256=uIRiM8wjjbHkCtbCyTvctU37IAZk0kEe5kxAld1dvzA,1633 +blinker-1.9.0.dist-info/RECORD,, +blinker-1.9.0.dist-info/WHEEL,sha256=CpUCUxeHQbRN5UGRQHYRJorO5Af-Qy_fHMctcQ8DSGI,82 +blinker/__init__.py,sha256=I2EdZqpy4LyjX17Hn1yzJGWCjeLaVaPzsMgHkLfj_cQ,317 +blinker/__pycache__/__init__.cpython-312.pyc,, +blinker/__pycache__/_utilities.cpython-312.pyc,, +blinker/__pycache__/base.cpython-312.pyc,, +blinker/_utilities.py,sha256=0J7eeXXTUx0Ivf8asfpx0ycVkp0Eqfqnj117x2mYX9E,1675 +blinker/base.py,sha256=QpDuvXXcwJF49lUBcH5BiST46Rz9wSG7VW_p7N_027M,19132 +blinker/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL new file mode 100644 index 00000000..e3c6feef --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker-1.9.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.10.1 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/blinker/__init__.py b/venv/lib/python3.12/site-packages/blinker/__init__.py new file mode 100644 index 00000000..1772fa4a --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/__init__.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from .base import ANY +from .base import default_namespace +from .base import NamedSignal +from .base import Namespace +from .base import Signal +from .base import signal + +__all__ = [ + "ANY", + "default_namespace", + "NamedSignal", + "Namespace", + "Signal", + "signal", +] diff --git a/venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/blinker/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9fedb27f7e1c6339bef2728c1bdd60749b3f8ae5 GIT binary patch literal 485 zcmaKoy-ve05Xa9+ny;!t9gvU^12A=<5wHSM79^yqLR1~dVqD_3Q5~mB(n3d`f}M?L z;SC~XLJZvy-8ykjRYp$M-@iNGo$dQ*G+aQtd8Xq_0`RGvt!Wz|s|SQv2q7c_ViFJn zp%&^wi}gUS*g!S{qv9HJEvQv&BAbC(v4v~}R>d~59oPg$5IS!pa29T>zEsz>NKt1} zCOONaL}p8TlZxqn_a3)q$cJnuaw=KOvnhMzD!+?P*o#Jz33MIhZqLlWu$gTV%(R9r zQ&Wkh#8%=cQIqJl+`^@FILl`#r!>_uRu}`8@&D@zi&7>8rSGu95?FVCCVr^f< tNjMYyDs5tOHI(cSIapZsuCsIK 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 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 00000000..000c902a --- /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 00000000..d051b94a --- /dev/null +++ b/venv/lib/python3.12/site-packages/blinker/base.py @@ -0,0 +1,512 @@ +from __future__ import annotations + +import collections.abc as c +import sys +import typing as t +import weakref +from collections import defaultdict +from contextlib import contextmanager +from functools import cached_property +from inspect import iscoroutinefunction + +from ._utilities import make_id +from ._utilities import make_ref +from ._utilities import Symbol + +F = t.TypeVar("F", bound=c.Callable[..., t.Any]) + +ANY = Symbol("ANY") +"""Symbol for "any sender".""" + +ANY_ID = 0 + + +class Signal: + """A notification emitter. + + :param doc: The docstring for the signal. + """ + + ANY = ANY + """An alias for the :data:`~blinker.ANY` sender symbol.""" + + set_class: type[set[t.Any]] = set + """The set class to use for tracking connected receivers and senders. + Python's ``set`` is unordered. If receivers must be dispatched in the order + they were connected, an ordered set implementation can be used. + + .. versionadded:: 1.7 + """ + + @cached_property + def receiver_connected(self) -> Signal: + """Emitted at the end of each :meth:`connect` call. + + The signal sender is the signal instance, and the :meth:`connect` + arguments are passed through: ``receiver``, ``sender``, and ``weak``. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver connects.") + + @cached_property + def receiver_disconnected(self) -> Signal: + """Emitted at the end of each :meth:`disconnect` call. + + The sender is the signal instance, and the :meth:`disconnect` arguments + are passed through: ``receiver`` and ``sender``. + + This signal is emitted **only** when :meth:`disconnect` is called + explicitly. This signal cannot be emitted by an automatic disconnect + when a weakly referenced receiver or sender goes out of scope, as the + instance is no longer be available to be used as the sender for this + signal. + + An alternative approach is available by subscribing to + :attr:`receiver_connected` and setting up a custom weakref cleanup + callback on weak receivers and senders. + + .. versionadded:: 1.2 + """ + return Signal(doc="Emitted after a receiver disconnects.") + + def __init__(self, doc: str | None = None) -> None: + if doc: + self.__doc__ = doc + + self.receivers: dict[ + t.Any, weakref.ref[c.Callable[..., t.Any]] | c.Callable[..., t.Any] + ] = {} + """The map of connected receivers. Useful to quickly check if any + receivers are connected to the signal: ``if s.receivers:``. The + structure and data is not part of the public API, but checking its + boolean value is. + """ + + self.is_muted: bool = False + self._by_receiver: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._by_sender: dict[t.Any, set[t.Any]] = defaultdict(self.set_class) + self._weak_senders: dict[t.Any, weakref.ref[t.Any]] = {} + + def connect(self, receiver: F, sender: t.Any = ANY, weak: bool = True) -> F: + """Connect ``receiver`` to be called when the signal is sent by + ``sender``. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends. + """ + receiver_id = make_id(receiver) + sender_id = ANY_ID if sender is ANY else make_id(sender) + + if weak: + self.receivers[receiver_id] = make_ref( + receiver, self._make_cleanup_receiver(receiver_id) + ) + else: + self.receivers[receiver_id] = receiver + + self._by_sender[sender_id].add(receiver_id) + self._by_receiver[receiver_id].add(sender_id) + + if sender is not ANY and sender_id not in self._weak_senders: + # store a cleanup for weakref-able senders + try: + self._weak_senders[sender_id] = make_ref( + sender, self._make_cleanup_sender(sender_id) + ) + except TypeError: + pass + + if "receiver_connected" in self.__dict__ and self.receiver_connected.receivers: + try: + self.receiver_connected.send( + self, receiver=receiver, sender=sender, weak=weak + ) + except TypeError: + # TODO no explanation or test for this + self.disconnect(receiver, sender) + raise + + return receiver + + def connect_via(self, sender: t.Any, weak: bool = False) -> c.Callable[[F], F]: + """Connect the decorated function to be called when the signal is sent + by ``sender``. + + The decorated function will be called when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument along + with any extra keyword arguments. + + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. A receiver may be connected + to multiple senders by calling :meth:`connect` multiple times. + :param weak: Track the receiver with a :mod:`weakref`. The receiver will + be automatically disconnected when it is garbage collected. When + connecting a receiver defined within a function, set to ``False``, + otherwise it will be disconnected when the function scope ends.= + + .. versionadded:: 1.1 + """ + + def decorator(fn: F) -> F: + self.connect(fn, sender, weak) + return fn + + return decorator + + @contextmanager + def connected_to( + self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY + ) -> c.Generator[None, None, None]: + """A context manager that temporarily connects ``receiver`` to the + signal while a ``with`` block executes. When the block exits, the + receiver is disconnected. Useful for tests. + + :param receiver: The callable to call when :meth:`send` is called with + the given ``sender``, passing ``sender`` as a positional argument + along with any extra keyword arguments. + :param sender: Any object or :data:`ANY`. ``receiver`` will only be + called when :meth:`send` is called with this sender. If ``ANY``, the + receiver will be called for any sender. + + .. versionadded:: 1.1 + """ + self.connect(receiver, sender=sender, weak=False) + + try: + yield None + finally: + self.disconnect(receiver) + + @contextmanager + def muted(self) -> c.Generator[None, None, None]: + """A context manager that temporarily disables the signal. No receivers + will be called if the signal is sent, until the ``with`` block exits. + Useful for tests. + """ + self.is_muted = True + + try: + yield None + finally: + self.is_muted = False + + def send( + self, + sender: t.Any | None = None, + /, + *, + _async_wrapper: c.Callable[ + [c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]]], c.Callable[..., t.Any] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Call all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _async_wrapper: Will be called on any receivers that are async + coroutines to turn them into sync callables. For example, could run + the receiver with an event loop. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionchanged:: 1.7 + Added the ``_async_wrapper`` argument. + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if iscoroutinefunction(receiver): + if _async_wrapper is None: + raise RuntimeError("Cannot send to a coroutine function.") + + result = _async_wrapper(receiver)(sender, **kwargs) + else: + result = receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + async def send_async( + self, + sender: t.Any | None = None, + /, + *, + _sync_wrapper: c.Callable[ + [c.Callable[..., t.Any]], c.Callable[..., c.Coroutine[t.Any, t.Any, t.Any]] + ] + | None = None, + **kwargs: t.Any, + ) -> list[tuple[c.Callable[..., t.Any], t.Any]]: + """Await all receivers that are connected to the given ``sender`` + or :data:`ANY`. Each receiver is called with ``sender`` as a positional + argument along with any extra keyword arguments. Return a list of + ``(receiver, return value)`` tuples. + + The order receivers are called is undefined, but can be influenced by + setting :attr:`set_class`. + + If a receiver raises an exception, that exception will propagate up. + This makes debugging straightforward, with an assumption that correctly + implemented receivers will not raise. + + :param sender: Call receivers connected to this sender, in addition to + those connected to :data:`ANY`. + :param _sync_wrapper: Will be called on any receivers that are sync + callables to turn them into async coroutines. For example, + could call the receiver in a thread. + :param kwargs: Extra keyword arguments to pass to each receiver. + + .. versionadded:: 1.7 + """ + if self.is_muted: + return [] + + results = [] + + for receiver in self.receivers_for(sender): + if not iscoroutinefunction(receiver): + if _sync_wrapper is None: + raise RuntimeError("Cannot send to a non-coroutine function.") + + result = await _sync_wrapper(receiver)(sender, **kwargs) + else: + result = await receiver(sender, **kwargs) + + results.append((receiver, result)) + + return results + + def has_receivers_for(self, sender: t.Any) -> bool: + """Check if there is at least one receiver that will be called with the + given ``sender``. A receiver connected to :data:`ANY` will always be + called, regardless of sender. Does not check if weakly referenced + receivers are still live. See :meth:`receivers_for` for a stronger + search. + + :param sender: Check for receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + if not self.receivers: + return False + + if self._by_sender[ANY_ID]: + return True + + if sender is ANY: + return False + + return make_id(sender) in self._by_sender + + def receivers_for( + self, sender: t.Any + ) -> c.Generator[c.Callable[..., t.Any], None, None]: + """Yield each receiver to be called for ``sender``, in addition to those + to be called for :data:`ANY`. Weakly referenced receivers that are not + live will be disconnected and skipped. + + :param sender: Yield receivers connected to this sender, in addition + to those connected to :data:`ANY`. + """ + # TODO: test receivers_for(ANY) + if not self.receivers: + return + + sender_id = make_id(sender) + + if sender_id in self._by_sender: + ids = self._by_sender[ANY_ID] | self._by_sender[sender_id] + else: + ids = self._by_sender[ANY_ID].copy() + + for receiver_id in ids: + receiver = self.receivers.get(receiver_id) + + if receiver is None: + continue + + if isinstance(receiver, weakref.ref): + strong = receiver() + + if strong is None: + self._disconnect(receiver_id, ANY_ID) + continue + + yield strong + else: + yield receiver + + def disconnect(self, receiver: c.Callable[..., t.Any], sender: t.Any = ANY) -> None: + """Disconnect ``receiver`` from being called when the signal is sent by + ``sender``. + + :param receiver: A connected receiver callable. + :param sender: Disconnect from only this sender. By default, disconnect + from all senders. + """ + sender_id: c.Hashable + + if sender is ANY: + sender_id = ANY_ID + else: + sender_id = make_id(sender) + + receiver_id = make_id(receiver) + self._disconnect(receiver_id, sender_id) + + if ( + "receiver_disconnected" in self.__dict__ + and self.receiver_disconnected.receivers + ): + self.receiver_disconnected.send(self, receiver=receiver, sender=sender) + + def _disconnect(self, receiver_id: c.Hashable, sender_id: c.Hashable) -> None: + if sender_id == ANY_ID: + if self._by_receiver.pop(receiver_id, None) is not None: + for bucket in self._by_sender.values(): + bucket.discard(receiver_id) + + self.receivers.pop(receiver_id, None) + else: + self._by_sender[sender_id].discard(receiver_id) + self._by_receiver[receiver_id].discard(sender_id) + + def _make_cleanup_receiver( + self, receiver_id: c.Hashable + ) -> c.Callable[[weakref.ref[c.Callable[..., t.Any]]], None]: + """Create a callback function to disconnect a weakly referenced + receiver when it is garbage collected. + """ + + def cleanup(ref: weakref.ref[c.Callable[..., t.Any]]) -> None: + # If the interpreter is shutting down, disconnecting can result in a + # weird ignored exception. Don't call it in that case. + if not sys.is_finalizing(): + self._disconnect(receiver_id, ANY_ID) + + return cleanup + + def _make_cleanup_sender( + self, sender_id: c.Hashable + ) -> c.Callable[[weakref.ref[t.Any]], None]: + """Create a callback function to disconnect all receivers for a weakly + referenced sender when it is garbage collected. + """ + assert sender_id != ANY_ID + + def cleanup(ref: weakref.ref[t.Any]) -> None: + self._weak_senders.pop(sender_id, None) + + for receiver_id in self._by_sender.pop(sender_id, ()): + self._by_receiver[receiver_id].discard(sender_id) + + return cleanup + + def _cleanup_bookkeeping(self) -> None: + """Prune unused sender/receiver bookkeeping. Not threadsafe. + + Connecting & disconnecting leaves behind a small amount of bookkeeping + data. Typical workloads using Blinker, for example in most web apps, + Flask, CLI scripts, etc., are not adversely affected by this + bookkeeping. + + With a long-running process performing dynamic signal routing with high + volume, e.g. connecting to function closures, senders are all unique + object instances. Doing all of this over and over may cause memory usage + to grow due to extraneous bookkeeping. (An empty ``set`` for each stale + sender/receiver pair.) + + This method will prune that bookkeeping away, with the caveat that such + pruning is not threadsafe. The risk is that cleanup of a fully + disconnected receiver/sender pair occurs while another thread is + connecting that same pair. If you are in the highly dynamic, unique + receiver/sender situation that has lead you to this method, that failure + mode is perhaps not a big deal for you. + """ + for mapping in (self._by_sender, self._by_receiver): + for ident, bucket in list(mapping.items()): + if not bucket: + mapping.pop(ident, None) + + def _clear_state(self) -> None: + """Disconnect all receivers and senders. Useful for tests.""" + self._weak_senders.clear() + self.receivers.clear() + self._by_sender.clear() + self._by_receiver.clear() + + +class NamedSignal(Signal): + """A named generic notification emitter. The name is not used by the signal + itself, but matches the key in the :class:`Namespace` that it belongs to. + + :param name: The name of the signal within the namespace. + :param doc: The docstring for the signal. + """ + + def __init__(self, name: str, doc: str | None = None) -> None: + super().__init__(doc) + + #: The name of this signal. + self.name: str = name + + def __repr__(self) -> str: + base = super().__repr__() + return f"{base[:-1]}; {self.name!r}>" # noqa: E702 + + +class Namespace(dict[str, NamedSignal]): + """A dict mapping names to signals.""" + + def signal(self, name: str, doc: str | None = None) -> NamedSignal: + """Return the :class:`NamedSignal` for the given ``name``, creating it + if required. Repeated calls with the same name return the same signal. + + :param name: The name of the signal. + :param doc: The docstring of the signal. + """ + if name not in self: + self[name] = NamedSignal(name, doc) + + return self[name] + + +class _PNamespaceSignal(t.Protocol): + def __call__(self, name: str, doc: str | None = None) -> NamedSignal: ... + + +default_namespace: Namespace = Namespace() +"""A default :class:`Namespace` for creating named signals. :func:`signal` +creates a :class:`NamedSignal` in this namespace. +""" + +signal: _PNamespaceSignal = default_namespace.signal +"""Return a :class:`NamedSignal` in :data:`default_namespace` with the given +``name``, creating it if required. Repeated calls with the same name return the +same signal. +""" diff --git a/venv/lib/python3.12/site-packages/blinker/py.typed b/venv/lib/python3.12/site-packages/blinker/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA new file mode 100644 index 00000000..e6c05af4 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/METADATA @@ -0,0 +1,82 @@ +Metadata-Version: 2.4 +Name: click +Version: 8.2.1 +Summary: Composable command line interface toolkit +Maintainer-email: Pallets +Requires-Python: >=3.10 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: colorama; platform_system == 'Windows' +Project-URL: Changes, https://click.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/click/ + +# $ click_ + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +## A Simple Example + +```python +import click + +@click.command() +@click.option("--count", default=1, help="Number of greetings.") +@click.option("--name", prompt="Your name", help="The person to greet.") +def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + +if __name__ == '__main__': + hello() +``` + +``` +$ python hello.py --count=3 +Your name: Click +Hello, Click! +Hello, Click! +Hello, Click! +``` + + +## Donate + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD new file mode 100644 index 00000000..61f4cd2b --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/RECORD @@ -0,0 +1,38 @@ +click-8.2.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.2.1.dist-info/METADATA,sha256=dI1MbhHTLoKD2tNCCGnx9rK2gok23HDNylFeLKdLSik,2471 +click-8.2.1.dist-info/RECORD,, +click-8.2.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +click-8.2.1.dist-info/licenses/LICENSE.txt,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click/__init__.py,sha256=6YyS1aeyknZ0LYweWozNZy0A9nZ_11wmYIhv3cbQrYo,4473 +click/__pycache__/__init__.cpython-312.pyc,, +click/__pycache__/_compat.cpython-312.pyc,, +click/__pycache__/_termui_impl.cpython-312.pyc,, +click/__pycache__/_textwrap.cpython-312.pyc,, +click/__pycache__/_winconsole.cpython-312.pyc,, +click/__pycache__/core.cpython-312.pyc,, +click/__pycache__/decorators.cpython-312.pyc,, +click/__pycache__/exceptions.cpython-312.pyc,, +click/__pycache__/formatting.cpython-312.pyc,, +click/__pycache__/globals.cpython-312.pyc,, +click/__pycache__/parser.cpython-312.pyc,, +click/__pycache__/shell_completion.cpython-312.pyc,, +click/__pycache__/termui.cpython-312.pyc,, +click/__pycache__/testing.cpython-312.pyc,, +click/__pycache__/types.cpython-312.pyc,, +click/__pycache__/utils.cpython-312.pyc,, +click/_compat.py,sha256=v3xBZkFbvA1BXPRkFfBJc6-pIwPI7345m-kQEnpVAs4,18693 +click/_termui_impl.py,sha256=ASXhLi9IQIc0Js9KQSS-3-SLZcPet3VqysBf9WgbbpI,26712 +click/_textwrap.py,sha256=BOae0RQ6vg3FkNgSJyOoGzG1meGMxJ_ukWVZKx_v-0o,1400 +click/_winconsole.py,sha256=_vxUuUaxwBhoR0vUWCNuHY8VUefiMdCIyU2SXPqoF-A,8465 +click/core.py,sha256=gUhpNS9cFBGdEXXdisGVG-eRvGf49RTyFagxulqwdFw,117343 +click/decorators.py,sha256=5P7abhJtAQYp_KHgjUvhMv464ERwOzrv2enNknlwHyQ,18461 +click/exceptions.py,sha256=1rdtXgHJ1b3OjGkN-UpXB9t_HCBihJvh_DtpmLmwn9s,9891 +click/formatting.py,sha256=Bhqx4QXdKQ9W4WKknIwj5KPKFmtduGOuGq1yw_THLZ8,9726 +click/globals.py,sha256=gM-Nh6A4M0HB_SgkaF5M4ncGGMDHc_flHXu9_oh4GEU,1923 +click/parser.py,sha256=nU1Ah2p11q29ul1vNdU9swPo_PUuKrxU6YXToi71q1c,18979 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=CQSGdjgun4ORbOZrXP0CVhEtPx4knsufOkRsDiK64cM,19857 +click/termui.py,sha256=vAYrKC2a7f_NfEIhAThEVYfa__ib5XQbTSCGtJlABRA,30847 +click/testing.py,sha256=2eLdAaCJCGToP5Tw-XN8JjrDb3wbJIfARxg3d0crW5M,18702 +click/types.py,sha256=KBTRxN28cR1VZ5mb9iJX98MQSw_p9SGzljqfEI8z5Tw,38389 +click/utils.py,sha256=b1Mm-usEDBHtEwcPltPIn3zSK4nw2KTp5GC7_oSTlLo,20245 diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL new file mode 100644 index 00000000..d8b9936d --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..d12a8491 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click-8.2.1.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/click/__init__.py b/venv/lib/python3.12/site-packages/click/__init__.py new file mode 100644 index 00000000..1aa547c5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/__init__.py @@ -0,0 +1,123 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" + +from __future__ import annotations + +from .core import Argument as Argument +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + from .core import _BaseCommand + + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + from .core import _MultiCommand + + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + if name == "OptionParser": + from .parser import _OptionParser + + warnings.warn( + "'OptionParser' is deprecated and will be removed in Click 9.0. The" + " old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return _OptionParser + + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Click 9.1. Use feature detection or" + " 'importlib.metadata.version(\"click\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("click") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..72f577e61a75aaffa9350070d60d43e7e5b68f13 GIT binary patch literal 4057 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 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..d799b83198faa8fdc66e0b529edb8e18504e7d1e GIT binary patch literal 31515 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

n|6C}*E{04B4%H{xhJr%cnP$){p>3Qq` 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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..f0c3adfc2d27164572f5c7a30ffd5ece4750d5bd GIT binary patch literal 22113 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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..255b61c87acc64b6202413fb8f49f0cf63dcceb4 GIT binary patch literal 14761 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 D0)l}h 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..4d5e9835b536c977c557ed2d461b8832ba046b51 GIT binary patch literal 2950 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%0D%>P_<#=x%{4e6G!rO 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 z%0D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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/testing.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b53025ce10cad1f6557e1c285bd79a315b01a82 GIT binary patch literal 26884 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 YK~dcDkwD=mPuq@4V)e%Yg$#@SFB|v5&;S4c literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc b/venv/lib/python3.12/site-packages/click/__pycache__/types.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6b666e9c081ea3fb99ee5c8ce1109fd1cadb23ff GIT binary patch literal 48944 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 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..61f5f4d4851bf31757f45433168b787e64a94cb0 GIT binary patch literal 24864 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 P<)VoyyHkP?bMgNNpyAZR 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 00000000..f2726b93 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_compat.py @@ -0,0 +1,622 @@ +from __future__ import annotations + +import codecs +import collections.abc as cabc +import io +import os +import re +import sys +import typing as t +from types import TracebackType +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +WIN = sys.platform.startswith("win") +auto_wrap_for_ansi: t.Callable[[t.TextIO], t.TextIO] | None = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO[t.Any]) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: str | None, + errors: str | None, + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write(b"") + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + return isinstance(stream.read(0), bytes) + except Exception: + return default + # This happens in some cases where the stream was already + # closed. In this case, we assume the default. + + +def _is_binary_writer(stream: t.IO[t.Any], default: bool = False) -> bool: + try: + stream.write(b"") + except Exception: + try: + stream.write("") + return False + except Exception: + pass + return default + return True + + +def _find_binary_reader(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO[t.Any]) -> t.BinaryIO | None: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: str | None) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: str | None, errors: str | None +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO[t.Any], + encoding: str | None, + errors: str | None, + is_binary: t.Callable[[t.IO[t.Any], bool], bool], + find_binary: t.Callable[[t.IO[t.Any]], t.BinaryIO | None], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO[t.Any], + encoding: str | None, + errors: str | None, + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr(encoding: str | None = None, errors: str | None = None) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: str | os.PathLike[str] | int, + mode: str, + encoding: str | None, + errors: str | None, +) -> t.IO[t.Any]: + """Handles not passing ``encoding`` and ``errors`` in binary mode.""" + if "b" in mode: + return open(file, mode) + + return open(file, mode, encoding=encoding, errors=errors) + + +def open_stream( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, +) -> tuple[t.IO[t.Any], bool]: + binary = "b" in mode + filename = os.fspath(filename) + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: int | None = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO[t.Any], af), True + + +class _AtomicFile: + def __init__(self, f: t.IO[t.Any], tmp_filename: str, real_filename: str) -> None: + self._f = f + self._tmp_filename = tmp_filename + self._real_filename = real_filename + self.closed = False + + @property + def name(self) -> str: + return self._real_filename + + def close(self, delete: bool = False) -> None: + if self.closed: + return + self._f.close() + os.replace(self._tmp_filename, self._real_filename) + self.closed = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._f, name) + + def __enter__(self) -> _AtomicFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close(delete=exc_type is not None) + + def __repr__(self) -> str: + return repr(self._f) + + +def strip_ansi(value: str) -> str: + return _ansi_re.sub("", value) + + +def _is_jupyter_kernel_output(stream: t.IO[t.Any]) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi(stream: t.TextIO, color: bool | None = None) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s: str) -> int: + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write # type: ignore[method-assign] + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or sys.getfilesystemencoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None + ) -> t.TextIO | None: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO[t.Any]) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO | None], + wrapper_func: t.Callable[[], t.TextIO], +) -> t.Callable[[], t.TextIO | None]: + cache: cabc.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO | None: + stream = src_func() + + if stream is None: + return None + + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: cabc.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: cabc.Mapping[str, t.Callable[[str | None, str | None], t.TextIO]] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/venv/lib/python3.12/site-packages/click/_termui_impl.py b/venv/lib/python3.12/site-packages/click/_termui_impl.py new file mode 100644 index 00000000..51fd9bf3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_termui_impl.py @@ -0,0 +1,839 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" + +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import math +import os +import shlex +import sys +import time +import typing as t +from gettext import gettext as _ +from io import StringIO +from pathlib import Path +from shutil import which +from types import TracebackType + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: cabc.Iterable[V] | None, + length: int | None = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + label: str | None = None, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.hidden = hidden + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label: str = label or "" + + if file is None: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + file = StringIO() + + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width: int = width + self.autowidth: bool = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast("cabc.Iterable[V]", range(length)) + self.iter: cabc.Iterable[V] = iter(iterable) + self.length = length + self.pos: int = 0 + self.avg: list[float] = [] + self.last_eta: float + self.start: float + self.start = self.last_eta = time.time() + self.eta_known: bool = False + self.finished: bool = False + self.max_width: int | None = None + self.entered: bool = False + self.current_item: V | None = None + self._is_atty = isatty(self.file) + self._last_line: str | None = None + + def __enter__(self) -> ProgressBar[V]: + self.entered = True + self.render_progress() + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.render_finish() + + def __iter__(self) -> cabc.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.hidden or not self._is_atty: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + import shutil + + if self.hidden: + return + + if not self._is_atty: + # Only output the label once if the output is not a TTY. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width and self.max_width is not None: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: V | None = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> cabc.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if not self._is_atty: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: cabc.Iterable[str], color: bool | None = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if stdout is None: + stdout = StringIO() + + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + + # Split and normalize the pager command into parts. + pager_cmd_parts = shlex.split(os.environ.get("PAGER", ""), posix=False) + if pager_cmd_parts: + if WIN: + if _tempfilepager(generator, pager_cmd_parts, color): + return + elif _pipepager(generator, pager_cmd_parts, color): + return + + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if (WIN or sys.platform.startswith("os2")) and _tempfilepager( + generator, ["more"], color + ): + return + if _pipepager(generator, ["less"], color): + return + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if _pipepager(generator, ["more"], color): + return + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + cmd = cmd_parts[0] + cmd_params = cmd_parts[1:] + + cmd_filepath = which(cmd) + if not cmd_filepath: + return False + # Resolves symlinks and produces a normalized absolute path string. + cmd_path = Path(cmd_filepath).resolve() + cmd_name = cmd_path.name + + import subprocess + + # Make a local copy of the environment to not affect the global one. + env = dict(os.environ) + + # If we're piping to less and the user hasn't decided on colors, we enable + # them by default we find the -R flag in the command line arguments. + if color is None and cmd_name == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_params)}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen( + [str(cmd_path)] + cmd_params, + shell=True, + stdin=subprocess.PIPE, + env=env, + errors="replace", + text=True, + ) + assert c.stdin is not None + try: + for text in generator: + if not color: + text = strip_ansi(text) + + c.stdin.write(text) + except BrokenPipeError: + # In case the pager exited unexpectedly, ignore the broken pipe error. + pass + except Exception as e: + # In case there is an exception we want to close the pager immediately + # and let the caller handle it. + # Otherwise the pager will keep running, and the user may not notice + # the error message, or worse yet it may leave the terminal in a broken state. + c.terminate() + raise e + finally: + # We must close stdin and wait for the pager to exit before we continue + try: + c.stdin.close() + # Close implies flush, so it might throw a BrokenPipeError if the pager + # process exited already. + except BrokenPipeError: + pass + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + return True + + +def _tempfilepager( + generator: cabc.Iterable[str], cmd_parts: list[str], color: bool | None +) -> bool: + """Page through text by invoking a program on a temporary file. + + Returns `True` if the command was found, `False` otherwise and thus another + pager should be attempted. + """ + # Split the command into the invoked CLI and its parameters. + if not cmd_parts: + return False + cmd = cmd_parts[0] + + cmd_filepath = which(cmd) + if not cmd_filepath: + return False + # Resolves symlinks and produces a normalized absolute path string. + cmd_path = Path(cmd_filepath).resolve() + + import subprocess + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + subprocess.call([str(cmd_path), filename]) + except OSError: + # Command not found + pass + finally: + os.close(fd) + os.unlink(filename) + + return True + + +def _nullpager( + stream: t.TextIO, generator: cabc.Iterable[str], color: bool | None +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if which(editor) is not None: + return editor + return "vi" + + def edit_files(self, filenames: cabc.Iterable[str]) -> None: + import subprocess + + editor = self.get_editor() + environ: dict[str, str] | None = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + exc_filename = " ".join(f'"{filename}"' for filename in filenames) + + try: + c = subprocess.Popen( + args=f"{editor} {exc_filename}", env=environ, shell=True + ) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + @t.overload + def edit(self, text: bytes | bytearray) -> bytes | None: ... + + # We cannot know whether or not the type expected is str or bytes when None + # is passed, so str is returned as that was what was done before. + @t.overload + def edit(self, text: str | None) -> str | None: ... + + def edit(self, text: str | bytes | bytearray | None) -> str | bytes | None: + import tempfile + + if text is None: + data = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_files((name,)) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url) + args = ["explorer", f"/select,{url}"] + else: + args = ["start"] + if wait: + args.append("/WAIT") + args.append("") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + elif CYGWIN: + if locate: + url = _unquote_file(url) + args = ["cygstart", os.path.dirname(url)] + else: + args = ["cygstart"] + if wait: + args.append("-w") + args.append(url) + try: + return subprocess.call(args) + except OSError: + # Command not found + return 127 + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> None: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if sys.platform == "win32": + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + + if echo: + func = t.cast(t.Callable[[], str], msvcrt.getwche) + else: + func = t.cast(t.Callable[[], str], msvcrt.getwch) + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import termios + import tty + + @contextlib.contextmanager + def raw_terminal() -> cabc.Iterator[int]: + f: t.TextIO | None + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/venv/lib/python3.12/site-packages/click/_textwrap.py b/venv/lib/python3.12/site-packages/click/_textwrap.py new file mode 100644 index 00000000..97fbee3d --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_textwrap.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import collections.abc as cabc +import textwrap +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: list[str], + cur_line: list[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> cabc.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/venv/lib/python3.12/site-packages/click/_winconsole.py b/venv/lib/python3.12/site-packages/click/_winconsole.py new file mode 100644 index 00000000..e56c7c6a --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/_winconsole.py @@ -0,0 +1,296 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +from __future__ import annotations + +import collections.abc as cabc +import io +import sys +import time +import typing as t +from ctypes import Array +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +if t.TYPE_CHECKING: + try: + # Using `typing_extensions.Buffer` instead of `collections.abc` + # on Windows for some reason does not have `Sized` implemented. + from collections.abc import Buffer # type: ignore + except ImportError: + from typing_extensions import Buffer + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ # noqa: RUF012 + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj: Buffer, writable: bool = False) -> Array[c_char]: + buf = Py_buffer() + flags: int = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + out: Array[c_char] = buffer_type.from_address(buf.buf) + return out + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle: int | None) -> None: + self.handle = handle + + def isatty(self) -> t.Literal[True]: + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self) -> t.Literal[True]: + return True + + def readinto(self, b: Buffer) -> int: + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self) -> t.Literal[True]: + return True + + @staticmethod + def _get_error_message(errno: int) -> str: + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b: Buffer) -> int: + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: cabc.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self) -> str: + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: cabc.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: str | None, errors: str | None +) -> t.TextIO | None: + if ( + get_buffer is None + or encoding not in {"utf-16-le", None} + or errors not in {"strict", None} + or not _is_console(f) + ): + return None + + func = _stream_factories.get(f.fileno()) + if func is None: + return None + + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/venv/lib/python3.12/site-packages/click/core.py b/venv/lib/python3.12/site-packages/click/core.py new file mode 100644 index 00000000..f57ada62 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/core.py @@ -0,0 +1,3135 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from collections import Counter +from contextlib import AbstractContextManager +from contextlib import contextmanager +from contextlib import ExitStack +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat +from types import TracebackType + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import NoArgsIsHelpError +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import _OptionParser +from .parser import _split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound="t.Callable[..., t.Any]") +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: Context, incomplete: str +) -> cabc.Iterator[tuple[str, Command]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(Group, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_nested_chain( + base_command: Group, cmd_name: str, cmd: Command, register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, Group): + return + + if register: + message = ( + f"It is not possible to add the group {cmd_name!r} to another" + f" group {base_command.name!r} that is in chain mode." + ) + else: + message = ( + f"Found the group {cmd_name!r} as subcommand to another group " + f" {base_command.name!r} that is in chain mode. This is not supported." + ) + + raise RuntimeError(message) + + +def batch(iterable: cabc.Iterable[V], batch_size: int) -> list[tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size), strict=False)) + + +@contextmanager +def augment_usage_errors( + ctx: Context, param: Parameter | None = None +) -> cabc.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: cabc.Sequence[Parameter], + declaration_order: cabc.Sequence[Parameter], +) -> list[Parameter]: + """Returns all declared parameters in the order they should be processed. + + The declared parameters are re-shuffled depending on the order in which + they were invoked, as well as the eagerness of each parameters. + + The invocation order takes precedence over the declaration order. I.e. the + order in which the user provided them to the CLI is respected. + + This behavior and its effect on callback evaluation is detailed at: + https://click.palletsprojects.com/en/stable/advanced/#callback-evaluation-order + """ + + def sort_key(item: Parameter) -> tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.2 + The ``protected_args`` attribute is deprecated and will be removed in + Click 9.0. ``args`` will contain remaining unparsed tokens. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: type[HelpFormatter] = HelpFormatter + + def __init__( + self, + command: Command, + parent: Context | None = None, + info_name: str | None = None, + obj: t.Any | None = None, + auto_envvar_prefix: str | None = None, + default_map: cabc.MutableMapping[str, t.Any] | None = None, + terminal_width: int | None = None, + max_content_width: int | None = None, + resilient_parsing: bool = False, + allow_extra_args: bool | None = None, + allow_interspersed_args: bool | None = None, + ignore_unknown_options: bool | None = None, + help_option_names: list[str] | None = None, + token_normalize_func: t.Callable[[str], str] | None = None, + color: bool | None = None, + show_default: bool | None = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: dict[str, t.Any] = {} + #: the leftover arguments. + self.args: list[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self._protected_args: list[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: cabc.MutableMapping[str, t.Any] | None = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: str | None = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: int | None = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: int | None = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: list[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Callable[[str], str] | None = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: str | None = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: bool | None = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: bool | None = show_default + + self._close_callbacks: list[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + @property + def protected_args(self) -> list[str]: + import warnings + + warnings.warn( + "'protected_args' is deprecated and will be removed in Click 9.0." + " 'args' will contain remaining unparsed tokens.", + DeprecationWarning, + stacklevel=2, + ) + return self._protected_args + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> Context: + self._depth += 1 + push_context(self) + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> cabc.Iterator[Context]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: AbstractContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> Context: + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: type[V]) -> V | None: + """Finds the closest object of a given type.""" + node: Context | None = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def lookup_default( + self, name: str, call: t.Literal[False] = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def lookup_default(self, name: str, call: bool = True) -> t.Any | None: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> t.NoReturn: + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> t.NoReturn: + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> t.NoReturn: + """Exits the application with a given exit code. + + .. versionchanged:: 8.2 + Callbacks and context managers registered with :meth:`call_on_close` + and :meth:`with_resource` are closed before exiting. + """ + self.close() + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: Command) -> Context: + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + @t.overload + def invoke( + self, callback: t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> V: ... + + @t.overload + def invoke(self, callback: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: ... + + def invoke( + self, callback: Command | t.Callable[..., V], /, *args: t.Any, **kwargs: t.Any + ) -> t.Any | V: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + + .. versionchanged:: 3.2 + A new context is created, and missing arguments use default values. + """ + if isinstance(callback, Command): + other_cmd = callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + callback = t.cast("t.Callable[..., V]", other_cmd.callback) + + ctx = self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = self + + with augment_usage_errors(self): + with ctx: + return callback(*args, **kwargs) + + def forward(self, cmd: Command, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(cmd, Command): + raise TypeError("Callback is not a command.") + + for param in self.params: + if param not in kwargs: + kwargs[param] = self.params[param] + + return self.invoke(cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> ParameterSource | None: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class Command: + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the command is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. + + .. versionchanged:: 8.2 + This is the base class for all commands, not ``BaseCommand``. + ``deprecated`` can be set to a string as well to customize the + deprecation message. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: type[Context] = Context + + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: str | None, + context_settings: cabc.MutableMapping[str, t.Any] | None = None, + callback: t.Callable[..., t.Any] | None = None, + params: list[Parameter] | None = None, + help: str | None = None, + epilog: str | None = None, + short_help: str | None = None, + options_metavar: str | None = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool | str = False, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: cabc.MutableMapping[str, t.Any] = context_settings + + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: list[Parameter] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self._help_option = None + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + return { + "name": self.name, + "params": [param.to_info_dict() for param in self.get_params(ctx)], + "help": self.help, + "epilog": self.epilog, + "short_help": self.short_help, + "hidden": self.hidden, + "deprecated": self.deprecated, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> list[Parameter]: + params = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + params = [*params, help_option] + + if __debug__: + import warnings + + opts = [opt for param in params for opt in param.opts] + opts_counter = Counter(opts) + duplicate_opts = (opt for opt, count in opts_counter.items() if count > 1) + + for duplicate_opt in duplicate_opts: + warnings.warn( + ( + f"The parameter {duplicate_opt} is used more than once. " + "Remove its duplicate as parameters should be unique." + ), + stacklevel=3, + ) + + return params + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> list[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> Option | None: + """Returns the help option object. + + Skipped if :attr:`add_help_option` is ``False``. + + .. versionchanged:: 8.1.8 + The help option is now cached to avoid creating it multiple times. + """ + help_option_names = self.get_help_option_names(ctx) + + if not help_option_names or not self.add_help_option: + return None + + # Cache the help option object in private _help_option attribute to + # avoid creating it multiple times. Not doing this will break the + # callback odering by iter_params_for_processing(), which relies on + # object comparison. + if self._help_option is None: + # Avoid circular import. + from .decorators import help_option + + # Apply help_option decorator and pop resulting option + help_option(*help_option_names)(self) + self._help_option = self.params.pop() # type: ignore[assignment] + + return self._help_option + + def make_parser(self, ctx: Context) -> _OptionParser: + """Creates the underlying option parser for this command.""" + parser = _OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + if self.help is not None: + # truncate the help text to the first form feed + text = inspect.cleandoc(self.help).partition("\f")[0] + else: + text = "" + + if self.deprecated: + deprecated_message = ( + f"(DEPRECATED: {self.deprecated})" + if isinstance(self.deprecated, str) + else "(DEPRECATED)" + ) + text = _("{text} {deprecated_message}").format( + text=text, deprecated_message=deprecated_message + ) + + if text: + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: Context | None = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class(self, info_name=info_name, parent=parent, **extra) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The command {name!r} is deprecated.{extra_message}" + ).format(name=self.name, extra_message=extra_message) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: list[CompletionItem] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, Group) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx._protected_args + ) + + return results + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: t.Literal[True] = True, + **extra: t.Any, + ) -> t.NoReturn: ... + + @t.overload + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: ... + + def main( + self, + args: cabc.Sequence[str] | None = None, + prog_name: str | None = None, + complete_var: str | None = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt) as e: + echo(file=sys.stderr) + raise Abort() from e + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str | None = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + + .. versionchanged:: 8.2.0 + Dots (``.``) in ``prog_name`` are replaced with underscores (``_``). + """ + if complete_var is None: + complete_name = prog_name.replace("-", "_").replace(".", "_") + complete_var = f"_{complete_name}_COMPLETE".upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class _FakeSubclassCheck(type): + def __subclasscheck__(cls, subclass: type) -> bool: + return issubclass(subclass, cls.__bases__[0]) + + def __instancecheck__(cls, instance: t.Any) -> bool: + return isinstance(instance, cls.__bases__[0]) + + +class _BaseCommand(Command, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Command`` instead. + """ + + +class Group(Command): + """A group is a command that nests other commands (or more groups). + + :param name: The name of the group command. + :param commands: Map names to :class:`Command` objects. Can be a list, which + will use :attr:`Command.name` as the keys. + :param invoke_without_command: Invoke the group's callback even if a + subcommand is not given. + :param no_args_is_help: If no arguments are given, show the group's help and + exit. Defaults to the opposite of ``invoke_without_command``. + :param subcommand_metavar: How to represent the subcommand argument in help. + The default will represent whether ``chain`` is set or not. + :param chain: Allow passing more than one subcommand argument. After parsing + a command's arguments, if any arguments remain another command will be + matched, and so on. + :param result_callback: A function to call after the group's and + subcommand's callbacks. The value returned by the subcommand is passed. + If ``chain`` is enabled, the value will be a list of values returned by + all the commands. If ``invoke_without_command`` is enabled, the value + will be the value returned by the group's callback, or an empty list if + ``chain`` is enabled. + :param kwargs: Other arguments passed to :class:`Command`. + + .. versionchanged:: 8.0 + The ``commands`` argument can be a list of command objects. + + .. versionchanged:: 8.2 + Merged with and replaces the ``MultiCommand`` base class. + """ + + allow_extra_args = True + allow_interspersed_args = False + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: type[Command] | None = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: type[Group] | type[type] | None = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: str | None = None, + commands: cabc.MutableMapping[str, Command] + | cabc.Sequence[Command] + | None = None, + invoke_without_command: bool = False, + no_args_is_help: bool | None = None, + subcommand_metavar: str | None = None, + chain: bool = False, + result_callback: t.Callable[..., t.Any] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: cabc.MutableMapping[str, Command] = commands + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "A group in chain mode cannot have optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def add_command(self, cmd: Command, name: str | None = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_nested_chain(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command] | Command: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'command(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> Group: ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group]: ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Group] | Group: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Callable[..., t.Any] | None = None + + if args and callable(args[0]): + assert len(args) == 1 and not kwargs, ( + "Use 'group(**kwargs)(callable)' to provide arguments." + ) + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> Group: + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(value: t.Any, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + inner = old_callback(value, *args, **kwargs) + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv # type: ignore[return-value] + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + """Given a context and a command name, this returns a :class:`Command` + object if it exists or returns ``None``. + """ + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> list[str]: + """Returns a list of subcommand names in the order they should appear.""" + return sorted(self.commands) + + def collect_usage_pieces(self, ctx: Context) -> list[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + raise NoArgsIsHelpError(ctx) + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx._protected_args = rest + ctx.args = [] + elif rest: + ctx._protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx._protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx._protected_args, *ctx.args] + ctx.args = [] + ctx._protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: list[str] + ) -> tuple[str | None, Command | None, list[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if _split_opt(cmd_name)[0]: + self.parse_args(ctx, args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class _MultiCommand(Group, metaclass=_FakeSubclassCheck): + """ + .. deprecated:: 8.2 + Will be removed in Click 9.0. Use ``Group`` instead. + """ + + +class CommandCollection(Group): + """A :class:`Group` that looks up subcommands on other groups. If a command + is not found on this group, each registered source is checked in order. + Parameters on a source are not added to this group, and a source's callback + is not invoked when invoking its commands. In other words, this "flattens" + commands in many groups into this one group. + + :param name: The name of the group command. + :param sources: A list of :class:`Group` objects to look up commands from. + :param kwargs: Other arguments passed to :class:`Group`. + + .. versionchanged:: 8.2 + This is a subclass of ``Group``. Commands are looked up first on this + group, then each of its sources. + """ + + def __init__( + self, + name: str | None = None, + sources: list[Group] | None = None, + **kwargs: t.Any, + ) -> None: + super().__init__(name, **kwargs) + #: The list of registered groups. + self.sources: list[Group] = sources or [] + + def add_source(self, group: Group) -> None: + """Add a group as a source of commands.""" + self.sources.append(group) + + def get_command(self, ctx: Context, cmd_name: str) -> Command | None: + rv = super().get_command(ctx, cmd_name) + + if rv is not None: + return rv + + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_nested_chain(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> list[str]: + rv: set[str] = set(super().list_commands(ctx)) + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The latter is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + :param deprecated: If ``True`` or non-empty string, issues a message + indicating that the argument is deprecated and highlights + its deprecation in --help. The message can be customized + by using a string as the value. A deprecated parameter + cannot be required, a ValueError will be raised otherwise. + + .. versionchanged:: 8.2.0 + Introduction of ``deprecated``. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.2 + Adding duplicate parameter names to a :class:`~click.core.Command` will + result in a ``UserWarning`` being shown. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + type: types.ParamType | t.Any | None = None, + required: bool = False, + default: t.Any | t.Callable[[], t.Any] | None = None, + callback: t.Callable[[Context, Parameter, t.Any], t.Any] | None = None, + nargs: int | None = None, + multiple: bool = False, + metavar: str | None = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: str | cabc.Sequence[str] | None = None, + shell_complete: t.Callable[ + [Context, Parameter, str], list[CompletionItem] | list[str] + ] + | None = None, + deprecated: bool | str = False, + ) -> None: + self.name: str | None + self.opts: list[str] + self.secondary_opts: list[str] + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type: types.ParamType = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + self.deprecated = deprecated + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={nargs}." + ) + + if required and deprecated: + raise ValueError( + f"The {self.param_type_name} '{self.human_readable_name}' " + "is deprecated and still required. A deprecated " + f"{self.param_type_name} cannot be required." + ) + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self.default, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(param=self, ctx=ctx) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, t.Any] + ) -> tuple[t.Any, ParameterSource]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + def check_iter(value: t.Any) -> cabc.Iterator[t.Any]: + try: + return _check_iter(value) + except TypeError: + # This should only happen when passing in args manually, + # the parser should construct an iterable when parsing + # the command line. + raise BadParameter( + _("Value must be an iterable."), ctx=ctx, param=self + ) from None + + if self.nargs == 1 or self.type.is_composite: + + def convert(value: t.Any) -> t.Any: + return self.type(value, param=self, ctx=ctx) + + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Any: # tuple[t.Any, ...] + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + if value is None: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> str | None: + if self.envvar is None: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any | None: + rv: t.Any | None = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: cabc.Mapping[str, t.Any], args: list[str] + ) -> tuple[t.Any, list[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + + if ( + self.deprecated + and value is not None + and source + not in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ) + ): + extra_message = ( + f" {self.deprecated}" if isinstance(self.deprecated, str) else "" + ) + message = _( + "DeprecationWarning: The {param_type} {name!r} is deprecated." + "{extra_message}" + ).format( + param_type=self.param_type_name, + name=self.human_readable_name, + extra_message=extra_message, + ) + echo(style(message, fg="red"), err=True) + + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + return value, args + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + pass + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> list[CompletionItem]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast("list[CompletionItem]", results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page and error messages. + Normally, environment variables are not shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. A deprecated option cannot be + prompted. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + :param attrs: Other command arguments described in :class:`Parameter`. + + .. versionchanged:: 8.2 + ``envvar`` used with ``flag_value`` will always use the ``flag_value``, + previously it would use the value of the environment variable. + + .. versionchanged:: 8.1 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: cabc.Sequence[str] | None = None, + show_default: bool | str | None = None, + prompt: bool | str = False, + confirmation_prompt: bool | str = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: bool | None = None, + flag_value: t.Any | None = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: types.ParamType | t.Any | None = None, + help: str | None = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + deprecated: bool | str = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + default_is_missing = "default" not in attrs + super().__init__( + param_decls, type=type, multiple=multiple, deprecated=deprecated, **attrs + ) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: str | None = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + if deprecated: + deprecated_message = ( + f"(DEPRECATED: {deprecated})" + if isinstance(deprecated, str) + else "(DEPRECATED)" + ) + help = help + deprecated_message if help is not None else deprecated_message + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + self.default: t.Any | t.Callable[[], t.Any] + + if is_flag and default_is_missing and not self.required: + if multiple: + self.default = () + else: + self.default = False + + if is_flag and flag_value is None: + flag_value = not self.default + + self.type: types.ParamType + if is_flag and type is None: + # Re-guess the type from the flag value instead of the + # default. + self.type = types.convert_type(None, flag_value) + + self.is_flag: bool = is_flag + self.is_bool_flag: bool = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if deprecated and prompt: + raise ValueError("`deprecated` options cannot use `prompt`.") + + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def get_error_hint(self, ctx: Context) -> str: + result = super().get_error_hint(ctx) + if self.show_envvar: + result += f" (env var: '{self.envvar}')" + return result + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(_split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(_split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError( + f"Could not determine name for option with declarations {decls!r}" + ) + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> tuple[str, str] | None: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: cabc.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar(ctx=ctx)}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + + extra = self.get_help_extra(ctx) + extra_items = [] + if "envvars" in extra: + extra_items.append( + _("env var: {var}").format(var=", ".join(extra["envvars"])) + ) + if "default" in extra: + extra_items.append(_("default: {default}").format(default=extra["default"])) + if "range" in extra: + extra_items.append(extra["range"]) + if "required" in extra: + extra_items.append(_(extra["required"])) + + if extra_items: + extra_str = "; ".join(extra_items) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + def get_help_extra(self, ctx: Context) -> types.OptionHelpExtra: + extra: types.OptionHelpExtra = {} + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + if isinstance(envvar, str): + extra["envvars"] = (envvar,) + else: + extra["envvars"] = tuple(str(d) for d in envvar) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or (show_default and (default_value is not None)): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = _split_opt( + (self.opts if default_value else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + elif default_value == "": + default_string = '""' + else: + default_string = str(default_value) + + if default_string: + extra["default"] = default_string + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra["range"] = range_str + + if self.required: + extra["required"] = "required" + + return extra + + @t.overload + def get_default( + self, ctx: Context, call: t.Literal[True] = True + ) -> t.Any | None: ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Any | t.Callable[[], t.Any] | None: ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Any | t.Callable[[], t.Any] | None: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return t.cast(Option, param).flag_value + + return None + + return super().get_default(ctx, call=call) + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + # If show_default is set to True/False, provide this to `prompt` as well. For + # non-bool values of `show_default`, we use `prompt`'s default behavior + prompt_kwargs: t.Any = {} + if isinstance(self.show_default, bool): + prompt_kwargs["show_default"] = self.show_default + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + **prompt_kwargs, + ) + + def resolve_envvar_value(self, ctx: Context) -> str | None: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + if self.is_flag and self.flag_value: + return str(self.flag_value) + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Any | None: + rv: t.Any | None = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: cabc.Mapping[str, Parameter] + ) -> tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + and any(v is _flag_needs_value for v in value) + ): + value = [self.flag_value if v is _flag_needs_value else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the constructor of :class:`Parameter`. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: cabc.Sequence[str], + required: bool | None = None, + **attrs: t.Any, + ) -> None: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self, ctx: Context) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(param=self, ctx=ctx) + if not var: + var = self.name.upper() # type: ignore + if self.deprecated: + var += "!" + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: cabc.Sequence[str], expose_value: bool + ) -> tuple[str | None, list[str], list[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Argument is marked as exposed, but does not have a name.") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}: {decls}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> list[str]: + return [self.make_metavar(ctx)] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar(ctx)}'" + + def add_to_parser(self, parser: _OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) + + +def __getattr__(name: str) -> object: + import warnings + + if name == "BaseCommand": + warnings.warn( + "'BaseCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Command' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _BaseCommand + + if name == "MultiCommand": + warnings.warn( + "'MultiCommand' is deprecated and will be removed in Click 9.0. Use" + " 'Group' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _MultiCommand + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/decorators.py b/venv/lib/python3.12/site-packages/click/decorators.py new file mode 100644 index 00000000..21f4c342 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/decorators.py @@ -0,0 +1,551 @@ +from __future__ import annotations + +import inspect +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") +T = t.TypeVar("T") +_AnyCallable = t.Callable[..., t.Any] +FC = t.TypeVar("FC", bound="_AnyCallable | Command") + + +def pass_context(f: t.Callable[te.Concatenate[Context, P], R]) -> t.Callable[P, R]: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(new_func, f) + + +def pass_obj(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + """Similar to :func:`pass_context`, but only pass the object on the + context onwards (:attr:`Context.obj`). This is useful if that object + represents the state of a nested system. + """ + + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + +def make_pass_decorator( + object_type: type[T], ensure: bool = False +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Given an object type this creates a decorator that will work + similar to :func:`pass_obj` but instead of passing the object of the + current context, it will find the innermost context of type + :func:`object_type`. + + This generates a decorator that works roughly like this:: + + from functools import update_wrapper + + def decorator(f): + @pass_context + def new_func(ctx, *args, **kwargs): + obj = ctx.find_object(object_type) + return ctx.invoke(f, obj, *args, **kwargs) + return update_wrapper(new_func, f) + return decorator + + :param object_type: the type of the object to pass. + :param ensure: if set to `True`, a new object will be created and + remembered on the context if it's not there yet. + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + + obj: T | None + if ensure: + obj = ctx.ensure_object(object_type) + else: + obj = ctx.find_object(object_type) + + if obj is None: + raise RuntimeError( + "Managed to invoke callback without a context" + f" object of type {object_type.__name__!r}" + " existing." + ) + + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: str | None = None +) -> t.Callable[[t.Callable[te.Concatenate[T, P], R]], t.Callable[P, R]]: + """Create a decorator that passes a key from + :attr:`click.Context.meta` as the first argument to the decorated + function. + + :param key: Key in ``Context.meta`` to pass. + :param doc_description: Description of the object being passed, + inserted into the decorator's docstring. Defaults to "the 'key' + key from Context.meta". + + .. versionadded:: 8.0 + """ + + def decorator(f: t.Callable[te.Concatenate[T, P], R]) -> t.Callable[P, R]: + def new_func(*args: P.args, **kwargs: P.kwargs) -> R: + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(new_func, f) + + if doc_description is None: + doc_description = f"the {key!r} key from :attr:`click.Context.meta`" + + decorator.__doc__ = ( + f"Decorator that passes {doc_description} as the first argument" + " to the decorated function." + ) + return decorator + + +CmdType = t.TypeVar("CmdType", bound=Command) + + +# variant: no call, directly as decorator for a function. +@t.overload +def command(name: _AnyCallable) -> Command: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @command(namearg, CommandCls, ...) or @command(namearg, cls=CommandCls, ...) +@t.overload +def command( + name: str | None, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @command(cls=CommandCls, ...) +@t.overload +def command( + name: None = None, + *, + cls: type[CmdType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], CmdType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def command( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Command]: ... + + +def command( + name: str | _AnyCallable | None = None, + cls: type[CmdType] | None = None, + **attrs: t.Any, +) -> Command | t.Callable[[_AnyCallable], Command | CmdType]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function, converted to + lowercase, with underscores ``_`` replaced by dashes ``-``, and the suffixes + ``_command``, ``_cmd``, ``_group``, and ``_grp`` are removed. For example, + ``init_data_command`` becomes ``init-data``. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: The name of the command. Defaults to modifying the function's + name as described above. + :param cls: The command class to create. Defaults to :class:`Command`. + + .. versionchanged:: 8.2 + The suffixes ``_command``, ``_cmd``, ``_group``, and ``_grp`` are + removed when generating the name. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Callable[[_AnyCallable], t.Any] | None = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = t.cast("type[CmdType]", Command) + + def decorator(f: _AnyCallable) -> CmdType: + if isinstance(f, Command): + raise TypeError("Attempted to convert a callback into a command twice.") + + attr_params = attrs.pop("params", None) + params = attr_params if attr_params is not None else [] + + try: + decorator_params = f.__click_params__ # type: ignore + except AttributeError: + pass + else: + del f.__click_params__ # type: ignore + params.extend(reversed(decorator_params)) + + if attrs.get("help") is None: + attrs["help"] = f.__doc__ + + if t.TYPE_CHECKING: + assert cls is not None + assert not callable(name) + + if name is not None: + cmd_name = name + else: + cmd_name = f.__name__.lower().replace("_", "-") + cmd_left, sep, suffix = cmd_name.rpartition("-") + + if sep and suffix in {"command", "cmd", "group", "grp"}: + cmd_name = cmd_left + + cmd = cls(name=cmd_name, callback=f, params=params, **attrs) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +GrpType = t.TypeVar("GrpType", bound=Group) + + +# variant: no call, directly as decorator for a function. +@t.overload +def group(name: _AnyCallable) -> Group: ... + + +# variant: with positional name and with positional or keyword cls argument: +# @group(namearg, GroupCls, ...) or @group(namearg, cls=GroupCls, ...) +@t.overload +def group( + name: str | None, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: name omitted, cls _must_ be a keyword argument, @group(cmd=GroupCls, ...) +@t.overload +def group( + name: None = None, + *, + cls: type[GrpType], + **attrs: t.Any, +) -> t.Callable[[_AnyCallable], GrpType]: ... + + +# variant: with optional string name, no cls argument provided. +@t.overload +def group( + name: str | None = ..., cls: None = None, **attrs: t.Any +) -> t.Callable[[_AnyCallable], Group]: ... + + +def group( + name: str | _AnyCallable | None = None, + cls: type[GrpType] | None = None, + **attrs: t.Any, +) -> Group | t.Callable[[_AnyCallable], Group | GrpType]: + """Creates a new :class:`Group` with a function as callback. This + works otherwise the same as :func:`command` just that the `cls` + parameter is set to :class:`Group`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + """ + if cls is None: + cls = t.cast("type[GrpType]", Group) + + if callable(name): + return command(cls=cls, **attrs)(name) + + return command(name, cls, **attrs) + + +def _param_memo(f: t.Callable[..., t.Any], param: Parameter) -> None: + if isinstance(f, Command): + f.params.append(param) + else: + if not hasattr(f, "__click_params__"): + f.__click_params__ = [] # type: ignore + + f.__click_params__.append(param) # type: ignore + + +def argument( + *param_decls: str, cls: type[Argument] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an argument to the command. All positional arguments are + passed as parameter declarations to :class:`Argument`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Argument` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default argument class, refer to :class:`Argument` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Argument + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def option( + *param_decls: str, cls: type[Option] | None = None, **attrs: t.Any +) -> t.Callable[[FC], FC]: + """Attaches an option to the command. All positional arguments are + passed as parameter declarations to :class:`Option`; all keyword + arguments are forwarded unchanged (except ``cls``). + This is equivalent to creating an :class:`Option` instance manually + and attaching it to the :attr:`Command.params` list. + + For the default option class, refer to :class:`Option` and + :class:`Parameter` for descriptions of parameters. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + :param param_decls: Passed as positional arguments to the constructor of + ``cls``. + :param attrs: Passed as keyword arguments to the constructor of ``cls``. + """ + if cls is None: + cls = Option + + def decorator(f: FC) -> FC: + _param_memo(f, cls(param_decls, **attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: str | None = None, + *param_decls: str, + package_name: str | None = None, + prog_name: str | None = None, + message: str | None = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + import importlib.metadata + + try: + version = importlib.metadata.version(package_name) + except importlib.metadata.PackageNotFoundError: + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + message % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Pre-configured ``--help`` option which immediately prints the help page + and exits the program. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def show_help(ctx: Context, param: Parameter, value: bool) -> None: + """Callback that print the help page on ```` and exits.""" + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs.setdefault("callback", show_help) + + return option(*param_decls, **kwargs) diff --git a/venv/lib/python3.12/site-packages/click/exceptions.py b/venv/lib/python3.12/site-packages/click/exceptions.py new file mode 100644 index 00000000..f141a832 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/exceptions.py @@ -0,0 +1,308 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .globals import resolve_color_default +from .utils import echo +from .utils import format_filename + +if t.TYPE_CHECKING: + from .core import Command + from .core import Context + from .core import Parameter + + +def _join_param_hints(param_hint: cabc.Sequence[str] | str | None) -> str | None: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + # The context will be removed by the time we print the message, so cache + # the color settings here to be used later on (in `show`) + self.show_color: bool | None = resolve_color_default() + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=self.show_color, + ) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: Context | None = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd: Command | None = self.ctx.command if self.ctx else None + + def show(self, file: t.IO[t.Any] | None = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: str | None = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: str | None = None, + ctx: Context | None = None, + param: Parameter | None = None, + param_hint: str | None = None, + param_type: str | None = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: str | None = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message( + param=self.param, ctx=self.ctx + ) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: str | None = None, + possibilities: cabc.Sequence[str] | None = None, + ctx: Context | None = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: Context | None = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class NoArgsIsHelpError(UsageError): + def __init__(self, ctx: Context) -> None: + self.ctx: Context + super().__init__(ctx.get_help(), ctx=ctx) + + def show(self, file: t.IO[t.Any] | None = None) -> None: + echo(self.format_message(), file=file, err=True, color=self.ctx.color) + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: str | None = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename: str = format_filename(filename) + self.filename = filename + + def format_message(self) -> str: + return _("Could not open file {filename!r}: {message}").format( + filename=self.ui_filename, message=self.message + ) + + +class Abort(RuntimeError): + """An internal signalling exception that signals Click to abort.""" + + +class Exit(RuntimeError): + """An exception that indicates that the application should exit with some + status code. + + :param code: the status code to exit with. + """ + + __slots__ = ("exit_code",) + + def __init__(self, code: int = 0) -> None: + self.exit_code: int = code diff --git a/venv/lib/python3.12/site-packages/click/formatting.py b/venv/lib/python3.12/site-packages/click/formatting.py new file mode 100644 index 00000000..9891f880 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +from __future__ import annotations + +import collections.abc as cabc +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import _split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: int | None = None + + +def measure_table(rows: cabc.Iterable[tuple[str, str]]) -> tuple[int, ...]: + widths: dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: cabc.Iterable[tuple[str, str]], col_count: int +) -> cabc.Iterator[tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: list[tuple[int, bool, str]] = [] + buf: list[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: int | None = None, + max_width: int | None = None, + ) -> None: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent: int = 0 + self.buffer: list[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage(self, prog: str, args: str = "", prefix: str | None = None) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: cabc.Sequence[tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> cabc.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> cabc.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: cabc.Sequence[str]) -> tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = _split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/venv/lib/python3.12/site-packages/click/globals.py b/venv/lib/python3.12/site-packages/click/globals.py new file mode 100644 index 00000000..a2f91723 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/globals.py @@ -0,0 +1,67 @@ +from __future__ import annotations + +import typing as t +from threading import local + +if t.TYPE_CHECKING: + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: t.Literal[False] = False) -> Context: ... + + +@t.overload +def get_current_context(silent: bool = ...) -> Context | None: ... + + +def get_current_context(silent: bool = False) -> Context | None: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: Context) -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: bool | None = None) -> bool | None: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/venv/lib/python3.12/site-packages/click/parser.py b/venv/lib/python3.12/site-packages/click/parser.py new file mode 100644 index 00000000..a8b7d263 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/parser.py @@ -0,0 +1,532 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" + +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +from __future__ import annotations + +import collections.abc as cabc +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + + +def _unpack_args( + args: cabc.Sequence[str], nargs_spec: cabc.Sequence[int] +) -> tuple[cabc.Sequence[str | cabc.Sequence[str | None] | None], list[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: list[str | tuple[str | None, ...] | None] = [] + spos: int | None = None + + def _fetch(c: deque[V]) -> V | None: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def _split_opt(opt: str) -> tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def _normalize_opt(opt: str, ctx: Context | None) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = _split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +class _Option: + def __init__( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes: set[str] = set() + + for opt in opts: + prefix, value = _split_opt(opt) + if not prefix: + raise ValueError(f"Invalid start character for option ({opt})") + self.prefixes.add(prefix[0]) + if len(prefix) == 1 and len(value) == 1: + self._short_opts.append(opt) + else: + self._long_opts.append(opt) + self.prefixes.add(prefix) + + if action is None: + action = "store" + + self.dest = dest + self.action = action + self.nargs = nargs + self.const = const + self.obj = obj + + @property + def takes_value(self) -> bool: + return self.action in ("store", "append") + + def process(self, value: t.Any, state: _ParsingState) -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class _Argument: + def __init__(self, obj: CoreArgument, dest: str | None, nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: str | cabc.Sequence[str | None] | None, + state: _ParsingState, + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class _ParsingState: + def __init__(self, rargs: list[str]) -> None: + self.opts: dict[str, t.Any] = {} + self.largs: list[str] = [] + self.rargs = rargs + self.order: list[CoreParameter] = [] + + +class _OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + + .. deprecated:: 8.2 + Will be removed in Click 9.0. + """ + + def __init__(self, ctx: Context | None = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args: bool = True + #: This tells the parser how to deal with unknown options. By + #: default it will error out (which is sensible), but there is a + #: second mode where it will ignore it and continue processing + #: after shifting all the unknown options into the resulting args. + self.ignore_unknown_options: bool = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: dict[str, _Option] = {} + self._long_opt: dict[str, _Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: list[_Argument] = [] + + def add_option( + self, + obj: CoreOption, + opts: cabc.Sequence[str], + dest: str | None, + action: str | None = None, + nargs: int = 1, + const: t.Any | None = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [_normalize_opt(opt, self.ctx) for opt in opts] + option = _Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument(self, obj: CoreArgument, dest: str | None, nargs: int = 1) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(_Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: list[str] + ) -> tuple[dict[str, t.Any], list[str], list[CoreParameter]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = _ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: _ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: _ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: str | None, state: _ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: _ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = _normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we recombine the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: _Option, state: _ParsingState + ) -> t.Any: + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: _ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = _normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) + + +def __getattr__(name: str) -> object: + import warnings + + if name in { + "OptionParser", + "Argument", + "Option", + "split_opt", + "normalize_opt", + "ParsingState", + }: + warnings.warn( + f"'parser.{name}' is deprecated and will be removed in Click 9.0." + " The old parser is available in 'optparse'.", + DeprecationWarning, + stacklevel=2, + ) + return globals()[f"_{name}"] + + if name == "split_arg_string": + from .shell_completion import split_arg_string + + warnings.warn( + "Importing 'parser.split_arg_string' is deprecated, it will only be" + " available in 'shell_completion' in Click 9.0.", + DeprecationWarning, + stacklevel=2, + ) + return split_arg_string + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/click/py.typed b/venv/lib/python3.12/site-packages/click/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/click/shell_completion.py b/venv/lib/python3.12/site-packages/click/shell_completion.py new file mode 100644 index 00000000..6c39d5eb --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/shell_completion.py @@ -0,0 +1,644 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .utils import echo + + +def shell_complete( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: str | None = None, + **kwargs: t.Any, + ) -> None: + self.value: t.Any = value + self.type: str = type + self.help: str | None = help + self._info = kwargs + + def __getattr__(self, name: str) -> t.Any: + return self._info.get(name) + + +# Only Bash >= 4.4 has the nosort option. +_SOURCE_BASH = """\ +%(complete_func)s() { + local IFS=$'\\n' + local response + + response=$(env COMP_WORDS="${COMP_WORDS[*]}" COMP_CWORD=$COMP_CWORD \ +%(complete_var)s=bash_complete $1) + + for completion in $response; do + IFS=',' read type value <<< "$completion" + + if [[ $type == 'dir' ]]; then + COMPREPLY=() + compopt -o dirnames + elif [[ $type == 'file' ]]; then + COMPREPLY=() + compopt -o default + elif [[ $type == 'plain' ]]; then + COMPREPLY+=($value) + fi + done + + return 0 +} + +%(complete_func)s_setup() { + complete -o nosort -F %(complete_func)s %(prog_name)s +} + +%(complete_func)s_setup; +""" + +_SOURCE_ZSH = """\ +#compdef %(prog_name)s + +%(complete_func)s() { + local -a completions + local -a completions_with_descriptions + local -a response + (( ! $+commands[%(prog_name)s] )) && return 1 + + response=("${(@f)$(env COMP_WORDS="${words[*]}" COMP_CWORD=$((CURRENT-1)) \ +%(complete_var)s=zsh_complete %(prog_name)s)}") + + for type key descr in ${response}; do + if [[ "$type" == "plain" ]]; then + if [[ "$descr" == "_" ]]; then + completions+=("$key") + else + completions_with_descriptions+=("$key":"$descr") + fi + elif [[ "$type" == "dir" ]]; then + _path_files -/ + elif [[ "$type" == "file" ]]; then + _path_files -f + fi + done + + if [ -n "$completions_with_descriptions" ]; then + _describe -V unsorted completions_with_descriptions -U + fi + + if [ -n "$completions" ]; then + compadd -U -V unsorted -a completions + fi +} + +if [[ $zsh_eval_context[-1] == loadautofunc ]]; then + # autoload from fpath, call function directly + %(complete_func)s "$@" +else + # eval/source/. command, register function for later + compdef %(complete_func)s %(prog_name)s +fi +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + complete_var: str, + ) -> None: + self.cli = cli + self.ctx_args = ctx_args + self.prog_name = prog_name + self.complete_var = complete_var + + @property + def func_name(self) -> str: + """The name of the shell function defined by the completion + script. + """ + safe_name = re.sub(r"\W*", "", self.prog_name.replace("-", "_"), flags=re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> tuple[list[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions(self, args: list[str], incomplete: str) -> list[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + @staticmethod + def _check_version() -> None: + import shutil + import subprocess + + bash_exe = shutil.which("bash") + + if bash_exe is None: + match = None + else: + output = subprocess.run( + [bash_exe, "--norc", "-c", 'echo "${BASH_VERSION}"'], + stdout=subprocess.PIPE, + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + echo( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ), + err=True, + ) + else: + echo( + _("Couldn't detect Bash version, shell completion is not supported."), + err=True, + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> tuple[list[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +ShellCompleteType = t.TypeVar("ShellCompleteType", bound="type[ShellComplete]") + + +_available_shells: dict[str, type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: ShellCompleteType, name: str | None = None +) -> ShellCompleteType: + """Register a :class:`ShellComplete` subclass under the given name. + The name will be provided by the completion instruction environment + variable during completion. + + :param cls: The completion class that will handle completion for the + shell. + :param name: Name to register the class under. Defaults to the + class's ``name`` attribute. + """ + if name is None: + name = cls.name + + _available_shells[name] = cls + + return cls + + +def get_completion_class(shell: str) -> type[ShellComplete] | None: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def split_arg_string(string: str) -> list[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + + .. versionchanged:: 8.2 + Moved to ``shell_completion`` from ``parser``. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + # Will be None if expose_value is False. + value = ctx.params.get(param.name) + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: list[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: Command, + ctx_args: cabc.MutableMapping[str, t.Any], + prog_name: str, + args: list[str], +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + with cli.make_context(prog_name, args.copy(), **ctx_args) as ctx: + args = ctx._protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, Group): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, args, parent=ctx, resilient_parsing=True + ) as sub_ctx: + ctx = sub_ctx + args = ctx._protected_args + ctx.args + else: + sub_ctx = ctx + + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + with cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) as sub_sub_ctx: + sub_ctx = sub_sub_ctx + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx._protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: list[str], incomplete: str +) -> tuple[Command | Parameter, str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/venv/lib/python3.12/site-packages/click/termui.py b/venv/lib/python3.12/site-packages/click/termui.py new file mode 100644 index 00000000..dcbb2221 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/termui.py @@ -0,0 +1,877 @@ +from __future__ import annotations + +import collections.abc as cabc +import inspect +import io +import itertools +import sys +import typing as t +from contextlib import AbstractContextManager +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Any | None = None, + show_choices: bool = True, + type: ParamType | None = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name + + return default + + +def prompt( + text: str, + default: t.Any | None = None, + hide_input: bool = False, + confirmation_prompt: bool | str = False, + type: ParamType | t.Any | None = None, + value_proc: t.Callable[[str], t.Any] | None = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: bool | None = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: cabc.Iterable[str] | t.Callable[[], cabc.Iterable[str]] | str, + color: bool | None = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast("t.Callable[[], cabc.Iterable[str]]", text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast("cabc.Iterable[str]", text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +@t.overload +def progressbar( + *, + length: int, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[int]: ... + + +@t.overload +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: ... + + +def progressbar( + iterable: cabc.Iterable[V] | None = None, + length: int | None = None, + label: str | None = None, + hidden: bool = False, + show_eta: bool = True, + show_percent: bool | None = None, + show_pos: bool = False, + item_show_func: t.Callable[[V | None], str | None] | None = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.TextIO | None = None, + color: bool | None = None, + update_min_steps: int = 1, +) -> ProgressBar[V]: + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param hidden: hide the progressbar. Defaults to ``False``. When no tty is + detected, it will only print the progressbar label. Setting this to + ``False`` also disables that. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionadded:: 8.2 + The ``hidden`` argument. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + The ``update_min_steps`` parameter. + + .. versionadded:: 4.0 + The ``color`` parameter and ``update`` method. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + hidden=hidden, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + + # ANSI escape \033[2J clears the screen, \033[1;1H moves the cursor + echo("\033[2J\033[1;1H", nl=False) + + +def _interpret_color(color: int | tuple[int, int, int] | str, offset: int = 0) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: int | tuple[int, int, int] | str | None = None, + bg: int | tuple[int, int, int] | str | None = None, + bold: bool | None = None, + dim: bool | None = None, + underline: bool | None = None, + overline: bool | None = None, + italic: bool | None = None, + blink: bool | None = None, + reverse: bool | None = None, + strikethrough: bool | None = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Any | None = None, + file: t.IO[t.AnyStr] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +@t.overload +def edit( + text: bytes | bytearray, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = False, + extension: str = ".txt", +) -> bytes | None: ... + + +@t.overload +def edit( + text: str, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", +) -> str | None: ... + + +@t.overload +def edit( + text: None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> None: ... + + +def edit( + text: str | bytes | bytearray | None = None, + editor: str | None = None, + env: cabc.Mapping[str, str] | None = None, + require_save: bool = True, + extension: str = ".txt", + filename: str | cabc.Iterable[str] | None = None, +) -> str | bytes | bytearray | None: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. If the editor supports + editing multiple files at once, a sequence of files may be + passed as well. Invoke `click.file` once per file instead + if multiple files cannot be managed at once or editing the + files serially is desired. + + .. versionchanged:: 8.2.0 + ``filename`` now accepts any ``Iterable[str]`` in addition to a ``str`` + if the ``editor`` supports editing multiple files at once. + + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + if isinstance(filename, str): + filename = (filename,) + + ed.edit_files(filenames=filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Callable[[bool], str] | None = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> AbstractContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: str | None = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/venv/lib/python3.12/site-packages/click/testing.py b/venv/lib/python3.12/site-packages/click/testing.py new file mode 100644 index 00000000..7c0e8741 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/testing.py @@ -0,0 +1,565 @@ +from __future__ import annotations + +import collections.abc as cabc +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import _compat +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from _typeshed import ReadableBuffer + + from .core import Command + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> list[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> cabc.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: EchoingStdin | None) -> cabc.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class BytesIOCopy(io.BytesIO): + """Patch ``io.BytesIO`` to let the written stream be copied to another. + + .. versionadded:: 8.2 + """ + + def __init__(self, copy_to: io.BytesIO) -> None: + super().__init__() + self.copy_to = copy_to + + def flush(self) -> None: + super().flush() + self.copy_to.flush() + + def write(self, b: ReadableBuffer) -> int: + self.copy_to.write(b) + return super().write(b) + + +class StreamMixer: + """Mixes `` and `` streams. + + The result is available in the ``output`` attribute. + + .. versionadded:: 8.2 + """ + + def __init__(self) -> None: + self.output: io.BytesIO = io.BytesIO() + self.stdout: io.BytesIO = BytesIOCopy(copy_to=self.output) + self.stderr: io.BytesIO = BytesIOCopy(copy_to=self.output) + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + def __next__(self) -> str: # type: ignore + try: + line = super().__next__() + except StopIteration as e: + raise EOFError() from e + return line + + +def make_input_stream( + input: str | bytes | t.IO[t.Any] | None, charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast("t.IO[t.Any]", input)) + + if rv is not None: + return rv + + raise TypeError("Could not find binary reader for input stream.") + + if input is None: + input = b"" + elif isinstance(input, str): + input = input.encode(charset) + + return io.BytesIO(input) + + +class Result: + """Holds the captured result of an invoked CLI script. + + :param runner: The runner that created the result + :param stdout_bytes: The standard output as bytes. + :param stderr_bytes: The standard error as bytes. + :param output_bytes: A mix of ``stdout_bytes`` and ``stderr_bytes``, as the + user would see it in its terminal. + :param return_value: The value returned from the invoked command. + :param exit_code: The exit code as integer. + :param exception: The exception that happened if one did. + :param exc_info: Exception information (exception type, exception instance, + traceback type). + + .. versionchanged:: 8.2 + ``stderr_bytes`` no longer optional, ``output_bytes`` introduced and + ``mix_stderr`` has been removed. + + .. versionadded:: 8.0 + Added ``return_value``. + """ + + def __init__( + self, + runner: CliRunner, + stdout_bytes: bytes, + stderr_bytes: bytes, + output_bytes: bytes, + return_value: t.Any, + exit_code: int, + exception: BaseException | None, + exc_info: tuple[type[BaseException], BaseException, TracebackType] + | None = None, + ): + self.runner = runner + self.stdout_bytes = stdout_bytes + self.stderr_bytes = stderr_bytes + self.output_bytes = output_bytes + self.return_value = return_value + self.exit_code = exit_code + self.exception = exception + self.exc_info = exc_info + + @property + def output(self) -> str: + """The terminal output as unicode string, as the user would see it. + + .. versionchanged:: 8.2 + No longer a proxy for ``self.stdout``. Now has its own independent stream + that is mixing `` and ``, in the order they were written. + """ + return self.output_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string. + + .. versionchanged:: 8.2 + No longer raise an exception, always returns the `` string. + """ + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from `` writes + to ``. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param catch_exceptions: Whether to catch any exceptions other than + ``SystemExit`` when running :meth:`~CliRunner.invoke`. + + .. versionchanged:: 8.2 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 8.2 + ``mix_stderr`` parameter has been removed. + """ + + def __init__( + self, + charset: str = "utf-8", + env: cabc.Mapping[str, str | None] | None = None, + echo_stdin: bool = False, + catch_exceptions: bool = True, + ) -> None: + self.charset = charset + self.env: cabc.Mapping[str, str | None] = env or {} + self.echo_stdin = echo_stdin + self.catch_exceptions = catch_exceptions + + def get_default_prog_name(self, cli: Command) -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: cabc.Mapping[str, str | None] | None = None + ) -> cabc.Mapping[str, str | None]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + color: bool = False, + ) -> cabc.Iterator[tuple[io.BytesIO, io.BytesIO, io.BytesIO]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up `` with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into `sys.stdin`. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + An additional output stream is returned, which is a mix of + `` and `` streams. + + .. versionchanged:: 8.2 + Always returns the `` stream. + + .. versionchanged:: 8.0 + `` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + stream_mixer = StreamMixer() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, stream_mixer.stdout) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + stream_mixer.stdout, encoding=self.charset, name="", mode="w" + ) + + sys.stderr = _NamedTextIOWrapper( + stream_mixer.stderr, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: str | None = None) -> str: + sys.stdout.write(prompt or "") + val = next(text_input).rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: str | None = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return next(text_input).rstrip("\r\n") + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.IO[t.Any] | None = None, color: bool | None = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + old__compat_should_strip_ansi = _compat.should_strip_ansi + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + _compat.should_strip_ansi = should_strip_ansi + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (stream_mixer.stdout, stream_mixer.stderr, stream_mixer.output) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + _compat.should_strip_ansi = old__compat_should_strip_ansi + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: Command, + args: str | cabc.Sequence[str] | None = None, + input: str | bytes | t.IO[t.Any] | None = None, + env: cabc.Mapping[str, str | None] | None = None, + catch_exceptions: bool | None = None, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. If :data:`None`, the value + from :class:`CliRunner` is used. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionadded:: 8.2 + The result object has the ``output_bytes`` attribute with + the mix of ``stdout_bytes`` and ``stderr_bytes``, as the user would + see it in its terminal. + + .. versionchanged:: 8.2 + The result object always returns the ``stderr_bytes`` stream. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + if catch_exceptions is None: + catch_exceptions = self.catch_exceptions + + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: BaseException | None = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast("int | t.Any | None", e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + sys.stderr.flush() + stdout = outstreams[0].getvalue() + stderr = outstreams[1].getvalue() + output = outstreams[2].getvalue() + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + output_bytes=output, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: str | os.PathLike[str] | None = None + ) -> cabc.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) + os.chdir(dt) + + try: + yield dt + finally: + os.chdir(cwd) + + if temp_dir is None: + try: + shutil.rmtree(dt) + except OSError: + pass diff --git a/venv/lib/python3.12/site-packages/click/types.py b/venv/lib/python3.12/site-packages/click/types.py new file mode 100644 index 00000000..684cb3b1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/types.py @@ -0,0 +1,1165 @@ +from __future__ import annotations + +import collections.abc as cabc +import enum +import os +import stat +import sys +import typing as t +from datetime import datetime +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import _get_argv_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import format_filename +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + +ParamTypeValue = t.TypeVar("ParamTypeValue") + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[str | None] = None + + def to_info_dict(self) -> dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str | None: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> cabc.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: Parameter | None = None, + ctx: Context | None = None, + ) -> t.NoReturn: + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name: str = func.__name__ + self.func = func + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = sys.getfilesystemencoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType, t.Generic[ParamTypeValue]): + """The choice type allows a value to be checked against a fixed set + of supported values. + + You may pass any iterable value which will be converted to a tuple + and thus will only be iterated once. + + The resulting value will always be one of the originally passed choices. + See :meth:`normalize_choice` for more info on the mapping of strings + to choices. See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + + .. versionchanged:: 8.2.0 + Non-``str`` ``choices`` are now supported. It can additionally be any + iterable. Before you were not recommended to pass anything but a list or + tuple. + + .. versionadded:: 8.2.0 + Choice normalization can be overridden via :meth:`normalize_choice`. + """ + + name = "choice" + + def __init__( + self, choices: cabc.Iterable[ParamTypeValue], case_sensitive: bool = True + ) -> None: + self.choices: cabc.Sequence[ParamTypeValue] = tuple(choices) + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def _normalized_mapping( + self, ctx: Context | None = None + ) -> cabc.Mapping[ParamTypeValue, str]: + """ + Returns mapping where keys are the original choices and the values are + the normalized values that are accepted via the command line. + + This is a simple wrapper around :meth:`normalize_choice`, use that + instead which is supported. + """ + return { + choice: self.normalize_choice( + choice=choice, + ctx=ctx, + ) + for choice in self.choices + } + + def normalize_choice(self, choice: ParamTypeValue, ctx: Context | None) -> str: + """ + Normalize a choice value, used to map a passed string to a choice. + Each choice must have a unique normalized value. + + By default uses :meth:`Context.token_normalize_func` and if not case + sensitive, convert it to a casefolded value. + + .. versionadded:: 8.2.0 + """ + normed_value = choice.name if isinstance(choice, enum.Enum) else str(choice) + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(normed_value) + + if not self.case_sensitive: + normed_value = normed_value.casefold() + + return normed_value + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + if param.param_type_name == "option" and not param.show_choices: # type: ignore + choice_metavars = [ + convert_type(type(choice)).name.upper() for choice in self.choices + ] + choices_str = "|".join([*dict.fromkeys(choice_metavars)]) + else: + choices_str = "|".join( + [str(i) for i in self._normalized_mapping(ctx=ctx).values()] + ) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: Parameter, ctx: Context | None) -> str: + """ + Message shown when no choice is passed. + + .. versionchanged:: 8.2.0 Added ``ctx`` argument. + """ + return _("Choose from:\n\t{choices}").format( + choices=",\n\t".join(self._normalized_mapping(ctx=ctx).values()) + ) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> ParamTypeValue: + """ + For a given value from the parser, normalize it and find its + matching normalized value in the list of choices. Then return the + matched "original" choice. + """ + normed_value = self.normalize_choice(choice=value, ctx=ctx) + normalized_mapping = self._normalized_mapping(ctx=ctx) + + try: + return next( + original + for original, normalized in normalized_mapping.items() + if normalized == normed_value + ) + except StopIteration: + self.fail( + self.get_invalid_choice_message(value=value, ctx=ctx), + param=param, + ctx=ctx, + ) + + def get_invalid_choice_message(self, value: t.Any, ctx: Context | None) -> str: + """Get the error message when the given choice is invalid. + + :param value: The invalid value. + + .. versionadded:: 8.2 + """ + choices_str = ", ".join(map(repr, self._normalized_mapping(ctx=ctx).values())) + return ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: cabc.Sequence[str] | None = None): + self.formats: cabc.Sequence[str] = formats or [ + "%Y-%m-%d", + "%Y-%m-%dT%H:%M:%S", + "%Y-%m-%d %H:%M:%S", + ] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: Parameter, ctx: Context) -> str | None: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> datetime | None: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[type[t.Any]] + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: t.Literal[1, -1], open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: float | None = None, + max: float | None = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: t.Literal[1, -1], open: bool) -> float: + if not open: + return bound + + # Could use math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Files can also be opened atomically in which case all writes go into a + separate file in the same folder and upon completion the file will + be moved over to the original location. This is useful if a file + regularly read by other users is modified. + + See :ref:`file-args` for more information. + + .. versionchanged:: 2.0 + Added the ``atomic`` parameter. + """ + + name = "filename" + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool | None = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: str | os.PathLike[str]) -> bool: + if self.lazy is not None: + return self.lazy + if os.fspath(value) == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, + value: str | os.PathLike[str] | t.IO[t.Any], + param: Parameter | None, + ctx: Context | None, + ) -> t.IO[t.Any]: + if _is_file_like(value): + return value + + value = t.cast("str | os.PathLike[str]", value) + + try: + lazy = self.resolve_lazy_flag(value) + + if lazy: + lf = LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + if ctx is not None: + ctx.call_on_close(lf.close_intelligently) + + return t.cast("t.IO[t.Any]", lf) + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: + self.fail(f"'{format_filename(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +def _is_file_like(value: t.Any) -> te.TypeGuard[t.IO[t.Any]]: + return hasattr(value, "read") or hasattr(value, "write") + + +class Path(ParamType): + """The ``Path`` type is similar to the :class:`File` type, but + returns the filename instead of an open file. Various checks can be + enabled to validate the type of file and permissions. + + :param exists: The file or directory needs to exist for the value to + be valid. If this is not set to ``True``, and the file does not + exist, then all further checks are silently skipped. + :param file_okay: Allow a file as a value. + :param dir_okay: Allow a directory as a value. + :param readable: if true, a readable check is performed. + :param writable: if true, a writable check is performed. + :param executable: if true, an executable check is performed. + :param resolve_path: Make the value absolute and resolve any + symlinks. A ``~`` is not expanded, as this is supposed to be + done by the shell only. + :param allow_dash: Allow a single dash as a value, which indicates + a standard stream (but does not open it). Use + :func:`~click.open_file` to handle opening this value. + :param path_type: Convert the incoming path value to this type. If + ``None``, keep Python's default, which is ``str``. Useful to + convert to :class:`pathlib.Path`. + + .. versionchanged:: 8.1 + Added the ``executable`` parameter. + + .. versionchanged:: 8.0 + Allow passing ``path_type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter: t.ClassVar[str] = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: type[t.Any] | None = None, + executable: bool = False, + ): + self.exists = exists + self.file_okay = file_okay + self.dir_okay = dir_okay + self.readable = readable + self.writable = writable + self.executable = executable + self.resolve_path = resolve_path + self.allow_dash = allow_dash + self.type = path_type + + if self.file_okay and not self.dir_okay: + self.name: str = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result( + self, value: str | os.PathLike[str] + ) -> str | bytes | os.PathLike[str]: + if self.type is not None and not isinstance(value, self.type): + if self.type is str: + return os.fsdecode(value) + elif self.type is bytes: + return os.fsencode(value) + else: + return t.cast("os.PathLike[str]", self.type(value)) + + return value + + def convert( + self, + value: str | os.PathLike[str], + param: Parameter | None, + ctx: Context | None, + ) -> str | bytes | os.PathLike[str]: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + rv = os.path.realpath(rv) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if not self.file_okay and stat.S_ISREG(st.st_mode): + self.fail( + _("{name} {filename!r} is a file.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} {filename!r} is a directory.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.readable and not os.access(rv, os.R_OK): + self.fail( + _("{name} {filename!r} is not readable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.writable and not os.access(rv, os.W_OK): + self.fail( + _("{name} {filename!r} is not writable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + if self.executable and not os.access(value, os.X_OK): + self.fail( + _("{name} {filename!r} is not executable.").format( + name=self.name.title(), filename=format_filename(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: Context, param: Parameter, incomplete: str + ) -> list[CompletionItem]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: cabc.Sequence[type[t.Any] | ParamType]) -> None: + self.types: cabc.Sequence[ParamType] = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: Parameter | None, ctx: Context | None + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple( + ty(x, param, ctx) for ty, x in zip(self.types, value, strict=False) + ) + + +def convert_type(ty: t.Any | None, default: t.Any | None = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() + + +class OptionHelpExtra(t.TypedDict, total=False): + envvars: tuple[str, ...] + default: str + range: str + required: str diff --git a/venv/lib/python3.12/site-packages/click/utils.py b/venv/lib/python3.12/site-packages/click/utils.py new file mode 100644 index 00000000..ab2fe588 --- /dev/null +++ b/venv/lib/python3.12/site-packages/click/utils.py @@ -0,0 +1,627 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType +from types import TracebackType + +from ._compat import _default_text_stderr +from ._compat import _default_text_stdout +from ._compat import _find_binary_writer +from ._compat import auto_wrap_for_ansi +from ._compat import binary_streams +from ._compat import open_stream +from ._compat import should_strip_ansi +from ._compat import strip_ansi +from ._compat import text_streams +from ._compat import WIN +from .globals import resolve_color_default + +if t.TYPE_CHECKING: + import typing_extensions as te + + P = te.ParamSpec("P") + +R = t.TypeVar("R") + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: t.Callable[P, R]) -> t.Callable[P, R | None]: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args: P.args, **kwargs: P.kwargs) -> R | None: + try: + return func(*args, **kwargs) + except Exception: + pass + return None + + return update_wrapper(wrapper, func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(sys.getfilesystemencoding()) + except UnicodeError: + return value.decode("utf-8", "replace") + return str(value) + + +def make_default_short_help(help: str, max_length: int = 45) -> str: + """Returns a condensed version of help string.""" + # Consider only the first paragraph. + paragraph_end = help.find("\n\n") + + if paragraph_end != -1: + help = help[:paragraph_end] + + # Collapse newlines, tabs, and spaces. + words = help.split() + + if not words: + return "" + + # The first paragraph started with a "no rewrap" marker, ignore it. + if words[0] == "\b": + words = words[1:] + + total_length = 0 + last_index = len(words) - 1 + + for i, word in enumerate(words): + total_length += len(word) + (i > 0) + + if total_length > max_length: # too long, truncate + break + + if word[-1] == ".": # sentence end, truncate without "..." + return " ".join(words[: i + 1]) + + if total_length == max_length and i != last_index: + break # not at sentence end, truncate with "..." + else: + return " ".join(words) # no truncation needed + + # Account for the length of the suffix. + total_length += len("...") + + # remove words until the length is short enough + while i > 0: + total_length -= len(words[i]) + (i > 0) + + if total_length <= max_length: + break + + i -= 1 + + return " ".join(words[:i]) + "..." + + +class LazyFile: + """A lazy file works like a regular file but it does not fully open + the file but it does perform some basic checks early to see if the + filename parameter does make sense. This is useful for safely opening + files for writing. + """ + + def __init__( + self, + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + atomic: bool = False, + ): + self.name: str = os.fspath(filename) + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.IO[t.Any] | None + self.should_close: bool + + if self.name == "-": + self._f, self.should_close = open_stream(filename, mode, encoding, errors) + else: + if "r" in mode: + # Open and close the file in case we're opening it for + # reading so that we can catch at least some errors in + # some cases early. + open(filename, mode).close() + self._f = None + self.should_close = True + + def __getattr__(self, name: str) -> t.Any: + return getattr(self.open(), name) + + def __repr__(self) -> str: + if self._f is not None: + return repr(self._f) + return f"" + + def open(self) -> t.IO[t.Any]: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> LazyFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.close_intelligently() + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO[t.Any]) -> None: + self._file: t.IO[t.Any] = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> KeepOpenFile: + return self + + def __exit__( + self, + exc_type: type[BaseException] | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> cabc.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Any | None = None, + file: t.IO[t.Any] | None = None, + nl: bool = True, + err: bool = False, + color: bool | None = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # There are no standard streams attached to write to. For example, + # pythonw on Windows. + if file is None: + return + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: str | bytes | None = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file, color) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: t.Literal["stdin", "stdout", "stderr"]) -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: t.Literal["stdin", "stdout", "stderr"], + encoding: str | None = None, + errors: str | None = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str | os.PathLike[str], + mode: str = "r", + encoding: str | None = None, + errors: str | None = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO[t.Any]: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name or Path of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast( + "t.IO[t.Any]", LazyFile(filename, mode, encoding, errors, atomic=atomic) + ) + + f, should_close = open_stream(filename, mode, encoding, errors, atomic=atomic) + + if not should_close: + f = t.cast("t.IO[t.Any]", KeepOpenFile(f)) + + return f + + +def format_filename( + filename: str | bytes | os.PathLike[str] | os.PathLike[bytes], + shorten: bool = False, +) -> str: + """Format a filename as a string for display. Ensures the filename can be + displayed by replacing any invalid bytes or surrogate escapes in the name + with the replacement character ``�``. + + Invalid bytes or surrogate escapes will raise an error when written to a + stream with ``errors="strict"``. This will typically happen with ``stdout`` + when the locale is something like ``en_GB.UTF-8``. + + Many scenarios *are* safe to write surrogates though, due to PEP 538 and + PEP 540, including: + + - Writing to ``stderr``, which uses ``errors="backslashreplace"``. + - The system has ``LANG=C.UTF-8``, ``C``, or ``POSIX``. Python opens + stdout and stderr with ``errors="surrogateescape"``. + - None of ``LANG/LC_*`` are set. Python assumes ``LANG=C.UTF-8``. + - Python is started in UTF-8 mode with ``PYTHONUTF8=1`` or ``-X utf8``. + Python opens stdout and stderr with ``errors="surrogateescape"``. + + :param filename: formats a filename for UI display. This will also convert + the filename into unicode without failing. + :param shorten: this optionally shortens the filename to strip of the + path that leads up to it. + """ + if shorten: + filename = os.path.basename(filename) + else: + filename = os.fspath(filename) + + if isinstance(filename, bytes): + filename = filename.decode(sys.getfilesystemencoding(), "replace") + else: + filename = filename.encode("utf-8", "surrogateescape").decode( + "utf-8", "replace" + ) + + return filename + + +def get_app_dir(app_name: str, roaming: bool = True, force_posix: bool = False) -> str: + r"""Returns the config folder for the application. The default behavior + is to return whatever is most appropriate for the operating system. + + To give you an idea, for an app called ``"Foo Bar"``, something like + the following folders could be returned: + + Mac OS X: + ``~/Library/Application Support/Foo Bar`` + Mac OS X (POSIX): + ``~/.foo-bar`` + Unix: + ``~/.config/foo-bar`` + Unix (POSIX): + ``~/.foo-bar`` + Windows (roaming): + ``C:\Users\\AppData\Roaming\Foo Bar`` + Windows (not roaming): + ``C:\Users\\AppData\Local\Foo Bar`` + + .. versionadded:: 2.0 + + :param app_name: the application name. This should be properly capitalized + and can contain whitespace. + :param roaming: controls if the folder should be roaming or not on Windows. + Has no effect otherwise. + :param force_posix: if this is set to `True` then on any POSIX system the + folder will be stored in the home folder with a leading + dot instead of the XDG config home or darwin's + application support folder. + """ + if WIN: + key = "APPDATA" if roaming else "LOCALAPPDATA" + folder = os.environ.get(key) + if folder is None: + folder = os.path.expanduser("~") + return os.path.join(folder, app_name) + if force_posix: + return os.path.join(os.path.expanduser(f"~/.{_posixify(app_name)}")) + if sys.platform == "darwin": + return os.path.join( + os.path.expanduser("~/Library/Application Support"), app_name + ) + return os.path.join( + os.environ.get("XDG_CONFIG_HOME", os.path.expanduser("~/.config")), + _posixify(app_name), + ) + + +class PacifyFlushWrapper: + """This wrapper is used to catch and suppress BrokenPipeErrors resulting + from ``.flush()`` being called on broken pipe during the shutdown/final-GC + of the Python interpreter. Notably ``.flush()`` is always called on + ``sys.stdout`` and ``sys.stderr``. So as to have minimal impact on any + other cleanup code, and the case where the underlying file is not a broken + pipe, all calls and attributes are proxied. + """ + + def __init__(self, wrapped: t.IO[t.Any]) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: str | None = None, _main: ModuleType | None = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + # It is set to "" inside a Shiv or PEX zipapp. + if getattr(_main, "__package__", None) in {None, ""} or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: cabc.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> list[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA new file mode 100644 index 00000000..42ce2131 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/METADATA @@ -0,0 +1,89 @@ +Metadata-Version: 2.4 +Name: Flask +Version: 3.1.1 +Summary: A simple framework for building complex web applications. +Maintainer-email: Pallets +Requires-Python: >=3.9 +Description-Content-Type: text/markdown +License-Expression: BSD-3-Clause +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: blinker>=1.9.0 +Requires-Dist: click>=8.1.3 +Requires-Dist: importlib-metadata>=3.6.0; python_version < '3.10' +Requires-Dist: itsdangerous>=2.2.0 +Requires-Dist: jinja2>=3.1.2 +Requires-Dist: markupsafe>=2.1.1 +Requires-Dist: werkzeug>=3.1.0 +Requires-Dist: asgiref>=3.2 ; extra == "async" +Requires-Dist: python-dotenv ; extra == "dotenv" +Project-URL: Changes, https://flask.palletsprojects.com/page/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/flask/ +Provides-Extra: async +Provides-Extra: dotenv + +# Flask + +Flask is a lightweight [WSGI] web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around [Werkzeug] +and [Jinja], and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +[WSGI]: https://wsgi.readthedocs.io/ +[Werkzeug]: https://werkzeug.palletsprojects.com/ +[Jinja]: https://jinja.palletsprojects.com/ + +## A Simple Example + +```python +# save this as app.py +from flask import Flask + +app = Flask(__name__) + +@app.route("/") +def hello(): + return "Hello, World!" +``` + +``` +$ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) +``` + +## Donate + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD new file mode 100644 index 00000000..c728867a --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/RECORD @@ -0,0 +1,58 @@ +../../../bin/flask,sha256=2mpWFp8C3b9GEEUrZEmcJH4oc687AZr7V9C2jrVfEUc,231 +flask-3.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +flask-3.1.1.dist-info/METADATA,sha256=EsnOyVfBXjw1BkGn-9lrI5mcv1NwYyB4_CfdW2FSDZQ,3014 +flask-3.1.1.dist-info/RECORD,, +flask-3.1.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask-3.1.1.dist-info/WHEEL,sha256=G2gURzTEtmeR8nrdXUJfNiB3VYVxigPQ-bEQujpNiNs,82 +flask-3.1.1.dist-info/entry_points.txt,sha256=bBP7hTOS5fz9zLtC7sPofBZAlMkEvBxu7KqS6l5lvc4,40 +flask-3.1.1.dist-info/licenses/LICENSE.txt,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +flask/__init__.py,sha256=mHvJN9Swtl1RDtjCqCIYyIniK_SZ_l_hqUynOzgpJ9o,2701 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-312.pyc,, +flask/__pycache__/__main__.cpython-312.pyc,, +flask/__pycache__/app.cpython-312.pyc,, +flask/__pycache__/blueprints.cpython-312.pyc,, +flask/__pycache__/cli.cpython-312.pyc,, +flask/__pycache__/config.cpython-312.pyc,, +flask/__pycache__/ctx.cpython-312.pyc,, +flask/__pycache__/debughelpers.cpython-312.pyc,, +flask/__pycache__/globals.cpython-312.pyc,, +flask/__pycache__/helpers.cpython-312.pyc,, +flask/__pycache__/logging.cpython-312.pyc,, +flask/__pycache__/sessions.cpython-312.pyc,, +flask/__pycache__/signals.cpython-312.pyc,, +flask/__pycache__/templating.cpython-312.pyc,, +flask/__pycache__/testing.cpython-312.pyc,, +flask/__pycache__/typing.cpython-312.pyc,, +flask/__pycache__/views.cpython-312.pyc,, +flask/__pycache__/wrappers.cpython-312.pyc,, +flask/app.py,sha256=XGqgFRsLgBhzIoB2HSftoMTIM3hjDiH6rdV7c3g3IKc,61744 +flask/blueprints.py,sha256=p5QE2lY18GItbdr_RKRpZ8Do17g0PvQGIgZkSUDhX2k,4541 +flask/cli.py,sha256=Pfh72-BxlvoH0QHCDOc1HvXG7Kq5Xetf3zzNz2kNSHk,37184 +flask/config.py,sha256=PiqF0DPam6HW0FH4CH1hpXTBe30NSzjPEOwrz1b6kt0,13219 +flask/ctx.py,sha256=4atDhJJ_cpV1VMq4qsfU4E_61M1oN93jlS2H9gjrl58,15120 +flask/debughelpers.py,sha256=PGIDhStW_efRjpaa3zHIpo-htStJOR41Ip3OJWPYBwo,6080 +flask/globals.py,sha256=XdQZmStBmPIs8t93tjx6pO7Bm3gobAaONWkFcUHaGas,1713 +flask/helpers.py,sha256=7njmzkFJvrPSQudsgONsgQzaGrGppeBINevKgWescPk,23521 +flask/json/__init__.py,sha256=hLNR898paqoefdeAhraa5wyJy-bmRB2k2dV4EgVy2Z8,5602 +flask/json/__pycache__/__init__.cpython-312.pyc,, +flask/json/__pycache__/provider.cpython-312.pyc,, +flask/json/__pycache__/tag.cpython-312.pyc,, +flask/json/provider.py,sha256=5imEzY5HjV2HoUVrQbJLqXCzMNpZXfD0Y1XqdLV2XBA,7672 +flask/json/tag.py,sha256=DhaNwuIOhdt2R74oOC9Y4Z8ZprxFYiRb5dUP5byyINw,9281 +flask/logging.py,sha256=8sM3WMTubi1cBb2c_lPkWpN0J8dMAqrgKRYLLi1dCVI,2377 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/sansio/README.md,sha256=-0X1tECnilmz1cogx-YhNw5d7guK7GKrq_DEV2OzlU0,228 +flask/sansio/__pycache__/app.cpython-312.pyc,, +flask/sansio/__pycache__/blueprints.cpython-312.pyc,, +flask/sansio/__pycache__/scaffold.cpython-312.pyc,, +flask/sansio/app.py,sha256=Wj9NVGtiR1jvkZ9gSFd91usUlM8H0g06aPVz2sMh4bw,38116 +flask/sansio/blueprints.py,sha256=Tqe-7EkZ-tbWchm8iDoCfD848f0_3nLv6NNjeIPvHwM,24637 +flask/sansio/scaffold.py,sha256=q6wM4Y4aYMGGN_Litsj3PYKpBS3Zvut0xhDmpBEHFdo,30387 +flask/sessions.py,sha256=ED_OV3Jl1emsy7Zntb7aFWxyoynt-PzNY0eFUH-Syo0,15495 +flask/signals.py,sha256=V7lMUww7CqgJ2ThUBn1PiatZtQanOyt7OZpu2GZI-34,750 +flask/templating.py,sha256=2TcXLT85Asflm2W9WOSFxKCmYn5e49w_Jkg9-NaaJWo,7537 +flask/testing.py,sha256=JT9fi_-_qsAXIpC1NSWcp1VrO-QSXgmdq95extfCwEw,10136 +flask/typing.py,sha256=L-L5t2jKgS0aOmVhioQ_ylqcgiVFnA6yxO-RLNhq-GU,3293 +flask/views.py,sha256=xzJx6oJqGElThtEghZN7ZQGMw5TDFyuRxUkecwRuAoA,6962 +flask/wrappers.py,sha256=jUkv4mVek2Iq4hwxd4RvqrIMb69Bv0PElDgWLmd5ORo,9406 diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/REQUESTED b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/REQUESTED new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL new file mode 100644 index 00000000..d8b9936d --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.12.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt new file mode 100644 index 00000000..eec6733e --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[console_scripts] +flask=flask.cli:main + diff --git a/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..9d227a0c --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask-3.1.1.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/flask/__init__.py b/venv/lib/python3.12/site-packages/flask/__init__.py new file mode 100644 index 00000000..1fdc50ce --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__init__.py @@ -0,0 +1,61 @@ +from __future__ import annotations + +import typing as t + +from . import json as json +from .app import Flask as Flask +from .blueprints import Blueprint as Blueprint +from .config import Config as Config +from .ctx import after_this_request as after_this_request +from .ctx import copy_current_request_context as copy_current_request_context +from .ctx import has_app_context as has_app_context +from .ctx import has_request_context as has_request_context +from .globals import current_app as current_app +from .globals import g as g +from .globals import request as request +from .globals import session as session +from .helpers import abort as abort +from .helpers import flash as flash +from .helpers import get_flashed_messages as get_flashed_messages +from .helpers import get_template_attribute as get_template_attribute +from .helpers import make_response as make_response +from .helpers import redirect as redirect +from .helpers import send_file as send_file +from .helpers import send_from_directory as send_from_directory +from .helpers import stream_with_context as stream_with_context +from .helpers import url_for as url_for +from .json import jsonify as jsonify +from .signals import appcontext_popped as appcontext_popped +from .signals import appcontext_pushed as appcontext_pushed +from .signals import appcontext_tearing_down as appcontext_tearing_down +from .signals import before_render_template as before_render_template +from .signals import got_request_exception as got_request_exception +from .signals import message_flashed as message_flashed +from .signals import request_finished as request_finished +from .signals import request_started as request_started +from .signals import request_tearing_down as request_tearing_down +from .signals import template_rendered as template_rendered +from .templating import render_template as render_template +from .templating import render_template_string as render_template_string +from .templating import stream_template as stream_template +from .templating import stream_template_string as stream_template_string +from .wrappers import Request as Request +from .wrappers import Response as Response + +if not t.TYPE_CHECKING: + + def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " Flask 3.2. Use feature detection or" + " 'importlib.metadata.version(\"flask\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("flask") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/flask/__main__.py b/venv/lib/python3.12/site-packages/flask/__main__.py new file mode 100644 index 00000000..4e28416e --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..52d6991f821d460608545c6a6a3b2c5038c39288 GIT binary patch literal 2517 zcmZXWTW=Fb6vta2mLqb_?z@ddyzhD>wt3r+L9y;6BLEsbg zgy13I2|6Ko7+9vV;1MHkPSQ!iqej7;qEmv$fT!uS;Bnv?IwSZ5@GPAbJONy!MZq%g z9Gw$930$Hj!3E%XIxlz%c!4emo(4WiPYRwf7R@p(3!Vk8(2C$9@F{vq@Eq`IdRlPF zSTdLCvfz2(GxUr^SafqUEP=ycH?E!37QT@)h2@|TnF|7g%oF+&RG@5 z?Qof;DK*_dNB*F}ZBseuVDnuedz`7JvaNfKBdbWZxS`Z+4n2~%v3dG*m4^}96Zv~V=82!u4wi)E_+~u!N3@_rC}o4%K}e--9FrVwo_#erWhQ#_Fja0 z15$Um^EKVl+mq%(&Gl67i8%T~=~xgw;k4~AL}&Q^ct``sB*lfjw=kzUAl$fcAdm)* zNr#=2H$PNb>SjAxRV>`_i33Clk={N6cu4l(-fPYg!Y^nMjTq#fBz~oPk-f+!_C5A! zQ7;inTI|pGV;Bn`iR?+6sRKT0H`7O32dpI?wA57mOOT$a7o%hQX_6UvM-rLrewOr&KhMuR&Cfi~ zFFwsL{$78UKl`NX>_6GDN4KA43r|vow=gUz#rQ|?<42*+{RC%_CF^e7E3a6)rE`9# zqSRWLI0y&V>nFTj2e#CgJfCnZT0aW60>?u2J2%41+2u*m8SWLhpg9(+AFX;jyaR~i zKLw7(%Dd2!tQ+=*YPcNhlV{Q7&~yuDgBcFgChtM17fl{bADVtN184@(451lDGlFIm zjGuJ%x`l&}p)`)>1eysnGMY&=1vFD=rqRrR@jKhM04$f!qFO`)2bk~@`cvB+mX5K_ zqqcxr=Jq!?)|Az&YpY*gTfZVQ_y^$^(SIJy`_x6#)>;Ppl&?b*kEZ)8nEj|ENdYOm zCcXcXk$_ADq#TgxfP5T~>j7B~$c2DZ0x}wqqIjnQ0`E#d)`YhdkcEJJCSK?OA3}e4 suZRw-0XZjz0t=sjem)>qLpv9c`B%x*5BDG3e;3Qfr}pC{H7G*<53Kjgg#Z8m literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/__main__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..369c78fedbe3f1d992b81e0f50037d0bb6d2accd GIT binary patch literal 225 zcmX@j%ge<81fCV~8FE1SF^B^LOi;#Wkj!+36owSW9EM!RC`LvGCWchT)lg|hhDs() z=9i2>t|sFxmfXb5JU>mQTg=HhnMKS%!Icc3K`MWF>6hmhWfvDDCZ`tbhdKra1^76I zx;g5XrRJ6C=VT`77gUyH&M4~jE;}jE2#X% oVUwGmQks)$SHuA{8f0}bFOc}a%*e=imqGL)14}Dg5gSkh0G)(2m;e9( 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..5ff73ed8f32f22f02b624424e22ad2f3437b6d04 GIT binary patch literal 62469 zcmdqKd30N6b|(lBAPEv6!JQPT1tKMplqgWUY-+J6iCQd)QjwHhW-S272T71XfPMfa zi=irZb@ha*II)y+#dOMPt2*w9eC$psIaypY=}9e_PI`LIG-0ZmEJT@6%~YRBotZyW zk?VBDIWuQ|_kPQJ03T&nb@w0BumwK6_q}hu-`(&1{%uuNr3;^vFGVhG`>D(If6x#0 zDHRv)$N#U#<$A+qxD0pFHQ^q0yXm?lSu)`n^~&qg(NexwHd@Ai%SV0uw_>yce?7^{ z3IC{{%X*W6iK@{mzAjBxPXtGUd|j5TnW!DDh+8;z#q=7}w%Tll&e z*X5%pi1;_&S8^y`y{idVTV#iKj=O=IeG`_l@@PbqB8Zjqc;?4Y=Mvx}UE% zCJ#&;96iX_o088=92z~u*PY4!iNm9Z`ML|&M@EnEb$9aU#K7nPUvI|svC(6Ey#?3D zN00M$53Wy)p5W`PxIQ_0lCQ(bXD3dLp5p7?jH@RJL-{rRy*jazg zwOIFU$+HvZM$e(V%h-s`t6iSwi9-L4X<^?j>0 zb!F_1_gwx1^~?JE{+{B9*p1mY0$7>`U|{6VGJCB2-hSjQH3T`ksu@ zYYlV<*O^OkBQk-4v5Rq9fFRwcfkg}~PURNB0b+a3%9e<~t)OlzLR zkJZC*bTNJ;oxYNY4~yn`WiDXp@w~?2UNeR|E~X=rjmJ!yU?Y8vK&J6xI;(~siQAUD zMve4BB9)*apm0##%Vc9_mTxtvTSfKy2U1rPW;!*2p5x8(Aw9!Y!}PLkIfKs+A3td; z{w`MG7^dyYkz@jI<7c({IRxlna0p0velC`risx62M9{-zGNJ}KX{N_9H4Mn5W9g}s zk*^%#q0_MQwRAl(nT%!Qkqe0=fVJS(#bkOcmdpojrLx!@;{0|0T)g3$ zalKNL)z4>KS&8agE`{{Wk{Q>qD=Rm>3vaydeowwJ?CLI|%?@zF2#id3Nxm|XNu)5% zsqwf;ZQ*I@RT^xD-U)p?(0eUyUdc>i(KEg0`-g|lo$fz>tiSgv0ID~c80($9p1qV# z?F?_<(VIzR<6BYk3ISj*LFAQQKty=*dOjGLh+TbCe)s*BT}#1+*}#we4Rh!3`#a{n9gk7QHBMjZQzI_ikG&Y^uVG^1u2Hw)8Z9{w z?q<{j9O_Mgw=q0la~ocx6yIfhUC!S={;oi&Qls*HznUJD3UJvfeqPPrL8AuuYmGX5 z*YlkQ{sy;zJI!3ag}+zv{U*a>v>I*r_86u3Z#Dj|F`A6EZw3B^UWn1MIB{0%;uS_{ zKZX*o9Q7OP@vEJFpVF1T|TceWUpj3X%9Vxr}h+8RomD8Tz)KHw^BO`)E% zKsBKRS2k|Off^0^buE!hQXi-bG1Y;P8NZmwWXiy{gfCt1Qd56adFDD#yBxGeknAOHsj$+u8pS2J_^-$jB|=dnMMyX>EzWo|D7^{ z1Vh9zgn%;>Mx2`Fiqwl3KlSiJItgyVJ~60~Xa?9P8g43N#3wj8**?&mcwaOU0cFibBEZAZ5Z#i! z@22I7g$Vf@G1I`r@EUeqp2}buLeVI_Al~Sf6Lt)5(EOnWtjL6%SrERgo}dtM92i(n zC=-vP3t%7nqG^m4)IXD^DU8a>&Sx-^ z)-i>urxGS`gC>2&(E>#IRkcXT#1&e(M5eD#fB}Iyud3KG*ehu>8{!`DRMK<6aOi-z z*Ame|?aezITW9l4c$xNev%!*#bg6o#>KEe^~%kKoeIRm>lcav?54o1TqKyqpQPA&RGEO>o)AD?tPB7LXe4

c0`kQVDb+VVg?XR#-AuQG1J_%%${H(oh?U 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 Zyu6$6PXwLfv-sV#Gk<^iQ$cQ$``>W#JF@@) 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..0d30d35d6f5fac844f5386518ad4e4ddc20196c0 GIT binary patch literal 4984 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 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..0c4ff68855cbd6620b7727f364d7b14487528b86 GIT binary patch literal 16236 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 YIr1|5bRQ`$4v?ZmX5Y%X_(eGNe=S@hp#T5? 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..461041b6a95a256c529dfefff39f2e9bb0d77d0f GIT binary patch literal 25429 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/logging.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..db2476c6089e4bc69e4c3e0edd1c1f594d6fc64e GIT binary patch literal 3251 zcmZuz&2JmW6`xstil3Hbsj#csgI2Oc*CyKr$$=G|x{fFdQ5_?eo0dgDuDC;TrR6R= zGqglOPKeZits;P%LnN9-^eI-Bq5%LJU_a7kEk%0_sp$0BuENRWsikg}O#ekZF z#SqK^E8K__Bft|hLRPfVSM0-xh8B+dYI`#a15enBHxk7J@I;Kb5xEt7&}Aqljf4@s z6)dJSM74!eJvpDE$p_e@i^u4(g&+Cry;(_)_P%|}=<_B08T?HeF|an+)-tJYC1VD= zaox5Zp$pTo`4#w%%{mp`y2_m8_P5eBEJYaoeT#AdWZ+`6S@BKCS%W8l5Z;>uVjT&& zrUo1A(F>C6xnbZFuyPHFpue#Y_Nm@{4P`X_eek1T+6EDIN*WFqL~k~k(`2SDD4~ow zjBvrI-XK*VB^NMQW<^DnB{Nl`lWq(#0>k7)uL$!7Jx463MubDkPs845dOAcG)O}#>S?)t@R zuV0-P}l@e;7Ugbv$)9zm|U(9AZges&vZ>NQC57RG0Y^AZ}~x zXca9S+?PBs{PO*ywu)}zRm>&@NO|LqR>cOs6u$f ztq-*Wuovyg`;@YZ-<@m+GQpJ(FV$&fk(gC^^Wm1r+fC};Wh17o>YG9kDBQ21^@x7%*C zYlFLe60P(app_eLLLu7%+zxwbb|aM*lS>C(|Alhh?LXu%`vF)!Ej|2=^ss|=qbNDJ zofzFnjBX~*bf$Jv$2-&iiuHdHPi>|Oe}7~9#i@-Kr?ygst$1N)@OzKa!`o@{X`1XL z`au+4AvAb$J^NnvPULYK#Rql=U{O`Z%1gf+o6tENe1m5An`CT4WzN>+r@U8V6Ai~` zS@4yYH02x$HNy{`Ih+RGdkpSEd)Tk0qgnz~+YvS6R|?#DbX1+NA0J&K{4}h`!R&M6 zKwC;Yw*{ZRHH?G=5;az_zsiR|XTQJRn}xh~YWSQOtzu|iSpNrvJWVAEQ&Nz)Dti;u zmUsFRvG*|?N*6%8N^D9EYIM8I9LRNfW$L}MotM3W5-u0I*qzsfVEHmA&w99DQtXo+ zmMhCyxgtw5Cc*oSI+S`>>aBxZ2Ayx!$`VGXtc+t7%N`E9X@gevmL+`P$!Gu)@E7xaxHVk<9ueZze6j*RGJ=-8 zRImxy%1fTB@amu^CsAr>J9%m&dFmd&zx=`SW^$racod1TY^1 z{ZZt8@`L17^vu`sk$b=1ijTtjcJ#zX^u$NGt?1cD@&3-QRGot-VMaxZ*(*_zor6Ds znb)9~OUIt3{Iq$IvkWY{!Fk8AfI|W$i^!K;W@q7*Iqt?vrD_Yb(Nc*?9A*-&nEVBI z!=l}UGjOqRQ%jUBuFzHu{xSf6nXG#^QnQ?S0AuezB02Zlt5c;*m!~ehI&)>(jd9)P zrjwOPQ$}TZdU;Mha|75JsVe~|Qcy=JD0BPvNtIA03tt8AwTS4Xhh!JnORym^igS4F z1~A57q91;RQlF#P=V;&?H1-V|c@zlVe)*l3zYLz<4I?e_SWDpHy#P?ViaK=+_wSxX zgA;!m-yRs>7#M#zk>4Enc_+Pt(%Wcc1C8tihdR^S!J&=d(8J*?o59zf1T?HYi4EZa H<<$QH>EJ~> 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..85bee547456790478dea80f195b53dad54910f1b GIT binary patch literal 17166 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/__pycache__/views.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2ca00fd3452f2f6186a693246a1258d16d41fc6a GIT binary patch literal 7002 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 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..d65377e2352b7cf8bd61cbb507245786b8598e72 GIT binary patch literal 10037 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 b$}1jTU3x6g@8h=u`^ACPTVD$J;nVyVQ00M9 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/app.py b/venv/lib/python3.12/site-packages/flask/app.py new file mode 100644 index 00000000..1232b03d --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/app.py @@ -0,0 +1,1536 @@ +from __future__ import annotations + +import collections.abc as cabc +import os +import sys +import typing as t +import weakref +from datetime import timedelta +from inspect import iscoroutinefunction +from itertools import chain +from types import TracebackType +from urllib.parse import quote as _url_quote + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import MapAdapter +from werkzeug.routing import RequestRedirect +from werkzeug.routing import RoutingException +from werkzeug.routing import Rule +from werkzeug.serving import is_running_from_reloader +from werkzeug.wrappers import Response as BaseResponse +from werkzeug.wsgi import get_host + +from . import cli +from . import typing as ft +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import send_from_directory +from .sansio.app import App +from .sansio.scaffold import _sentinel +from .sessions import SecureCookieSessionInterface +from .sessions import SessionInterface +from .signals import appcontext_tearing_down +from .signals import got_request_exception +from .signals import request_finished +from .signals import request_started +from .signals import request_tearing_down +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + + from .testing import FlaskClient + from .testing import FlaskCliRunner + from .typing import HeadersValue + +T_shell_context_processor = t.TypeVar( + "T_shell_context_processor", bound=ft.ShellContextProcessorCallable +) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) + + +def _make_timedelta(value: timedelta | int | None) -> timedelta | None: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(App): + """The flask object implements a WSGI application and acts as the central + object. It is passed the name of the module or package of the + application. Once it is created it will act as a central registry for + the view functions, the URL rules, template configuration and much more. + + The name of the package is used to resolve resources from inside the + package or the folder the module is contained in depending on if the + package parameter resolves to an actual python package (a folder with + an :file:`__init__.py` file inside) or a standard module (just a ``.py`` file). + + For more information about resource loading, see :func:`open_resource`. + + Usually you create a :class:`Flask` instance in your main module or + in the :file:`__init__.py` file of your package like this:: + + from flask import Flask + app = Flask(__name__) + + .. admonition:: About the First Parameter + + The idea of the first parameter is to give Flask an idea of what + belongs to your application. This name is used to find resources + on the filesystem, can be used by extensions to improve debugging + information and a lot more. + + So it's important what you provide there. If you are using a single + module, `__name__` is always the correct value. If you however are + using a package, it's usually recommended to hardcode the name of + your package there. + + For example if your application is defined in :file:`yourapplication/app.py` + you should create it with one of the two versions below:: + + app = Flask('yourapplication') + app = Flask(__name__.split('.')[0]) + + Why is that? The application will work even with `__name__`, thanks + to how resources are looked up. However it will make debugging more + painful. Certain extensions can make assumptions based on the + import name of your application. For example the Flask-SQLAlchemy + extension will look for the code in your application that triggered + an SQL query in debug mode. If the import name is not properly set + up, that debugging information is lost. (For example it would only + pick up SQL queries in `yourapplication.app` and not + `yourapplication.views.frontend`) + + .. versionadded:: 0.7 + The `static_url_path`, `static_folder`, and `template_folder` + parameters were added. + + .. versionadded:: 0.8 + The `instance_path` and `instance_relative_config` parameters were + added. + + .. versionadded:: 0.11 + The `root_path` parameter was added. + + .. versionadded:: 1.0 + The ``host_matching`` and ``static_host`` parameters were added. + + .. versionadded:: 1.0 + The ``subdomain_matching`` parameter was added. Subdomain + matching needs to be enabled manually now. Setting + :data:`SERVER_NAME` does not implicitly enable it. + + :param import_name: the name of the application package + :param static_url_path: can be used to specify a different path for the + static files on the web. Defaults to the name + of the `static_folder` folder. + :param static_folder: The folder with static files that is served at + ``static_url_path``. Relative to the application ``root_path`` + or an absolute path. Defaults to ``'static'``. + :param static_host: the host to use when adding the static route. + Defaults to None. Required when using ``host_matching=True`` + with a ``static_folder`` configured. + :param host_matching: set ``url_map.host_matching`` attribute. + Defaults to False. + :param subdomain_matching: consider the subdomain relative to + :data:`SERVER_NAME` when matching routes. Defaults to False. + :param template_folder: the folder that contains the templates that should + be used by the application. Defaults to + ``'templates'`` folder in the root path of the + application. + :param instance_path: An alternative instance path for the application. + By default the folder ``'instance'`` next to the + package or module is assumed to be the instance + path. + :param instance_relative_config: if set to ``True`` relative filenames + for loading the config are assumed to + be relative to the instance path instead + of the application root. + :param root_path: The path to the root of the application files. + This should only be set manually when it can't be detected + automatically, such as for namespace packages. + """ + + default_config = ImmutableDict( + { + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "SECRET_KEY_FALLBACKS": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "TRUSTED_HOSTS": None, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_PARTITIONED": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "MAX_FORM_MEMORY_SIZE": 500_000, + "MAX_FORM_PARTS": 1_000, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + "PROVIDE_AUTOMATIC_OPTIONS": True, + } + ) + + #: The class that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class: type[Request] = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class: type[Response] = Response + + #: the session interface to use. By default an instance of + #: :class:`~flask.sessions.SecureCookieSessionInterface` is used here. + #: + #: .. versionadded:: 0.8 + session_interface: SessionInterface = SecureCookieSessionInterface() + + def __init__( + self, + import_name: str, + static_url_path: str | None = None, + static_folder: str | os.PathLike[str] | None = "static", + static_host: str | None = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: str | os.PathLike[str] | None = "templates", + instance_path: str | None = None, + instance_relative_config: bool = False, + root_path: str | None = None, + ): + super().__init__( + import_name=import_name, + static_url_path=static_url_path, + static_folder=static_folder, + static_host=static_host, + host_matching=host_matching, + subdomain_matching=subdomain_matching, + template_folder=template_folder, + instance_path=instance_path, + instance_relative_config=instance_relative_config, + root_path=root_path, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = cli.AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + # Add a static route using the provided static_url_path, static_host, + # and static_folder if there is a configured static_folder. + # Note we do this without checking if static_folder exists. + # For one, it might be created while the server is running (e.g. during + # development). Also, Google App Engine stores static files somewhere + if self.has_static_folder: + assert bool(static_host) == host_matching, ( + "Invalid static_host/host_matching combination" + ) + # Use a weakref to avoid creating a reference cycle between the app + # and the view function (see #3761). + self_ref = weakref.ref(self) + self.add_url_rule( + f"{self.static_url_path}/", + endpoint="static", + host=static_host, + view_func=lambda **kw: self_ref().send_static_file(**kw), # type: ignore # noqa: B950 + ) + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = None + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. + + For example, if the file ``schema.sql`` is next to the file + ``app.py`` where the ``Flask`` app is defined, it can be opened + with: + + .. code-block:: python + + with app.open_resource("schema.sql") as f: + conn.executescript(f.read()) + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) + + def open_instance_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to the application's instance folder + :attr:`instance_path`. Unlike :meth:`open_resource`, files in the + instance folder can be opened for writing. + + :param resource: Path to the resource relative to :attr:`instance_path`. + :param mode: Open the file in this mode. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + path = os.path.join(self.instance_path, resource) + + if "b" in mode: + return open(path, mode) + + return open(path, mode, encoding=encoding) + + def create_jinja_environment(self) -> Environment: + """Create the Jinja environment based on :attr:`jinja_options` + and the various Jinja-related methods of the app. Changing + :attr:`jinja_options` after this will have no effect. Also adds + Flask-related globals and filters to the environment. + + .. versionchanged:: 0.11 + ``Environment.auto_reload`` set in accordance with + ``TEMPLATES_AUTO_RELOAD`` configuration option. + + .. versionadded:: 0.5 + """ + options = dict(self.jinja_options) + + if "autoescape" not in options: + options["autoescape"] = self.select_jinja_autoescape + + if "auto_reload" not in options: + auto_reload = self.config["TEMPLATES_AUTO_RELOAD"] + + if auto_reload is None: + auto_reload = self.debug + + options["auto_reload"] = auto_reload + + rv = self.jinja_environment(self, **options) + rv.globals.update( + url_for=self.url_for, + get_flashed_messages=get_flashed_messages, + config=self.config, + # request, session and g are normally added with the + # context processor for efficiency reasons but for imported + # templates we also want the proxies in there. + request=request, + session=session, + g=g, + ) + rv.policies["json.dumps_function"] = self.json.dumps + return rv + + def create_url_adapter(self, request: Request | None) -> MapAdapter | None: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionchanged:: 3.1 + If :data:`SERVER_NAME` is set, it does not restrict requests to + only that domain, for both ``subdomain_matching`` and + ``host_matching``. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + + .. versionchanged:: 0.9 + This can be called outside a request when the URL adapter is created + for an application context. + + .. versionadded:: 0.6 + """ + if request is not None: + if (trusted_hosts := self.config["TRUSTED_HOSTS"]) is not None: + request.trusted_hosts = trusted_hosts + + # Check trusted_hosts here until bind_to_environ does. + request.host = get_host(request.environ, request.trusted_hosts) # pyright: ignore + subdomain = None + server_name = self.config["SERVER_NAME"] + + if self.url_map.host_matching: + # Don't pass SERVER_NAME, otherwise it's used and the actual + # host is ignored, which breaks host matching. + server_name = None + elif not self.subdomain_matching: + # Werkzeug doesn't implement subdomain matching yet. Until then, + # disable it by forcing the current subdomain to the default, or + # the empty string. + subdomain = self.url_map.default_subdomain or "" + + return self.url_map.bind_to_environ( + request.environ, server_name=server_name, subdomain=subdomain + ) + + # Need at least SERVER_NAME to match/build outside a request. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def raise_routing_exception(self, request: Request) -> t.NoReturn: + """Intercept routing exceptions and possibly do something else. + + In debug mode, intercept a routing redirect and replace it with + an error if the body will be discarded. + + With modern Werkzeug this shouldn't occur, since it now uses a + 308 status which tells the browser to resend the method and + body. + + .. versionchanged:: 2.1 + Don't intercept 307 and 308 redirects. + + :meta private: + :internal: + """ + if ( + not self.debug + or not isinstance(request.routing_exception, RequestRedirect) + or request.routing_exception.code in {307, 308} + or request.method in {"GET", "HEAD", "OPTIONS"} + ): + raise request.routing_exception # type: ignore[misc] + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + def update_template_context(self, context: dict[str, t.Any]) -> None: + """Update the template context with some commonly used variables. + This injects request, session, config and g into the template + context as well as everything template context processors want + to inject. Note that the as of Flask 0.6, the original values + in the context will not be overridden if a context processor + decides to return a value with the same key. + + :param context: the context as a dictionary that is updated in place + to add extra variables. + """ + names: t.Iterable[str | None] = (None,) + + # A template may be rendered outside a request context. + if request: + names = chain(names, reversed(request.blueprints)) + + # The values passed to render_template take precedence. Keep a + # copy to re-apply after all context functions. + orig_ctx = context.copy() + + for name in names: + if name in self.template_context_processors: + for func in self.template_context_processors[name]: + context.update(self.ensure_sync(func)()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict[str, t.Any]: + """Returns the shell context for an interactive shell for this + application. This runs all the registered shell context + processors. + + .. versionadded:: 0.11 + """ + rv = {"app": self, "g": g} + for processor in self.shell_context_processors: + rv.update(processor()) + return rv + + def run( + self, + host: str | None = None, + port: int | None = None, + debug: bool | None = None, + load_dotenv: bool = True, + **options: t.Any, + ) -> None: + """Runs the application on a local development server. + + Do not use ``run()`` in a production setting. It is not intended to + meet security and performance requirements for a production server. + Instead, see :doc:`/deploying/index` for WSGI server recommendations. + + If the :attr:`debug` flag is set the server will automatically reload + for code changes and show a debugger in case an exception happened. + + If you want to run the application in debug mode, but disable the + code execution on the interactive debugger, you can pass + ``use_evalex=False`` as parameter. This will keep the debugger's + traceback screen active, but disable code execution. + + It is not recommended to use this function for development with + automatic reloading as this is badly supported. Instead you should + be using the :command:`flask` command line script's ``run`` support. + + .. admonition:: Keep in Mind + + Flask will suppress any server error with a generic error page + unless it is in debug mode. As such to enable just the + interactive debugger without the code reloading, you have to + invoke :meth:`run` with ``debug=True`` and ``use_reloader=False``. + Setting ``use_debugger`` to ``True`` without being in debug mode + won't catch any exceptions because there won't be any to + catch. + + :param host: the hostname to listen on. Set this to ``'0.0.0.0'`` to + have the server available externally as well. Defaults to + ``'127.0.0.1'`` or the host in the ``SERVER_NAME`` config variable + if present. + :param port: the port of the webserver. Defaults to ``5000`` or the + port defined in the ``SERVER_NAME`` config variable if present. + :param debug: if given, enable or disable debug mode. See + :attr:`debug`. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param options: the options to be forwarded to the underlying Werkzeug + server. See :func:`werkzeug.serving.run_simple` for more + information. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment + variables from :file:`.env` and :file:`.flaskenv` files. + + The :envvar:`FLASK_DEBUG` environment variable will override :attr:`debug`. + + Threaded mode is enabled by default. + + .. versionchanged:: 0.10 + The default port is now picked from the ``SERVER_NAME`` + variable. + """ + # Ignore this call so that it doesn't start another server if + # the 'flask run' command is used. + if os.environ.get("FLASK_RUN_FROM_CLI") == "true": + if not is_running_from_reloader(): + click.secho( + " * Ignoring a call to 'app.run()' that would block" + " the current 'flask' CLI command.\n" + " Only call 'app.run()' in an 'if __name__ ==" + ' "__main__"\' guard.', + fg="red", + ) + + return + + if get_load_dotenv(load_dotenv): + cli.load_dotenv() + + # if set, env var overrides existing value + if "FLASK_DEBUG" in os.environ: + self.debug = get_debug_flag() + + # debug passed to method overrides all other sources + if debug is not None: + self.debug = bool(debug) + + server_name = self.config.get("SERVER_NAME") + sn_host = sn_port = None + + if server_name: + sn_host, _, sn_port = server_name.partition(":") + + if not host: + if sn_host: + host = sn_host + else: + host = "127.0.0.1" + + if port or port == 0: + port = int(port) + elif sn_port: + port = int(sn_port) + else: + port = 5000 + + options.setdefault("use_reloader", self.debug) + options.setdefault("use_debugger", self.debug) + options.setdefault("threaded", True) + + cli.show_server_banner(self.debug, self.name) + + from werkzeug.serving import run_simple + + try: + run_simple(t.cast(str, host), port, self, **options) + finally: + # reset the first request information if the development server + # reset normally. This makes it possible to restart the server + # without reloader and that stuff from an interactive shell. + self._got_first_request = False + + def test_client(self, use_cookies: bool = True, **kwargs: t.Any) -> FlaskClient: + """Creates a test client for this application. For information + about unit testing head over to :doc:`/testing`. + + Note that if you are testing for assertions or exceptions in your + application code, you must set ``app.testing = True`` in order for the + exceptions to propagate to the test client. Otherwise, the exception + will be handled by the application (not visible to the test client) and + the only indication of an AssertionError or other exception will be a + 500 status code response to the test client. See the :attr:`testing` + attribute. For example:: + + app.testing = True + client = app.test_client() + + The test client can be used in a ``with`` block to defer the closing down + of the context until the end of the ``with`` block. This is useful if + you want to access the context locals for testing:: + + with app.test_client() as c: + rv = c.get('/?vodka=42') + assert request.args['vodka'] == '42' + + Additionally, you may pass optional keyword arguments that will then + be passed to the application's :attr:`test_client_class` constructor. + For example:: + + from flask.testing import FlaskClient + + class CustomClient(FlaskClient): + def __init__(self, *args, **kwargs): + self._authentication = kwargs.pop("authentication") + super(CustomClient,self).__init__( *args, **kwargs) + + app.test_client_class = CustomClient + client = app.test_client(authentication='Basic ....') + + See :class:`~flask.testing.FlaskClient` for more information. + + .. versionchanged:: 0.4 + added support for ``with`` block usage for the client. + + .. versionadded:: 0.7 + The `use_cookies` parameter was added as well as the ability + to override the client to be used by setting the + :attr:`test_client_class` attribute. + + .. versionchanged:: 0.11 + Added `**kwargs` to support passing additional keyword arguments to + the constructor of :attr:`test_client_class`. + """ + cls = self.test_client_class + if cls is None: + from .testing import FlaskClient as cls + return cls( # type: ignore + self, self.response_class, use_cookies=use_cookies, **kwargs + ) + + def test_cli_runner(self, **kwargs: t.Any) -> FlaskCliRunner: + """Create a CLI runner for testing CLI commands. + See :ref:`testing-cli`. + + Returns an instance of :attr:`test_cli_runner_class`, by default + :class:`~flask.testing.FlaskCliRunner`. The Flask app object is + passed as the first argument. + + .. versionadded:: 1.0 + """ + cls = self.test_cli_runner_class + + if cls is None: + from .testing import FlaskCliRunner as cls + + return cls(self, **kwargs) # type: ignore + + def handle_http_exception( + self, e: HTTPException + ) -> HTTPException | ft.ResponseReturnValue: + """Handles an HTTP exception. By default this will invoke the + registered error handlers and fall back to returning the + exception as response. + + .. versionchanged:: 1.0.3 + ``RoutingException``, used internally for actions such as + slash redirects during routing, is not passed to error + handlers. + + .. versionchanged:: 1.0 + Exceptions are looked up by code *and* by MRO, so + ``HTTPException`` subclasses can be handled with a catch-all + handler for the base ``HTTPException``. + + .. versionadded:: 0.3 + """ + # Proxy exceptions don't have error codes. We want to always return + # those unchanged as errors + if e.code is None: + return e + + # RoutingExceptions are used internally to trigger routing + # actions, such as slash redirects raising RequestRedirect. They + # are not raised or handled in user code. + if isinstance(e, RoutingException): + return e + + handler = self._find_error_handler(e, request.blueprints) + if handler is None: + return e + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_user_exception( + self, e: Exception + ) -> HTTPException | ft.ResponseReturnValue: + """This method is called whenever an exception occurs that + should be handled. A special case is :class:`~werkzeug + .exceptions.HTTPException` which is forwarded to the + :meth:`handle_http_exception` method. This function will either + return a response value or reraise the exception with the same + traceback. + + .. versionchanged:: 1.0 + Key errors raised from request data like ``form`` show the + bad key in debug mode rather than a generic bad request + message. + + .. versionadded:: 0.7 + """ + if isinstance(e, BadRequestKeyError) and ( + self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"] + ): + e.show_exception = True + + if isinstance(e, HTTPException) and not self.trap_http_exception(e): + return self.handle_http_exception(e) + + handler = self._find_error_handler(e, request.blueprints) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) # type: ignore[no-any-return] + + def handle_exception(self, e: Exception) -> Response: + """Handle an exception that did not have an error handler + associated with it, or that was raised from an error handler. + This always causes a 500 ``InternalServerError``. + + Always sends the :data:`got_request_exception` signal. + + If :data:`PROPAGATE_EXCEPTIONS` is ``True``, such as in debug + mode, the error will be re-raised so that the debugger can + display it. Otherwise, the original exception is logged, and + an :exc:`~werkzeug.exceptions.InternalServerError` is returned. + + If an error handler is registered for ``InternalServerError`` or + ``500``, it will be used. For consistency, the handler will + always receive the ``InternalServerError``. The original + unhandled exception is available as ``e.original_exception``. + + .. versionchanged:: 1.1.0 + Always passes the ``InternalServerError`` instance to the + handler, setting ``original_exception`` to the unhandled + error. + + .. versionchanged:: 1.1.0 + ``after_request`` functions and other finalization is done + even for the default 500 response when there is no handler. + + .. versionadded:: 0.3 + """ + exc_info = sys.exc_info() + got_request_exception.send(self, _async_wrapper=self.ensure_sync, exception=e) + propagate = self.config["PROPAGATE_EXCEPTIONS"] + + if propagate is None: + propagate = self.testing or self.debug + + if propagate: + # Re-raise if called with an active exception, otherwise + # raise the passed in exception. + if exc_info[1] is e: + raise + + raise e + + self.log_exception(exc_info) + server_error: InternalServerError | ft.ResponseReturnValue + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error, request.blueprints) + + if handler is not None: + server_error = self.ensure_sync(handler)(server_error) + + return self.finalize_request(server_error, from_error_handler=True) + + def log_exception( + self, + exc_info: (tuple[type, BaseException, TracebackType] | tuple[None, None, None]), + ) -> None: + """Logs an exception. This is called by :meth:`handle_exception` + if debugging is disabled and right before the handler is called. + The default implementation logs the exception as error on the + :attr:`logger`. + + .. versionadded:: 0.8 + """ + self.logger.error( + f"Exception on {request.path} [{request.method}]", exc_info=exc_info + ) + + def dispatch_request(self) -> ft.ResponseReturnValue: + """Does the request dispatching. Matches the URL and returns the + return value of the view or error handler. This does not have to + be a response object. In order to convert the return value to a + proper response object, call :func:`make_response`. + + .. versionchanged:: 0.7 + This no longer does the exception handling, this code was + moved to the new :meth:`full_dispatch_request`. + """ + req = request_ctx.request + if req.routing_exception is not None: + self.raise_routing_exception(req) + rule: Rule = req.url_rule # type: ignore[assignment] + # if we provide automatic options for this URL and the + # request came with the OPTIONS method, reply automatically + if ( + getattr(rule, "provide_automatic_options", False) + and req.method == "OPTIONS" + ): + return self.make_default_options_response() + # otherwise dispatch to the handler for that endpoint + view_args: dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) # type: ignore[no-any-return] + + def full_dispatch_request(self) -> Response: + """Dispatches the request and on top of that performs request + pre and postprocessing as well as HTTP exception catching and + error handling. + + .. versionadded:: 0.7 + """ + self._got_first_request = True + + try: + request_started.send(self, _async_wrapper=self.ensure_sync) + rv = self.preprocess_request() + if rv is None: + rv = self.dispatch_request() + except Exception as e: + rv = self.handle_user_exception(e) + return self.finalize_request(rv) + + def finalize_request( + self, + rv: ft.ResponseReturnValue | HTTPException, + from_error_handler: bool = False, + ) -> Response: + """Given the return value from a view function this finalizes + the request by converting it into a response and invoking the + postprocessing functions. This is invoked for both normal + request dispatching as well as error handlers. + + Because this means that it might be called as a result of a + failure a special safe mode is available which can be enabled + with the `from_error_handler` flag. If enabled, failures in + response processing will be logged and otherwise ignored. + + :internal: + """ + response = self.make_response(rv) + try: + response = self.process_response(response) + request_finished.send( + self, _async_wrapper=self.ensure_sync, response=response + ) + except Exception: + if not from_error_handler: + raise + self.logger.exception( + "Request finalizing failed with an error while handling an error" + ) + return response + + def make_default_options_response(self) -> Response: + """This method is called to create the default ``OPTIONS`` response. + This can be changed through subclassing to change the default + behavior of ``OPTIONS`` responses. + + .. versionadded:: 0.7 + """ + adapter = request_ctx.url_adapter + methods = adapter.allowed_methods() # type: ignore[union-attr] + rv = self.response_class() + rv.allow.update(methods) + return rv + + def ensure_sync(self, func: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Ensure that the function is synchronous for WSGI workers. + Plain ``def`` functions are returned as-is. ``async def`` + functions are wrapped to run and wait for the response. + + Override this method to change how the app runs async views. + + .. versionadded:: 2.0 + """ + if iscoroutinefunction(func): + return self.async_to_sync(func) + + return func + + def async_to_sync( + self, func: t.Callable[..., t.Coroutine[t.Any, t.Any, t.Any]] + ) -> t.Callable[..., t.Any]: + """Return a sync function that will run the coroutine function. + + .. code-block:: python + + result = app.async_to_sync(func)(*args, **kwargs) + + Override this method to change how the app converts async code + to be synchronously callable. + + .. versionadded:: 2.0 + """ + try: + from asgiref.sync import async_to_sync as asgiref_async_to_sync + except ImportError: + raise RuntimeError( + "Install Flask with the 'async' extra in order to use async views." + ) from None + + return asgiref_async_to_sync(func) + + def url_for( + self, + /, + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, + ) -> str: + """Generate a URL to the given endpoint with the given values. + + This is called by :func:`flask.url_for`, and can be called + directly as well. + + An *endpoint* is the name of a URL rule, usually added with + :meth:`@app.route() `, and usually the same name as the + view function. A route defined in a :class:`~flask.Blueprint` + will prepend the blueprint's name separated by a ``.`` to the + endpoint. + + In some cases, such as email messages, you want URLs to include + the scheme and domain, like ``https://example.com/hello``. When + not in an active request, URLs will be external by default, but + this requires setting :data:`SERVER_NAME` so Flask knows what + domain to use. :data:`APPLICATION_ROOT` and + :data:`PREFERRED_URL_SCHEME` should also be configured as + needed. This config is only used when not in an active request. + + Functions can be decorated with :meth:`url_defaults` to modify + keyword arguments before the URL is built. + + If building fails for some reason, such as an unknown endpoint + or incorrect values, the app's :meth:`handle_url_build_error` + method is called. If that returns a string, that is returned, + otherwise a :exc:`~werkzeug.routing.BuildError` is raised. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it + is external. + :param _external: If given, prefer the URL to be internal + (False) or require it to be external (True). External URLs + include the scheme and domain. When not in an active + request, URLs are external by default. + :param values: Values to use for the variable parts of the URL + rule. Unknown keys are appended as query string arguments, + like ``?a=b&c=d``. + + .. versionadded:: 2.2 + Moved from ``flask.url_for``, which calls this method. + """ + req_ctx = _cv_request.get(None) + + if req_ctx is not None: + url_adapter = req_ctx.url_adapter + blueprint_name = req_ctx.request.blueprint + + # If the endpoint starts with "." and the request matches a + # blueprint, the endpoint is relative to the blueprint. + if endpoint[:1] == ".": + if blueprint_name is not None: + endpoint = f"{blueprint_name}{endpoint}" + else: + endpoint = endpoint[1:] + + # When in a request, generate a URL without scheme and + # domain by default, unless a scheme is given. + if _external is None: + _external = _scheme is not None + else: + app_ctx = _cv_app.get(None) + + # If called by helpers.url_for, an app context is active, + # use its url_adapter. Otherwise, app.url_for was called + # directly, build an adapter. + if app_ctx is not None: + url_adapter = app_ctx.url_adapter + else: + url_adapter = self.create_url_adapter(None) + + if url_adapter is None: + raise RuntimeError( + "Unable to build URLs outside an active request" + " without 'SERVER_NAME' configured. Also configure" + " 'APPLICATION_ROOT' and 'PREFERRED_URL_SCHEME' as" + " needed." + ) + + # When outside a request, generate a URL with scheme and + # domain by default. + if _external is None: + _external = True + + # It is an error to set _scheme when _external=False, in order + # to avoid accidental insecure URLs. + if _scheme is not None and not _external: + raise ValueError("When specifying '_scheme', '_external' must be True.") + + self.inject_url_defaults(endpoint, values) + + try: + rv = url_adapter.build( # type: ignore[union-attr] + endpoint, + values, + method=_method, + url_scheme=_scheme, + force_external=_external, + ) + except BuildError as error: + values.update( + _anchor=_anchor, _method=_method, _scheme=_scheme, _external=_external + ) + return self.handle_url_build_error(error, endpoint, values) + + if _anchor is not None: + _anchor = _url_quote(_anchor, safe="%!#$&'()*+,/:;=?@") + rv = f"{rv}#{_anchor}" + + return rv + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status: int | None = None + headers: HeadersValue | None = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv # pyright: ignore + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, cabc.Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, # pyright: ignore + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, # type: ignore[arg-type] + request.environ, + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) + + return rv + + def preprocess_request(self) -> ft.ResponseReturnValue | None: + """Called before the request is dispatched. Calls + :attr:`url_value_preprocessors` registered with the app and the + current blueprint (if any). Then calls :attr:`before_request_funcs` + registered with the app and the blueprint. + + If any :meth:`before_request` handler returns a non-None value, the + value is handled as if it was the return value from the view, and + further request handling is stopped. + """ + names = (None, *reversed(request.blueprints)) + + for name in names: + if name in self.url_value_preprocessors: + for url_func in self.url_value_preprocessors[name]: + url_func(request.endpoint, request.view_args) + + for name in names: + if name in self.before_request_funcs: + for before_func in self.before_request_funcs[name]: + rv = self.ensure_sync(before_func)() + + if rv is not None: + return rv # type: ignore[no-any-return] + + return None + + def process_response(self, response: Response) -> Response: + """Can be overridden in order to modify the response object + before it's sent to the WSGI server. By default this will + call all the :meth:`after_request` decorated functions. + + .. versionchanged:: 0.5 + As of Flask 0.5 the functions registered for after request + execution are called in reverse order of registration. + + :param response: a :attr:`response_class` object. + :return: a new response object or the same, has to be an + instance of :attr:`response_class`. + """ + ctx = request_ctx._get_current_object() # type: ignore[attr-defined] + + for func in ctx._after_request_functions: + response = self.ensure_sync(func)(response) + + for name in chain(request.blueprints, (None,)): + if name in self.after_request_funcs: + for func in reversed(self.after_request_funcs[name]): + response = self.ensure_sync(func)(response) + + if not self.session_interface.is_null_session(ctx.session): + self.session_interface.save_session(self, ctx.session, response) + + return response + + def do_teardown_request( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called after the request is dispatched and the response is + returned, right before the request context is popped. + + This calls all functions decorated with + :meth:`teardown_request`, and :meth:`Blueprint.teardown_request` + if a blueprint handled the request. Finally, the + :data:`request_tearing_down` signal is sent. + + This is called by + :meth:`RequestContext.pop() `, + which may be delayed during testing to maintain access to + resources. + + :param exc: An unhandled exception raised while dispatching the + request. Detected from the current exception information if + not passed. Passed to each teardown function. + + .. versionchanged:: 0.9 + Added the ``exc`` argument. + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for name in chain(request.blueprints, (None,)): + if name in self.teardown_request_funcs: + for func in reversed(self.teardown_request_funcs[name]): + self.ensure_sync(func)(exc) + + request_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def do_teardown_appcontext( + self, + exc: BaseException | None = _sentinel, # type: ignore[assignment] + ) -> None: + """Called right before the application context is popped. + + When handling a request, the application context is popped + after the request context. See :meth:`do_teardown_request`. + + This calls all functions decorated with + :meth:`teardown_appcontext`. Then the + :data:`appcontext_tearing_down` signal is sent. + + This is called by + :meth:`AppContext.pop() `. + + .. versionadded:: 0.9 + """ + if exc is _sentinel: + exc = sys.exc_info()[1] + + for func in reversed(self.teardown_appcontext_funcs): + self.ensure_sync(func)(exc) + + appcontext_tearing_down.send(self, _async_wrapper=self.ensure_sync, exc=exc) + + def app_context(self) -> AppContext: + """Create an :class:`~flask.ctx.AppContext`. Use as a ``with`` + block to push the context, which will make :data:`current_app` + point at this application. + + An application context is automatically pushed by + :meth:`RequestContext.push() ` + when handling a request, and when running a CLI command. Use + this to manually create a context outside of these situations. + + :: + + with app.app_context(): + init_db() + + See :doc:`/appcontext`. + + .. versionadded:: 0.9 + """ + return AppContext(self) + + def request_context(self, environ: WSGIEnvironment) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` representing a + WSGI environment. Use a ``with`` block to push the context, + which will make :data:`request` point at this request. + + See :doc:`/reqcontext`. + + Typically you should not call this from your own code. A request + context is automatically pushed by the :meth:`wsgi_app` when + handling a request. Use :meth:`test_request_context` to create + an environment and context instead of this method. + + :param environ: a WSGI environment + """ + return RequestContext(self, environ) + + def test_request_context(self, *args: t.Any, **kwargs: t.Any) -> RequestContext: + """Create a :class:`~flask.ctx.RequestContext` for a WSGI + environment created from the given values. This is mostly useful + during testing, where you may want to run a function that uses + request data without dispatching a full request. + + See :doc:`/reqcontext`. + + Use a ``with`` block to push the context, which will make + :data:`request` point at the request for the created + environment. :: + + with app.test_request_context(...): + generate_report() + + When using the shell, it may be easier to push and pop the + context manually to avoid indentation. :: + + ctx = app.test_request_context(...) + ctx.push() + ... + ctx.pop() + + Takes the same arguments as Werkzeug's + :class:`~werkzeug.test.EnvironBuilder`, with some defaults from + the application. See the linked Werkzeug docs for most of the + available arguments. Flask-specific behavior is listed here. + + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to + :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param data: The request body, either as a string or a dict of + form keys and values. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + from .testing import EnvironBuilder + + builder = EnvironBuilder(self, *args, **kwargs) + + try: + return self.request_context(builder.get_environ()) + finally: + builder.close() + + def wsgi_app( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The actual WSGI application. This is not implemented in + :meth:`__call__` so that middlewares can be applied without + losing a reference to the app object. Instead of doing this:: + + app = MyMiddleware(app) + + It's a better idea to do this instead:: + + app.wsgi_app = MyMiddleware(app.wsgi_app) + + Then you still have the original application object around and + can continue to call methods on it. + + .. versionchanged:: 0.7 + Teardown events for the request and app contexts are called + even if an unhandled error occurs. Other events may not be + called depending on when an error occurs during dispatch. + See :ref:`callbacks-and-errors`. + + :param environ: A WSGI environment. + :param start_response: A callable accepting a status code, + a list of headers, and an optional exception context to + start the response. + """ + ctx = self.request_context(environ) + error: BaseException | None = None + try: + try: + ctx.push() + response = self.full_dispatch_request() + except Exception as e: + error = e + response = self.handle_exception(e) + except: # noqa: B001 + error = sys.exc_info()[1] + raise + return response(environ, start_response) + finally: + if "werkzeug.debug.preserve_context" in environ: + environ["werkzeug.debug.preserve_context"](_cv_app.get()) + environ["werkzeug.debug.preserve_context"](_cv_request.get()) + + if error is not None and self.should_ignore_error(error): + error = None + + ctx.pop(error) + + def __call__( + self, environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + """The WSGI server calls the Flask application object as the + WSGI application. This calls :meth:`wsgi_app`, which can be + wrapped to apply middleware. + """ + return self.wsgi_app(environ, start_response) diff --git a/venv/lib/python3.12/site-packages/flask/blueprints.py b/venv/lib/python3.12/site-packages/flask/blueprints.py new file mode 100644 index 00000000..b6d4e433 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/blueprints.py @@ -0,0 +1,128 @@ +from __future__ import annotations + +import os +import typing as t +from datetime import timedelta + +from .cli import AppGroup +from .globals import current_app +from .helpers import send_from_directory +from .sansio.blueprints import Blueprint as SansioBlueprint +from .sansio.blueprints import BlueprintSetupState as BlueprintSetupState # noqa +from .sansio.scaffold import _sentinel + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +class Blueprint(SansioBlueprint): + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore + ) -> None: + super().__init__( + name, + import_name, + static_folder, + static_url_path, + template_folder, + url_prefix, + subdomain, + url_defaults, + root_path, + cli_group, + ) + + #: The Click command group for registering CLI commands for this + #: object. The commands are available from the ``flask`` command + #: once the application has been discovered and blueprints have + #: been registered. + self.cli = AppGroup() + + # Set the name of the Click group in case someone wants to add + # the app's commands to another CLI tool. + self.cli.name = self.name + + def get_send_file_max_age(self, filename: str | None) -> int | None: + """Used by :func:`send_file` to determine the ``max_age`` cache + value for a given file path if it wasn't passed. + + By default, this returns :data:`SEND_FILE_MAX_AGE_DEFAULT` from + the configuration of :data:`~flask.current_app`. This defaults + to ``None``, which tells the browser to use conditional requests + instead of a timed cache, which is usually preferable. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionchanged:: 2.0 + The default configuration is ``None`` instead of 12 hours. + + .. versionadded:: 0.9 + """ + value = current_app.config["SEND_FILE_MAX_AGE_DEFAULT"] + + if value is None: + return None + + if isinstance(value, timedelta): + return int(value.total_seconds()) + + return value # type: ignore[no-any-return] + + def send_static_file(self, filename: str) -> Response: + """The view function used to serve files from + :attr:`static_folder`. A route is automatically registered for + this view at :attr:`static_url_path` if :attr:`static_folder` is + set. + + Note this is a duplicate of the same method in the Flask + class. + + .. versionadded:: 0.5 + + """ + if not self.has_static_folder: + raise RuntimeError("'static_folder' must be set to serve static_files.") + + # send_file only knows to call get_send_file_max_age on the app, + # call it here so it works for blueprints too. + max_age = self.get_send_file_max_age(filename) + return send_from_directory( + t.cast(str, self.static_folder), filename, max_age=max_age + ) + + def open_resource( + self, resource: str, mode: str = "rb", encoding: str | None = "utf-8" + ) -> t.IO[t.AnyStr]: + """Open a resource file relative to :attr:`root_path` for reading. The + blueprint-relative equivalent of the app's :meth:`~.Flask.open_resource` + method. + + :param resource: Path to the resource relative to :attr:`root_path`. + :param mode: Open the file in this mode. Only reading is supported, + valid values are ``"r"`` (or ``"rt"``) and ``"rb"``. + :param encoding: Open the file with this encoding when opening in text + mode. This is ignored when opening in binary mode. + + .. versionchanged:: 3.1 + Added the ``encoding`` parameter. + """ + if mode not in {"r", "rt", "rb"}: + raise ValueError("Resources can only be opened for reading.") + + path = os.path.join(self.root_path, resource) + + if mode == "rb": + return open(path, mode) # pyright: ignore + + return open(path, mode, encoding=encoding) diff --git a/venv/lib/python3.12/site-packages/flask/cli.py b/venv/lib/python3.12/site-packages/flask/cli.py new file mode 100644 index 00000000..ed11f256 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/cli.py @@ -0,0 +1,1135 @@ +from __future__ import annotations + +import ast +import collections.abc as cabc +import importlib.metadata +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import itemgetter +from types import ModuleType + +import click +from click.core import ParameterSource +from werkzeug import run_simple +from werkzeug.serving import is_running_from_reloader +from werkzeug.utils import import_string + +from .globals import current_app +from .helpers import get_debug_flag +from .helpers import get_load_dotenv + +if t.TYPE_CHECKING: + import ssl + + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module: ModuleType) -> Flask: + """Given a module instance this tries to find the best possible + application in the module or raises an exception. + """ + from . import Flask + + # Search for the most common names first. + for attr_name in ("app", "application"): + app = getattr(module, attr_name, None) + + if isinstance(app, Flask): + return app + + # Otherwise find the only object that is a Flask instance. + matches = [v for v in module.__dict__.values() if isinstance(v, Flask)] + + if len(matches) == 1: + return matches[0] + elif len(matches) > 1: + raise NoAppException( + "Detected multiple Flask applications in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify the correct one." + ) + + # Search for app factory functions. + for attr_name in ("create_app", "make_app"): + app_factory = getattr(module, attr_name, None) + + if inspect.isfunction(app_factory): + try: + app = app_factory() + + if isinstance(app, Flask): + return app + except TypeError as e: + if not _called_with_wrong_args(app_factory): + raise + + raise NoAppException( + f"Detected factory '{attr_name}' in module '{module.__name__}'," + " but could not call it without arguments. Use" + f" '{module.__name__}:{attr_name}(args)'" + " to specify arguments." + ) from e + + raise NoAppException( + "Failed to find Flask application or factory in module" + f" '{module.__name__}'. Use '{module.__name__}:name'" + " to specify one." + ) + + +def _called_with_wrong_args(f: t.Callable[..., Flask]) -> bool: + """Check whether calling a function raised a ``TypeError`` because + the call failed or because something in the factory raised the + error. + + :param f: The function that was called. + :return: ``True`` if the call failed. + """ + tb = sys.exc_info()[2] + + try: + while tb is not None: + if tb.tb_frame.f_code is f.__code__: + # In the function, it was called successfully. + return False + + tb = tb.tb_next + + # Didn't reach the function. + return True + finally: + # Delete tb to break a circular reference. + # https://docs.python.org/2/library/sys.html#sys.exc_info + del tb + + +def find_app_by_string(module: ModuleType, app_name: str) -> Flask: + """Check if the given string is a variable name or a function. Call + a function to get the app instance, or return the variable directly. + """ + from . import Flask + + # Parse app_name as a single expression to determine if it's a valid + # attribute name or function call. + try: + expr = ast.parse(app_name.strip(), mode="eval").body + except SyntaxError: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) from None + + if isinstance(expr, ast.Name): + name = expr.id + args = [] + kwargs = {} + elif isinstance(expr, ast.Call): + # Ensure the function name is an attribute name only. + if not isinstance(expr.func, ast.Name): + raise NoAppException( + f"Function reference must be a simple name: {app_name!r}." + ) + + name = expr.func.id + + # Parse the positional and keyword arguments as literals. + try: + args = [ast.literal_eval(arg) for arg in expr.args] + kwargs = { + kw.arg: ast.literal_eval(kw.value) + for kw in expr.keywords + if kw.arg is not None + } + except ValueError: + # literal_eval gives cryptic error messages, show a generic + # message with the full expression instead. + raise NoAppException( + f"Failed to parse arguments as literal values: {app_name!r}." + ) from None + else: + raise NoAppException( + f"Failed to parse {app_name!r} as an attribute name or function call." + ) + + try: + attr = getattr(module, name) + except AttributeError as e: + raise NoAppException( + f"Failed to find attribute {name!r} in {module.__name__!r}." + ) from e + + # If the attribute is a function, call it with any args and kwargs + # to get the real application. + if inspect.isfunction(attr): + try: + app = attr(*args, **kwargs) + except TypeError as e: + if not _called_with_wrong_args(attr): + raise + + raise NoAppException( + f"The factory {app_name!r} in module" + f" {module.__name__!r} could not be called with the" + " specified arguments." + ) from e + else: + app = attr + + if isinstance(app, Flask): + return app + + raise NoAppException( + "A valid Flask application was not obtained from" + f" '{module.__name__}:{app_name}'." + ) + + +def prepare_import(path: str) -> str: + """Given a filename this will try to calculate the python path, add it + to the search path and return the actual module name that is expected. + """ + path = os.path.realpath(path) + + fname, ext = os.path.splitext(path) + if ext == ".py": + path = fname + + if os.path.basename(path) == "__init__": + path = os.path.dirname(path) + + module_name = [] + + # move up until outside package structure (no __init__.py) + while True: + path, name = os.path.split(path) + module_name.append(name) + + if not os.path.exists(os.path.join(path, "__init__.py")): + break + + if sys.path[0] != path: + sys.path.insert(0, path) + + return ".".join(module_name[::-1]) + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[True] = True +) -> Flask: ... + + +@t.overload +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: t.Literal[False] = ... +) -> Flask | None: ... + + +def locate_app( + module_name: str, app_name: str | None, raise_if_not_found: bool = True +) -> Flask | None: + try: + __import__(module_name) + except ImportError: + # Reraise the ImportError if it occurred within the imported module. + # Determine this by checking whether the trace has a depth > 1. + if sys.exc_info()[2].tb_next: # type: ignore[union-attr] + raise NoAppException( + f"While importing {module_name!r}, an ImportError was" + f" raised:\n\n{traceback.format_exc()}" + ) from None + elif raise_if_not_found: + raise NoAppException(f"Could not import {module_name!r}.") from None + else: + return None + + module = sys.modules[module_name] + + if app_name is None: + return find_best_app(module) + else: + return find_app_by_string(module, app_name) + + +def get_version(ctx: click.Context, param: click.Parameter, value: t.Any) -> None: + if not value or ctx.resilient_parsing: + return + + flask_version = importlib.metadata.version("flask") + werkzeug_version = importlib.metadata.version("werkzeug") + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {flask_version}\n" + f"Werkzeug {werkzeug_version}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + + .. versionchanged:: 3.1 + Added the ``load_dotenv_defaults`` parameter and attribute. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + load_dotenv_defaults: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + + self.load_dotenv_defaults = get_load_dotenv(load_dotenv_defaults) + """Whether default ``.flaskenv`` and ``.env`` files should be loaded. + + ``ScriptInfo`` doesn't load anything, this is for reference when doing + the load elsewhere during processing. + + .. versionadded:: 3.1 + """ + + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + app: Flask | None = None + if self.create_app is not None: + app = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, maxsplit=1) + [None] + )[:2] + import_name = prepare_import(path) + app = locate_app(import_name, name) + else: + for path in ("wsgi.py", "app.py"): + import_name = prepare_import(path) + app = locate_app(import_name, None, raise_if_not_found=False) + + if app is not None: + break + + if app is None: + raise NoAppException( + "Could not locate a Flask application. Use the" + " 'flask --app' option, 'FLASK_APP' environment" + " variable, or a 'wsgi.py' or 'app.py' file in the" + " current directory." + ) + + if self.set_debug_flag: + # Update the app's debug flag through the descriptor so that + # other values repopulate as well. + app.debug = get_debug_flag() + + self._loaded_app = app + return app + + +pass_script_info = click.make_pass_decorator(ScriptInfo, ensure=True) + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def with_appcontext(f: F) -> F: + """Wraps a callback so that it's guaranteed to be executed with the + script's application context. + + Custom commands (and their options) registered under ``app.cli`` or + ``blueprint.cli`` will always have an app context available, this + decorator is not required in that case. + + .. versionchanged:: 2.2 + The app context is active for subcommands as well as the + decorated callback. The app context is always available to + ``app.cli`` command and parameter callbacks. + """ + + @click.pass_context + def decorator(ctx: click.Context, /, *args: t.Any, **kwargs: t.Any) -> t.Any: + if not current_app: + app = ctx.ensure_object(ScriptInfo).load_app() + ctx.with_resource(app.app_context()) + + return ctx.invoke(f, *args, **kwargs) + + return update_wrapper(decorator, f) # type: ignore[return-value] + + +class AppGroup(click.Group): + """This works similar to a regular click :class:`~click.Group` but it + changes the behavior of the :meth:`command` decorator so that it + automatically wraps the functions in :func:`with_appcontext`. + + Not to be confused with :class:`FlaskGroup`. + """ + + def command( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Command]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it wraps callbacks in :func:`with_appcontext` + unless it's disabled by passing ``with_appcontext=False``. + """ + wrap_for_ctx = kwargs.pop("with_appcontext", True) + + def decorator(f: t.Callable[..., t.Any]) -> click.Command: + if wrap_for_ctx: + f = with_appcontext(f) + return super(AppGroup, self).command(*args, **kwargs)(f) # type: ignore[no-any-return] + + return decorator + + def group( # type: ignore[override] + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], click.Group]: + """This works exactly like the method of the same name on a regular + :class:`click.Group` but it defaults the group class to + :class:`AppGroup`. + """ + kwargs.setdefault("cls", AppGroup) + return super().group(*args, **kwargs) # type: ignore[no-any-return] + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + try: + import dotenv # noqa: F401 + except ImportError: + # Only show an error if a value was passed, otherwise we still want to + # call load_dotenv and show a message without exiting. + if value is not None: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Load if a value was passed, or we want to load default files, or both. + if value is not None or ctx.obj.load_dotenv_defaults: + load_dotenv(value, load_defaults=ctx.obj.load_dotenv_defaults) + + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help=( + "Load environment variables from this file, taking precedence over" + " those set by '.env' and '.flaskenv'. Variables set directly in the" + " environment take highest precedence. python-dotenv must be installed." + ), + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 3.1 + ``-e path`` takes precedence over default ``.env`` and ``.flaskenv`` files. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params: list[click.Parameter] = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self) -> None: + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata # pyright: ignore + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx: click.Context, name: str) -> click.Command | None: + self._load_plugin_commands() + # Look up built-in and plugin commands, which should be + # available even if the app fails to load. + rv = super().get_command(ctx, name) + + if rv is not None: + return rv + + info = ctx.ensure_object(ScriptInfo) + + # Look up commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + app = info.load_app() + except NoAppException as e: + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + return None + + # Push an app context for the loaded app unless it is already + # active somehow. This makes the context available to parameter + # and command callbacks without needing @with_appcontext. + if not current_app or current_app._get_current_object() is not app: # type: ignore[attr-defined] + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx: click.Context) -> list[str]: + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, + set_debug_flag=self.set_debug_flag, + load_dotenv_defaults=self.load_dotenv, + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if (not args and self.no_args_is_help) or ( + len(args) == 1 and args[0] in self.get_help_option_names(ctx) + ): + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path: str, other: str) -> bool: + """Take ``other`` and remove the length of ``path`` from it. Then join it + to ``path``. If it is the original value, ``path`` is an ancestor of + ``other``.""" + return os.path.join(path, other[len(path) :].lstrip(os.sep)) == other + + +def load_dotenv( + path: str | os.PathLike[str] | None = None, load_defaults: bool = True +) -> bool: + """Load "dotenv" files to set environment variables. A given path takes + precedence over ``.env``, which takes precedence over ``.flaskenv``. After + loading and combining these files, values are only set if the key is not + already set in ``os.environ``. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location. + :param load_defaults: Search for and load the default ``.flaskenv`` and + ``.env`` files. + :return: ``True`` if at least one env var was loaded. + + .. versionchanged:: 3.1 + Added the ``load_defaults`` parameter. A given path takes precedence + over default files. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env files present. Install python-dotenv" + " to use them.", + fg="yellow", + err=True, + ) + + return False + + data: dict[str, str | None] = {} + + if load_defaults: + for default_name in (".flaskenv", ".env"): + if not (default_path := dotenv.find_dotenv(default_name, usecwd=True)): + continue + + data |= dotenv.dotenv_values(default_path, encoding="utf-8") + + if path is not None and os.path.isfile(path): + data |= dotenv.dotenv_values(path, encoding="utf-8") + + for key, value in data.items(): + if key in os.environ or value is None: + continue + + os.environ[key] = value + + return bool(data) # True if at least one env var was loaded. + + +def show_server_banner(debug: bool, app_import_path: str | None) -> None: + """Show extra startup messages the first time the server is run, + ignoring the reloader. + """ + if is_running_from_reloader(): + return + + if app_import_path is not None: + click.echo(f" * Serving Flask app '{app_import_path}'") + + if debug is not None: + click.echo(f" * Debug mode: {'on' if debug else 'off'}") + + +class CertParamType(click.ParamType): + """Click option type for the ``--cert`` option. Allows either an + existing file, the string ``'adhoc'``, or an import for a + :class:`~ssl.SSLContext` object. + """ + + name = "path" + + def __init__(self) -> None: + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + try: + import ssl + except ImportError: + raise click.BadParameter( + 'Using "--cert" requires Python to be compiled with SSL support.', + ctx, + param, + ) from None + + try: + return self.path_type(value, param, ctx) + except click.BadParameter: + value = click.STRING(value, param, ctx).lower() + + if value == "adhoc": + try: + import cryptography # noqa: F401 + except ImportError: + raise click.BadParameter( + "Using ad-hoc certificates requires the cryptography library.", + ctx, + param, + ) from None + + return value + + obj = import_string(value, silent=True) + + if isinstance(obj, ssl.SSLContext): + return obj + + raise + + +def _validate_key(ctx: click.Context, param: click.Parameter, value: t.Any) -> t.Any: + """The ``--key`` option must be specified when ``--cert`` is a file. + Modifies the ``cert`` param to be a ``(cert, key)`` pair if needed. + """ + cert = ctx.params.get("cert") + is_adhoc = cert == "adhoc" + + try: + import ssl + except ImportError: + is_context = False + else: + is_context = isinstance(cert, ssl.SSLContext) + + if value is not None: + if is_adhoc: + raise click.BadParameter( + 'When "--cert" is "adhoc", "--key" is not used.', ctx, param + ) + + if is_context: + raise click.BadParameter( + 'When "--cert" is an SSLContext object, "--key" is not used.', + ctx, + param, + ) + + if not cert: + raise click.BadParameter('"--cert" must also be specified.', ctx, param) + + ctx.params["cert"] = cert, value + + else: + if cert and not (is_adhoc or is_context): + raise click.BadParameter('Required when using "--cert".', ctx, param) + + return value + + +class SeparatedPathType(click.Path): + """Click option type that accepts a list of values separated by the + OS's path separator (``:``, ``;`` on Windows). Each value is + validated as a :class:`click.Path` type. + """ + + def convert( + self, value: t.Any, param: click.Parameter | None, ctx: click.Context | None + ) -> t.Any: + items = self.split_envvar_value(value) + # can't call no-arg super() inside list comprehension until Python 3.12 + super_convert = super().convert + return [super_convert(item, param, ctx) for item in items] + + +@click.command("run", short_help="Run a development server.") +@click.option("--host", "-h", default="127.0.0.1", help="The interface to bind to.") +@click.option("--port", "-p", default=5000, help="The port to bind to.") +@click.option( + "--cert", + type=CertParamType(), + help="Specify a certificate file to use HTTPS.", + is_eager=True, +) +@click.option( + "--key", + type=click.Path(exists=True, dir_okay=False, resolve_path=True), + callback=_validate_key, + expose_value=False, + help="The key file to use when specifying a certificate.", +) +@click.option( + "--reload/--no-reload", + default=None, + help="Enable or disable the reloader. By default the reloader " + "is active if debug is enabled.", +) +@click.option( + "--debugger/--no-debugger", + default=None, + help="Enable or disable the debugger. By default the debugger " + "is active if debug is enabled.", +) +@click.option( + "--with-threads/--without-threads", + default=True, + help="Enable or disable multithreading.", +) +@click.option( + "--extra-files", + default=None, + type=SeparatedPathType(), + help=( + "Extra files that trigger a reload on change. Multiple paths" + f" are separated by {os.path.pathsep!r}." + ), +) +@click.option( + "--exclude-patterns", + default=None, + type=SeparatedPathType(), + help=( + "Files matching these fnmatch patterns will not trigger a reload" + " on change. Multiple patterns are separated by" + f" {os.path.pathsep!r}." + ), +) +@pass_script_info +def run_command( + info: ScriptInfo, + host: str, + port: int, + reload: bool, + debugger: bool, + with_threads: bool, + cert: ssl.SSLContext | tuple[str, str | None] | t.Literal["adhoc"] | None, + extra_files: list[str] | None, + exclude_patterns: list[str] | None, +) -> None: + """Run a local development server. + + This server is for development purposes only. It does not provide + the stability, security, or performance of production WSGI servers. + + The reloader and debugger are enabled by default with the '--debug' + option. + """ + try: + app: WSGIApplication = info.load_app() # pyright: ignore + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app( + environ: WSGIEnvironment, start_response: StartResponse + ) -> cabc.Iterable[bytes]: + raise err from None + + else: + # When not reloading, raise the error immediately so the + # command fails. + raise e from None + + debug = get_debug_flag() + + if reload is None: + reload = debug + + if debugger is None: + debugger = debug + + show_server_banner(debug, info.app_import_path) + + run_simple( + host, + port, + app, + use_reloader=reload, + use_debugger=debugger, + threaded=with_threads, + ssl_context=cert, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + ) + + +run_command.params.insert(0, _debug_option) + + +@click.command("shell", short_help="Run a shell in the app context.") +@with_appcontext +def shell_command() -> None: + """Run an interactive Python shell in the context of a given + Flask application. The application will populate the default + namespace of this shell according to its configuration. + + This is useful for executing small snippets of management code + without having to manually configure the application. + """ + import code + + banner = ( + f"Python {sys.version} on {sys.platform}\n" + f"App: {current_app.import_name}\n" + f"Instance: {current_app.instance_path}" + ) + ctx: dict[str, t.Any] = {} + + # Support the regular Python interpreter startup script if someone + # is using it. + startup = os.environ.get("PYTHONSTARTUP") + if startup and os.path.isfile(startup): + with open(startup) as f: + eval(compile(f.read(), startup, "exec"), ctx) + + ctx.update(current_app.make_shell_context()) + + # Site, customize, or startup script can set a hook to call when + # entering interactive mode. The default one sets up readline with + # tab and history completion. + interactive_hook = getattr(sys, "__interactivehook__", None) + + if interactive_hook is not None: + try: + import readline + from rlcompleter import Completer + except ImportError: + pass + else: + # rlcompleter uses __main__.__dict__ by default, which is + # flask.__main__. Use the shell context instead. + readline.set_completer(Completer(ctx).complete) + + interactive_hook() + + code.interact(banner=banner, local=ctx) + + +@click.command("routes", short_help="Show the routes for the app.") +@click.option( + "--sort", + "-s", + type=click.Choice(("endpoint", "methods", "domain", "rule", "match")), + default="endpoint", + help=( + "Method to sort routes by. 'match' is the order that Flask will match routes" + " when dispatching a request." + ), +) +@click.option("--all-methods", is_flag=True, help="Show HEAD and OPTIONS methods.") +@with_appcontext +def routes_command(sort: str, all_methods: bool) -> None: + """Show all registered routes with endpoints and methods.""" + rules = list(current_app.url_map.iter_rules()) + + if not rules: + click.echo("No routes were registered.") + return + + ignored_methods = set() if all_methods else {"HEAD", "OPTIONS"} + host_matching = current_app.url_map.host_matching + has_domain = any(rule.host if host_matching else rule.subdomain for rule in rules) + rows = [] + + for rule in rules: + row = [ + rule.endpoint, + ", ".join(sorted((rule.methods or set()) - ignored_methods)), + ] + + if has_domain: + row.append((rule.host if host_matching else rule.subdomain) or "") + + row.append(rule.rule) + rows.append(row) + + headers = ["Endpoint", "Methods"] + sorts = ["endpoint", "methods"] + + if has_domain: + headers.append("Host" if host_matching else "Subdomain") + sorts.append("domain") + + headers.append("Rule") + sorts.append("rule") + + try: + rows.sort(key=itemgetter(sorts.index(sort))) + except ValueError: + pass + + rows.insert(0, headers) + widths = [max(len(row[i]) for row in rows) for i in range(len(headers))] + rows.insert(1, ["-" * w for w in widths]) + template = " ".join(f"{{{i}:<{w}}}" for i, w in enumerate(widths)) + + for row in rows: + click.echo(template.format(*row)) + + +cli = FlaskGroup( + name="flask", + help="""\ +A general utility script for Flask applications. + +An application to load must be given with the '--app' option, +'FLASK_APP' environment variable, or with a 'wsgi.py' or 'app.py' file +in the current directory. +""", +) + + +def main() -> None: + cli.main() + + +if __name__ == "__main__": + main() diff --git a/venv/lib/python3.12/site-packages/flask/config.py b/venv/lib/python3.12/site-packages/flask/config.py new file mode 100644 index 00000000..34ef1a57 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/config.py @@ -0,0 +1,367 @@ +from __future__ import annotations + +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .sansio.app import App + + +T = t.TypeVar("T") + + +class ConfigAttribute(t.Generic[T]): + """Makes an attribute forward to the config""" + + def __init__( + self, name: str, get_converter: t.Callable[[t.Any], T] | None = None + ) -> None: + self.__name__ = name + self.get_converter = get_converter + + @t.overload + def __get__(self, obj: None, owner: None) -> te.Self: ... + + @t.overload + def __get__(self, obj: App, owner: type[App]) -> T: ... + + def __get__(self, obj: App | None, owner: type[App] | None = None) -> T | te.Self: + if obj is None: + return self + + rv = obj.config[self.__name__] + + if self.get_converter is not None: + rv = self.get_converter(rv) + + return rv # type: ignore[no-any-return] + + def __set__(self, obj: App, value: t.Any) -> None: + obj.config[self.__name__] = value + + +class Config(dict): # type: ignore[type-arg] + """Works exactly like a dict but provides ways to fill it from files + or special dictionaries. There are two common patterns to populate the + config. + + Either you can fill the config from a config file:: + + app.config.from_pyfile('yourconfig.cfg') + + Or alternatively you can define the configuration options in the + module that calls :meth:`from_object` or provide an import path to + a module that should be loaded. It is also possible to tell it to + use the same module and with that provide the configuration values + just before the call:: + + DEBUG = True + SECRET_KEY = 'development key' + app.config.from_object(__name__) + + In both cases (loading from any Python file or loading from modules), + only uppercase keys are added to the config. This makes it possible to use + lowercase values in the config file for temporary values that are not added + to the config or to define the config keys in the same file that implements + the application. + + Probably the most interesting way to load configurations is from an + environment variable pointing to a file:: + + app.config.from_envvar('YOURAPPLICATION_SETTINGS') + + In this case before launching the application you have to set this + environment variable to the file you want to use. On Linux and OS X + use the export statement:: + + export YOURAPPLICATION_SETTINGS='/path/to/config/file' + + On windows use `set` instead. + + :param root_path: path to which files are read relative from. When the + config object is created by the application, this is + the application's :attr:`~flask.Flask.root_path`. + :param defaults: an optional dictionary of default values + """ + + def __init__( + self, + root_path: str | os.PathLike[str], + defaults: dict[str, t.Any] | None = None, + ) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + key = key.removeprefix(prefix) + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile( + self, filename: str | os.PathLike[str], silent: bool = False + ) -> bool: + """Updates the values in the config from a Python file. This function + behaves as if the file was imported as module with the + :meth:`from_object` function. + + :param filename: the filename of the config. This can either be an + absolute filename or a filename relative to the + root path. + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 0.7 + `silent` parameter. + """ + filename = os.path.join(self.root_path, filename) + d = types.ModuleType("config") + d.__file__ = filename + try: + with open(filename, mode="rb") as config_file: + exec(compile(config_file.read(), filename, "exec"), d.__dict__) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR, errno.ENOTDIR): + return False + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + self.from_object(d) + return True + + def from_object(self, obj: object | str) -> None: + """Updates the values from the given object. An object can be of one + of the following two types: + + - a string: in this case the object with that name will be imported + - an actual object reference: that object is used directly + + Objects are usually either modules or classes. :meth:`from_object` + loads only the uppercase attributes of the module/class. A ``dict`` + object will not work with :meth:`from_object` because the keys of a + ``dict`` are not attributes of the ``dict`` class. + + Example of module-based configuration:: + + app.config.from_object('yourapplication.default_config') + from yourapplication import default_config + app.config.from_object(default_config) + + Nothing is done to the object before loading. If the object is a + class and has ``@property`` attributes, it needs to be + instantiated before being passed to this method. + + You should not use this function to load the actual configuration but + rather configuration defaults. The actual config should be loaded + with :meth:`from_pyfile` and ideally from a location not within the + package because the package might be installed system wide. + + See :ref:`config-dev-prod` for an example of class-based configuration + using :meth:`from_object`. + + :param obj: an import name or object + """ + if isinstance(obj, str): + obj = import_string(obj) + for key in dir(obj): + if key.isupper(): + self[key] = getattr(obj, key) + + def from_file( + self, + filename: str | os.PathLike[str], + load: t.Callable[[t.IO[t.Any]], t.Mapping[str, t.Any]], + silent: bool = False, + text: bool = True, + ) -> bool: + """Update the values in the config from a file that is loaded + using the ``load`` parameter. The loaded data is passed to the + :meth:`from_mapping` method. + + .. code-block:: python + + import json + app.config.from_file("config.json", load=json.load) + + import tomllib + app.config.from_file("config.toml", load=tomllib.load, text=False) + + :param filename: The path to the data file. This can be an + absolute path or relative to the config root path. + :param load: A callable that takes a file handle and returns a + mapping of loaded data from the file. + :type load: ``Callable[[Reader], Mapping]`` where ``Reader`` + implements a ``read`` method. + :param silent: Ignore the file if it doesn't exist. + :param text: Open the file in text or binary mode. + :return: ``True`` if the file was loaded successfully. + + .. versionchanged:: 2.3 + The ``text`` parameter was added. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename, "r" if text else "rb") as f: + obj = load(f) + except OSError as e: + if silent and e.errno in (errno.ENOENT, errno.EISDIR): + return False + + e.strerror = f"Unable to load configuration file ({e.strerror})" + raise + + return self.from_mapping(obj) + + def from_mapping( + self, mapping: t.Mapping[str, t.Any] | None = None, **kwargs: t.Any + ) -> bool: + """Updates the config like :meth:`update` ignoring items with + non-upper keys. + + :return: Always returns ``True``. + + .. versionadded:: 0.11 + """ + mappings: dict[str, t.Any] = {} + if mapping is not None: + mappings.update(mapping) + mappings.update(kwargs) + for key, value in mappings.items(): + if key.isupper(): + self[key] = value + return True + + def get_namespace( + self, namespace: str, lowercase: bool = True, trim_namespace: bool = True + ) -> dict[str, t.Any]: + """Returns a dictionary containing a subset of configuration options + that match the specified namespace/prefix. Example usage:: + + app.config['IMAGE_STORE_TYPE'] = 'fs' + app.config['IMAGE_STORE_PATH'] = '/var/app/images' + app.config['IMAGE_STORE_BASE_URL'] = 'http://img.website.com' + image_store_config = app.config.get_namespace('IMAGE_STORE_') + + The resulting dictionary `image_store_config` would look like:: + + { + 'type': 'fs', + 'path': '/var/app/images', + 'base_url': 'http://img.website.com' + } + + This is often useful when configuration options map directly to + keyword arguments in functions or class constructors. + + :param namespace: a configuration namespace + :param lowercase: a flag indicating if the keys of the resulting + dictionary should be lowercase + :param trim_namespace: a flag indicating if the keys of the resulting + dictionary should not include the namespace + + .. versionadded:: 0.11 + """ + rv = {} + for k, v in self.items(): + if not k.startswith(namespace): + continue + if trim_namespace: + key = k[len(namespace) :] + else: + key = k + if lowercase: + key = key.lower() + rv[key] = v + return rv + + def __repr__(self) -> str: + return f"<{type(self).__name__} {dict.__repr__(self)}>" diff --git a/venv/lib/python3.12/site-packages/flask/ctx.py b/venv/lib/python3.12/site-packages/flask/ctx.py new file mode 100644 index 00000000..9b164d39 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/ctx.py @@ -0,0 +1,449 @@ +from __future__ import annotations + +import contextvars +import sys +import typing as t +from functools import update_wrapper +from types import TracebackType + +from werkzeug.exceptions import HTTPException + +from . import typing as ft +from .globals import _cv_app +from .globals import _cv_request +from .signals import appcontext_popped +from .signals import appcontext_pushed + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + + from .app import Flask + from .sessions import SessionMixin + from .wrappers import Request + + +# a singleton sentinel value for parameter defaults +_sentinel = object() + + +class _AppCtxGlobals: + """A plain object. Used as a namespace for storing data during an + application context. + + Creating an app context automatically creates this object, which is + made available as the :data:`g` proxy. + + .. describe:: 'key' in g + + Check whether an attribute is present. + + .. versionadded:: 0.10 + + .. describe:: iter(g) + + Return an iterator over the attribute names. + + .. versionadded:: 0.10 + """ + + # Define attr methods to let mypy know this is a namespace object + # that has arbitrary attributes. + + def __getattr__(self, name: str) -> t.Any: + try: + return self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def __setattr__(self, name: str, value: t.Any) -> None: + self.__dict__[name] = value + + def __delattr__(self, name: str) -> None: + try: + del self.__dict__[name] + except KeyError: + raise AttributeError(name) from None + + def get(self, name: str, default: t.Any | None = None) -> t.Any: + """Get an attribute by name, or a default value. Like + :meth:`dict.get`. + + :param name: Name of attribute to get. + :param default: Value to return if the attribute is not present. + + .. versionadded:: 0.10 + """ + return self.__dict__.get(name, default) + + def pop(self, name: str, default: t.Any = _sentinel) -> t.Any: + """Get and remove an attribute by name. Like :meth:`dict.pop`. + + :param name: Name of attribute to pop. + :param default: Value to return if the attribute is not present, + instead of raising a ``KeyError``. + + .. versionadded:: 0.11 + """ + if default is _sentinel: + return self.__dict__.pop(name) + else: + return self.__dict__.pop(name, default) + + def setdefault(self, name: str, default: t.Any = None) -> t.Any: + """Get the value of an attribute if it is present, otherwise + set and return a default value. Like :meth:`dict.setdefault`. + + :param name: Name of attribute to get. + :param default: Value to set and return if the attribute is not + present. + + .. versionadded:: 0.11 + """ + return self.__dict__.setdefault(name, default) + + def __contains__(self, item: str) -> bool: + return item in self.__dict__ + + def __iter__(self) -> t.Iterator[str]: + return iter(self.__dict__) + + def __repr__(self) -> str: + ctx = _cv_app.get(None) + if ctx is not None: + return f"" + return object.__repr__(self) + + +def after_this_request( + f: ft.AfterRequestCallable[t.Any], +) -> ft.AfterRequestCallable[t.Any]: + """Executes a function after this request. This is useful to modify + response objects. The function is passed the response object and has + to return the same or a new one. + + Example:: + + @app.route('/') + def index(): + @after_this_request + def add_header(response): + response.headers['X-Foo'] = 'Parachute' + return response + return 'Hello World!' + + This is more useful if a function other than the view function wants to + modify a response. For instance think of a decorator that wants to add + some headers without converting the return value into a response object. + + .. versionadded:: 0.9 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'after_this_request' can only be used when a request" + " context is active, such as in a view function." + ) + + ctx._after_request_functions.append(f) + return f + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def copy_current_request_context(f: F) -> F: + """A helper function that decorates a function to retain the current + request context. This is useful when working with greenlets. The moment + the function is decorated a copy of the request context is created and + then pushed when the function is called. The current session is also + included in the copied request context. + + Example:: + + import gevent + from flask import copy_current_request_context + + @app.route('/') + def index(): + @copy_current_request_context + def do_some_work(): + # do some work here, it can access flask.request or + # flask.session like you would otherwise in the view function. + ... + gevent.spawn(do_some_work) + return 'Regular response' + + .. versionadded:: 0.10 + """ + ctx = _cv_request.get(None) + + if ctx is None: + raise RuntimeError( + "'copy_current_request_context' can only be used when a" + " request context is active, such as in a view function." + ) + + ctx = ctx.copy() + + def wrapper(*args: t.Any, **kwargs: t.Any) -> t.Any: + with ctx: # type: ignore[union-attr] + return ctx.app.ensure_sync(f)(*args, **kwargs) # type: ignore[union-attr] + + return update_wrapper(wrapper, f) # type: ignore[return-value] + + +def has_request_context() -> bool: + """If you have code that wants to test if a request context is there or + not this function can be used. For instance, you may want to take advantage + of request information if the request object is available, but fail + silently if it is unavailable. + + :: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and has_request_context(): + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + Alternatively you can also just test any of the context bound objects + (such as :class:`request` or :class:`g`) for truthness:: + + class User(db.Model): + + def __init__(self, username, remote_addr=None): + self.username = username + if remote_addr is None and request: + remote_addr = request.remote_addr + self.remote_addr = remote_addr + + .. versionadded:: 0.7 + """ + return _cv_request.get(None) is not None + + +def has_app_context() -> bool: + """Works like :func:`has_request_context` but for the application + context. You can also just do a boolean check on the + :data:`current_app` object instead. + + .. versionadded:: 0.9 + """ + return _cv_app.get(None) is not None + + +class AppContext: + """The app context contains application-specific information. An app + context is created and pushed at the beginning of each request if + one is not already active. An app context is also pushed when + running CLI commands. + """ + + def __init__(self, app: Flask) -> None: + self.app = app + self.url_adapter = app.create_url_adapter(None) + self.g: _AppCtxGlobals = app.app_ctx_globals_class() + self._cv_tokens: list[contextvars.Token[AppContext]] = [] + + def push(self) -> None: + """Binds the app context to the current context.""" + self._cv_tokens.append(_cv_app.set(self)) + appcontext_pushed.send(self.app, _async_wrapper=self.app.ensure_sync) + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the app context.""" + try: + if len(self._cv_tokens) == 1: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_appcontext(exc) + finally: + ctx = _cv_app.get() + _cv_app.reset(self._cv_tokens.pop()) + + if ctx is not self: + raise AssertionError( + f"Popped wrong app context. ({ctx!r} instead of {self!r})" + ) + + appcontext_popped.send(self.app, _async_wrapper=self.app.ensure_sync) + + def __enter__(self) -> AppContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + +class RequestContext: + """The request context contains per-request information. The Flask + app creates and pushes it at the beginning of the request, then pops + it at the end of the request. It will create the URL adapter and + request object for the WSGI environment provided. + + Do not attempt to use this class directly, instead use + :meth:`~flask.Flask.test_request_context` and + :meth:`~flask.Flask.request_context` to create this object. + + When the request context is popped, it will evaluate all the + functions registered on the application for teardown execution + (:meth:`~flask.Flask.teardown_request`). + + The request context is automatically popped at the end of the + request. When using the interactive debugger, the context will be + restored so ``request`` is still accessible. Similarly, the test + client can preserve the context after the request ends. However, + teardown functions may already have closed some resources such as + database connections. + """ + + def __init__( + self, + app: Flask, + environ: WSGIEnvironment, + request: Request | None = None, + session: SessionMixin | None = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json + self.request: Request = request + self.url_adapter = None + try: + self.url_adapter = app.create_url_adapter(self.request) + except HTTPException as e: + self.request.routing_exception = e + self.flashes: list[tuple[str, str]] | None = None + self.session: SessionMixin | None = session + # Functions that should be executed after the request on the response + # object. These will be called before the regular "after_request" + # functions. + self._after_request_functions: list[ft.AfterRequestCallable[t.Any]] = [] + + self._cv_tokens: list[ + tuple[contextvars.Token[RequestContext], AppContext | None] + ] = [] + + def copy(self) -> RequestContext: + """Creates a copy of this request context with the same request object. + This can be used to move a request context to a different greenlet. + Because the actual request object is the same this cannot be used to + move a request context to a different thread unless access to the + request object is locked. + + .. versionadded:: 0.10 + + .. versionchanged:: 1.1 + The current session object is used instead of reloading the original + data. This prevents `flask.session` pointing to an out-of-date object. + """ + return self.__class__( + self.app, + environ=self.request.environ, + request=self.request, + session=self.session, + ) + + def match_request(self) -> None: + """Can be overridden by a subclass to hook into the matching + of the request. + """ + try: + result = self.url_adapter.match(return_rule=True) # type: ignore + self.request.url_rule, self.request.view_args = result # type: ignore + except HTTPException as e: + self.request.routing_exception = e + + def push(self) -> None: + # Before we push the request context we have to ensure that there + # is an application context. + app_ctx = _cv_app.get(None) + + if app_ctx is None or app_ctx.app is not self.app: + app_ctx = self.app.app_context() + app_ctx.push() + else: + app_ctx = None + + self._cv_tokens.append((_cv_request.set(self), app_ctx)) + + # Open the session at the moment that the request context is available. + # This allows a custom open_session method to use the request context. + # Only open a new session if this is the first time the request was + # pushed, otherwise stream_with_context loses the session. + if self.session is None: + session_interface = self.app.session_interface + self.session = session_interface.open_session(self.app, self.request) + + if self.session is None: + self.session = session_interface.make_null_session(self.app) + + # Match the request URL after loading the session, so that the + # session is available in custom URL converters. + if self.url_adapter is not None: + self.match_request() + + def pop(self, exc: BaseException | None = _sentinel) -> None: # type: ignore + """Pops the request context and unbinds it by doing that. This will + also trigger the execution of functions registered by the + :meth:`~flask.Flask.teardown_request` decorator. + + .. versionchanged:: 0.9 + Added the `exc` argument. + """ + clear_request = len(self._cv_tokens) == 1 + + try: + if clear_request: + if exc is _sentinel: + exc = sys.exc_info()[1] + self.app.do_teardown_request(exc) + + request_close = getattr(self.request, "close", None) + if request_close is not None: + request_close() + finally: + ctx = _cv_request.get() + token, app_ctx = self._cv_tokens.pop() + _cv_request.reset(token) + + # get rid of circular dependencies at the end of the request + # so that we don't require the GC to be active. + if clear_request: + ctx.request.environ["werkzeug.request"] = None + + if app_ctx is not None: + app_ctx.pop(exc) + + if ctx is not self: + raise AssertionError( + f"Popped wrong request context. ({ctx!r} instead of {self!r})" + ) + + def __enter__(self) -> RequestContext: + self.push() + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.pop(exc_value) + + def __repr__(self) -> str: + return ( + f"<{type(self).__name__} {self.request.url!r}" + f" [{self.request.method}] of {self.app.name}>" + ) diff --git a/venv/lib/python3.12/site-packages/flask/debughelpers.py b/venv/lib/python3.12/site-packages/flask/debughelpers.py new file mode 100644 index 00000000..2c8c4c48 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/debughelpers.py @@ -0,0 +1,178 @@ +from __future__ import annotations + +import typing as t + +from jinja2.loaders import BaseLoader +from werkzeug.routing import RequestRedirect + +from .blueprints import Blueprint +from .globals import request_ctx +from .sansio.app import App + +if t.TYPE_CHECKING: + from .sansio.scaffold import Scaffold + from .wrappers import Request + + +class UnexpectedUnicodeError(AssertionError, UnicodeError): + """Raised in places where we want some better error reporting for + unexpected unicode or binary data. + """ + + +class DebugFilesKeyError(KeyError, AssertionError): + """Raised from request.files during debugging. The idea is that it can + provide a better error message than just a generic KeyError/BadRequest. + """ + + def __init__(self, request: Request, key: str) -> None: + form_matches = request.form.getlist(key) + buf = [ + f"You tried to access the file {key!r} in the request.files" + " dictionary but it does not exist. The mimetype for the" + f" request is {request.mimetype!r} instead of" + " 'multipart/form-data' which means that no file contents" + " were transmitted. To fix this error you should provide" + ' enctype="multipart/form-data" in your form.' + ] + if form_matches: + names = ", ".join(repr(x) for x in form_matches) + buf.append( + "\n\nThe browser instead transmitted some file names. " + f"This was submitted: {names}" + ) + self.msg = "".join(buf) + + def __str__(self) -> str: + return self.msg + + +class FormDataRoutingRedirect(AssertionError): + """This exception is raised in debug mode if a routing redirect + would cause the browser to drop the method or body. This happens + when method is not GET, HEAD or OPTIONS and the status code is not + 307 or 308. + """ + + def __init__(self, request: Request) -> None: + exc = request.routing_exception + assert isinstance(exc, RequestRedirect) + buf = [ + f"A request was sent to '{request.url}', but routing issued" + f" a redirect to the canonical URL '{exc.new_url}'." + ] + + if f"{request.base_url}/" == exc.new_url.partition("?")[0]: + buf.append( + " The URL was defined with a trailing slash. Flask" + " will redirect to the URL with a trailing slash if it" + " was accessed without one." + ) + + buf.append( + " Send requests to the canonical URL, or use 307 or 308 for" + " routing redirects. Otherwise, browsers will drop form" + " data.\n\n" + "This exception is only raised in debug mode." + ) + super().__init__("".join(buf)) + + +def attach_enctype_error_multidict(request: Request) -> None: + """Patch ``request.files.__getitem__`` to raise a descriptive error + about ``enctype=multipart/form-data``. + + :param request: The request to patch. + :meta private: + """ + oldcls = request.files.__class__ + + class newcls(oldcls): # type: ignore[valid-type, misc] + def __getitem__(self, key: str) -> t.Any: + try: + return super().__getitem__(key) + except KeyError as e: + if key not in request.form: + raise + + raise DebugFilesKeyError(request, key).with_traceback( + e.__traceback__ + ) from None + + newcls.__name__ = oldcls.__name__ + newcls.__module__ = oldcls.__module__ + request.files.__class__ = newcls + + +def _dump_loader_info(loader: BaseLoader) -> t.Iterator[str]: + yield f"class: {type(loader).__module__}.{type(loader).__name__}" + for key, value in sorted(loader.__dict__.items()): + if key.startswith("_"): + continue + if isinstance(value, (tuple, list)): + if not all(isinstance(x, str) for x in value): + continue + yield f"{key}:" + for item in value: + yield f" - {item}" + continue + elif not isinstance(value, (str, int, float, bool)): + continue + yield f"{key}: {value!r}" + + +def explain_template_loading_attempts( + app: App, + template: str, + attempts: list[ + tuple[ + BaseLoader, + Scaffold, + tuple[str, str | None, t.Callable[[], bool] | None] | None, + ] + ], +) -> None: + """This should help developers understand what failed""" + info = [f"Locating template {template!r}:"] + total_found = 0 + blueprint = None + if request_ctx and request_ctx.request.blueprint is not None: + blueprint = request_ctx.request.blueprint + + for idx, (loader, srcobj, triple) in enumerate(attempts): + if isinstance(srcobj, App): + src_info = f"application {srcobj.import_name!r}" + elif isinstance(srcobj, Blueprint): + src_info = f"blueprint {srcobj.name!r} ({srcobj.import_name})" + else: + src_info = repr(srcobj) + + info.append(f"{idx + 1:5}: trying loader of {src_info}") + + for line in _dump_loader_info(loader): + info.append(f" {line}") + + if triple is None: + detail = "no match" + else: + detail = f"found ({triple[1] or ''!r})" + total_found += 1 + info.append(f" -> {detail}") + + seems_fishy = False + if total_found == 0: + info.append("Error: the template could not be found.") + seems_fishy = True + elif total_found > 1: + info.append("Warning: multiple loaders returned a match for the template.") + seems_fishy = True + + if blueprint is not None and seems_fishy: + info.append( + " The template was looked up from an endpoint that belongs" + f" to the blueprint {blueprint!r}." + ) + info.append(" Maybe you did not place a template in the right folder?") + info.append(" See https://flask.palletsprojects.com/blueprints/#templates") + + app.logger.info("\n".join(info)) diff --git a/venv/lib/python3.12/site-packages/flask/globals.py b/venv/lib/python3.12/site-packages/flask/globals.py new file mode 100644 index 00000000..e2c410cc --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/globals.py @@ -0,0 +1,51 @@ +from __future__ import annotations + +import typing as t +from contextvars import ContextVar + +from werkzeug.local import LocalProxy + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .ctx import _AppCtxGlobals + from .ctx import AppContext + from .ctx import RequestContext + from .sessions import SessionMixin + from .wrappers import Request + + +_no_app_msg = """\ +Working outside of application context. + +This typically means that you attempted to use functionality that needed +the current application. To solve this, set up an application context +with app.app_context(). See the documentation for more information.\ +""" +_cv_app: ContextVar[AppContext] = ContextVar("flask.app_ctx") +app_ctx: AppContext = LocalProxy( # type: ignore[assignment] + _cv_app, unbound_message=_no_app_msg +) +current_app: Flask = LocalProxy( # type: ignore[assignment] + _cv_app, "app", unbound_message=_no_app_msg +) +g: _AppCtxGlobals = LocalProxy( # type: ignore[assignment] + _cv_app, "g", unbound_message=_no_app_msg +) + +_no_req_msg = """\ +Working outside of request context. + +This typically means that you attempted to use functionality that needed +an active HTTP request. Consult the documentation on testing for +information about how to avoid this problem.\ +""" +_cv_request: ContextVar[RequestContext] = ContextVar("flask.request_ctx") +request_ctx: RequestContext = LocalProxy( # type: ignore[assignment] + _cv_request, unbound_message=_no_req_msg +) +request: Request = LocalProxy( # type: ignore[assignment] + _cv_request, "request", unbound_message=_no_req_msg +) +session: SessionMixin = LocalProxy( # type: ignore[assignment] + _cv_request, "session", unbound_message=_no_req_msg +) diff --git a/venv/lib/python3.12/site-packages/flask/helpers.py b/venv/lib/python3.12/site-packages/flask/helpers.py new file mode 100644 index 00000000..a6b7e150 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/helpers.py @@ -0,0 +1,634 @@ +from __future__ import annotations + +import importlib.util +import os +import sys +import typing as t +from datetime import datetime +from functools import cache +from functools import update_wrapper + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .globals import request_ctx +from .globals import session +from .signals import message_flashed + +if t.TYPE_CHECKING: # pragma: no cover + from .wrappers import Response + + +def get_debug_flag() -> bool: + """Get whether debug mode should be enabled for the app, indicated by the + :envvar:`FLASK_DEBUG` environment variable. The default is ``False``. + """ + val = os.environ.get("FLASK_DEBUG") + return bool(val and val.lower() not in {"0", "false", "no"}) + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +@t.overload +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr], +) -> t.Iterator[t.AnyStr]: ... + + +@t.overload +def stream_with_context( + generator_or_function: t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: ... + + +def stream_with_context( + generator_or_function: t.Iterator[t.AnyStr] | t.Callable[..., t.Iterator[t.AnyStr]], +) -> t.Iterator[t.AnyStr] | t.Callable[[t.Iterator[t.AnyStr]], t.Iterator[t.AnyStr]]: + """Request contexts disappear when the response is started on the server. + This is done for efficiency reasons and to make it less likely to encounter + memory leaks with badly written WSGI middlewares. The downside is that if + you are using streamed responses, the generator cannot access request bound + information any more. + + This function however can help you keep the context around for longer:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + @stream_with_context + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(generate()) + + Alternatively it can also be used around a specific generator:: + + from flask import stream_with_context, request, Response + + @app.route('/stream') + def streamed_response(): + def generate(): + yield 'Hello ' + yield request.args['name'] + yield '!' + return Response(stream_with_context(generate())) + + .. versionadded:: 0.9 + """ + try: + gen = iter(generator_or_function) # type: ignore[arg-type] + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore[operator] + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore[arg-type] + + def generator() -> t.Iterator[t.AnyStr | None]: + ctx = _cv_request.get(None) + if ctx is None: + raise RuntimeError( + "'stream_with_context' can only be used when a request" + " context is active, such as in a view function." + ) + with ctx: + # Dummy sentinel. Has to be inside the context block or we're + # not actually keeping the context around. + yield None + + # The try/finally is here so that if someone passes a WSGI level + # iterator in we're still running the cleanup logic. Generators + # don't need that because they are closed on their destruction + # automatically. + try: + yield from gen + finally: + if hasattr(gen, "close"): + gen.close() + + # The trick is to start the generator. Then the code execution runs until + # the first dummy None is yielded at which point the context was already + # pushed. This item is discarded. Then when the iteration continues the + # real generator is executed. + wrapped_g = generator() + next(wrapped_g) + return wrapped_g # type: ignore[return-value] + + +def make_response(*args: t.Any) -> Response: + """Sometimes it is necessary to set additional headers in a view. Because + views do not have to return response objects but can return a value that + is converted into a response object by Flask itself, it becomes tricky to + add headers to it. This function can be called instead of using a return + and you will get a response object which you can use to attach headers. + + If view looked like this and you want to add a new header:: + + def index(): + return render_template('index.html', foo=42) + + You can now do something like this:: + + def index(): + response = make_response(render_template('index.html', foo=42)) + response.headers['X-Parachutes'] = 'parachutes are cool' + return response + + This function accepts the very same arguments you can return from a + view function. This for example creates a response with a 404 error + code:: + + response = make_response(render_template('not_found.html'), 404) + + The other use case of this function is to force the return value of a + view function into a response which is helpful with view + decorators:: + + response = make_response(view_function()) + response.headers['X-Parachutes'] = 'parachutes are cool' + + Internally this function does the following things: + + - if no arguments are passed, it creates a new response argument + - if one argument is passed, :meth:`flask.Flask.make_response` + is invoked with it. + - if more than one argument is passed, the arguments are passed + to the :meth:`flask.Flask.make_response` function as tuple. + + .. versionadded:: 0.6 + """ + if not args: + return current_app.response_class() + if len(args) == 1: + args = args[0] + return current_app.make_response(args) + + +def url_for( + endpoint: str, + *, + _anchor: str | None = None, + _method: str | None = None, + _scheme: str | None = None, + _external: bool | None = None, + **values: t.Any, +) -> str: + """Generate a URL to the given endpoint with the given values. + + This requires an active request or application context, and calls + :meth:`current_app.url_for() `. See that method + for full documentation. + + :param endpoint: The endpoint name associated with the URL to + generate. If this starts with a ``.``, the current blueprint + name (if any) will be used. + :param _anchor: If given, append this as ``#anchor`` to the URL. + :param _method: If given, generate the URL associated with this + method for the endpoint. + :param _scheme: If given, the URL will have this scheme if it is + external. + :param _external: If given, prefer the URL to be internal (False) or + require it to be external (True). External URLs include the + scheme and domain. When not in an active request, URLs are + external by default. + :param values: Values to use for the variable parts of the URL rule. + Unknown keys are appended as query string arguments, like + ``?a=b&c=d``. + + .. versionchanged:: 2.2 + Calls ``current_app.url_for``, allowing an app to override the + behavior. + + .. versionchanged:: 0.10 + The ``_scheme`` parameter was added. + + .. versionchanged:: 0.9 + The ``_anchor`` and ``_method`` parameters were added. + + .. versionchanged:: 0.9 + Calls ``app.handle_url_build_error`` on build errors. + """ + return current_app.url_for( + endpoint, + _anchor=_anchor, + _method=_method, + _scheme=_scheme, + _external=_external, + **values, + ) + + +def redirect( + location: str, code: int = 302, Response: type[BaseResponse] | None = None +) -> BaseResponse: + """Create a redirect response object. + + If :data:`~flask.current_app` is available, it will use its + :meth:`~flask.Flask.redirect` method, otherwise it will use + :func:`werkzeug.utils.redirect`. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + :param Response: The response class to use. Not used when + ``current_app`` is active, which uses ``app.response_class``. + + .. versionadded:: 2.2 + Calls ``current_app.redirect`` if available instead of always + using Werkzeug's default ``redirect``. + """ + if current_app: + return current_app.redirect(location, code=code) + + return _wz_redirect(location, code=code, Response=Response) + + +def abort(code: int | BaseResponse, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + """Raise an :exc:`~werkzeug.exceptions.HTTPException` for the given + status code. + + If :data:`~flask.current_app` is available, it will call its + :attr:`~flask.Flask.aborter` object, otherwise it will use + :func:`werkzeug.exceptions.abort`. + + :param code: The status code for the exception, which must be + registered in ``app.aborter``. + :param args: Passed to the exception. + :param kwargs: Passed to the exception. + + .. versionadded:: 2.2 + Calls ``current_app.aborter`` if available instead of always + using Werkzeug's default ``abort``. + """ + if current_app: + current_app.aborter(code, *args, **kwargs) + + _wz_abort(code, *args, **kwargs) + + +def get_template_attribute(template_name: str, attribute: str) -> t.Any: + """Loads a macro (or variable) a template exports. This can be used to + invoke a macro from within Python code. If you for example have a + template named :file:`_cider.html` with the following contents: + + .. sourcecode:: html+jinja + + {% macro hello(name) %}Hello {{ name }}!{% endmacro %} + + You can access this from Python code like this:: + + hello = get_template_attribute('_cider.html', 'hello') + return hello('World') + + .. versionadded:: 0.2 + + :param template_name: the name of the template + :param attribute: the name of the variable of macro to access + """ + return getattr(current_app.jinja_env.get_template(template_name).module, attribute) + + +def flash(message: str, category: str = "message") -> None: + """Flashes a message to the next request. In order to remove the + flashed message from the session and to display it to the user, + the template has to call :func:`get_flashed_messages`. + + .. versionchanged:: 0.3 + `category` parameter added. + + :param message: the message to be flashed. + :param category: the category for the message. The following values + are recommended: ``'message'`` for any kind of message, + ``'error'`` for errors, ``'info'`` for information + messages and ``'warning'`` for warnings. However any + kind of string can be used as category. + """ + # Original implementation: + # + # session.setdefault('_flashes', []).append((category, message)) + # + # This assumed that changes made to mutable structures in the session are + # always in sync with the session object, which is not true for session + # implementations that use external storage for keeping their keys/values. + flashes = session.get("_flashes", []) + flashes.append((category, message)) + session["_flashes"] = flashes + app = current_app._get_current_object() # type: ignore + message_flashed.send( + app, + _async_wrapper=app.ensure_sync, + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> list[str] | list[tuple[str, str]]: + """Pulls all flashed messages from the session and returns them. + Further calls in the same request to the function will return + the same messages. By default just the messages are returned, + but when `with_categories` is set to ``True``, the return value will + be a list of tuples in the form ``(category, message)`` instead. + + Filter the flashed messages to one or more categories by providing those + categories in `category_filter`. This allows rendering categories in + separate html blocks. The `with_categories` and `category_filter` + arguments are distinct: + + * `with_categories` controls whether categories are returned with message + text (``True`` gives a tuple, where ``False`` gives just the message text). + * `category_filter` filters the messages down to only those matching the + provided categories. + + See :doc:`/patterns/flashing` for examples. + + .. versionchanged:: 0.3 + `with_categories` parameter added. + + .. versionchanged:: 0.9 + `category_filter` parameter added. + + :param with_categories: set to ``True`` to also receive categories. + :param category_filter: filter of categories to limit return values. Only + categories in the list will be returned. + """ + flashes = request_ctx.flashes + if flashes is None: + flashes = session.pop("_flashes") if "_flashes" in session else [] + request_ctx.flashes = flashes + if category_filter: + flashes = list(filter(lambda f: f[0] in category_filter, flashes)) + if not with_categories: + return [x[1] for x in flashes] + return flashes + + +def _prepare_send_file_kwargs(**kwargs: t.Any) -> dict[str, t.Any]: + if kwargs.get("max_age") is None: + kwargs["max_age"] = current_app.get_send_file_max_age + + kwargs.update( + environ=request.environ, + use_x_sendfile=current_app.config["USE_X_SENDFILE"], + response_class=current_app.response_class, + _root_path=current_app.root_path, # type: ignore + ) + return kwargs + + +def send_file( + path_or_file: os.PathLike[t.AnyStr] | str | t.BinaryIO, + mimetype: str | None = None, + as_attachment: bool = False, + download_name: str | None = None, + conditional: bool = True, + etag: bool | str = True, + last_modified: datetime | int | float | None = None, + max_age: None | (int | t.Callable[[str | None], int | None]) = None, +) -> Response: + """Send the contents of a file to the client. + + The first argument can be a file path or a file-like object. Paths + are preferred in most cases because Werkzeug can manage the file and + get extra information from the path. Passing a file-like object + requires that the file is opened in binary mode, and is mostly + useful when building a file in memory with :class:`io.BytesIO`. + + Never pass file paths provided by a user. The path is assumed to be + trusted, so a user could craft a path to access a file you didn't + intend. Use :func:`send_from_directory` to safely serve + user-requested paths from within a directory. + + If the WSGI server sets a ``file_wrapper`` in ``environ``, it is + used, otherwise Werkzeug's built-in wrapper is used. Alternatively, + if the HTTP server supports ``X-Sendfile``, configuring Flask with + ``USE_X_SENDFILE = True`` will tell the server to send the given + path, which is much more efficient than reading it in Python. + + :param path_or_file: The path to the file to send, relative to the + current working directory if a relative path is given. + Alternatively, a file-like object opened in binary mode. Make + sure the file pointer is seeked to the start of the data. + :param mimetype: The MIME type to send for the file. If not + provided, it will try to detect it from the file name. + :param as_attachment: Indicate to a browser that it should offer to + save the file instead of displaying it. + :param download_name: The default name browsers will use when saving + the file. Defaults to the passed file name. + :param conditional: Enable conditional and range responses based on + request headers. Requires passing a file path and ``environ``. + :param etag: Calculate an ETag for the file, which requires passing + a file path. Can also be a string to use instead. + :param last_modified: The last modified time to send for the file, + in seconds. If not provided, it will try to detect it from the + file path. + :param max_age: How long the client should cache the file, in + seconds. If set, ``Cache-Control`` will be ``public``, otherwise + it will be ``no-cache`` to prefer conditional caching. + + .. versionchanged:: 2.0 + ``download_name`` replaces the ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces the ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces the ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + Passing a file-like object that inherits from + :class:`~io.TextIOBase` will raise a :exc:`ValueError` rather + than sending an empty file. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionchanged:: 1.1 + ``filename`` may be a :class:`~os.PathLike` object. + + .. versionchanged:: 1.1 + Passing a :class:`~io.BytesIO` object supports range requests. + + .. versionchanged:: 1.0.3 + Filenames are encoded with ASCII instead of Latin-1 for broader + compatibility with WSGI servers. + + .. versionchanged:: 1.0 + UTF-8 filenames as specified in :rfc:`2231` are supported. + + .. versionchanged:: 0.12 + The filename is no longer automatically inferred from file + objects. If you want to use automatic MIME and etag support, + pass a filename via ``filename_or_fp`` or + ``attachment_filename``. + + .. versionchanged:: 0.12 + ``attachment_filename`` is preferred over ``filename`` for MIME + detection. + + .. versionchanged:: 0.9 + ``cache_timeout`` defaults to + :meth:`Flask.get_send_file_max_age`. + + .. versionchanged:: 0.7 + MIME guessing and etag support for file-like objects was + removed because it was unreliable. Pass a filename if you are + able to, otherwise attach an etag yourself. + + .. versionchanged:: 0.5 + The ``add_etags``, ``cache_timeout`` and ``conditional`` + parameters were added. The default behavior is to add etags. + + .. versionadded:: 0.2 + """ + return werkzeug.utils.send_file( # type: ignore[return-value] + **_prepare_send_file_kwargs( + path_or_file=path_or_file, + environ=request.environ, + mimetype=mimetype, + as_attachment=as_attachment, + download_name=download_name, + conditional=conditional, + etag=etag, + last_modified=last_modified, + max_age=max_age, + ) + ) + + +def send_from_directory( + directory: os.PathLike[str] | str, + path: os.PathLike[str] | str, + **kwargs: t.Any, +) -> Response: + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. This *must not* + be a value provided by the client, otherwise it becomes insecure. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + try: + spec = importlib.util.find_spec(import_name) + + if spec is None: + raise ValueError + except (ImportError, ValueError): + loader = None + else: + loader = spec.loader + + # Loader does not exist or we're referring to an unloaded main + # module or a main module without path (interactive sessions), go + # with the current working directory. + if loader is None: + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) # pyright: ignore + else: + # Fall back to imports. + __import__(import_name) + mod = sys.modules[import_name] + filepath = getattr(mod, "__file__", None) + + # If we don't have a file path it might be because it is a + # namespace package. In this case pick the root path from the + # first module that is contained in the package. + if filepath is None: + raise RuntimeError( + "No root path can be found for the provided module" + f" {import_name!r}. This can happen because the module" + " came from an import hook that does not provide file" + " name information or because it's a namespace package." + " In this case the root path needs to be explicitly" + " provided." + ) + + # filepath is import_name.py for a module, or __init__.py for a package. + return os.path.dirname(os.path.abspath(filepath)) # type: ignore[no-any-return] + + +@cache +def _split_blueprint_path(name: str) -> list[str]: + out: list[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/venv/lib/python3.12/site-packages/flask/json/__init__.py b/venv/lib/python3.12/site-packages/flask/json/__init__.py new file mode 100644 index 00000000..c0941d04 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/__init__.py @@ -0,0 +1,170 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..wrappers import Response + + +def dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dumps() ` + method, otherwise it will use :func:`json.dumps`. + + :param obj: The data to serialize. + :param kwargs: Arguments passed to the ``dumps`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump(obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.dump() ` + method, otherwise it will use :func:`json.dump`. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: Arguments passed to the ``dump`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if current_app: + current_app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.loads() ` + method, otherwise it will use :func:`json.loads`. + + :param s: Text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``loads`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.loads``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The data must be a + string or UTF-8 bytes. + + .. versionchanged:: 1.0.3 + ``app`` can be passed directly, rather than requiring an app + context for configuration. + """ + if current_app: + return current_app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + If :data:`~flask.current_app` is available, it will use its + :meth:`app.json.load() ` + method, otherwise it will use :func:`json.load`. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: Arguments passed to the ``load`` implementation. + + .. versionchanged:: 2.3 + The ``app`` parameter was removed. + + .. versionchanged:: 2.2 + Calls ``current_app.json.load``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + ``encoding`` will be removed in Flask 2.1. The file must be text + mode, or binary mode with UTF-8 bytes. + """ + if current_app: + return current_app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def jsonify(*args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. A dict or list returned from a view will be converted to a + JSON response automatically without needing to call this. + + This requires an active request or application context, and calls + :meth:`app.json.response() `. + + In debug mode, the output is formatted with indentation to make it + easier to read. This may also be controlled by the provider. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + + .. versionchanged:: 2.2 + Calls ``current_app.json.response``, allowing an app to override + the behavior. + + .. versionchanged:: 2.0.2 + :class:`decimal.Decimal` is supported by converting to a string. + + .. versionchanged:: 0.11 + Added support for serializing top-level arrays. This was a + security risk in ancient browsers. See :ref:`security-json`. + + .. versionadded:: 0.2 + """ + return current_app.json.response(*args, **kwargs) # type: ignore[return-value] diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..38322b285149c44afa3f23fee4e22a639515babe GIT binary patch literal 6677 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 CuP-M6 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/json/__pycache__/tag.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..17fbe5a8b598b92fb8f2b4ef733d77ac70a92977 GIT binary patch literal 13939 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 to an instance of the class. + + :param app: An application instance. This will be stored as a + :class:`weakref.proxy` on the :attr:`_app` attribute. + + .. versionadded:: 2.2 + """ + + def __init__(self, app: App) -> None: + self._app: App = weakref.proxy(app) + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON. + + :param obj: The data to serialize. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def dump(self, obj: t.Any, fp: t.IO[str], **kwargs: t.Any) -> None: + """Serialize data as JSON and write to a file. + + :param obj: The data to serialize. + :param fp: A file opened for writing text. Should use the UTF-8 + encoding to be valid JSON. + :param kwargs: May be passed to the underlying JSON library. + """ + fp.write(self.dumps(obj, **kwargs)) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON. + + :param s: Text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + raise NotImplementedError + + def load(self, fp: t.IO[t.AnyStr], **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON read from a file. + + :param fp: A file opened for reading text or UTF-8 bytes. + :param kwargs: May be passed to the underlying JSON library. + """ + return self.loads(fp.read(), **kwargs) + + def _prepare_response_obj( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> t.Any: + if args and kwargs: + raise TypeError("app.json.response() takes either args or kwargs, not both") + + if not args and not kwargs: + return None + + if len(args) == 1: + return args[0] + + return args or kwargs + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with the ``application/json`` + mimetype. + + The :func:`~flask.json.jsonify` function calls this method for + the current application. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + return self._app.response_class(self.dumps(obj), mimetype="application/json") + + +def _default(o: t.Any) -> t.Any: + if isinstance(o, date): + return http_date(o) + + if isinstance(o, (decimal.Decimal, uuid.UUID)): + return str(o) + + if dataclasses and dataclasses.is_dataclass(o): + return dataclasses.asdict(o) # type: ignore[arg-type] + + if hasattr(o, "__html__"): + return str(o.__html__()) + + raise TypeError(f"Object of type {type(o).__name__} is not JSON serializable") + + +class DefaultJSONProvider(JSONProvider): + """Provide JSON operations using Python's built-in :mod:`json` + library. Serializes the following additional data types: + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`uuid.UUID` is serialized to a string. + - :class:`dataclasses.dataclass` is passed to + :func:`dataclasses.asdict`. + - :class:`~markupsafe.Markup` (or any object with a ``__html__`` + method) will call the ``__html__`` method to get a string. + """ + + default: t.Callable[[t.Any], t.Any] = staticmethod(_default) # type: ignore[assignment] + """Apply this function to any object that :meth:`json.dumps` does + not know how to serialize. It should return a valid JSON type or + raise a ``TypeError``. + """ + + ensure_ascii = True + """Replace non-ASCII characters with escape sequences. This may be + more compatible with some clients, but can be disabled for better + performance and size. + """ + + sort_keys = True + """Sort the keys in any serialized dicts. This may be useful for + some caching situations, but can be disabled for better performance. + When enabled, keys must all be strings, they are not converted + before sorting. + """ + + compact: bool | None = None + """If ``True``, or ``None`` out of debug mode, the :meth:`response` + output will not add indentation, newlines, or spaces. If ``False``, + or ``None`` in debug mode, it will use a non-compact representation. + """ + + mimetype = "application/json" + """The mimetype set in :meth:`response`.""" + + def dumps(self, obj: t.Any, **kwargs: t.Any) -> str: + """Serialize data as JSON to a string. + + Keyword arguments are passed to :func:`json.dumps`. Sets some + parameter defaults from the :attr:`default`, + :attr:`ensure_ascii`, and :attr:`sort_keys` attributes. + + :param obj: The data to serialize. + :param kwargs: Passed to :func:`json.dumps`. + """ + kwargs.setdefault("default", self.default) + kwargs.setdefault("ensure_ascii", self.ensure_ascii) + kwargs.setdefault("sort_keys", self.sort_keys) + return json.dumps(obj, **kwargs) + + def loads(self, s: str | bytes, **kwargs: t.Any) -> t.Any: + """Deserialize data as JSON from a string or bytes. + + :param s: Text or UTF-8 bytes. + :param kwargs: Passed to :func:`json.loads`. + """ + return json.loads(s, **kwargs) + + def response(self, *args: t.Any, **kwargs: t.Any) -> Response: + """Serialize the given arguments as JSON, and return a + :class:`~flask.Response` object with it. The response mimetype + will be "application/json" and can be changed with + :attr:`mimetype`. + + If :attr:`compact` is ``False`` or debug mode is enabled, the + output will be formatted to be easier to read. + + Either positional or keyword arguments can be given, not both. + If no arguments are given, ``None`` is serialized. + + :param args: A single value to serialize, or multiple values to + treat as a list to serialize. + :param kwargs: Treat as a dict to serialize. + """ + obj = self._prepare_response_obj(args, kwargs) + dump_args: dict[str, t.Any] = {} + + if (self.compact is None and self._app.debug) or self.compact is False: + dump_args.setdefault("indent", 2) + else: + dump_args.setdefault("separators", (",", ":")) + + return self._app.response_class( + f"{self.dumps(obj, **dump_args)}\n", mimetype=self.mimetype + ) diff --git a/venv/lib/python3.12/site-packages/flask/json/tag.py b/venv/lib/python3.12/site-packages/flask/json/tag.py new file mode 100644 index 00000000..8dc3629b --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/json/tag.py @@ -0,0 +1,327 @@ +""" +Tagged JSON +~~~~~~~~~~~ + +A compact representation for lossless serialization of non-standard JSON +types. :class:`~flask.sessions.SecureCookieSessionInterface` uses this +to serialize the session data, but it may be useful in other places. It +can be extended to support other types. + +.. autoclass:: TaggedJSONSerializer + :members: + +.. autoclass:: JSONTag + :members: + +Let's see an example that adds support for +:class:`~collections.OrderedDict`. Dicts don't have an order in JSON, so +to handle this we will dump the items as a list of ``[key, value]`` +pairs. Subclass :class:`JSONTag` and give it the new key ``' od'`` to +identify the type. The session serializer processes dicts first, so +insert the new tag at the front of the order since ``OrderedDict`` must +be processed before ``dict``. + +.. code-block:: python + + from flask.json.tag import JSONTag + + class TagOrderedDict(JSONTag): + __slots__ = ('serializer',) + key = ' od' + + def check(self, value): + return isinstance(value, OrderedDict) + + def to_json(self, value): + return [[k, self.serializer.tag(v)] for k, v in iteritems(value)] + + def to_python(self, value): + return OrderedDict(value) + + app.session_interface.serializer.register(TagOrderedDict, index=0) +""" + +from __future__ import annotations + +import typing as t +from base64 import b64decode +from base64 import b64encode +from datetime import datetime +from uuid import UUID + +from markupsafe import Markup +from werkzeug.http import http_date +from werkzeug.http import parse_date + +from ..json import dumps +from ..json import loads + + +class JSONTag: + """Base class for defining type tags for :class:`TaggedJSONSerializer`.""" + + __slots__ = ("serializer",) + + #: The tag to mark the serialized object with. If empty, this tag is + #: only used as an intermediate step during tagging. + key: str = "" + + def __init__(self, serializer: TaggedJSONSerializer) -> None: + """Create a tagger for the given serializer.""" + self.serializer = serializer + + def check(self, value: t.Any) -> bool: + """Check if the given value should be tagged by this tag.""" + raise NotImplementedError + + def to_json(self, value: t.Any) -> t.Any: + """Convert the Python object to an object that is a valid JSON type. + The tag will be added later.""" + raise NotImplementedError + + def to_python(self, value: t.Any) -> t.Any: + """Convert the JSON representation back to the correct type. The tag + will already be removed.""" + raise NotImplementedError + + def tag(self, value: t.Any) -> dict[str, t.Any]: + """Convert the value to a valid JSON type and add the tag structure + around it.""" + return {self.key: self.to_json(value)} + + +class TagDict(JSONTag): + """Tag for 1-item dicts whose only key matches a registered tag. + + Internally, the dict key is suffixed with `__`, and the suffix is removed + when deserializing. + """ + + __slots__ = () + key = " di" + + def check(self, value: t.Any) -> bool: + return ( + isinstance(value, dict) + and len(value) == 1 + and next(iter(value)) in self.serializer.tags + ) + + def to_json(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {f"{key}__": self.serializer.tag(value[key])} + + def to_python(self, value: t.Any) -> t.Any: + key = next(iter(value)) + return {key[:-2]: value[key]} + + +class PassDict(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, dict) + + def to_json(self, value: t.Any) -> t.Any: + # JSON objects may only have string keys, so don't bother tagging the + # key here. + return {k: self.serializer.tag(v) for k, v in value.items()} + + tag = to_json + + +class TagTuple(JSONTag): + __slots__ = () + key = " t" + + def check(self, value: t.Any) -> bool: + return isinstance(value, tuple) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + def to_python(self, value: t.Any) -> t.Any: + return tuple(value) + + +class PassList(JSONTag): + __slots__ = () + + def check(self, value: t.Any) -> bool: + return isinstance(value, list) + + def to_json(self, value: t.Any) -> t.Any: + return [self.serializer.tag(item) for item in value] + + tag = to_json + + +class TagBytes(JSONTag): + __slots__ = () + key = " b" + + def check(self, value: t.Any) -> bool: + return isinstance(value, bytes) + + def to_json(self, value: t.Any) -> t.Any: + return b64encode(value).decode("ascii") + + def to_python(self, value: t.Any) -> t.Any: + return b64decode(value) + + +class TagMarkup(JSONTag): + """Serialize anything matching the :class:`~markupsafe.Markup` API by + having a ``__html__`` method to the result of that method. Always + deserializes to an instance of :class:`~markupsafe.Markup`.""" + + __slots__ = () + key = " m" + + def check(self, value: t.Any) -> bool: + return callable(getattr(value, "__html__", None)) + + def to_json(self, value: t.Any) -> t.Any: + return str(value.__html__()) + + def to_python(self, value: t.Any) -> t.Any: + return Markup(value) + + +class TagUUID(JSONTag): + __slots__ = () + key = " u" + + def check(self, value: t.Any) -> bool: + return isinstance(value, UUID) + + def to_json(self, value: t.Any) -> t.Any: + return value.hex + + def to_python(self, value: t.Any) -> t.Any: + return UUID(value) + + +class TagDateTime(JSONTag): + __slots__ = () + key = " d" + + def check(self, value: t.Any) -> bool: + return isinstance(value, datetime) + + def to_json(self, value: t.Any) -> t.Any: + return http_date(value) + + def to_python(self, value: t.Any) -> t.Any: + return parse_date(value) + + +class TaggedJSONSerializer: + """Serializer that uses a tag system to compactly represent objects that + are not JSON types. Passed as the intermediate serializer to + :class:`itsdangerous.Serializer`. + + The following extra types are supported: + + * :class:`dict` + * :class:`tuple` + * :class:`bytes` + * :class:`~markupsafe.Markup` + * :class:`~uuid.UUID` + * :class:`~datetime.datetime` + """ + + __slots__ = ("tags", "order") + + #: Tag classes to bind when creating the serializer. Other tags can be + #: added later using :meth:`~register`. + default_tags = [ + TagDict, + PassDict, + TagTuple, + PassList, + TagBytes, + TagMarkup, + TagUUID, + TagDateTime, + ] + + def __init__(self) -> None: + self.tags: dict[str, JSONTag] = {} + self.order: list[JSONTag] = [] + + for cls in self.default_tags: + self.register(cls) + + def register( + self, + tag_class: type[JSONTag], + force: bool = False, + index: int | None = None, + ) -> None: + """Register a new tag with this serializer. + + :param tag_class: tag class to register. Will be instantiated with this + serializer instance. + :param force: overwrite an existing tag. If false (default), a + :exc:`KeyError` is raised. + :param index: index to insert the new tag in the tag order. Useful when + the new tag is a special case of an existing tag. If ``None`` + (default), the tag is appended to the end of the order. + + :raise KeyError: if the tag key is already registered and ``force`` is + not true. + """ + tag = tag_class(self) + key = tag.key + + if key: + if not force and key in self.tags: + raise KeyError(f"Tag '{key}' is already registered.") + + self.tags[key] = tag + + if index is None: + self.order.append(tag) + else: + self.order.insert(index, tag) + + def tag(self, value: t.Any) -> t.Any: + """Convert a value to a tagged representation if necessary.""" + for tag in self.order: + if tag.check(value): + return tag.tag(value) + + return value + + def untag(self, value: dict[str, t.Any]) -> t.Any: + """Convert a tagged representation back to the original type.""" + if len(value) != 1: + return value + + key = next(iter(value)) + + if key not in self.tags: + return value + + return self.tags[key].to_python(value[key]) + + def _untag_scan(self, value: t.Any) -> t.Any: + if isinstance(value, dict): + # untag each item recursively + value = {k: self._untag_scan(v) for k, v in value.items()} + # untag the dict itself + value = self.untag(value) + elif isinstance(value, list): + # untag each item recursively + value = [self._untag_scan(item) for item in value] + + return value + + def dumps(self, value: t.Any) -> str: + """Tag the value and dump it to a compact JSON string.""" + return dumps(self.tag(value), separators=(",", ":")) + + def loads(self, value: str) -> t.Any: + """Load data from a JSON string and deserialized any tagged objects.""" + return self._untag_scan(loads(value)) diff --git a/venv/lib/python3.12/site-packages/flask/logging.py b/venv/lib/python3.12/site-packages/flask/logging.py new file mode 100644 index 00000000..0cb8f437 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/logging.py @@ -0,0 +1,79 @@ +from __future__ import annotations + +import logging +import sys +import typing as t + +from werkzeug.local import LocalProxy + +from .globals import request + +if t.TYPE_CHECKING: # pragma: no cover + from .sansio.app import App + + +@LocalProxy +def wsgi_errors_stream() -> t.TextIO: + """Find the most appropriate error stream for the application. If a request + is active, log to ``wsgi.errors``, otherwise use ``sys.stderr``. + + If you configure your own :class:`logging.StreamHandler`, you may want to + use this for the stream. If you are using file or dict configuration and + can't import this directly, you can refer to it as + ``ext://flask.logging.wsgi_errors_stream``. + """ + if request: + return request.environ["wsgi.errors"] # type: ignore[no-any-return] + + return sys.stderr + + +def has_level_handler(logger: logging.Logger) -> bool: + """Check if there is a handler in the logging chain that will handle the + given logger's :meth:`effective level <~logging.Logger.getEffectiveLevel>`. + """ + level = logger.getEffectiveLevel() + current = logger + + while current: + if any(handler.level <= level for handler in current.handlers): + return True + + if not current.propagate: + break + + current = current.parent # type: ignore + + return False + + +#: Log messages to :func:`~flask.logging.wsgi_errors_stream` with the format +#: ``[%(asctime)s] %(levelname)s in %(module)s: %(message)s``. +default_handler = logging.StreamHandler(wsgi_errors_stream) # type: ignore +default_handler.setFormatter( + logging.Formatter("[%(asctime)s] %(levelname)s in %(module)s: %(message)s") +) + + +def create_logger(app: App) -> logging.Logger: + """Get the Flask app's logger and configure it if needed. + + The logger name will be the same as + :attr:`app.import_name `. + + When :attr:`~flask.Flask.debug` is enabled, set the logger level to + :data:`logging.DEBUG` if it is not set. + + If there is no handler for the logger's effective level, add a + :class:`~logging.StreamHandler` for + :func:`~flask.logging.wsgi_errors_stream` with a basic format. + """ + logger = logging.getLogger(app.name) + + if app.debug and not logger.level: + logger.setLevel(logging.DEBUG) + + if not has_level_handler(logger): + logger.addHandler(default_handler) + + return logger diff --git a/venv/lib/python3.12/site-packages/flask/py.typed b/venv/lib/python3.12/site-packages/flask/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/flask/sansio/README.md b/venv/lib/python3.12/site-packages/flask/sansio/README.md new file mode 100644 index 00000000..623ac198 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/README.md @@ -0,0 +1,6 @@ +# Sansio + +This folder contains code that can be used by alternative Flask +implementations, for example Quart. The code therefore cannot do any +IO, nor be part of a likely IO path. Finally this code cannot use the +Flask globals. diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..662caa374d23e37fd85dfa0c0a8228a43b44a71e GIT binary patch literal 33697 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc b/venv/lib/python3.12/site-packages/flask/sansio/__pycache__/blueprints.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00db9c5ce3219c70c9bbd1ebce573d1229f335fc GIT binary patch literal 31197 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 LYm;j|Gok%oh!>dk 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 00000000..36201714 --- /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, + ) -> None: + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if instance_path is None: + instance_path = self.auto_find_instance_path() + elif not os.path.isabs(instance_path): + raise ValueError( + "If an instance path is provided it must be absolute." + " A relative path was given instead." + ) + + #: Holds the path to the instance folder. + #: + #: .. versionadded:: 0.8 + self.instance_path = instance_path + + #: The configuration dictionary as :class:`Config`. This behaves + #: exactly like a regular dictionary but supports additional methods + #: to load a config from files. + self.config = self.make_config(instance_relative_config) + + #: An instance of :attr:`aborter_class` created by + #: :meth:`make_aborter`. This is called by :func:`flask.abort` + #: to raise HTTP errors, and can be called directly as well. + #: + #: .. versionadded:: 2.2 + #: Moved from ``flask.abort``, which calls this object. + self.aborter = self.make_aborter() + + self.json: JSONProvider = self.json_provider_class(self) + """Provides access to JSON methods. Functions in ``flask.json`` + will call methods on this provider when the application context + is active. Used for handling JSON requests and responses. + + An instance of :attr:`json_provider_class`. Can be customized by + changing that attribute on a subclass, or by assigning to this + attribute afterwards. + + The default, :class:`~flask.json.provider.DefaultJSONProvider`, + uses Python's built-in :mod:`json` library. A different provider + can use a different JSON library. + + .. versionadded:: 2.2 + """ + + #: A list of functions that are called by + #: :meth:`handle_url_build_error` when :meth:`.url_for` raises a + #: :exc:`~werkzeug.routing.BuildError`. Each function is called + #: with ``error``, ``endpoint`` and ``values``. If a function + #: returns ``None`` or raises a ``BuildError``, it is skipped. + #: Otherwise, its return value is returned by ``url_for``. + #: + #: .. versionadded:: 0.9 + self.url_build_error_handlers: list[ + t.Callable[[Exception, str, dict[str, t.Any]], str] + ] = [] + + #: A list of functions that are called when the application context + #: is destroyed. Since the application context is also torn down + #: if the request ends this is the place to store code that disconnects + #: from databases. + #: + #: .. versionadded:: 0.9 + self.teardown_appcontext_funcs: list[ft.TeardownCallable] = [] + + #: A list of shell context processor functions that should be run + #: when a shell context is created. + #: + #: .. versionadded:: 0.11 + self.shell_context_processors: list[ft.ShellContextProcessorCallable] = [] + + #: Maps registered blueprint names to blueprint objects. The + #: dict retains the order the blueprints were registered in. + #: Blueprints can be registered multiple times, this dict does + #: not track how often they were attached. + #: + #: .. versionadded:: 0.7 + self.blueprints: dict[str, Blueprint] = {} + + #: a place where extensions can store application specific state. For + #: example this is where an extension could store database engines and + #: similar things. + #: + #: The key must match the name of the extension module. For example in + #: case of a "Flask-Foo" extension in `flask_foo`, the key would be + #: ``'foo'``. + #: + #: .. versionadded:: 0.7 + self.extensions: dict[str, t.Any] = {} + + #: The :class:`~werkzeug.routing.Map` for this instance. You can use + #: this to change the routing converters after the class was created + #: but before any routes are connected. Example:: + #: + #: from werkzeug.routing import BaseConverter + #: + #: class ListConverter(BaseConverter): + #: def to_python(self, value): + #: return value.split(',') + #: def to_url(self, values): + #: return ','.join(super(ListConverter, self).to_url(value) + #: for value in values) + #: + #: app = Flask(__name__) + #: app.url_map.converters['list'] = ListConverter + self.url_map = self.url_map_class(host_matching=host_matching) + + self.subdomain_matching = subdomain_matching + + # tracks internally if the application already handled at least one + # request. + self._got_first_request = False + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_first_request: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called" + " on the application. It has already handled its first" + " request, any changes will not be applied" + " consistently.\n" + "Make sure all imports, decorators, functions, etc." + " needed to set up the application are done before" + " running it." + ) + + @cached_property + def name(self) -> str: # type: ignore + """The name of the application. This is usually the import name + with the difference that it's guessed from the run file if the + import name is main. This name is used as a display name when + Flask needs the name of the application. It can be set and overridden + to change the value. + + .. versionadded:: 0.8 + """ + if self.import_name == "__main__": + fn: str | None = getattr(sys.modules["__main__"], "__file__", None) + if fn is None: + return "__main__" + return os.path.splitext(os.path.basename(fn))[0] + return self.import_name + + @cached_property + def logger(self) -> logging.Logger: + """A standard Python :class:`~logging.Logger` for the app, with + the same name as :attr:`name`. + + In debug mode, the logger's :attr:`~logging.Logger.level` will + be set to :data:`~logging.DEBUG`. + + If there are no handlers configured, a default handler will be + added. See :doc:`/logging` for more information. + + .. versionchanged:: 1.1.0 + The logger takes the same name as :attr:`name` rather than + hard-coding ``"flask.app"``. + + .. versionchanged:: 1.0.0 + Behavior was simplified. The logger is always named + ``"flask.app"``. The level is only set during configuration, + it doesn't check ``app.debug`` each time. Only one format is + used, not different ones depending on ``app.debug``. No + handlers are removed, and a handler is only added if no + handlers are already configured. + + .. versionadded:: 0.3 + """ + return create_logger(self) + + @cached_property + def jinja_env(self) -> Environment: + """The Jinja environment used to load templates. + + The environment is created the first time this property is + accessed. Changing :attr:`jinja_options` after that will have no + effect. + """ + return self.create_jinja_environment() + + def create_jinja_environment(self) -> Environment: + raise NotImplementedError() + + def make_config(self, instance_relative: bool = False) -> Config: + """Used to create the config attribute by the Flask constructor. + The `instance_relative` parameter is passed in from the constructor + of Flask (there named `instance_relative_config`) and indicates if + the config should be relative to the instance path or the root path + of the application. + + .. versionadded:: 0.8 + """ + root_path = self.root_path + if instance_relative: + root_path = self.instance_path + defaults = dict(self.default_config) + defaults["DEBUG"] = get_debug_flag() + return self.config_class(root_path, defaults) + + def make_aborter(self) -> Aborter: + """Create the object to assign to :attr:`aborter`. That object + is called by :func:`flask.abort` to raise HTTP errors, and can + be called directly as well. + + By default, this creates an instance of :attr:`aborter_class`, + which defaults to :class:`werkzeug.exceptions.Aborter`. + + .. versionadded:: 2.2 + """ + return self.aborter_class() + + def auto_find_instance_path(self) -> str: + """Tries to locate the instance path if it was not provided to the + constructor of the application class. It will basically calculate + the path to a folder named ``instance`` next to your main file or + the package. + + .. versionadded:: 0.8 + """ + prefix, package_path = find_package(self.import_name) + if prefix is None: + return os.path.join(package_path, "instance") + return os.path.join(prefix, "var", f"{self.name}-instance") + + def create_global_jinja_loader(self) -> DispatchingJinjaLoader: + """Creates the loader for the Jinja2 environment. Can be used to + override just the loader and keeping the rest unchanged. It's + discouraged to override this function. Instead one should override + the :meth:`jinja_loader` function instead. + + The global loader dispatches between the loaders of the application + and the individual blueprints. + + .. versionadded:: 0.7 + """ + return DispatchingJinjaLoader(self) + + def select_jinja_autoescape(self, filename: str) -> bool: + """Returns ``True`` if autoescaping should be active for the given + template name. If no template name is given, returns `True`. + + .. versionchanged:: 2.2 + Autoescaping is now enabled by default for ``.svg`` files. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml", ".svg")) + + @property + def debug(self) -> bool: + """Whether debug mode is enabled. When using ``flask run`` to start the + development server, an interactive debugger will be shown for unhandled + exceptions, and the server will be reloaded when code changes. This maps to the + :data:`DEBUG` config key. It may not behave as expected if set late. + + **Do not enable debug mode when deploying in production.** + + Default: ``False`` + """ + return self.config["DEBUG"] # type: ignore[no-any-return] + + @debug.setter + def debug(self, value: bool) -> None: + self.config["DEBUG"] = value + + if self.config["TEMPLATES_AUTO_RELOAD"] is None: + self.jinja_env.auto_reload = value + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on the application. Keyword + arguments passed to this method will override the defaults set on the + blueprint. + + Calls the blueprint's :meth:`~flask.Blueprint.register` method after + recording the blueprint in the application's :attr:`blueprints`. + + :param blueprint: The blueprint to register. + :param url_prefix: Blueprint routes will be prefixed with this. + :param subdomain: Blueprint routes will match on this subdomain. + :param url_defaults: Blueprint routes will use these default values for + view arguments. + :param options: Additional keyword arguments are passed to + :class:`~flask.blueprints.BlueprintSetupState`. They can be + accessed in :meth:`~flask.Blueprint.record` callbacks. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 0.7 + """ + blueprint.register(self, options) + + def iter_blueprints(self) -> t.ValuesView[Blueprint]: + """Iterates over all blueprints by the order they were registered. + + .. versionadded:: 0.11 + """ + return self.blueprints.values() + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods: set[str] = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods and self.config["PROVIDE_AUTOMATIC_OPTIONS"]: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule_obj = self.url_rule_class(rule, methods=methods, **options) + rule_obj.provide_automatic_options = provide_automatic_options # type: ignore[attr-defined] + + self.url_map.add(rule_obj) + if view_func is not None: + old_func = self.view_functions.get(endpoint) + if old_func is not None and old_func != view_func: + raise AssertionError( + "View function mapping is overwriting an existing" + f" endpoint function: {endpoint}" + ) + self.view_functions[endpoint] = view_func + + @setupmethod + def template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """A decorator that is used to register custom template filter. + You can specify a name for the filter, otherwise the function + name will be used. Example:: + + @app.template_filter() + def reverse(s): + return s[::-1] + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a custom template filter. Works exactly like the + :meth:`template_filter` decorator. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + self.jinja_env.filters[name or f.__name__] = f + + @setupmethod + def template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """A decorator that is used to register custom template test. + You can specify a name for the test, otherwise the function + name will be used. Example:: + + @app.template_test() + def is_prime(n): + if n == 2: + return True + for i in range(2, int(math.ceil(math.sqrt(n))) + 1): + if n % i == 0: + return False + return True + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a custom template test. Works exactly like the + :meth:`template_test` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + self.jinja_env.tests[name or f.__name__] = f + + @setupmethod + def template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """A decorator that is used to register a custom template global function. + You can specify a name for the global function, otherwise the function + name will be used. Example:: + + @app.template_global() + def double(n): + return 2 * n + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a custom template global function. Works exactly like the + :meth:`template_global` decorator. + + .. versionadded:: 0.10 + + :param name: the optional name of the global function, otherwise the + function name will be used. + """ + self.jinja_env.globals[name or f.__name__] = f + + @setupmethod + def teardown_appcontext(self, f: T_teardown) -> T_teardown: + """Registers a function to be called when the application + context is popped. The application context is typically popped + after the request context for each request, at the end of CLI + commands, or after a manually pushed context ends. + + .. code-block:: python + + with app.app_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the app context is + made inactive. Since a request context typically also manages an + application context it would also be called when you pop a + request context. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + .. versionadded:: 0.9 + """ + self.teardown_appcontext_funcs.append(f) + return f + + @setupmethod + def shell_context_processor( + self, f: T_shell_context_processor + ) -> T_shell_context_processor: + """Registers a shell context processor function. + + .. versionadded:: 0.11 + """ + self.shell_context_processors.append(f) + return f + + def _find_error_handler( + self, e: Exception, blueprints: list[str] + ) -> ft.ErrorHandlerCallable | None: + """Return a registered error handler for an exception in this order: + blueprint handler for a specific code, app handler for a specific code, + blueprint handler for an exception class, app handler for an exception + class, or ``None`` if a suitable handler is not found. + """ + exc_class, code = self._get_exc_class_and_code(type(e)) + names = (*blueprints, None) + + for c in (code, None) if code is not None else (None,): + for name in names: + handler_map = self.error_handler_spec[name][c] + + if not handler_map: + continue + + for cls in exc_class.__mro__: + handler = handler_map.get(cls) + + if handler is not None: + return handler + return None + + def trap_http_exception(self, e: Exception) -> bool: + """Checks if an HTTP exception should be trapped or not. By default + this will return ``False`` for all exceptions except for a bad request + key error if ``TRAP_BAD_REQUEST_ERRORS`` is set to ``True``. It + also returns ``True`` if ``TRAP_HTTP_EXCEPTIONS`` is set to ``True``. + + This is called for all HTTP exceptions raised by a view function. + If it returns ``True`` for any exception the error handler for this + exception is not called and it shows up as regular exception in the + traceback. This is helpful for debugging implicitly raised HTTP + exceptions. + + .. versionchanged:: 1.0 + Bad request errors are not trapped by default in debug mode. + + .. versionadded:: 0.8 + """ + if self.config["TRAP_HTTP_EXCEPTIONS"]: + return True + + trap_bad_request = self.config["TRAP_BAD_REQUEST_ERRORS"] + + # if unset, trap key errors in debug mode + if ( + trap_bad_request is None + and self.debug + and isinstance(e, BadRequestKeyError) + ): + return True + + if trap_bad_request: + return isinstance(e, BadRequest) + + return False + + def should_ignore_error(self, error: BaseException | None) -> bool: + """This is called to figure out if an error should be ignored + or not as far as the teardown system is concerned. If this + function returns ``True`` then the teardown handlers will not be + passed the error. + + .. versionadded:: 0.10 + """ + return False + + def redirect(self, location: str, code: int = 302) -> BaseResponse: + """Create a redirect response object. + + This is called by :func:`flask.redirect`, and can be called + directly as well. + + :param location: The URL to redirect to. + :param code: The status code for the redirect. + + .. versionadded:: 2.2 + Moved from ``flask.redirect``, which calls this method. + """ + return _wz_redirect( + location, + code=code, + Response=self.response_class, # type: ignore[arg-type] + ) + + def inject_url_defaults(self, endpoint: str, values: dict[str, t.Any]) -> None: + """Injects the URL defaults for the given endpoint directly into + the values dictionary passed. This is used internally and + automatically called on URL building. + + .. versionadded:: 0.7 + """ + names: t.Iterable[str | None] = (None,) + + # url_for may be called outside a request context, parse the + # passed endpoint instead of using request.blueprints. + if "." in endpoint: + names = chain( + names, reversed(_split_blueprint_path(endpoint.rpartition(".")[0])) + ) + + for name in names: + if name in self.url_default_functions: + for func in self.url_default_functions[name]: + func(endpoint, values) + + def handle_url_build_error( + self, error: BuildError, endpoint: str, values: dict[str, t.Any] + ) -> str: + """Called by :meth:`.url_for` if a + :exc:`~werkzeug.routing.BuildError` was raised. If this returns + a value, it will be returned by ``url_for``, otherwise the error + will be re-raised. + + Each function in :attr:`url_build_error_handlers` is called with + ``error``, ``endpoint`` and ``values``. If a function returns + ``None`` or raises a ``BuildError``, it is skipped. Otherwise, + its return value is returned by ``url_for``. + + :param error: The active ``BuildError`` being handled. + :param endpoint: The endpoint being built. + :param values: The keyword arguments passed to ``url_for``. + """ + for handler in self.url_build_error_handlers: + try: + rv = handler(error, endpoint, values) + except BuildError as e: + # make error available outside except block + error = e + else: + if rv is not None: + return rv + + # Re-raise if called with an active exception, otherwise raise + # the passed in exception. + if error is sys.exc_info()[1]: + raise + + raise error diff --git a/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py new file mode 100644 index 00000000..4f912cca --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/blueprints.py @@ -0,0 +1,632 @@ +from __future__ import annotations + +import os +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from .. import typing as ft +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import Scaffold +from .scaffold import setupmethod + +if t.TYPE_CHECKING: # pragma: no cover + from .app import App + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], None] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_template_filter = t.TypeVar("T_template_filter", bound=ft.TemplateFilterCallable) +T_template_global = t.TypeVar("T_template_global", bound=ft.TemplateGlobalCallable) +T_template_test = t.TypeVar("T_template_test", bound=ft.TemplateTestCallable) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) + + +class BlueprintSetupState: + """Temporary holder object for registering a blueprint with the + application. An instance of this class is created by the + :meth:`~flask.Blueprint.make_setup_state` method and later passed + to all register callback functions. + """ + + def __init__( + self, + blueprint: Blueprint, + app: App, + options: t.Any, + first_registration: bool, + ) -> None: + #: a reference to the current application + self.app = app + + #: a reference to the blueprint that created this setup state. + self.blueprint = blueprint + + #: a dictionary with all options that were passed to the + #: :meth:`~flask.Flask.register_blueprint` method. + self.options = options + + #: as blueprints can be registered multiple times with the + #: application and not everything wants to be registered + #: multiple times on it, this attribute can be used to figure + #: out if the blueprint was registered in the past already. + self.first_registration = first_registration + + subdomain = self.options.get("subdomain") + if subdomain is None: + subdomain = self.blueprint.subdomain + + #: The subdomain that the blueprint should be active for, ``None`` + #: otherwise. + self.subdomain = subdomain + + url_prefix = self.options.get("url_prefix") + if url_prefix is None: + url_prefix = self.blueprint.url_prefix + #: The prefix that should be used for all URLs defined on the + #: blueprint. + self.url_prefix = url_prefix + + self.name = self.options.get("name", blueprint.name) + self.name_prefix = self.options.get("name_prefix", "") + + #: A dictionary with URL defaults that is added to each and every + #: URL that was defined with the blueprint. + self.url_defaults = dict(self.blueprint.url_values_defaults) + self.url_defaults.update(self.options.get("url_defaults", ())) + + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + **options: t.Any, + ) -> None: + """A helper method to register a rule (and optionally a view function) + to the application. The endpoint is automatically prefixed with the + blueprint's name. + """ + if self.url_prefix is not None: + if rule: + rule = "/".join((self.url_prefix.rstrip("/"), rule.lstrip("/"))) + else: + rule = self.url_prefix + options.setdefault("subdomain", self.subdomain) + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + defaults = self.url_defaults + if "defaults" in options: + defaults = dict(defaults, **options.pop("defaults")) + + self.app.add_url_rule( + rule, + f"{self.name_prefix}.{self.name}.{endpoint}".lstrip("."), + view_func, + defaults=defaults, + **options, + ) + + +class Blueprint(Scaffold): + """Represents a blueprint, a collection of routes and other + app-related functions that can be registered on a real application + later. + + A blueprint is an object that allows defining application functions + without requiring an application object ahead of time. It uses the + same decorators as :class:`~flask.Flask`, but defers the need for an + application by recording them for later registration. + + Decorating a function with a blueprint creates a deferred function + that is called with :class:`~flask.blueprints.BlueprintSetupState` + when the blueprint is registered on an application. + + See :doc:`/blueprints` for more information. + + :param name: The name of the blueprint. Will be prepended to each + endpoint name. + :param import_name: The name of the blueprint package, usually + ``__name__``. This helps locate the ``root_path`` for the + blueprint. + :param static_folder: A folder with static files that should be + served by the blueprint's static route. The path is relative to + the blueprint's root path. Blueprint static files are disabled + by default. + :param static_url_path: The url to serve static files from. + Defaults to ``static_folder``. If the blueprint does not have + a ``url_prefix``, the app's static route will take precedence, + and the blueprint's static files won't be accessible. + :param template_folder: A folder with templates that should be added + to the app's template search path. The path is relative to the + blueprint's root path. Blueprint templates are disabled by + default. Blueprint templates have a lower precedence than those + in the app's templates folder. + :param url_prefix: A path to prepend to all of the blueprint's URLs, + to make them distinct from the rest of the app's routes. + :param subdomain: A subdomain that blueprint routes will match on by + default. + :param url_defaults: A dict of default values that blueprint routes + will receive by default. + :param root_path: By default, the blueprint will automatically set + this based on ``import_name``. In certain situations this + automatic detection can fail, so the path can be specified + manually instead. + + .. versionchanged:: 1.1.0 + Blueprints have a ``cli`` group to register nested CLI commands. + The ``cli_group`` parameter controls the name of the group under + the ``flask`` command. + + .. versionadded:: 0.7 + """ + + _got_registered_once = False + + def __init__( + self, + name: str, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + url_prefix: str | None = None, + subdomain: str | None = None, + url_defaults: dict[str, t.Any] | None = None, + root_path: str | None = None, + cli_group: str | None = _sentinel, # type: ignore[assignment] + ): + super().__init__( + import_name=import_name, + static_folder=static_folder, + static_url_path=static_url_path, + template_folder=template_folder, + root_path=root_path, + ) + + if not name: + raise ValueError("'name' may not be empty.") + + if "." in name: + raise ValueError("'name' may not contain a dot '.' character.") + + self.name = name + self.url_prefix = url_prefix + self.subdomain = subdomain + self.deferred_functions: list[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: list[tuple[Blueprint, dict[str, t.Any]]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + raise AssertionError( + f"The setup method '{f_name}' can no longer be called on the blueprint" + f" '{self.name}'. It has already been registered at least once, any" + " changes will not be applied consistently.\n" + "Make sure all imports, decorators, functions, etc. needed to set up" + " the blueprint are done before registering it." + ) + + @setupmethod + def record(self, func: DeferredSetupFunction) -> None: + """Registers a function that is called when the blueprint is + registered on the application. This function is called with the + state as argument as returned by the :meth:`make_setup_state` + method. + """ + self.deferred_functions.append(func) + + @setupmethod + def record_once(self, func: DeferredSetupFunction) -> None: + """Works like :meth:`record` but wraps the function in another + function that will ensure the function is only called once. If the + blueprint is registered a second time on the application, the + function passed is not called. + """ + + def wrapper(state: BlueprintSetupState) -> None: + if state.first_registration: + func(state) + + self.record(update_wrapper(wrapper, func)) + + def make_setup_state( + self, app: App, options: dict[str, t.Any], first_registration: bool = False + ) -> BlueprintSetupState: + """Creates an instance of :meth:`~flask.blueprints.BlueprintSetupState` + object that is later passed to the register callback functions. + Subclasses can override this to return a subclass of the setup state. + """ + return BlueprintSetupState(self, app, options, first_registration) + + @setupmethod + def register_blueprint(self, blueprint: Blueprint, **options: t.Any) -> None: + """Register a :class:`~flask.Blueprint` on this blueprint. Keyword + arguments passed to this method will override the defaults set + on the blueprint. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + + .. versionadded:: 2.0 + """ + if blueprint is self: + raise ValueError("Cannot register a blueprint on itself") + self._blueprints.append((blueprint, options)) + + def register(self, app: App, options: dict[str, t.Any]) -> None: + """Called by :meth:`Flask.register_blueprint` to register all + views and callbacks registered on the blueprint with the + application. Creates a :class:`.BlueprintSetupState` and calls + each :meth:`record` callback with it. + + :param app: The application this blueprint is being registered + with. + :param options: Keyword arguments forwarded from + :meth:`~Flask.register_blueprint`. + + .. versionchanged:: 2.3 + Nested blueprints now correctly apply subdomains. + + .. versionchanged:: 2.1 + Registering the same blueprint with the same name multiple + times is an error. + + .. versionchanged:: 2.0.1 + Nested blueprints are registered with their dotted name. + This allows different blueprints with the same name to be + nested at different locations. + + .. versionchanged:: 2.0.1 + The ``name`` option can be used to change the (pre-dotted) + name the blueprint is registered with. This allows the same + blueprint to be registered multiple times with unique names + for ``url_for``. + """ + name_prefix = options.get("name_prefix", "") + self_name = options.get("name", self.name) + name = f"{name_prefix}.{self_name}".lstrip(".") + + if name in app.blueprints: + bp_desc = "this" if app.blueprints[name] is self else "a different" + existing_at = f" '{name}'" if self_name != name else "" + + raise ValueError( + f"The name '{self_name}' is already registered for" + f" {bp_desc} blueprint{existing_at}. Use 'name=' to" + f" provide a unique name." + ) + + first_bp_registration = not any(bp is self for bp in app.blueprints.values()) + first_name_registration = name not in app.blueprints + + app.blueprints[name] = self + self._got_registered_once = True + state = self.make_setup_state(app, options, first_bp_registration) + + if self.has_static_folder: + state.add_url_rule( + f"{self.static_url_path}/", + view_func=self.send_static_file, # type: ignore[attr-defined] + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + self._merge_blueprint_funcs(app, name) + + for deferred in self.deferred_functions: + deferred(state) + + cli_resolved_group = options.get("cli_group", self.cli_group) + + if self.cli.commands: + if cli_resolved_group is None: + app.cli.commands.update(self.cli.commands) + elif cli_resolved_group is _sentinel: + self.cli.name = name + app.cli.add_command(self.cli) + else: + self.cli.name = cli_resolved_group + app.cli.add_command(self.cli) + + for blueprint, bp_options in self._blueprints: + bp_options = bp_options.copy() + bp_url_prefix = bp_options.get("url_prefix") + bp_subdomain = bp_options.get("subdomain") + + if bp_subdomain is None: + bp_subdomain = blueprint.subdomain + + if state.subdomain is not None and bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + "." + state.subdomain + elif bp_subdomain is not None: + bp_options["subdomain"] = bp_subdomain + elif state.subdomain is not None: + bp_options["subdomain"] = state.subdomain + + if bp_url_prefix is None: + bp_url_prefix = blueprint.url_prefix + + if state.url_prefix is not None and bp_url_prefix is not None: + bp_options["url_prefix"] = ( + state.url_prefix.rstrip("/") + "/" + bp_url_prefix.lstrip("/") + ) + elif bp_url_prefix is not None: + bp_options["url_prefix"] = bp_url_prefix + elif state.url_prefix is not None: + bp_options["url_prefix"] = state.url_prefix + + bp_options["name_prefix"] = name + blueprint.register(app, bp_options) + + def _merge_blueprint_funcs(self, app: App, name: str) -> None: + def extend( + bp_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + parent_dict: dict[ft.AppOrBlueprintKey, list[t.Any]], + ) -> None: + for key, values in bp_dict.items(): + key = name if key is None else f"{name}.{key}" + parent_dict[key].extend(values) + + for key, value in self.error_handler_spec.items(): + key = name if key is None else f"{name}.{key}" + value = defaultdict( + dict, + { + code: {exc_class: func for exc_class, func in code_values.items()} + for code, code_values in value.items() + }, + ) + app.error_handler_spec[key] = value + + for endpoint, func in self.view_functions.items(): + app.view_functions[endpoint] = func + + extend(self.before_request_funcs, app.before_request_funcs) + extend(self.after_request_funcs, app.after_request_funcs) + extend( + self.teardown_request_funcs, + app.teardown_request_funcs, + ) + extend(self.url_default_functions, app.url_default_functions) + extend(self.url_value_preprocessors, app.url_value_preprocessors) + extend(self.template_context_processors, app.template_context_processors) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a URL rule with the blueprint. See :meth:`.Flask.add_url_rule` for + full documentation. + + The URL rule is prefixed with the blueprint's URL prefix. The endpoint name, + used with :func:`url_for`, is prefixed with the blueprint's name. + """ + if endpoint and "." in endpoint: + raise ValueError("'endpoint' may not contain a dot '.' character.") + + if view_func and hasattr(view_func, "__name__") and "." in view_func.__name__: + raise ValueError("'view_func' name may not contain a dot '.' character.") + + self.record( + lambda s: s.add_url_rule( + rule, + endpoint, + view_func, + provide_automatic_options=provide_automatic_options, + **options, + ) + ) + + @setupmethod + def app_template_filter( + self, name: str | None = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a template filter, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def decorator(f: T_template_filter) -> T_template_filter: + self.add_app_template_filter(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_filter( + self, f: ft.TemplateFilterCallable, name: str | None = None + ) -> None: + """Register a template filter, available in any template rendered by the + application. Works like the :meth:`app_template_filter` decorator. Equivalent to + :meth:`.Flask.add_template_filter`. + + :param name: the optional name of the filter, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.filters[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_test( + self, name: str | None = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a template test, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def decorator(f: T_template_test) -> T_template_test: + self.add_app_template_test(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_test( + self, f: ft.TemplateTestCallable, name: str | None = None + ) -> None: + """Register a template test, available in any template rendered by the + application. Works like the :meth:`app_template_test` decorator. Equivalent to + :meth:`.Flask.add_template_test`. + + .. versionadded:: 0.10 + + :param name: the optional name of the test, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.tests[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def app_template_global( + self, name: str | None = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a template global, available in any template rendered by the + application. Equivalent to :meth:`.Flask.template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def decorator(f: T_template_global) -> T_template_global: + self.add_app_template_global(f, name=name) + return f + + return decorator + + @setupmethod + def add_app_template_global( + self, f: ft.TemplateGlobalCallable, name: str | None = None + ) -> None: + """Register a template global, available in any template rendered by the + application. Works like the :meth:`app_template_global` decorator. Equivalent to + :meth:`.Flask.add_template_global`. + + .. versionadded:: 0.10 + + :param name: the optional name of the global, otherwise the + function name will be used. + """ + + def register_template(state: BlueprintSetupState) -> None: + state.app.jinja_env.globals[name or f.__name__] = f + + self.record_once(register_template) + + @setupmethod + def before_app_request(self, f: T_before_request) -> T_before_request: + """Like :meth:`before_request`, but before every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.before_request`. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`after_request`, but after every request, not only those handled + by the blueprint. Equivalent to :meth:`.Flask.after_request`. + """ + self.record_once( + lambda s: s.app.after_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def teardown_app_request(self, f: T_teardown) -> T_teardown: + """Like :meth:`teardown_request`, but after every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.teardown_request`. + """ + self.record_once( + lambda s: s.app.teardown_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_context_processor( + self, f: T_template_context_processor + ) -> T_template_context_processor: + """Like :meth:`context_processor`, but for templates rendered by every view, not + only by the blueprint. Equivalent to :meth:`.Flask.context_processor`. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`errorhandler`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.errorhandler`. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + def from_blueprint(state: BlueprintSetupState) -> None: + state.app.errorhandler(code)(f) + + self.record_once(from_blueprint) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Like :meth:`url_value_preprocessor`, but for every request, not only those + handled by the blueprint. Equivalent to :meth:`.Flask.url_value_preprocessor`. + """ + self.record_once( + lambda s: s.app.url_value_preprocessors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Like :meth:`url_defaults`, but for every request, not only those handled by + the blueprint. Equivalent to :meth:`.Flask.url_defaults`. + """ + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py new file mode 100644 index 00000000..3a839f5a --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sansio/scaffold.py @@ -0,0 +1,792 @@ +from __future__ import annotations + +import importlib.util +import os +import pathlib +import sys +import typing as t +from collections import defaultdict +from functools import update_wrapper + +from jinja2 import BaseLoader +from jinja2 import FileSystemLoader +from werkzeug.exceptions import default_exceptions +from werkzeug.exceptions import HTTPException +from werkzeug.utils import cached_property + +from .. import typing as ft +from ..helpers import get_root_path +from ..templating import _default_template_ctx_processor + +if t.TYPE_CHECKING: # pragma: no cover + from click import Group + +# a singleton sentinel value for parameter defaults +_sentinel = object() + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable[t.Any]) +T_before_request = t.TypeVar("T_before_request", bound=ft.BeforeRequestCallable) +T_error_handler = t.TypeVar("T_error_handler", bound=ft.ErrorHandlerCallable) +T_teardown = t.TypeVar("T_teardown", bound=ft.TeardownCallable) +T_template_context_processor = t.TypeVar( + "T_template_context_processor", bound=ft.TemplateContextProcessorCallable +) +T_url_defaults = t.TypeVar("T_url_defaults", bound=ft.URLDefaultCallable) +T_url_value_preprocessor = t.TypeVar( + "T_url_value_preprocessor", bound=ft.URLValuePreprocessorCallable +) +T_route = t.TypeVar("T_route", bound=ft.RouteCallable) + + +def setupmethod(f: F) -> F: + f_name = f.__name__ + + def wrapper_func(self: Scaffold, *args: t.Any, **kwargs: t.Any) -> t.Any: + self._check_setup_finished(f_name) + return f(self, *args, **kwargs) + + return t.cast(F, update_wrapper(wrapper_func, f)) + + +class Scaffold: + """Common behavior shared between :class:`~flask.Flask` and + :class:`~flask.blueprints.Blueprint`. + + :param import_name: The import name of the module where this object + is defined. Usually :attr:`__name__` should be used. + :param static_folder: Path to a folder of static files to serve. + If this is set, a static route will be added. + :param static_url_path: URL prefix for the static route. + :param template_folder: Path to a folder containing template files. + for rendering. If this is set, a Jinja loader will be added. + :param root_path: The path that static, template, and resource files + are relative to. Typically not set, it is discovered based on + the ``import_name``. + + .. versionadded:: 2.0 + """ + + cli: Group + name: str + _static_folder: str | None = None + _static_url_path: str | None = None + + def __init__( + self, + import_name: str, + static_folder: str | os.PathLike[str] | None = None, + static_url_path: str | None = None, + template_folder: str | os.PathLike[str] | None = None, + root_path: str | None = None, + ): + #: The name of the package or module that this object belongs + #: to. Do not change this once it is set by the constructor. + self.import_name = import_name + + self.static_folder = static_folder # type: ignore + self.static_url_path = static_url_path + + #: The path to the templates folder, relative to + #: :attr:`root_path`, to add to the template loader. ``None`` if + #: templates should not be added. + self.template_folder = template_folder + + if root_path is None: + root_path = get_root_path(self.import_name) + + #: Absolute path to the package on the filesystem. Used to look + #: up resources contained in the package. + self.root_path = root_path + + #: A dictionary mapping endpoint names to view functions. + #: + #: To register a view function, use the :meth:`route` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.view_functions: dict[str, ft.RouteCallable] = {} + + #: A data structure of registered error handlers, in the format + #: ``{scope: {code: {class: handler}}}``. The ``scope`` key is + #: the name of a blueprint the handlers are active for, or + #: ``None`` for all requests. The ``code`` key is the HTTP + #: status code for ``HTTPException``, or ``None`` for + #: other exceptions. The innermost dictionary maps exception + #: classes to handler functions. + #: + #: To register an error handler, use the :meth:`errorhandler` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.error_handler_spec: dict[ + ft.AppOrBlueprintKey, + dict[int | None, dict[type[Exception], ft.ErrorHandlerCallable]], + ] = defaultdict(lambda: defaultdict(dict)) + + #: A data structure of functions to call at the beginning of + #: each request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`before_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.before_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.BeforeRequestCallable] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request, in the format ``{scope: [functions]}``. The + #: ``scope`` key is the name of a blueprint the functions are + #: active for, or ``None`` for all requests. + #: + #: To register a function, use the :meth:`after_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.after_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.AfterRequestCallable[t.Any]] + ] = defaultdict(list) + + #: A data structure of functions to call at the end of each + #: request even if an exception is raised, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`teardown_request` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.teardown_request_funcs: dict[ + ft.AppOrBlueprintKey, list[ft.TeardownCallable] + ] = defaultdict(list) + + #: A data structure of functions to call to pass extra context + #: values when rendering templates, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`context_processor` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.template_context_processors: dict[ + ft.AppOrBlueprintKey, list[ft.TemplateContextProcessorCallable] + ] = defaultdict(list, {None: [_default_template_ctx_processor]}) + + #: A data structure of functions to call to modify the keyword + #: arguments passed to the view function, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the + #: :meth:`url_value_preprocessor` decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_value_preprocessors: dict[ + ft.AppOrBlueprintKey, + list[ft.URLValuePreprocessorCallable], + ] = defaultdict(list) + + #: A data structure of functions to call to modify the keyword + #: arguments when generating URLs, in the format + #: ``{scope: [functions]}``. The ``scope`` key is the name of a + #: blueprint the functions are active for, or ``None`` for all + #: requests. + #: + #: To register a function, use the :meth:`url_defaults` + #: decorator. + #: + #: This data structure is internal. It should not be modified + #: directly and its format may change at any time. + self.url_default_functions: dict[ + ft.AppOrBlueprintKey, list[ft.URLDefaultCallable] + ] = defaultdict(list) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.name!r}>" + + def _check_setup_finished(self, f_name: str) -> None: + raise NotImplementedError + + @property + def static_folder(self) -> str | None: + """The absolute path to the configured static folder. ``None`` + if no static folder is set. + """ + if self._static_folder is not None: + return os.path.join(self.root_path, self._static_folder) + else: + return None + + @static_folder.setter + def static_folder(self, value: str | os.PathLike[str] | None) -> None: + if value is not None: + value = os.fspath(value).rstrip(r"\/") + + self._static_folder = value + + @property + def has_static_folder(self) -> bool: + """``True`` if :attr:`static_folder` is set. + + .. versionadded:: 0.5 + """ + return self.static_folder is not None + + @property + def static_url_path(self) -> str | None: + """The URL prefix that the static route will be accessible from. + + If it was not configured during init, it is derived from + :attr:`static_folder`. + """ + if self._static_url_path is not None: + return self._static_url_path + + if self.static_folder is not None: + basename = os.path.basename(self.static_folder) + return f"/{basename}".rstrip("/") + + return None + + @static_url_path.setter + def static_url_path(self, value: str | None) -> None: + if value is not None: + value = value.rstrip("/") + + self._static_url_path = value + + @cached_property + def jinja_loader(self) -> BaseLoader | None: + """The Jinja loader for this object's templates. By default this + is a class :class:`jinja2.loaders.FileSystemLoader` to + :attr:`template_folder` if it is set. + + .. versionadded:: 0.5 + """ + if self.template_folder is not None: + return FileSystemLoader(os.path.join(self.root_path, self.template_folder)) + else: + return None + + def _method_route( + self, + method: str, + rule: str, + options: dict[str, t.Any], + ) -> t.Callable[[T_route], T_route]: + if "methods" in options: + raise TypeError("Use the 'route' decorator to use the 'methods' argument.") + + return self.route(rule, methods=[method], **options) + + @setupmethod + def get(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["GET"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("GET", rule, options) + + @setupmethod + def post(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["POST"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("POST", rule, options) + + @setupmethod + def put(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PUT"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PUT", rule, options) + + @setupmethod + def delete(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["DELETE"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("DELETE", rule, options) + + @setupmethod + def patch(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Shortcut for :meth:`route` with ``methods=["PATCH"]``. + + .. versionadded:: 2.0 + """ + return self._method_route("PATCH", rule, options) + + @setupmethod + def route(self, rule: str, **options: t.Any) -> t.Callable[[T_route], T_route]: + """Decorate a view function to register it with the given URL + rule and options. Calls :meth:`add_url_rule`, which has more + details about the implementation. + + .. code-block:: python + + @app.route("/") + def index(): + return "Hello, World!" + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` and + ``OPTIONS`` are added automatically. + + :param rule: The URL rule string. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + + def decorator(f: T_route) -> T_route: + endpoint = options.pop("endpoint", None) + self.add_url_rule(rule, endpoint, f, **options) + return f + + return decorator + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: str | None = None, + view_func: ft.RouteCallable | None = None, + provide_automatic_options: bool | None = None, + **options: t.Any, + ) -> None: + """Register a rule for routing incoming requests and building + URLs. The :meth:`route` decorator is a shortcut to call this + with the ``view_func`` argument. These are equivalent: + + .. code-block:: python + + @app.route("/") + def index(): + ... + + .. code-block:: python + + def index(): + ... + + app.add_url_rule("/", view_func=index) + + See :ref:`url-route-registrations`. + + The endpoint name for the route defaults to the name of the view + function if the ``endpoint`` parameter isn't passed. An error + will be raised if a function has already been registered for the + endpoint. + + The ``methods`` parameter defaults to ``["GET"]``. ``HEAD`` is + always added automatically, and ``OPTIONS`` is added + automatically by default. + + ``view_func`` does not necessarily need to be passed, but if the + rule should participate in routing an endpoint name must be + associated with a view function at some point with the + :meth:`endpoint` decorator. + + .. code-block:: python + + app.add_url_rule("/", endpoint="index") + + @app.endpoint("index") + def index(): + ... + + If ``view_func`` has a ``required_methods`` attribute, those + methods are added to the passed and automatic methods. If it + has a ``provide_automatic_methods`` attribute, it is used as the + default if the parameter is not passed. + + :param rule: The URL rule string. + :param endpoint: The endpoint name to associate with the rule + and view function. Used when routing and building URLs. + Defaults to ``view_func.__name__``. + :param view_func: The view function to associate with the + endpoint name. + :param provide_automatic_options: Add the ``OPTIONS`` method and + respond to ``OPTIONS`` requests automatically. + :param options: Extra options passed to the + :class:`~werkzeug.routing.Rule` object. + """ + raise NotImplementedError + + @setupmethod + def endpoint(self, endpoint: str) -> t.Callable[[F], F]: + """Decorate a view function to register it for the given + endpoint. Used if a rule is added without a ``view_func`` with + :meth:`add_url_rule`. + + .. code-block:: python + + app.add_url_rule("/ex", endpoint="example") + + @app.endpoint("example") + def example(): + ... + + :param endpoint: The endpoint name to associate with the view + function. + """ + + def decorator(f: F) -> F: + self.view_functions[endpoint] = f + return f + + return decorator + + @setupmethod + def before_request(self, f: T_before_request) -> T_before_request: + """Register a function to run before each request. + + For example, this can be used to open a database connection, or + to load the logged in user from the session. + + .. code-block:: python + + @app.before_request + def load_user(): + if "user_id" in session: + g.user = db.session.get(session["user_id"]) + + The function will be called without any arguments. If it returns + a non-``None`` value, the value is handled as if it was the + return value from the view, and further request handling is + stopped. + + This is available on both app and blueprint objects. When used on an app, this + executes before every request. When used on a blueprint, this executes before + every request that the blueprint handles. To register with a blueprint and + execute before every request, use :meth:`.Blueprint.before_app_request`. + """ + self.before_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def after_request(self, f: T_after_request) -> T_after_request: + """Register a function to run after each request to this object. + + The function is called with the response object, and must return + a response object. This allows the functions to modify or + replace the response before it is sent. + + If a function raises an exception, any remaining + ``after_request`` functions will not be called. Therefore, this + should not be used for actions that must execute, such as to + close resources. Use :meth:`teardown_request` for that. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.after_app_request`. + """ + self.after_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def teardown_request(self, f: T_teardown) -> T_teardown: + """Register a function to be called when the request context is + popped. Typically this happens at the end of each request, but + contexts may be pushed manually as well during testing. + + .. code-block:: python + + with app.test_request_context(): + ... + + When the ``with`` block exits (or ``ctx.pop()`` is called), the + teardown functions are called just before the request context is + made inactive. + + When a teardown function was called because of an unhandled + exception it will be passed an error object. If an + :meth:`errorhandler` is registered, it will handle the exception + and the teardown will not receive it. + + Teardown functions must avoid raising exceptions. If they + execute code that might fail they must surround that code with a + ``try``/``except`` block and log any errors. + + The return values of teardown functions are ignored. + + This is available on both app and blueprint objects. When used on an app, this + executes after every request. When used on a blueprint, this executes after + every request that the blueprint handles. To register with a blueprint and + execute after every request, use :meth:`.Blueprint.teardown_app_request`. + """ + self.teardown_request_funcs.setdefault(None, []).append(f) + return f + + @setupmethod + def context_processor( + self, + f: T_template_context_processor, + ) -> T_template_context_processor: + """Registers a template context processor function. These functions run before + rendering a template. The keys of the returned dict are added as variables + available in the template. + + This is available on both app and blueprint objects. When used on an app, this + is called for every rendered template. When used on a blueprint, this is called + for templates rendered from the blueprint's views. To register with a blueprint + and affect every template, use :meth:`.Blueprint.app_context_processor`. + """ + self.template_context_processors[None].append(f) + return f + + @setupmethod + def url_value_preprocessor( + self, + f: T_url_value_preprocessor, + ) -> T_url_value_preprocessor: + """Register a URL value preprocessor function for all view + functions in the application. These functions will be called before the + :meth:`before_request` functions. + + The function can modify the values captured from the matched url before + they are passed to the view. For example, this can be used to pop a + common language code value and place it in ``g`` rather than pass it to + every view. + + The function is passed the endpoint name and values dict. The return + value is ignored. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_value_preprocessor`. + """ + self.url_value_preprocessors[None].append(f) + return f + + @setupmethod + def url_defaults(self, f: T_url_defaults) -> T_url_defaults: + """Callback function for URL defaults for all view functions of the + application. It's called with the endpoint and values and should + update the values passed in place. + + This is available on both app and blueprint objects. When used on an app, this + is called for every request. When used on a blueprint, this is called for + requests that the blueprint handles. To register with a blueprint and affect + every request, use :meth:`.Blueprint.app_url_defaults`. + """ + self.url_default_functions[None].append(f) + return f + + @setupmethod + def errorhandler( + self, code_or_exception: type[Exception] | int + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Register a function to handle errors by code or exception class. + + A decorator that is used to register a function given an + error code. Example:: + + @app.errorhandler(404) + def page_not_found(error): + return 'This page does not exist', 404 + + You can also register handlers for arbitrary exceptions:: + + @app.errorhandler(DatabaseError) + def special_exception_handler(error): + return 'Database connection failed', 500 + + This is available on both app and blueprint objects. When used on an app, this + can handle errors from every request. When used on a blueprint, this can handle + errors from requests that the blueprint handles. To register with a blueprint + and affect every request, use :meth:`.Blueprint.app_errorhandler`. + + .. versionadded:: 0.7 + Use :meth:`register_error_handler` instead of modifying + :attr:`error_handler_spec` directly, for application wide error + handlers. + + .. versionadded:: 0.7 + One can now additionally also register custom exception types + that do not necessarily have to be a subclass of the + :class:`~werkzeug.exceptions.HTTPException` class. + + :param code_or_exception: the code as integer for the handler, or + an arbitrary exception + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.register_error_handler(code_or_exception, f) + return f + + return decorator + + @setupmethod + def register_error_handler( + self, + code_or_exception: type[Exception] | int, + f: ft.ErrorHandlerCallable, + ) -> None: + """Alternative error attach function to the :meth:`errorhandler` + decorator that is more straightforward to use for non decorator + usage. + + .. versionadded:: 0.7 + """ + exc_class, code = self._get_exc_class_and_code(code_or_exception) + self.error_handler_spec[None][code][exc_class] = f + + @staticmethod + def _get_exc_class_and_code( + exc_class_or_code: type[Exception] | int, + ) -> tuple[type[Exception], int | None]: + """Get the exception class being handled. For HTTP status codes + or ``HTTPException`` subclasses, return both the exception and + status code. + + :param exc_class_or_code: Any exception class, or an HTTP status + code as an integer. + """ + exc_class: type[Exception] + + if isinstance(exc_class_or_code, int): + try: + exc_class = default_exceptions[exc_class_or_code] + except KeyError: + raise ValueError( + f"'{exc_class_or_code}' is not a recognized HTTP" + " error code. Use a subclass of HTTPException with" + " that code instead." + ) from None + else: + exc_class = exc_class_or_code + + if isinstance(exc_class, Exception): + raise TypeError( + f"{exc_class!r} is an instance, not a class. Handlers" + " can only be registered for Exception classes or HTTP" + " error codes." + ) + + if not issubclass(exc_class, Exception): + raise ValueError( + f"'{exc_class.__name__}' is not a subclass of Exception." + " Handlers can only be registered for Exception classes" + " or HTTP error codes." + ) + + if issubclass(exc_class, HTTPException): + return exc_class, exc_class.code + else: + return exc_class, None + + +def _endpoint_from_view_func(view_func: ft.RouteCallable) -> str: + """Internal helper that returns the default endpoint for a given + function. This always is the function name. + """ + assert view_func is not None, "expected view func if endpoint is not provided." + return view_func.__name__ + + +def _find_package_path(import_name: str) -> str: + """Find the path that contains the package or module.""" + root_mod_name, _, _ = import_name.partition(".") + + try: + root_spec = importlib.util.find_spec(root_mod_name) + + if root_spec is None: + raise ValueError("not found") + except (ImportError, ValueError): + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - we raised `ValueError` due to `root_spec` being `None` + return os.getcwd() + + if root_spec.submodule_search_locations: + if root_spec.origin is None or root_spec.origin == "namespace": + # namespace package + package_spec = importlib.util.find_spec(import_name) + + if package_spec is not None and package_spec.submodule_search_locations: + # Pick the path in the namespace that contains the submodule. + package_path = pathlib.Path( + os.path.commonpath(package_spec.submodule_search_locations) + ) + search_location = next( + location + for location in root_spec.submodule_search_locations + if package_path.is_relative_to(location) + ) + else: + # Pick the first path. + search_location = root_spec.submodule_search_locations[0] + + return os.path.dirname(search_location) + else: + # package with __init__.py + return os.path.dirname(os.path.dirname(root_spec.origin)) + else: + # module + return os.path.dirname(root_spec.origin) # type: ignore[type-var, return-value] + + +def find_package(import_name: str) -> tuple[str | None, str]: + """Find the prefix that a package is installed under, and the path + that it would be imported from. + + The prefix is the directory containing the standard directory + hierarchy (lib, bin, etc.). If the package is not installed to the + system (:attr:`sys.prefix`) or a virtualenv (``site-packages``), + ``None`` is returned. + + The path is the entry in :attr:`sys.path` that contains the package + for import. If the package is not installed, it's assumed that the + package was imported from the current working directory. + """ + package_path = _find_package_path(import_name) + py_prefix = os.path.abspath(sys.prefix) + + # installed to the system + if pathlib.PurePath(package_path).is_relative_to(py_prefix): + return py_prefix, package_path + + site_parent, site_folder = os.path.split(package_path) + + # installed to a virtualenv + if site_folder.lower() == "site-packages": + parent, folder = os.path.split(site_parent) + + # Windows (prefix/lib/site-packages) + if folder.lower() == "lib": + return parent, package_path + + # Unix (prefix/lib/pythonX.Y/site-packages) + if os.path.basename(parent).lower() == "lib": + return os.path.dirname(parent), package_path + + # something else (prefix/site-packages) + return site_parent, package_path + + # not installed + return None, package_path diff --git a/venv/lib/python3.12/site-packages/flask/sessions.py b/venv/lib/python3.12/site-packages/flask/sessions.py new file mode 100644 index 00000000..4ffde713 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/sessions.py @@ -0,0 +1,399 @@ +from __future__ import annotations + +import collections.abc as c +import hashlib +import typing as t +from collections.abc import MutableMapping +from datetime import datetime +from datetime import timezone + +from itsdangerous import BadSignature +from itsdangerous import URLSafeTimedSerializer +from werkzeug.datastructures import CallbackDict + +from .json.tag import TaggedJSONSerializer + +if t.TYPE_CHECKING: # pragma: no cover + import typing_extensions as te + + from .app import Flask + from .wrappers import Request + from .wrappers import Response + + +class SessionMixin(MutableMapping[str, t.Any]): + """Expands a basic dictionary with session attributes.""" + + @property + def permanent(self) -> bool: + """This reflects the ``'_permanent'`` key in the dict.""" + return self.get("_permanent", False) + + @permanent.setter + def permanent(self, value: bool) -> None: + self["_permanent"] = bool(value) + + #: Some implementations can detect whether a session is newly + #: created, but that is not guaranteed. Use with caution. The mixin + # default is hard-coded ``False``. + new = False + + #: Some implementations can detect changes to the session and set + #: this when that happens. The mixin default is hard coded to + #: ``True``. + modified = True + + #: Some implementations can detect when session data is read or + #: written and set this when that happens. The mixin default is hard + #: coded to ``True``. + accessed = True + + +class SecureCookieSession(CallbackDict[str, t.Any], SessionMixin): + """Base class for sessions based on signed cookies. + + This session backend will set the :attr:`modified` and + :attr:`accessed` attributes. It cannot reliably track whether a + session is new (vs. empty), so :attr:`new` remains hard coded to + ``False``. + """ + + #: When data is changed, this is set to ``True``. Only the session + #: dictionary itself is tracked; if the session contains mutable + #: data (for example a nested dict) then this must be set to + #: ``True`` manually when modifying that data. The session cookie + #: will only be written to the response if this is ``True``. + modified = False + + #: When data is read or written, this is set to ``True``. Used by + # :class:`.SecureCookieSessionInterface` to add a ``Vary: Cookie`` + #: header, which allows caching proxies to cache different pages for + #: different users. + accessed = False + + def __init__( + self, + initial: c.Mapping[str, t.Any] | c.Iterable[tuple[str, t.Any]] | None = None, + ) -> None: + def on_update(self: te.Self) -> None: + self.modified = True + self.accessed = True + + super().__init__(initial, on_update) + + def __getitem__(self, key: str) -> t.Any: + self.accessed = True + return super().__getitem__(key) + + def get(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().get(key, default) + + def setdefault(self, key: str, default: t.Any = None) -> t.Any: + self.accessed = True + return super().setdefault(key, default) + + +class NullSession(SecureCookieSession): + """Class used to generate nicer error messages if sessions are not + available. Will still allow read-only access to the empty session + but fail on setting. + """ + + def _fail(self, *args: t.Any, **kwargs: t.Any) -> t.NoReturn: + raise RuntimeError( + "The session is unavailable because no secret " + "key was set. Set the secret_key on the " + "application to something unique and secret." + ) + + __setitem__ = __delitem__ = clear = pop = popitem = update = setdefault = _fail # type: ignore # noqa: B950 + del _fail + + +class SessionInterface: + """The basic interface you have to implement in order to replace the + default session interface which uses werkzeug's securecookie + implementation. The only methods you have to implement are + :meth:`open_session` and :meth:`save_session`, the others have + useful defaults which you don't need to change. + + The session object returned by the :meth:`open_session` method has to + provide a dictionary like interface plus the properties and methods + from the :class:`SessionMixin`. We recommend just subclassing a dict + and adding that mixin:: + + class Session(dict, SessionMixin): + pass + + If :meth:`open_session` returns ``None`` Flask will call into + :meth:`make_null_session` to create a session that acts as replacement + if the session support cannot work because some requirement is not + fulfilled. The default :class:`NullSession` class that is created + will complain that the secret key was not set. + + To replace the session interface on an application all you have to do + is to assign :attr:`flask.Flask.session_interface`:: + + app = Flask(__name__) + app.session_interface = MySessionInterface() + + Multiple requests with the same session may be sent and handled + concurrently. When implementing a new session interface, consider + whether reads or writes to the backing store must be synchronized. + There is no guarantee on the order in which the session for each + request is opened or saved, it will occur in the order that requests + begin and end processing. + + .. versionadded:: 0.8 + """ + + #: :meth:`make_null_session` will look here for the class that should + #: be created when a null session is requested. Likewise the + #: :meth:`is_null_session` method will perform a typecheck against + #: this type. + null_session_class = NullSession + + #: A flag that indicates if the session interface is pickle based. + #: This can be used by Flask extensions to make a decision in regards + #: to how to deal with the session object. + #: + #: .. versionadded:: 0.10 + pickle_based = False + + def make_null_session(self, app: Flask) -> NullSession: + """Creates a null session which acts as a replacement object if the + real session support could not be loaded due to a configuration + error. This mainly aids the user experience because the job of the + null session is to still support lookup without complaining but + modifications are answered with a helpful error message of what + failed. + + This creates an instance of :attr:`null_session_class` by default. + """ + return self.null_session_class() + + def is_null_session(self, obj: object) -> bool: + """Checks if a given object is a null session. Null sessions are + not asked to be saved. + + This checks if the object is an instance of :attr:`null_session_class` + by default. + """ + return isinstance(obj, self.null_session_class) + + def get_cookie_name(self, app: Flask) -> str: + """The name of the session cookie. Uses``app.config["SESSION_COOKIE_NAME"]``.""" + return app.config["SESSION_COOKIE_NAME"] # type: ignore[no-any-return] + + def get_cookie_domain(self, app: Flask) -> str | None: + """The value of the ``Domain`` parameter on the session cookie. If not set, + browsers will only send the cookie to the exact domain it was set from. + Otherwise, they will send it to any subdomain of the given value as well. + + Uses the :data:`SESSION_COOKIE_DOMAIN` config. + + .. versionchanged:: 2.3 + Not set by default, does not fall back to ``SERVER_NAME``. + """ + return app.config["SESSION_COOKIE_DOMAIN"] # type: ignore[no-any-return] + + def get_cookie_path(self, app: Flask) -> str: + """Returns the path for which the cookie should be valid. The + default implementation uses the value from the ``SESSION_COOKIE_PATH`` + config var if it's set, and falls back to ``APPLICATION_ROOT`` or + uses ``/`` if it's ``None``. + """ + return app.config["SESSION_COOKIE_PATH"] or app.config["APPLICATION_ROOT"] # type: ignore[no-any-return] + + def get_cookie_httponly(self, app: Flask) -> bool: + """Returns True if the session cookie should be httponly. This + currently just returns the value of the ``SESSION_COOKIE_HTTPONLY`` + config var. + """ + return app.config["SESSION_COOKIE_HTTPONLY"] # type: ignore[no-any-return] + + def get_cookie_secure(self, app: Flask) -> bool: + """Returns True if the cookie should be secure. This currently + just returns the value of the ``SESSION_COOKIE_SECURE`` setting. + """ + return app.config["SESSION_COOKIE_SECURE"] # type: ignore[no-any-return] + + def get_cookie_samesite(self, app: Flask) -> str | None: + """Return ``'Strict'`` or ``'Lax'`` if the cookie should use the + ``SameSite`` attribute. This currently just returns the value of + the :data:`SESSION_COOKIE_SAMESITE` setting. + """ + return app.config["SESSION_COOKIE_SAMESITE"] # type: ignore[no-any-return] + + def get_cookie_partitioned(self, app: Flask) -> bool: + """Returns True if the cookie should be partitioned. By default, uses + the value of :data:`SESSION_COOKIE_PARTITIONED`. + + .. versionadded:: 3.1 + """ + return app.config["SESSION_COOKIE_PARTITIONED"] # type: ignore[no-any-return] + + def get_expiration_time(self, app: Flask, session: SessionMixin) -> datetime | None: + """A helper method that returns an expiration date for the session + or ``None`` if the session is linked to the browser session. The + default implementation returns now + the permanent session + lifetime configured on the application. + """ + if session.permanent: + return datetime.now(timezone.utc) + app.permanent_session_lifetime + return None + + def should_set_cookie(self, app: Flask, session: SessionMixin) -> bool: + """Used by session backends to determine if a ``Set-Cookie`` header + should be set for this session cookie for this response. If the session + has been modified, the cookie is set. If the session is permanent and + the ``SESSION_REFRESH_EACH_REQUEST`` config is true, the cookie is + always set. + + This check is usually skipped if the session was deleted. + + .. versionadded:: 0.11 + """ + + return session.modified or ( + session.permanent and app.config["SESSION_REFRESH_EACH_REQUEST"] + ) + + def open_session(self, app: Flask, request: Request) -> SessionMixin | None: + """This is called at the beginning of each request, after + pushing the request context, before matching the URL. + + This must return an object which implements a dictionary-like + interface as well as the :class:`SessionMixin` interface. + + This will return ``None`` to indicate that loading failed in + some way that is not immediately an error. The request + context will fall back to using :meth:`make_null_session` + in this case. + """ + raise NotImplementedError() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + """This is called at the end of each request, after generating + a response, before removing the request context. It is skipped + if :meth:`is_null_session` returns ``True``. + """ + raise NotImplementedError() + + +session_json_serializer = TaggedJSONSerializer() + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class SecureCookieSessionInterface(SessionInterface): + """The default session interface that stores sessions in signed cookies + through the :mod:`itsdangerous` module. + """ + + #: the salt that should be applied on top of the secret key for the + #: signing of cookie based sessions. + salt = "cookie-session" + #: the hash function to use for the signature. The default is sha1 + digest_method = staticmethod(_lazy_sha1) + #: the name of the itsdangerous supported key derivation. The default + #: is hmac. + key_derivation = "hmac" + #: A python serializer for the payload. The default is a compact + #: JSON derived serializer with support for some extra Python types + #: such as datetime objects or tuples. + serializer = session_json_serializer + session_class = SecureCookieSession + + def get_signing_serializer(self, app: Flask) -> URLSafeTimedSerializer | None: + if not app.secret_key: + return None + + keys: list[str | bytes] = [] + + if fallbacks := app.config["SECRET_KEY_FALLBACKS"]: + keys.extend(fallbacks) + + keys.append(app.secret_key) # itsdangerous expects current key at top + return URLSafeTimedSerializer( + keys, # type: ignore[arg-type] + salt=self.salt, + serializer=self.serializer, + signer_kwargs={ + "key_derivation": self.key_derivation, + "digest_method": self.digest_method, + }, + ) + + def open_session(self, app: Flask, request: Request) -> SecureCookieSession | None: + s = self.get_signing_serializer(app) + if s is None: + return None + val = request.cookies.get(self.get_cookie_name(app)) + if not val: + return self.session_class() + max_age = int(app.permanent_session_lifetime.total_seconds()) + try: + data = s.loads(val, max_age=max_age) + return self.session_class(data) + except BadSignature: + return self.session_class() + + def save_session( + self, app: Flask, session: SessionMixin, response: Response + ) -> None: + name = self.get_cookie_name(app) + domain = self.get_cookie_domain(app) + path = self.get_cookie_path(app) + secure = self.get_cookie_secure(app) + partitioned = self.get_cookie_partitioned(app) + samesite = self.get_cookie_samesite(app) + httponly = self.get_cookie_httponly(app) + + # Add a "Vary: Cookie" header if the session was accessed at all. + if session.accessed: + response.vary.add("Cookie") + + # If the session is modified to be empty, remove the cookie. + # If the session is empty, return without setting the cookie. + if not session: + if session.modified: + response.delete_cookie( + name, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + httponly=httponly, + ) + response.vary.add("Cookie") + + return + + if not self.should_set_cookie(app, session): + return + + expires = self.get_expiration_time(app, session) + val = self.get_signing_serializer(app).dumps(dict(session)) # type: ignore[union-attr] + response.set_cookie( + name, + val, + expires=expires, + httponly=httponly, + domain=domain, + path=path, + secure=secure, + partitioned=partitioned, + samesite=samesite, + ) + response.vary.add("Cookie") diff --git a/venv/lib/python3.12/site-packages/flask/signals.py b/venv/lib/python3.12/site-packages/flask/signals.py new file mode 100644 index 00000000..444fda99 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/signals.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +from blinker import Namespace + +# This namespace is only for signals provided by Flask itself. +_signals = Namespace() + +template_rendered = _signals.signal("template-rendered") +before_render_template = _signals.signal("before-render-template") +request_started = _signals.signal("request-started") +request_finished = _signals.signal("request-finished") +request_tearing_down = _signals.signal("request-tearing-down") +got_request_exception = _signals.signal("got-request-exception") +appcontext_tearing_down = _signals.signal("appcontext-tearing-down") +appcontext_pushed = _signals.signal("appcontext-pushed") +appcontext_popped = _signals.signal("appcontext-popped") +message_flashed = _signals.signal("message-flashed") diff --git a/venv/lib/python3.12/site-packages/flask/templating.py b/venv/lib/python3.12/site-packages/flask/templating.py new file mode 100644 index 00000000..618a3b35 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/templating.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +import typing as t + +from jinja2 import BaseLoader +from jinja2 import Environment as BaseEnvironment +from jinja2 import Template +from jinja2 import TemplateNotFound + +from .globals import _cv_app +from .globals import _cv_request +from .globals import current_app +from .globals import request +from .helpers import stream_with_context +from .signals import before_render_template +from .signals import template_rendered + +if t.TYPE_CHECKING: # pragma: no cover + from .app import Flask + from .sansio.app import App + from .sansio.scaffold import Scaffold + + +def _default_template_ctx_processor() -> dict[str, t.Any]: + """Default template context processor. Injects `request`, + `session` and `g`. + """ + appctx = _cv_app.get(None) + reqctx = _cv_request.get(None) + rv: dict[str, t.Any] = {} + if appctx is not None: + rv["g"] = appctx.g + if reqctx is not None: + rv["request"] = reqctx.request + rv["session"] = reqctx.session + return rv + + +class Environment(BaseEnvironment): + """Works like a regular Jinja2 environment but has some additional + knowledge of how Flask's blueprint works so that it can prepend the + name of the blueprint to referenced templates if necessary. + """ + + def __init__(self, app: App, **options: t.Any) -> None: + if "loader" not in options: + options["loader"] = app.create_global_jinja_loader() + BaseEnvironment.__init__(self, **options) + self.app = app + + +class DispatchingJinjaLoader(BaseLoader): + """A loader that looks for templates in the application and all + the blueprint folders. + """ + + def __init__(self, app: App) -> None: + self.app = app + + def get_source( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + if self.app.config["EXPLAIN_TEMPLATE_LOADING"]: + return self._get_source_explained(environment, template) + return self._get_source_fast(environment, template) + + def _get_source_explained( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + attempts = [] + rv: tuple[str, str | None, t.Callable[[], bool] | None] | None + trv: None | (tuple[str, str | None, t.Callable[[], bool] | None]) = None + + for srcobj, loader in self._iter_loaders(template): + try: + rv = loader.get_source(environment, template) + if trv is None: + trv = rv + except TemplateNotFound: + rv = None + attempts.append((loader, srcobj, rv)) + + from .debughelpers import explain_template_loading_attempts + + explain_template_loading_attempts(self.app, template, attempts) + + if trv is not None: + return trv + raise TemplateNotFound(template) + + def _get_source_fast( + self, environment: BaseEnvironment, template: str + ) -> tuple[str, str | None, t.Callable[[], bool] | None]: + for _srcobj, loader in self._iter_loaders(template): + try: + return loader.get_source(environment, template) + except TemplateNotFound: + continue + raise TemplateNotFound(template) + + def _iter_loaders(self, template: str) -> t.Iterator[tuple[Scaffold, BaseLoader]]: + loader = self.app.jinja_loader + if loader is not None: + yield self.app, loader + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + yield blueprint, loader + + def list_templates(self) -> list[str]: + result = set() + loader = self.app.jinja_loader + if loader is not None: + result.update(loader.list_templates()) + + for blueprint in self.app.iter_blueprints(): + loader = blueprint.jinja_loader + if loader is not None: + for template in loader.list_templates(): + result.add(template) + + return list(result) + + +def _render(app: Flask, template: Template, context: dict[str, t.Any]) -> str: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + rv = template.render(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + return rv + + +def render_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> str: + """Render a template by name with the given context. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _render(app, template, context) + + +def render_template_string(source: str, **context: t.Any) -> str: + """Render a template from the given source string with the given + context. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _render(app, template, context) + + +def _stream( + app: Flask, template: Template, context: dict[str, t.Any] +) -> t.Iterator[str]: + app.update_template_context(context) + before_render_template.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + def generate() -> t.Iterator[str]: + yield from template.generate(context) + template_rendered.send( + app, _async_wrapper=app.ensure_sync, template=template, context=context + ) + + rv = generate() + + # If a request context is active, keep it while generating. + if request: + rv = stream_with_context(rv) + + return rv + + +def stream_template( + template_name_or_list: str | Template | list[str | Template], + **context: t.Any, +) -> t.Iterator[str]: + """Render a template by name with the given context as a stream. + This returns an iterator of strings, which can be used as a + streaming response from a view. + + :param template_name_or_list: The name of the template to render. If + a list is given, the first name to exist will be rendered. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.get_or_select_template(template_name_or_list) + return _stream(app, template, context) + + +def stream_template_string(source: str, **context: t.Any) -> t.Iterator[str]: + """Render a template from the given source string with the given + context as a stream. This returns an iterator of strings, which can + be used as a streaming response from a view. + + :param source: The source code of the template to render. + :param context: The variables to make available in the template. + + .. versionadded:: 2.2 + """ + app = current_app._get_current_object() # type: ignore[attr-defined] + template = app.jinja_env.from_string(source) + return _stream(app, template, context) diff --git a/venv/lib/python3.12/site-packages/flask/testing.py b/venv/lib/python3.12/site-packages/flask/testing.py new file mode 100644 index 00000000..da156cc1 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/testing.py @@ -0,0 +1,298 @@ +from __future__ import annotations + +import importlib.metadata +import typing as t +from contextlib import contextmanager +from contextlib import ExitStack +from copy import copy +from types import TracebackType +from urllib.parse import urlsplit + +import werkzeug.test +from click.testing import CliRunner +from click.testing import Result +from werkzeug.test import Client +from werkzeug.wrappers import Request as BaseRequest + +from .cli import ScriptInfo +from .sessions import SessionMixin + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIEnvironment + from werkzeug.test import TestResponse + + from .app import Flask + + +class EnvironBuilder(werkzeug.test.EnvironBuilder): + """An :class:`~werkzeug.test.EnvironBuilder`, that takes defaults from the + application. + + :param app: The Flask application to configure the environment from. + :param path: URL path being requested. + :param base_url: Base URL where the app is being served, which + ``path`` is relative to. If not given, built from + :data:`PREFERRED_URL_SCHEME`, ``subdomain``, + :data:`SERVER_NAME`, and :data:`APPLICATION_ROOT`. + :param subdomain: Subdomain name to append to :data:`SERVER_NAME`. + :param url_scheme: Scheme to use instead of + :data:`PREFERRED_URL_SCHEME`. + :param json: If given, this is serialized as JSON and passed as + ``data``. Also defaults ``content_type`` to + ``application/json``. + :param args: other positional arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + :param kwargs: other keyword arguments passed to + :class:`~werkzeug.test.EnvironBuilder`. + """ + + def __init__( + self, + app: Flask, + path: str = "/", + base_url: str | None = None, + subdomain: str | None = None, + url_scheme: str | None = None, + *args: t.Any, + **kwargs: t.Any, + ) -> None: + assert not (base_url or subdomain or url_scheme) or ( + base_url is not None + ) != bool(subdomain or url_scheme), ( + 'Cannot pass "subdomain" or "url_scheme" with "base_url".' + ) + + if base_url is None: + http_host = app.config.get("SERVER_NAME") or "localhost" + app_root = app.config["APPLICATION_ROOT"] + + if subdomain: + http_host = f"{subdomain}.{http_host}" + + if url_scheme is None: + url_scheme = app.config["PREFERRED_URL_SCHEME"] + + url = urlsplit(path) + base_url = ( + f"{url.scheme or url_scheme}://{url.netloc or http_host}" + f"/{app_root.lstrip('/')}" + ) + path = url.path + + if url.query: + path = f"{path}?{url.query}" + + self.app = app + super().__init__(path, base_url, *args, **kwargs) + + def json_dumps(self, obj: t.Any, **kwargs: t.Any) -> str: # type: ignore + """Serialize ``obj`` to a JSON-formatted string. + + The serialization will be configured according to the config associated + with this EnvironBuilder's ``app``. + """ + return self.app.json.dumps(obj, **kwargs) + + +_werkzeug_version = "" + + +def _get_werkzeug_version() -> str: + global _werkzeug_version + + if not _werkzeug_version: + _werkzeug_version = importlib.metadata.version("werkzeug") + + return _werkzeug_version + + +class FlaskClient(Client): + """Works like a regular Werkzeug test client but has knowledge about + Flask's contexts to defer the cleanup of the request context until + the end of a ``with`` block. For general information about how to + use this class refer to :class:`werkzeug.test.Client`. + + .. versionchanged:: 0.12 + `app.test_client()` includes preset default environment, which can be + set after instantiation of the `app.test_client()` object in + `client.environ_base`. + + Basic usage is outlined in the :doc:`/testing` chapter. + """ + + application: Flask + + def __init__(self, *args: t.Any, **kwargs: t.Any) -> None: + super().__init__(*args, **kwargs) + self.preserve_context = False + self._new_contexts: list[t.ContextManager[t.Any]] = [] + self._context_stack = ExitStack() + self.environ_base = { + "REMOTE_ADDR": "127.0.0.1", + "HTTP_USER_AGENT": f"Werkzeug/{_get_werkzeug_version()}", + } + + @contextmanager + def session_transaction( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Iterator[SessionMixin]: + """When used in combination with a ``with`` statement this opens a + session transaction. This can be used to modify the session that + the test client uses. Once the ``with`` block is left the session is + stored back. + + :: + + with client.session_transaction() as session: + session['value'] = 42 + + Internally this is implemented by going through a temporary test + request context and since session handling could depend on + request variables this function accepts the same arguments as + :meth:`~flask.Flask.test_request_context` which are directly + passed through. + """ + if self._cookies is None: + raise TypeError( + "Cookies are disabled. Create a client with 'use_cookies=True'." + ) + + app = self.application + ctx = app.test_request_context(*args, **kwargs) + self._add_cookies_to_wsgi(ctx.request.environ) + + with ctx: + sess = app.session_interface.open_session(app, ctx.request) + + if sess is None: + raise RuntimeError("Session backend did not open a session.") + + yield sess + resp = app.response_class() + + if app.session_interface.is_null_session(sess): + return + + with ctx: + app.session_interface.save_session(app, sess, resp) + + self._update_cookies_from_response( + ctx.request.host.partition(":")[0], + ctx.request.path, + resp.headers.getlist("Set-Cookie"), + ) + + def _copy_environ(self, other: WSGIEnvironment) -> WSGIEnvironment: + out = {**self.environ_base, **other} + + if self.preserve_context: + out["werkzeug.debug.preserve_context"] = self._new_contexts.append + + return out + + def _request_from_builder_args( + self, args: tuple[t.Any, ...], kwargs: dict[str, t.Any] + ) -> BaseRequest: + kwargs["environ_base"] = self._copy_environ(kwargs.get("environ_base", {})) + builder = EnvironBuilder(self.application, *args, **kwargs) + + try: + return builder.get_request() + finally: + builder.close() + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> TestResponse: + if args and isinstance( + args[0], (werkzeug.test.EnvironBuilder, dict, BaseRequest) + ): + if isinstance(args[0], werkzeug.test.EnvironBuilder): + builder = copy(args[0]) + builder.environ_base = self._copy_environ(builder.environ_base or {}) # type: ignore[arg-type] + request = builder.get_request() + elif isinstance(args[0], dict): + request = EnvironBuilder.from_environ( + args[0], app=self.application, environ_base=self._copy_environ({}) + ).get_request() + else: + # isinstance(args[0], BaseRequest) + request = copy(args[0]) + request.environ = self._copy_environ(request.environ) + else: + # request is None + request = self._request_from_builder_args(args, kwargs) + + # Pop any previously preserved contexts. This prevents contexts + # from being preserved across redirects or multiple requests + # within a single block. + self._context_stack.close() + + response = super().open( + request, + buffered=buffered, + follow_redirects=follow_redirects, + ) + response.json_module = self.application.json # type: ignore[assignment] + + # Re-push contexts that were preserved during the request. + while self._new_contexts: + cm = self._new_contexts.pop() + self._context_stack.enter_context(cm) + + return response + + def __enter__(self) -> FlaskClient: + if self.preserve_context: + raise RuntimeError("Cannot nest client invocations") + self.preserve_context = True + return self + + def __exit__( + self, + exc_type: type | None, + exc_value: BaseException | None, + tb: TracebackType | None, + ) -> None: + self.preserve_context = False + self._context_stack.close() + + +class FlaskCliRunner(CliRunner): + """A :class:`~click.testing.CliRunner` for testing a Flask app's + CLI commands. Typically created using + :meth:`~flask.Flask.test_cli_runner`. See :ref:`testing-cli`. + """ + + def __init__(self, app: Flask, **kwargs: t.Any) -> None: + self.app = app + super().__init__(**kwargs) + + def invoke( # type: ignore + self, cli: t.Any = None, args: t.Any = None, **kwargs: t.Any + ) -> Result: + """Invokes a CLI command in an isolated environment. See + :meth:`CliRunner.invoke ` for + full method documentation. See :ref:`testing-cli` for examples. + + If the ``obj`` argument is not given, passes an instance of + :class:`~flask.cli.ScriptInfo` that knows how to load the Flask + app being tested. + + :param cli: Command object to invoke. Default is the app's + :attr:`~flask.app.Flask.cli` group. + :param args: List of strings to invoke the command with. + + :return: a :class:`~click.testing.Result` object. + """ + if cli is None: + cli = self.app.cli + + if "obj" not in kwargs: + kwargs["obj"] = ScriptInfo(create_app=lambda: self.app) + + return super().invoke(cli, args, **kwargs) diff --git a/venv/lib/python3.12/site-packages/flask/typing.py b/venv/lib/python3.12/site-packages/flask/typing.py new file mode 100644 index 00000000..6b70c409 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/typing.py @@ -0,0 +1,93 @@ +from __future__ import annotations + +import collections.abc as cabc +import typing as t + +if t.TYPE_CHECKING: # pragma: no cover + from _typeshed.wsgi import WSGIApplication # noqa: F401 + from werkzeug.datastructures import Headers # noqa: F401 + from werkzeug.sansio.response import Response # noqa: F401 + +# The possible types that are directly convertible or are a Response object. +ResponseValue = t.Union[ + "Response", + str, + bytes, + list[t.Any], + # Only dict is actually accepted, but Mapping allows for TypedDict. + t.Mapping[str, t.Any], + t.Iterator[str], + t.Iterator[bytes], + cabc.AsyncIterable[str], # for Quart, until App is generic. + cabc.AsyncIterable[bytes], +] + +# the possible types for an individual HTTP header +# This should be a Union, but mypy doesn't pass unless it's a TypeVar. +HeaderValue = t.Union[str, list[str], tuple[str, ...]] + +# the possible types for HTTP headers +HeadersValue = t.Union[ + "Headers", + t.Mapping[str, HeaderValue], + t.Sequence[tuple[str, HeaderValue]], +] + +# The possible types returned by a route function. +ResponseReturnValue = t.Union[ + ResponseValue, + tuple[ResponseValue, HeadersValue], + tuple[ResponseValue, int], + tuple[ResponseValue, int, HeadersValue], + "WSGIApplication", +] + +# Allow any subclass of werkzeug.Response, such as the one from Flask, +# as a callback argument. Using werkzeug.Response directly makes a +# callback annotated with flask.Response fail type checking. +ResponseClass = t.TypeVar("ResponseClass", bound="Response") + +AppOrBlueprintKey = t.Optional[str] # The App key is None, whereas blueprints are named +AfterRequestCallable = t.Union[ + t.Callable[[ResponseClass], ResponseClass], + t.Callable[[ResponseClass], t.Awaitable[ResponseClass]], +] +BeforeFirstRequestCallable = t.Union[ + t.Callable[[], None], t.Callable[[], t.Awaitable[None]] +] +BeforeRequestCallable = t.Union[ + t.Callable[[], t.Optional[ResponseReturnValue]], + t.Callable[[], t.Awaitable[t.Optional[ResponseReturnValue]]], +] +ShellContextProcessorCallable = t.Callable[[], dict[str, t.Any]] +TeardownCallable = t.Union[ + t.Callable[[t.Optional[BaseException]], None], + t.Callable[[t.Optional[BaseException]], t.Awaitable[None]], +] +TemplateContextProcessorCallable = t.Union[ + t.Callable[[], dict[str, t.Any]], + t.Callable[[], t.Awaitable[dict[str, t.Any]]], +] +TemplateFilterCallable = t.Callable[..., t.Any] +TemplateGlobalCallable = t.Callable[..., t.Any] +TemplateTestCallable = t.Callable[..., bool] +URLDefaultCallable = t.Callable[[str, dict[str, t.Any]], None] +URLValuePreprocessorCallable = t.Callable[ + [t.Optional[str], t.Optional[dict[str, t.Any]]], None +] + +# This should take Exception, but that either breaks typing the argument +# with a specific exception, or decorating multiple times with different +# exceptions (and using a union type on the argument). +# https://github.com/pallets/flask/issues/4095 +# https://github.com/pallets/flask/issues/4295 +# https://github.com/pallets/flask/issues/4297 +ErrorHandlerCallable = t.Union[ + t.Callable[[t.Any], ResponseReturnValue], + t.Callable[[t.Any], t.Awaitable[ResponseReturnValue]], +] + +RouteCallable = t.Union[ + t.Callable[..., ResponseReturnValue], + t.Callable[..., t.Awaitable[ResponseReturnValue]], +] diff --git a/venv/lib/python3.12/site-packages/flask/views.py b/venv/lib/python3.12/site-packages/flask/views.py new file mode 100644 index 00000000..53fe976d --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/views.py @@ -0,0 +1,191 @@ +from __future__ import annotations + +import typing as t + +from . import typing as ft +from .globals import current_app +from .globals import request + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +http_method_funcs = frozenset( + ["get", "post", "head", "options", "delete", "put", "trace", "patch"] +) + + +class View: + """Subclass this class and override :meth:`dispatch_request` to + create a generic class-based view. Call :meth:`as_view` to create a + view function that creates an instance of the class with the given + arguments and calls its ``dispatch_request`` method with any URL + variables. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class Hello(View): + init_every_request = False + + def dispatch_request(self, name): + return f"Hello, {name}!" + + app.add_url_rule( + "/hello/", view_func=Hello.as_view("hello") + ) + + Set :attr:`methods` on the class to change what methods the view + accepts. + + Set :attr:`decorators` on the class to apply a list of decorators to + the generated view function. Decorators applied to the class itself + will not be applied to the generated view function! + + Set :attr:`init_every_request` to ``False`` for efficiency, unless + you need to store request-global data on ``self``. + """ + + #: The methods this view is registered for. Uses the same default + #: (``["GET", "HEAD", "OPTIONS"]``) as ``route`` and + #: ``add_url_rule`` by default. + methods: t.ClassVar[t.Collection[str] | None] = None + + #: Control whether the ``OPTIONS`` method is handled automatically. + #: Uses the same default (``True``) as ``route`` and + #: ``add_url_rule`` by default. + provide_automatic_options: t.ClassVar[bool | None] = None + + #: A list of decorators to apply, in order, to the generated view + #: function. Remember that ``@decorator`` syntax is applied bottom + #: to top, so the first decorator in the list would be the bottom + #: decorator. + #: + #: .. versionadded:: 0.8 + decorators: t.ClassVar[list[t.Callable[..., t.Any]]] = [] + + #: Create a new instance of this view class for every request by + #: default. If a view subclass sets this to ``False``, the same + #: instance is used for every request. + #: + #: A single instance is more efficient, especially if complex setup + #: is done during init. However, storing data on ``self`` is no + #: longer safe across requests, and :data:`~flask.g` should be used + #: instead. + #: + #: .. versionadded:: 2.2 + init_every_request: t.ClassVar[bool] = True + + def dispatch_request(self) -> ft.ResponseReturnValue: + """The actual view function behavior. Subclasses must override + this and return a valid response. Any variables from the URL + rule are passed as keyword arguments. + """ + raise NotImplementedError() + + @classmethod + def as_view( + cls, name: str, *class_args: t.Any, **class_kwargs: t.Any + ) -> ft.RouteCallable: + """Convert the class into a view function that can be registered + for a route. + + By default, the generated view will create a new instance of the + view class for every request and call its + :meth:`dispatch_request` method. If the view class sets + :attr:`init_every_request` to ``False``, the same instance will + be used for every request. + + Except for ``name``, all other arguments passed to this method + are forwarded to the view class ``__init__`` method. + + .. versionchanged:: 2.2 + Added the ``init_every_request`` class attribute. + """ + if cls.init_every_request: + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + self = view.view_class( # type: ignore[attr-defined] + *class_args, **class_kwargs + ) + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + else: + self = cls(*class_args, **class_kwargs) # pyright: ignore + + def view(**kwargs: t.Any) -> ft.ResponseReturnValue: + return current_app.ensure_sync(self.dispatch_request)(**kwargs) # type: ignore[no-any-return] + + if cls.decorators: + view.__name__ = name + view.__module__ = cls.__module__ + for decorator in cls.decorators: + view = decorator(view) + + # We attach the view class to the view function for two reasons: + # first of all it allows us to easily figure out what class-based + # view this thing came from, secondly it's also used for instantiating + # the view class so you can actually replace it with something else + # for testing purposes and debugging. + view.view_class = cls # type: ignore + view.__name__ = name + view.__doc__ = cls.__doc__ + view.__module__ = cls.__module__ + view.methods = cls.methods # type: ignore + view.provide_automatic_options = cls.provide_automatic_options # type: ignore + return view + + +class MethodView(View): + """Dispatches request methods to the corresponding instance methods. + For example, if you implement a ``get`` method, it will be used to + handle ``GET`` requests. + + This can be useful for defining a REST API. + + :attr:`methods` is automatically set based on the methods defined on + the class. + + See :doc:`views` for a detailed guide. + + .. code-block:: python + + class CounterAPI(MethodView): + def get(self): + return str(session.get("counter", 0)) + + def post(self): + session["counter"] = session.get("counter", 0) + 1 + return redirect(url_for("counter")) + + app.add_url_rule( + "/counter", view_func=CounterAPI.as_view("counter") + ) + """ + + def __init_subclass__(cls, **kwargs: t.Any) -> None: + super().__init_subclass__(**kwargs) + + if "methods" not in cls.__dict__: + methods = set() + + for base in cls.__bases__: + if getattr(base, "methods", None): + methods.update(base.methods) # type: ignore[attr-defined] + + for key in http_method_funcs: + if hasattr(cls, key): + methods.add(key.upper()) + + if methods: + cls.methods = methods + + def dispatch_request(self, **kwargs: t.Any) -> ft.ResponseReturnValue: + meth = getattr(self, request.method.lower(), None) + + # If the request method is HEAD and we don't have a handler for it + # retry with GET. + if meth is None and request.method == "HEAD": + meth = getattr(self, "get", None) + + assert meth is not None, f"Unimplemented method {request.method!r}" + return current_app.ensure_sync(meth)(**kwargs) # type: ignore[no-any-return] diff --git a/venv/lib/python3.12/site-packages/flask/wrappers.py b/venv/lib/python3.12/site-packages/flask/wrappers.py new file mode 100644 index 00000000..bab61029 --- /dev/null +++ b/venv/lib/python3.12/site-packages/flask/wrappers.py @@ -0,0 +1,257 @@ +from __future__ import annotations + +import typing as t + +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import HTTPException +from werkzeug.wrappers import Request as RequestBase +from werkzeug.wrappers import Response as ResponseBase + +from . import json +from .globals import current_app +from .helpers import _split_blueprint_path + +if t.TYPE_CHECKING: # pragma: no cover + from werkzeug.routing import Rule + + +class Request(RequestBase): + """The request object used by default in Flask. Remembers the + matched endpoint and view arguments. + + It is what ends up as :class:`~flask.request`. If you want to replace + the request object used you can subclass this and set + :attr:`~flask.Flask.request_class` to your subclass. + + The request object is a :class:`~werkzeug.wrappers.Request` subclass and + provides all of the attributes Werkzeug defines plus a few Flask + specific ones. + """ + + json_module: t.Any = json + + #: The internal URL rule that matched the request. This can be + #: useful to inspect which methods are allowed for the URL from + #: a before/after handler (``request.url_rule.methods``) etc. + #: Though if the request's method was invalid for the URL rule, + #: the valid list is available in ``routing_exception.valid_methods`` + #: instead (an attribute of the Werkzeug exception + #: :exc:`~werkzeug.exceptions.MethodNotAllowed`) + #: because the request was never internally bound. + #: + #: .. versionadded:: 0.6 + url_rule: Rule | None = None + + #: A dict of view arguments that matched the request. If an exception + #: happened when matching, this will be ``None``. + view_args: dict[str, t.Any] | None = None + + #: If matching the URL failed, this is the exception that will be + #: raised / was raised as part of the request handling. This is + #: usually a :exc:`~werkzeug.exceptions.NotFound` exception or + #: something similar. + routing_exception: HTTPException | None = None + + _max_content_length: int | None = None + _max_form_memory_size: int | None = None + _max_form_parts: int | None = None + + @property + def max_content_length(self) -> int | None: + """The maximum number of bytes that will be read during this request. If + this limit is exceeded, a 413 :exc:`~werkzeug.exceptions.RequestEntityTooLarge` + error is raised. If it is set to ``None``, no limit is enforced at the + Flask application level. However, if it is ``None`` and the request has + no ``Content-Length`` header and the WSGI server does not indicate that + it terminates the stream, then no data is read to avoid an infinite + stream. + + Each request defaults to the :data:`MAX_CONTENT_LENGTH` config, which + defaults to ``None``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This can be set per-request. + + .. versionchanged:: 0.6 + This is configurable through Flask config. + """ + if self._max_content_length is not None: + return self._max_content_length + + if not current_app: + return super().max_content_length + + return current_app.config["MAX_CONTENT_LENGTH"] # type: ignore[no-any-return] + + @max_content_length.setter + def max_content_length(self, value: int | None) -> None: + self._max_content_length = value + + @property + def max_form_memory_size(self) -> int | None: + """The maximum size in bytes any non-file form field may be in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_MEMORY_SIZE` config, which + defaults to ``500_000``. It can be set on a specific ``request`` to + apply the limit to that specific view. This should be set appropriately + based on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_memory_size is not None: + return self._max_form_memory_size + + if not current_app: + return super().max_form_memory_size + + return current_app.config["MAX_FORM_MEMORY_SIZE"] # type: ignore[no-any-return] + + @max_form_memory_size.setter + def max_form_memory_size(self, value: int | None) -> None: + self._max_form_memory_size = value + + @property # type: ignore[override] + def max_form_parts(self) -> int | None: + """The maximum number of fields that may be present in a + ``multipart/form-data`` body. If this limit is exceeded, a 413 + :exc:`~werkzeug.exceptions.RequestEntityTooLarge` error is raised. If it + is set to ``None``, no limit is enforced at the Flask application level. + + Each request defaults to the :data:`MAX_FORM_PARTS` config, which + defaults to ``1_000``. It can be set on a specific ``request`` to apply + the limit to that specific view. This should be set appropriately based + on an application's or view's specific needs. + + .. versionchanged:: 3.1 + This is configurable through Flask config. + """ + if self._max_form_parts is not None: + return self._max_form_parts + + if not current_app: + return super().max_form_parts + + return current_app.config["MAX_FORM_PARTS"] # type: ignore[no-any-return] + + @max_form_parts.setter + def max_form_parts(self, value: int | None) -> None: + self._max_form_parts = value + + @property + def endpoint(self) -> str | None: + """The endpoint that matched the request URL. + + This will be ``None`` if matching failed or has not been + performed yet. + + This in combination with :attr:`view_args` can be used to + reconstruct the same URL or a modified URL. + """ + if self.url_rule is not None: + return self.url_rule.endpoint # type: ignore[no-any-return] + + return None + + @property + def blueprint(self) -> str | None: + """The registered name of the current blueprint. + + This will be ``None`` if the endpoint is not part of a + blueprint, or if URL matching failed or has not been performed + yet. + + This does not necessarily match the name the blueprint was + created with. It may have been nested, or registered with a + different name. + """ + endpoint = self.endpoint + + if endpoint is not None and "." in endpoint: + return endpoint.rpartition(".")[0] + + return None + + @property + def blueprints(self) -> list[str]: + """The registered names of the current blueprint upwards through + parent blueprints. + + This will be an empty list if there is no current blueprint, or + if URL matching failed. + + .. versionadded:: 2.0.1 + """ + name = self.blueprint + + if name is None: + return [] + + return _split_blueprint_path(name) + + def _load_form_data(self) -> None: + super()._load_form_data() + + # In debug mode we're replacing the files multidict with an ad-hoc + # subclass that raises a different error for key errors. + if ( + current_app + and current_app.debug + and self.mimetype != "multipart/form-data" + and not self.files + ): + from .debughelpers import attach_enctype_error_multidict + + attach_enctype_error_multidict(self) + + def on_json_loading_failed(self, e: ValueError | None) -> t.Any: + try: + return super().on_json_loading_failed(e) + except BadRequest as ebr: + if current_app and current_app.debug: + raise + + raise BadRequest() from ebr + + +class Response(ResponseBase): + """The response object that is used by default in Flask. Works like the + response object from Werkzeug but is set to have an HTML mimetype by + default. Quite often you don't have to create this object yourself because + :meth:`~flask.Flask.make_response` will take care of that for you. + + If you want to replace the response object used you can subclass this and + set :attr:`~flask.Flask.response_class` to your subclass. + + .. versionchanged:: 1.0 + JSON support is added to the response, like the request. This is useful + when testing to get the test client response data as JSON. + + .. versionchanged:: 1.0 + + Added :attr:`max_cookie_size`. + """ + + default_mimetype: str | None = "text/html" + + json_module = json + + autocorrect_location_header = False + + @property + def max_cookie_size(self) -> int: # type: ignore + """Read-only view of the :data:`MAX_COOKIE_SIZE` config key. + + See :attr:`~werkzeug.wrappers.Response.max_cookie_size` in + Werkzeug's docs. + """ + if current_app: + return current_app.config["MAX_COOKIE_SIZE"] # type: ignore[no-any-return] + + # return Werkzeug's default when not in an app context + return super().max_cookie_size diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt new file mode 100644 index 00000000..7b190ca6 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2011 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA new file mode 100644 index 00000000..ddf54648 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/METADATA @@ -0,0 +1,60 @@ +Metadata-Version: 2.1 +Name: itsdangerous +Version: 2.2.0 +Summary: Safely pass data to untrusted environments and back. +Maintainer-email: Pallets +Requires-Python: >=3.8 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Typing :: Typed +Project-URL: Changes, https://itsdangerous.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://itsdangerous.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/itsdangerous/ + +# ItsDangerous + +... so better sign this + +Various helpers to pass data to untrusted environments and to get it +back safe and sound. Data is cryptographically signed to ensure that a +token has not been tampered with. + +It's possible to customize how data is serialized. Data is compressed as +needed. A timestamp can be added and verified automatically while +loading a token. + + +## A Simple Example + +Here's how you could generate a token for transmitting a user's id and +name between web requests. + +```python +from itsdangerous import URLSafeSerializer +auth_s = URLSafeSerializer("secret key", "auth") +token = auth_s.dumps({"id": 5, "name": "itsdangerous"}) + +print(token) +# eyJpZCI6NSwibmFtZSI6Iml0c2Rhbmdlcm91cyJ9.6YP6T0BaO67XP--9UzTrmurXSmg + +data = auth_s.loads(token) +print(data["name"]) +# itsdangerous +``` + + +## Donate + +The Pallets organization develops and supports ItsDangerous and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +[please donate today][]. + +[please donate today]: https://palletsprojects.com/donate + diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD new file mode 100644 index 00000000..245f43e8 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/RECORD @@ -0,0 +1,22 @@ +itsdangerous-2.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +itsdangerous-2.2.0.dist-info/LICENSE.txt,sha256=Y68JiRtr6K0aQlLtQ68PTvun_JSOIoNnvtfzxa4LCdc,1475 +itsdangerous-2.2.0.dist-info/METADATA,sha256=0rk0-1ZwihuU5DnwJVwPWoEI4yWOyCexih3JyZHblhE,1924 +itsdangerous-2.2.0.dist-info/RECORD,, +itsdangerous-2.2.0.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81 +itsdangerous/__init__.py,sha256=4SK75sCe29xbRgQE1ZQtMHnKUuZYAf3bSpZOrff1IAY,1427 +itsdangerous/__pycache__/__init__.cpython-312.pyc,, +itsdangerous/__pycache__/_json.cpython-312.pyc,, +itsdangerous/__pycache__/encoding.cpython-312.pyc,, +itsdangerous/__pycache__/exc.cpython-312.pyc,, +itsdangerous/__pycache__/serializer.cpython-312.pyc,, +itsdangerous/__pycache__/signer.cpython-312.pyc,, +itsdangerous/__pycache__/timed.cpython-312.pyc,, +itsdangerous/__pycache__/url_safe.cpython-312.pyc,, +itsdangerous/_json.py,sha256=wPQGmge2yZ9328EHKF6gadGeyGYCJQKxtU-iLKE6UnA,473 +itsdangerous/encoding.py,sha256=wwTz5q_3zLcaAdunk6_vSoStwGqYWe307Zl_U87aRFM,1409 +itsdangerous/exc.py,sha256=Rr3exo0MRFEcPZltwecyK16VV1bE2K9_F1-d-ljcUn4,3201 +itsdangerous/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +itsdangerous/serializer.py,sha256=PmdwADLqkSyQLZ0jOKAgDsAW4k_H0TlA71Ei3z0C5aI,15601 +itsdangerous/signer.py,sha256=YO0CV7NBvHA6j549REHJFUjUojw2pHqwcUpQnU7yNYQ,9647 +itsdangerous/timed.py,sha256=6RvDMqNumGMxf0-HlpaZdN9PUQQmRvrQGplKhxuivUs,8083 +itsdangerous/url_safe.py,sha256=az4e5fXi_vs-YbWj8YZwn4wiVKfeD--GEKRT5Ueu4P4,2505 diff --git a/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL new file mode 100644 index 00000000..3b5e64b5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous-2.2.0.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.9.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__init__.py b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py new file mode 100644 index 00000000..ea55256e --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/__init__.py @@ -0,0 +1,38 @@ +from __future__ import annotations + +import typing as t + +from .encoding import base64_decode as base64_decode +from .encoding import base64_encode as base64_encode +from .encoding import want_bytes as want_bytes +from .exc import BadData as BadData +from .exc import BadHeader as BadHeader +from .exc import BadPayload as BadPayload +from .exc import BadSignature as BadSignature +from .exc import BadTimeSignature as BadTimeSignature +from .exc import SignatureExpired as SignatureExpired +from .serializer import Serializer as Serializer +from .signer import HMACAlgorithm as HMACAlgorithm +from .signer import NoneAlgorithm as NoneAlgorithm +from .signer import Signer as Signer +from .timed import TimedSerializer as TimedSerializer +from .timed import TimestampSigner as TimestampSigner +from .url_safe import URLSafeSerializer as URLSafeSerializer +from .url_safe import URLSafeTimedSerializer as URLSafeTimedSerializer + + +def __getattr__(name: str) -> t.Any: + if name == "__version__": + import importlib.metadata + import warnings + + warnings.warn( + "The '__version__' attribute is deprecated and will be removed in" + " ItsDangerous 2.3. Use feature detection or" + " 'importlib.metadata.version(\"itsdangerous\")' instead.", + DeprecationWarning, + stacklevel=2, + ) + return importlib.metadata.version("itsdangerous") + + raise AttributeError(name) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4fb5c5f98b49609e9783a4bad230fae15bc865ef GIT binary patch literal 1616 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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..146b7afe4a3e62fb32f6832ba1089484fd83fbc9 GIT binary patch literal 3930 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 K!!}dN2>Nf%)1Y7g literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc b/venv/lib/python3.12/site-packages/itsdangerous/__pycache__/timed.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3e60c5825e371176a12ab5cef6983ccb8eac08b7 GIT binary patch literal 8724 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 q?D>qqub-B5Y}${rO#5eg6*}fnXZ| 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..1450d134a325b2eb471b697249969e805017cbc6 GIT binary patch literal 3520 zcmbtWU2Ggz6~41Gv;RN-+qIp<_%=?}Y)IBLNrP|#)JaH4)wrQ<6xb?^$2-^d*t0v! zo!Q!6t!adU*a(4|2NYKn$wEA&3P?fXfhW`;@qp-qQzKywi4@fG(6>$PiYR^IoIAT- z$CM)AdVS~IbIv_;=bZDMd;XM2LMk{8oUCEL|q(=It znvCd4-MFAHTDES0xI?>eT6gtv#!cNatBeCL`ot>ridkevn^o{n?$6DGN*mvV^$)=D zjN~PQ9TT+DV{4>IJG9?+otI2%GhzL4#HJ%6Vf|QSp zlWf$>TzvV(aea!lk8$2yFiX{U;lT`Qmgv0c&QP6lHeIoFPMxg}qNWQ%%c8pLvSQh# zu1%|!IT@ue3gA4>9EZ9yj5;niOVcPX>T?YDIWsnQ8K>qHEwKXV>3lIq&$SF%jxDVC zKBvBmx0`ZoSm`dBD(EHZz!zAHbdu4sr5F5j>l8jMC(KmSJA?5m9O<&xWw0r|V!2xT zqcGIb_OcLY1_iT1h5r;G(#Bp`{X_yVNK0x>nnl@;VFYe9xja;p01RXoS&|H8NsSP< znZSh9q?XoFu%_}1$N+x+m=%z0t^8*#*w%LwE!nkjjr?d2SPM=|HTmb#uYxA2DZh|@ zERB;P;x;phkbQ)AFNNGDpdoA2TIiR-Tg@-5g}xUs$WrLLp?PVZEXdy?^U`PT4*jRy z+3?tz4fH~e;~8G59zSJQEQ12pXfv=rm_%U9K5`(21-;@hYEMxJEL$kBG6ECAlC-%w zZI*OPW1QQ(I@&geX-Co6wxnwtoU%C+QbS}RBxF;T4MVJ5ox2VuIS;}qy~x*EujFA| zD`?w`wvBtLQz5ijm4h9`TgX7BMZw$}de9nQ|!<^xZqvJ1McyaXNnbG0bSn0K4ILvT)(VekNM{>^| z9(GKZ9RkfceHxTa*D>_cG~;%~8Ln_kLtNy_i@XnBP#yYosOPqSM=vNkzk}(~71BtO z%fo0>*v7zev|{b-WXp*&xTr zdU2ytEVpu&r;!zIfyR?9R^nJ4vLTKattZ=)vwQ%lgz0E4J!W{(ZFIdoSNv4iW~1NGDEduaXq2VH|J%39ac_0Zp9ee0QB%a^W~ z>SrIMGWFyJyaDb#z6&0nI=SdFhwldZvFheVON#=w)wrN(jgHwR#-X$l{(007a^_Ze zNi4Dof4U{$2a!4e6Wpj_O)Kd|rfFVO(~7oHv5<~y+IK3t)s%!Z&9Doa#xZGl5+*OD zY1`Tm5FuuT`@BT6QWThFXyxe=s2&!^yvHKVL(>HjVO8c%d1Le zweQfHa-tC@`}RMKd`><7pfl4@;R(p;0Ei(KCh4adD1$xSeT^7WaS}~^oB-+{&r3d_MAX8OiCnu8nV^#u zmtu}Ma1|I7>y!f>3A7R7ZjWN3VTEh;7X|3wOvl9{54Q(49+fgw>gMKo#tYEG(ZY<* zp{)bHuO!UqR(VFBWG>YmIuCBf=fuP_+A|Xq2az}ggs=m24rsrx7<*gchtL~XZul@x zUx4Xt;`@jq<7jL8IuIL(kE`S(42`dY;{VEzt%hw!^H}}Er#W+n(r0;8xB+7He|l7y zLD&C}9_7!WzmDM~@{A(&rPlNk5?CpGA@Z|n#Mx8@fC)I`P_+T4?qV6Tz>{3R#;F=! zx&mxoSTvI$71zC}cb*JwhPdqo{5f979NRBXb+JX~SadxZT1EjfKcwPJPoDE}_=J!5 zuke$w0}&y>*pMYjx=;4LPrCj}Vt*%t_sNj>?Y>X;10Q~y!DCYIa{i|LrnX6d+~krX kg;)D>x1+y3^6S(lfz@UbSp!FIYwwKTeeT@H$P<3}C-3H#TL1t6 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 00000000..fc23feaa --- /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 00000000..f5ca80f9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/encoding.py @@ -0,0 +1,54 @@ +from __future__ import annotations + +import base64 +import string +import struct +import typing as t + +from .exc import BadData + + +def want_bytes( + s: str | bytes, encoding: str = "utf-8", errors: str = "strict" +) -> bytes: + if isinstance(s, str): + s = s.encode(encoding, errors) + + return s + + +def base64_encode(string: str | bytes) -> bytes: + """Base64 encode a string of bytes or text. The resulting bytes are + safe to use in URLs. + """ + string = want_bytes(string) + return base64.urlsafe_b64encode(string).rstrip(b"=") + + +def base64_decode(string: str | bytes) -> bytes: + """Base64 decode a URL-safe string of bytes or text. The result is + bytes. + """ + string = want_bytes(string, encoding="ascii", errors="ignore") + string += b"=" * (-len(string) % 4) + + try: + return base64.urlsafe_b64decode(string) + except (TypeError, ValueError) as e: + raise BadData("Invalid base64-encoded data") from e + + +# The alphabet used by base64.urlsafe_* +_base64_alphabet = f"{string.ascii_letters}{string.digits}-_=".encode("ascii") + +_int64_struct = struct.Struct(">Q") +_int_to_bytes = _int64_struct.pack +_bytes_to_int = t.cast("t.Callable[[bytes], tuple[int]]", _int64_struct.unpack) + + +def int_to_bytes(num: int) -> bytes: + return _int_to_bytes(num).lstrip(b"\x00") + + +def bytes_to_int(bytestr: bytes) -> int: + return _bytes_to_int(bytestr.rjust(8, b"\x00"))[0] diff --git a/venv/lib/python3.12/site-packages/itsdangerous/exc.py b/venv/lib/python3.12/site-packages/itsdangerous/exc.py new file mode 100644 index 00000000..a75adcd5 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/exc.py @@ -0,0 +1,106 @@ +from __future__ import annotations + +import typing as t +from datetime import datetime + + +class BadData(Exception): + """Raised if bad data of any sort was encountered. This is the base + for all exceptions that ItsDangerous defines. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str): + super().__init__(message) + self.message = message + + def __str__(self) -> str: + return self.message + + +class BadSignature(BadData): + """Raised if a signature does not match.""" + + def __init__(self, message: str, payload: t.Any | None = None): + super().__init__(message) + + #: The payload that failed the signature test. In some + #: situations you might still want to inspect this, even if + #: you know it was tampered with. + #: + #: .. versionadded:: 0.14 + self.payload: t.Any | None = payload + + +class BadTimeSignature(BadSignature): + """Raised if a time-based signature is invalid. This is a subclass + of :class:`BadSignature`. + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + date_signed: datetime | None = None, + ): + super().__init__(message, payload) + + #: If the signature expired this exposes the date of when the + #: signature was created. This can be helpful in order to + #: tell the user how long a link has been gone stale. + #: + #: .. versionchanged:: 2.0 + #: The datetime value is timezone-aware rather than naive. + #: + #: .. versionadded:: 0.14 + self.date_signed = date_signed + + +class SignatureExpired(BadTimeSignature): + """Raised if a signature timestamp is older than ``max_age``. This + is a subclass of :exc:`BadTimeSignature`. + """ + + +class BadHeader(BadSignature): + """Raised if a signed header is invalid in some form. This only + happens for serializers that have a header that goes with the + signature. + + .. versionadded:: 0.24 + """ + + def __init__( + self, + message: str, + payload: t.Any | None = None, + header: t.Any | None = None, + original_error: Exception | None = None, + ): + super().__init__(message, payload) + + #: If the header is actually available but just malformed it + #: might be stored here. + self.header: t.Any | None = header + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error + + +class BadPayload(BadData): + """Raised if a payload is invalid. This could happen if the payload + is loaded despite an invalid signature, or if there is a mismatch + between the serializer and deserializer. The original exception + that occurred during loading is stored on as :attr:`original_error`. + + .. versionadded:: 0.15 + """ + + def __init__(self, message: str, original_error: Exception | None = None): + super().__init__(message) + + #: If available, the error that indicates why the payload was + #: not valid. This might be ``None``. + self.original_error: Exception | None = original_error diff --git a/venv/lib/python3.12/site-packages/itsdangerous/py.typed b/venv/lib/python3.12/site-packages/itsdangerous/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/venv/lib/python3.12/site-packages/itsdangerous/serializer.py b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py new file mode 100644 index 00000000..5ddf3871 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/serializer.py @@ -0,0 +1,406 @@ +from __future__ import annotations + +import collections.abc as cabc +import json +import typing as t + +from .encoding import want_bytes +from .exc import BadPayload +from .exc import BadSignature +from .signer import _make_keys_list +from .signer import Signer + +if t.TYPE_CHECKING: + import typing_extensions as te + + # This should be either be str or bytes. To avoid having to specify the + # bound type, it falls back to a union if structural matching fails. + _TSerialized = te.TypeVar( + "_TSerialized", bound=t.Union[str, bytes], default=t.Union[str, bytes] + ) +else: + # Still available at runtime on Python < 3.13, but without the default. + _TSerialized = t.TypeVar("_TSerialized", bound=t.Union[str, bytes]) + + +class _PDataSerializer(t.Protocol[_TSerialized]): + def loads(self, payload: _TSerialized, /) -> t.Any: ... + # A signature with additional arguments is not handled correctly by type + # checkers right now, so an overload is used below for serializers that + # don't match this strict protocol. + def dumps(self, obj: t.Any, /) -> _TSerialized: ... + + +# Use TypeIs once it's available in typing_extensions or 3.13. +def is_text_serializer( + serializer: _PDataSerializer[t.Any], +) -> te.TypeGuard[_PDataSerializer[str]]: + """Checks whether a serializer generates text or binary.""" + return isinstance(serializer.dumps({}), str) + + +class Serializer(t.Generic[_TSerialized]): + """A serializer wraps a :class:`~itsdangerous.signer.Signer` to + enable serializing and securely signing data other than bytes. It + can unsign to verify that the data hasn't been changed. + + The serializer provides :meth:`dumps` and :meth:`loads`, similar to + :mod:`json`, and by default uses :mod:`json` internally to serialize + the data to bytes. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param serializer: An object that provides ``dumps`` and ``loads`` + methods for serializing data to a string. Defaults to + :attr:`default_serializer`, which defaults to :mod:`json`. + :param serializer_kwargs: Keyword arguments to pass when calling + ``serializer.dumps``. + :param signer: A ``Signer`` class to instantiate when signing data. + Defaults to :attr:`default_signer`, which defaults to + :class:`~itsdangerous.signer.Signer`. + :param signer_kwargs: Keyword arguments to pass when instantiating + the ``Signer`` class. + :param fallback_signers: List of signer parameters to try when + unsigning with the default signer fails. Each item can be a dict + of ``signer_kwargs``, a ``Signer`` class, or a tuple of + ``(signer, signer_kwargs)``. Defaults to + :attr:`default_fallback_signers`. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 2.0 + Removed the default SHA-512 fallback signer from + ``default_fallback_signers``. + + .. versionchanged:: 1.1 + Added support for ``fallback_signers`` and configured a default + SHA-512 fallback. This fallback is for users who used the yanked + 1.0.0 release which defaulted to SHA-512. + + .. versionchanged:: 0.14 + The ``signer`` and ``signer_kwargs`` parameters were added to + the constructor. + """ + + #: The default serialization module to use to serialize data to a + #: string internally. The default is :mod:`json`, but can be changed + #: to any object that provides ``dumps`` and ``loads`` methods. + default_serializer: _PDataSerializer[t.Any] = json + + #: The default ``Signer`` class to instantiate when signing data. + #: The default is :class:`itsdangerous.signer.Signer`. + default_signer: type[Signer] = Signer + + #: The default fallback signers to try when unsigning fails. + default_fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = [] + + # Serializer[str] if no data serializer is provided, or if it returns str. + @t.overload + def __init__( + self: Serializer[str], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: None | _PDataSerializer[str] = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer positional argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Serializer[bytes] with a bytes data serializer keyword argument. + @t.overload + def __init__( + self: Serializer[bytes], + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: _PDataSerializer[bytes], + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a positional argument. If the strict signature of + # _PDataSerializer doesn't match, fall back to a union, requiring the user + # to specify the type. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + # Fall back with a keyword argument. + @t.overload + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + *, + serializer: t.Any, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): ... + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous", + serializer: t.Any | None = None, + serializer_kwargs: dict[str, t.Any] | None = None, + signer: type[Signer] | None = None, + signer_kwargs: dict[str, t.Any] | None = None, + fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] + | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + + if salt is not None: + salt = want_bytes(salt) + # if salt is None then the signer's default is used + + self.salt = salt + + if serializer is None: + serializer = self.default_serializer + + self.serializer: _PDataSerializer[_TSerialized] = serializer + self.is_text_serializer: bool = is_text_serializer(serializer) + + if signer is None: + signer = self.default_signer + + self.signer: type[Signer] = signer + self.signer_kwargs: dict[str, t.Any] = signer_kwargs or {} + + if fallback_signers is None: + fallback_signers = list(self.default_fallback_signers) + + self.fallback_signers: list[ + dict[str, t.Any] | tuple[type[Signer], dict[str, t.Any]] | type[Signer] + ] = fallback_signers + self.serializer_kwargs: dict[str, t.Any] = serializer_kwargs or {} + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def load_payload( + self, payload: bytes, serializer: _PDataSerializer[t.Any] | None = None + ) -> t.Any: + """Loads the encoded object. This function raises + :class:`.BadPayload` if the payload is not valid. The + ``serializer`` parameter can be used to override the serializer + stored on the class. The encoded ``payload`` should always be + bytes. + """ + if serializer is None: + use_serializer = self.serializer + is_text = self.is_text_serializer + else: + use_serializer = serializer + is_text = is_text_serializer(serializer) + + try: + if is_text: + return use_serializer.loads(payload.decode("utf-8")) # type: ignore[arg-type] + + return use_serializer.loads(payload) # type: ignore[arg-type] + except Exception as e: + raise BadPayload( + "Could not load the payload because an exception" + " occurred on unserializing the data.", + original_error=e, + ) from e + + def dump_payload(self, obj: t.Any) -> bytes: + """Dumps the encoded object. The return value is always bytes. + If the internal serializer returns text, the value will be + encoded as UTF-8. + """ + return want_bytes(self.serializer.dumps(obj, **self.serializer_kwargs)) + + def make_signer(self, salt: str | bytes | None = None) -> Signer: + """Creates a new instance of the signer to be used. The default + implementation uses the :class:`.Signer` base class. + """ + if salt is None: + salt = self.salt + + return self.signer(self.secret_keys, salt=salt, **self.signer_kwargs) + + def iter_unsigners(self, salt: str | bytes | None = None) -> cabc.Iterator[Signer]: + """Iterates over all signers to be tried for unsigning. Starts + with the configured signer, then constructs each signer + specified in ``fallback_signers``. + """ + if salt is None: + salt = self.salt + + yield self.make_signer(salt) + + for fallback in self.fallback_signers: + if isinstance(fallback, dict): + kwargs = fallback + fallback = self.signer + elif isinstance(fallback, tuple): + fallback, kwargs = fallback + else: + kwargs = self.signer_kwargs + + for secret_key in self.secret_keys: + yield fallback(secret_key, salt=salt, **kwargs) + + def dumps(self, obj: t.Any, salt: str | bytes | None = None) -> _TSerialized: + """Returns a signed string serialized with the internal + serializer. The return value can be either a byte or unicode + string depending on the format of the internal serializer. + """ + payload = want_bytes(self.dump_payload(obj)) + rv = self.make_signer(salt).sign(payload) + + if self.is_text_serializer: + return rv.decode("utf-8") # type: ignore[return-value] + + return rv # type: ignore[return-value] + + def dump(self, obj: t.Any, f: t.IO[t.Any], salt: str | bytes | None = None) -> None: + """Like :meth:`dumps` but dumps into a file. The file handle has + to be compatible with what the internal serializer expects. + """ + f.write(self.dumps(obj, salt)) + + def loads( + self, s: str | bytes, salt: str | bytes | None = None, **kwargs: t.Any + ) -> t.Any: + """Reverse of :meth:`dumps`. Raises :exc:`.BadSignature` if the + signature validation fails. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + return self.load_payload(signer.unsign(s)) + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def load(self, f: t.IO[t.Any], salt: str | bytes | None = None) -> t.Any: + """Like :meth:`loads` but loads from a file.""" + return self.loads(f.read(), salt) + + def loads_unsafe( + self, s: str | bytes, salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads` but without verifying the signature. This + is potentially very dangerous to use depending on how your + serializer works. The return value is ``(signature_valid, + payload)`` instead of just the payload. The first item will be a + boolean that indicates if the signature is valid. This function + never fails. + + Use it for debugging only and if you know that your serializer + module is not exploitable (for example, do not use it with a + pickle serializer). + + .. versionadded:: 0.15 + """ + return self._loads_unsafe_impl(s, salt) + + def _loads_unsafe_impl( + self, + s: str | bytes, + salt: str | bytes | None, + load_kwargs: dict[str, t.Any] | None = None, + load_payload_kwargs: dict[str, t.Any] | None = None, + ) -> tuple[bool, t.Any]: + """Low level helper function to implement :meth:`loads_unsafe` + in serializer subclasses. + """ + if load_kwargs is None: + load_kwargs = {} + + try: + return True, self.loads(s, salt=salt, **load_kwargs) + except BadSignature as e: + if e.payload is None: + return False, None + + if load_payload_kwargs is None: + load_payload_kwargs = {} + + try: + return ( + False, + self.load_payload(e.payload, **load_payload_kwargs), + ) + except BadPayload: + return False, None + + def load_unsafe( + self, f: t.IO[t.Any], salt: str | bytes | None = None + ) -> tuple[bool, t.Any]: + """Like :meth:`loads_unsafe` but loads from a file. + + .. versionadded:: 0.15 + """ + return self.loads_unsafe(f.read(), salt=salt) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/signer.py b/venv/lib/python3.12/site-packages/itsdangerous/signer.py new file mode 100644 index 00000000..e324dc03 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/signer.py @@ -0,0 +1,266 @@ +from __future__ import annotations + +import collections.abc as cabc +import hashlib +import hmac +import typing as t + +from .encoding import _base64_alphabet +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import want_bytes +from .exc import BadSignature + + +class SigningAlgorithm: + """Subclasses must implement :meth:`get_signature` to provide + signature generation functionality. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + """Returns the signature for the given key and value.""" + raise NotImplementedError() + + def verify_signature(self, key: bytes, value: bytes, sig: bytes) -> bool: + """Verifies the given signature matches the expected + signature. + """ + return hmac.compare_digest(sig, self.get_signature(key, value)) + + +class NoneAlgorithm(SigningAlgorithm): + """Provides an algorithm that does not perform any signing and + returns an empty signature. + """ + + def get_signature(self, key: bytes, value: bytes) -> bytes: + return b"" + + +def _lazy_sha1(string: bytes = b"") -> t.Any: + """Don't access ``hashlib.sha1`` until runtime. FIPS builds may not include + SHA-1, in which case the import and use as a default would fail before the + developer can configure something else. + """ + return hashlib.sha1(string) + + +class HMACAlgorithm(SigningAlgorithm): + """Provides signature generation using HMACs.""" + + #: The digest method to use with the MAC algorithm. This defaults to + #: SHA1, but can be changed to any other function in the hashlib + #: module. + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + def __init__(self, digest_method: t.Any = None): + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + def get_signature(self, key: bytes, value: bytes) -> bytes: + mac = hmac.new(key, msg=value, digestmod=self.digest_method) + return mac.digest() + + +def _make_keys_list( + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], +) -> list[bytes]: + if isinstance(secret_key, (str, bytes)): + return [want_bytes(secret_key)] + + return [want_bytes(s) for s in secret_key] # pyright: ignore + + +class Signer: + """A signer securely signs bytes, then unsigns them to verify that + the value hasn't been changed. + + The secret key should be a random string of ``bytes`` and should not + be saved to code or version control. Different salts should be used + to distinguish signing in different contexts. See :doc:`/concepts` + for information about the security of the secret key and salt. + + :param secret_key: The secret key to sign and verify with. Can be a + list of keys, oldest to newest, to support key rotation. + :param salt: Extra key to combine with ``secret_key`` to distinguish + signatures in different contexts. + :param sep: Separator between the signature and value. + :param key_derivation: How to derive the signing key from the secret + key and salt. Possible values are ``concat``, ``django-concat``, + or ``hmac``. Defaults to :attr:`default_key_derivation`, which + defaults to ``django-concat``. + :param digest_method: Hash function to use when generating the HMAC + signature. Defaults to :attr:`default_digest_method`, which + defaults to :func:`hashlib.sha1`. Note that the security of the + hash alone doesn't apply when used intermediately in HMAC. + :param algorithm: A :class:`SigningAlgorithm` instance to use + instead of building a default :class:`HMACAlgorithm` with the + ``digest_method``. + + .. versionchanged:: 2.0 + Added support for key rotation by passing a list to + ``secret_key``. + + .. versionchanged:: 0.18 + ``algorithm`` was added as an argument to the class constructor. + + .. versionchanged:: 0.14 + ``key_derivation`` and ``digest_method`` were added as arguments + to the class constructor. + """ + + #: The default digest method to use for the signer. The default is + #: :func:`hashlib.sha1`, but can be changed to any :mod:`hashlib` or + #: compatible object. Note that the security of the hash alone + #: doesn't apply when used intermediately in HMAC. + #: + #: .. versionadded:: 0.14 + default_digest_method: t.Any = staticmethod(_lazy_sha1) + + #: The default scheme to use to derive the signing key from the + #: secret key and salt. The default is ``django-concat``. Possible + #: values are ``concat``, ``django-concat``, and ``hmac``. + #: + #: .. versionadded:: 0.14 + default_key_derivation: str = "django-concat" + + def __init__( + self, + secret_key: str | bytes | cabc.Iterable[str] | cabc.Iterable[bytes], + salt: str | bytes | None = b"itsdangerous.Signer", + sep: str | bytes = b".", + key_derivation: str | None = None, + digest_method: t.Any | None = None, + algorithm: SigningAlgorithm | None = None, + ): + #: The list of secret keys to try for verifying signatures, from + #: oldest to newest. The newest (last) key is used for signing. + #: + #: This allows a key rotation system to keep a list of allowed + #: keys and remove expired ones. + self.secret_keys: list[bytes] = _make_keys_list(secret_key) + self.sep: bytes = want_bytes(sep) + + if self.sep in _base64_alphabet: + raise ValueError( + "The given separator cannot be used because it may be" + " contained in the signature itself. ASCII letters," + " digits, and '-_=' must not be used." + ) + + if salt is not None: + salt = want_bytes(salt) + else: + salt = b"itsdangerous.Signer" + + self.salt = salt + + if key_derivation is None: + key_derivation = self.default_key_derivation + + self.key_derivation: str = key_derivation + + if digest_method is None: + digest_method = self.default_digest_method + + self.digest_method: t.Any = digest_method + + if algorithm is None: + algorithm = HMACAlgorithm(self.digest_method) + + self.algorithm: SigningAlgorithm = algorithm + + @property + def secret_key(self) -> bytes: + """The newest (last) entry in the :attr:`secret_keys` list. This + is for compatibility from before key rotation support was added. + """ + return self.secret_keys[-1] + + def derive_key(self, secret_key: str | bytes | None = None) -> bytes: + """This method is called to derive the key. The default key + derivation choices can be overridden here. Key derivation is not + intended to be used as a security method to make a complex key + out of a short password. Instead you should use large random + secret keys. + + :param secret_key: A specific secret key to derive from. + Defaults to the last item in :attr:`secret_keys`. + + .. versionchanged:: 2.0 + Added the ``secret_key`` parameter. + """ + if secret_key is None: + secret_key = self.secret_keys[-1] + else: + secret_key = want_bytes(secret_key) + + if self.key_derivation == "concat": + return t.cast(bytes, self.digest_method(self.salt + secret_key).digest()) + elif self.key_derivation == "django-concat": + return t.cast( + bytes, self.digest_method(self.salt + b"signer" + secret_key).digest() + ) + elif self.key_derivation == "hmac": + mac = hmac.new(secret_key, digestmod=self.digest_method) + mac.update(self.salt) + return mac.digest() + elif self.key_derivation == "none": + return secret_key + else: + raise TypeError("Unknown key derivation method") + + def get_signature(self, value: str | bytes) -> bytes: + """Returns the signature for the given value.""" + value = want_bytes(value) + key = self.derive_key() + sig = self.algorithm.get_signature(key, value) + return base64_encode(sig) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string.""" + value = want_bytes(value) + return value + self.sep + self.get_signature(value) + + def verify_signature(self, value: str | bytes, sig: str | bytes) -> bool: + """Verifies the signature for the given value.""" + try: + sig = base64_decode(sig) + except Exception: + return False + + value = want_bytes(value) + + for secret_key in reversed(self.secret_keys): + key = self.derive_key(secret_key) + + if self.algorithm.verify_signature(key, value, sig): + return True + + return False + + def unsign(self, signed_value: str | bytes) -> bytes: + """Unsigns the given string.""" + signed_value = want_bytes(signed_value) + + if self.sep not in signed_value: + raise BadSignature(f"No {self.sep!r} found in value") + + value, sig = signed_value.rsplit(self.sep, 1) + + if self.verify_signature(value, sig): + return value + + raise BadSignature(f"Signature {sig!r} does not match", payload=value) + + def validate(self, signed_value: str | bytes) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid. + """ + try: + self.unsign(signed_value) + return True + except BadSignature: + return False diff --git a/venv/lib/python3.12/site-packages/itsdangerous/timed.py b/venv/lib/python3.12/site-packages/itsdangerous/timed.py new file mode 100644 index 00000000..73843755 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/timed.py @@ -0,0 +1,228 @@ +from __future__ import annotations + +import collections.abc as cabc +import time +import typing as t +from datetime import datetime +from datetime import timezone + +from .encoding import base64_decode +from .encoding import base64_encode +from .encoding import bytes_to_int +from .encoding import int_to_bytes +from .encoding import want_bytes +from .exc import BadSignature +from .exc import BadTimeSignature +from .exc import SignatureExpired +from .serializer import _TSerialized +from .serializer import Serializer +from .signer import Signer + + +class TimestampSigner(Signer): + """Works like the regular :class:`.Signer` but also records the time + of the signing and can be used to expire signatures. The + :meth:`unsign` method can raise :exc:`.SignatureExpired` if the + unsigning failed because the signature is expired. + """ + + def get_timestamp(self) -> int: + """Returns the current timestamp. The function must return an + integer. + """ + return int(time.time()) + + def timestamp_to_datetime(self, ts: int) -> datetime: + """Convert the timestamp from :meth:`get_timestamp` into an + aware :class`datetime.datetime` in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + return datetime.fromtimestamp(ts, tz=timezone.utc) + + def sign(self, value: str | bytes) -> bytes: + """Signs the given string and also attaches time information.""" + value = want_bytes(value) + timestamp = base64_encode(int_to_bytes(self.get_timestamp())) + sep = want_bytes(self.sep) + value = value + sep + timestamp + return value + sep + self.get_signature(value) + + # Ignore overlapping signatures check, return_timestamp is the only + # parameter that affects the return type. + + @t.overload + def unsign( # type: ignore[overload-overlap] + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[False] = False, + ) -> bytes: ... + + @t.overload + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: t.Literal[True] = True, + ) -> tuple[bytes, datetime]: ... + + def unsign( + self, + signed_value: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + ) -> tuple[bytes, datetime] | bytes: + """Works like the regular :meth:`.Signer.unsign` but can also + validate the time. See the base docstring of the class for + the general behavior. If ``return_timestamp`` is ``True`` the + timestamp of the signature will be returned as an aware + :class:`datetime.datetime` object in UTC. + + .. versionchanged:: 2.0 + The timestamp is returned as a timezone-aware ``datetime`` + in UTC rather than a naive ``datetime`` assumed to be UTC. + """ + try: + result = super().unsign(signed_value) + sig_error = None + except BadSignature as e: + sig_error = e + result = e.payload or b"" + + sep = want_bytes(self.sep) + + # If there is no timestamp in the result there is something + # seriously wrong. In case there was a signature error, we raise + # that one directly, otherwise we have a weird situation in + # which we shouldn't have come except someone uses a time-based + # serializer on non-timestamp data, so catch that. + if sep not in result: + if sig_error: + raise sig_error + + raise BadTimeSignature("timestamp missing", payload=result) + + value, ts_bytes = result.rsplit(sep, 1) + ts_int: int | None = None + ts_dt: datetime | None = None + + try: + ts_int = bytes_to_int(base64_decode(ts_bytes)) + except Exception: + pass + + # Signature is *not* okay. Raise a proper error now that we have + # split the value and the timestamp. + if sig_error is not None: + if ts_int is not None: + try: + ts_dt = self.timestamp_to_datetime(ts_int) + except (ValueError, OSError, OverflowError) as exc: + # Windows raises OSError + # 32-bit raises OverflowError + raise BadTimeSignature( + "Malformed timestamp", payload=value + ) from exc + + raise BadTimeSignature(str(sig_error), payload=value, date_signed=ts_dt) + + # Signature was okay but the timestamp is actually not there or + # malformed. Should not happen, but we handle it anyway. + if ts_int is None: + raise BadTimeSignature("Malformed timestamp", payload=value) + + # Check timestamp is not older than max_age + if max_age is not None: + age = self.get_timestamp() - ts_int + + if age > max_age: + raise SignatureExpired( + f"Signature age {age} > {max_age} seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if age < 0: + raise SignatureExpired( + f"Signature age {age} < 0 seconds", + payload=value, + date_signed=self.timestamp_to_datetime(ts_int), + ) + + if return_timestamp: + return value, self.timestamp_to_datetime(ts_int) + + return value + + def validate(self, signed_value: str | bytes, max_age: int | None = None) -> bool: + """Only validates the given signed value. Returns ``True`` if + the signature exists and is valid.""" + try: + self.unsign(signed_value, max_age=max_age) + return True + except BadSignature: + return False + + +class TimedSerializer(Serializer[_TSerialized]): + """Uses :class:`TimestampSigner` instead of the default + :class:`.Signer`. + """ + + default_signer: type[TimestampSigner] = TimestampSigner + + def iter_unsigners( + self, salt: str | bytes | None = None + ) -> cabc.Iterator[TimestampSigner]: + return t.cast("cabc.Iterator[TimestampSigner]", super().iter_unsigners(salt)) + + # TODO: Signature is incompatible because parameters were added + # before salt. + + def loads( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + return_timestamp: bool = False, + salt: str | bytes | None = None, + ) -> t.Any: + """Reverse of :meth:`dumps`, raises :exc:`.BadSignature` if the + signature validation fails. If a ``max_age`` is provided it will + ensure the signature is not older than that time in seconds. In + case the signature is outdated, :exc:`.SignatureExpired` is + raised. All arguments are forwarded to the signer's + :meth:`~TimestampSigner.unsign` method. + """ + s = want_bytes(s) + last_exception = None + + for signer in self.iter_unsigners(salt): + try: + base64d, timestamp = signer.unsign( + s, max_age=max_age, return_timestamp=True + ) + payload = self.load_payload(base64d) + + if return_timestamp: + return payload, timestamp + + return payload + except SignatureExpired: + # The signature was unsigned successfully but was + # expired. Do not try the next signer. + raise + except BadSignature as err: + last_exception = err + + raise t.cast(BadSignature, last_exception) + + def loads_unsafe( # type: ignore[override] + self, + s: str | bytes, + max_age: int | None = None, + salt: str | bytes | None = None, + ) -> tuple[bool, t.Any]: + return self._loads_unsafe_impl(s, salt, load_kwargs={"max_age": max_age}) diff --git a/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py new file mode 100644 index 00000000..56a07933 --- /dev/null +++ b/venv/lib/python3.12/site-packages/itsdangerous/url_safe.py @@ -0,0 +1,83 @@ +from __future__ import annotations + +import typing as t +import zlib + +from ._json import _CompactJSON +from .encoding import base64_decode +from .encoding import base64_encode +from .exc import BadPayload +from .serializer import _PDataSerializer +from .serializer import Serializer +from .timed import TimedSerializer + + +class URLSafeSerializerMixin(Serializer[str]): + """Mixed in with a regular serializer it will attempt to zlib + compress the string to make it shorter if necessary. It will also + base64 encode the string so that it can safely be placed in a URL. + """ + + default_serializer: _PDataSerializer[str] = _CompactJSON + + def load_payload( + self, + payload: bytes, + *args: t.Any, + serializer: t.Any | None = None, + **kwargs: t.Any, + ) -> t.Any: + decompress = False + + if payload.startswith(b"."): + payload = payload[1:] + decompress = True + + try: + json = base64_decode(payload) + except Exception as e: + raise BadPayload( + "Could not base64 decode the payload because of an exception", + original_error=e, + ) from e + + if decompress: + try: + json = zlib.decompress(json) + except Exception as e: + raise BadPayload( + "Could not zlib decompress the payload before decoding the payload", + original_error=e, + ) from e + + return super().load_payload(json, *args, **kwargs) + + def dump_payload(self, obj: t.Any) -> bytes: + json = super().dump_payload(obj) + is_compressed = False + compressed = zlib.compress(json) + + if len(compressed) < (len(json) - 1): + json = compressed + is_compressed = True + + base64d = base64_encode(json) + + if is_compressed: + base64d = b"." + base64d + + return base64d + + +class URLSafeSerializer(URLSafeSerializerMixin, Serializer[str]): + """Works like :class:`.Serializer` but dumps and loads into a URL + safe string consisting of the upper and lowercase character of the + alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ + + +class URLSafeTimedSerializer(URLSafeSerializerMixin, TimedSerializer[str]): + """Works like :class:`.TimedSerializer` but dumps and loads into a + URL safe string consisting of the upper and lowercase character of + the alphabet as well as ``'_'``, ``'-'`` and ``'.'``. + """ diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER new file mode 100644 index 00000000..a1b589e3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA new file mode 100644 index 00000000..ffef2ff3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/METADATA @@ -0,0 +1,84 @@ +Metadata-Version: 2.4 +Name: Jinja2 +Version: 3.1.6 +Summary: A very fast and expressive template engine. +Maintainer-email: Pallets +Requires-Python: >=3.7 +Description-Content-Type: text/markdown +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Classifier: Typing :: Typed +License-File: LICENSE.txt +Requires-Dist: MarkupSafe>=2.0 +Requires-Dist: Babel>=2.7 ; extra == "i18n" +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Chat, https://discord.gg/pallets +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Source, https://github.com/pallets/jinja/ +Provides-Extra: i18n + +# Jinja + +Jinja is a fast, expressive, extensible templating engine. Special +placeholders in the template allow writing code similar to Python +syntax. Then the template is passed data to render the final document. + +It includes: + +- Template inheritance and inclusion. +- Define and import macros within templates. +- HTML templates can use autoescaping to prevent XSS from untrusted + user input. +- A sandboxed environment can safely render untrusted templates. +- AsyncIO support for generating templates and calling async + functions. +- I18N support with Babel. +- Templates are compiled to optimized Python code just-in-time and + cached, or can be compiled ahead-of-time. +- Exceptions point to the correct line in templates to make debugging + easier. +- Extensible filters, tests, functions, and even syntax. + +Jinja's philosophy is that while application logic belongs in Python if +possible, it shouldn't make the template designer's job difficult by +restricting functionality too much. + + +## In A Nutshell + +```jinja +{% extends "base.html" %} +{% block title %}Members{% endblock %} +{% block content %} +

+{% endblock %} +``` + +## Donate + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, [please +donate today][]. + +[please donate today]: https://palletsprojects.com/donate + +## Contributing + +See our [detailed contributing documentation][contrib] for many ways to +contribute, including reporting issues, requesting features, asking or answering +questions, and making PRs. + +[contrib]: https://palletsprojects.com/contributing/ + diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD new file mode 100644 index 00000000..ffa3866a --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/RECORD @@ -0,0 +1,57 @@ +jinja2-3.1.6.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +jinja2-3.1.6.dist-info/METADATA,sha256=aMVUj7Z8QTKhOJjZsx7FDGvqKr3ZFdkh8hQ1XDpkmcg,2871 +jinja2-3.1.6.dist-info/RECORD,, +jinja2-3.1.6.dist-info/WHEEL,sha256=_2ozNFCLWc93bK4WKHCO-eDUENDlo-dgc9cU3qokYO4,82 +jinja2-3.1.6.dist-info/entry_points.txt,sha256=OL85gYU1eD8cuPlikifFngXpeBjaxl6rIJ8KkC_3r-I,58 +jinja2-3.1.6.dist-info/licenses/LICENSE.txt,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +jinja2/__init__.py,sha256=xxepO9i7DHsqkQrgBEduLtfoz2QCuT6_gbL4XSN1hbU,1928 +jinja2/__pycache__/__init__.cpython-312.pyc,, +jinja2/__pycache__/_identifier.cpython-312.pyc,, +jinja2/__pycache__/async_utils.cpython-312.pyc,, +jinja2/__pycache__/bccache.cpython-312.pyc,, +jinja2/__pycache__/compiler.cpython-312.pyc,, +jinja2/__pycache__/constants.cpython-312.pyc,, +jinja2/__pycache__/debug.cpython-312.pyc,, +jinja2/__pycache__/defaults.cpython-312.pyc,, +jinja2/__pycache__/environment.cpython-312.pyc,, +jinja2/__pycache__/exceptions.cpython-312.pyc,, +jinja2/__pycache__/ext.cpython-312.pyc,, +jinja2/__pycache__/filters.cpython-312.pyc,, +jinja2/__pycache__/idtracking.cpython-312.pyc,, +jinja2/__pycache__/lexer.cpython-312.pyc,, +jinja2/__pycache__/loaders.cpython-312.pyc,, +jinja2/__pycache__/meta.cpython-312.pyc,, +jinja2/__pycache__/nativetypes.cpython-312.pyc,, +jinja2/__pycache__/nodes.cpython-312.pyc,, +jinja2/__pycache__/optimizer.cpython-312.pyc,, +jinja2/__pycache__/parser.cpython-312.pyc,, +jinja2/__pycache__/runtime.cpython-312.pyc,, +jinja2/__pycache__/sandbox.cpython-312.pyc,, +jinja2/__pycache__/tests.cpython-312.pyc,, +jinja2/__pycache__/utils.cpython-312.pyc,, +jinja2/__pycache__/visitor.cpython-312.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=vK-PdsuorOMnWSnEkT3iUJRIkTnYgO2T6MnGxDgHI5o,2834 +jinja2/bccache.py,sha256=gh0qs9rulnXo0PhX5jTJy2UHzI8wFnQ63o_vw7nhzRg,14061 +jinja2/compiler.py,sha256=9RpCQl5X88BHllJiPsHPh295Hh0uApvwFJNQuutULeM,74131 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=CnHqCDHd-BVGvti_8ZsTolnXNhA3ECsY-6n_2pwU8Hw,6297 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=9nhrP7Ch-NbGX00wvyr4yy-uhNHq2OCc60ggGrni_fk,61513 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=5PF5eHfh8mXAIxXHHRB2xXbXohi8pE3nHSOxa66uS7E,31875 +jinja2/filters.py,sha256=PQ_Egd9n9jSgtnGQYyF4K5j2nYwhUIulhPnyimkdr-k,55212 +jinja2/idtracking.py,sha256=-ll5lIp73pML3ErUYiIJj7tdmWxcH_IlDv3yA_hiZYo,10555 +jinja2/lexer.py,sha256=LYiYio6br-Tep9nPcupWXsPEtjluw3p1mU-lNBVRUfk,29786 +jinja2/loaders.py,sha256=wIrnxjvcbqh5VwW28NSkfotiDq8qNCxIOSFbGUiSLB4,24055 +jinja2/meta.py,sha256=OTDPkaFvU2Hgvx-6akz7154F8BIWaRmvJcBFvwopHww,4397 +jinja2/nativetypes.py,sha256=7GIGALVJgdyL80oZJdQUaUfwSt5q2lSSZbXt0dNf_M4,4210 +jinja2/nodes.py,sha256=m1Duzcr6qhZI8JQ6VyJgUNinjAf5bQzijSmDnMsvUx8,34579 +jinja2/optimizer.py,sha256=rJnCRlQ7pZsEEmMhsQDgC_pKyDHxP5TPS6zVPGsgcu8,1651 +jinja2/parser.py,sha256=lLOFy3sEmHc5IaEHRiH1sQVnId2moUQzhyeJZTtdY30,40383 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=gDk-GvdriJXqgsGbHgrcKTP0Yp6zPXzhzrIpCFH3jAU,34249 +jinja2/sandbox.py,sha256=Mw2aitlY2I8la7FYhcX2YG9BtUYcLnD0Gh3d29cDWrY,15009 +jinja2/tests.py,sha256=VLsBhVFnWg-PxSBz1MhRnNWgP1ovXk3neO1FLQMeC9Q,5926 +jinja2/utils.py,sha256=rRp3o9e7ZKS4fyrWRbELyLcpuGVTFcnooaOa1qx_FIk,24129 +jinja2/visitor.py,sha256=EcnL1PIwf_4RVCOMxsRNuR8AXHbS1qfAdMOE2ngKJz4,3557 diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL new file mode 100644 index 00000000..23d2d7e9 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/WHEEL @@ -0,0 +1,4 @@ +Wheel-Version: 1.0 +Generator: flit 3.11.0 +Root-Is-Purelib: true +Tag: py3-none-any diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt new file mode 100644 index 00000000..abc3eae3 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/entry_points.txt @@ -0,0 +1,3 @@ +[babel.extractors] +jinja2=jinja2.ext:babel_extract[i18n] + diff --git a/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt new file mode 100644 index 00000000..c37cae49 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2-3.1.6.dist-info/licenses/LICENSE.txt @@ -0,0 +1,28 @@ +Copyright 2007 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/venv/lib/python3.12/site-packages/jinja2/__init__.py b/venv/lib/python3.12/site-packages/jinja2/__init__.py new file mode 100644 index 00000000..1a423a3e --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/__init__.py @@ -0,0 +1,38 @@ +"""Jinja is a template engine written in pure Python. It provides a +non-XML syntax that supports inline expressions and an optional +sandboxed environment. +""" + +from .bccache import BytecodeCache as BytecodeCache +from .bccache import FileSystemBytecodeCache as FileSystemBytecodeCache +from .bccache import MemcachedBytecodeCache as MemcachedBytecodeCache +from .environment import Environment as Environment +from .environment import Template as Template +from .exceptions import TemplateAssertionError as TemplateAssertionError +from .exceptions import TemplateError as TemplateError +from .exceptions import TemplateNotFound as TemplateNotFound +from .exceptions import TemplateRuntimeError as TemplateRuntimeError +from .exceptions import TemplatesNotFound as TemplatesNotFound +from .exceptions import TemplateSyntaxError as TemplateSyntaxError +from .exceptions import UndefinedError as UndefinedError +from .loaders import BaseLoader as BaseLoader +from .loaders import ChoiceLoader as ChoiceLoader +from .loaders import DictLoader as DictLoader +from .loaders import FileSystemLoader as FileSystemLoader +from .loaders import FunctionLoader as FunctionLoader +from .loaders import ModuleLoader as ModuleLoader +from .loaders import PackageLoader as PackageLoader +from .loaders import PrefixLoader as PrefixLoader +from .runtime import ChainableUndefined as ChainableUndefined +from .runtime import DebugUndefined as DebugUndefined +from .runtime import make_logging_undefined as make_logging_undefined +from .runtime import StrictUndefined as StrictUndefined +from .runtime import Undefined as Undefined +from .utils import clear_caches as clear_caches +from .utils import is_undefined as is_undefined +from .utils import pass_context as pass_context +from .utils import pass_environment as pass_environment +from .utils import pass_eval_context as pass_eval_context +from .utils import select_autoescape as select_autoescape + +__version__ = "3.1.6" diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7479530cbd0cad565dcb0291b7f3bc7131516f6d GIT binary patch literal 1641 zcmZ9M%Wm676oy9^TM~7@`)=A!S{Q*PBx%zINCWtqrnLhjj)7n{1Vv6I#^ek!Gg73i z+FjqEeT6N2b{-w%?5A*7c}RAi@2z{09?W)%|+lcE^99Nm7t2Nn#;g7T+>_uuH(AqDsTfg zG}nNexT(1g+`=u*4d6CzYiGUcYnt1@>v&!B3h)Nr(7Xz~i8nQ`0dL_g z&FlVlU}97A2JjBv(Yy(~i+43|0q@~G&D+3t@Ey%2@LhZtcn5zr+1=lJ_v?2aePf%R zFl|$kAoOiXOhWq}CFWc1NlB>bQ8OHJVqQ+=*f2)+)yJ&@w_-jNf^fB{ zQ_dMzQ^zf_QHhNgOrEhJbs?z{doPDndI5=ZtFbQ@lIyW~r4K94EnQQW`~U~##*T4h z3v$kEm#Bpljt9(h=CN_&IdaxonIFi^E1eCgqxLd$3Kz^B`tvc0m$q|b_vc38lEWIt zvktZ6f$dSd=abp$U@4^&(i`>{omODq5X)zMsF}V6hjP0U$Sq$<4hvmO&MgK7$0s(o z^cxduo1XYz|3YXBVL6OSGM3O@(eXl+fLFcsMz+6@SQW%4j zda?icG-FvVb1Z9`={b68o`Oo_X(dY_)BM5=d|BD>5kpghj2)tjR`9HHb4t{gj^~vW zloXYeK&BaAzdgar%Bm=-Dyb={D`_ZcDrtdCGyJxIcw1R3N>-JuDOm@ZE)AvU3%;R@ zO(k1Oww0Jlc0i_i%Nh}`u9{{2hTemPK78MO%lM55ZHI{N_2Jda%k#tQv%~HPcG~s5 zUN_V?8;fK&Gk<(S4)74iCDPzXnQt5us-hI*ri72pvS|+Xy|1(31$AMCfURjw1B6_U~(b9HB2G1PsZb-{=tf Zeifm65$eW22qE+FAEo9`d43P3{15xl;E4bL literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/_identifier.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a61f870df94cbb1acac9e95ed78c3fe14f12dfd5 GIT binary patch literal 2122 zcmYL~OKjuT8HHsV?KBOt?5>NVyQH{rn=ZO33e2WJfg&hcWRtcCrm@<1GVvH5C+Vz8 zy=BXcMSDiFY)hs^y-13tBvKDslmv9!$0CbyCQdW|l~=tR6Ywspo{Ki9fRE?g{~lic zm!!bIz4FSpBl!K|&+oj~xD$z7%fZ*brT>}RAHozPE0L9j2a&fUi;-yL{^Hl6|Le-4 zz3|`B+l!AEUS0aP9K8AAPq6H7fA{fUhksYtKiq$2K25MsGtV^kZ1QY&8M};MCNEQ$ zna}dT2j;~JGRqd*I)w;6SmGg!6MTh-s`^yIVvh%`bFT58M(hH3A z66r?}gY-J2NxBJf=(NP>^oWdoM#d=_2BTVnY8Q}zYEwq_U8-x4BGs!@H>eR~)JRYx zpay1}Nor=OnWbh91C^RZYF4RfP;*KxBwGn;1=K>)jFXumGfO6trb?zpW{1o!nSHX5 zv=U?mWFcv%$j(5v$VSvw$*z)Zkd2<~8MTpZC#W4z8(AkwPKKN;IfyzcIR$cxm}G2KQ~BJVZT}yr<+9$g7fPkdGz(1o>m~1M-pXC#jEgKTCb2`zrN|)UQ(Cph27l z2^wzGaF@~W2@MN0Jb*i)VULC$jk+}Q8I3OJ9QWb;6T0Zq1qv7EbTOujfW}!yW0isf z3Q838DHu|4PQjFd8BMy3rb(KnX_}#_ib0X4c*fI!W@)b2j4M+fD=;1_@mK|-^H>#9 zah1n+dHfKr%+)gE>IpyIWBm9DKkh+%Uf$#7eO~VIvd1ev<0t$4 zq|Egky3Q<29StI*>7M6&Y_Gaq}tTW`&!WGXrkUxP@tJ!rKbt?Idqw zH7Cg(H0*f%48^lJKRbmu+-)%Kdc0F(yffrpo^fxFdru%O?m65;Z=TP+A>^D7aq18< zhRo*5Y#vkQu_yCHp3M`-^Tg>qQHSfylLzzU+1zv4-0RN!v-wbG^Wp4TvDmfZUdKz< z@k3E^MagHPG!cgtad;w*I^w7+^tjN|LeB}^U_x(-sv@c}QAN;52}6f;g)tMg1`{<$ z)H6)f_eDctqLB~{kBO!tnsw1KnP?4!nGoiVFjZlWnJ_29>IkdHgyjosD6EmNrox&D zJ0@(K3ELHRU)TfT;>xZi+_rF?n|9@9q_CUO?#)PtxHlv3X5`Ny`OGBD z=kzeI4j2v>VIKcg91z?L*Sp_XmKWQSlHYPk~( za#pDA$P;!FUN87ZM~Xu}+$uj4Yzu^no<>{Q2IbTU;`$)Gc^p% zqfoQ9VXRW9b>!tb10XNgnT1+!52n`yrZkxHyD+{qxPp%z`x7AVb00Udk97xfxxps@ z&t#y1eObWv$Fh&{AS~GEzF_-dp)E}tl?j?DOr~LBx(hSi3y*qbPzlSaI>W&Pjx;@h zU6k>Z%ITCeIbccSgypR`%vLfixA0)ftpSi>vkm%T*}{xN*ZLP zIRMC1lv7}U8o&dqC{|c8@-Rjrtkjb*_3c|7Z`7@xaex1VSC>9t+=zaD=iP@Ntgk+R zS--cr8QoYjBe(L~`qi7uA3xl9|IzxrccYJ%-@5yoU;pZtci;N?-Q|y>YacB?SpCED z`s2;_9l{AhJE%8-2j-k%V@zq)q+-W$vBtgb}YHdp_+8r^t({qa}d`soJ` zS3Z0Y{n^G#SYCe2AAJvpaA{#-;VSY{_|3@6-^qS|_qDCp!o|op{_@@1rNx&QV|O<2 Hg^&CPG8z1U 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..9216219c63f756e482a502ef01a2812b402a38cd GIT binary patch literal 4962 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 V7cDcrZ}g_0edF{U5&8z!{{>S+Pp|+0 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/bccache.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..21c658c2134f413f4d700f2e7c8e55f9c5796ec7 GIT binary patch literal 19333 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 WNbB@f!G2D+PZ@d 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�Pj2Q$lBnE}2=ANvN8* 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

5Ms}-w5+>Wj3*|-gxT_53lurK(J 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

Y_Dx@w!@DSN?Nb)RGC|N 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/environment.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..806984aaf215e71733e27e19367b8f555620323d GIT binary patch literal 76646 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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..579cc2a39dec3646abd9583f89f6957a744cfc55 GIT binary patch literal 7708 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 J=!GBq{{dJUn}q-X literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/ext.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..025d3b4916bbc45daaf69fae252039050b0dbb9a GIT binary patch literal 41901 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/filters.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8d913b2d61b788516a35a17b94d8dbe45c6a2b31 GIT binary patch literal 72313 zcmdSC349#ac_&zXqJaj`xC!uV;vfJLY~F_;k`j26BB_IiL`XEyL>0gWfo`a}K@wm? zhA7zvL?#3+*@P@AhGIFULOG^mCzf-}ikY1m?PfFEAm|Y4;biGVn~is~JCvY_B_^|( z|M$JR8ffs4WM|Spp!#*yt9O3yd*A*3JSQhh!e_^crXz1(m!!X;ANr?2OH7o{m!$KO zEHz59O}2N~8g2Y-Z?yBbqtU_N&PJ#9?ZUUC!`+$Dm|>%LoE@Id%*ISkyE?Kuy^UT@ zyOGXr%;t1PM^0yMV=kvXNc$RnoX$i#uQ3nlEZN(U-&xRD!0BwH3mXeLor82yV-crw zkuGj5=CrS)q;p2&3{K~Dly;UimT@}2V`k^9##x*$KzerLY)%&%(S#tIK#iDjF-%_R@~3&IOGN_`R}@>duXfTq zbT+Qclrkmx7xDtRTCPD`+RZlTDctSQ)8@CbMp-LbNiCIYr+qg~uhaLr&6fVYrIv-$ z*3xXYOiyvUD)Gh_)PmM5dC`lm#s@H7|M$O=@w)%s$Mn%NzthhOjjouPR*zhVad}W) zJnih<9e${#>Fd7hyMW{XAbFi!Auj=B`|x`yey<0lPY1cK_PE(UJq3uq!&=0%=k%QB zH}3YEzx33dOX87pXwbO^tzCxJHYjr$u9nLyy`s+y_wZCd==7{N6n6sH7j0<-in-ikT}(gU9Lrk!hSZpw9cANBJRTC;G4kQ2VfD+#a!v zQv=$#YuYw$G;rx|%R8I!&K|<0n8m;6F;3SqV>IN=XvG$JtGta{Gac;rn`5A-6r&6t z(JXm8*50Ga9IfvEmoZa?yn{=oT0Rd}uatMTX3LLQ#_2Ipll=b~^?d$1b^){Qw$$-B z#=by#Tpwp1Q@y@DJaV6}PgLKdminGB`tq3k_!m(A6Bx6-fQP-mg0Xr6ZQo~U`@UaM z9s4bH?B^NyFHAWc0QK-B!|V#Ipr-(P2WUkC>TmIyB%GTbPd4iiY<@Ei+W;*0x#kmV zIZHlhY44K^KToE>kJ-9(`-!Xlve_y@}U=<#t!i`kIvK9(GmGDhZFLbEIFTKWkduvW(U?^E+uqntSAw6|AJ-wAi>+??>Zd0f$Wx z7xiHjLh?V|A$JoXstHi{9CEfJ-x~SL=tVln>!0Snpc|e?yN-efpb}2qaU3YWTYdrc zb!gNn(Pb~<{Z7m_N|3)Ie-%CWnmiy^%7f^|OUN7M6&lvZM9aBHyI!o|T7q)I9PzJbjiq;je=eei`lfz{HAr%HV{f z0(#{C-`HCT$ESm8gO8N&pSvU4qf&ka`|UR@{fqJV#mwA{z$>A^hA={#^?^_cLz)vX0vg*#4IrhtIN3?u)0xioTQr8QO}*u6^Hi%OqiV+fv%|Jf6>| zj;FlmGnD*&l>B>^l27TF=QFqS2bR)a;C8<71-0|CrQ{bscRPP*DeWuV&aZqy?fiX9 z$zT24?fj9Yw6AeHzxD;S^T(Ew2Q2bpqIlBL8h?QM>8L-QX@fdPT-h^Z0$v6em!+(Svb=|U()lM-|1_+vxW%0`3Wen)Bgg!cn9tMf_fqU zlzHbbtUT~We}qvvBXGEeCHl>g)>G+6T>iZC`-P7TaBHso$LP^-Xgv~G^j~w2zK

    t8Axaowi$ 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/loaders.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f9cdfa80d7c7f584cf3cf8fb9ce93668167faa6 GIT binary patch literal 32337 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/meta.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f5673c5e8cd1e4f1a2db37ba8c25bec57669ebe4 GIT binary patch literal 5478 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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/nodes.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..2373a5396796603475db7a51c61b79473f8cd1ca GIT binary patch literal 58256 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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..8d729dbf9c34bba7b92fffd9922d1c0c067f5106 GIT binary patch literal 2677 zcmaJ@U2Gdg5Z*nX&wp`}HV#Q!epYHA7>d&tih!U(TGG-&LPf$ujo@_kt&?-lw`TX8 zKMbl+CDI3=kwBpmqNPHjs37_XPZhlKLMW)w38YGh2i^=RqUsZ~d%h&C0wZ~Mc6V-e z=9`%vf1k~!5zwI-b5a-x{U#R?!CKME$1p7-8x@g_ZOz3+&5qf+8>{L?9V6i5ZoFy~ z4UDK(X>WbCZsG>W7;dtfDyBd_LG?;*-EoVxlXl8ZZ+uoZ?955Mn9RzUBF(%v_t$nHr};IIu}9&n8u7 zJLOs8!?#0Y<7vkuHP-Wht+DcfYr;Kd-w~6w-gl0FM3vfkSy5#64zH0ZhjzFyq|vghYvQ*vbrhQx0cd73>If zDHvqv+7_3o8W^1Vb?%ikskTM(K<3HHn=mXQU*4stfiJfBH#EPMNeET+=zMMVqdGv9 zMti5T^;yF-yuq;z&RvT@%g}^$K|-NWBoHe}Dn05~M4aJ_Wi2HHc3+!twJlo`5|r z-3d~w1tTO3aKp{#2V{1L8dQN8cxhwt`0PdI?aGhfVwON0Xc@GzM?H&Mi z^dXQuZcTu2#qlcE?txX6h1zV8TwQGj{j%`I4j4|L>jv7i^}`3Rbl!L3&@Y*`_Z~g< z===9BKCtk>ht64chF!3)-2L#C%p*VOkF0<^D#;;6j>(%oxpM6^*Fpf{l`4+omW_Q4EWhd0a2Y7vboYEWU9mt#pp1=+5 zJpR&fP$Tv!eiy%i{WyH1sDb~#I->07BPp~_a)Y>3vXRcUxq&Ovy4$Fs@pwbC@fO(k zAm&k}fpq6>qOfeBiUj>O`a+Ak#~64xhPJP_ZiC*`hd6Y)qe^xf&BTtPX`GLZav33r znE_8L^;j6fOb{1!DC8hJK|RWylBtR=NJHtVK2)Nuk{pIk6vX$-?i93_Ijfp=&*ydM zFm{l%gbCFR<+}~;2un46s9IytxsJIsALn<-eO1T3l9O-*Dbp;umJp^XWQ?Gg$qAJ| z{4Q9|^{l1NEwgYQ+{zJ#$g=c>37`${~sbg?nzn(;Gcbv9A z8a{jY%;BFh{Y@>A?f#|b&c)XkUccJ2YpG|~a;|rAWMSm<@pFCWUOV4^$-k0&a(UZ5 zX9v#=E|b2iWakpu*-W6`-784%-P}a_rp?Vx)R~*l+_;`Vxh+?_wl8&U{|n)4_i|_M zT1VG>rkQ}nO(BDLX(%(a7k#_8YhQQlyBvlwuPbEcdi;WPjd_;)^14>>iYmp?d|H-| zXH}_b25HlTjt>n8_%_pgt!}yD3Gaa`RAjjP55wDF2x3FttimqHwxBIh*ELP3*FHEG zvWGk!BCJYZ4l-b39}G86q7@Ct`me(J5Ke%0@98am!{de7n$3r|2e@tzAKYWkX9u6$F0DC0fX+q-e@bjRNa HCUxDvHm`u3 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..0b0935f4daf224a4692abc7829c2e424b856d178 GIT binary patch literal 61191 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 F{|C6hZ2ABI 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..cb888d06bd45791a66ff4ede8414fba0e9dfa71b GIT binary patch literal 48879 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 z

    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 literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/tests.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5a8b996f1e2b8e68bdde5adff699f0a676c1043f GIT binary patch literal 9038 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 kA$qQTe9=(cZl|{Ln5mEFTRoxA^-pY literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc b/venv/lib/python3.12/site-packages/jinja2/__pycache__/utils.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..26eebe88aa02171cbf82dbdd4d18604776d3f7cf GIT binary patch literal 34851 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 QVZYG2F!^r+5AM`|0l?@cK>z>% literal 0 HcmV?d00001 diff --git a/venv/lib/python3.12/site-packages/jinja2/_identifier.py b/venv/lib/python3.12/site-packages/jinja2/_identifier.py new file mode 100644 index 00000000..928c1503 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/_identifier.py @@ -0,0 +1,6 @@ +import re + +# generated by scripts/generate_identifier_pattern.py +pattern = re.compile( + r"[\w·̀-ͯ·҃-֑҇-ׇֽֿׁׂׅׄؐ-ًؚ-ٰٟۖ-ۜ۟-۪ۤۧۨ-ܑۭܰ-݊ަ-ް߫-߽߳ࠖ-࠙ࠛ-ࠣࠥ-ࠧࠩ-࡙࠭-࡛࣓-ࣣ࣡-ःऺ-़ा-ॏ॑-ॗॢॣঁ-ঃ়া-ৄেৈো-্ৗৢৣ৾ਁ-ਃ਼ਾ-ੂੇੈੋ-੍ੑੰੱੵઁ-ઃ઼ા-ૅે-ૉો-્ૢૣૺ-૿ଁ-ଃ଼ା-ୄେୈୋ-୍ୖୗୢୣஂா-ூெ-ைொ-்ௗఀ-ఄా-ౄె-ైొ-్ౕౖౢౣಁ-ಃ಼ಾ-ೄೆ-ೈೊ-್ೕೖೢೣഀ-ഃ഻഼ാ-ൄെ-ൈൊ-്ൗൢൣංඃ්ා-ුූෘ-ෟෲෳัิ-ฺ็-๎ັິ-ູົຼ່-ໍ༹༘༙༵༷༾༿ཱ-྄྆྇ྍ-ྗྙ-ྼ࿆ါ-ှၖ-ၙၞ-ၠၢ-ၤၧ-ၭၱ-ၴႂ-ႍႏႚ-ႝ፝-፟ᜒ-᜔ᜲ-᜴ᝒᝓᝲᝳ឴-៓៝᠋-᠍ᢅᢆᢩᤠ-ᤫᤰ-᤻ᨗ-ᨛᩕ-ᩞ᩠-᩿᩼᪰-᪽ᬀ-ᬄ᬴-᭄᭫-᭳ᮀ-ᮂᮡ-ᮭ᯦-᯳ᰤ-᰷᳐-᳔᳒-᳨᳭ᳲ-᳴᳷-᳹᷀-᷹᷻-᷿‿⁀⁔⃐-⃥⃜⃡-⃰℘℮⳯-⵿⳱ⷠ-〪ⷿ-゙゚〯꙯ꙴ-꙽ꚞꚟ꛰꛱ꠂ꠆ꠋꠣ-ꠧꢀꢁꢴ-ꣅ꣠-꣱ꣿꤦ-꤭ꥇ-꥓ꦀ-ꦃ꦳-꧀ꧥꨩ-ꨶꩃꩌꩍꩻ-ꩽꪰꪲ-ꪴꪷꪸꪾ꪿꫁ꫫ-ꫯꫵ꫶ꯣ-ꯪ꯬꯭ﬞ︀-️︠-︯︳︴﹍-﹏_𐇽𐋠𐍶-𐍺𐨁-𐨃𐨅𐨆𐨌-𐨏𐨸-𐨿𐨺𐫦𐫥𐴤-𐽆𐴧-𐽐𑀀-𑀂𑀸-𑁆𑁿-𑂂𑂰-𑂺𑄀-𑄂𑄧-𑄴𑅅𑅆𑅳𑆀-𑆂𑆳-𑇀𑇉-𑇌𑈬-𑈷𑈾𑋟-𑋪𑌀-𑌃𑌻𑌼𑌾-𑍄𑍇𑍈𑍋-𑍍𑍗𑍢𑍣𑍦-𑍬𑍰-𑍴𑐵-𑑆𑑞𑒰-𑓃𑖯-𑖵𑖸-𑗀𑗜𑗝𑘰-𑙀𑚫-𑚷𑜝-𑜫𑠬-𑠺𑨁-𑨊𑨳-𑨹𑨻-𑨾𑩇𑩑-𑩛𑪊-𑪙𑰯-𑰶𑰸-𑰿𑲒-𑲧𑲩-𑲶𑴱-𑴶𑴺𑴼𑴽𑴿-𑵅𑵇𑶊-𑶎𑶐𑶑𑶓-𑶗𑻳-𑻶𖫰-𖫴𖬰-𖬶𖽑-𖽾𖾏-𖾒𛲝𛲞𝅥-𝅩𝅭-𝅲𝅻-𝆂𝆅-𝆋𝆪-𝆭𝉂-𝉄𝨀-𝨶𝨻-𝩬𝩵𝪄𝪛-𝪟𝪡-𝪯𞀀-𞀆𞀈-𞀘𞀛-𞀡𞀣𞀤𞀦-𞣐𞀪-𞣖𞥄-𞥊󠄀-󠇯]+" # noqa: B950 +) diff --git a/venv/lib/python3.12/site-packages/jinja2/async_utils.py b/venv/lib/python3.12/site-packages/jinja2/async_utils.py new file mode 100644 index 00000000..f0c14020 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/async_utils.py @@ -0,0 +1,99 @@ +import inspect +import typing as t +from functools import WRAPPER_ASSIGNMENTS +from functools import wraps + +from .utils import _PassArg +from .utils import pass_eval_context + +if t.TYPE_CHECKING: + import typing_extensions as te + +V = t.TypeVar("V") + + +def async_variant(normal_func): # type: ignore + def decorator(async_func): # type: ignore + pass_arg = _PassArg.from_obj(normal_func) + need_eval_context = pass_arg is None + + if pass_arg is _PassArg.environment: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].is_async) + + else: + + def is_async(args: t.Any) -> bool: + return t.cast(bool, args[0].environment.is_async) + + # Take the doc and annotations from the sync function, but the + # name from the async function. Pallets-Sphinx-Themes + # build_function_directive expects __wrapped__ to point to the + # sync function. + async_func_attrs = ("__module__", "__name__", "__qualname__") + normal_func_attrs = tuple(set(WRAPPER_ASSIGNMENTS).difference(async_func_attrs)) + + @wraps(normal_func, assigned=normal_func_attrs) + @wraps(async_func, assigned=async_func_attrs, updated=()) + def wrapper(*args, **kwargs): # type: ignore + b = is_async(args) + + if need_eval_context: + args = args[1:] + + if b: + return async_func(*args, **kwargs) + + return normal_func(*args, **kwargs) + + if need_eval_context: + wrapper = pass_eval_context(wrapper) + + wrapper.jinja_async_variant = True # type: ignore[attr-defined] + return wrapper + + return decorator + + +_common_primitives = {int, float, bool, str, list, dict, tuple, type(None)} + + +async def auto_await(value: t.Union[t.Awaitable["V"], "V"]) -> "V": + # Avoid a costly call to isawaitable + if type(value) in _common_primitives: + return t.cast("V", value) + + if inspect.isawaitable(value): + return await t.cast("t.Awaitable[V]", value) + + return value + + +class _IteratorToAsyncIterator(t.Generic[V]): + def __init__(self, iterator: "t.Iterator[V]"): + self._iterator = iterator + + def __aiter__(self) -> "te.Self": + return self + + async def __anext__(self) -> V: + try: + return next(self._iterator) + except StopIteration as e: + raise StopAsyncIteration(e.value) from e + + +def auto_aiter( + iterable: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> "t.AsyncIterator[V]": + if hasattr(iterable, "__aiter__"): + return iterable.__aiter__() + else: + return _IteratorToAsyncIterator(iter(iterable)) + + +async def auto_to_list( + value: "t.Union[t.AsyncIterable[V], t.Iterable[V]]", +) -> t.List["V"]: + return [x async for x in auto_aiter(value)] diff --git a/venv/lib/python3.12/site-packages/jinja2/bccache.py b/venv/lib/python3.12/site-packages/jinja2/bccache.py new file mode 100644 index 00000000..ada8b099 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/bccache.py @@ -0,0 +1,408 @@ +"""The optional bytecode cache system. This is useful if you have very +complex template situations and the compilation of all those templates +slows down your application too much. + +Situations where this is useful are often forking web applications that +are initialized on the first request. +""" + +import errno +import fnmatch +import marshal +import os +import pickle +import stat +import sys +import tempfile +import typing as t +from hashlib import sha1 +from io import BytesIO +from types import CodeType + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .environment import Environment + + class _MemcachedClient(te.Protocol): + def get(self, key: str) -> bytes: ... + + def set( + self, key: str, value: bytes, timeout: t.Optional[int] = None + ) -> None: ... + + +bc_version = 5 +# Magic bytes to identify Jinja bytecode cache files. Contains the +# Python major and minor version to avoid loading incompatible bytecode +# if a project upgrades its Python version. +bc_magic = ( + b"j2" + + pickle.dumps(bc_version, 2) + + pickle.dumps((sys.version_info[0] << 24) | sys.version_info[1], 2) +) + + +class Bucket: + """Buckets are used to store the bytecode for one template. It's created + and initialized by the bytecode cache and passed to the loading functions. + + The buckets get an internal checksum from the cache assigned and use this + to automatically reject outdated cache material. Individual bytecode + cache subclasses don't have to care about cache invalidation. + """ + + def __init__(self, environment: "Environment", key: str, checksum: str) -> None: + self.environment = environment + self.key = key + self.checksum = checksum + self.reset() + + def reset(self) -> None: + """Resets the bucket (unloads the bytecode).""" + self.code: t.Optional[CodeType] = None + + def load_bytecode(self, f: t.BinaryIO) -> None: + """Loads bytecode from a file or file like object.""" + # make sure the magic header is correct + magic = f.read(len(bc_magic)) + if magic != bc_magic: + self.reset() + return + # the source code of the file changed, we need to reload + checksum = pickle.load(f) + if self.checksum != checksum: + self.reset() + return + # if marshal_load fails then we need to reload + try: + self.code = marshal.load(f) + except (EOFError, ValueError, TypeError): + self.reset() + return + + def write_bytecode(self, f: t.IO[bytes]) -> None: + """Dump the bytecode into the file or file like object passed.""" + if self.code is None: + raise TypeError("can't write empty bucket") + f.write(bc_magic) + pickle.dump(self.checksum, f, 2) + marshal.dump(self.code, f) + + def bytecode_from_string(self, string: bytes) -> None: + """Load bytecode from bytes.""" + self.load_bytecode(BytesIO(string)) + + def bytecode_to_string(self) -> bytes: + """Return the bytecode as bytes.""" + out = BytesIO() + self.write_bytecode(out) + return out.getvalue() + + +class BytecodeCache: + """To implement your own bytecode cache you have to subclass this class + and override :meth:`load_bytecode` and :meth:`dump_bytecode`. Both of + these methods are passed a :class:`~jinja2.bccache.Bucket`. + + A very basic bytecode cache that saves the bytecode on the file system:: + + from os import path + + class MyCache(BytecodeCache): + + def __init__(self, directory): + self.directory = directory + + def load_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + if path.exists(filename): + with open(filename, 'rb') as f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket): + filename = path.join(self.directory, bucket.key) + with open(filename, 'wb') as f: + bucket.write_bytecode(f) + + A more advanced version of a filesystem based bytecode cache is part of + Jinja. + """ + + def load_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to load bytecode into a + bucket. If they are not able to find code in the cache for the + bucket, it must not do anything. + """ + raise NotImplementedError() + + def dump_bytecode(self, bucket: Bucket) -> None: + """Subclasses have to override this method to write the bytecode + from a bucket back to the cache. If it unable to do so it must not + fail silently but raise an exception. + """ + raise NotImplementedError() + + def clear(self) -> None: + """Clears the cache. This method is not used by Jinja but should be + implemented to allow applications to clear the bytecode cache used + by a particular environment. + """ + + def get_cache_key( + self, name: str, filename: t.Optional[t.Union[str]] = None + ) -> str: + """Returns the unique hash key for this template name.""" + hash = sha1(name.encode("utf-8")) + + if filename is not None: + hash.update(f"|{filename}".encode()) + + return hash.hexdigest() + + def get_source_checksum(self, source: str) -> str: + """Returns a checksum for the source.""" + return sha1(source.encode("utf-8")).hexdigest() + + def get_bucket( + self, + environment: "Environment", + name: str, + filename: t.Optional[str], + source: str, + ) -> Bucket: + """Return a cache bucket for the given template. All arguments are + mandatory but filename may be `None`. + """ + key = self.get_cache_key(name, filename) + checksum = self.get_source_checksum(source) + bucket = Bucket(environment, key, checksum) + self.load_bytecode(bucket) + return bucket + + def set_bucket(self, bucket: Bucket) -> None: + """Put the bucket into the cache.""" + self.dump_bytecode(bucket) + + +class FileSystemBytecodeCache(BytecodeCache): + """A bytecode cache that stores bytecode on the filesystem. It accepts + two arguments: The directory where the cache items are stored and a + pattern string that is used to build the filename. + + If no directory is specified a default cache directory is selected. On + Windows the user's temp directory is used, on UNIX systems a directory + is created for the user in the system temp directory. + + The pattern can be used to have multiple separate caches operate on the + same directory. The default pattern is ``'__jinja2_%s.cache'``. ``%s`` + is replaced with the cache key. + + >>> bcc = FileSystemBytecodeCache('/tmp/jinja_cache', '%s.cache') + + This bytecode cache supports clearing of the cache using the clear method. + """ + + def __init__( + self, directory: t.Optional[str] = None, pattern: str = "__jinja2_%s.cache" + ) -> None: + if directory is None: + directory = self._get_default_cache_dir() + self.directory = directory + self.pattern = pattern + + def _get_default_cache_dir(self) -> str: + def _unsafe_dir() -> "te.NoReturn": + raise RuntimeError( + "Cannot determine safe temp directory. You " + "need to explicitly provide one." + ) + + tmpdir = tempfile.gettempdir() + + # On windows the temporary directory is used specific unless + # explicitly forced otherwise. We can just use that. + if os.name == "nt": + return tmpdir + if not hasattr(os, "getuid"): + _unsafe_dir() + + dirname = f"_jinja2-cache-{os.getuid()}" + actual_dir = os.path.join(tmpdir, dirname) + + try: + os.mkdir(actual_dir, stat.S_IRWXU) + except OSError as e: + if e.errno != errno.EEXIST: + raise + try: + os.chmod(actual_dir, stat.S_IRWXU) + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + except OSError as e: + if e.errno != errno.EEXIST: + raise + + actual_dir_stat = os.lstat(actual_dir) + if ( + actual_dir_stat.st_uid != os.getuid() + or not stat.S_ISDIR(actual_dir_stat.st_mode) + or stat.S_IMODE(actual_dir_stat.st_mode) != stat.S_IRWXU + ): + _unsafe_dir() + + return actual_dir + + def _get_cache_filename(self, bucket: Bucket) -> str: + return os.path.join(self.directory, self.pattern % (bucket.key,)) + + def load_bytecode(self, bucket: Bucket) -> None: + filename = self._get_cache_filename(bucket) + + # Don't test for existence before opening the file, since the + # file could disappear after the test before the open. + try: + f = open(filename, "rb") + except (FileNotFoundError, IsADirectoryError, PermissionError): + # PermissionError can occur on Windows when an operation is + # in progress, such as calling clear(). + return + + with f: + bucket.load_bytecode(f) + + def dump_bytecode(self, bucket: Bucket) -> None: + # Write to a temporary file, then rename to the real name after + # writing. This avoids another process reading the file before + # it is fully written. + name = self._get_cache_filename(bucket) + f = tempfile.NamedTemporaryFile( + mode="wb", + dir=os.path.dirname(name), + prefix=os.path.basename(name), + suffix=".tmp", + delete=False, + ) + + def remove_silent() -> None: + try: + os.remove(f.name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + pass + + try: + with f: + bucket.write_bytecode(f) + except BaseException: + remove_silent() + raise + + try: + os.replace(f.name, name) + except OSError: + # Another process may have called clear(). On Windows, + # another program may be holding the file open. + remove_silent() + except BaseException: + remove_silent() + raise + + def clear(self) -> None: + # imported lazily here because google app-engine doesn't support + # write access on the file system and the function does not exist + # normally. + from os import remove + + files = fnmatch.filter(os.listdir(self.directory), self.pattern % ("*",)) + for filename in files: + try: + remove(os.path.join(self.directory, filename)) + except OSError: + pass + + +class MemcachedBytecodeCache(BytecodeCache): + """This class implements a bytecode cache that uses a memcache cache for + storing the information. It does not enforce a specific memcache library + (tummy's memcache or cmemcache) but will accept any class that provides + the minimal interface required. + + Libraries compatible with this class: + + - `cachelib `_ + - `python-memcached `_ + + (Unfortunately the django cache interface is not compatible because it + does not support storing binary data, only text. You can however pass + the underlying cache client to the bytecode cache which is available + as `django.core.cache.cache._client`.) + + The minimal interface for the client passed to the constructor is this: + + .. class:: MinimalClientInterface + + .. method:: set(key, value[, timeout]) + + Stores the bytecode in the cache. `value` is a string and + `timeout` the timeout of the key. If timeout is not provided + a default timeout or no timeout should be assumed, if it's + provided it's an integer with the number of seconds the cache + item should exist. + + .. method:: get(key) + + Returns the value for the cache key. If the item does not + exist in the cache the return value must be `None`. + + The other arguments to the constructor are the prefix for all keys that + is added before the actual cache key and the timeout for the bytecode in + the cache system. We recommend a high (or no) timeout. + + This bytecode cache does not support clearing of used items in the cache. + The clear method is a no-operation function. + + .. versionadded:: 2.7 + Added support for ignoring memcache errors through the + `ignore_memcache_errors` parameter. + """ + + def __init__( + self, + client: "_MemcachedClient", + prefix: str = "jinja2/bytecode/", + timeout: t.Optional[int] = None, + ignore_memcache_errors: bool = True, + ): + self.client = client + self.prefix = prefix + self.timeout = timeout + self.ignore_memcache_errors = ignore_memcache_errors + + def load_bytecode(self, bucket: Bucket) -> None: + try: + code = self.client.get(self.prefix + bucket.key) + except Exception: + if not self.ignore_memcache_errors: + raise + else: + bucket.bytecode_from_string(code) + + def dump_bytecode(self, bucket: Bucket) -> None: + key = self.prefix + bucket.key + value = bucket.bytecode_to_string() + + try: + if self.timeout is not None: + self.client.set(key, value, self.timeout) + else: + self.client.set(key, value) + except Exception: + if not self.ignore_memcache_errors: + raise diff --git a/venv/lib/python3.12/site-packages/jinja2/compiler.py b/venv/lib/python3.12/site-packages/jinja2/compiler.py new file mode 100644 index 00000000..a4ff6a1b --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/compiler.py @@ -0,0 +1,1998 @@ +"""Compiles nodes from the parser into Python code.""" + +import typing as t +from contextlib import contextmanager +from functools import update_wrapper +from io import StringIO +from itertools import chain +from keyword import iskeyword as is_python_keyword + +from markupsafe import escape +from markupsafe import Markup + +from . import nodes +from .exceptions import TemplateAssertionError +from .idtracking import Symbols +from .idtracking import VAR_LOAD_ALIAS +from .idtracking import VAR_LOAD_PARAMETER +from .idtracking import VAR_LOAD_RESOLVE +from .idtracking import VAR_LOAD_UNDEFINED +from .nodes import EvalContext +from .optimizer import Optimizer +from .utils import _PassArg +from .utils import concat +from .visitor import NodeVisitor + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .environment import Environment + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + +operators = { + "eq": "==", + "ne": "!=", + "gt": ">", + "gteq": ">=", + "lt": "<", + "lteq": "<=", + "in": "in", + "notin": "not in", +} + + +def optimizeconst(f: F) -> F: + def new_func( + self: "CodeGenerator", node: nodes.Expr, frame: "Frame", **kwargs: t.Any + ) -> t.Any: + # Only optimize if the frame is not volatile + if self.optimizer is not None and not frame.eval_ctx.volatile: + new_node = self.optimizer.visit(node, frame.eval_ctx) + + if new_node != node: + return self.visit(new_node, frame) + + return f(self, node, frame, **kwargs) + + return update_wrapper(new_func, f) # type: ignore[return-value] + + +def _make_binop(op: str) -> t.Callable[["CodeGenerator", nodes.BinExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.BinExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed and op in self.environment.intercepted_binops # type: ignore + ): + self.write(f"environment.call_binop(context, {op!r}, ") + self.visit(node.left, frame) + self.write(", ") + self.visit(node.right, frame) + else: + self.write("(") + self.visit(node.left, frame) + self.write(f" {op} ") + self.visit(node.right, frame) + + self.write(")") + + return visitor + + +def _make_unop( + op: str, +) -> t.Callable[["CodeGenerator", nodes.UnaryExpr, "Frame"], None]: + @optimizeconst + def visitor(self: "CodeGenerator", node: nodes.UnaryExpr, frame: Frame) -> None: + if ( + self.environment.sandboxed and op in self.environment.intercepted_unops # type: ignore + ): + self.write(f"environment.call_unop(context, {op!r}, ") + self.visit(node.node, frame) + else: + self.write("(" + op) + self.visit(node.node, frame) + + self.write(")") + + return visitor + + +def generate( + node: nodes.Template, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, +) -> t.Optional[str]: + """Generate the python source for a node tree.""" + if not isinstance(node, nodes.Template): + raise TypeError("Can't compile non template nodes") + + generator = environment.code_generator_class( + environment, name, filename, stream, defer_init, optimized + ) + generator.visit(node) + + if stream is None: + return generator.stream.getvalue() # type: ignore + + return None + + +def has_safe_repr(value: t.Any) -> bool: + """Does the node have a safe representation?""" + if value is None or value is NotImplemented or value is Ellipsis: + return True + + if type(value) in {bool, int, float, complex, range, str, Markup}: + return True + + if type(value) in {tuple, list, set, frozenset}: + return all(has_safe_repr(v) for v in value) + + if type(value) is dict: # noqa E721 + return all(has_safe_repr(k) and has_safe_repr(v) for k, v in value.items()) + + return False + + +def find_undeclared( + nodes: t.Iterable[nodes.Node], names: t.Iterable[str] +) -> t.Set[str]: + """Check if the names passed are accessed undeclared. The return value + is a set of all the undeclared names from the sequence of names found. + """ + visitor = UndeclaredNameVisitor(names) + try: + for node in nodes: + visitor.visit(node) + except VisitorExit: + pass + return visitor.undeclared + + +class MacroRef: + def __init__(self, node: t.Union[nodes.Macro, nodes.CallBlock]) -> None: + self.node = node + self.accesses_caller = False + self.accesses_kwargs = False + self.accesses_varargs = False + + +class Frame: + """Holds compile time information for us.""" + + def __init__( + self, + eval_ctx: EvalContext, + parent: t.Optional["Frame"] = None, + level: t.Optional[int] = None, + ) -> None: + self.eval_ctx = eval_ctx + + # the parent of this frame + self.parent = parent + + if parent is None: + self.symbols = Symbols(level=level) + + # in some dynamic inheritance situations the compiler needs to add + # write tests around output statements. + self.require_output_check = False + + # inside some tags we are using a buffer rather than yield statements. + # this for example affects {% filter %} or {% macro %}. If a frame + # is buffered this variable points to the name of the list used as + # buffer. + self.buffer: t.Optional[str] = None + + # the name of the block we're in, otherwise None. + self.block: t.Optional[str] = None + + else: + self.symbols = Symbols(parent.symbols, level=level) + self.require_output_check = parent.require_output_check + self.buffer = parent.buffer + self.block = parent.block + + # a toplevel frame is the root + soft frames such as if conditions. + self.toplevel = False + + # the root frame is basically just the outermost frame, so no if + # conditions. This information is used to optimize inheritance + # situations. + self.rootlevel = False + + # variables set inside of loops and blocks should not affect outer frames, + # but they still needs to be kept track of as part of the active context. + self.loop_frame = False + self.block_frame = False + + # track whether the frame is being used in an if-statement or conditional + # expression as it determines which errors should be raised during runtime + # or compile time. + self.soft_frame = False + + def copy(self) -> "te.Self": + """Create a copy of the current one.""" + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.symbols = self.symbols.copy() + return rv + + def inner(self, isolated: bool = False) -> "Frame": + """Return an inner frame.""" + if isolated: + return Frame(self.eval_ctx, level=self.symbols.level + 1) + return Frame(self.eval_ctx, self) + + def soft(self) -> "te.Self": + """Return a soft frame. A soft frame may not be modified as + standalone thing as it shares the resources with the frame it + was created of, but it's not a rootlevel frame any longer. + + This is only used to implement if-statements and conditional + expressions. + """ + rv = self.copy() + rv.rootlevel = False + rv.soft_frame = True + return rv + + __copy__ = copy + + +class VisitorExit(RuntimeError): + """Exception used by the `UndeclaredNameVisitor` to signal a stop.""" + + +class DependencyFinderVisitor(NodeVisitor): + """A visitor that collects filter and test calls.""" + + def __init__(self) -> None: + self.filters: t.Set[str] = set() + self.tests: t.Set[str] = set() + + def visit_Filter(self, node: nodes.Filter) -> None: + self.generic_visit(node) + self.filters.add(node.name) + + def visit_Test(self, node: nodes.Test) -> None: + self.generic_visit(node) + self.tests.add(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting at blocks.""" + + +class UndeclaredNameVisitor(NodeVisitor): + """A visitor that checks if a name is accessed without being + declared. This is different from the frame visitor as it will + not stop at closure frames. + """ + + def __init__(self, names: t.Iterable[str]) -> None: + self.names = set(names) + self.undeclared: t.Set[str] = set() + + def visit_Name(self, node: nodes.Name) -> None: + if node.ctx == "load" and node.name in self.names: + self.undeclared.add(node.name) + if self.undeclared == self.names: + raise VisitorExit() + else: + self.names.discard(node.name) + + def visit_Block(self, node: nodes.Block) -> None: + """Stop visiting a blocks.""" + + +class CompilerExit(Exception): + """Raised if the compiler encountered a situation where it just + doesn't make sense to further process the code. Any block that + raises such an exception is not further processed. + """ + + +class CodeGenerator(NodeVisitor): + def __init__( + self, + environment: "Environment", + name: t.Optional[str], + filename: t.Optional[str], + stream: t.Optional[t.TextIO] = None, + defer_init: bool = False, + optimized: bool = True, + ) -> None: + if stream is None: + stream = StringIO() + self.environment = environment + self.name = name + self.filename = filename + self.stream = stream + self.created_block_context = False + self.defer_init = defer_init + self.optimizer: t.Optional[Optimizer] = None + + if optimized: + self.optimizer = Optimizer(environment) + + # aliases for imports + self.import_aliases: t.Dict[str, str] = {} + + # a registry for all blocks. Because blocks are moved out + # into the global python scope they are registered here + self.blocks: t.Dict[str, nodes.Block] = {} + + # the number of extends statements so far + self.extends_so_far = 0 + + # some templates have a rootlevel extends. In this case we + # can safely assume that we're a child template and do some + # more optimizations. + self.has_known_extends = False + + # the current line number + self.code_lineno = 1 + + # registry of all filters and tests (global, not block local) + self.tests: t.Dict[str, str] = {} + self.filters: t.Dict[str, str] = {} + + # the debug information + self.debug_info: t.List[t.Tuple[int, int]] = [] + self._write_debug_info: t.Optional[int] = None + + # the number of new lines before the next write() + self._new_lines = 0 + + # the line number of the last written statement + self._last_line = 0 + + # true if nothing was written so far. + self._first_write = True + + # used by the `temporary_identifier` method to get new + # unique, temporary identifier + self._last_identifier = 0 + + # the current indentation + self._indentation = 0 + + # Tracks toplevel assignments + self._assign_stack: t.List[t.Set[str]] = [] + + # Tracks parameter definition blocks + self._param_def_block: t.List[t.Set[str]] = [] + + # Tracks the current context. + self._context_reference_stack = ["context"] + + @property + def optimized(self) -> bool: + return self.optimizer is not None + + # -- Various compilation helpers + + def fail(self, msg: str, lineno: int) -> "te.NoReturn": + """Fail with a :exc:`TemplateAssertionError`.""" + raise TemplateAssertionError(msg, lineno, self.name, self.filename) + + def temporary_identifier(self) -> str: + """Get a new unique identifier.""" + self._last_identifier += 1 + return f"t_{self._last_identifier}" + + def buffer(self, frame: Frame) -> None: + """Enable buffering for the frame from that point onwards.""" + frame.buffer = self.temporary_identifier() + self.writeline(f"{frame.buffer} = []") + + def return_buffer_contents( + self, frame: Frame, force_unescaped: bool = False + ) -> None: + """Return the buffer contents of the frame.""" + if not force_unescaped: + if frame.eval_ctx.volatile: + self.writeline("if context.eval_ctx.autoescape:") + self.indent() + self.writeline(f"return Markup(concat({frame.buffer}))") + self.outdent() + self.writeline("else:") + self.indent() + self.writeline(f"return concat({frame.buffer})") + self.outdent() + return + elif frame.eval_ctx.autoescape: + self.writeline(f"return Markup(concat({frame.buffer}))") + return + self.writeline(f"return concat({frame.buffer})") + + def indent(self) -> None: + """Indent by one.""" + self._indentation += 1 + + def outdent(self, step: int = 1) -> None: + """Outdent by step.""" + self._indentation -= step + + def start_write(self, frame: Frame, node: t.Optional[nodes.Node] = None) -> None: + """Yield or write into the frame buffer.""" + if frame.buffer is None: + self.writeline("yield ", node) + else: + self.writeline(f"{frame.buffer}.append(", node) + + def end_write(self, frame: Frame) -> None: + """End the writing process started by `start_write`.""" + if frame.buffer is not None: + self.write(")") + + def simple_write( + self, s: str, frame: Frame, node: t.Optional[nodes.Node] = None + ) -> None: + """Simple shortcut for start_write + write + end_write.""" + self.start_write(frame, node) + self.write(s) + self.end_write(frame) + + def blockvisit(self, nodes: t.Iterable[nodes.Node], frame: Frame) -> None: + """Visit a list of nodes as block in a frame. If the current frame + is no buffer a dummy ``if 0: yield None`` is written automatically. + """ + try: + self.writeline("pass") + for node in nodes: + self.visit(node, frame) + except CompilerExit: + pass + + def write(self, x: str) -> None: + """Write a string into the output stream.""" + if self._new_lines: + if not self._first_write: + self.stream.write("\n" * self._new_lines) + self.code_lineno += self._new_lines + if self._write_debug_info is not None: + self.debug_info.append((self._write_debug_info, self.code_lineno)) + self._write_debug_info = None + self._first_write = False + self.stream.write(" " * self._indentation) + self._new_lines = 0 + self.stream.write(x) + + def writeline( + self, x: str, node: t.Optional[nodes.Node] = None, extra: int = 0 + ) -> None: + """Combination of newline and write.""" + self.newline(node, extra) + self.write(x) + + def newline(self, node: t.Optional[nodes.Node] = None, extra: int = 0) -> None: + """Add one or more newlines before the next write.""" + self._new_lines = max(self._new_lines, 1 + extra) + if node is not None and node.lineno != self._last_line: + self._write_debug_info = node.lineno + self._last_line = node.lineno + + def signature( + self, + node: t.Union[nodes.Call, nodes.Filter, nodes.Test], + frame: Frame, + extra_kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + ) -> None: + """Writes a function call to the stream for the current node. + A leading comma is added automatically. The extra keyword + arguments may not include python keywords otherwise a syntax + error could occur. The extra keyword arguments should be given + as python dict. + """ + # if any of the given keyword arguments is a python keyword + # we have to make sure that no invalid call is created. + kwarg_workaround = any( + is_python_keyword(t.cast(str, k)) + for k in chain((x.key for x in node.kwargs), extra_kwargs or ()) + ) + + for arg in node.args: + self.write(", ") + self.visit(arg, frame) + + if not kwarg_workaround: + for kwarg in node.kwargs: + self.write(", ") + self.visit(kwarg, frame) + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f", {key}={value}") + if node.dyn_args: + self.write(", *") + self.visit(node.dyn_args, frame) + + if kwarg_workaround: + if node.dyn_kwargs is not None: + self.write(", **dict({") + else: + self.write(", **{") + for kwarg in node.kwargs: + self.write(f"{kwarg.key!r}: ") + self.visit(kwarg.value, frame) + self.write(", ") + if extra_kwargs is not None: + for key, value in extra_kwargs.items(): + self.write(f"{key!r}: {value}, ") + if node.dyn_kwargs is not None: + self.write("}, **") + self.visit(node.dyn_kwargs, frame) + self.write(")") + else: + self.write("}") + + elif node.dyn_kwargs is not None: + self.write(", **") + self.visit(node.dyn_kwargs, frame) + + def pull_dependencies(self, nodes: t.Iterable[nodes.Node]) -> None: + """Find all filter and test names used in the template and + assign them to variables in the compiled namespace. Checking + that the names are registered with the environment is done when + compiling the Filter and Test nodes. If the node is in an If or + CondExpr node, the check is done at runtime instead. + + .. versionchanged:: 3.0 + Filters and tests in If and CondExpr nodes are checked at + runtime instead of compile time. + """ + visitor = DependencyFinderVisitor() + + for node in nodes: + visitor.visit(node) + + for id_map, names, dependency in ( + (self.filters, visitor.filters, "filters"), + ( + self.tests, + visitor.tests, + "tests", + ), + ): + for name in sorted(names): + if name not in id_map: + id_map[name] = self.temporary_identifier() + + # add check during runtime that dependencies used inside of executed + # blocks are defined, as this step may be skipped during compile time + self.writeline("try:") + self.indent() + self.writeline(f"{id_map[name]} = environment.{dependency}[{name!r}]") + self.outdent() + self.writeline("except KeyError:") + self.indent() + self.writeline("@internalcode") + self.writeline(f"def {id_map[name]}(*unused):") + self.indent() + self.writeline( + f'raise TemplateRuntimeError("No {dependency[:-1]}' + f' named {name!r} found.")' + ) + self.outdent() + self.outdent() + + def enter_frame(self, frame: Frame) -> None: + undefs = [] + for target, (action, param) in frame.symbols.loads.items(): + if action == VAR_LOAD_PARAMETER: + pass + elif action == VAR_LOAD_RESOLVE: + self.writeline(f"{target} = {self.get_resolve_func()}({param!r})") + elif action == VAR_LOAD_ALIAS: + self.writeline(f"{target} = {param}") + elif action == VAR_LOAD_UNDEFINED: + undefs.append(target) + else: + raise NotImplementedError("unknown load instruction") + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def leave_frame(self, frame: Frame, with_python_scope: bool = False) -> None: + if not with_python_scope: + undefs = [] + for target in frame.symbols.loads: + undefs.append(target) + if undefs: + self.writeline(f"{' = '.join(undefs)} = missing") + + def choose_async(self, async_value: str = "async ", sync_value: str = "") -> str: + return async_value if self.environment.is_async else sync_value + + def func(self, name: str) -> str: + return f"{self.choose_async()}def {name}" + + def macro_body( + self, node: t.Union[nodes.Macro, nodes.CallBlock], frame: Frame + ) -> t.Tuple[Frame, MacroRef]: + """Dump the function def of a macro or call block.""" + frame = frame.inner() + frame.symbols.analyze_node(node) + macro_ref = MacroRef(node) + + explicit_caller = None + skip_special_params = set() + args = [] + + for idx, arg in enumerate(node.args): + if arg.name == "caller": + explicit_caller = idx + if arg.name in ("kwargs", "varargs"): + skip_special_params.add(arg.name) + args.append(frame.symbols.ref(arg.name)) + + undeclared = find_undeclared(node.body, ("caller", "kwargs", "varargs")) + + if "caller" in undeclared: + # In older Jinja versions there was a bug that allowed caller + # to retain the special behavior even if it was mentioned in + # the argument list. However thankfully this was only really + # working if it was the last argument. So we are explicitly + # checking this now and error out if it is anywhere else in + # the argument list. + if explicit_caller is not None: + try: + node.defaults[explicit_caller - len(node.args)] + except IndexError: + self.fail( + "When defining macros or call blocks the " + 'special "caller" argument must be omitted ' + "or be given a default.", + node.lineno, + ) + else: + args.append(frame.symbols.declare_parameter("caller")) + macro_ref.accesses_caller = True + if "kwargs" in undeclared and "kwargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("kwargs")) + macro_ref.accesses_kwargs = True + if "varargs" in undeclared and "varargs" not in skip_special_params: + args.append(frame.symbols.declare_parameter("varargs")) + macro_ref.accesses_varargs = True + + # macros are delayed, they never require output checks + frame.require_output_check = False + frame.symbols.analyze_node(node) + self.writeline(f"{self.func('macro')}({', '.join(args)}):", node) + self.indent() + + self.buffer(frame) + self.enter_frame(frame) + + self.push_parameter_definitions(frame) + for idx, arg in enumerate(node.args): + ref = frame.symbols.ref(arg.name) + self.writeline(f"if {ref} is missing:") + self.indent() + try: + default = node.defaults[idx - len(node.args)] + except IndexError: + self.writeline( + f'{ref} = undefined("parameter {arg.name!r} was not provided",' + f" name={arg.name!r})" + ) + else: + self.writeline(f"{ref} = ") + self.visit(default, frame) + self.mark_parameter_stored(ref) + self.outdent() + self.pop_parameter_definitions() + + self.blockvisit(node.body, frame) + self.return_buffer_contents(frame, force_unescaped=True) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + return frame, macro_ref + + def macro_def(self, macro_ref: MacroRef, frame: Frame) -> None: + """Dump the macro definition for the def created by macro_body.""" + arg_tuple = ", ".join(repr(x.name) for x in macro_ref.node.args) + name = getattr(macro_ref.node, "name", None) + if len(macro_ref.node.args) == 1: + arg_tuple += "," + self.write( + f"Macro(environment, macro, {name!r}, ({arg_tuple})," + f" {macro_ref.accesses_kwargs!r}, {macro_ref.accesses_varargs!r}," + f" {macro_ref.accesses_caller!r}, context.eval_ctx.autoescape)" + ) + + def position(self, node: nodes.Node) -> str: + """Return a human readable position for the node.""" + rv = f"line {node.lineno}" + if self.name is not None: + rv = f"{rv} in {self.name!r}" + return rv + + def dump_local_context(self, frame: Frame) -> str: + items_kv = ", ".join( + f"{name!r}: {target}" + for name, target in frame.symbols.dump_stores().items() + ) + return f"{{{items_kv}}}" + + def write_commons(self) -> None: + """Writes a common preamble that is used by root and block functions. + Primarily this sets up common local helpers and enforces a generator + through a dead branch. + """ + self.writeline("resolve = context.resolve_or_missing") + self.writeline("undefined = environment.undefined") + self.writeline("concat = environment.concat") + # always use the standard Undefined class for the implicit else of + # conditional expressions + self.writeline("cond_expr_undefined = Undefined") + self.writeline("if 0: yield None") + + def push_parameter_definitions(self, frame: Frame) -> None: + """Pushes all parameter targets from the given frame into a local + stack that permits tracking of yet to be assigned parameters. In + particular this enables the optimization from `visit_Name` to skip + undefined expressions for parameters in macros as macros can reference + otherwise unbound parameters. + """ + self._param_def_block.append(frame.symbols.dump_param_targets()) + + def pop_parameter_definitions(self) -> None: + """Pops the current parameter definitions set.""" + self._param_def_block.pop() + + def mark_parameter_stored(self, target: str) -> None: + """Marks a parameter in the current parameter definitions as stored. + This will skip the enforced undefined checks. + """ + if self._param_def_block: + self._param_def_block[-1].discard(target) + + def push_context_reference(self, target: str) -> None: + self._context_reference_stack.append(target) + + def pop_context_reference(self) -> None: + self._context_reference_stack.pop() + + def get_context_ref(self) -> str: + return self._context_reference_stack[-1] + + def get_resolve_func(self) -> str: + target = self._context_reference_stack[-1] + if target == "context": + return "resolve" + return f"{target}.resolve" + + def derive_context(self, frame: Frame) -> str: + return f"{self.get_context_ref()}.derived({self.dump_local_context(frame)})" + + def parameter_is_undeclared(self, target: str) -> bool: + """Checks if a given target is an undeclared parameter.""" + if not self._param_def_block: + return False + return target in self._param_def_block[-1] + + def push_assign_tracking(self) -> None: + """Pushes a new layer for assignment tracking.""" + self._assign_stack.append(set()) + + def pop_assign_tracking(self, frame: Frame) -> None: + """Pops the topmost level for assignment tracking and updates the + context variables if necessary. + """ + vars = self._assign_stack.pop() + if ( + not frame.block_frame + and not frame.loop_frame + and not frame.toplevel + or not vars + ): + return + public_names = [x for x in vars if x[:1] != "_"] + if len(vars) == 1: + name = next(iter(vars)) + ref = frame.symbols.ref(name) + if frame.loop_frame: + self.writeline(f"_loop_vars[{name!r}] = {ref}") + return + if frame.block_frame: + self.writeline(f"_block_vars[{name!r}] = {ref}") + return + self.writeline(f"context.vars[{name!r}] = {ref}") + else: + if frame.loop_frame: + self.writeline("_loop_vars.update({") + elif frame.block_frame: + self.writeline("_block_vars.update({") + else: + self.writeline("context.vars.update({") + for idx, name in enumerate(sorted(vars)): + if idx: + self.write(", ") + ref = frame.symbols.ref(name) + self.write(f"{name!r}: {ref}") + self.write("})") + if not frame.block_frame and not frame.loop_frame and public_names: + if len(public_names) == 1: + self.writeline(f"context.exported_vars.add({public_names[0]!r})") + else: + names_str = ", ".join(map(repr, sorted(public_names))) + self.writeline(f"context.exported_vars.update(({names_str}))") + + # -- Statement Visitors + + def visit_Template( + self, node: nodes.Template, frame: t.Optional[Frame] = None + ) -> None: + assert frame is None, "no root frame allowed" + eval_ctx = EvalContext(self.environment, self.name) + + from .runtime import async_exported + from .runtime import exported + + if self.environment.is_async: + exported_names = sorted(exported + async_exported) + else: + exported_names = sorted(exported) + + self.writeline("from jinja2.runtime import " + ", ".join(exported_names)) + + # if we want a deferred initialization we cannot move the + # environment into a local name + envenv = "" if self.defer_init else ", environment=environment" + + # do we have an extends tag at all? If not, we can save some + # overhead by just not processing any inheritance code. + have_extends = node.find(nodes.Extends) is not None + + # find all blocks + for block in node.find_all(nodes.Block): + if block.name in self.blocks: + self.fail(f"block {block.name!r} defined twice", block.lineno) + self.blocks[block.name] = block + + # find all imports and import them + for import_ in node.find_all(nodes.ImportedName): + if import_.importname not in self.import_aliases: + imp = import_.importname + self.import_aliases[imp] = alias = self.temporary_identifier() + if "." in imp: + module, obj = imp.rsplit(".", 1) + self.writeline(f"from {module} import {obj} as {alias}") + else: + self.writeline(f"import {imp} as {alias}") + + # add the load name + self.writeline(f"name = {self.name!r}") + + # generate the root render function. + self.writeline( + f"{self.func('root')}(context, missing=missing{envenv}):", extra=1 + ) + self.indent() + self.write_commons() + + # process the root + frame = Frame(eval_ctx) + if "self" in find_undeclared(node.body, ("self",)): + ref = frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + frame.symbols.analyze_node(node) + frame.toplevel = frame.rootlevel = True + frame.require_output_check = have_extends and not self.has_known_extends + if have_extends: + self.writeline("parent_template = None") + self.enter_frame(frame) + self.pull_dependencies(node.body) + self.blockvisit(node.body, frame) + self.leave_frame(frame, with_python_scope=True) + self.outdent() + + # make sure that the parent root is called. + if have_extends: + if not self.has_known_extends: + self.indent() + self.writeline("if parent_template is not None:") + self.indent() + if not self.environment.is_async: + self.writeline("yield from parent_template.root_render_func(context)") + else: + self.writeline("agen = parent_template.root_render_func(context)") + self.writeline("try:") + self.indent() + self.writeline("async for event in agen:") + self.indent() + self.writeline("yield event") + self.outdent() + self.outdent() + self.writeline("finally: await agen.aclose()") + self.outdent(1 + (not self.has_known_extends)) + + # at this point we now have the blocks collected and can visit them too. + for name, block in self.blocks.items(): + self.writeline( + f"{self.func('block_' + name)}(context, missing=missing{envenv}):", + block, + 1, + ) + self.indent() + self.write_commons() + # It's important that we do not make this frame a child of the + # toplevel template. This would cause a variety of + # interesting issues with identifier tracking. + block_frame = Frame(eval_ctx) + block_frame.block_frame = True + undeclared = find_undeclared(block.body, ("self", "super")) + if "self" in undeclared: + ref = block_frame.symbols.declare_parameter("self") + self.writeline(f"{ref} = TemplateReference(context)") + if "super" in undeclared: + ref = block_frame.symbols.declare_parameter("super") + self.writeline(f"{ref} = context.super({name!r}, block_{name})") + block_frame.symbols.analyze_node(block) + block_frame.block = name + self.writeline("_block_vars = {}") + self.enter_frame(block_frame) + self.pull_dependencies(block.body) + self.blockvisit(block.body, block_frame) + self.leave_frame(block_frame, with_python_scope=True) + self.outdent() + + blocks_kv_str = ", ".join(f"{x!r}: block_{x}" for x in self.blocks) + self.writeline(f"blocks = {{{blocks_kv_str}}}", extra=1) + debug_kv_str = "&".join(f"{k}={v}" for k, v in self.debug_info) + self.writeline(f"debug_info = {debug_kv_str!r}") + + def visit_Block(self, node: nodes.Block, frame: Frame) -> None: + """Call a block and register it for the template.""" + level = 0 + if frame.toplevel: + # if we know that we are a child template, there is no need to + # check if we are one + if self.has_known_extends: + return + if self.extends_so_far > 0: + self.writeline("if parent_template is None:") + self.indent() + level += 1 + + if node.scoped: + context = self.derive_context(frame) + else: + context = self.get_context_ref() + + if node.required: + self.writeline(f"if len(context.blocks[{node.name!r}]) <= 1:", node) + self.indent() + self.writeline( + f'raise TemplateRuntimeError("Required block {node.name!r} not found")', + node, + ) + self.outdent() + + if not self.environment.is_async and frame.buffer is None: + self.writeline( + f"yield from context.blocks[{node.name!r}][0]({context})", node + ) + else: + self.writeline(f"gen = context.blocks[{node.name!r}][0]({context})") + self.writeline("try:") + self.indent() + self.writeline( + f"{self.choose_async()}for event in gen:", + node, + ) + self.indent() + self.simple_write("event", frame) + self.outdent() + self.outdent() + self.writeline( + f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" + ) + + self.outdent(level) + + def visit_Extends(self, node: nodes.Extends, frame: Frame) -> None: + """Calls the extender.""" + if not frame.toplevel: + self.fail("cannot use extend from a non top-level scope", node.lineno) + + # if the number of extends statements in general is zero so + # far, we don't have to add a check if something extended + # the template before this one. + if self.extends_so_far > 0: + # if we have a known extends we just add a template runtime + # error into the generated code. We could catch that at compile + # time too, but i welcome it not to confuse users by throwing the + # same error at different times just "because we can". + if not self.has_known_extends: + self.writeline("if parent_template is not None:") + self.indent() + self.writeline('raise TemplateRuntimeError("extended multiple times")') + + # if we have a known extends already we don't need that code here + # as we know that the template execution will end here. + if self.has_known_extends: + raise CompilerExit() + else: + self.outdent() + + self.writeline("parent_template = environment.get_template(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + self.writeline("for name, parent_block in parent_template.blocks.items():") + self.indent() + self.writeline("context.blocks.setdefault(name, []).append(parent_block)") + self.outdent() + + # if this extends statement was in the root level we can take + # advantage of that information and simplify the generated code + # in the top level from this point onwards + if frame.rootlevel: + self.has_known_extends = True + + # and now we have one more + self.extends_so_far += 1 + + def visit_Include(self, node: nodes.Include, frame: Frame) -> None: + """Handles includes.""" + if node.ignore_missing: + self.writeline("try:") + self.indent() + + func_name = "get_or_select_template" + if isinstance(node.template, nodes.Const): + if isinstance(node.template.value, str): + func_name = "get_template" + elif isinstance(node.template.value, (tuple, list)): + func_name = "select_template" + elif isinstance(node.template, (nodes.Tuple, nodes.List)): + func_name = "select_template" + + self.writeline(f"template = environment.{func_name}(", node) + self.visit(node.template, frame) + self.write(f", {self.name!r})") + if node.ignore_missing: + self.outdent() + self.writeline("except TemplateNotFound:") + self.indent() + self.writeline("pass") + self.outdent() + self.writeline("else:") + self.indent() + + def loop_body() -> None: + self.indent() + self.simple_write("event", frame) + self.outdent() + + if node.with_context: + self.writeline( + f"gen = template.root_render_func(" + "template.new_context(context.get_all(), True," + f" {self.dump_local_context(frame)}))" + ) + self.writeline("try:") + self.indent() + self.writeline(f"{self.choose_async()}for event in gen:") + loop_body() + self.outdent() + self.writeline( + f"finally: {self.choose_async('await gen.aclose()', 'gen.close()')}" + ) + elif self.environment.is_async: + self.writeline( + "for event in (await template._get_default_module_async())" + "._body_stream:" + ) + loop_body() + else: + self.writeline("yield from template._get_default_module()._body_stream") + + if node.ignore_missing: + self.outdent() + + def _import_common( + self, node: t.Union[nodes.Import, nodes.FromImport], frame: Frame + ) -> None: + self.write(f"{self.choose_async('await ')}environment.get_template(") + self.visit(node.template, frame) + self.write(f", {self.name!r}).") + + if node.with_context: + f_name = f"make_module{self.choose_async('_async')}" + self.write( + f"{f_name}(context.get_all(), True, {self.dump_local_context(frame)})" + ) + else: + self.write(f"_get_default_module{self.choose_async('_async')}(context)") + + def visit_Import(self, node: nodes.Import, frame: Frame) -> None: + """Visit regular imports.""" + self.writeline(f"{frame.symbols.ref(node.target)} = ", node) + if frame.toplevel: + self.write(f"context.vars[{node.target!r}] = ") + + self._import_common(node, frame) + + if frame.toplevel and not node.target.startswith("_"): + self.writeline(f"context.exported_vars.discard({node.target!r})") + + def visit_FromImport(self, node: nodes.FromImport, frame: Frame) -> None: + """Visit named imports.""" + self.newline(node) + self.write("included_template = ") + self._import_common(node, frame) + var_names = [] + discarded_names = [] + for name in node.names: + if isinstance(name, tuple): + name, alias = name + else: + alias = name + self.writeline( + f"{frame.symbols.ref(alias)} =" + f" getattr(included_template, {name!r}, missing)" + ) + self.writeline(f"if {frame.symbols.ref(alias)} is missing:") + self.indent() + # The position will contain the template name, and will be formatted + # into a string that will be compiled into an f-string. Curly braces + # in the name must be replaced with escapes so that they will not be + # executed as part of the f-string. + position = self.position(node).replace("{", "{{").replace("}", "}}") + message = ( + "the template {included_template.__name__!r}" + f" (imported on {position})" + f" does not export the requested name {name!r}" + ) + self.writeline( + f"{frame.symbols.ref(alias)} = undefined(f{message!r}, name={name!r})" + ) + self.outdent() + if frame.toplevel: + var_names.append(alias) + if not alias.startswith("_"): + discarded_names.append(alias) + + if var_names: + if len(var_names) == 1: + name = var_names[0] + self.writeline(f"context.vars[{name!r}] = {frame.symbols.ref(name)}") + else: + names_kv = ", ".join( + f"{name!r}: {frame.symbols.ref(name)}" for name in var_names + ) + self.writeline(f"context.vars.update({{{names_kv}}})") + if discarded_names: + if len(discarded_names) == 1: + self.writeline(f"context.exported_vars.discard({discarded_names[0]!r})") + else: + names_str = ", ".join(map(repr, discarded_names)) + self.writeline( + f"context.exported_vars.difference_update(({names_str}))" + ) + + def visit_For(self, node: nodes.For, frame: Frame) -> None: + loop_frame = frame.inner() + loop_frame.loop_frame = True + test_frame = frame.inner() + else_frame = frame.inner() + + # try to figure out if we have an extended loop. An extended loop + # is necessary if the loop is in recursive mode if the special loop + # variable is accessed in the body if the body is a scoped block. + extended_loop = ( + node.recursive + or "loop" + in find_undeclared(node.iter_child_nodes(only=("body",)), ("loop",)) + or any(block.scoped for block in node.find_all(nodes.Block)) + ) + + loop_ref = None + if extended_loop: + loop_ref = loop_frame.symbols.declare_parameter("loop") + + loop_frame.symbols.analyze_node(node, for_branch="body") + if node.else_: + else_frame.symbols.analyze_node(node, for_branch="else") + + if node.test: + loop_filter_func = self.temporary_identifier() + test_frame.symbols.analyze_node(node, for_branch="test") + self.writeline(f"{self.func(loop_filter_func)}(fiter):", node.test) + self.indent() + self.enter_frame(test_frame) + self.writeline(self.choose_async("async for ", "for ")) + self.visit(node.target, loop_frame) + self.write(" in ") + self.write(self.choose_async("auto_aiter(fiter)", "fiter")) + self.write(":") + self.indent() + self.writeline("if ", node.test) + self.visit(node.test, test_frame) + self.write(":") + self.indent() + self.writeline("yield ") + self.visit(node.target, loop_frame) + self.outdent(3) + self.leave_frame(test_frame, with_python_scope=True) + + # if we don't have an recursive loop we have to find the shadowed + # variables at that point. Because loops can be nested but the loop + # variable is a special one we have to enforce aliasing for it. + if node.recursive: + self.writeline( + f"{self.func('loop')}(reciter, loop_render_func, depth=0):", node + ) + self.indent() + self.buffer(loop_frame) + + # Use the same buffer for the else frame + else_frame.buffer = loop_frame.buffer + + # make sure the loop variable is a special one and raise a template + # assertion error if a loop tries to write to loop + if extended_loop: + self.writeline(f"{loop_ref} = missing") + + for name in node.find_all(nodes.Name): + if name.ctx == "store" and name.name == "loop": + self.fail( + "Can't assign to special loop variable in for-loop target", + name.lineno, + ) + + if node.else_: + iteration_indicator = self.temporary_identifier() + self.writeline(f"{iteration_indicator} = 1") + + self.writeline(self.choose_async("async for ", "for "), node) + self.visit(node.target, loop_frame) + if extended_loop: + self.write(f", {loop_ref} in {self.choose_async('Async')}LoopContext(") + else: + self.write(" in ") + + if node.test: + self.write(f"{loop_filter_func}(") + if node.recursive: + self.write("reciter") + else: + if self.environment.is_async and not extended_loop: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async and not extended_loop: + self.write(")") + if node.test: + self.write(")") + + if node.recursive: + self.write(", undefined, loop_render_func, depth):") + else: + self.write(", undefined):" if extended_loop else ":") + + self.indent() + self.enter_frame(loop_frame) + + self.writeline("_loop_vars = {}") + self.blockvisit(node.body, loop_frame) + if node.else_: + self.writeline(f"{iteration_indicator} = 0") + self.outdent() + self.leave_frame( + loop_frame, with_python_scope=node.recursive and not node.else_ + ) + + if node.else_: + self.writeline(f"if {iteration_indicator}:") + self.indent() + self.enter_frame(else_frame) + self.blockvisit(node.else_, else_frame) + self.leave_frame(else_frame) + self.outdent() + + # if the node was recursive we have to return the buffer contents + # and start the iteration code + if node.recursive: + self.return_buffer_contents(loop_frame) + self.outdent() + self.start_write(frame, node) + self.write(f"{self.choose_async('await ')}loop(") + if self.environment.is_async: + self.write("auto_aiter(") + self.visit(node.iter, frame) + if self.environment.is_async: + self.write(")") + self.write(", loop)") + self.end_write(frame) + + # at the end of the iteration, clear any assignments made in the + # loop from the top level + if self._assign_stack: + self._assign_stack[-1].difference_update(loop_frame.symbols.stores) + + def visit_If(self, node: nodes.If, frame: Frame) -> None: + if_frame = frame.soft() + self.writeline("if ", node) + self.visit(node.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(node.body, if_frame) + self.outdent() + for elif_ in node.elif_: + self.writeline("elif ", elif_) + self.visit(elif_.test, if_frame) + self.write(":") + self.indent() + self.blockvisit(elif_.body, if_frame) + self.outdent() + if node.else_: + self.writeline("else:") + self.indent() + self.blockvisit(node.else_, if_frame) + self.outdent() + + def visit_Macro(self, node: nodes.Macro, frame: Frame) -> None: + macro_frame, macro_ref = self.macro_body(node, frame) + self.newline() + if frame.toplevel: + if not node.name.startswith("_"): + self.write(f"context.exported_vars.add({node.name!r})") + self.writeline(f"context.vars[{node.name!r}] = ") + self.write(f"{frame.symbols.ref(node.name)} = ") + self.macro_def(macro_ref, macro_frame) + + def visit_CallBlock(self, node: nodes.CallBlock, frame: Frame) -> None: + call_frame, macro_ref = self.macro_body(node, frame) + self.writeline("caller = ") + self.macro_def(macro_ref, call_frame) + self.start_write(frame, node) + self.visit_Call(node.call, frame, forward_caller=True) + self.end_write(frame) + + def visit_FilterBlock(self, node: nodes.FilterBlock, frame: Frame) -> None: + filter_frame = frame.inner() + filter_frame.symbols.analyze_node(node) + self.enter_frame(filter_frame) + self.buffer(filter_frame) + self.blockvisit(node.body, filter_frame) + self.start_write(frame, node) + self.visit_Filter(node.filter, filter_frame) + self.end_write(frame) + self.leave_frame(filter_frame) + + def visit_With(self, node: nodes.With, frame: Frame) -> None: + with_frame = frame.inner() + with_frame.symbols.analyze_node(node) + self.enter_frame(with_frame) + for target, expr in zip(node.targets, node.values): + self.newline() + self.visit(target, with_frame) + self.write(" = ") + self.visit(expr, frame) + self.blockvisit(node.body, with_frame) + self.leave_frame(with_frame) + + def visit_ExprStmt(self, node: nodes.ExprStmt, frame: Frame) -> None: + self.newline(node) + self.visit(node.node, frame) + + class _FinalizeInfo(t.NamedTuple): + const: t.Optional[t.Callable[..., str]] + src: t.Optional[str] + + @staticmethod + def _default_finalize(value: t.Any) -> t.Any: + """The default finalize function if the environment isn't + configured with one. Or, if the environment has one, this is + called on that function's output for constants. + """ + return str(value) + + _finalize: t.Optional[_FinalizeInfo] = None + + def _make_finalize(self) -> _FinalizeInfo: + """Build the finalize function to be used on constants and at + runtime. Cached so it's only created once for all output nodes. + + Returns a ``namedtuple`` with the following attributes: + + ``const`` + A function to finalize constant data at compile time. + + ``src`` + Source code to output around nodes to be evaluated at + runtime. + """ + if self._finalize is not None: + return self._finalize + + finalize: t.Optional[t.Callable[..., t.Any]] + finalize = default = self._default_finalize + src = None + + if self.environment.finalize: + src = "environment.finalize(" + env_finalize = self.environment.finalize + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(env_finalize) # type: ignore + ) + finalize = None + + if pass_arg is None: + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(value)) + + else: + src = f"{src}{pass_arg}, " + + if pass_arg == "environment": + + def finalize(value: t.Any) -> t.Any: # noqa: F811 + return default(env_finalize(self.environment, value)) + + self._finalize = self._FinalizeInfo(finalize, src) + return self._finalize + + def _output_const_repr(self, group: t.Iterable[t.Any]) -> str: + """Given a group of constant values converted from ``Output`` + child nodes, produce a string to write to the template module + source. + """ + return repr(concat(group)) + + def _output_child_to_const( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> str: + """Try to optimize a child of an ``Output`` node by trying to + convert it to constant, finalized data at compile time. + + If :exc:`Impossible` is raised, the node is not constant and + will be evaluated at runtime. Any other exception will also be + evaluated at runtime for easier debugging. + """ + const = node.as_const(frame.eval_ctx) + + if frame.eval_ctx.autoescape: + const = escape(const) + + # Template data doesn't go through finalize. + if isinstance(node, nodes.TemplateData): + return str(const) + + return finalize.const(const) # type: ignore + + def _output_child_pre( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code before visiting a child of an + ``Output`` node. + """ + if frame.eval_ctx.volatile: + self.write("(escape if context.eval_ctx.autoescape else str)(") + elif frame.eval_ctx.autoescape: + self.write("escape(") + else: + self.write("str(") + + if finalize.src is not None: + self.write(finalize.src) + + def _output_child_post( + self, node: nodes.Expr, frame: Frame, finalize: _FinalizeInfo + ) -> None: + """Output extra source code after visiting a child of an + ``Output`` node. + """ + self.write(")") + + if finalize.src is not None: + self.write(")") + + def visit_Output(self, node: nodes.Output, frame: Frame) -> None: + # If an extends is active, don't render outside a block. + if frame.require_output_check: + # A top-level extends is known to exist at compile time. + if self.has_known_extends: + return + + self.writeline("if parent_template is None:") + self.indent() + + finalize = self._make_finalize() + body: t.List[t.Union[t.List[t.Any], nodes.Expr]] = [] + + # Evaluate constants at compile time if possible. Each item in + # body will be either a list of static data or a node to be + # evaluated at runtime. + for child in node.nodes: + try: + if not ( + # If the finalize function requires runtime context, + # constants can't be evaluated at compile time. + finalize.const + # Unless it's basic template data that won't be + # finalized anyway. + or isinstance(child, nodes.TemplateData) + ): + raise nodes.Impossible() + + const = self._output_child_to_const(child, frame, finalize) + except (nodes.Impossible, Exception): + # The node was not constant and needs to be evaluated at + # runtime. Or another error was raised, which is easier + # to debug at runtime. + body.append(child) + continue + + if body and isinstance(body[-1], list): + body[-1].append(const) + else: + body.append([const]) + + if frame.buffer is not None: + if len(body) == 1: + self.writeline(f"{frame.buffer}.append(") + else: + self.writeline(f"{frame.buffer}.extend((") + + self.indent() + + for item in body: + if isinstance(item, list): + # A group of constant data to join and output. + val = self._output_const_repr(item) + + if frame.buffer is None: + self.writeline("yield " + val) + else: + self.writeline(val + ",") + else: + if frame.buffer is None: + self.writeline("yield ", item) + else: + self.newline(item) + + # A node to be evaluated at runtime. + self._output_child_pre(item, frame, finalize) + self.visit(item, frame) + self._output_child_post(item, frame, finalize) + + if frame.buffer is not None: + self.write(",") + + if frame.buffer is not None: + self.outdent() + self.writeline(")" if len(body) == 1 else "))") + + if frame.require_output_check: + self.outdent() + + def visit_Assign(self, node: nodes.Assign, frame: Frame) -> None: + self.push_assign_tracking() + + # ``a.b`` is allowed for assignment, and is parsed as an NSRef. However, + # it is only valid if it references a Namespace object. Emit a check for + # that for each ref here, before assignment code is emitted. This can't + # be done in visit_NSRef as the ref could be in the middle of a tuple. + seen_refs: t.Set[str] = set() + + for nsref in node.find_all(nodes.NSRef): + if nsref.name in seen_refs: + # Only emit the check for each reference once, in case the same + # ref is used multiple times in a tuple, `ns.a, ns.b = c, d`. + continue + + seen_refs.add(nsref.name) + ref = frame.symbols.ref(nsref.name) + self.writeline(f"if not isinstance({ref}, Namespace):") + self.indent() + self.writeline( + "raise TemplateRuntimeError" + '("cannot assign attribute on non-namespace object")' + ) + self.outdent() + + self.newline(node) + self.visit(node.target, frame) + self.write(" = ") + self.visit(node.node, frame) + self.pop_assign_tracking(frame) + + def visit_AssignBlock(self, node: nodes.AssignBlock, frame: Frame) -> None: + self.push_assign_tracking() + block_frame = frame.inner() + # This is a special case. Since a set block always captures we + # will disable output checks. This way one can use set blocks + # toplevel even in extended templates. + block_frame.require_output_check = False + block_frame.symbols.analyze_node(node) + self.enter_frame(block_frame) + self.buffer(block_frame) + self.blockvisit(node.body, block_frame) + self.newline(node) + self.visit(node.target, frame) + self.write(" = (Markup if context.eval_ctx.autoescape else identity)(") + if node.filter is not None: + self.visit_Filter(node.filter, block_frame) + else: + self.write(f"concat({block_frame.buffer})") + self.write(")") + self.pop_assign_tracking(frame) + self.leave_frame(block_frame) + + # -- Expression Visitors + + def visit_Name(self, node: nodes.Name, frame: Frame) -> None: + if node.ctx == "store" and ( + frame.toplevel or frame.loop_frame or frame.block_frame + ): + if self._assign_stack: + self._assign_stack[-1].add(node.name) + ref = frame.symbols.ref(node.name) + + # If we are looking up a variable we might have to deal with the + # case where it's undefined. We can skip that case if the load + # instruction indicates a parameter which are always defined. + if node.ctx == "load": + load = frame.symbols.find_load(ref) + if not ( + load is not None + and load[0] == VAR_LOAD_PARAMETER + and not self.parameter_is_undeclared(ref) + ): + self.write( + f"(undefined(name={node.name!r}) if {ref} is missing else {ref})" + ) + return + + self.write(ref) + + def visit_NSRef(self, node: nodes.NSRef, frame: Frame) -> None: + # NSRef is a dotted assignment target a.b=c, but uses a[b]=c internally. + # visit_Assign emits code to validate that each ref is to a Namespace + # object only. That can't be emitted here as the ref could be in the + # middle of a tuple assignment. + ref = frame.symbols.ref(node.name) + self.writeline(f"{ref}[{node.attr!r}]") + + def visit_Const(self, node: nodes.Const, frame: Frame) -> None: + val = node.as_const(frame.eval_ctx) + if isinstance(val, float): + self.write(str(val)) + else: + self.write(repr(val)) + + def visit_TemplateData(self, node: nodes.TemplateData, frame: Frame) -> None: + try: + self.write(repr(node.as_const(frame.eval_ctx))) + except nodes.Impossible: + self.write( + f"(Markup if context.eval_ctx.autoescape else identity)({node.data!r})" + ) + + def visit_Tuple(self, node: nodes.Tuple, frame: Frame) -> None: + self.write("(") + idx = -1 + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write(",)" if idx == 0 else ")") + + def visit_List(self, node: nodes.List, frame: Frame) -> None: + self.write("[") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item, frame) + self.write("]") + + def visit_Dict(self, node: nodes.Dict, frame: Frame) -> None: + self.write("{") + for idx, item in enumerate(node.items): + if idx: + self.write(", ") + self.visit(item.key, frame) + self.write(": ") + self.visit(item.value, frame) + self.write("}") + + visit_Add = _make_binop("+") + visit_Sub = _make_binop("-") + visit_Mul = _make_binop("*") + visit_Div = _make_binop("/") + visit_FloorDiv = _make_binop("//") + visit_Pow = _make_binop("**") + visit_Mod = _make_binop("%") + visit_And = _make_binop("and") + visit_Or = _make_binop("or") + visit_Pos = _make_unop("+") + visit_Neg = _make_unop("-") + visit_Not = _make_unop("not ") + + @optimizeconst + def visit_Concat(self, node: nodes.Concat, frame: Frame) -> None: + if frame.eval_ctx.volatile: + func_name = "(markup_join if context.eval_ctx.volatile else str_join)" + elif frame.eval_ctx.autoescape: + func_name = "markup_join" + else: + func_name = "str_join" + self.write(f"{func_name}((") + for arg in node.nodes: + self.visit(arg, frame) + self.write(", ") + self.write("))") + + @optimizeconst + def visit_Compare(self, node: nodes.Compare, frame: Frame) -> None: + self.write("(") + self.visit(node.expr, frame) + for op in node.ops: + self.visit(op, frame) + self.write(")") + + def visit_Operand(self, node: nodes.Operand, frame: Frame) -> None: + self.write(f" {operators[node.op]} ") + self.visit(node.expr, frame) + + @optimizeconst + def visit_Getattr(self, node: nodes.Getattr, frame: Frame) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getattr(") + self.visit(node.node, frame) + self.write(f", {node.attr!r})") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Getitem(self, node: nodes.Getitem, frame: Frame) -> None: + # slices bypass the environment getitem method. + if isinstance(node.arg, nodes.Slice): + self.visit(node.node, frame) + self.write("[") + self.visit(node.arg, frame) + self.write("]") + else: + if self.environment.is_async: + self.write("(await auto_await(") + + self.write("environment.getitem(") + self.visit(node.node, frame) + self.write(", ") + self.visit(node.arg, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + def visit_Slice(self, node: nodes.Slice, frame: Frame) -> None: + if node.start is not None: + self.visit(node.start, frame) + self.write(":") + if node.stop is not None: + self.visit(node.stop, frame) + if node.step is not None: + self.write(":") + self.visit(node.step, frame) + + @contextmanager + def _filter_test_common( + self, node: t.Union[nodes.Filter, nodes.Test], frame: Frame, is_filter: bool + ) -> t.Iterator[None]: + if self.environment.is_async: + self.write("(await auto_await(") + + if is_filter: + self.write(f"{self.filters[node.name]}(") + func = self.environment.filters.get(node.name) + else: + self.write(f"{self.tests[node.name]}(") + func = self.environment.tests.get(node.name) + + # When inside an If or CondExpr frame, allow the filter to be + # undefined at compile time and only raise an error if it's + # actually called at runtime. See pull_dependencies. + if func is None and not frame.soft_frame: + type_name = "filter" if is_filter else "test" + self.fail(f"No {type_name} named {node.name!r}.", node.lineno) + + pass_arg = { + _PassArg.context: "context", + _PassArg.eval_context: "context.eval_ctx", + _PassArg.environment: "environment", + }.get( + _PassArg.from_obj(func) # type: ignore + ) + + if pass_arg is not None: + self.write(f"{pass_arg}, ") + + # Back to the visitor function to handle visiting the target of + # the filter or test. + yield + + self.signature(node, frame) + self.write(")") + + if self.environment.is_async: + self.write("))") + + @optimizeconst + def visit_Filter(self, node: nodes.Filter, frame: Frame) -> None: + with self._filter_test_common(node, frame, True): + # if the filter node is None we are inside a filter block + # and want to write to the current buffer + if node.node is not None: + self.visit(node.node, frame) + elif frame.eval_ctx.volatile: + self.write( + f"(Markup(concat({frame.buffer}))" + f" if context.eval_ctx.autoescape else concat({frame.buffer}))" + ) + elif frame.eval_ctx.autoescape: + self.write(f"Markup(concat({frame.buffer}))") + else: + self.write(f"concat({frame.buffer})") + + @optimizeconst + def visit_Test(self, node: nodes.Test, frame: Frame) -> None: + with self._filter_test_common(node, frame, False): + self.visit(node.node, frame) + + @optimizeconst + def visit_CondExpr(self, node: nodes.CondExpr, frame: Frame) -> None: + frame = frame.soft() + + def write_expr2() -> None: + if node.expr2 is not None: + self.visit(node.expr2, frame) + return + + self.write( + f'cond_expr_undefined("the inline if-expression on' + f" {self.position(node)} evaluated to false and no else" + f' section was defined.")' + ) + + self.write("(") + self.visit(node.expr1, frame) + self.write(" if ") + self.visit(node.test, frame) + self.write(" else ") + write_expr2() + self.write(")") + + @optimizeconst + def visit_Call( + self, node: nodes.Call, frame: Frame, forward_caller: bool = False + ) -> None: + if self.environment.is_async: + self.write("(await auto_await(") + if self.environment.sandboxed: + self.write("environment.call(context, ") + else: + self.write("context.call(") + self.visit(node.node, frame) + extra_kwargs = {"caller": "caller"} if forward_caller else None + loop_kwargs = {"_loop_vars": "_loop_vars"} if frame.loop_frame else {} + block_kwargs = {"_block_vars": "_block_vars"} if frame.block_frame else {} + if extra_kwargs: + extra_kwargs.update(loop_kwargs, **block_kwargs) + elif loop_kwargs or block_kwargs: + extra_kwargs = dict(loop_kwargs, **block_kwargs) + self.signature(node, frame, extra_kwargs) + self.write(")") + if self.environment.is_async: + self.write("))") + + def visit_Keyword(self, node: nodes.Keyword, frame: Frame) -> None: + self.write(node.key + "=") + self.visit(node.value, frame) + + # -- Unused nodes for extensions + + def visit_MarkSafe(self, node: nodes.MarkSafe, frame: Frame) -> None: + self.write("Markup(") + self.visit(node.expr, frame) + self.write(")") + + def visit_MarkSafeIfAutoescape( + self, node: nodes.MarkSafeIfAutoescape, frame: Frame + ) -> None: + self.write("(Markup if context.eval_ctx.autoescape else identity)(") + self.visit(node.expr, frame) + self.write(")") + + def visit_EnvironmentAttribute( + self, node: nodes.EnvironmentAttribute, frame: Frame + ) -> None: + self.write("environment." + node.name) + + def visit_ExtensionAttribute( + self, node: nodes.ExtensionAttribute, frame: Frame + ) -> None: + self.write(f"environment.extensions[{node.identifier!r}].{node.name}") + + def visit_ImportedName(self, node: nodes.ImportedName, frame: Frame) -> None: + self.write(self.import_aliases[node.importname]) + + def visit_InternalName(self, node: nodes.InternalName, frame: Frame) -> None: + self.write(node.name) + + def visit_ContextReference( + self, node: nodes.ContextReference, frame: Frame + ) -> None: + self.write("context") + + def visit_DerivedContextReference( + self, node: nodes.DerivedContextReference, frame: Frame + ) -> None: + self.write(self.derive_context(frame)) + + def visit_Continue(self, node: nodes.Continue, frame: Frame) -> None: + self.writeline("continue", node) + + def visit_Break(self, node: nodes.Break, frame: Frame) -> None: + self.writeline("break", node) + + def visit_Scope(self, node: nodes.Scope, frame: Frame) -> None: + scope_frame = frame.inner() + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + + def visit_OverlayScope(self, node: nodes.OverlayScope, frame: Frame) -> None: + ctx = self.temporary_identifier() + self.writeline(f"{ctx} = {self.derive_context(frame)}") + self.writeline(f"{ctx}.vars = ") + self.visit(node.context, frame) + self.push_context_reference(ctx) + + scope_frame = frame.inner(isolated=True) + scope_frame.symbols.analyze_node(node) + self.enter_frame(scope_frame) + self.blockvisit(node.body, scope_frame) + self.leave_frame(scope_frame) + self.pop_context_reference() + + def visit_EvalContextModifier( + self, node: nodes.EvalContextModifier, frame: Frame + ) -> None: + for keyword in node.options: + self.writeline(f"context.eval_ctx.{keyword.key} = ") + self.visit(keyword.value, frame) + try: + val = keyword.value.as_const(frame.eval_ctx) + except nodes.Impossible: + frame.eval_ctx.volatile = True + else: + setattr(frame.eval_ctx, keyword.key, val) + + def visit_ScopedEvalContextModifier( + self, node: nodes.ScopedEvalContextModifier, frame: Frame + ) -> None: + old_ctx_name = self.temporary_identifier() + saved_ctx = frame.eval_ctx.save() + self.writeline(f"{old_ctx_name} = context.eval_ctx.save()") + self.visit_EvalContextModifier(node, frame) + for child in node.body: + self.visit(child, frame) + frame.eval_ctx.revert(saved_ctx) + self.writeline(f"context.eval_ctx.revert({old_ctx_name})") diff --git a/venv/lib/python3.12/site-packages/jinja2/constants.py b/venv/lib/python3.12/site-packages/jinja2/constants.py new file mode 100644 index 00000000..41a1c23b --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/constants.py @@ -0,0 +1,20 @@ +#: list of lorem ipsum words used by the lipsum() helper function +LOREM_IPSUM_WORDS = """\ +a ac accumsan ad adipiscing aenean aliquam aliquet amet ante aptent arcu at +auctor augue bibendum blandit class commodo condimentum congue consectetuer +consequat conubia convallis cras cubilia cum curabitur curae cursus dapibus +diam dictum dictumst dignissim dis dolor donec dui duis egestas eget eleifend +elementum elit enim erat eros est et etiam eu euismod facilisi facilisis fames +faucibus felis fermentum feugiat fringilla fusce gravida habitant habitasse hac +hendrerit hymenaeos iaculis id imperdiet in inceptos integer interdum ipsum +justo lacinia lacus laoreet lectus leo libero ligula litora lobortis lorem +luctus maecenas magna magnis malesuada massa mattis mauris metus mi molestie +mollis montes morbi mus nam nascetur natoque nec neque netus nibh nisi nisl non +nonummy nostra nulla nullam nunc odio orci ornare parturient pede pellentesque +penatibus per pharetra phasellus placerat platea porta porttitor posuere +potenti praesent pretium primis proin pulvinar purus quam quis quisque rhoncus +ridiculus risus rutrum sagittis sapien scelerisque sed sem semper senectus sit +sociis sociosqu sodales sollicitudin suscipit suspendisse taciti tellus tempor +tempus tincidunt torquent tortor tristique turpis ullamcorper ultrices +ultricies urna ut varius vehicula vel velit venenatis vestibulum vitae vivamus +viverra volutpat vulputate""" diff --git a/venv/lib/python3.12/site-packages/jinja2/debug.py b/venv/lib/python3.12/site-packages/jinja2/debug.py new file mode 100644 index 00000000..eeeeee78 --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/debug.py @@ -0,0 +1,191 @@ +import sys +import typing as t +from types import CodeType +from types import TracebackType + +from .exceptions import TemplateSyntaxError +from .utils import internal_code +from .utils import missing + +if t.TYPE_CHECKING: + from .runtime import Context + + +def rewrite_traceback_stack(source: t.Optional[str] = None) -> BaseException: + """Rewrite the current exception to replace any tracebacks from + within compiled template code with tracebacks that look like they + came from the template source. + + This must be called within an ``except`` block. + + :param source: For ``TemplateSyntaxError``, the original source if + known. + :return: The original exception with the rewritten traceback. + """ + _, exc_value, tb = sys.exc_info() + exc_value = t.cast(BaseException, exc_value) + tb = t.cast(TracebackType, tb) + + if isinstance(exc_value, TemplateSyntaxError) and not exc_value.translated: + exc_value.translated = True + exc_value.source = source + # Remove the old traceback, otherwise the frames from the + # compiler still show up. + exc_value.with_traceback(None) + # Outside of runtime, so the frame isn't executing template + # code, but it still needs to point at the template. + tb = fake_traceback( + exc_value, None, exc_value.filename or "", exc_value.lineno + ) + else: + # Skip the frame for the render function. + tb = tb.tb_next + + stack = [] + + # Build the stack of traceback object, replacing any in template + # code with the source file and line information. + while tb is not None: + # Skip frames decorated with @internalcode. These are internal + # calls that aren't useful in template debugging output. + if tb.tb_frame.f_code in internal_code: + tb = tb.tb_next + continue + + template = tb.tb_frame.f_globals.get("__jinja_template__") + + if template is not None: + lineno = template.get_corresponding_lineno(tb.tb_lineno) + fake_tb = fake_traceback(exc_value, tb, template.filename, lineno) + stack.append(fake_tb) + else: + stack.append(tb) + + tb = tb.tb_next + + tb_next = None + + # Assign tb_next in reverse to avoid circular references. + for tb in reversed(stack): + tb.tb_next = tb_next + tb_next = tb + + return exc_value.with_traceback(tb_next) + + +def fake_traceback( # type: ignore + exc_value: BaseException, tb: t.Optional[TracebackType], filename: str, lineno: int +) -> TracebackType: + """Produce a new traceback object that looks like it came from the + template source instead of the compiled code. The filename, line + number, and location name will point to the template, and the local + variables will be the current template context. + + :param exc_value: The original exception to be re-raised to create + the new traceback. + :param tb: The original traceback to get the local variables and + code info from. + :param filename: The template filename. + :param lineno: The line number in the template source. + """ + if tb is not None: + # Replace the real locals with the context that would be + # available at that point in the template. + locals = get_template_locals(tb.tb_frame.f_locals) + locals.pop("__jinja_exception__", None) + else: + locals = {} + + globals = { + "__name__": filename, + "__file__": filename, + "__jinja_exception__": exc_value, + } + # Raise an exception at the correct line number. + code: CodeType = compile( + "\n" * (lineno - 1) + "raise __jinja_exception__", filename, "exec" + ) + + # Build a new code object that points to the template file and + # replaces the location with a block name. + location = "template" + + if tb is not None: + function = tb.tb_frame.f_code.co_name + + if function == "root": + location = "top-level template code" + elif function.startswith("block_"): + location = f"block {function[6:]!r}" + + if sys.version_info >= (3, 8): + code = code.replace(co_name=location) + else: + code = CodeType( + code.co_argcount, + code.co_kwonlyargcount, + code.co_nlocals, + code.co_stacksize, + code.co_flags, + code.co_code, + code.co_consts, + code.co_names, + code.co_varnames, + code.co_filename, + location, + code.co_firstlineno, + code.co_lnotab, + code.co_freevars, + code.co_cellvars, + ) + + # Execute the new code, which is guaranteed to raise, and return + # the new traceback without this frame. + try: + exec(code, globals, locals) + except BaseException: + return sys.exc_info()[2].tb_next # type: ignore + + +def get_template_locals(real_locals: t.Mapping[str, t.Any]) -> t.Dict[str, t.Any]: + """Based on the runtime locals, get the context that would be + available at that point in the template. + """ + # Start with the current template context. + ctx: t.Optional[Context] = real_locals.get("context") + + if ctx is not None: + data: t.Dict[str, t.Any] = ctx.get_all().copy() + else: + data = {} + + # Might be in a derived context that only sets local variables + # rather than pushing a context. Local variables follow the scheme + # l_depth_name. Find the highest-depth local that has a value for + # each name. + local_overrides: t.Dict[str, t.Tuple[int, t.Any]] = {} + + for name, value in real_locals.items(): + if not name.startswith("l_") or value is missing: + # Not a template variable, or no longer relevant. + continue + + try: + _, depth_str, name = name.split("_", 2) + depth = int(depth_str) + except ValueError: + continue + + cur_depth = local_overrides.get(name, (-1,))[0] + + if cur_depth < depth: + local_overrides[name] = (depth, value) + + # Modify the context with any derived context. + for name, (_, value) in local_overrides.items(): + if value is missing: + data.pop(name, None) + else: + data[name] = value + + return data diff --git a/venv/lib/python3.12/site-packages/jinja2/defaults.py b/venv/lib/python3.12/site-packages/jinja2/defaults.py new file mode 100644 index 00000000..638cad3d --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/defaults.py @@ -0,0 +1,48 @@ +import typing as t + +from .filters import FILTERS as DEFAULT_FILTERS # noqa: F401 +from .tests import TESTS as DEFAULT_TESTS # noqa: F401 +from .utils import Cycler +from .utils import generate_lorem_ipsum +from .utils import Joiner +from .utils import Namespace + +if t.TYPE_CHECKING: + import typing_extensions as te + +# defaults for the parser / lexer +BLOCK_START_STRING = "{%" +BLOCK_END_STRING = "%}" +VARIABLE_START_STRING = "{{" +VARIABLE_END_STRING = "}}" +COMMENT_START_STRING = "{#" +COMMENT_END_STRING = "#}" +LINE_STATEMENT_PREFIX: t.Optional[str] = None +LINE_COMMENT_PREFIX: t.Optional[str] = None +TRIM_BLOCKS = False +LSTRIP_BLOCKS = False +NEWLINE_SEQUENCE: "te.Literal['\\n', '\\r\\n', '\\r']" = "\n" +KEEP_TRAILING_NEWLINE = False + +# default filters, tests and namespace + +DEFAULT_NAMESPACE = { + "range": range, + "dict": dict, + "lipsum": generate_lorem_ipsum, + "cycler": Cycler, + "joiner": Joiner, + "namespace": Namespace, +} + +# default policies +DEFAULT_POLICIES: t.Dict[str, t.Any] = { + "compiler.ascii_str": True, + "urlize.rel": "noopener", + "urlize.target": None, + "urlize.extra_schemes": None, + "truncate.leeway": 5, + "json.dumps_function": None, + "json.dumps_kwargs": {"sort_keys": True}, + "ext.i18n.trimmed": False, +} diff --git a/venv/lib/python3.12/site-packages/jinja2/environment.py b/venv/lib/python3.12/site-packages/jinja2/environment.py new file mode 100644 index 00000000..0fc6e5be --- /dev/null +++ b/venv/lib/python3.12/site-packages/jinja2/environment.py @@ -0,0 +1,1672 @@ +"""Classes for managing templates and their runtime and compile time +options. +""" + +import os +import typing +import typing as t +import weakref +from collections import ChainMap +from functools import lru_cache +from functools import partial +from functools import reduce +from types import CodeType + +from markupsafe import Markup + +from . import nodes +from .compiler import CodeGenerator +from .compiler import generate +from .defaults import BLOCK_END_STRING +from .defaults import BLOCK_START_STRING +from .defaults import COMMENT_END_STRING +from .defaults import COMMENT_START_STRING +from .defaults import DEFAULT_FILTERS # type: ignore[attr-defined] +from .defaults import DEFAULT_NAMESPACE +from .defaults import DEFAULT_POLICIES +from .defaults import DEFAULT_TESTS # type: ignore[attr-defined] +from .defaults import KEEP_TRAILING_NEWLINE +from .defaults import LINE_COMMENT_PREFIX +from .defaults import LINE_STATEMENT_PREFIX +from .defaults import LSTRIP_BLOCKS +from .defaults import NEWLINE_SEQUENCE +from .defaults import TRIM_BLOCKS +from .defaults import VARIABLE_END_STRING +from .defaults import VARIABLE_START_STRING +from .exceptions import TemplateNotFound +from .exceptions import TemplateRuntimeError +from .exceptions import TemplatesNotFound +from .exceptions import TemplateSyntaxError +from .exceptions import UndefinedError +from .lexer import get_lexer +from .lexer import Lexer +from .lexer import TokenStream +from .nodes import EvalContext +from .parser import Parser +from .runtime import Context +from .runtime import new_context +from .runtime import Undefined +from .utils import _PassArg +from .utils import concat +from .utils import consume +from .utils import import_string +from .utils import internalcode +from .utils import LRUCache +from .utils import missing + +if t.TYPE_CHECKING: + import typing_extensions as te + + from .bccache import BytecodeCache + from .ext import Extension + from .loaders import BaseLoader + +_env_bound = t.TypeVar("_env_bound", bound="Environment") + + +# for direct template usage we have up to ten living environments +@lru_cache(maxsize=10) +def get_spontaneous_environment(cls: t.Type[_env_bound], *args: t.Any) -> _env_bound: + """Return a new spontaneous environment. A spontaneous environment + is used for templates created directly rather than through an + existing environment. + + :param cls: Environment class to create. + :param args: Positional arguments passed to environment. + """ + env = cls(*args) + env.shared = True + return env + + +def create_cache( + size: int, +) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: + """Return the cache class for the given size.""" + if size == 0: + return None + + if size < 0: + return {} + + return LRUCache(size) # type: ignore + + +def copy_cache( + cache: t.Optional[t.MutableMapping[t.Any, t.Any]], +) -> t.Optional[t.MutableMapping[t.Tuple["weakref.ref[t.Any]", str], "Template"]]: + """Create an empty copy of the given cache.""" + if cache is None: + return None + + if type(cache) is dict: # noqa E721 + return {} + + return LRUCache(cache.capacity) # type: ignore + + +def load_extensions( + environment: "Environment", + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]], +) -> t.Dict[str, "Extension"]: + """Load the extensions from the list and bind it to the environment. + Returns a dict of instantiated extensions. + """ + result = {} + + for extension in extensions: + if isinstance(extension, str): + extension = t.cast(t.Type["Extension"], import_string(extension)) + + result[extension.identifier] = extension(environment) + + return result + + +def _environment_config_check(environment: _env_bound) -> _env_bound: + """Perform a sanity check on the environment.""" + assert issubclass( + environment.undefined, Undefined + ), "'undefined' must be a subclass of 'jinja2.Undefined'." + assert ( + environment.block_start_string + != environment.variable_start_string + != environment.comment_start_string + ), "block, variable and comment start strings must be different." + assert environment.newline_sequence in { + "\r", + "\r\n", + "\n", + }, "'newline_sequence' must be one of '\\n', '\\r\\n', or '\\r'." + return environment + + +class Environment: + r"""The core component of Jinja is the `Environment`. It contains + important shared variables like configuration, filters, tests, + globals and others. Instances of this class may be modified if + they are not shared and if no template was loaded so far. + Modifications on environments after the first template was loaded + will lead to surprising effects and undefined behavior. + + Here are the possible initialization parameters: + + `block_start_string` + The string marking the beginning of a block. Defaults to ``'{%'``. + + `block_end_string` + The string marking the end of a block. Defaults to ``'%}'``. + + `variable_start_string` + The string marking the beginning of a print statement. + Defaults to ``'{{'``. + + `variable_end_string` + The string marking the end of a print statement. Defaults to + ``'}}'``. + + `comment_start_string` + The string marking the beginning of a comment. Defaults to ``'{#'``. + + `comment_end_string` + The string marking the end of a comment. Defaults to ``'#}'``. + + `line_statement_prefix` + If given and a string, this will be used as prefix for line based + statements. See also :ref:`line-statements`. + + `line_comment_prefix` + If given and a string, this will be used as prefix for line based + comments. See also :ref:`line-statements`. + + .. versionadded:: 2.2 + + `trim_blocks` + If this is set to ``True`` the first newline after a block is + removed (block, not variable tag!). Defaults to `False`. + + `lstrip_blocks` + If this is set to ``True`` leading spaces and tabs are stripped + from the start of a line to a block. Defaults to `False`. + + `newline_sequence` + The sequence that starts a newline. Must be one of ``'\r'``, + ``'\n'`` or ``'\r\n'``. The default is ``'\n'`` which is a + useful default for Linux and OS X systems as well as web + applications. + + `keep_trailing_newline` + Preserve the trailing newline when rendering templates. + The default is ``False``, which causes a single newline, + if present, to be stripped from the end of the template. + + .. versionadded:: 2.7 + + `extensions` + List of Jinja extensions to use. This can either be import paths + as strings or extension classes. For more information have a + look at :ref:`the extensions documentation `. + + `optimized` + should the optimizer be enabled? Default is ``True``. + + `undefined` + :class:`Undefined` or a subclass of it that is used to represent + undefined values in the template. + + `finalize` + A callable that can be used to process the result of a variable + expression before it is output. For example one can convert + ``None`` implicitly into an empty string here. + + `autoescape` + If set to ``True`` the XML/HTML autoescaping feature is enabled by + default. For more details about autoescaping see + :class:`~markupsafe.Markup`. As of Jinja 2.4 this can also + be a callable that is passed the template name and has to + return ``True`` or ``False`` depending on autoescape should be + enabled by default. + + .. versionchanged:: 2.4 + `autoescape` can now be a function + + `loader` + The template loader for this environment. + + `cache_size` + The size of the cache. Per default this is ``400`` which means + that if more than 400 templates are loaded the loader will clean + out the least recently used template. If the cache size is set to + ``0`` templates are recompiled all the time, if the cache size is + ``-1`` the cache will not be cleaned. + + .. versionchanged:: 2.8 + The cache size was increased to 400 from a low 50. + + `auto_reload` + Some loaders load templates from locations where the template + sources may change (ie: file system or database). If + ``auto_reload`` is set to ``True`` (default) every time a template is + requested the loader checks if the source changed and if yes, it + will reload the template. For higher performance it's possible to + disable that. + + `bytecode_cache` + If set to a bytecode cache object, this object will provide a + cache for the internal Jinja bytecode so that templates don't + have to be parsed if they were not changed. + + See :ref:`bytecode-cache` for more information. + + `enable_async` + If set to true this enables async template execution which + allows using async functions and generators. + """ + + #: if this environment is sandboxed. Modifying this variable won't make + #: the environment sandboxed though. For a real sandboxed environment + #: have a look at jinja2.sandbox. This flag alone controls the code + #: generation by the compiler. + sandboxed = False + + #: True if the environment is just an overlay + overlayed = False + + #: the environment this environment is linked to if it is an overlay + linked_to: t.Optional["Environment"] = None + + #: shared environments have this set to `True`. A shared environment + #: must not be modified + shared = False + + #: the class that is used for code generation. See + #: :class:`~jinja2.compiler.CodeGenerator` for more information. + code_generator_class: t.Type["CodeGenerator"] = CodeGenerator + + concat = "".join + + #: the context class that is used for templates. See + #: :class:`~jinja2.runtime.Context` for more information. + context_class: t.Type[Context] = Context + + template_class: t.Type["Template"] + + def __init__( + self, + block_start_string: str = BLOCK_START_STRING, + block_end_string: str = BLOCK_END_STRING, + variable_start_string: str = VARIABLE_START_STRING, + variable_end_string: str = VARIABLE_END_STRING, + comment_start_string: str = COMMENT_START_STRING, + comment_end_string: str = COMMENT_END_STRING, + line_statement_prefix: t.Optional[str] = LINE_STATEMENT_PREFIX, + line_comment_prefix: t.Optional[str] = LINE_COMMENT_PREFIX, + trim_blocks: bool = TRIM_BLOCKS, + lstrip_blocks: bool = LSTRIP_BLOCKS, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = NEWLINE_SEQUENCE, + keep_trailing_newline: bool = KEEP_TRAILING_NEWLINE, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = (), + optimized: bool = True, + undefined: t.Type[Undefined] = Undefined, + finalize: t.Optional[t.Callable[..., t.Any]] = None, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = False, + loader: t.Optional["BaseLoader"] = None, + cache_size: int = 400, + auto_reload: bool = True, + bytecode_cache: t.Optional["BytecodeCache"] = None, + enable_async: bool = False, + ): + # !!Important notice!! + # The constructor accepts quite a few arguments that should be + # passed by keyword rather than position. However it's important to + # not change the order of arguments because it's used at least + # internally in those cases: + # - spontaneous environments (i18n extension and Template) + # - unittests + # If parameter changes are required only add parameters at the end + # and don't change the arguments (or the defaults!) of the arguments + # existing already. + + # lexer / parser information + self.block_start_string = block_start_string + self.block_end_string = block_end_string + self.variable_start_string = variable_start_string + self.variable_end_string = variable_end_string + self.comment_start_string = comment_start_string + self.comment_end_string = comment_end_string + self.line_statement_prefix = line_statement_prefix + self.line_comment_prefix = line_comment_prefix + self.trim_blocks = trim_blocks + self.lstrip_blocks = lstrip_blocks + self.newline_sequence = newline_sequence + self.keep_trailing_newline = keep_trailing_newline + + # runtime information + self.undefined: t.Type[Undefined] = undefined + self.optimized = optimized + self.finalize = finalize + self.autoescape = autoescape + + # defaults + self.filters = DEFAULT_FILTERS.copy() + self.tests = DEFAULT_TESTS.copy() + self.globals = DEFAULT_NAMESPACE.copy() + + # set the loader provided + self.loader = loader + self.cache = create_cache(cache_size) + self.bytecode_cache = bytecode_cache + self.auto_reload = auto_reload + + # configurable policies + self.policies = DEFAULT_POLICIES.copy() + + # load extensions + self.extensions = load_extensions(self, extensions) + + self.is_async = enable_async + _environment_config_check(self) + + def add_extension(self, extension: t.Union[str, t.Type["Extension"]]) -> None: + """Adds an extension after the environment was created. + + .. versionadded:: 2.5 + """ + self.extensions.update(load_extensions(self, [extension])) + + def extend(self, **attributes: t.Any) -> None: + """Add the items to the instance of the environment if they do not exist + yet. This is used by :ref:`extensions ` to register + callbacks and configuration values without breaking inheritance. + """ + for key, value in attributes.items(): + if not hasattr(self, key): + setattr(self, key, value) + + def overlay( + self, + block_start_string: str = missing, + block_end_string: str = missing, + variable_start_string: str = missing, + variable_end_string: str = missing, + comment_start_string: str = missing, + comment_end_string: str = missing, + line_statement_prefix: t.Optional[str] = missing, + line_comment_prefix: t.Optional[str] = missing, + trim_blocks: bool = missing, + lstrip_blocks: bool = missing, + newline_sequence: "te.Literal['\\n', '\\r\\n', '\\r']" = missing, + keep_trailing_newline: bool = missing, + extensions: t.Sequence[t.Union[str, t.Type["Extension"]]] = missing, + optimized: bool = missing, + undefined: t.Type[Undefined] = missing, + finalize: t.Optional[t.Callable[..., t.Any]] = missing, + autoescape: t.Union[bool, t.Callable[[t.Optional[str]], bool]] = missing, + loader: t.Optional["BaseLoader"] = missing, + cache_size: int = missing, + auto_reload: bool = missing, + bytecode_cache: t.Optional["BytecodeCache"] = missing, + enable_async: bool = missing, + ) -> "te.Self": + """Create a new overlay environment that shares all the data with the + current environment except for cache and the overridden attributes. + Extensions cannot be removed for an overlayed environment. An overlayed + environment automatically gets all the extensions of the environment it + is linked to plus optional extra extensions. + + Creating overlays should happen after the initial environment was set + up completely. Not all attributes are truly linked, some are just + copied over so modifications on the original environment may not shine + through. + + .. versionchanged:: 3.1.5 + ``enable_async`` is applied correctly. + + .. versionchanged:: 3.1.2 + Added the ``newline_sequence``, ``keep_trailing_newline``, + and ``enable_async`` parameters to match ``__init__``. + """ + args = dict(locals()) + del args["self"], args["cache_size"], args["extensions"], args["enable_async"] + + rv = object.__new__(self.__class__) + rv.__dict__.update(self.__dict__) + rv.overlayed = True + rv.linked_to = self + + for key, value in args.items(): + if value is not missing: + setattr(rv, key, value) + + if cache_size is not missing: + rv.cache = create_cache(cache_size) + else: + rv.cache = copy_cache(self.cache) + + rv.extensions = {} + for key, value in self.extensions.items(): + rv.extensions[key] = value.bind(rv) + if extensions is not missing: + rv.extensions.update(load_extensions(rv, extensions)) + + if enable_async is not missing: + rv.is_async = enable_async + + return _environment_config_check(rv) + + @property + def lexer(self) -> Lexer: + """The lexer for this environment.""" + return get_lexer(self) + + def iter_extensions(self) -> t.Iterator["Extension"]: + """Iterates over the extensions by priority.""" + return iter(sorted(self.extensions.values(), key=lambda x: x.priority)) + + def getitem( + self, obj: t.Any, argument: t.Union[str, t.Any] + ) -> t.Union[t.Any, Undefined]: + """Get an item or attribute of an object but prefer the item.""" + try: + return obj[argument] + except (AttributeError, TypeError, LookupError): + if isinstance(argument, str): + try: + attr = str(argument) + except Exception: + pass + else: + try: + return getattr(obj, attr) + except AttributeError: + pass + return self.undefined(obj=obj, name=argument) + + def getattr(self, obj: t.Any, attribute: str) -> t.Any: + """Get an item or attribute of an object but prefer the attribute. + Unlike :meth:`getitem` the attribute *must* be a string. + """ + try: + return getattr(obj, attribute) + except AttributeError: + pass + try: + return obj[attribute] + except (TypeError, LookupError, AttributeError): + return self.undefined(obj=obj, name=attribute) + + def _filter_test_common( + self, + name: t.Union[str, Undefined], + value: t.Any, + args: t.Optional[t.Sequence[t.Any]], + kwargs: t.Optional[t.Mapping[str, t.Any]], + context: t.Optional[Context], + eval_ctx: t.Optional[EvalContext], + is_filter: bool, + ) -> t.Any: + if is_filter: + env_map = self.filters + type_name = "filter" + else: + env_map = self.tests + type_name = "test" + + func = env_map.get(name) # type: ignore + + if func is None: + msg = f"No {type_name} named {name!r}." + + if isinstance(name, Undefined): + try: + name._fail_with_undefined_error() + except Exception as e: + msg = f"{msg} ({e}; did you forget to quote the callable name?)" + + raise TemplateRuntimeError(msg) + + args = [value, *(args if args is not None else ())] + kwargs = kwargs if kwargs is not None else {} + pass_arg = _PassArg.from_obj(func) + + if pass_arg is _PassArg.context: + if context is None: + raise TemplateRuntimeError( + f"Attempted to invoke a context {type_name} without context." + ) + + args.insert(0, context) + elif pass_arg is _PassArg.eval_context: + if eval_ctx is None: + if context is not None: + eval_ctx = context.eval_ctx + else: + eval_ctx = EvalContext(self) + + args.insert(0, eval_ctx) + elif pass_arg is _PassArg.environment: + args.insert(0, self) + + return func(*args, **kwargs) + + def call_filter( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a filter on a value the same way the compiler does. + + This might return a coroutine if the filter is running from an + environment in async mode and the filter supports async + execution. It's your responsibility to await this if needed. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, True + ) + + def call_test( + self, + name: str, + value: t.Any, + args: t.Optional[t.Sequence[t.Any]] = None, + kwargs: t.Optional[t.Mapping[str, t.Any]] = None, + context: t.Optional[Context] = None, + eval_ctx: t.Optional[EvalContext] = None, + ) -> t.Any: + """Invoke a test on a value the same way the compiler does. + + This might return a coroutine if the test is running from an + environment in async mode and the test supports async execution. + It's your responsibility to await this if needed. + + .. versionchanged:: 3.0 + Tests support ``@pass_context``, etc. decorators. Added + the ``context`` and ``eval_ctx`` parameters. + + .. versionadded:: 2.7 + """ + return self._filter_test_common( + name, value, args, kwargs, context, eval_ctx, False + ) + + @internalcode + def parse( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> nodes.Template: + """Parse the sourcecode and return the abstract syntax tree. This + tree of nodes is used by the compiler to convert the template into + executable source- or bytecode. This is useful for debugging or to + extract information from templates. + + If you are :ref:`developing Jinja extensions ` + this gives you a good overview of the node tree generated. + """ + try: + return self._parse(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def _parse( + self, source: str, name: t.Optional[str], filename: t.Optional[str] + ) -> nodes.Template: + """Internal parsing function used by `parse` and `compile`.""" + return Parser(self, source, name, filename).parse() + + def lex( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> t.Iterator[t.Tuple[int, str, str]]: + """Lex the given sourcecode and return a generator that yields + tokens as tuples in the form ``(lineno, token_type, value)``. + This can be useful for :ref:`extension development ` + and debugging templates. + + This does not perform preprocessing. If you want the preprocessing + of the extensions to be applied you have to filter source through + the :meth:`preprocess` method. + """ + source = str(source) + try: + return self.lexer.tokeniter(source, name, filename) + except TemplateSyntaxError: + self.handle_exception(source=source) + + def preprocess( + self, + source: str, + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + ) -> str: + """Preprocesses the source with all extensions. This is automatically + called for all parsing and compiling methods but *not* for :meth:`lex` + because there you usually only want the actual source tokenized. + """ + return reduce( + lambda s, e: e.preprocess(s, name, filename), + self.iter_extensions(), + str(source), + ) + + def _tokenize( + self, + source: str, + name: t.Optional[str], + filename: t.Optional[str] = None, + state: t.Optional[str] = None, + ) -> TokenStream: + """Called by the parser to do the preprocessing and filtering + for all the extensions. Returns a :class:`~jinja2.lexer.TokenStream`. + """ + source = self.preprocess(source, name, filename) + stream = self.lexer.tokenize(source, name, filename, state) + + for ext in self.iter_extensions(): + stream = ext.filter_stream(stream) # type: ignore + + if not isinstance(stream, TokenStream): + stream = TokenStream(stream, name, filename) + + return stream + + def _generate( + self, + source: nodes.Template, + name: t.Optional[str], + filename: t.Optional[str], + defer_init: bool = False, + ) -> str: + """Internal hook that can be overridden to hook a different generate + method in. + + .. versionadded:: 2.5 + """ + return generate( # type: ignore + source, + self, + name, + filename, + defer_init=defer_init, + optimized=self.optimized, + ) + + def _compile(self, source: str, filename: str) -> CodeType: + """Internal hook that can be overridden to hook a different compile + method in. + + .. versionadded:: 2.5 + """ + return compile(source, filename, "exec") + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[False]" = False, + defer_init: bool = False, + ) -> CodeType: ... + + @typing.overload + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: "te.Literal[True]" = ..., + defer_init: bool = False, + ) -> str: ... + + @internalcode + def compile( + self, + source: t.Union[str, nodes.Template], + name: t.Optional[str] = None, + filename: t.Optional[str] = None, + raw: bool = False, + defer_init: bool = False, + ) -> t.Union[str, CodeType]: + """Compile a node or template source code. The `name` parameter is + the load name of the template after it was joined using + :meth:`join_path` if necessary, not the filename on the file system. + the `filename` parameter is the estimated filename of the template on + the file system. If the template came from a database or memory this + can be omitted. + + The return value of this method is a python code object. If the `raw` + parameter is `True` the return value will be a string with python + code equivalent to the bytecode returned otherwise. This method is + mainly used internally. + + `defer_init` is use internally to aid the module code generator. This + causes the generated code to be able to import without the global + environment variable to be set. + + .. versionadded:: 2.4 + `defer_init` parameter added. + """ + source_hint = None + try: + if isinstance(source, str): + source_hint = source + source = self._parse(source, name, filename) + source = self._generate(source, name, filename, defer_init=defer_init) + if raw: + return source + if filename is None: + filename = "