From 1ae9f764e0075139075f395f5006073f4c9da6e3 Mon Sep 17 00:00:00 2001 From: grgr Date: Fri, 21 Oct 2022 17:57:34 +0200 Subject: [PATCH] first commit --- .../Flask-2.2.2.dist-info/INSTALLER | 1 + .../Flask-2.2.2.dist-info/LICENSE.rst | 28 + .../Flask-2.2.2.dist-info/METADATA | 123 + .../Flask-2.2.2.dist-info/RECORD | 54 + .../Flask-2.2.2.dist-info/REQUESTED | 0 .../site-packages/Flask-2.2.2.dist-info/WHEEL | 5 + .../Flask-2.2.2.dist-info/entry_points.txt | 2 + .../Flask-2.2.2.dist-info/top_level.txt | 1 + .../Jinja2-3.1.2.dist-info/INSTALLER | 1 + .../Jinja2-3.1.2.dist-info/LICENSE.rst | 28 + .../Jinja2-3.1.2.dist-info/METADATA | 113 + .../Jinja2-3.1.2.dist-info/RECORD | 58 + .../Jinja2-3.1.2.dist-info/WHEEL | 5 + .../Jinja2-3.1.2.dist-info/entry_points.txt | 2 + .../Jinja2-3.1.2.dist-info/top_level.txt | 1 + .../MarkupSafe-2.1.1.dist-info/INSTALLER | 1 + .../MarkupSafe-2.1.1.dist-info/LICENSE.rst | 28 + .../MarkupSafe-2.1.1.dist-info/METADATA | 101 + .../MarkupSafe-2.1.1.dist-info/RECORD | 14 + .../MarkupSafe-2.1.1.dist-info/WHEEL | 5 + .../MarkupSafe-2.1.1.dist-info/top_level.txt | 1 + .../Werkzeug-2.2.2.dist-info/INSTALLER | 1 + .../Werkzeug-2.2.2.dist-info/LICENSE.rst | 28 + .../Werkzeug-2.2.2.dist-info/METADATA | 126 + .../Werkzeug-2.2.2.dist-info/RECORD | 98 + .../Werkzeug-2.2.2.dist-info/WHEEL | 5 + .../Werkzeug-2.2.2.dist-info/top_level.txt | 1 + .../site-packages/_distutils_hack/__init__.py | 128 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 5124 bytes .../__pycache__/override.cpython-310.pyc | Bin 0 -> 229 bytes .../site-packages/_distutils_hack/override.py | 1 + .../click-8.1.3.dist-info/INSTALLER | 1 + .../click-8.1.3.dist-info/LICENSE.rst | 28 + .../click-8.1.3.dist-info/METADATA | 111 + .../click-8.1.3.dist-info/RECORD | 39 + .../site-packages/click-8.1.3.dist-info/WHEEL | 5 + .../click-8.1.3.dist-info/top_level.txt | 1 + .vcrunch/Lib/site-packages/click/__init__.py | 73 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2612 bytes .../click/__pycache__/_compat.cpython-310.pyc | Bin 0 -> 15750 bytes .../__pycache__/_termui_impl.cpython-310.pyc | Bin 0 -> 16071 bytes .../__pycache__/_textwrap.cpython-310.pyc | Bin 0 -> 1546 bytes .../__pycache__/_winconsole.cpython-310.pyc | Bin 0 -> 7664 bytes .../click/__pycache__/core.cpython-310.pyc | Bin 0 -> 90241 bytes .../__pycache__/decorators.cpython-310.pyc | Bin 0 -> 15612 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 10194 bytes .../__pycache__/formatting.cpython-310.pyc | Bin 0 -> 9457 bytes .../click/__pycache__/globals.cpython-310.pyc | Bin 0 -> 2431 bytes .../click/__pycache__/parser.cpython-310.pyc | Bin 0 -> 13674 bytes .../shell_completion.cpython-310.pyc | Bin 0 -> 16585 bytes .../click/__pycache__/termui.cpython-310.pyc | Bin 0 -> 26215 bytes .../click/__pycache__/testing.cpython-310.pyc | Bin 0 -> 15193 bytes .../click/__pycache__/types.cpython-310.pyc | Bin 0 -> 33242 bytes .../click/__pycache__/utils.cpython-310.pyc | Bin 0 -> 17624 bytes .vcrunch/Lib/site-packages/click/_compat.py | 626 ++ .../Lib/site-packages/click/_termui_impl.py | 717 ++ .vcrunch/Lib/site-packages/click/_textwrap.py | 49 + .../Lib/site-packages/click/_winconsole.py | 279 + .vcrunch/Lib/site-packages/click/core.py | 2998 ++++++ .../Lib/site-packages/click/decorators.py | 497 + .../Lib/site-packages/click/exceptions.py | 287 + .../Lib/site-packages/click/formatting.py | 301 + .vcrunch/Lib/site-packages/click/globals.py | 68 + .vcrunch/Lib/site-packages/click/parser.py | 529 ++ .vcrunch/Lib/site-packages/click/py.typed | 0 .../site-packages/click/shell_completion.py | 580 ++ .vcrunch/Lib/site-packages/click/termui.py | 787 ++ .vcrunch/Lib/site-packages/click/testing.py | 479 + .vcrunch/Lib/site-packages/click/types.py | 1073 +++ .vcrunch/Lib/site-packages/click/utils.py | 580 ++ .../colorama-0.4.5.dist-info/INSTALLER | 1 + .../colorama-0.4.5.dist-info/LICENSE.txt | 27 + .../colorama-0.4.5.dist-info/METADATA | 411 + .../colorama-0.4.5.dist-info/RECORD | 18 + .../colorama-0.4.5.dist-info/WHEEL | 6 + .../colorama-0.4.5.dist-info/top_level.txt | 1 + .../Lib/site-packages/colorama/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 422 bytes .../colorama/__pycache__/ansi.cpython-310.pyc | Bin 0 -> 2983 bytes .../__pycache__/ansitowin32.cpython-310.pyc | Bin 0 -> 8186 bytes .../__pycache__/initialise.cpython-310.pyc | Bin 0 -> 1669 bytes .../__pycache__/win32.cpython-310.pyc | Bin 0 -> 3930 bytes .../__pycache__/winterm.cpython-310.pyc | Bin 0 -> 4546 bytes .vcrunch/Lib/site-packages/colorama/ansi.py | 102 + .../Lib/site-packages/colorama/ansitowin32.py | 266 + .../Lib/site-packages/colorama/initialise.py | 80 + .vcrunch/Lib/site-packages/colorama/win32.py | 152 + .../Lib/site-packages/colorama/winterm.py | 169 + .../site-packages/distutils-precedence.pth | 1 + .vcrunch/Lib/site-packages/flask/__init__.py | 71 + .vcrunch/Lib/site-packages/flask/__main__.py | 3 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2380 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 208 bytes .../flask/__pycache__/app.cpython-310.pyc | Bin 0 -> 74894 bytes .../__pycache__/blueprints.cpython-310.pyc | Bin 0 -> 24185 bytes .../flask/__pycache__/cli.cpython-310.pyc | Bin 0 -> 26873 bytes .../flask/__pycache__/config.cpython-310.pyc | Bin 0 -> 12425 bytes .../flask/__pycache__/ctx.cpython-310.pyc | Bin 0 -> 14459 bytes .../__pycache__/debughelpers.cpython-310.pyc | Bin 0 -> 5922 bytes .../flask/__pycache__/globals.cpython-310.pyc | Bin 0 -> 3298 bytes .../flask/__pycache__/helpers.cpython-310.pyc | Bin 0 -> 24015 bytes .../flask/__pycache__/logging.cpython-310.pyc | Bin 0 -> 2451 bytes .../__pycache__/scaffold.cpython-310.pyc | Bin 0 -> 24710 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 13611 bytes .../flask/__pycache__/signals.cpython-310.pyc | Bin 0 -> 2387 bytes .../__pycache__/templating.cpython-310.pyc | Bin 0 -> 6955 bytes .../flask/__pycache__/testing.cpython-310.pyc | Bin 0 -> 9397 bytes .../flask/__pycache__/typing.cpython-310.pyc | Bin 0 -> 1671 bytes .../flask/__pycache__/views.cpython-310.pyc | Bin 0 -> 5387 bytes .../__pycache__/wrappers.cpython-310.pyc | Bin 0 -> 5074 bytes .vcrunch/Lib/site-packages/flask/app.py | 2548 +++++ .../Lib/site-packages/flask/blueprints.py | 706 ++ .vcrunch/Lib/site-packages/flask/cli.py | 1051 ++ .vcrunch/Lib/site-packages/flask/config.py | 337 + .vcrunch/Lib/site-packages/flask/ctx.py | 438 + .../Lib/site-packages/flask/debughelpers.py | 158 + .vcrunch/Lib/site-packages/flask/globals.py | 107 + .vcrunch/Lib/site-packages/flask/helpers.py | 705 ++ .../Lib/site-packages/flask/json/__init__.py | 342 + .../json/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 11496 bytes .../json/__pycache__/provider.cpython-310.pyc | Bin 0 -> 9342 bytes .../json/__pycache__/tag.cpython-310.pyc | Bin 0 -> 10994 bytes .../Lib/site-packages/flask/json/provider.py | 310 + .vcrunch/Lib/site-packages/flask/json/tag.py | 312 + .vcrunch/Lib/site-packages/flask/logging.py | 74 + .vcrunch/Lib/site-packages/flask/py.typed | 0 .vcrunch/Lib/site-packages/flask/scaffold.py | 898 ++ .vcrunch/Lib/site-packages/flask/sessions.py | 419 + .vcrunch/Lib/site-packages/flask/signals.py | 56 + .../Lib/site-packages/flask/templating.py | 212 + .vcrunch/Lib/site-packages/flask/testing.py | 286 + .vcrunch/Lib/site-packages/flask/typing.py | 80 + .vcrunch/Lib/site-packages/flask/views.py | 188 + .vcrunch/Lib/site-packages/flask/wrappers.py | 171 + .../itsdangerous-2.1.2.dist-info/INSTALLER | 1 + .../itsdangerous-2.1.2.dist-info/LICENSE.rst | 28 + .../itsdangerous-2.1.2.dist-info/METADATA | 97 + .../itsdangerous-2.1.2.dist-info/RECORD | 23 + .../itsdangerous-2.1.2.dist-info/WHEEL | 5 + .../top_level.txt | 1 + .../site-packages/itsdangerous/__init__.py | 19 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 861 bytes .../__pycache__/_json.cpython-310.pyc | Bin 0 -> 916 bytes .../__pycache__/encoding.cpython-310.pyc | Bin 0 -> 1866 bytes .../__pycache__/exc.cpython-310.pyc | Bin 0 -> 3404 bytes .../__pycache__/serializer.cpython-310.pyc | Bin 0 -> 9695 bytes .../__pycache__/signer.cpython-310.pyc | Bin 0 -> 8464 bytes .../__pycache__/timed.cpython-310.pyc | Bin 0 -> 6474 bytes .../__pycache__/url_safe.cpython-310.pyc | Bin 0 -> 2689 bytes .../Lib/site-packages/itsdangerous/_json.py | 16 + .../site-packages/itsdangerous/encoding.py | 54 + .../Lib/site-packages/itsdangerous/exc.py | 107 + .../Lib/site-packages/itsdangerous/py.typed | 0 .../site-packages/itsdangerous/serializer.py | 295 + .../Lib/site-packages/itsdangerous/signer.py | 257 + .../Lib/site-packages/itsdangerous/timed.py | 234 + .../site-packages/itsdangerous/url_safe.py | 80 + .vcrunch/Lib/site-packages/jinja2/__init__.py | 37 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1597 bytes .../__pycache__/_identifier.cpython-310.pyc | Bin 0 -> 2072 bytes .../__pycache__/async_utils.cpython-310.pyc | Bin 0 -> 2709 bytes .../__pycache__/bccache.cpython-310.pyc | Bin 0 -> 13956 bytes .../__pycache__/compiler.cpython-310.pyc | Bin 0 -> 54564 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 1533 bytes .../jinja2/__pycache__/debug.cpython-310.pyc | Bin 0 -> 3989 bytes .../__pycache__/defaults.cpython-310.pyc | Bin 0 -> 1333 bytes .../__pycache__/environment.cpython-310.pyc | Bin 0 -> 53409 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5532 bytes .../jinja2/__pycache__/ext.cpython-310.pyc | Bin 0 -> 25698 bytes .../__pycache__/filters.cpython-310.pyc | Bin 0 -> 51222 bytes .../__pycache__/idtracking.cpython-310.pyc | Bin 0 -> 11084 bytes .../jinja2/__pycache__/lexer.cpython-310.pyc | Bin 0 -> 20439 bytes .../__pycache__/loaders.cpython-310.pyc | Bin 0 -> 20522 bytes .../jinja2/__pycache__/meta.cpython-310.pyc | Bin 0 -> 3808 bytes .../__pycache__/nativetypes.cpython-310.pyc | Bin 0 -> 5009 bytes .../jinja2/__pycache__/nodes.cpython-310.pyc | Bin 0 -> 40324 bytes .../__pycache__/optimizer.cpython-310.pyc | Bin 0 -> 1954 bytes .../jinja2/__pycache__/parser.cpython-310.pyc | Bin 0 -> 27691 bytes .../__pycache__/runtime.cpython-310.pyc | Bin 0 -> 32168 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 11978 bytes .../jinja2/__pycache__/tests.cpython-310.pyc | Bin 0 -> 6709 bytes .../jinja2/__pycache__/utils.cpython-310.pyc | Bin 0 -> 24529 bytes .../__pycache__/visitor.cpython-310.pyc | Bin 0 -> 3973 bytes .../Lib/site-packages/jinja2/_identifier.py | 6 + .../Lib/site-packages/jinja2/async_utils.py | 84 + .vcrunch/Lib/site-packages/jinja2/bccache.py | 406 + .vcrunch/Lib/site-packages/jinja2/compiler.py | 1957 ++++ .../Lib/site-packages/jinja2/constants.py | 20 + .vcrunch/Lib/site-packages/jinja2/debug.py | 191 + .vcrunch/Lib/site-packages/jinja2/defaults.py | 48 + .../Lib/site-packages/jinja2/environment.py | 1667 ++++ .../Lib/site-packages/jinja2/exceptions.py | 166 + .vcrunch/Lib/site-packages/jinja2/ext.py | 859 ++ .vcrunch/Lib/site-packages/jinja2/filters.py | 1840 ++++ .../Lib/site-packages/jinja2/idtracking.py | 318 + .vcrunch/Lib/site-packages/jinja2/lexer.py | 866 ++ .vcrunch/Lib/site-packages/jinja2/loaders.py | 661 ++ .vcrunch/Lib/site-packages/jinja2/meta.py | 111 + .../Lib/site-packages/jinja2/nativetypes.py | 130 + .vcrunch/Lib/site-packages/jinja2/nodes.py | 1204 +++ .../Lib/site-packages/jinja2/optimizer.py | 47 + .vcrunch/Lib/site-packages/jinja2/parser.py | 1032 ++ .vcrunch/Lib/site-packages/jinja2/py.typed | 0 .vcrunch/Lib/site-packages/jinja2/runtime.py | 1053 ++ .vcrunch/Lib/site-packages/jinja2/sandbox.py | 428 + .vcrunch/Lib/site-packages/jinja2/tests.py | 255 + .vcrunch/Lib/site-packages/jinja2/utils.py | 755 ++ .vcrunch/Lib/site-packages/jinja2/visitor.py | 92 + .../Lib/site-packages/markupsafe/__init__.py | 295 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 10631 bytes .../__pycache__/_native.cpython-310.pyc | Bin 0 -> 1999 bytes .../Lib/site-packages/markupsafe/_native.py | 63 + .../Lib/site-packages/markupsafe/_speedups.c | 320 + .../markupsafe/_speedups.cp310-win_amd64.pyd | Bin 0 -> 15872 bytes .../site-packages/markupsafe/_speedups.pyi | 9 + .../Lib/site-packages/markupsafe/py.typed | 0 .../pip-21.2.3.dist-info/INSTALLER | 1 + .../pip-21.2.3.dist-info/LICENSE.txt | 20 + .../pip-21.2.3.dist-info/METADATA | 92 + .../site-packages/pip-21.2.3.dist-info/RECORD | 795 ++ .../pip-21.2.3.dist-info/REQUESTED | 0 .../site-packages/pip-21.2.3.dist-info/WHEEL | 5 + .../pip-21.2.3.dist-info/entry_points.txt | 5 + .../pip-21.2.3.dist-info/top_level.txt | 1 + .vcrunch/Lib/site-packages/pip/__init__.py | 13 + .vcrunch/Lib/site-packages/pip/__main__.py | 31 + .../pip/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 623 bytes .../pip/__pycache__/__main__.cpython-310.pyc | Bin 0 -> 584 bytes .../site-packages/pip/_internal/__init__.py | 19 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 744 bytes .../__pycache__/build_env.cpython-310.pyc | Bin 0 -> 9123 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 7751 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 10713 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 15285 bytes .../__pycache__/main.cpython-310.pyc | Bin 0 -> 568 bytes .../__pycache__/pyproject.cpython-310.pyc | Bin 0 -> 3440 bytes .../self_outdated_check.cpython-310.pyc | Bin 0 -> 4346 bytes .../__pycache__/wheel_builder.cpython-310.pyc | Bin 0 -> 8280 bytes .../site-packages/pip/_internal/build_env.py | 294 + .../Lib/site-packages/pip/_internal/cache.py | 287 + .../pip/_internal/cli/__init__.py | 4 + .../cli/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 263 bytes .../autocompletion.cpython-310.pyc | Bin 0 -> 5164 bytes .../__pycache__/base_command.cpython-310.pyc | Bin 0 -> 5970 bytes .../__pycache__/cmdoptions.cpython-310.pyc | Bin 0 -> 22331 bytes .../command_context.cpython-310.pyc | Bin 0 -> 1297 bytes .../cli/__pycache__/main.cpython-310.pyc | Bin 0 -> 1361 bytes .../__pycache__/main_parser.cpython-310.pyc | Bin 0 -> 2148 bytes .../cli/__pycache__/parser.cpython-310.pyc | Bin 0 -> 9936 bytes .../__pycache__/progress_bars.cpython-310.pyc | Bin 0 -> 7602 bytes .../__pycache__/req_command.cpython-310.pyc | Bin 0 -> 12133 bytes .../cli/__pycache__/spinners.cpython-310.pyc | Bin 0 -> 4937 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 342 bytes .../pip/_internal/cli/autocompletion.py | 163 + .../pip/_internal/cli/base_command.py | 214 + .../pip/_internal/cli/cmdoptions.py | 1009 ++ .../pip/_internal/cli/command_context.py | 27 + .../site-packages/pip/_internal/cli/main.py | 70 + .../pip/_internal/cli/main_parser.py | 87 + .../site-packages/pip/_internal/cli/parser.py | 292 + .../pip/_internal/cli/progress_bars.py | 250 + .../pip/_internal/cli/req_command.py | 453 + .../pip/_internal/cli/spinners.py | 157 + .../pip/_internal/cli/status_codes.py | 6 + .../pip/_internal/commands/__init__.py | 112 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3090 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 6031 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 1562 bytes .../__pycache__/completion.cpython-310.pyc | Bin 0 -> 3126 bytes .../__pycache__/configuration.cpython-310.pyc | Bin 0 -> 8324 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 6682 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 3979 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 2621 bytes .../commands/__pycache__/hash.cpython-310.pyc | Bin 0 -> 2137 bytes .../commands/__pycache__/help.cpython-310.pyc | Bin 0 -> 1300 bytes .../__pycache__/index.cpython-310.pyc | Bin 0 -> 4547 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 17753 bytes .../commands/__pycache__/list.cpython-310.pyc | Bin 0 -> 10053 bytes .../__pycache__/search.cpython-310.pyc | Bin 0 -> 5348 bytes .../commands/__pycache__/show.cpython-310.pyc | Bin 0 -> 8425 bytes .../__pycache__/uninstall.cpython-310.pyc | Bin 0 -> 3095 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4840 bytes .../pip/_internal/commands/cache.py | 216 + .../pip/_internal/commands/check.py | 47 + .../pip/_internal/commands/completion.py | 91 + .../pip/_internal/commands/configuration.py | 266 + .../pip/_internal/commands/debug.py | 204 + .../pip/_internal/commands/download.py | 139 + .../pip/_internal/commands/freeze.py | 84 + .../pip/_internal/commands/hash.py | 55 + .../pip/_internal/commands/help.py | 41 + .../pip/_internal/commands/index.py | 139 + .../pip/_internal/commands/install.py | 750 ++ .../pip/_internal/commands/list.py | 337 + .../pip/_internal/commands/search.py | 164 + .../pip/_internal/commands/show.py | 234 + .../pip/_internal/commands/uninstall.py | 100 + .../pip/_internal/commands/wheel.py | 176 + .../pip/_internal/configuration.py | 403 + .../pip/_internal/distributions/__init__.py | 21 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 791 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1899 bytes .../__pycache__/installed.cpython-310.pyc | Bin 0 -> 1237 bytes .../__pycache__/sdist.cpython-310.pyc | Bin 0 -> 3577 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1574 bytes .../pip/_internal/distributions/base.py | 38 + .../pip/_internal/distributions/installed.py | 22 + .../pip/_internal/distributions/sdist.py | 95 + .../pip/_internal/distributions/wheel.py | 34 + .../site-packages/pip/_internal/exceptions.py | 397 + .../pip/_internal/index/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 217 bytes .../__pycache__/collector.cpython-310.pyc | Bin 0 -> 15941 bytes .../package_finder.cpython-310.pyc | Bin 0 -> 28148 bytes .../index/__pycache__/sources.cpython-310.pyc | Bin 0 -> 7113 bytes .../pip/_internal/index/collector.py | 534 ++ .../pip/_internal/index/package_finder.py | 982 ++ .../pip/_internal/index/sources.py | 224 + .../pip/_internal/locations/__init__.py | 351 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 8357 bytes .../__pycache__/_distutils.cpython-310.pyc | Bin 0 -> 4646 bytes .../__pycache__/_sysconfig.cpython-310.pyc | Bin 0 -> 6232 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1528 bytes .../pip/_internal/locations/_distutils.py | 169 + .../pip/_internal/locations/_sysconfig.py | 219 + .../pip/_internal/locations/base.py | 52 + .../Lib/site-packages/pip/_internal/main.py | 13 + .../pip/_internal/metadata/__init__.py | 48 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1831 bytes .../metadata/__pycache__/base.cpython-310.pyc | Bin 0 -> 9228 bytes .../__pycache__/pkg_resources.cpython-310.pyc | Bin 0 -> 6071 bytes .../pip/_internal/metadata/base.py | 242 + .../pip/_internal/metadata/pkg_resources.py | 153 + .../pip/_internal/models/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 251 bytes .../__pycache__/candidate.cpython-310.pyc | Bin 0 -> 1404 bytes .../__pycache__/direct_url.cpython-310.pyc | Bin 0 -> 7105 bytes .../format_control.cpython-310.pyc | Bin 0 -> 2743 bytes .../models/__pycache__/index.cpython-310.pyc | Bin 0 -> 1229 bytes .../models/__pycache__/link.cpython-310.pyc | Bin 0 -> 10226 bytes .../models/__pycache__/scheme.cpython-310.pyc | Bin 0 -> 1019 bytes .../__pycache__/search_scope.cpython-310.pyc | Bin 0 -> 3482 bytes .../selection_prefs.cpython-310.pyc | Bin 0 -> 1681 bytes .../__pycache__/target_python.cpython-310.pyc | Bin 0 -> 3438 bytes .../models/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 4339 bytes .../pip/_internal/models/candidate.py | 31 + .../pip/_internal/models/direct_url.py | 220 + .../pip/_internal/models/format_control.py | 84 + .../pip/_internal/models/index.py | 32 + .../pip/_internal/models/link.py | 288 + .../pip/_internal/models/scheme.py | 31 + .../pip/_internal/models/search_scope.py | 126 + .../pip/_internal/models/selection_prefs.py | 46 + .../pip/_internal/models/target_python.py | 111 + .../pip/_internal/models/wheel.py | 92 + .../pip/_internal/network/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 239 bytes .../network/__pycache__/auth.cpython-310.pyc | Bin 0 -> 7484 bytes .../network/__pycache__/cache.cpython-310.pyc | Bin 0 -> 2886 bytes .../__pycache__/download.cpython-310.pyc | Bin 0 -> 5456 bytes .../__pycache__/lazy_wheel.cpython-310.pyc | Bin 0 -> 8368 bytes .../__pycache__/session.cpython-310.pyc | Bin 0 -> 10518 bytes .../network/__pycache__/utils.cpython-310.pyc | Bin 0 -> 1435 bytes .../__pycache__/xmlrpc.cpython-310.pyc | Bin 0 -> 2052 bytes .../pip/_internal/network/auth.py | 316 + .../pip/_internal/network/cache.py | 69 + .../pip/_internal/network/download.py | 184 + .../pip/_internal/network/lazy_wheel.py | 210 + .../pip/_internal/network/session.py | 454 + .../pip/_internal/network/utils.py | 96 + .../pip/_internal/network/xmlrpc.py | 60 + .../pip/_internal/operations/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 187 bytes .../__pycache__/check.cpython-310.pyc | Bin 0 -> 3947 bytes .../__pycache__/freeze.cpython-310.pyc | Bin 0 -> 6298 bytes .../__pycache__/prepare.cpython-310.pyc | Bin 0 -> 14259 bytes .../_internal/operations/build/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 193 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 1145 bytes .../metadata_legacy.cpython-310.pyc | Bin 0 -> 1938 bytes .../build/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 1124 bytes .../__pycache__/wheel_legacy.cpython-310.pyc | Bin 0 -> 2523 bytes .../_internal/operations/build/metadata.py | 35 + .../operations/build/metadata_legacy.py | 74 + .../pip/_internal/operations/build/wheel.py | 38 + .../operations/build/wheel_legacy.py | 110 + .../pip/_internal/operations/check.py | 153 + .../pip/_internal/operations/freeze.py | 277 + .../_internal/operations/install/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 251 bytes .../editable_legacy.cpython-310.pyc | Bin 0 -> 1320 bytes .../__pycache__/legacy.cpython-310.pyc | Bin 0 -> 3477 bytes .../install/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 20423 bytes .../operations/install/editable_legacy.py | 47 + .../_internal/operations/install/legacy.py | 132 + .../pip/_internal/operations/install/wheel.py | 803 ++ .../pip/_internal/operations/prepare.py | 655 ++ .../site-packages/pip/_internal/pyproject.py | 183 + .../pip/_internal/req/__init__.py | 94 + .../req/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2589 bytes .../__pycache__/constructors.cpython-310.pyc | Bin 0 -> 11700 bytes .../req/__pycache__/req_file.cpython-310.pyc | Bin 0 -> 13478 bytes .../__pycache__/req_install.cpython-310.pyc | Bin 0 -> 21457 bytes .../req/__pycache__/req_set.cpython-310.pyc | Bin 0 -> 5830 bytes .../__pycache__/req_tracker.cpython-310.pyc | Bin 0 -> 4325 bytes .../__pycache__/req_uninstall.cpython-310.pyc | Bin 0 -> 18823 bytes .../pip/_internal/req/constructors.py | 474 + .../pip/_internal/req/req_file.py | 528 ++ .../pip/_internal/req/req_install.py | 846 ++ .../pip/_internal/req/req_set.py | 190 + .../pip/_internal/req/req_tracker.py | 130 + .../pip/_internal/req/req_uninstall.py | 629 ++ .../pip/_internal/resolution/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 187 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 1012 bytes .../pip/_internal/resolution/base.py | 18 + .../_internal/resolution/legacy/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 194 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 12094 bytes .../_internal/resolution/legacy/resolver.py | 453 + .../resolution/resolvelib/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 198 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 6582 bytes .../__pycache__/candidates.cpython-310.pyc | Bin 0 -> 18880 bytes .../__pycache__/factory.cpython-310.pyc | Bin 0 -> 18551 bytes .../found_candidates.cpython-310.pyc | Bin 0 -> 4816 bytes .../__pycache__/provider.cpython-310.pyc | Bin 0 -> 6798 bytes .../__pycache__/reporter.cpython-310.pyc | Bin 0 -> 3225 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 7456 bytes .../__pycache__/resolver.cpython-310.pyc | Bin 0 -> 7798 bytes .../_internal/resolution/resolvelib/base.py | 144 + .../resolution/resolvelib/candidates.py | 555 ++ .../resolution/resolvelib/factory.py | 700 ++ .../resolution/resolvelib/found_candidates.py | 142 + .../resolution/resolvelib/provider.py | 197 + .../resolution/resolvelib/reporter.py | 69 + .../resolution/resolvelib/requirements.py | 166 + .../resolution/resolvelib/resolver.py | 272 + .../pip/_internal/self_outdated_check.py | 187 + .../pip/_internal/utils/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 182 bytes .../utils/__pycache__/_log.cpython-310.pyc | Bin 0 -> 1511 bytes .../utils/__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 1314 bytes .../utils/__pycache__/compat.cpython-310.pyc | Bin 0 -> 1499 bytes .../compatibility_tags.cpython-310.pyc | Bin 0 -> 4114 bytes .../__pycache__/datetime.cpython-310.pyc | Bin 0 -> 505 bytes .../__pycache__/deprecation.cpython-310.pyc | Bin 0 -> 3030 bytes .../direct_url_helpers.cpython-310.pyc | Bin 0 -> 1823 bytes .../distutils_args.cpython-310.pyc | Bin 0 -> 1090 bytes .../__pycache__/encoding.cpython-310.pyc | Bin 0 -> 1295 bytes .../__pycache__/entrypoints.cpython-310.pyc | Bin 0 -> 1293 bytes .../__pycache__/filesystem.cpython-310.pyc | Bin 0 -> 5152 bytes .../__pycache__/filetypes.cpython-310.pyc | Bin 0 -> 795 bytes .../utils/__pycache__/glibc.cpython-310.pyc | Bin 0 -> 1605 bytes .../utils/__pycache__/hashes.cpython-310.pyc | Bin 0 -> 5009 bytes .../inject_securetransport.cpython-310.pyc | Bin 0 -> 959 bytes .../utils/__pycache__/logging.cpython-310.pyc | Bin 0 -> 9072 bytes .../utils/__pycache__/misc.cpython-310.pyc | Bin 0 -> 21695 bytes .../utils/__pycache__/models.cpython-310.pyc | Bin 0 -> 1824 bytes .../__pycache__/packaging.cpython-310.pyc | Bin 0 -> 2512 bytes .../__pycache__/parallel.cpython-310.pyc | Bin 0 -> 3024 bytes .../__pycache__/pkg_resources.cpython-310.pyc | Bin 0 -> 1692 bytes .../setuptools_build.cpython-310.pyc | Bin 0 -> 2959 bytes .../__pycache__/subprocess.cpython-310.pyc | Bin 0 -> 5718 bytes .../__pycache__/temp_dir.cpython-310.pyc | Bin 0 -> 6876 bytes .../__pycache__/unpacking.cpython-310.pyc | Bin 0 -> 6452 bytes .../utils/__pycache__/urls.cpython-310.pyc | Bin 0 -> 1527 bytes .../__pycache__/virtualenv.cpython-310.pyc | Bin 0 -> 3214 bytes .../utils/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 5911 bytes .../site-packages/pip/_internal/utils/_log.py | 38 + .../pip/_internal/utils/appdirs.py | 35 + .../pip/_internal/utils/compat.py | 63 + .../pip/_internal/utils/compatibility_tags.py | 168 + .../pip/_internal/utils/datetime.py | 11 + .../pip/_internal/utils/deprecation.py | 104 + .../pip/_internal/utils/direct_url_helpers.py | 79 + .../pip/_internal/utils/distutils_args.py | 42 + .../pip/_internal/utils/encoding.py | 36 + .../pip/_internal/utils/entrypoints.py | 27 + .../pip/_internal/utils/filesystem.py | 182 + .../pip/_internal/utils/filetypes.py | 28 + .../pip/_internal/utils/glibc.py | 92 + .../pip/_internal/utils/hashes.py | 165 + .../_internal/utils/inject_securetransport.py | 36 + .../pip/_internal/utils/logging.py | 391 + .../site-packages/pip/_internal/utils/misc.py | 828 ++ .../pip/_internal/utils/models.py | 47 + .../pip/_internal/utils/packaging.py | 89 + .../pip/_internal/utils/parallel.py | 101 + .../pip/_internal/utils/pkg_resources.py | 40 + .../pip/_internal/utils/setuptools_build.py | 173 + .../pip/_internal/utils/subprocess.py | 281 + .../pip/_internal/utils/temp_dir.py | 260 + .../pip/_internal/utils/unpacking.py | 267 + .../site-packages/pip/_internal/utils/urls.py | 65 + .../pip/_internal/utils/virtualenv.py | 111 + .../pip/_internal/utils/wheel.py | 189 + .../pip/_internal/vcs/__init__.py | 15 + .../vcs/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 505 bytes .../vcs/__pycache__/bazaar.cpython-310.pyc | Bin 0 -> 2994 bytes .../vcs/__pycache__/git.cpython-310.pyc | Bin 0 -> 11723 bytes .../vcs/__pycache__/mercurial.cpython-310.pyc | Bin 0 -> 4642 bytes .../__pycache__/subversion.cpython-310.pyc | Bin 0 -> 7949 bytes .../versioncontrol.cpython-310.pyc | Bin 0 -> 19470 bytes .../site-packages/pip/_internal/vcs/bazaar.py | 96 + .../site-packages/pip/_internal/vcs/git.py | 506 + .../pip/_internal/vcs/mercurial.py | 158 + .../pip/_internal/vcs/subversion.py | 329 + .../pip/_internal/vcs/versioncontrol.py | 722 ++ .../pip/_internal/wheel_builder.py | 360 + .../Lib/site-packages/pip/_vendor/__init__.py | 111 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2900 bytes .../__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 21177 bytes .../__pycache__/distro.cpython-310.pyc | Bin 0 -> 36672 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 237882 bytes .../_vendor/__pycache__/six.cpython-310.pyc | Bin 0 -> 27586 bytes .../Lib/site-packages/pip/_vendor/appdirs.py | 633 ++ .../pip/_vendor/cachecontrol/__init__.py | 11 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 540 bytes .../__pycache__/_cmd.cpython-310.pyc | Bin 0 -> 1571 bytes .../__pycache__/adapter.cpython-310.pyc | Bin 0 -> 3089 bytes .../__pycache__/cache.cpython-310.pyc | Bin 0 -> 1819 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 747 bytes .../__pycache__/controller.cpython-310.pyc | Bin 0 -> 7771 bytes .../__pycache__/filewrapper.cpython-310.pyc | Bin 0 -> 2168 bytes .../__pycache__/heuristics.cpython-310.pyc | Bin 0 -> 4709 bytes .../__pycache__/serialize.cpython-310.pyc | Bin 0 -> 4214 bytes .../__pycache__/wrapper.cpython-310.pyc | Bin 0 -> 678 bytes .../pip/_vendor/cachecontrol/_cmd.py | 57 + .../pip/_vendor/cachecontrol/adapter.py | 133 + .../pip/_vendor/cachecontrol/cache.py | 39 + .../_vendor/cachecontrol/caches/__init__.py | 2 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 284 bytes .../__pycache__/file_cache.cpython-310.pyc | Bin 0 -> 3343 bytes .../__pycache__/redis_cache.cpython-310.pyc | Bin 0 -> 1564 bytes .../_vendor/cachecontrol/caches/file_cache.py | 146 + .../cachecontrol/caches/redis_cache.py | 33 + .../pip/_vendor/cachecontrol/compat.py | 29 + .../pip/_vendor/cachecontrol/controller.py | 376 + .../pip/_vendor/cachecontrol/filewrapper.py | 80 + .../pip/_vendor/cachecontrol/heuristics.py | 135 + .../pip/_vendor/cachecontrol/serialize.py | 188 + .../pip/_vendor/cachecontrol/wrapper.py | 29 + .../pip/_vendor/certifi/__init__.py | 3 + .../pip/_vendor/certifi/__main__.py | 12 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 266 bytes .../__pycache__/__main__.cpython-310.pyc | Bin 0 -> 445 bytes .../certifi/__pycache__/core.cpython-310.pyc | Bin 0 -> 1540 bytes .../pip/_vendor/certifi/cacert.pem | 4257 +++++++++ .../site-packages/pip/_vendor/certifi/core.py | 76 + .../pip/_vendor/chardet/__init__.py | 83 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1892 bytes .../__pycache__/big5freq.cpython-310.pyc | Bin 0 -> 27169 bytes .../__pycache__/big5prober.cpython-310.pyc | Bin 0 -> 1120 bytes .../chardistribution.cpython-310.pyc | Bin 0 -> 5731 bytes .../charsetgroupprober.cpython-310.pyc | Bin 0 -> 2219 bytes .../__pycache__/charsetprober.cpython-310.pyc | Bin 0 -> 3473 bytes .../codingstatemachine.cpython-310.pyc | Bin 0 -> 2892 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 391 bytes .../__pycache__/cp949prober.cpython-310.pyc | Bin 0 -> 1127 bytes .../chardet/__pycache__/enums.cpython-310.pyc | Bin 0 -> 2575 bytes .../__pycache__/escprober.cpython-310.pyc | Bin 0 -> 2621 bytes .../chardet/__pycache__/escsm.cpython-310.pyc | Bin 0 -> 8368 bytes .../__pycache__/eucjpprober.cpython-310.pyc | Bin 0 -> 2425 bytes .../__pycache__/euckrfreq.cpython-310.pyc | Bin 0 -> 12053 bytes .../__pycache__/euckrprober.cpython-310.pyc | Bin 0 -> 1128 bytes .../__pycache__/euctwfreq.cpython-310.pyc | Bin 0 -> 27173 bytes .../__pycache__/euctwprober.cpython-310.pyc | Bin 0 -> 1128 bytes .../__pycache__/gb2312freq.cpython-310.pyc | Bin 0 -> 19097 bytes .../__pycache__/gb2312prober.cpython-310.pyc | Bin 0 -> 1136 bytes .../__pycache__/hebrewprober.cpython-310.pyc | Bin 0 -> 3013 bytes .../__pycache__/jisfreq.cpython-310.pyc | Bin 0 -> 22125 bytes .../__pycache__/jpcntx.cpython-310.pyc | Bin 0 -> 37632 bytes .../langbulgarianmodel.cpython-310.pyc | Bin 0 -> 47913 bytes .../langgreekmodel.cpython-310.pyc | Bin 0 -> 46103 bytes .../langhebrewmodel.cpython-310.pyc | Bin 0 -> 44552 bytes .../langhungarianmodel.cpython-310.pyc | Bin 0 -> 47873 bytes .../langrussianmodel.cpython-310.pyc | Bin 0 -> 61006 bytes .../__pycache__/langthaimodel.cpython-310.pyc | Bin 0 -> 44728 bytes .../langturkishmodel.cpython-310.pyc | Bin 0 -> 44569 bytes .../__pycache__/latin1prober.cpython-310.pyc | Bin 0 -> 4419 bytes .../mbcharsetprober.cpython-310.pyc | Bin 0 -> 2240 bytes .../mbcsgroupprober.cpython-310.pyc | Bin 0 -> 1123 bytes .../__pycache__/mbcssm.cpython-310.pyc | Bin 0 -> 18750 bytes .../sbcharsetprober.cpython-310.pyc | Bin 0 -> 3069 bytes .../sbcsgroupprober.cpython-310.pyc | Bin 0 -> 1692 bytes .../__pycache__/sjisprober.cpython-310.pyc | Bin 0 -> 2463 bytes .../universaldetector.cpython-310.pyc | Bin 0 -> 5815 bytes .../__pycache__/utf8prober.cpython-310.pyc | Bin 0 -> 1972 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 429 bytes .../pip/_vendor/chardet/big5freq.py | 386 + .../pip/_vendor/chardet/big5prober.py | 47 + .../pip/_vendor/chardet/chardistribution.py | 233 + .../pip/_vendor/chardet/charsetgroupprober.py | 107 + .../pip/_vendor/chardet/charsetprober.py | 145 + .../pip/_vendor/chardet/cli/__init__.py | 1 + .../cli/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 186 bytes .../__pycache__/chardetect.cpython-310.pyc | Bin 0 -> 2686 bytes .../pip/_vendor/chardet/cli/chardetect.py | 84 + .../pip/_vendor/chardet/codingstatemachine.py | 88 + .../pip/_vendor/chardet/compat.py | 36 + .../pip/_vendor/chardet/cp949prober.py | 49 + .../pip/_vendor/chardet/enums.py | 76 + .../pip/_vendor/chardet/escprober.py | 101 + .../pip/_vendor/chardet/escsm.py | 246 + .../pip/_vendor/chardet/eucjpprober.py | 92 + .../pip/_vendor/chardet/euckrfreq.py | 195 + .../pip/_vendor/chardet/euckrprober.py | 47 + .../pip/_vendor/chardet/euctwfreq.py | 387 + .../pip/_vendor/chardet/euctwprober.py | 46 + .../pip/_vendor/chardet/gb2312freq.py | 283 + .../pip/_vendor/chardet/gb2312prober.py | 46 + .../pip/_vendor/chardet/hebrewprober.py | 292 + .../pip/_vendor/chardet/jisfreq.py | 325 + .../pip/_vendor/chardet/jpcntx.py | 233 + .../pip/_vendor/chardet/langbulgarianmodel.py | 4650 +++++++++ .../pip/_vendor/chardet/langgreekmodel.py | 4398 +++++++++ .../pip/_vendor/chardet/langhebrewmodel.py | 4383 +++++++++ .../pip/_vendor/chardet/langhungarianmodel.py | 4650 +++++++++ .../pip/_vendor/chardet/langrussianmodel.py | 5718 +++++++++++ .../pip/_vendor/chardet/langthaimodel.py | 4383 +++++++++ .../pip/_vendor/chardet/langturkishmodel.py | 4383 +++++++++ .../pip/_vendor/chardet/latin1prober.py | 145 + .../pip/_vendor/chardet/mbcharsetprober.py | 91 + .../pip/_vendor/chardet/mbcsgroupprober.py | 54 + .../pip/_vendor/chardet/mbcssm.py | 572 ++ .../pip/_vendor/chardet/metadata/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 191 bytes .../__pycache__/languages.cpython-310.pyc | Bin 0 -> 7953 bytes .../pip/_vendor/chardet/metadata/languages.py | 310 + .../pip/_vendor/chardet/sbcharsetprober.py | 145 + .../pip/_vendor/chardet/sbcsgroupprober.py | 83 + .../pip/_vendor/chardet/sjisprober.py | 92 + .../pip/_vendor/chardet/universaldetector.py | 286 + .../pip/_vendor/chardet/utf8prober.py | 82 + .../pip/_vendor/chardet/version.py | 9 + .../pip/_vendor/colorama/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 434 bytes .../colorama/__pycache__/ansi.cpython-310.pyc | Bin 0 -> 2995 bytes .../__pycache__/ansitowin32.cpython-310.pyc | Bin 0 -> 7894 bytes .../__pycache__/initialise.cpython-310.pyc | Bin 0 -> 1681 bytes .../__pycache__/win32.cpython-310.pyc | Bin 0 -> 3942 bytes .../__pycache__/winterm.cpython-310.pyc | Bin 0 -> 4558 bytes .../pip/_vendor/colorama/ansi.py | 102 + .../pip/_vendor/colorama/ansitowin32.py | 258 + .../pip/_vendor/colorama/initialise.py | 80 + .../pip/_vendor/colorama/win32.py | 152 + .../pip/_vendor/colorama/winterm.py | 169 + .../pip/_vendor/distlib/__init__.py | 23 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1053 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 31878 bytes .../__pycache__/database.cpython-310.pyc | Bin 0 -> 42624 bytes .../distlib/__pycache__/index.cpython-310.pyc | Bin 0 -> 17315 bytes .../__pycache__/locators.cpython-310.pyc | Bin 0 -> 38391 bytes .../__pycache__/manifest.cpython-310.pyc | Bin 0 -> 10224 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 4412 bytes .../__pycache__/metadata.cpython-310.pyc | Bin 0 -> 26548 bytes .../__pycache__/resources.cpython-310.pyc | Bin 0 -> 11029 bytes .../__pycache__/scripts.cpython-310.pyc | Bin 0 -> 11098 bytes .../distlib/__pycache__/util.cpython-310.pyc | Bin 0 -> 52569 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 20135 bytes .../distlib/__pycache__/wheel.cpython-310.pyc | Bin 0 -> 27357 bytes .../pip/_vendor/distlib/_backport/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 474 bytes .../__pycache__/misc.cpython-310.pyc | Bin 0 -> 1096 bytes .../__pycache__/shutil.cpython-310.pyc | Bin 0 -> 21536 bytes .../__pycache__/sysconfig.cpython-310.pyc | Bin 0 -> 15890 bytes .../__pycache__/tarfile.cpython-310.pyc | Bin 0 -> 62500 bytes .../pip/_vendor/distlib/_backport/misc.py | 41 + .../pip/_vendor/distlib/_backport/shutil.py | 764 ++ .../_vendor/distlib/_backport/sysconfig.cfg | 84 + .../_vendor/distlib/_backport/sysconfig.py | 786 ++ .../pip/_vendor/distlib/_backport/tarfile.py | 2607 +++++ .../pip/_vendor/distlib/compat.py | 1120 +++ .../pip/_vendor/distlib/database.py | 1339 +++ .../pip/_vendor/distlib/index.py | 509 + .../pip/_vendor/distlib/locators.py | 1300 +++ .../pip/_vendor/distlib/manifest.py | 393 + .../pip/_vendor/distlib/markers.py | 130 + .../pip/_vendor/distlib/metadata.py | 1058 +++ .../pip/_vendor/distlib/resources.py | 358 + .../pip/_vendor/distlib/scripts.py | 423 + .../site-packages/pip/_vendor/distlib/t32.exe | Bin 0 -> 96768 bytes .../site-packages/pip/_vendor/distlib/t64.exe | Bin 0 -> 105984 bytes .../site-packages/pip/_vendor/distlib/util.py | 1965 ++++ .../pip/_vendor/distlib/version.py | 739 ++ .../site-packages/pip/_vendor/distlib/w32.exe | Bin 0 -> 90112 bytes .../site-packages/pip/_vendor/distlib/w64.exe | Bin 0 -> 99840 bytes .../pip/_vendor/distlib/wheel.py | 1056 +++ .../Lib/site-packages/pip/_vendor/distro.py | 1230 +++ .../pip/_vendor/html5lib/__init__.py | 35 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1293 bytes .../__pycache__/_ihatexml.cpython-310.pyc | Bin 0 -> 13850 bytes .../__pycache__/_inputstream.cpython-310.pyc | Bin 0 -> 21675 bytes .../__pycache__/_tokenizer.cpython-310.pyc | Bin 0 -> 37352 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 4785 bytes .../__pycache__/constants.cpython-310.pyc | Bin 0 -> 161252 bytes .../__pycache__/html5parser.cpython-310.pyc | Bin 0 -> 88512 bytes .../__pycache__/serializer.cpython-310.pyc | Bin 0 -> 10735 bytes .../pip/_vendor/html5lib/_ihatexml.py | 289 + .../pip/_vendor/html5lib/_inputstream.py | 918 ++ .../pip/_vendor/html5lib/_tokenizer.py | 1735 ++++ .../pip/_vendor/html5lib/_trie/__init__.py | 5 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 343 bytes .../_trie/__pycache__/_base.cpython-310.pyc | Bin 0 -> 1595 bytes .../_trie/__pycache__/py.cpython-310.pyc | Bin 0 -> 2258 bytes .../pip/_vendor/html5lib/_trie/_base.py | 40 + .../pip/_vendor/html5lib/_trie/py.py | 67 + .../pip/_vendor/html5lib/_utils.py | 159 + .../pip/_vendor/html5lib/constants.py | 2946 ++++++ .../pip/_vendor/html5lib/filters/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 191 bytes .../alphabeticalattributes.cpython-310.pyc | Bin 0 -> 1322 bytes .../filters/__pycache__/base.cpython-310.pyc | Bin 0 -> 861 bytes .../inject_meta_charset.cpython-310.pyc | Bin 0 -> 1859 bytes .../filters/__pycache__/lint.cpython-310.pyc | Bin 0 -> 2565 bytes .../__pycache__/optionaltags.cpython-310.pyc | Bin 0 -> 2720 bytes .../__pycache__/sanitizer.cpython-310.pyc | Bin 0 -> 20023 bytes .../__pycache__/whitespace.cpython-310.pyc | Bin 0 -> 1367 bytes .../filters/alphabeticalattributes.py | 29 + .../pip/_vendor/html5lib/filters/base.py | 12 + .../html5lib/filters/inject_meta_charset.py | 73 + .../pip/_vendor/html5lib/filters/lint.py | 93 + .../_vendor/html5lib/filters/optionaltags.py | 207 + .../pip/_vendor/html5lib/filters/sanitizer.py | 916 ++ .../_vendor/html5lib/filters/whitespace.py | 38 + .../pip/_vendor/html5lib/html5parser.py | 2795 ++++++ .../pip/_vendor/html5lib/serializer.py | 409 + .../_vendor/html5lib/treeadapters/__init__.py | 30 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 932 bytes .../__pycache__/genshi.cpython-310.pyc | Bin 0 -> 1544 bytes .../__pycache__/sax.cpython-310.pyc | Bin 0 -> 1451 bytes .../_vendor/html5lib/treeadapters/genshi.py | 54 + .../pip/_vendor/html5lib/treeadapters/sax.py | 50 + .../_vendor/html5lib/treebuilders/__init__.py | 88 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3323 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 11326 bytes .../__pycache__/dom.cpython-310.pyc | Bin 0 -> 9403 bytes .../__pycache__/etree.cpython-310.pyc | Bin 0 -> 11701 bytes .../__pycache__/etree_lxml.cpython-310.pyc | Bin 0 -> 13023 bytes .../pip/_vendor/html5lib/treebuilders/base.py | 417 + .../pip/_vendor/html5lib/treebuilders/dom.py | 239 + .../_vendor/html5lib/treebuilders/etree.py | 343 + .../html5lib/treebuilders/etree_lxml.py | 392 + .../_vendor/html5lib/treewalkers/__init__.py | 154 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 3974 bytes .../__pycache__/base.cpython-310.pyc | Bin 0 -> 6937 bytes .../__pycache__/dom.cpython-310.pyc | Bin 0 -> 1705 bytes .../__pycache__/etree.cpython-310.pyc | Bin 0 -> 3463 bytes .../__pycache__/etree_lxml.cpython-310.pyc | Bin 0 -> 6550 bytes .../__pycache__/genshi.cpython-310.pyc | Bin 0 -> 1911 bytes .../pip/_vendor/html5lib/treewalkers/base.py | 252 + .../pip/_vendor/html5lib/treewalkers/dom.py | 43 + .../pip/_vendor/html5lib/treewalkers/etree.py | 131 + .../html5lib/treewalkers/etree_lxml.py | 215 + .../_vendor/html5lib/treewalkers/genshi.py | 69 + .../pip/_vendor/idna/__init__.py | 44 + .../idna/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 838 bytes .../idna/__pycache__/codec.cpython-310.pyc | Bin 0 -> 2600 bytes .../idna/__pycache__/compat.cpython-310.pyc | Bin 0 -> 659 bytes .../idna/__pycache__/core.cpython-310.pyc | Bin 0 -> 9044 bytes .../idna/__pycache__/idnadata.cpython-310.pyc | Bin 0 -> 35667 bytes .../__pycache__/intranges.cpython-310.pyc | Bin 0 -> 1851 bytes .../__pycache__/package_data.cpython-310.pyc | Bin 0 -> 202 bytes .../__pycache__/uts46data.cpython-310.pyc | Bin 0 -> 145376 bytes .../site-packages/pip/_vendor/idna/codec.py | 117 + .../site-packages/pip/_vendor/idna/compat.py | 16 + .../site-packages/pip/_vendor/idna/core.py | 409 + .../pip/_vendor/idna/idnadata.py | 2050 ++++ .../pip/_vendor/idna/intranges.py | 58 + .../pip/_vendor/idna/package_data.py | 2 + .../pip/_vendor/idna/uts46data.py | 8438 +++++++++++++++++ .../pip/_vendor/msgpack/__init__.py | 54 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1419 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 209 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 1799 bytes .../msgpack/__pycache__/ext.cpython-310.pyc | Bin 0 -> 6318 bytes .../__pycache__/fallback.cpython-310.pyc | Bin 0 -> 26436 bytes .../pip/_vendor/msgpack/_version.py | 1 + .../pip/_vendor/msgpack/exceptions.py | 48 + .../site-packages/pip/_vendor/msgpack/ext.py | 193 + .../pip/_vendor/msgpack/fallback.py | 1087 +++ .../pip/_vendor/packaging/__about__.py | 26 + .../pip/_vendor/packaging/__init__.py | 25 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 581 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 437 bytes .../__pycache__/_manylinux.cpython-310.pyc | Bin 0 -> 7293 bytes .../__pycache__/_musllinux.cpython-310.pyc | Bin 0 -> 4603 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2961 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9280 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 3966 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 22179 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 12226 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 3566 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 12917 bytes .../pip/_vendor/packaging/_manylinux.py | 301 + .../pip/_vendor/packaging/_musllinux.py | 136 + .../pip/_vendor/packaging/_structures.py | 67 + .../pip/_vendor/packaging/markers.py | 304 + .../pip/_vendor/packaging/requirements.py | 146 + .../pip/_vendor/packaging/specifiers.py | 828 ++ .../pip/_vendor/packaging/tags.py | 484 + .../pip/_vendor/packaging/utils.py | 136 + .../pip/_vendor/packaging/version.py | 504 + .../pip/_vendor/pep517/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 304 bytes .../pep517/__pycache__/build.cpython-310.pyc | Bin 0 -> 3605 bytes .../pep517/__pycache__/check.cpython-310.pyc | Bin 0 -> 4568 bytes .../__pycache__/colorlog.cpython-310.pyc | Bin 0 -> 2955 bytes .../pep517/__pycache__/compat.cpython-310.pyc | Bin 0 -> 1300 bytes .../__pycache__/dirtools.cpython-310.pyc | Bin 0 -> 1347 bytes .../__pycache__/envbuild.cpython-310.pyc | Bin 0 -> 4386 bytes .../pep517/__pycache__/meta.cpython-310.pyc | Bin 0 -> 2952 bytes .../__pycache__/wrappers.cpython-310.pyc | Bin 0 -> 12081 bytes .../site-packages/pip/_vendor/pep517/build.py | 127 + .../site-packages/pip/_vendor/pep517/check.py | 207 + .../pip/_vendor/pep517/colorlog.py | 115 + .../pip/_vendor/pep517/compat.py | 42 + .../pip/_vendor/pep517/dirtools.py | 44 + .../pip/_vendor/pep517/envbuild.py | 171 + .../pip/_vendor/pep517/in_process/__init__.py | 17 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 912 bytes .../__pycache__/_in_process.cpython-310.pyc | Bin 0 -> 9730 bytes .../_vendor/pep517/in_process/_in_process.py | 349 + .../site-packages/pip/_vendor/pep517/meta.py | 92 + .../pip/_vendor/pep517/wrappers.py | 371 + .../pip/_vendor/pkg_resources/__init__.py | 3296 +++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 99921 bytes .../__pycache__/py31compat.cpython-310.pyc | Bin 0 -> 651 bytes .../pip/_vendor/pkg_resources/py31compat.py | 23 + .../pip/_vendor/progress/__init__.py | 177 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 5708 bytes .../progress/__pycache__/bar.cpython-310.pyc | Bin 0 -> 2598 bytes .../__pycache__/counter.cpython-310.pyc | Bin 0 -> 1426 bytes .../__pycache__/spinner.cpython-310.pyc | Bin 0 -> 1319 bytes .../site-packages/pip/_vendor/progress/bar.py | 91 + .../pip/_vendor/progress/counter.py | 41 + .../pip/_vendor/progress/spinner.py | 43 + .../site-packages/pip/_vendor/pyparsing.py | 7107 ++++++++++++++ .../pip/_vendor/requests/__init__.py | 154 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 4003 bytes .../__pycache__/__version__.cpython-310.pyc | Bin 0 -> 546 bytes .../_internal_utils.cpython-310.pyc | Bin 0 -> 1300 bytes .../__pycache__/adapters.cpython-310.pyc | Bin 0 -> 16903 bytes .../requests/__pycache__/api.cpython-310.pyc | Bin 0 -> 6652 bytes .../requests/__pycache__/auth.cpython-310.pyc | Bin 0 -> 8089 bytes .../__pycache__/certs.cpython-310.pyc | Bin 0 -> 630 bytes .../__pycache__/compat.cpython-310.pyc | Bin 0 -> 1609 bytes .../__pycache__/cookies.cpython-310.pyc | Bin 0 -> 18695 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5004 bytes .../requests/__pycache__/help.cpython-310.pyc | Bin 0 -> 2899 bytes .../__pycache__/hooks.cpython-310.pyc | Bin 0 -> 985 bytes .../__pycache__/models.cpython-310.pyc | Bin 0 -> 24428 bytes .../__pycache__/packages.cpython-310.pyc | Bin 0 -> 499 bytes .../__pycache__/sessions.cpython-310.pyc | Bin 0 -> 19783 bytes .../__pycache__/status_codes.cpython-310.pyc | Bin 0 -> 4662 bytes .../__pycache__/structures.cpython-310.pyc | Bin 0 -> 4445 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 23438 bytes .../pip/_vendor/requests/__version__.py | 14 + .../pip/_vendor/requests/_internal_utils.py | 42 + .../pip/_vendor/requests/adapters.py | 533 ++ .../site-packages/pip/_vendor/requests/api.py | 159 + .../pip/_vendor/requests/auth.py | 305 + .../pip/_vendor/requests/certs.py | 18 + .../pip/_vendor/requests/compat.py | 76 + .../pip/_vendor/requests/cookies.py | 549 ++ .../pip/_vendor/requests/exceptions.py | 127 + .../pip/_vendor/requests/help.py | 132 + .../pip/_vendor/requests/hooks.py | 34 + .../pip/_vendor/requests/models.py | 966 ++ .../pip/_vendor/requests/packages.py | 16 + .../pip/_vendor/requests/sessions.py | 781 ++ .../pip/_vendor/requests/status_codes.py | 123 + .../pip/_vendor/requests/structures.py | 105 + .../pip/_vendor/requests/utils.py | 1013 ++ .../pip/_vendor/resolvelib/__init__.py | 26 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 597 bytes .../__pycache__/providers.cpython-310.pyc | Bin 0 -> 6475 bytes .../__pycache__/reporters.cpython-310.pyc | Bin 0 -> 2259 bytes .../__pycache__/resolvers.cpython-310.pyc | Bin 0 -> 14968 bytes .../__pycache__/structs.cpython-310.pyc | Bin 0 -> 7156 bytes .../pip/_vendor/resolvelib/compat/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 192 bytes .../collections_abc.cpython-310.pyc | Bin 0 -> 368 bytes .../resolvelib/compat/collections_abc.py | 6 + .../pip/_vendor/resolvelib/providers.py | 124 + .../pip/_vendor/resolvelib/reporters.py | 37 + .../pip/_vendor/resolvelib/resolvers.py | 473 + .../pip/_vendor/resolvelib/structs.py | 165 + .vcrunch/Lib/site-packages/pip/_vendor/six.py | 998 ++ .../pip/_vendor/tenacity/__init__.py | 517 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 16370 bytes .../__pycache__/_asyncio.cpython-310.pyc | Bin 0 -> 2605 bytes .../__pycache__/_utils.cpython-310.pyc | Bin 0 -> 1219 bytes .../__pycache__/after.cpython-310.pyc | Bin 0 -> 1222 bytes .../__pycache__/before.cpython-310.pyc | Bin 0 -> 1100 bytes .../__pycache__/before_sleep.cpython-310.pyc | Bin 0 -> 1402 bytes .../tenacity/__pycache__/nap.cpython-310.pyc | Bin 0 -> 1190 bytes .../__pycache__/retry.cpython-310.pyc | Bin 0 -> 8420 bytes .../tenacity/__pycache__/stop.cpython-310.pyc | Bin 0 -> 4008 bytes .../__pycache__/tornadoweb.cpython-310.pyc | Bin 0 -> 1755 bytes .../tenacity/__pycache__/wait.cpython-310.pyc | Bin 0 -> 7952 bytes .../pip/_vendor/tenacity/_asyncio.py | 92 + .../pip/_vendor/tenacity/_utils.py | 68 + .../pip/_vendor/tenacity/after.py | 46 + .../pip/_vendor/tenacity/before.py | 41 + .../pip/_vendor/tenacity/before_sleep.py | 58 + .../site-packages/pip/_vendor/tenacity/nap.py | 43 + .../pip/_vendor/tenacity/retry.py | 213 + .../pip/_vendor/tenacity/stop.py | 96 + .../pip/_vendor/tenacity/tornadoweb.py | 59 + .../pip/_vendor/tenacity/wait.py | 191 + .../pip/_vendor/tomli/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 370 bytes .../tomli/__pycache__/_parser.cpython-310.pyc | Bin 0 -> 16325 bytes .../tomli/__pycache__/_re.cpython-310.pyc | Bin 0 -> 2414 bytes .../pip/_vendor/tomli/_parser.py | 703 ++ .../site-packages/pip/_vendor/tomli/_re.py | 83 + .../pip/_vendor/urllib3/__init__.py | 85 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2181 bytes .../__pycache__/_collections.cpython-310.pyc | Bin 0 -> 10844 bytes .../__pycache__/_version.cpython-310.pyc | Bin 0 -> 204 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 13332 bytes .../connectionpool.cpython-310.pyc | Bin 0 -> 24475 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 10985 bytes .../__pycache__/fields.cpython-310.pyc | Bin 0 -> 8181 bytes .../__pycache__/filepost.cpython-310.pyc | Bin 0 -> 2743 bytes .../__pycache__/poolmanager.cpython-310.pyc | Bin 0 -> 15198 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 5618 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 20922 bytes .../pip/_vendor/urllib3/_collections.py | 337 + .../pip/_vendor/urllib3/_version.py | 2 + .../pip/_vendor/urllib3/connection.py | 539 ++ .../pip/_vendor/urllib3/connectionpool.py | 1067 +++ .../pip/_vendor/urllib3/contrib/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 190 bytes .../_appengine_environ.cpython-310.pyc | Bin 0 -> 1372 bytes .../__pycache__/appengine.cpython-310.pyc | Bin 0 -> 8186 bytes .../__pycache__/ntlmpool.cpython-310.pyc | Bin 0 -> 3625 bytes .../__pycache__/pyopenssl.cpython-310.pyc | Bin 0 -> 15519 bytes .../securetransport.cpython-310.pyc | Bin 0 -> 21918 bytes .../contrib/__pycache__/socks.cpython-310.pyc | Bin 0 -> 5592 bytes .../urllib3/contrib/_appengine_environ.py | 36 + .../contrib/_securetransport/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 207 bytes .../__pycache__/bindings.cpython-310.pyc | Bin 0 -> 10718 bytes .../__pycache__/low_level.cpython-310.pyc | Bin 0 -> 9102 bytes .../contrib/_securetransport/bindings.py | 519 + .../contrib/_securetransport/low_level.py | 396 + .../pip/_vendor/urllib3/contrib/appengine.py | 314 + .../pip/_vendor/urllib3/contrib/ntlmpool.py | 130 + .../pip/_vendor/urllib3/contrib/pyopenssl.py | 511 + .../urllib3/contrib/securetransport.py | 922 ++ .../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 | 5 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 304 bytes .../packages/__pycache__/six.cpython-310.pyc | Bin 0 -> 27661 bytes .../urllib3/packages/backports/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 201 bytes .../__pycache__/makefile.cpython-310.pyc | Bin 0 -> 1301 bytes .../urllib3/packages/backports/makefile.py | 51 + .../pip/_vendor/urllib3/packages/six.py | 1077 +++ .../packages/ssl_match_hostname/__init__.py | 24 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 589 bytes .../_implementation.cpython-310.pyc | Bin 0 -> 3293 bytes .../ssl_match_hostname/_implementation.py | 160 + .../pip/_vendor/urllib3/poolmanager.py | 536 ++ .../pip/_vendor/urllib3/request.py | 170 + .../pip/_vendor/urllib3/response.py | 821 ++ .../pip/_vendor/urllib3/util/__init__.py | 49 + .../util/__pycache__/__init__.cpython-310.pyc | Bin 0 -> 1100 bytes .../__pycache__/connection.cpython-310.pyc | Bin 0 -> 3449 bytes .../util/__pycache__/proxy.cpython-310.pyc | Bin 0 -> 1336 bytes .../util/__pycache__/queue.cpython-310.pyc | Bin 0 -> 1055 bytes .../util/__pycache__/request.cpython-310.pyc | Bin 0 -> 3464 bytes .../util/__pycache__/response.cpython-310.pyc | Bin 0 -> 2349 bytes .../util/__pycache__/retry.cpython-310.pyc | Bin 0 -> 15778 bytes .../util/__pycache__/ssl_.cpython-310.pyc | Bin 0 -> 11304 bytes .../__pycache__/ssltransport.cpython-310.pyc | Bin 0 -> 7425 bytes .../util/__pycache__/timeout.cpython-310.pyc | Bin 0 -> 8934 bytes .../util/__pycache__/url.cpython-310.pyc | Bin 0 -> 10678 bytes .../util/__pycache__/wait.cpython-310.pyc | Bin 0 -> 3086 bytes .../pip/_vendor/urllib3/util/connection.py | 150 + .../pip/_vendor/urllib3/util/proxy.py | 56 + .../pip/_vendor/urllib3/util/queue.py | 22 + .../pip/_vendor/urllib3/util/request.py | 143 + .../pip/_vendor/urllib3/util/response.py | 107 + .../pip/_vendor/urllib3/util/retry.py | 602 ++ .../pip/_vendor/urllib3/util/ssl_.py | 495 + .../pip/_vendor/urllib3/util/ssltransport.py | 221 + .../pip/_vendor/urllib3/util/timeout.py | 268 + .../pip/_vendor/urllib3/util/url.py | 432 + .../pip/_vendor/urllib3/util/wait.py | 153 + .../Lib/site-packages/pip/_vendor/vendor.txt | 22 + .../pip/_vendor/webencodings/__init__.py | 342 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 9742 bytes .../__pycache__/labels.cpython-310.pyc | Bin 0 -> 5227 bytes .../__pycache__/mklabels.cpython-310.pyc | Bin 0 -> 1932 bytes .../__pycache__/tests.cpython-310.pyc | Bin 0 -> 5034 bytes .../x_user_defined.cpython-310.pyc | Bin 0 -> 2583 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 + .vcrunch/Lib/site-packages/pip/py.typed | 4 + .../site-packages/pkg_resources/__init__.py | 3288 +++++++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 100078 bytes .../pkg_resources/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 184 bytes .../__pycache__/appdirs.cpython-310.pyc | Bin 0 -> 20247 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 199005 bytes .../pkg_resources/_vendor/appdirs.py | 608 ++ .../_vendor/packaging/__about__.py | 27 + .../_vendor/packaging/__init__.py | 26 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 700 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 546 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 1147 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2690 bytes .../__pycache__/_typing.cpython-310.pyc | Bin 0 -> 1502 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9187 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 4092 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 20453 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 17332 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 1637 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 13018 bytes .../_vendor/packaging/_compat.py | 38 + .../_vendor/packaging/_structures.py | 86 + .../_vendor/packaging/_typing.py | 48 + .../_vendor/packaging/markers.py | 328 + .../_vendor/packaging/requirements.py | 145 + .../_vendor/packaging/specifiers.py | 863 ++ .../pkg_resources/_vendor/packaging/tags.py | 751 ++ .../pkg_resources/_vendor/packaging/utils.py | 65 + .../_vendor/packaging/version.py | 535 ++ .../pkg_resources/_vendor/pyparsing.py | 5742 +++++++++++ .../pkg_resources/extern/__init__.py | 73 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2893 bytes .../__pycache__/setup.cpython-310.pyc | Bin 0 -> 312 bytes .../data/my-test-package-source/setup.py | 6 + .../setuptools-57.4.0.dist-info/INSTALLER | 1 + .../setuptools-57.4.0.dist-info/LICENSE | 19 + .../setuptools-57.4.0.dist-info/METADATA | 119 + .../setuptools-57.4.0.dist-info/RECORD | 298 + .../setuptools-57.4.0.dist-info/REQUESTED | 0 .../setuptools-57.4.0.dist-info/WHEEL | 5 + .../entry_points.txt | 60 + .../setuptools-57.4.0.dist-info/top_level.txt | 3 + .../Lib/site-packages/setuptools/__init__.py | 241 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 8681 bytes .../_deprecation_warning.cpython-310.pyc | Bin 0 -> 545 bytes .../__pycache__/_imp.cpython-310.pyc | Bin 0 -> 2071 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 5842 bytes .../__pycache__/build_meta.cpython-310.pyc | Bin 0 -> 9113 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 20160 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 853 bytes .../__pycache__/depends.cpython-310.pyc | Bin 0 -> 5265 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 36048 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 845 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 1942 bytes .../__pycache__/glob.cpython-310.pyc | Bin 0 -> 3733 bytes .../__pycache__/installer.cpython-310.pyc | Bin 0 -> 2749 bytes .../__pycache__/launch.cpython-310.pyc | Bin 0 -> 902 bytes .../__pycache__/lib2to3_ex.cpython-310.pyc | Bin 0 -> 2672 bytes .../__pycache__/monkey.cpython-310.pyc | Bin 0 -> 4633 bytes .../__pycache__/msvc.cpython-310.pyc | Bin 0 -> 42683 bytes .../__pycache__/namespaces.cpython-310.pyc | Bin 0 -> 3614 bytes .../__pycache__/package_index.cpython-310.pyc | Bin 0 -> 32493 bytes .../__pycache__/py34compat.cpython-310.pyc | Bin 0 -> 477 bytes .../__pycache__/sandbox.cpython-310.pyc | Bin 0 -> 15779 bytes .../__pycache__/unicode_utils.cpython-310.pyc | Bin 0 -> 1107 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 319 bytes .../__pycache__/wheel.cpython-310.pyc | Bin 0 -> 7347 bytes .../windows_support.cpython-310.pyc | Bin 0 -> 1020 bytes .../setuptools/_deprecation_warning.py | 7 + .../setuptools/_distutils/__init__.py | 15 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 451 bytes .../__pycache__/_msvccompiler.cpython-310.pyc | Bin 0 -> 13832 bytes .../__pycache__/archive_util.cpython-310.pyc | Bin 0 -> 6558 bytes .../__pycache__/bcppcompiler.cpython-310.pyc | Bin 0 -> 6545 bytes .../__pycache__/ccompiler.cpython-310.pyc | Bin 0 -> 33281 bytes .../__pycache__/cmd.cpython-310.pyc | Bin 0 -> 13952 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 3588 bytes .../__pycache__/core.cpython-310.pyc | Bin 0 -> 6653 bytes .../cygwinccompiler.cpython-310.pyc | Bin 0 -> 8741 bytes .../__pycache__/debug.cpython-310.pyc | Bin 0 -> 247 bytes .../__pycache__/dep_util.cpython-310.pyc | Bin 0 -> 2771 bytes .../__pycache__/dir_util.cpython-310.pyc | Bin 0 -> 5879 bytes .../__pycache__/dist.cpython-310.pyc | Bin 0 -> 34055 bytes .../__pycache__/errors.cpython-310.pyc | Bin 0 -> 4989 bytes .../__pycache__/extension.cpython-310.pyc | Bin 0 -> 7003 bytes .../__pycache__/fancy_getopt.cpython-310.pyc | Bin 0 -> 10632 bytes .../__pycache__/file_util.cpython-310.pyc | Bin 0 -> 5974 bytes .../__pycache__/filelist.cpython-310.pyc | Bin 0 -> 10823 bytes .../__pycache__/log.cpython-310.pyc | Bin 0 -> 2304 bytes .../__pycache__/msvc9compiler.cpython-310.pyc | Bin 0 -> 17562 bytes .../__pycache__/msvccompiler.cpython-310.pyc | Bin 0 -> 14781 bytes .../__pycache__/py35compat.cpython-310.pyc | Bin 0 -> 624 bytes .../__pycache__/py38compat.cpython-310.pyc | Bin 0 -> 420 bytes .../__pycache__/spawn.cpython-310.pyc | Bin 0 -> 2890 bytes .../__pycache__/sysconfig.cpython-310.pyc | Bin 0 -> 12379 bytes .../__pycache__/text_file.cpython-310.pyc | Bin 0 -> 8466 bytes .../__pycache__/unixccompiler.cpython-310.pyc | Bin 0 -> 6787 bytes .../__pycache__/util.cpython-310.pyc | Bin 0 -> 17278 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 7354 bytes .../versionpredicate.cpython-310.pyc | Bin 0 -> 5186 bytes .../setuptools/_distutils/_msvccompiler.py | 561 ++ .../setuptools/_distutils/archive_util.py | 256 + .../setuptools/_distutils/bcppcompiler.py | 393 + .../setuptools/_distutils/ccompiler.py | 1123 +++ .../setuptools/_distutils/cmd.py | 403 + .../setuptools/_distutils/command/__init__.py | 31 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 526 bytes .../command/__pycache__/bdist.cpython-310.pyc | Bin 0 -> 3660 bytes .../__pycache__/bdist_dumb.cpython-310.pyc | Bin 0 -> 3641 bytes .../__pycache__/bdist_msi.cpython-310.pyc | Bin 0 -> 19721 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 12286 bytes .../__pycache__/bdist_wininst.cpython-310.pyc | Bin 0 -> 8626 bytes .../command/__pycache__/build.cpython-310.pyc | Bin 0 -> 3888 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 4865 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 16310 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 10528 bytes .../__pycache__/build_scripts.cpython-310.pyc | Bin 0 -> 4379 bytes .../command/__pycache__/check.cpython-310.pyc | Bin 0 -> 5005 bytes .../command/__pycache__/clean.cpython-310.pyc | Bin 0 -> 2143 bytes .../__pycache__/config.cpython-310.pyc | Bin 0 -> 10332 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 13834 bytes .../__pycache__/install_data.cpython-310.pyc | Bin 0 -> 2342 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 3086 bytes .../install_headers.cpython-310.pyc | Bin 0 -> 1765 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 5169 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2194 bytes .../__pycache__/py37compat.cpython-310.pyc | Bin 0 -> 1039 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 8678 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 14497 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 5370 bytes .../setuptools/_distutils/command/bdist.py | 143 + .../_distutils/command/bdist_dumb.py | 123 + .../_distutils/command/bdist_msi.py | 749 ++ .../_distutils/command/bdist_rpm.py | 579 ++ .../_distutils/command/bdist_wininst.py | 377 + .../setuptools/_distutils/command/build.py | 157 + .../_distutils/command/build_clib.py | 209 + .../_distutils/command/build_ext.py | 757 ++ .../setuptools/_distutils/command/build_py.py | 416 + .../_distutils/command/build_scripts.py | 160 + .../setuptools/_distutils/command/check.py | 148 + .../setuptools/_distutils/command/clean.py | 76 + .../setuptools/_distutils/command/config.py | 344 + .../setuptools/_distutils/command/install.py | 677 ++ .../_distutils/command/install_data.py | 79 + .../_distutils/command/install_egg_info.py | 77 + .../_distutils/command/install_headers.py | 47 + .../_distutils/command/install_lib.py | 217 + .../_distutils/command/install_scripts.py | 60 + .../_distutils/command/py37compat.py | 30 + .../setuptools/_distutils/command/register.py | 304 + .../setuptools/_distutils/command/sdist.py | 494 + .../setuptools/_distutils/command/upload.py | 214 + .../setuptools/_distutils/config.py | 130 + .../setuptools/_distutils/core.py | 234 + .../setuptools/_distutils/cygwinccompiler.py | 414 + .../setuptools/_distutils/debug.py | 5 + .../setuptools/_distutils/dep_util.py | 92 + .../setuptools/_distutils/dir_util.py | 210 + .../setuptools/_distutils/dist.py | 1257 +++ .../setuptools/_distutils/errors.py | 97 + .../setuptools/_distutils/extension.py | 240 + .../setuptools/_distutils/fancy_getopt.py | 457 + .../setuptools/_distutils/file_util.py | 238 + .../setuptools/_distutils/filelist.py | 355 + .../setuptools/_distutils/log.py | 77 + .../setuptools/_distutils/msvc9compiler.py | 788 ++ .../setuptools/_distutils/msvccompiler.py | 643 ++ .../setuptools/_distutils/py35compat.py | 19 + .../setuptools/_distutils/py38compat.py | 7 + .../setuptools/_distutils/spawn.py | 106 + .../setuptools/_distutils/sysconfig.py | 573 ++ .../setuptools/_distutils/text_file.py | 286 + .../setuptools/_distutils/unixccompiler.py | 332 + .../setuptools/_distutils/util.py | 616 ++ .../setuptools/_distutils/version.py | 347 + .../setuptools/_distutils/versionpredicate.py | 166 + .vcrunch/Lib/site-packages/setuptools/_imp.py | 82 + .../setuptools/_vendor/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 181 bytes .../__pycache__/ordered_set.cpython-310.pyc | Bin 0 -> 16334 bytes .../__pycache__/pyparsing.cpython-310.pyc | Bin 0 -> 199002 bytes .../_vendor/more_itertools/__init__.py | 4 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 262 bytes .../__pycache__/more.cpython-310.pyc | Bin 0 -> 110020 bytes .../__pycache__/recipes.cpython-310.pyc | Bin 0 -> 17984 bytes .../setuptools/_vendor/more_itertools/more.py | 3825 ++++++++ .../_vendor/more_itertools/recipes.py | 620 ++ .../setuptools/_vendor/ordered_set.py | 488 + .../setuptools/_vendor/packaging/__about__.py | 27 + .../setuptools/_vendor/packaging/__init__.py | 26 + .../__pycache__/__about__.cpython-310.pyc | Bin 0 -> 697 bytes .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 543 bytes .../__pycache__/_compat.cpython-310.pyc | Bin 0 -> 1144 bytes .../__pycache__/_structures.cpython-310.pyc | Bin 0 -> 2687 bytes .../__pycache__/_typing.cpython-310.pyc | Bin 0 -> 1499 bytes .../__pycache__/markers.cpython-310.pyc | Bin 0 -> 9181 bytes .../__pycache__/requirements.cpython-310.pyc | Bin 0 -> 4086 bytes .../__pycache__/specifiers.cpython-310.pyc | Bin 0 -> 20450 bytes .../__pycache__/tags.cpython-310.pyc | Bin 0 -> 17329 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 1634 bytes .../__pycache__/version.cpython-310.pyc | Bin 0 -> 13015 bytes .../setuptools/_vendor/packaging/_compat.py | 38 + .../_vendor/packaging/_structures.py | 86 + .../setuptools/_vendor/packaging/_typing.py | 48 + .../setuptools/_vendor/packaging/markers.py | 328 + .../_vendor/packaging/requirements.py | 145 + .../_vendor/packaging/specifiers.py | 863 ++ .../setuptools/_vendor/packaging/tags.py | 751 ++ .../setuptools/_vendor/packaging/utils.py | 65 + .../setuptools/_vendor/packaging/version.py | 535 ++ .../setuptools/_vendor/pyparsing.py | 5742 +++++++++++ .../site-packages/setuptools/archive_util.py | 205 + .../site-packages/setuptools/build_meta.py | 281 + .../Lib/site-packages/setuptools/cli-32.exe | Bin 0 -> 65536 bytes .../Lib/site-packages/setuptools/cli-64.exe | Bin 0 -> 74752 bytes .vcrunch/Lib/site-packages/setuptools/cli.exe | Bin 0 -> 65536 bytes .../setuptools/command/__init__.py | 8 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 370 bytes .../command/__pycache__/alias.cpython-310.pyc | Bin 0 -> 2373 bytes .../__pycache__/bdist_egg.cpython-310.pyc | Bin 0 -> 13100 bytes .../__pycache__/bdist_rpm.cpython-310.pyc | Bin 0 -> 1358 bytes .../__pycache__/build_clib.cpython-310.pyc | Bin 0 -> 2461 bytes .../__pycache__/build_ext.cpython-310.pyc | Bin 0 -> 9888 bytes .../__pycache__/build_py.cpython-310.pyc | Bin 0 -> 8448 bytes .../__pycache__/develop.cpython-310.pyc | Bin 0 -> 6464 bytes .../__pycache__/dist_info.cpython-310.pyc | Bin 0 -> 1390 bytes .../__pycache__/easy_install.cpython-310.pyc | Bin 0 -> 63698 bytes .../__pycache__/egg_info.cpython-310.pyc | Bin 0 -> 22026 bytes .../__pycache__/install.cpython-310.pyc | Bin 0 -> 4047 bytes .../install_egg_info.cpython-310.pyc | Bin 0 -> 2424 bytes .../__pycache__/install_lib.cpython-310.pyc | Bin 0 -> 4170 bytes .../install_scripts.cpython-310.pyc | Bin 0 -> 2425 bytes .../__pycache__/py36compat.cpython-310.pyc | Bin 0 -> 4533 bytes .../__pycache__/register.cpython-310.pyc | Bin 0 -> 836 bytes .../__pycache__/rotate.cpython-310.pyc | Bin 0 -> 2503 bytes .../__pycache__/saveopts.cpython-310.pyc | Bin 0 -> 922 bytes .../command/__pycache__/sdist.cpython-310.pyc | Bin 0 -> 6524 bytes .../__pycache__/setopt.cpython-310.pyc | Bin 0 -> 4544 bytes .../command/__pycache__/test.cpython-310.pyc | Bin 0 -> 8621 bytes .../__pycache__/upload.cpython-310.pyc | Bin 0 -> 809 bytes .../__pycache__/upload_docs.cpython-310.pyc | Bin 0 -> 6179 bytes .../site-packages/setuptools/command/alias.py | 78 + .../setuptools/command/bdist_egg.py | 456 + .../setuptools/command/bdist_rpm.py | 31 + .../setuptools/command/build_clib.py | 101 + .../setuptools/command/build_ext.py | 328 + .../setuptools/command/build_py.py | 252 + .../setuptools/command/develop.py | 216 + .../setuptools/command/dist_info.py | 36 + .../setuptools/command/easy_install.py | 2290 +++++ .../setuptools/command/egg_info.py | 734 ++ .../setuptools/command/install.py | 125 + .../setuptools/command/install_egg_info.py | 62 + .../setuptools/command/install_lib.py | 122 + .../setuptools/command/install_scripts.py | 69 + .../setuptools/command/launcher manifest.xml | 15 + .../setuptools/command/py36compat.py | 134 + .../setuptools/command/register.py | 18 + .../setuptools/command/rotate.py | 64 + .../setuptools/command/saveopts.py | 22 + .../site-packages/setuptools/command/sdist.py | 189 + .../setuptools/command/setopt.py | 148 + .../site-packages/setuptools/command/test.py | 274 + .../setuptools/command/upload.py | 17 + .../setuptools/command/upload_docs.py | 202 + .../Lib/site-packages/setuptools/config.py | 715 ++ .../Lib/site-packages/setuptools/dep_util.py | 25 + .../Lib/site-packages/setuptools/depends.py | 175 + .vcrunch/Lib/site-packages/setuptools/dist.py | 1121 +++ .../Lib/site-packages/setuptools/errors.py | 16 + .../Lib/site-packages/setuptools/extension.py | 55 + .../setuptools/extern/__init__.py | 73 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 2932 bytes .vcrunch/Lib/site-packages/setuptools/glob.py | 167 + .../Lib/site-packages/setuptools/gui-32.exe | Bin 0 -> 65536 bytes .../Lib/site-packages/setuptools/gui-64.exe | Bin 0 -> 75264 bytes .vcrunch/Lib/site-packages/setuptools/gui.exe | Bin 0 -> 65536 bytes .../Lib/site-packages/setuptools/installer.py | 97 + .../Lib/site-packages/setuptools/launch.py | 36 + .../site-packages/setuptools/lib2to3_ex.py | 68 + .../Lib/site-packages/setuptools/monkey.py | 177 + .vcrunch/Lib/site-packages/setuptools/msvc.py | 1805 ++++ .../site-packages/setuptools/namespaces.py | 107 + .../site-packages/setuptools/package_index.py | 1119 +++ .../site-packages/setuptools/py34compat.py | 13 + .../Lib/site-packages/setuptools/sandbox.py | 496 + .../setuptools/script (dev).tmpl | 6 + .../Lib/site-packages/setuptools/script.tmpl | 3 + .../site-packages/setuptools/unicode_utils.py | 42 + .../Lib/site-packages/setuptools/version.py | 6 + .../Lib/site-packages/setuptools/wheel.py | 213 + .../setuptools/windows_support.py | 29 + .../Lib/site-packages/werkzeug/__init__.py | 6 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 345 bytes .../__pycache__/_internal.cpython-310.pyc | Bin 0 -> 17240 bytes .../__pycache__/_reloader.cpython-310.pyc | Bin 0 -> 12368 bytes .../datastructures.cpython-310.pyc | Bin 0 -> 104652 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 27718 bytes .../__pycache__/formparser.cpython-310.pyc | Bin 0 -> 13220 bytes .../werkzeug/__pycache__/http.cpython-310.pyc | Bin 0 -> 36914 bytes .../__pycache__/local.cpython-310.pyc | Bin 0 -> 20709 bytes .../__pycache__/security.cpython-310.pyc | Bin 0 -> 4873 bytes .../__pycache__/serving.cpython-310.pyc | Bin 0 -> 30101 bytes .../werkzeug/__pycache__/test.cpython-310.pyc | Bin 0 -> 39292 bytes .../__pycache__/testapp.cpython-310.pyc | Bin 0 -> 9552 bytes .../werkzeug/__pycache__/urls.cpython-310.pyc | Bin 0 -> 32561 bytes .../__pycache__/user_agent.cpython-310.pyc | Bin 0 -> 1832 bytes .../__pycache__/utils.cpython-310.pyc | Bin 0 -> 21703 bytes .../werkzeug/__pycache__/wsgi.cpython-310.pyc | Bin 0 -> 31378 bytes .../Lib/site-packages/werkzeug/_internal.py | 548 ++ .../Lib/site-packages/werkzeug/_reloader.py | 446 + .../site-packages/werkzeug/datastructures.py | 3040 ++++++ .../site-packages/werkzeug/datastructures.pyi | 921 ++ .../site-packages/werkzeug/debug/__init__.py | 533 ++ .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 14243 bytes .../debug/__pycache__/console.cpython-310.pyc | Bin 0 -> 8140 bytes .../debug/__pycache__/repr.cpython-310.pyc | Bin 0 -> 8882 bytes .../debug/__pycache__/tbtools.cpython-310.pyc | Bin 0 -> 11533 bytes .../site-packages/werkzeug/debug/console.py | 222 + .../Lib/site-packages/werkzeug/debug/repr.py | 285 + .../werkzeug/debug/shared/ICON_LICENSE.md | 6 + .../werkzeug/debug/shared/console.png | Bin 0 -> 507 bytes .../werkzeug/debug/shared/debugger.js | 359 + .../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 | 435 + .../Lib/site-packages/werkzeug/exceptions.py | 884 ++ .../Lib/site-packages/werkzeug/formparser.py | 455 + .vcrunch/Lib/site-packages/werkzeug/http.py | 1311 +++ .vcrunch/Lib/site-packages/werkzeug/local.py | 648 ++ .../werkzeug/middleware/__init__.py | 22 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 690 bytes .../__pycache__/dispatcher.cpython-310.pyc | Bin 0 -> 2774 bytes .../__pycache__/http_proxy.cpython-310.pyc | Bin 0 -> 6865 bytes .../__pycache__/lint.cpython-310.pyc | Bin 0 -> 12738 bytes .../__pycache__/profiler.cpython-310.pyc | Bin 0 -> 4981 bytes .../__pycache__/proxy_fix.cpython-310.pyc | Bin 0 -> 6193 bytes .../__pycache__/shared_data.cpython-310.pyc | Bin 0 -> 9148 bytes .../werkzeug/middleware/dispatcher.py | 78 + .../werkzeug/middleware/http_proxy.py | 230 + .../site-packages/werkzeug/middleware/lint.py | 420 + .../werkzeug/middleware/profiler.py | 139 + .../werkzeug/middleware/proxy_fix.py | 187 + .../werkzeug/middleware/shared_data.py | 280 + .vcrunch/Lib/site-packages/werkzeug/py.typed | 0 .../werkzeug/routing/__init__.py | 133 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 4620 bytes .../__pycache__/converters.cpython-310.pyc | Bin 0 -> 8737 bytes .../__pycache__/exceptions.cpython-310.pyc | Bin 0 -> 5487 bytes .../routing/__pycache__/map.cpython-310.pyc | Bin 0 -> 30976 bytes .../__pycache__/matcher.cpython-310.pyc | Bin 0 -> 4531 bytes .../routing/__pycache__/rules.cpython-310.pyc | Bin 0 -> 27058 bytes .../werkzeug/routing/converters.py | 257 + .../werkzeug/routing/exceptions.py | 146 + .../Lib/site-packages/werkzeug/routing/map.py | 944 ++ .../site-packages/werkzeug/routing/matcher.py | 185 + .../site-packages/werkzeug/routing/rules.py | 879 ++ .../site-packages/werkzeug/sansio/__init__.py | 0 .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 178 bytes .../sansio/__pycache__/http.cpython-310.pyc | Bin 0 -> 3865 bytes .../__pycache__/multipart.cpython-310.pyc | Bin 0 -> 6632 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 17056 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 22412 bytes .../sansio/__pycache__/utils.cpython-310.pyc | Bin 0 -> 4569 bytes .../Lib/site-packages/werkzeug/sansio/http.py | 140 + .../werkzeug/sansio/multipart.py | 279 + .../site-packages/werkzeug/sansio/request.py | 547 ++ .../site-packages/werkzeug/sansio/response.py | 704 ++ .../site-packages/werkzeug/sansio/utils.py | 165 + .../Lib/site-packages/werkzeug/security.py | 140 + .../Lib/site-packages/werkzeug/serving.py | 1098 +++ .vcrunch/Lib/site-packages/werkzeug/test.py | 1337 +++ .../Lib/site-packages/werkzeug/testapp.py | 241 + .vcrunch/Lib/site-packages/werkzeug/urls.py | 1067 +++ .../Lib/site-packages/werkzeug/user_agent.py | 47 + .vcrunch/Lib/site-packages/werkzeug/utils.py | 705 ++ .../werkzeug/wrappers/__init__.py | 3 + .../__pycache__/__init__.cpython-310.pyc | Bin 0 -> 297 bytes .../__pycache__/request.cpython-310.pyc | Bin 0 -> 20226 bytes .../__pycache__/response.cpython-310.pyc | Bin 0 -> 29155 bytes .../werkzeug/wrappers/request.py | 614 ++ .../werkzeug/wrappers/response.py | 877 ++ .vcrunch/Lib/site-packages/werkzeug/wsgi.py | 1020 ++ .vcrunch/Scripts/Activate.ps1 | 405 + .vcrunch/Scripts/activate | 69 + .vcrunch/Scripts/activate.bat | 34 + .vcrunch/Scripts/deactivate.bat | 22 + .vcrunch/Scripts/flask.exe | Bin 0 -> 106356 bytes .vcrunch/Scripts/pip.exe | Bin 0 -> 106369 bytes .vcrunch/Scripts/pip3.10.exe | Bin 0 -> 106369 bytes .vcrunch/Scripts/pip3.exe | Bin 0 -> 106369 bytes .vcrunch/Scripts/python.exe | Bin 0 -> 242920 bytes .vcrunch/Scripts/pythonw.exe | Bin 0 -> 232688 bytes .vcrunch/pyvenv.cfg | 3 + __pycache__/app.cpython-310.pyc | Bin 0 -> 1208 bytes app.py | 34 + templates/index.html | 1 + 1407 files changed, 270747 insertions(+) create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/REQUESTED create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/entry_points.txt create mode 100644 .vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt create mode 100644 .vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/_distutils_hack/__init__.py create mode 100644 .vcrunch/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/_distutils_hack/override.py create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/click-8.1.3.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/click/__init__.py create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/_compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/_textwrap.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/_winconsole.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/core.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/decorators.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/formatting.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/globals.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/shell_completion.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/termui.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/testing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/types.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/click/_compat.py create mode 100644 .vcrunch/Lib/site-packages/click/_termui_impl.py create mode 100644 .vcrunch/Lib/site-packages/click/_textwrap.py create mode 100644 .vcrunch/Lib/site-packages/click/_winconsole.py create mode 100644 .vcrunch/Lib/site-packages/click/core.py create mode 100644 .vcrunch/Lib/site-packages/click/decorators.py create mode 100644 .vcrunch/Lib/site-packages/click/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/click/formatting.py create mode 100644 .vcrunch/Lib/site-packages/click/globals.py create mode 100644 .vcrunch/Lib/site-packages/click/parser.py create mode 100644 .vcrunch/Lib/site-packages/click/py.typed create mode 100644 .vcrunch/Lib/site-packages/click/shell_completion.py create mode 100644 .vcrunch/Lib/site-packages/click/termui.py create mode 100644 .vcrunch/Lib/site-packages/click/testing.py create mode 100644 .vcrunch/Lib/site-packages/click/types.py create mode 100644 .vcrunch/Lib/site-packages/click/utils.py create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/LICENSE.txt create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/colorama/__init__.py create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/ansi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/ansitowin32.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/initialise.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/win32.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/__pycache__/winterm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/colorama/ansi.py create mode 100644 .vcrunch/Lib/site-packages/colorama/ansitowin32.py create mode 100644 .vcrunch/Lib/site-packages/colorama/initialise.py create mode 100644 .vcrunch/Lib/site-packages/colorama/win32.py create mode 100644 .vcrunch/Lib/site-packages/colorama/winterm.py create mode 100644 .vcrunch/Lib/site-packages/distutils-precedence.pth create mode 100644 .vcrunch/Lib/site-packages/flask/__init__.py create mode 100644 .vcrunch/Lib/site-packages/flask/__main__.py create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/__main__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/app.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/blueprints.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/cli.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/config.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/ctx.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/globals.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/helpers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/logging.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/scaffold.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/sessions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/signals.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/templating.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/testing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/typing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/views.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/__pycache__/wrappers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/app.py create mode 100644 .vcrunch/Lib/site-packages/flask/blueprints.py create mode 100644 .vcrunch/Lib/site-packages/flask/cli.py create mode 100644 .vcrunch/Lib/site-packages/flask/config.py create mode 100644 .vcrunch/Lib/site-packages/flask/ctx.py create mode 100644 .vcrunch/Lib/site-packages/flask/debughelpers.py create mode 100644 .vcrunch/Lib/site-packages/flask/globals.py create mode 100644 .vcrunch/Lib/site-packages/flask/helpers.py create mode 100644 .vcrunch/Lib/site-packages/flask/json/__init__.py create mode 100644 .vcrunch/Lib/site-packages/flask/json/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/json/__pycache__/provider.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/json/__pycache__/tag.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/flask/json/provider.py create mode 100644 .vcrunch/Lib/site-packages/flask/json/tag.py create mode 100644 .vcrunch/Lib/site-packages/flask/logging.py create mode 100644 .vcrunch/Lib/site-packages/flask/py.typed create mode 100644 .vcrunch/Lib/site-packages/flask/scaffold.py create mode 100644 .vcrunch/Lib/site-packages/flask/sessions.py create mode 100644 .vcrunch/Lib/site-packages/flask/signals.py create mode 100644 .vcrunch/Lib/site-packages/flask/templating.py create mode 100644 .vcrunch/Lib/site-packages/flask/testing.py create mode 100644 .vcrunch/Lib/site-packages/flask/typing.py create mode 100644 .vcrunch/Lib/site-packages/flask/views.py create mode 100644 .vcrunch/Lib/site-packages/flask/wrappers.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/LICENSE.rst create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/itsdangerous-2.1.2.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__init__.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/_json.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/encoding.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/exc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/serializer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/signer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/timed.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/__pycache__/url_safe.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/_json.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/encoding.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/exc.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/py.typed create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/serializer.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/signer.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/timed.py create mode 100644 .vcrunch/Lib/site-packages/itsdangerous/url_safe.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/__init__.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/_identifier.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/async_utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/bccache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/compiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/constants.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/debug.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/defaults.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/environment.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/ext.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/filters.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/idtracking.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/lexer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/loaders.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/meta.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/nativetypes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/nodes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/optimizer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/runtime.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/sandbox.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/tests.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/__pycache__/visitor.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/jinja2/_identifier.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/async_utils.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/bccache.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/compiler.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/constants.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/debug.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/defaults.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/environment.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/ext.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/filters.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/idtracking.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/lexer.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/loaders.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/meta.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/nativetypes.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/nodes.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/optimizer.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/parser.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/py.typed create mode 100644 .vcrunch/Lib/site-packages/jinja2/runtime.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/sandbox.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/tests.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/utils.py create mode 100644 .vcrunch/Lib/site-packages/jinja2/visitor.py create mode 100644 .vcrunch/Lib/site-packages/markupsafe/__init__.py create mode 100644 .vcrunch/Lib/site-packages/markupsafe/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/markupsafe/__pycache__/_native.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/markupsafe/_native.py create mode 100644 .vcrunch/Lib/site-packages/markupsafe/_speedups.c create mode 100644 .vcrunch/Lib/site-packages/markupsafe/_speedups.cp310-win_amd64.pyd create mode 100644 .vcrunch/Lib/site-packages/markupsafe/_speedups.pyi create mode 100644 .vcrunch/Lib/site-packages/markupsafe/py.typed create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/LICENSE.txt create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/REQUESTED create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/entry_points.txt create mode 100644 .vcrunch/Lib/site-packages/pip-21.2.3.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/pip/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/__main__.py create mode 100644 .vcrunch/Lib/site-packages/pip/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/__pycache__/__main__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/build_env.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/configuration.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/main.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/pyproject.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/build_env.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/main.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/autocompletion.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/base_command.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/cmdoptions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/command_context.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/main.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/main_parser.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/parser.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/progress_bars.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/req_command.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/spinners.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/cli/status_codes.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/check.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/completion.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/debug.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/download.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/hash.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/help.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/index.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/install.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/list.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/search.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/show.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/check.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/completion.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/configuration.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/debug.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/download.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/freeze.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/hash.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/help.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/index.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/install.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/list.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/search.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/show.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/uninstall.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/commands/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/configuration.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/installed.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/sdist.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/distributions/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/__pycache__/collector.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/__pycache__/sources.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/collector.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/package_finder.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/index/sources.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/_distutils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/_sysconfig.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/locations/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/main.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/metadata/pkg_resources.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/candidate.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/format_control.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/index.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/link.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/scheme.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/target_python.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/candidate.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/direct_url.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/format_control.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/index.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/link.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/scheme.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/search_scope.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/selection_prefs.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/target_python.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/models/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/auth.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/download.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/session.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/auth.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/download.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/lazy_wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/session.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/network/xmlrpc.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/__pycache__/check.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/metadata.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/metadata_legacy.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/build/wheel_legacy.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/check.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/freeze.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/__pycache__/legacy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/editable_legacy.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/legacy.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/install/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/operations/prepare.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/pyproject.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/constructors.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/req_file.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/req_install.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/req_set.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/req_tracker.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/constructors.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/req_file.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/req_install.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/req_set.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/req_tracker.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/req/req_uninstall.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/legacy/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/legacy/resolver.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/candidates.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/factory.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/provider.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/reporter.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/requirements.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/resolution/resolvelib/resolver.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/self_outdated_check.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/_log.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/distutils_args.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/inject_securetransport.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/logging.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/misc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/models.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/parallel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/pkg_resources.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/urls.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/_log.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/appdirs.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/compatibility_tags.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/datetime.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/deprecation.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/direct_url_helpers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/distutils_args.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/encoding.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/entrypoints.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/filesystem.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/filetypes.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/glibc.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/hashes.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/inject_securetransport.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/logging.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/misc.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/models.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/packaging.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/parallel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/pkg_resources.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/setuptools_build.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/subprocess.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/temp_dir.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/unpacking.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/urls.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/virtualenv.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/utils/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/git.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/bazaar.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/git.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/mercurial.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/subversion.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/vcs/versioncontrol.py create mode 100644 .vcrunch/Lib/site-packages/pip/_internal/wheel_builder.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__pycache__/appdirs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__pycache__/distro.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/__pycache__/six.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/appdirs.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/_cmd.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/adapter.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/controller.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/filewrapper.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/heuristics.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/serialize.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/cachecontrol/wrapper.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/__main__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/cacert.pem create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/certifi/core.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5freq.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/big5prober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/chardistribution.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetgroupprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/charsetprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/codingstatemachine.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/cp949prober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/enums.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/escprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/escsm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/eucjpprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrfreq.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/euckrprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwfreq.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/euctwprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312freq.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/gb2312prober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/hebrewprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/jisfreq.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/jpcntx.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langbulgarianmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langgreekmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhebrewmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langhungarianmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langrussianmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langthaimodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/langturkishmodel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/latin1prober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcharsetprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcsgroupprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/mbcssm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcharsetprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/sbcsgroupprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/sjisprober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/universaldetector.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/utf8prober.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/big5freq.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/big5prober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/chardistribution.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/charsetgroupprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/charsetprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/cli/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/cli/__pycache__/chardetect.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/cli/chardetect.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/codingstatemachine.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/cp949prober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/enums.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/escprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/escsm.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/eucjpprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/euckrfreq.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/euckrprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/euctwfreq.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/euctwprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/gb2312freq.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/gb2312prober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/hebrewprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/jisfreq.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/jpcntx.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langbulgarianmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langgreekmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langhebrewmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langhungarianmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langrussianmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langthaimodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/langturkishmodel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/latin1prober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/mbcharsetprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/mbcsgroupprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/mbcssm.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/metadata/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/metadata/__pycache__/languages.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/metadata/languages.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/sbcharsetprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/sbcsgroupprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/sjisprober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/universaldetector.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/utf8prober.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/chardet/version.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/ansitowin32.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/initialise.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/win32.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/__pycache__/winterm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/ansi.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/ansitowin32.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/initialise.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/win32.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/colorama/winterm.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__pycache__/misc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__pycache__/shutil.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__pycache__/sysconfig.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/__pycache__/tarfile.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/misc.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/shutil.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/sysconfig.cfg create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/sysconfig.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/_backport/tarfile.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/database.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/index.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/locators.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/manifest.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/markers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/metadata.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/resources.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/scripts.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/t32.exe create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/t64.exe create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/util.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/version.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/w32.exe create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/w64.exe create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distlib/wheel.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/distro.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/_ihatexml.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/_inputstream.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/_tokenizer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/_utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/constants.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/html5parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/__pycache__/serializer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_ihatexml.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_inputstream.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_tokenizer.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/__pycache__/_base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/__pycache__/py.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/_base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_trie/py.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/_utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/constants.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/alphabeticalattributes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/inject_meta_charset.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/lint.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/optionaltags.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/sanitizer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/__pycache__/whitespace.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/alphabeticalattributes.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/inject_meta_charset.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/lint.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/optionaltags.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/sanitizer.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/whitespace.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/html5parser.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/serializer.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/genshi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/__pycache__/sax.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/genshi.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treeadapters/sax.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/dom.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/__pycache__/etree_lxml.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/dom.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/etree.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treebuilders/etree_lxml.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/base.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/dom.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/etree_lxml.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/__pycache__/genshi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/base.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/dom.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/etree.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/etree_lxml.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/html5lib/treewalkers/genshi.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/core.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/codec.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/core.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/idnadata.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/intranges.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/package_data.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/idna/uts46data.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__pycache__/_version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/_version.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/ext.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/msgpack/fallback.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__about__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/_manylinux.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/_musllinux.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/_structures.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/markers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/requirements.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/specifiers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/tags.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/packaging/version.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/build.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/check.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/colorlog.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/dirtools.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/envbuild.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/meta.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/__pycache__/wrappers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/build.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/check.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/colorlog.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/dirtools.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/envbuild.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/in_process/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/in_process/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/in_process/__pycache__/_in_process.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/in_process/_in_process.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/meta.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pep517/wrappers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pkg_resources/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pkg_resources/__pycache__/py31compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pkg_resources/py31compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/__pycache__/bar.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/__pycache__/counter.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/__pycache__/spinner.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/bar.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/counter.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/progress/spinner.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/pyparsing.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/api.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/help.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/models.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/__version__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/_internal_utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/adapters.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/api.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/auth.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/certs.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/compat.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/cookies.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/help.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/hooks.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/models.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/packages.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/sessions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/status_codes.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/structures.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/requests/utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/compat/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/providers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/reporters.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/resolvers.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/resolvelib/structs.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/six.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_asyncio.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/_utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/after.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/before_sleep.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/nap.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/retry.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/stop.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/tornadoweb.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/__pycache__/wait.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/_asyncio.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/_utils.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/after.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/before.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/before_sleep.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/nap.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/retry.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/stop.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/tornadoweb.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tenacity/wait.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/_parser.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/tomli/_re.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/_collections.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/_version.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/connection.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/connectionpool.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/appengine.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/securetransport.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/contrib/socks.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/fields.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/filepost.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/six.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/__pycache__/_implementation.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/packages/ssl_match_hostname/_implementation.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/poolmanager.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/request.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/response.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/connection.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/proxy.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/queue.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/request.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/response.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/retry.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/ssl_.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/ssltransport.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/timeout.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/url.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/urllib3/util/wait.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/vendor.txt create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__pycache__/labels.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__pycache__/mklabels.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__pycache__/tests.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/__pycache__/x_user_defined.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/labels.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/mklabels.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/tests.py create mode 100644 .vcrunch/Lib/site-packages/pip/_vendor/webencodings/x_user_defined.py create mode 100644 .vcrunch/Lib/site-packages/pip/py.typed create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/__pycache__/appdirs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/appdirs.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__about__.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/_typing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/_compat.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/_structures.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/_typing.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/markers.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/requirements.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/specifiers.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/tags.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/utils.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/packaging/version.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/_vendor/pyparsing.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/extern/__init__.py create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/tests/data/my-test-package-source/__pycache__/setup.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/pkg_resources/tests/data/my-test-package-source/setup.py create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/INSTALLER create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/LICENSE create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/METADATA create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/RECORD create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/REQUESTED create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/WHEEL create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/entry_points.txt create mode 100644 .vcrunch/Lib/site-packages/setuptools-57.4.0.dist-info/top_level.txt create mode 100644 .vcrunch/Lib/site-packages/setuptools/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/_deprecation_warning.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/_imp.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/archive_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/build_meta.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/config.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/dep_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/depends.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/dist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/errors.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/extension.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/glob.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/installer.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/launch.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/lib2to3_ex.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/monkey.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/msvc.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/namespaces.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/package_index.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/py34compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/sandbox.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/unicode_utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/wheel.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/__pycache__/windows_support.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_deprecation_warning.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/_msvccompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/archive_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/bcppcompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/ccompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/cmd.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/config.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/core.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/cygwinccompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/debug.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/dep_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/dir_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/dist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/errors.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/extension.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/fancy_getopt.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/file_util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/filelist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/log.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/msvc9compiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/msvccompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/py35compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/py38compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/spawn.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/sysconfig.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/text_file.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/unixccompiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/util.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/__pycache__/versionpredicate.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/_msvccompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/archive_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/bcppcompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/ccompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/cmd.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_dumb.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_msi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/bdist_wininst.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/build.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_py.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/build_scripts.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/check.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/clean.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/config.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_data.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_headers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/py37compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/register.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/sdist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/__pycache__/upload.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/bdist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/bdist_dumb.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/bdist_msi.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/bdist_rpm.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/bdist_wininst.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/build.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/build_clib.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/build_ext.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/build_py.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/build_scripts.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/check.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/clean.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/config.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install_data.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install_egg_info.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install_headers.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install_lib.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/install_scripts.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/py37compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/register.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/sdist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/command/upload.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/config.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/core.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/cygwinccompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/debug.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/dep_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/dir_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/dist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/errors.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/extension.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/fancy_getopt.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/file_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/filelist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/log.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/msvc9compiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/msvccompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/py35compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/py38compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/spawn.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/sysconfig.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/text_file.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/unixccompiler.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/version.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_distutils/versionpredicate.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_imp.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/__pycache__/ordered_set.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/__pycache__/pyparsing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/more.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/__pycache__/recipes.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/more.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/more_itertools/recipes.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/ordered_set.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__about__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__about__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_structures.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/_typing.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/markers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/requirements.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/specifiers.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/tags.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/__pycache__/version.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/_compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/_structures.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/_typing.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/markers.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/requirements.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/specifiers.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/tags.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/utils.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/packaging/version.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/_vendor/pyparsing.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/archive_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/build_meta.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/cli-32.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/cli-64.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/cli.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/alias.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/bdist_egg.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/bdist_rpm.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/build_clib.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/build_ext.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/build_py.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/develop.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/dist_info.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/easy_install.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/egg_info.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/install.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/install_egg_info.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/install_lib.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/install_scripts.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/py36compat.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/register.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/rotate.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/saveopts.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/sdist.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/setopt.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/test.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/upload.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/__pycache__/upload_docs.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/alias.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/bdist_egg.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/bdist_rpm.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/build_clib.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/build_ext.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/build_py.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/develop.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/dist_info.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/easy_install.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/egg_info.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/install.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/install_egg_info.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/install_lib.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/install_scripts.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/launcher manifest.xml create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/py36compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/register.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/rotate.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/saveopts.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/sdist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/setopt.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/test.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/upload.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/command/upload_docs.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/config.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/dep_util.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/depends.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/dist.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/errors.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/extension.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/extern/__init__.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/extern/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/setuptools/glob.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/gui-32.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/gui-64.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/gui.exe create mode 100644 .vcrunch/Lib/site-packages/setuptools/installer.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/launch.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/lib2to3_ex.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/monkey.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/msvc.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/namespaces.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/package_index.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/py34compat.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/sandbox.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/script (dev).tmpl create mode 100644 .vcrunch/Lib/site-packages/setuptools/script.tmpl create mode 100644 .vcrunch/Lib/site-packages/setuptools/unicode_utils.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/version.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/wheel.py create mode 100644 .vcrunch/Lib/site-packages/setuptools/windows_support.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/_internal.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/_reloader.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/datastructures.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/formparser.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/http.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/local.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/security.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/serving.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/test.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/testapp.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/urls.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/user_agent.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/__pycache__/wsgi.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/_internal.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/_reloader.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/datastructures.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/datastructures.pyi create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/__pycache__/console.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/__pycache__/repr.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/__pycache__/tbtools.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/console.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/repr.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/ICON_LICENSE.md create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/console.png create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/debugger.js create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/less.png create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/more.png create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/shared/style.css create mode 100644 .vcrunch/Lib/site-packages/werkzeug/debug/tbtools.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/formparser.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/http.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/local.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/lint.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/profiler.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/proxy_fix.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/dispatcher.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/http_proxy.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/lint.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/profiler.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/proxy_fix.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/middleware/shared_data.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/py.typed create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/exceptions.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/rules.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/converters.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/exceptions.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/map.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/matcher.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/routing/rules.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/multipart.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/response.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/http.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/multipart.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/request.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/response.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/sansio/utils.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/security.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/serving.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/test.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/testapp.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/urls.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/user_agent.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/utils.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/__init__.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/request.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wrappers/response.py create mode 100644 .vcrunch/Lib/site-packages/werkzeug/wsgi.py create mode 100644 .vcrunch/Scripts/Activate.ps1 create mode 100644 .vcrunch/Scripts/activate create mode 100644 .vcrunch/Scripts/activate.bat create mode 100644 .vcrunch/Scripts/deactivate.bat create mode 100644 .vcrunch/Scripts/flask.exe create mode 100644 .vcrunch/Scripts/pip.exe create mode 100644 .vcrunch/Scripts/pip3.10.exe create mode 100644 .vcrunch/Scripts/pip3.exe create mode 100644 .vcrunch/Scripts/python.exe create mode 100644 .vcrunch/Scripts/pythonw.exe create mode 100644 .vcrunch/pyvenv.cfg create mode 100644 __pycache__/app.cpython-310.pyc create mode 100644 app.py create mode 100644 templates/index.html diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/LICENSE.rst b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/METADATA b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/METADATA new file mode 100644 index 0000000..f644287 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/METADATA @@ -0,0 +1,123 @@ +Metadata-Version: 2.1 +Name: Flask +Version: 2.2.2 +Summary: A simple framework for building complex web applications. +Home-page: https://palletsprojects.com/p/flask +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://flask.palletsprojects.com/ +Project-URL: Changes, https://flask.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/flask/ +Project-URL: Issue Tracker, https://github.com/pallets/flask/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Framework :: Flask +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: Werkzeug (>=2.2.2) +Requires-Dist: Jinja2 (>=3.0) +Requires-Dist: itsdangerous (>=2.0) +Requires-Dist: click (>=8.0) +Requires-Dist: importlib-metadata (>=3.6.0) ; python_version < "3.10" +Provides-Extra: async +Requires-Dist: asgiref (>=3.2) ; extra == 'async' +Provides-Extra: dotenv +Requires-Dist: python-dotenv ; extra == 'dotenv' + +Flask +===== + +Flask is a lightweight `WSGI`_ web application framework. It is designed +to make getting started quick and easy, with the ability to scale up to +complex applications. It began as a simple wrapper around `Werkzeug`_ +and `Jinja`_ and has become one of the most popular Python web +application frameworks. + +Flask offers suggestions, but doesn't enforce any dependencies or +project layout. It is up to the developer to choose the tools and +libraries they want to use. There are many extensions provided by the +community that make adding new functionality easy. + +.. _WSGI: https://wsgi.readthedocs.io/ +.. _Werkzeug: https://werkzeug.palletsprojects.com/ +.. _Jinja: https://jinja.palletsprojects.com/ + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Flask + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + # save this as app.py + from flask import Flask + + app = Flask(__name__) + + @app.route("/") + def hello(): + return "Hello, World!" + +.. code-block:: text + + $ flask run + * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) + + +Contributing +------------ + +For guidance on setting up a development environment and how to make a +contribution to Flask, see the `contributing guidelines`_. + +.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst + + +Donate +------ + +The Pallets organization develops and supports Flask and the libraries +it uses. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://flask.palletsprojects.com/ +- Changes: https://flask.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Flask/ +- Source Code: https://github.com/pallets/flask/ +- Issue Tracker: https://github.com/pallets/flask/issues/ +- Website: https://palletsprojects.com/p/flask/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/RECORD b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/RECORD new file mode 100644 index 0000000..010c44d --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/RECORD @@ -0,0 +1,54 @@ +../../Scripts/flask.exe,sha256=fVEwmSyJtdhDcs23_i4UTUnJZs0dHAxwHZM57vqlbzM,106356 +Flask-2.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Flask-2.2.2.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475 +Flask-2.2.2.dist-info/METADATA,sha256=UXiwRLD1johd_tGlYOlOKXkJFIG82ehR3bxqh4XWFwA,3889 +Flask-2.2.2.dist-info/RECORD,, +Flask-2.2.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +Flask-2.2.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Flask-2.2.2.dist-info/entry_points.txt,sha256=s3MqQpduU25y4dq3ftBYD6bMVdVnbMpZP-sUNw0zw0k,41 +Flask-2.2.2.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6 +flask/__init__.py,sha256=Y4mEWqAMxj_Oxq9eYv3tWyN-0nU9yVKBGK_t6BxqvvM,2890 +flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30 +flask/__pycache__/__init__.cpython-310.pyc,, +flask/__pycache__/__main__.cpython-310.pyc,, +flask/__pycache__/app.cpython-310.pyc,, +flask/__pycache__/blueprints.cpython-310.pyc,, +flask/__pycache__/cli.cpython-310.pyc,, +flask/__pycache__/config.cpython-310.pyc,, +flask/__pycache__/ctx.cpython-310.pyc,, +flask/__pycache__/debughelpers.cpython-310.pyc,, +flask/__pycache__/globals.cpython-310.pyc,, +flask/__pycache__/helpers.cpython-310.pyc,, +flask/__pycache__/logging.cpython-310.pyc,, +flask/__pycache__/scaffold.cpython-310.pyc,, +flask/__pycache__/sessions.cpython-310.pyc,, +flask/__pycache__/signals.cpython-310.pyc,, +flask/__pycache__/templating.cpython-310.pyc,, +flask/__pycache__/testing.cpython-310.pyc,, +flask/__pycache__/typing.cpython-310.pyc,, +flask/__pycache__/views.cpython-310.pyc,, +flask/__pycache__/wrappers.cpython-310.pyc,, +flask/app.py,sha256=VfBcGmEVveMcSajkUmDXCEOvAd-2mIBJ355KicvQ4gE,99025 +flask/blueprints.py,sha256=Jbrt-2jlLiFklC3De9EWBioPtDjHYYbXlTDK9Z7L2nk,26936 +flask/cli.py,sha256=foLlD8NiIXcxpxMmRQvvlZPbVM8pxOaJG3sa58c9dAA,33486 +flask/config.py,sha256=IWqHecH4poDxNEUg4U_ZA1CTlL5BKZDX3ofG4UGYyi0,12584 +flask/ctx.py,sha256=ZOGEWuFjsCIk3vm-C9pLME0e4saeBkeGpr2tTSvemSM,14851 +flask/debughelpers.py,sha256=_RvAL3TW5lqMJeCVWtTU6rSDJC7jnRaBL6OEkVmooyU,5511 +flask/globals.py,sha256=1DLZMi8Su-S1gf8zEiR3JPi6VXYIrYqm8C9__Ly66ss,3187 +flask/helpers.py,sha256=ELq27745jihrdyAP9qY8KENlCVDdnWRWTIn35L9a-UU,25334 +flask/json/__init__.py,sha256=TOwldHT3_kFaXHlORKi9yCWt7dbPNB0ovdHHQWlSRzY,11175 +flask/json/__pycache__/__init__.cpython-310.pyc,, +flask/json/__pycache__/provider.cpython-310.pyc,, +flask/json/__pycache__/tag.cpython-310.pyc,, +flask/json/provider.py,sha256=jXCNypf11PN4ngQjEt6LnSdCWQ1yHIAkNLHlXQlCB-A,10674 +flask/json/tag.py,sha256=fys3HBLssWHuMAIJuTcf2K0bCtosePBKXIWASZEEjnU,8857 +flask/logging.py,sha256=WYng0bLTRS_CJrocGcCLJpibHf1lygHE_pg-KoUIQ4w,2293 +flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +flask/scaffold.py,sha256=tiQRK-vMY5nucoN6pewXF87GaxrltsCGOgTVsT6wm7s,33443 +flask/sessions.py,sha256=66oGlE-v9iac-eb54tFN3ILAjJ1FeeuHHWw98UVaoxc,15847 +flask/signals.py,sha256=H7QwDciK-dtBxinjKpexpglP0E6k0MJILiFWTItfmqU,2136 +flask/templating.py,sha256=1P4OzvSnA2fsJTYgQT3G4owVKsuOz8XddCiR6jMHGJ0,7419 +flask/testing.py,sha256=p51f9P7jDc_IDSiZug7jypnfVcxsQrMg3B2tnjlpEFw,10596 +flask/typing.py,sha256=KgxegTF9v9WvuongeF8LooIvpZPauzGrq9ZXf3gBlYc,2969 +flask/views.py,sha256=bveWilivkPP-4HB9w_fOusBz6sHNIl0QTqKUFMCltzE,6738 +flask/wrappers.py,sha256=Wa-bhjNdPPveSHS1dpzD_r-ayZxIYFF1DoWncKOafrk,5695 diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/REQUESTED b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/REQUESTED new file mode 100644 index 0000000..e69de29 diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/WHEEL b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/entry_points.txt b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/entry_points.txt new file mode 100644 index 0000000..137232d --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[console_scripts] +flask = flask.cli:main diff --git a/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/top_level.txt new file mode 100644 index 0000000..7e10602 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Flask-2.2.2.dist-info/top_level.txt @@ -0,0 +1 @@ +flask diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/LICENSE.rst @@ -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/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA new file mode 100644 index 0000000..f54bb5c --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/METADATA @@ -0,0 +1,113 @@ +Metadata-Version: 2.1 +Name: Jinja2 +Version: 3.1.2 +Summary: A very fast and expressive template engine. +Home-page: https://palletsprojects.com/p/jinja/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://jinja.palletsprojects.com/ +Project-URL: Changes, https://jinja.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/jinja/ +Project-URL: Issue Tracker, https://github.com/pallets/jinja/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe (>=2.0) +Provides-Extra: i18n +Requires-Dist: Babel (>=2.7) ; 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. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U Jinja2 + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +In A Nutshell +------------- + +.. code-block:: jinja + + {% extends "base.html" %} + {% block title %}Members{% endblock %} + {% block content %} + + {% endblock %} + + +Donate +------ + +The Pallets organization develops and supports Jinja and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://jinja.palletsprojects.com/ +- Changes: https://jinja.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Jinja2/ +- Source Code: https://github.com/pallets/jinja/ +- Issue Tracker: https://github.com/pallets/jinja/issues/ +- Website: https://palletsprojects.com/p/jinja/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD new file mode 100644 index 0000000..af42ee3 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/RECORD @@ -0,0 +1,58 @@ +Jinja2-3.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Jinja2-3.1.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Jinja2-3.1.2.dist-info/METADATA,sha256=PZ6v2SIidMNixR7MRUX9f7ZWsPwtXanknqiZUmRbh4U,3539 +Jinja2-3.1.2.dist-info/RECORD,, +Jinja2-3.1.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Jinja2-3.1.2.dist-info/entry_points.txt,sha256=zRd62fbqIyfUpsRtU7EVIFyiu1tPwfgO7EvPErnxgTE,59 +Jinja2-3.1.2.dist-info/top_level.txt,sha256=PkeVWtLb3-CqjWi1fO29OCbj55EhX_chhKrCdrVe_zs,7 +jinja2/__init__.py,sha256=8vGduD8ytwgD6GDSqpYc2m3aU-T7PKOAddvVXgGr_Fs,1927 +jinja2/__pycache__/__init__.cpython-310.pyc,, +jinja2/__pycache__/_identifier.cpython-310.pyc,, +jinja2/__pycache__/async_utils.cpython-310.pyc,, +jinja2/__pycache__/bccache.cpython-310.pyc,, +jinja2/__pycache__/compiler.cpython-310.pyc,, +jinja2/__pycache__/constants.cpython-310.pyc,, +jinja2/__pycache__/debug.cpython-310.pyc,, +jinja2/__pycache__/defaults.cpython-310.pyc,, +jinja2/__pycache__/environment.cpython-310.pyc,, +jinja2/__pycache__/exceptions.cpython-310.pyc,, +jinja2/__pycache__/ext.cpython-310.pyc,, +jinja2/__pycache__/filters.cpython-310.pyc,, +jinja2/__pycache__/idtracking.cpython-310.pyc,, +jinja2/__pycache__/lexer.cpython-310.pyc,, +jinja2/__pycache__/loaders.cpython-310.pyc,, +jinja2/__pycache__/meta.cpython-310.pyc,, +jinja2/__pycache__/nativetypes.cpython-310.pyc,, +jinja2/__pycache__/nodes.cpython-310.pyc,, +jinja2/__pycache__/optimizer.cpython-310.pyc,, +jinja2/__pycache__/parser.cpython-310.pyc,, +jinja2/__pycache__/runtime.cpython-310.pyc,, +jinja2/__pycache__/sandbox.cpython-310.pyc,, +jinja2/__pycache__/tests.cpython-310.pyc,, +jinja2/__pycache__/utils.cpython-310.pyc,, +jinja2/__pycache__/visitor.cpython-310.pyc,, +jinja2/_identifier.py,sha256=_zYctNKzRqlk_murTNlzrju1FFJL7Va_Ijqqd7ii2lU,1958 +jinja2/async_utils.py,sha256=dHlbTeaxFPtAOQEYOGYh_PHcDT0rsDaUJAFDl_0XtTg,2472 +jinja2/bccache.py,sha256=mhz5xtLxCcHRAa56azOhphIAe19u1we0ojifNMClDio,14061 +jinja2/compiler.py,sha256=Gs-N8ThJ7OWK4-reKoO8Wh1ZXz95MVphBKNVf75qBr8,72172 +jinja2/constants.py,sha256=GMoFydBF_kdpaRKPoM5cl5MviquVRLVyZtfp5-16jg0,1433 +jinja2/debug.py,sha256=iWJ432RadxJNnaMOPrjIDInz50UEgni3_HKuFXi2vuQ,6299 +jinja2/defaults.py,sha256=boBcSw78h-lp20YbaXSJsqkAI2uN_mD_TtCydpeq5wU,1267 +jinja2/environment.py,sha256=6uHIcc7ZblqOMdx_uYNKqRnnwAF0_nzbyeMP9FFtuh4,61349 +jinja2/exceptions.py,sha256=ioHeHrWwCWNaXX1inHmHVblvc4haO7AXsjCp3GfWvx0,5071 +jinja2/ext.py,sha256=ivr3P7LKbddiXDVez20EflcO3q2aHQwz9P_PgWGHVqE,31502 +jinja2/filters.py,sha256=9js1V-h2RlyW90IhLiBGLM2U-k6SCy2F4BUUMgB3K9Q,53509 +jinja2/idtracking.py,sha256=GfNmadir4oDALVxzn3DL9YInhJDr69ebXeA2ygfuCGA,10704 +jinja2/lexer.py,sha256=DW2nX9zk-6MWp65YR2bqqj0xqCvLtD-u9NWT8AnFRxQ,29726 +jinja2/loaders.py,sha256=BfptfvTVpClUd-leMkHczdyPNYFzp_n7PKOJ98iyHOg,23207 +jinja2/meta.py,sha256=GNPEvifmSaU3CMxlbheBOZjeZ277HThOPUTf1RkppKQ,4396 +jinja2/nativetypes.py,sha256=DXgORDPRmVWgy034H0xL8eF7qYoK3DrMxs-935d0Fzk,4226 +jinja2/nodes.py,sha256=i34GPRAZexXMT6bwuf5SEyvdmS-bRCy9KMjwN5O6pjk,34550 +jinja2/optimizer.py,sha256=tHkMwXxfZkbfA1KmLcqmBMSaz7RLIvvItrJcPoXTyD8,1650 +jinja2/parser.py,sha256=nHd-DFHbiygvfaPtm9rcQXJChZG7DPsWfiEsqfwKerY,39595 +jinja2/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +jinja2/runtime.py,sha256=5CmD5BjbEJxSiDNTFBeKCaq8qU4aYD2v6q2EluyExms,33476 +jinja2/sandbox.py,sha256=Y0xZeXQnH6EX5VjaV2YixESxoepnRbW_3UeQosaBU3M,14584 +jinja2/tests.py,sha256=Am5Z6Lmfr2XaH_npIfJJ8MdXtWsbLjMULZJulTAj30E,5905 +jinja2/utils.py,sha256=u9jXESxGn8ATZNVolwmkjUVu4SA-tLgV0W7PcSfPfdQ,23965 +jinja2/visitor.py,sha256=MH14C6yq24G_KVtWzjwaI7Wg14PCJIYlWW1kpkxYak0,3568 diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt new file mode 100644 index 0000000..7b9666c --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/entry_points.txt @@ -0,0 +1,2 @@ +[babel.extractors] +jinja2 = jinja2.ext:babel_extract[i18n] diff --git a/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt new file mode 100644 index 0000000..7f7afbf --- /dev/null +++ b/.vcrunch/Lib/site-packages/Jinja2-3.1.2.dist-info/top_level.txt @@ -0,0 +1 @@ +jinja2 diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst new file mode 100644 index 0000000..9d227a0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2010 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/METADATA b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/METADATA new file mode 100644 index 0000000..485a5e0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/METADATA @@ -0,0 +1,101 @@ +Metadata-Version: 2.1 +Name: MarkupSafe +Version: 2.1.1 +Summary: Safely add untrusted strings to HTML/XML markup. +Home-page: https://palletsprojects.com/p/markupsafe/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://markupsafe.palletsprojects.com/ +Project-URL: Changes, https://markupsafe.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/markupsafe/ +Project-URL: Issue Tracker, https://github.com/pallets/markupsafe/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Web Environment +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content +Classifier: Topic :: Text Processing :: Markup :: HTML +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst + +MarkupSafe +========== + +MarkupSafe implements a text object that escapes characters so it is +safe to use in HTML and XML. Characters that have special meanings are +replaced so that they display as the actual characters. This mitigates +injection attacks, meaning untrusted user input can safely be displayed +on a page. + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U MarkupSafe + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +Examples +-------- + +.. code-block:: pycon + + >>> from markupsafe import Markup, escape + + >>> # escape replaces special characters and wraps in Markup + >>> escape("") + Markup('<script>alert(document.cookie);</script>') + + >>> # wrap in Markup to mark text "safe" and prevent escaping + >>> Markup("Hello") + Markup('hello') + + >>> escape(Markup("Hello")) + Markup('hello') + + >>> # Markup is a str subclass + >>> # methods and operators escape their arguments + >>> template = Markup("Hello {name}") + >>> template.format(name='"World"') + Markup('Hello "World"') + + +Donate +------ + +The Pallets organization develops and supports MarkupSafe and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://markupsafe.palletsprojects.com/ +- Changes: https://markupsafe.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/MarkupSafe/ +- Source Code: https://github.com/pallets/markupsafe/ +- Issue Tracker: https://github.com/pallets/markupsafe/issues/ +- Website: https://palletsprojects.com/p/markupsafe/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/RECORD b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/RECORD new file mode 100644 index 0000000..4801a06 --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/RECORD @@ -0,0 +1,14 @@ +MarkupSafe-2.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +MarkupSafe-2.1.1.dist-info/LICENSE.rst,sha256=RjHsDbX9kKVH4zaBcmTGeYIUM4FG-KyUtKV_lu6MnsQ,1503 +MarkupSafe-2.1.1.dist-info/METADATA,sha256=DC93VszmzjLQcrVChRUjtW4XbUwjTdbaplpgdlbFdbs,3242 +MarkupSafe-2.1.1.dist-info/RECORD,, +MarkupSafe-2.1.1.dist-info/WHEEL,sha256=C6CHup2HLC2Rld8AL5u9w89MYULjdaP5k0k7SG83CcI,102 +MarkupSafe-2.1.1.dist-info/top_level.txt,sha256=qy0Plje5IJuvsCBjejJyhDCjEAdcDLK_2agVcex8Z6U,11 +markupsafe/__init__.py,sha256=XGdbhy_OLrsQ5ZoFV3V6HQ3GeJ_ojcabRl_8yqehISk,9579 +markupsafe/__pycache__/__init__.cpython-310.pyc,, +markupsafe/__pycache__/_native.cpython-310.pyc,, +markupsafe/_native.py,sha256=_Q7UsXCOvgdonCgqG3l5asANI6eo50EKnDM-mlwEC5M,1776 +markupsafe/_speedups.c,sha256=n3jzzaJwXcoN8nTFyA53f3vSqsWK2vujI-v6QYifjhQ,7403 +markupsafe/_speedups.cp310-win_amd64.pyd,sha256=Mh72D6F52No2JwGW5GRZfeQKwRrES4u8uZFnw_nN4vk,15872 +markupsafe/_speedups.pyi,sha256=f5QtwIOP0eLrxh2v5p6SmaYmlcHIGIfmz0DovaqL0OU,238 +markupsafe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL new file mode 100644 index 0000000..ab9f74a --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.0) +Root-Is-Purelib: false +Tag: cp310-cp310-win_amd64 + diff --git a/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt new file mode 100644 index 0000000..75bf729 --- /dev/null +++ b/.vcrunch/Lib/site-packages/MarkupSafe-2.1.1.dist-info/top_level.txt @@ -0,0 +1 @@ +markupsafe diff --git a/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/LICENSE.rst b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/LICENSE.rst new file mode 100644 index 0000000..c37cae4 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/LICENSE.rst @@ -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/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/METADATA b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/METADATA new file mode 100644 index 0000000..a40cd1b --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/METADATA @@ -0,0 +1,126 @@ +Metadata-Version: 2.1 +Name: Werkzeug +Version: 2.2.2 +Summary: The comprehensive WSGI web application library. +Home-page: https://palletsprojects.com/p/werkzeug/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://werkzeug.palletsprojects.com/ +Project-URL: Changes, https://werkzeug.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/werkzeug/ +Project-URL: Issue Tracker, https://github.com/pallets/werkzeug/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +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 :: Internet :: WWW/HTTP :: WSGI +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application +Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Middleware +Classifier: Topic :: Software Development :: Libraries :: Application Frameworks +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: MarkupSafe (>=2.1.1) +Provides-Extra: watchdog +Requires-Dist: watchdog ; extra == 'watchdog' + +Werkzeug +======== + +*werkzeug* German noun: "tool". Etymology: *werk* ("work"), *zeug* ("stuff") + +Werkzeug is a comprehensive `WSGI`_ web application library. It began as +a simple collection of various utilities for WSGI applications and has +become one of the most advanced WSGI utility libraries. + +It includes: + +- An interactive debugger that allows inspecting stack traces and + source code in the browser with an interactive interpreter for any + frame in the stack. +- A full-featured request object with objects to interact with + headers, query args, form data, files, and cookies. +- A response object that can wrap other WSGI applications and handle + streaming data. +- A routing system for matching URLs to endpoints and generating URLs + for endpoints, with an extensible system for capturing variables + from URLs. +- HTTP utilities to handle entity tags, cache control, dates, user + agents, cookies, files, and more. +- A threaded WSGI server for use while developing applications + locally. +- A test client for simulating HTTP requests during testing without + requiring running a server. + +Werkzeug doesn't enforce any dependencies. It is up to the developer to +choose a template engine, database adapter, and even how to handle +requests. It can be used to build all sorts of end user applications +such as blogs, wikis, or bulletin boards. + +`Flask`_ wraps Werkzeug, using it to handle the details of WSGI while +providing more structure and patterns for defining powerful +applications. + +.. _WSGI: https://wsgi.readthedocs.io/en/latest/ +.. _Flask: https://www.palletsprojects.com/p/flask/ + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + pip install -U Werkzeug + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + from werkzeug.wrappers import Request, Response + + @Request.application + def application(request): + return Response('Hello, World!') + + if __name__ == '__main__': + from werkzeug.serving import run_simple + run_simple('localhost', 4000, application) + + +Donate +------ + +The Pallets organization develops and supports Werkzeug and other +popular packages. In order to grow the community of contributors and +users, and allow the maintainers to devote more time to the projects, +`please donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://werkzeug.palletsprojects.com/ +- Changes: https://werkzeug.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/Werkzeug/ +- Source Code: https://github.com/pallets/werkzeug/ +- Issue Tracker: https://github.com/pallets/werkzeug/issues/ +- Website: https://palletsprojects.com/p/werkzeug/ +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets diff --git a/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/RECORD b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/RECORD new file mode 100644 index 0000000..af07154 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/RECORD @@ -0,0 +1,98 @@ +Werkzeug-2.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +Werkzeug-2.2.2.dist-info/LICENSE.rst,sha256=O0nc7kEF6ze6wQ-vG-JgQI_oXSUrjp3y4JefweCUQ3s,1475 +Werkzeug-2.2.2.dist-info/METADATA,sha256=hz42ndovEQQy3rwXKZDwR7LA4UNthKegxf_7xIQrjsM,4416 +Werkzeug-2.2.2.dist-info/RECORD,, +Werkzeug-2.2.2.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +Werkzeug-2.2.2.dist-info/top_level.txt,sha256=QRyj2VjwJoQkrwjwFIOlB8Xg3r9un0NtqVHQF-15xaw,9 +werkzeug/__init__.py,sha256=UP218Ddd2NYm1dUhTlhvGRQytzAx1Ms1A716UKiPOYk,188 +werkzeug/__pycache__/__init__.cpython-310.pyc,, +werkzeug/__pycache__/_internal.cpython-310.pyc,, +werkzeug/__pycache__/_reloader.cpython-310.pyc,, +werkzeug/__pycache__/datastructures.cpython-310.pyc,, +werkzeug/__pycache__/exceptions.cpython-310.pyc,, +werkzeug/__pycache__/formparser.cpython-310.pyc,, +werkzeug/__pycache__/http.cpython-310.pyc,, +werkzeug/__pycache__/local.cpython-310.pyc,, +werkzeug/__pycache__/security.cpython-310.pyc,, +werkzeug/__pycache__/serving.cpython-310.pyc,, +werkzeug/__pycache__/test.cpython-310.pyc,, +werkzeug/__pycache__/testapp.cpython-310.pyc,, +werkzeug/__pycache__/urls.cpython-310.pyc,, +werkzeug/__pycache__/user_agent.cpython-310.pyc,, +werkzeug/__pycache__/utils.cpython-310.pyc,, +werkzeug/__pycache__/wsgi.cpython-310.pyc,, +werkzeug/_internal.py,sha256=g8PHJz2z39I3x0vwTvTKbXIg0eUQqGF9UtUzDMWT0Qw,16222 +werkzeug/_reloader.py,sha256=lYStlIDduTxBOB8BSozy_44HQ7YT5fup-x3uuac1-2o,14331 +werkzeug/datastructures.py,sha256=T1SRE_KRuNz9Q7P-Ck4PyKPyil1NOx9zDuNMLgrN1Z0,97083 +werkzeug/datastructures.pyi,sha256=HRzDLc7A6qnwluhNqn6AT76CsLZIkAbVVqxn0AbfV-s,34506 +werkzeug/debug/__init__.py,sha256=Gpq6OpS6mHwHk0mJkHc2fWvvjo6ccJVS9QJwJgoeb9I,18893 +werkzeug/debug/__pycache__/__init__.cpython-310.pyc,, +werkzeug/debug/__pycache__/console.cpython-310.pyc,, +werkzeug/debug/__pycache__/repr.cpython-310.pyc,, +werkzeug/debug/__pycache__/tbtools.cpython-310.pyc,, +werkzeug/debug/console.py,sha256=dechqiCtHfs0AQZWZofUC1S97tCuvwDgT0gdha5KwWM,6208 +werkzeug/debug/repr.py,sha256=FFczy4yhVfEQjW99HuZtUce-ebtJWMjp9GnfasXa0KA,9488 +werkzeug/debug/shared/ICON_LICENSE.md,sha256=DhA6Y1gUl5Jwfg0NFN9Rj4VWITt8tUx0IvdGf0ux9-s,222 +werkzeug/debug/shared/console.png,sha256=bxax6RXXlvOij_KeqvSNX0ojJf83YbnZ7my-3Gx9w2A,507 +werkzeug/debug/shared/debugger.js,sha256=tg42SZs1SVmYWZ-_Fj5ELK5-FLHnGNQrei0K2By8Bw8,10521 +werkzeug/debug/shared/less.png,sha256=-4-kNRaXJSONVLahrQKUxMwXGm9R4OnZ9SxDGpHlIR4,191 +werkzeug/debug/shared/more.png,sha256=GngN7CioHQoV58rH6ojnkYi8c_qED2Aka5FO5UXrReY,200 +werkzeug/debug/shared/style.css,sha256=-xSxzUEZGw_IqlDR5iZxitNl8LQUjBM-_Y4UAvXVH8g,6078 +werkzeug/debug/tbtools.py,sha256=Fsmlk6Ao3CcXm9iX7i_8MhCp2SQZ8uHm8Cf5wacnlW4,13293 +werkzeug/exceptions.py,sha256=5MFy6RyaU4nokoYzdDafloY51QUDIGVNKeK_FORUFS0,26543 +werkzeug/formparser.py,sha256=rLEu_ZwVpvqshZg6E4Qiv36QsmzmCytTijBeGX3dDGk,16056 +werkzeug/http.py,sha256=i_LrIU9KsOz27zfkwKIK6eifFuFMKgSuW15k57HbMiE,42162 +werkzeug/local.py,sha256=1IRMV9MFrauLaZeliF0Md1n7ZOcOKLbS03bnQ8Gz5WY,22326 +werkzeug/middleware/__init__.py,sha256=qfqgdT5npwG9ses3-FXQJf3aB95JYP1zchetH_T3PUw,500 +werkzeug/middleware/__pycache__/__init__.cpython-310.pyc,, +werkzeug/middleware/__pycache__/dispatcher.cpython-310.pyc,, +werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc,, +werkzeug/middleware/__pycache__/lint.cpython-310.pyc,, +werkzeug/middleware/__pycache__/profiler.cpython-310.pyc,, +werkzeug/middleware/__pycache__/proxy_fix.cpython-310.pyc,, +werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc,, +werkzeug/middleware/dispatcher.py,sha256=Fh_w-KyWnTSYF-Lfv5dimQ7THSS7afPAZMmvc4zF1gg,2580 +werkzeug/middleware/http_proxy.py,sha256=HE8VyhS7CR-E1O6_9b68huv8FLgGGR1DLYqkS3Xcp3Q,7558 +werkzeug/middleware/lint.py,sha256=Sr6gV4royDs6ezkqv5trRAyKMDQ60KaEq3-tQ3opUvw,13968 +werkzeug/middleware/profiler.py,sha256=QkXk7cqnaPnF8wQu-5SyPCIOT3_kdABUBorQOghVNOA,4899 +werkzeug/middleware/proxy_fix.py,sha256=l7LC_LDu0Yd4SvUxS5SFigAJMzcIOGm6LNKl9IXJBSU,6974 +werkzeug/middleware/shared_data.py,sha256=fXjrEkuqxUVLG1DLrOdQLc96QQdjftCBZ1oM5oK89h4,9528 +werkzeug/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/routing/__init__.py,sha256=HpvahY7WwkLdV4Cq3Bsc3GrqNon4u6t8-vhbb9E5o00,4819 +werkzeug/routing/__pycache__/__init__.cpython-310.pyc,, +werkzeug/routing/__pycache__/converters.cpython-310.pyc,, +werkzeug/routing/__pycache__/exceptions.cpython-310.pyc,, +werkzeug/routing/__pycache__/map.cpython-310.pyc,, +werkzeug/routing/__pycache__/matcher.cpython-310.pyc,, +werkzeug/routing/__pycache__/rules.cpython-310.pyc,, +werkzeug/routing/converters.py,sha256=05bkekg64vLC6mqqK4ddBh589WH9yBsjtW8IJhdUBvw,6968 +werkzeug/routing/exceptions.py,sha256=RklUDL9ajOv2fTcRNj4pb18Bs4Y-GKk4rIeTSfsqkks,4737 +werkzeug/routing/map.py,sha256=XN4ZjzEF1SfMxtdov89SDE-1_U78KVnnobTfnHzqbmE,36757 +werkzeug/routing/matcher.py,sha256=U8xZTB3e5f3TgbkxdDyVuyxK4w72l1lo_b3tdG2zNrc,7122 +werkzeug/routing/rules.py,sha256=v27RaR5H3sIPRdJ_pdEfOBMN6EivFVpmFzJk7aizdyw,31072 +werkzeug/sansio/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +werkzeug/sansio/__pycache__/__init__.cpython-310.pyc,, +werkzeug/sansio/__pycache__/http.cpython-310.pyc,, +werkzeug/sansio/__pycache__/multipart.cpython-310.pyc,, +werkzeug/sansio/__pycache__/request.cpython-310.pyc,, +werkzeug/sansio/__pycache__/response.cpython-310.pyc,, +werkzeug/sansio/__pycache__/utils.cpython-310.pyc,, +werkzeug/sansio/http.py,sha256=9eORg44CDxpmV9i_U_pZ_NR8gdc9UXFCdE7EAP1v-c0,5162 +werkzeug/sansio/multipart.py,sha256=Uyrg2U6s2oft8LXOyuTvFCWTLOEr7INVW8zFTXNwZ7A,9756 +werkzeug/sansio/request.py,sha256=SiGcx2cz-l81TlCCrKrT2fePqC64hN8fSg5Ig6J6vRs,20175 +werkzeug/sansio/response.py,sha256=UTl-teQDDjovrZMkjj3ZQsHw-JtiFak5JfKEk1_vBYU,26026 +werkzeug/sansio/utils.py,sha256=EjbqdHdT-JZWgjUQaaWSgBUIRprXUkrsMQQqJlJHpVU,4847 +werkzeug/security.py,sha256=vrBofh4WZZoUo1eAdJ6F1DrzVRlYauGS2CUDYpbQKj8,4658 +werkzeug/serving.py,sha256=18pfjrHw8b5UCgPPo1ZEoxlYZZ5UREl4jQ9f8LGWMAo,38458 +werkzeug/test.py,sha256=t7T5G-HciIlv1ZXtlydFVpow0VrXnJ_Y3yyEB7T0_Ww,48125 +werkzeug/testapp.py,sha256=RJhT_2JweNiMKe304N3bF1zaIeMpRx-CIMERdeydfTY,9404 +werkzeug/urls.py,sha256=Q9Si-eVh7yxk3rwkzrwGRm146FXVXgg9lBP3k0HUfVM,36600 +werkzeug/user_agent.py,sha256=WclZhpvgLurMF45hsioSbS75H1Zb4iMQGKN3_yZ2oKo,1420 +werkzeug/utils.py,sha256=OYdB2cZPYYgq3C0EVKMIv05BrYzzr9xdefW0H00_IVo,24936 +werkzeug/wrappers/__init__.py,sha256=kGyK7rOud3qCxll_jFyW15YarJhj1xtdf3ocx9ZheB8,120 +werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/request.cpython-310.pyc,, +werkzeug/wrappers/__pycache__/response.cpython-310.pyc,, +werkzeug/wrappers/request.py,sha256=UQ559KkGS0Po6HTBgvKMlk1_AsNw5zstzm8o_dRrfdQ,23415 +werkzeug/wrappers/response.py,sha256=c2HUXrrt5Sf8-XEB1fUXxm6jp7Lu80KR0A_tbQFvw1Q,34750 +werkzeug/wsgi.py,sha256=sgkFCzhl23hlSmbvjxbI-hVEjSlPuEBGTDAHmXFcAts,34732 diff --git a/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/WHEEL b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/top_level.txt new file mode 100644 index 0000000..6fe8da8 --- /dev/null +++ b/.vcrunch/Lib/site-packages/Werkzeug-2.2.2.dist-info/top_level.txt @@ -0,0 +1 @@ +werkzeug diff --git a/.vcrunch/Lib/site-packages/_distutils_hack/__init__.py b/.vcrunch/Lib/site-packages/_distutils_hack/__init__.py new file mode 100644 index 0000000..5f40996 --- /dev/null +++ b/.vcrunch/Lib/site-packages/_distutils_hack/__init__.py @@ -0,0 +1,128 @@ +import sys +import os +import re +import importlib +import warnings + + +is_pypy = '__pypy__' in sys.builtin_module_names + + +warnings.filterwarnings('ignore', + r'.+ distutils\b.+ deprecated', + DeprecationWarning) + + +def warn_distutils_present(): + if 'distutils' not in sys.modules: + return + if is_pypy and sys.version_info < (3, 7): + # PyPy for 3.6 unconditionally imports distutils, so bypass the warning + # https://foss.heptapod.net/pypy/pypy/-/blob/be829135bc0d758997b3566062999ee8b23872b4/lib-python/3/site.py#L250 + return + warnings.warn( + "Distutils was imported before Setuptools, but importing Setuptools " + "also replaces the `distutils` module in `sys.modules`. This may lead " + "to undesirable behaviors or errors. To avoid these issues, avoid " + "using distutils directly, ensure that setuptools is installed in the " + "traditional way (e.g. not an editable install), and/or make sure " + "that setuptools is always imported before distutils.") + + +def clear_distutils(): + if 'distutils' not in sys.modules: + return + warnings.warn("Setuptools is replacing distutils.") + mods = [name for name in sys.modules if re.match(r'distutils\b', name)] + for name in mods: + del sys.modules[name] + + +def enabled(): + """ + Allow selection of distutils by environment variable. + """ + which = os.environ.get('SETUPTOOLS_USE_DISTUTILS', 'stdlib') + return which == 'local' + + +def ensure_local_distutils(): + clear_distutils() + distutils = importlib.import_module('setuptools._distutils') + distutils.__name__ = 'distutils' + sys.modules['distutils'] = distutils + + # sanity check that submodules load as expected + core = importlib.import_module('distutils.core') + assert '_distutils' in core.__file__, core.__file__ + + +def do_override(): + """ + Ensure that the local copy of distutils is preferred over stdlib. + + See https://github.com/pypa/setuptools/issues/417#issuecomment-392298401 + for more motivation. + """ + if enabled(): + warn_distutils_present() + ensure_local_distutils() + + +class DistutilsMetaFinder: + def find_spec(self, fullname, path, target=None): + if path is not None: + return + + method_name = 'spec_for_{fullname}'.format(**locals()) + method = getattr(self, method_name, lambda: None) + return method() + + def spec_for_distutils(self): + import importlib.abc + import importlib.util + + class DistutilsLoader(importlib.abc.Loader): + + def create_module(self, spec): + return importlib.import_module('setuptools._distutils') + + def exec_module(self, module): + pass + + return importlib.util.spec_from_loader('distutils', DistutilsLoader()) + + def spec_for_pip(self): + """ + Ensure stdlib distutils when running under pip. + See pypa/pip#8761 for rationale. + """ + if self.pip_imported_during_build(): + return + clear_distutils() + self.spec_for_distutils = lambda: None + + @staticmethod + def pip_imported_during_build(): + """ + Detect if pip is being imported in a build script. Ref #2355. + """ + import traceback + return any( + frame.f_globals['__file__'].endswith('setup.py') + for frame, line in traceback.walk_stack(None) + ) + + +DISTUTILS_FINDER = DistutilsMetaFinder() + + +def add_shim(): + sys.meta_path.insert(0, DISTUTILS_FINDER) + + +def remove_shim(): + try: + sys.meta_path.remove(DISTUTILS_FINDER) + except ValueError: + pass diff --git a/.vcrunch/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/_distutils_hack/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..876470a3c99ba93575ccd586073c87f8d561dd9c GIT binary patch literal 5124 zcmbtYO>^7E8Qujz2%;ofmL1n=(gv;5G@Qm%>^L8GRp-NUQnxmpMpiuKC12u-EOr-*-DltTc|R8M z++3OA`uo2=3ECCL{!NX^tAxgTxRbx45KQohHS#BKaNRZ&f~iCraoksrv!P219aP^|aB?Zl!VNjL1e50agvmN%0JHTPaSOx%vY<3`dKZW_D& zu8>Kn{3eDsW!v8hW0knEa-~wJ;fvVyx8e|k+cLqFNz#`9miP4&f>kVx8ibifJFmI2 zoAj}lwC$&EQfvsH15}dwQH1>h9sy64FTym8yM6?D?6|MW+Ir3H#;NOfU5Qs3-0-t1 zmhOs00POgi(tXw6nZpq@h6`D&+*P3vMzp_4M7=MIN7w(p?LNbw> z{<3j?<>tNBkMG^Rdwa!OUAgHk-&(o1dhgclmCR035rxgHq-9aBnwb&90)}&C=DJL) zJS%Ot!=Qb9=NLt6h$?M>c2cn%u3kXp$Ucv7?*qNhea2a;_j(A931gRe<}OREjgl~y z@;C6Cdt6w%e8b*i$xFWhH#Y2j{%5d+WK#d;xv>kWjg^|yvQp5d7QlUG(l-5Kx zox51t`&?f2aLvhwZaH}RYR|kSv2o)ft<@doTp_uUh)#jhgf5S33Qju z^ITmxE+@1hmLVU0h)T-#!M~JiX&F>fDAVE082nRf_U433CBLaxc7wRLbCe#iO}LB} z95{Sz3~%P>Y_Ry0E!A4snMVL7yR1C zwBUVOnKOc&Sv@~(XLjlwctyk07sZ#unl9wgd#XtGXBzy4g)4&(H79)O*1z(K69s8hLKzbWpBd2)= z9a>6Xumf!EkaAh0t|)X?xq68nhPsFcbOWt^#nq3|$fd3YJ{Ks7RCegx?&GD7hh;vv zQ>;IxeC>PStsR;91o{z!)hh((=Oa`jxOVPskMmwukmOo3nvx!J3>P~ z(?RNS-k5g=uM~K{Q`1N6i_}LXyg{?MD0V@>Lk4#T3g$5>cW#K?$XP&3Yp|jHKjkXJ zxReK(i8N)qExRr=!nQ945d>nF_h z8GM@{Sm7_#tJu#vZbhlf;PQ8hhwx2gin*_Zn|vNGywN$$6Mcm(dCh(p37uf5_c1k0 zlx%YXgI3yXp){HU19EkhEcn0*AGrSu&yl^;zKgizqCp8{#P*=1+(AKc1||2D(C?F? zN`t$FqLyWfbkYr5qz6jjo03#B+83S2e4IG3D>n&L*h_2fC$i;UxctVOZ;sWb9ccXs ze@q}D|D4eMGKxP@ra!l4?D0Kh_z0KmdCK|W(mq9I^AHdL%~U_Z(1D|q4jg>y$n&RL z-g*=_k*Q~n?22R?2?_?D#=xx9QV5@!6@}ds+1T{by6nnFJ#{@M3>0dNKU&N-Do@H! z2Jbyh$j?;i1OrBsf&$YxrUtT!!y4?kyOWi-{bq?gW;xCHxF8evMn_rw-1M zj^k8}a)m2;bA)JUkIyS~5*nRXQuELl{^LMsB0dg}QQ0(>_q{wxz+qjgG@CEZ9^Qwy z>dQAjc^a(D@deV9cG!7@*>u2K;Ob-4Paq;e(uNbV>A`f435Ymn_jTfA;astEhJ$0A z{a*KM=ivxZK%e#Q;KR&TvO`JdU22p+^`pMLNq;+@if$$!tO4%Q+L~K@fzQH#jVEda zebt40_8*|GPEnx)GmXs7l0l_mcNBdn1xys}B&*<Ofn K`=VpcTK@&e0SRaT literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc b/.vcrunch/Lib/site-packages/_distutils_hack/__pycache__/override.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..02b918f61770ccccaa30b13d070b0f2be84e5b12 GIT binary patch literal 229 zcmd1j<>g`kf=PRWl68ReV-N=!FabFZKwK;UBvKht7@8RuFfL?ZWJqBQX3%7c;*U?s zEG{W6$;>H^&qz$p_S0m##T6f)nOl%wR1zN_#hsELpI??*RFs*Lx{{#?WE`0I73ypi z6Iz^FR2-99l$o3uQ=DH~kd&WT5|dn1nwOjrqgMuH_+%!<6la#C>J|WvPfSlOjzP0h cA7;K@LFFwDo80`A(wtN~Mv$XH)(J2G0Dd(=*8l(j literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/_distutils_hack/override.py b/.vcrunch/Lib/site-packages/_distutils_hack/override.py new file mode 100644 index 0000000..2cc433a --- /dev/null +++ b/.vcrunch/Lib/site-packages/_distutils_hack/override.py @@ -0,0 +1 @@ +__import__('_distutils_hack').do_override() diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst new file mode 100644 index 0000000..d12a849 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/LICENSE.rst @@ -0,0 +1,28 @@ +Copyright 2014 Pallets + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/METADATA b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/METADATA new file mode 100644 index 0000000..8e5dc1e --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/METADATA @@ -0,0 +1,111 @@ +Metadata-Version: 2.1 +Name: click +Version: 8.1.3 +Summary: Composable command line interface toolkit +Home-page: https://palletsprojects.com/p/click/ +Author: Armin Ronacher +Author-email: armin.ronacher@active-4.com +Maintainer: Pallets +Maintainer-email: contact@palletsprojects.com +License: BSD-3-Clause +Project-URL: Donate, https://palletsprojects.com/donate +Project-URL: Documentation, https://click.palletsprojects.com/ +Project-URL: Changes, https://click.palletsprojects.com/changes/ +Project-URL: Source Code, https://github.com/pallets/click/ +Project-URL: Issue Tracker, https://github.com/pallets/click/issues/ +Project-URL: Twitter, https://twitter.com/PalletsTeam +Project-URL: Chat, https://discord.gg/pallets +Platform: UNKNOWN +Classifier: Development Status :: 5 - Production/Stable +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Requires-Python: >=3.7 +Description-Content-Type: text/x-rst +License-File: LICENSE.rst +Requires-Dist: colorama ; platform_system == "Windows" +Requires-Dist: importlib-metadata ; python_version < "3.8" + +\$ click\_ +========== + +Click is a Python package for creating beautiful command line interfaces +in a composable way with as little code as necessary. It's the "Command +Line Interface Creation Kit". It's highly configurable but comes with +sensible defaults out of the box. + +It aims to make the process of writing command line tools quick and fun +while also preventing any frustration caused by the inability to +implement an intended CLI API. + +Click in three points: + +- Arbitrary nesting of commands +- Automatic help page generation +- Supports lazy loading of subcommands at runtime + + +Installing +---------- + +Install and update using `pip`_: + +.. code-block:: text + + $ pip install -U click + +.. _pip: https://pip.pypa.io/en/stable/getting-started/ + + +A Simple Example +---------------- + +.. code-block:: python + + import click + + @click.command() + @click.option("--count", default=1, help="Number of greetings.") + @click.option("--name", prompt="Your name", help="The person to greet.") + def hello(count, name): + """Simple program that greets NAME for a total of COUNT times.""" + for _ in range(count): + click.echo(f"Hello, {name}!") + + if __name__ == '__main__': + hello() + +.. code-block:: text + + $ python hello.py --count=3 + Your name: Click + Hello, Click! + Hello, Click! + Hello, Click! + + +Donate +------ + +The Pallets organization develops and supports Click and other popular +packages. In order to grow the community of contributors and users, and +allow the maintainers to devote more time to the projects, `please +donate today`_. + +.. _please donate today: https://palletsprojects.com/donate + + +Links +----- + +- Documentation: https://click.palletsprojects.com/ +- Changes: https://click.palletsprojects.com/changes/ +- PyPI Releases: https://pypi.org/project/click/ +- Source Code: https://github.com/pallets/click +- Issue Tracker: https://github.com/pallets/click/issues +- Website: https://palletsprojects.com/p/click +- Twitter: https://twitter.com/PalletsTeam +- Chat: https://discord.gg/pallets + + diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/RECORD b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/RECORD new file mode 100644 index 0000000..0fd3496 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/RECORD @@ -0,0 +1,39 @@ +click-8.1.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +click-8.1.3.dist-info/LICENSE.rst,sha256=morRBqOU6FO_4h9C9OctWSgZoigF2ZG18ydQKSkrZY0,1475 +click-8.1.3.dist-info/METADATA,sha256=tFJIX5lOjx7c5LjZbdTPFVDJSgyv9F74XY0XCPp_gnc,3247 +click-8.1.3.dist-info/RECORD,, +click-8.1.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92 +click-8.1.3.dist-info/top_level.txt,sha256=J1ZQogalYS4pphY_lPECoNMfw0HzTSrZglC4Yfwo4xA,6 +click/__init__.py,sha256=rQBLutqg-z6m8nOzivIfigDn_emijB_dKv9BZ2FNi5s,3138 +click/__pycache__/__init__.cpython-310.pyc,, +click/__pycache__/_compat.cpython-310.pyc,, +click/__pycache__/_termui_impl.cpython-310.pyc,, +click/__pycache__/_textwrap.cpython-310.pyc,, +click/__pycache__/_winconsole.cpython-310.pyc,, +click/__pycache__/core.cpython-310.pyc,, +click/__pycache__/decorators.cpython-310.pyc,, +click/__pycache__/exceptions.cpython-310.pyc,, +click/__pycache__/formatting.cpython-310.pyc,, +click/__pycache__/globals.cpython-310.pyc,, +click/__pycache__/parser.cpython-310.pyc,, +click/__pycache__/shell_completion.cpython-310.pyc,, +click/__pycache__/termui.cpython-310.pyc,, +click/__pycache__/testing.cpython-310.pyc,, +click/__pycache__/types.cpython-310.pyc,, +click/__pycache__/utils.cpython-310.pyc,, +click/_compat.py,sha256=JIHLYs7Jzz4KT9t-ds4o4jBzLjnwCiJQKqur-5iwCKI,18810 +click/_termui_impl.py,sha256=qK6Cfy4mRFxvxE8dya8RBhLpSC8HjF-lvBc6aNrPdwg,23451 +click/_textwrap.py,sha256=10fQ64OcBUMuK7mFvh8363_uoOxPlRItZBmKzRJDgoY,1353 +click/_winconsole.py,sha256=5ju3jQkcZD0W27WEMGqmEP4y_crUVzPCqsX_FYb7BO0,7860 +click/core.py,sha256=mz87bYEKzIoNYEa56BFAiOJnvt1Y0L-i7wD4_ZecieE,112782 +click/decorators.py,sha256=yo3zvzgUm5q7h5CXjyV6q3h_PJAiUaem178zXwdWUFI,16350 +click/exceptions.py,sha256=7gDaLGuFZBeCNwY9ERMsF2-Z3R9Fvq09Zc6IZSKjseo,9167 +click/formatting.py,sha256=Frf0-5W33-loyY_i9qrwXR8-STnW3m5gvyxLVUdyxyk,9706 +click/globals.py,sha256=TP-qM88STzc7f127h35TD_v920FgfOD2EwzqA0oE8XU,1961 +click/parser.py,sha256=cAEt1uQR8gq3-S9ysqbVU-fdAZNvilxw4ReJ_T1OQMk,19044 +click/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0 +click/shell_completion.py,sha256=qOp_BeC9esEOSZKyu5G7RIxEUaLsXUX-mTb7hB1r4QY,18018 +click/termui.py,sha256=ACBQVOvFCTSqtD5VREeCAdRtlHd-Imla-Lte4wSfMjA,28355 +click/testing.py,sha256=ptpMYgRY7dVfE3UDgkgwayu9ePw98sQI3D7zZXiCpj4,16063 +click/types.py,sha256=rEb1aZSQKq3ciCMmjpG2Uva9vk498XRL7ThrcK2GRss,35805 +click/utils.py,sha256=33D6E7poH_nrKB-xr-UyDEXnxOcCiQqxuRLtrqeVv6o,18682 diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/WHEEL b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/WHEEL new file mode 100644 index 0000000..becc9a6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/WHEEL @@ -0,0 +1,5 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py3-none-any + diff --git a/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/top_level.txt new file mode 100644 index 0000000..dca9a90 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click-8.1.3.dist-info/top_level.txt @@ -0,0 +1 @@ +click diff --git a/.vcrunch/Lib/site-packages/click/__init__.py b/.vcrunch/Lib/site-packages/click/__init__.py new file mode 100644 index 0000000..e3ef423 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/__init__.py @@ -0,0 +1,73 @@ +""" +Click is a simple Python module inspired by the stdlib optparse to make +writing command line scripts fun. Unlike other modules, it's based +around a simple API that does not come with too much magic and is +composable. +""" +from .core import Argument as Argument +from .core import BaseCommand as BaseCommand +from .core import Command as Command +from .core import CommandCollection as CommandCollection +from .core import Context as Context +from .core import Group as Group +from .core import MultiCommand as MultiCommand +from .core import Option as Option +from .core import Parameter as Parameter +from .decorators import argument as argument +from .decorators import command as command +from .decorators import confirmation_option as confirmation_option +from .decorators import group as group +from .decorators import help_option as help_option +from .decorators import make_pass_decorator as make_pass_decorator +from .decorators import option as option +from .decorators import pass_context as pass_context +from .decorators import pass_obj as pass_obj +from .decorators import password_option as password_option +from .decorators import version_option as version_option +from .exceptions import Abort as Abort +from .exceptions import BadArgumentUsage as BadArgumentUsage +from .exceptions import BadOptionUsage as BadOptionUsage +from .exceptions import BadParameter as BadParameter +from .exceptions import ClickException as ClickException +from .exceptions import FileError as FileError +from .exceptions import MissingParameter as MissingParameter +from .exceptions import NoSuchOption as NoSuchOption +from .exceptions import UsageError as UsageError +from .formatting import HelpFormatter as HelpFormatter +from .formatting import wrap_text as wrap_text +from .globals import get_current_context as get_current_context +from .parser import OptionParser as OptionParser +from .termui import clear as clear +from .termui import confirm as confirm +from .termui import echo_via_pager as echo_via_pager +from .termui import edit as edit +from .termui import getchar as getchar +from .termui import launch as launch +from .termui import pause as pause +from .termui import progressbar as progressbar +from .termui import prompt as prompt +from .termui import secho as secho +from .termui import style as style +from .termui import unstyle as unstyle +from .types import BOOL as BOOL +from .types import Choice as Choice +from .types import DateTime as DateTime +from .types import File as File +from .types import FLOAT as FLOAT +from .types import FloatRange as FloatRange +from .types import INT as INT +from .types import IntRange as IntRange +from .types import ParamType as ParamType +from .types import Path as Path +from .types import STRING as STRING +from .types import Tuple as Tuple +from .types import UNPROCESSED as UNPROCESSED +from .types import UUID as UUID +from .utils import echo as echo +from .utils import format_filename as format_filename +from .utils import get_app_dir as get_app_dir +from .utils import get_binary_stream as get_binary_stream +from .utils import get_text_stream as get_text_stream +from .utils import open_file as open_file + +__version__ = "8.1.3" diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1a8a05d37122c65328c3d7303ca671e07ff58da GIT binary patch literal 2612 zcmc)M*;3m`6b4`e-ZA?U)}TNLVKZykH`^>BAwaR*oT5r4%Z=TGw(6Ec$OFu~%uCFJ z_;#-573ONrIW~}af`Q`a>sG5(~PM{NzU?~?eqbg(Q>&Ifl2rq~nCM|T>g+3(RaFvFfi&%!MG19}eT z*i-0vm}h@PXCcd;MlZkudj`D-i|kqS5-hRj(95vQo=3013OkElg;n-~^T}Ot)`LhtDj7@E5v5vm0b-Me8&-XD1EPf+zZ7IIx}{H7Z)Hh->Ob1 zUr&r*1dY+DOG{a<2!+C7N$Yjhg#EH&kL`Q+Qn?nLV`35O3&qNf*;^~Z310hqsI+Ea zX>FE-?JFzvY4Z5Xi5WhIlQu3h$!)**8;AM7c%vztiWvCUQbzsrd?GEKTh-Yt~2$?a23tPkJ*l}s8CpWE;rqa zuq(d#U0PVqGLMRilB7FN;G}ki$HyJ3>e&_Sj0ILzQw>@J<(HMvx>z59O*h~jp=m}M zs>3ITh9;`sGo$&7i!0t8E3dN0d$x*5i{*E1=UF2>M>0`&Y!Yj+;vbUU` zQ)lwjd+Dn0t(&KSPrtN6y2kkR&DH7o2~BiU#U~fhdV79(bx}CFzCJp{X7u*OI9I#RrNhijNf26f+dF6mt~w6j_W~EW}S! zs|D&gHelBLy1?qOC5U@`xFNhIf^_+t<^N2 zpMUd@i26zgDE|3c*t)yLM@QcYC2i|Y@Kj6g)ZZNVvcvzse#eMLGVx5)|NEV6{uhV7u?GME literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/_compat.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/_compat.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd2721cb6ab9eafec2d571f0d0b7cd31a2332862 GIT binary patch literal 15750 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 YydNsD`lDaq-aEZ?U!?CIF?09+H~X8!e*gdg literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/_termui_impl.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8288c464d496f14657acdf5ee6b7bc4a0aa9efd5 GIT binary patch literal 16071 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 V;2*BeJnN3qSC~d$?{o?s{J(YGq^$q| literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/_textwrap.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/_textwrap.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a47efbbf3f41557dadc452bbf923075ede5508f3 GIT binary patch literal 1546 zcmZWpOK;mo5Z)J86fMh*>-Z6%JrrmG9_j|U6exlsKnfHo3>}iT0R$BU#a-K!C{o@f z{Q?EFu=^{50`jqcqCaG>J^3%B4|j%AQnguPhdZ+~oY`-_WwE{<5E%5g=gBjVkl#^R z9RidmFzq7{iYS_q{^Cvh40M+9iRcSTz9xz*aZQxaWaM4(zNhF55_-1~M|vT3-K5A% zeO^xDJU-GULHp{!I-bC^3WO$ost9DDnvaC`_8`;S71t87NaZPc7^s%=uSLJ5ebv^U z^1!RD9mB&sRT~;RVB>>sm(S{Ym^%Q1vh?3Nz=DPse6`OfA8Bz0b zO%>ZCGg(VTYVT)Uw`y5?iZpA#W^-1zZYU+SkG_uq>=&eF_F=O_=lq7?E?RMhymw0> z;q4uaP&ht`&)s`NqvLUu75PzgRv2ZS#3Sa)@o6y)+fG=W9U3gw;0cUG(E{NDJBRjA2V=yoRogNKHQ{j6|>l8eMAi zvZKiNgp!xgf*NgR8Y{;6biEe1(`wjjIc+VhH9SuV1+B&Z$+Qg+s%4KPZ_sp6da4@?l*3ngriZl=90<#Bb zVdm8FRGkAkA)vwW|KO}G(2t5dyZ8iRY!`%}TY!xZbBhJ+a%UBj75}i~{3y!fiH;%{ zMA4*B6>u|hohUk~;%vD?;c^_L7Vd>D4b+pD<~}4b$U5ggEAe23G1wXN5emFGD*~Hn zI0(eseh9)R460*)`<(s71pAYD><=b`*KG3v-R?BLfSQjD!<*w|c`;4%BZCKY!SdId grNgF##(gDSlf5C1|9EktFR>FAFNII=if!|M07qhh3IG5A literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/_winconsole.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/_winconsole.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..400281818bffa0cd4a722ab8f83d8f187087d71a GIT binary patch literal 7664 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 H^1u6EBVX-z literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/core.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/core.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0f4533ad22093630d4b87343d05c2bc7e67c7bf2 GIT binary patch literal 90241 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 +}&c40p+_7&K`bCr-QywB97+Ct@7=!FN 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/exceptions.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/exceptions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d1cd2635cb92080155bd66d172b5446729d6699f GIT binary patch literal 10194 zcmbtaOLH98b?(FOd6tX#rB96DWyE2Gi*%v01fp# zbi0QnhCszGvdW8u+iV^(ceqRzwEonyOO`)n>UU1S3cufHrLIxv>hZ#a6dt^+|SaV zVMz@XoIt+K%66Rifl?@Pg3iu>uWb(c*=v;>p7MG@5~#E~WU{>z_LH=zf@Gxn9rl%9 zOgp$YamR1qv5)N;nd)SMRAN4~;*-Al#PTiQeuR?ujECk^On2YFl%3|-cHeU6`m@l5 z&Axb_#p4%f`?J!4iT=!o=EsIX*@Iet&R$YYTZh$jkiO9eSNlyzL;q-HF1^CvOG! zJHaps2mN?sxR+Mm*$(=_{h@kym9ygKT0dVi#;>(^2VuWGU7>j6ooLYUqWIm7$t&x2 zS`Fi{A17YF6Qp*WsMO(m>!zxpCz-K+G>}bKj&xe*phY}Z?Ng>>snbYyaL-*-9$s-5 zkHBb|z5%5%Tefet9N!KKRFtmsOQUQ0MZff@)++i=Q0Q8I*{?vzOIfb!FCkZkfY*Y` zZWZ?ultSJWB`CCNzr=>Oma%`0w7$vZx}LAr_>Zsk-O1Xy$&Qz}(!%X{eRs#}`%&QH z>Bc*Qdu}p7i@+UWqc#*5H7)gmIL0<80!6b!S;((kE<`rgP?{JIjVI>F*7 z3blkPEO{Xw4I#bdc025cNxQAiu-rH%-+!Ed-(`^GM$ROa){%tll%pyKd`*SiDN^OAPV++8m_5OL|x>5sm#eI-{^?}S3D)B11 zTQ4Yzv*I$QW;-qF?^Z7BEWLp+U-wAUX;~fq5MGy#g*VbB&jn1Y@X!c6cm|~x`@}94!2PnyB>5I@3`QVf!c80TRUOwCVN9ba1`xTU0mMQKqY9|-*dYo1@%`N z7Q+7aMpar|5jb@-xws+_AsyyL#0@`;hmp6pG5ba*xqrnSWIGV;$%`FLX&Q+-9-ziY z8neo$D8k|13!_N7;uP}>Vjtm?=lbzR$pE^lKZup_pclAckP!;W7ShXSRNtoPd}?D_ ziaREl*0Hm_<3FbJJANCPIY_ezX#f#Ro#d0s)OM&oKA=UXv=|o@X;O>h*O5v~ok6b$ zl*QORf8EylLJ3o>Rw8*5AdvU|1m&VLHR#L*b9{2T_Y<@e&76Y)LICx2lW+e$9`i8Z z8wY@a1I&Au@L;M9rgp6-Qt~t_OB~+QjSl*z(slh`{oTk8RUPD(JbSdw#M65GoUd@>+qRN;5Ua7jLOO_tJxG$qw8H zT7nKPxd0t^Cy0g{intEk`3C-_MO~koRg}ESl0s(?4U`ffCETvpGcFuuhUQBYC1XC^kqzCT0-Ux-Qgf_>$S)@udD@(%8~i`335{!2V&aj##Ov(18QOun08M&s043sOn7FTV z4!Ie683To#9qDH>8@3AL^$dqMHr%_gpwWTn`+QUeo|R?PIXD8+4N6 z0arKy)}RcXL#_V56}VB*O}Ltu#Y#N-g@WDuHq4cl+=5=ht~(sWakv!)bMzon6hG#Q z?3DuL=xI{Gu>nIY>~w2f(tox;3r3L{)2PLyg;nsb7YRKk;oX31en&>ULzd`xaiBMC z{);7tEmwit8O5L$_pTR(zHkX`=hDkH7^ z8me?BcT12Kt{`VXm5i83ne*Mg^%SPzJ{iv1ckr}{&zjww8Fu?N-jTjxAc`eDCACS_ zB6{2AfHWrSr6LXb)3d5QA-FknnhZWMacO6PYqVoa)`5}RUnBbnuSx0&x!QheqK3>v z^Ou}fr15*xK#9$gq(moH%E52InL=}X_Wi!>I`@7Q95#u^>vPq@N)M*8d@$1=DMVHGKTn=+i)pixFREt4T(!zp6$~;yKewV9 zdUA*6ncZwQpH&xf$0FKrF~ISR@eXP~!X4A-CSzEq$XU*BE%KRdeO`8~-<1p2Z>?he z`P!0V`ws58YdOosKS$yylL(uvkWF@BN7EKzD&rKUG^gaXV34d`73>1{80^Bx5!nTn zHrR#HBRbVO$Jmk6stDIqAp@&vy08Zj}TQKXo#<1Uz7KBucX7{ zI%4x};BG%hUEt-%gi@_kz-B<~ojaE%U0%9#=kjr#p`EtV(1du))=<_(&7h zy45#*3nj*G;lP4r&Je;MO?r{kZV@%cZfVB;zsVN6=%9oZwG!yP5O4A#mmj-rYpNNwl>^WITx96uG|w%Ro}v5j_cXNXR6$) zOk{Jsl2=WOPUS@z_EWG95H8^+r{)HH4gqbELYn&;;~6QGCan|Fl_;<{7TP&=*iGvs z>7l0)C#$^I)v_?v4=|6z>v9og|G-HS zE{brv;DlM@vq!!)3&6of;I+QAkU^(DmvHHPQ0jOZy@sLxigTd%CN#QC8Wk#i4)<`5 zO3Ov-xmBwFcYSH?D~fL(A=HU$=A-r~p@IM>u9>)D1#!p<2tvUrn|IYF4qC;pO1P>l z4w^oSnUZEbtu+TXVcdQo5ub7QFk8YW3VK6Yudu}@q34`9B{c01z*;$1BDxpad6VQPtM7>&q(=Ol(!=$hm5!L6Fl-Le=}|7fL&|@1~UTLsY3Bu|6}Pr9gz3rF!ZM;zR$8 zO6{VT8fM+nM)d6RFD4CYBR^j>lA0hIDM22Dv2ZGsFsvgdLL>;D5hXO5QS#8~iibvZx zPdXBhaq;@U;f~kvC?X!yu(aBhP3!ZbQ~X_{Fg`!GwDXXszJvFU!Gd{fIxXLX!5HAs zX(m*CY$WE-(Ct5QUPLDWgo=Q{#ICN-+SPT%_8r`F7de7gOsjhy1`u!25P+j3iOcBN zwADq-1@^LzO_#(bE@Ok2(mGrUt=kfd^3Kj##Mo}FhqN1cI;R+7hDHpBQ3#!lc`5p1iY!Hiu`pf{Y=1_Mq7R{&6^@DXRDdr z35#(@;^zoVbot$8WcJM0;X>DGVwE!P0yEib> ze{e`5oycz0`4ZAAH}vXD%Ub(FvDFcYg-{t+asQ@)$E?Kq^v>sJ@xM-q z2K$~1!|yMK`5XU#L6msGoD}ALb2h(^9DWmCp0L_8XW=f$DZ%u?HBukq@n2jq?r#|( zWhptbu#5@uir>RyZeepE$V0LPFup#Z;<+@P=7KQ3K9>eO;Ix?`*`>7dJ)A^d=i$=$ z;><3%JfP$WGe3C?dV_cw!c@()%nGr~{uGn=KMr8Nh9(&umo*)OhE32gToax#C-xIq zj893$1vzgn3Kd(;@$#tuNuL2*39*1VgnB2en_7byQ;Ge6XNT$1C~QyW^)Uv`PiUA{ zGSLMZg%gd8fnhh-EIF56oh-*hrREG`$~HG?6SvUK#LB>V5-1fv4UiZVtcf=_CDzCV z-QqC_on(8LIoK8(rGPM>eRxqf##TLvRnG#K+tGMMzW==KuQ;mu~zx9jw z{ZYv;KPupd8byeIHFd7z0DAm4nE9bu&W2#{iwn{fg2sp$%>|Nqe2tUNWJeAyMelK9 zk&I%{m5*4tlw_x`EYVCf(}affq!S$m!7m%+_=l^UI&wD7uH5p+&)HQG-ZErFA9HakTJ~+ES|$82pocR& zIr>Wrqa=)CeQdXU>!&xaw>N)qee;L!H^0wCQi0}Y4kX8AY2l+j&RNt4ED+|SL+1OgQQ5Ge8J3uP9!xgzoUQg@Ge(R&Yy|q nHU0r#inwd0WuFCoBFOtiqtZCjxYT%~alLV|v4Y&nDd&Fx&A%T$ literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/formatting.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/formatting.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..071c1298c3ba8f2769b09fa012755f18f2a9f3d9 GIT binary patch literal 9457 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 I+gINFU#h-EH2?qr literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/globals.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/globals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..efa63adff1eaf89ec6a2f1b3c0748a461f9e100f GIT binary patch literal 2431 zcmZ`*UvJz*5ck@?%jJ?>o3y1#TVRp+cc?uO5<)s51d3V+R7aHtp&p0s_Pl#%r#`Q> zyS_`J6rr}Se24b2d;*^MAb#bk&%9MgWoB(dQiYYg-rX6`{^qwcvzBXXO$QqJV>fuV zlB@6d6Fli2AKc)PJX^ZFif1ljl1Wh<%m>)hjhyfka{8zAu>IsIjj zH~D40$(wxTaqSW5uh^9>UKgvp0pm5kyyZ-MzE;UW`&C&BW&IU?g`el^kNtj&U*#M8 z0*ub_Yy2Ww5vyBHVGl=O?-G9vzB$jyU8nu}b3pI(+9a>VGGOs@0#leRZOg=n19K~{ z>nIk9d9iLp=XPX-V)2i+SggfQd0h#UsYLnkO@JR(4afLw!}AwPxpUWfMtaYnQ#F_? zt#qo%ArjFcoGPWJ&?xVNiImf*4%rd{?c(tMk7|RRcjSV`t&vm;V7(t2jjq=W)=2 z?vy3m0zX5abq~6urg5GSPK>+nad*pk>iz&M_>S>SZQ>rjOPmLUI7h8xM_)A%ACJf} zc?df99PU3LKNIfXEk_HoaN0HY5VqL0jB9E_K}$!erGb|2b|~EoBTWOA(6OMI7MwCo z8C|eLYGji_V?iMFD>e$Us2uN$z|e`3Gs=>~MJSZ0OoCNLXHp3o%~GH~GKIAmf+Ari znhV&#BI{1z=(?knX$H zip7F~PScv%lQhkAc$UU>+MNj#c1LB3baWt7F*?b3X{6JkbHENRGR_6>cIhXbj|%(U zlqoi&MQ(LzG@)7;q;IsRGBAe7itM6u7H2@YrlX!rKm@vptd84)#WOw8@SNr>irF|W z&Q1XL6PCqDQb_^mz-Ed?T2OYDk*+v^6Wq-b6V1d;rKB2lte(yG=P#ihy|stofzSXD zgR_JPI30|=_EJtv?gvbpygsxgCa-A&8JxGiG)6_^%oOJH=1#)Jf!!)!J-Kn)wKXFr z;;d}Eg!#4soqO&g*&se?lIBa_Yy9H=oqK^fIF+PWl&~JzB;AC8arVg*my;=^=M(SP zc}fVBa43x4(Fb=R00hQ-A{G_jRfJc$XI<&23t+0(_7&pD8^a-w0y7-uO*qt&`n=B4 zR3yAj6z=u%4cm?pBYACZVU==D{cnSsAR&@91on0}Lb3l$k zWMoQXF&B_cnA5maVD7a&3)f=Ly;PS(;Ff#8k_S-g?CQob*@tV$0{4%8+ri{bSX^d3k_{Ezg03RC z$ObvFi*|cDiP;ot%Fd*Wkrle^PVn~31)byKv59tIP4=d&!&KqVhE2RS>43mS5XP|;^Z*4a^z7Z$UeD|1FomM0@S@6>O{fIp zILEWe*Y@t+xjEea`sVhxJH4;^>xJ$R?s}16snWS?1Y|7KdAnm7(-2T9mW*3}bAK#l zoHxEpv3|4IMyU-6i~h_&YJ4`6Jd4HWn1dR_y5X#ny4xVw`(BIq{xx#NZ*DegZ`b|- D6moJz literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/parser.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/parser.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e82ae6d3d4981cd021df934791c55eb9c18e83fb GIT binary patch literal 13674 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 TuJAv)YMzLXaCWyj`sx1xq53t8 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/termui.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/termui.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..790f0ce5f75382c6c003c2e5f74dd876aebfc892 GIT binary patch literal 26215 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 F{~w=Nw)Ox3 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/testing.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0e794b9ef6c3822f71f484badfee6dbc344c8483 GIT binary patch literal 15193 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 Ki!d=ev;4m_?4^zX literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/__pycache__/types.cpython-310.pyc b/.vcrunch/Lib/site-packages/click/__pycache__/types.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..0c1891b04a6c62827d852ed3475014d24ee65dac GIT binary patch literal 33242 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 ZyV_Ugx7b(drz~T*KgVYumD2RX{|98=ZdU*R literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/click/_compat.py b/.vcrunch/Lib/site-packages/click/_compat.py new file mode 100644 index 0000000..766d286 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/_compat.py @@ -0,0 +1,626 @@ +import codecs +import io +import os +import re +import sys +import typing as t +from weakref import WeakKeyDictionary + +CYGWIN = sys.platform.startswith("cygwin") +MSYS2 = sys.platform.startswith("win") and ("GCC" in sys.version) +# Determine local App Engine environment, per Google's own suggestion +APP_ENGINE = "APPENGINE_RUNTIME" in os.environ and "Development/" in os.environ.get( + "SERVER_SOFTWARE", "" +) +WIN = sys.platform.startswith("win") and not APP_ENGINE and not MSYS2 +auto_wrap_for_ansi: t.Optional[t.Callable[[t.TextIO], t.TextIO]] = None +_ansi_re = re.compile(r"\033\[[;?0-9]*[a-zA-Z]") + + +def get_filesystem_encoding() -> str: + return sys.getfilesystemencoding() or sys.getdefaultencoding() + + +def _make_text_stream( + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if encoding is None: + encoding = get_best_encoding(stream) + if errors is None: + errors = "replace" + return _NonClosingTextIOWrapper( + stream, + encoding, + errors, + line_buffering=True, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def is_ascii_encoding(encoding: str) -> bool: + """Checks if a given encoding is ascii.""" + try: + return codecs.lookup(encoding).name == "ascii" + except LookupError: + return False + + +def get_best_encoding(stream: t.IO) -> str: + """Returns the default stream encoding if not found.""" + rv = getattr(stream, "encoding", None) or sys.getdefaultencoding() + if is_ascii_encoding(rv): + return "utf-8" + return rv + + +class _NonClosingTextIOWrapper(io.TextIOWrapper): + def __init__( + self, + stream: t.BinaryIO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, + force_writable: bool = False, + **extra: t.Any, + ) -> None: + self._stream = stream = t.cast( + t.BinaryIO, _FixupStream(stream, force_readable, force_writable) + ) + super().__init__(stream, encoding, errors, **extra) + + def __del__(self) -> None: + try: + self.detach() + except Exception: + pass + + def isatty(self) -> bool: + # https://bitbucket.org/pypy/pypy/issue/1803 + return self._stream.isatty() + + +class _FixupStream: + """The new io interface needs more from streams than streams + traditionally implement. As such, this fix-up code is necessary in + some circumstances. + + The forcing of readable and writable flags are there because some tools + put badly patched objects on sys (one such offender are certain version + of jupyter notebook). + """ + + def __init__( + self, + stream: t.BinaryIO, + force_readable: bool = False, + force_writable: bool = False, + ): + self._stream = stream + self._force_readable = force_readable + self._force_writable = force_writable + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._stream, name) + + def read1(self, size: int) -> bytes: + f = getattr(self._stream, "read1", None) + + if f is not None: + return t.cast(bytes, f(size)) + + return self._stream.read(size) + + def readable(self) -> bool: + if self._force_readable: + return True + x = getattr(self._stream, "readable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.read(0) + except Exception: + return False + return True + + def writable(self) -> bool: + if self._force_writable: + return True + x = getattr(self._stream, "writable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.write("") # type: ignore + except Exception: + try: + self._stream.write(b"") + except Exception: + return False + return True + + def seekable(self) -> bool: + x = getattr(self._stream, "seekable", None) + if x is not None: + return t.cast(bool, x()) + try: + self._stream.seek(self._stream.tell()) + except Exception: + return False + return True + + +def _is_binary_reader(stream: t.IO, 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, 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.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_reader(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_reader(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _find_binary_writer(stream: t.IO) -> t.Optional[t.BinaryIO]: + # We need to figure out if the given stream is already binary. + # This can happen because the official docs recommend detaching + # the streams to get binary streams. Some code might do this, so + # we need to deal with this case explicitly. + if _is_binary_writer(stream, False): + return t.cast(t.BinaryIO, stream) + + buf = getattr(stream, "buffer", None) + + # Same situation here; this time we assume that the buffer is + # actually binary in case it's closed. + if buf is not None and _is_binary_writer(buf, True): + return t.cast(t.BinaryIO, buf) + + return None + + +def _stream_is_misconfigured(stream: t.TextIO) -> bool: + """A stream is misconfigured if its encoding is ASCII.""" + # If the stream does not have an encoding set, we assume it's set + # to ASCII. This appears to happen in certain unittest + # environments. It's not quite clear what the correct behavior is + # but this at least will force Click to recover somehow. + return is_ascii_encoding(getattr(stream, "encoding", None) or "ascii") + + +def _is_compat_stream_attr(stream: t.TextIO, attr: str, value: t.Optional[str]) -> bool: + """A stream attribute is compatible if it is equal to the + desired value or the desired value is unset and the attribute + has a value. + """ + stream_value = getattr(stream, attr, None) + return stream_value == value or (value is None and stream_value is not None) + + +def _is_compatible_text_stream( + stream: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> bool: + """Check if a stream's encoding and errors attributes are + compatible with the desired values. + """ + return _is_compat_stream_attr( + stream, "encoding", encoding + ) and _is_compat_stream_attr(stream, "errors", errors) + + +def _force_correct_text_stream( + text_stream: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + is_binary: t.Callable[[t.IO, bool], bool], + find_binary: t.Callable[[t.IO], t.Optional[t.BinaryIO]], + force_readable: bool = False, + force_writable: bool = False, +) -> t.TextIO: + if is_binary(text_stream, False): + binary_reader = t.cast(t.BinaryIO, text_stream) + else: + text_stream = t.cast(t.TextIO, text_stream) + # If the stream looks compatible, and won't default to a + # misconfigured ascii encoding, return it as-is. + if _is_compatible_text_stream(text_stream, encoding, errors) and not ( + encoding is None and _stream_is_misconfigured(text_stream) + ): + return text_stream + + # Otherwise, get the underlying binary reader. + possible_binary_reader = find_binary(text_stream) + + # If that's not possible, silently use the original reader + # and get mojibake instead of exceptions. + if possible_binary_reader is None: + return text_stream + + binary_reader = possible_binary_reader + + # Default errors to replace instead of strict in order to get + # something that works. + if errors is None: + errors = "replace" + + # Wrap the binary stream in a text stream with the correct + # encoding parameters. + return _make_text_stream( + binary_reader, + encoding, + errors, + force_readable=force_readable, + force_writable=force_writable, + ) + + +def _force_correct_text_reader( + text_reader: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_readable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_reader, + encoding, + errors, + _is_binary_reader, + _find_binary_reader, + force_readable=force_readable, + ) + + +def _force_correct_text_writer( + text_writer: t.IO, + encoding: t.Optional[str], + errors: t.Optional[str], + force_writable: bool = False, +) -> t.TextIO: + return _force_correct_text_stream( + text_writer, + encoding, + errors, + _is_binary_writer, + _find_binary_writer, + force_writable=force_writable, + ) + + +def get_binary_stdin() -> t.BinaryIO: + reader = _find_binary_reader(sys.stdin) + if reader is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdin.") + return reader + + +def get_binary_stdout() -> t.BinaryIO: + writer = _find_binary_writer(sys.stdout) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stdout.") + return writer + + +def get_binary_stderr() -> t.BinaryIO: + writer = _find_binary_writer(sys.stderr) + if writer is None: + raise RuntimeError("Was not able to determine binary stream for sys.stderr.") + return writer + + +def get_text_stdin( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdin, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_reader(sys.stdin, encoding, errors, force_readable=True) + + +def get_text_stdout( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stdout, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stdout, encoding, errors, force_writable=True) + + +def get_text_stderr( + encoding: t.Optional[str] = None, errors: t.Optional[str] = None +) -> t.TextIO: + rv = _get_windows_console_stream(sys.stderr, encoding, errors) + if rv is not None: + return rv + return _force_correct_text_writer(sys.stderr, encoding, errors, force_writable=True) + + +def _wrap_io_open( + file: t.Union[str, os.PathLike, int], + mode: str, + encoding: t.Optional[str], + errors: t.Optional[str], +) -> t.IO: + """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, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, +) -> t.Tuple[t.IO, bool]: + binary = "b" in mode + + # Standard streams first. These are simple because they ignore the + # atomic flag. Use fsdecode to handle Path("-"). + if os.fsdecode(filename) == "-": + if any(m in mode for m in ["w", "a", "x"]): + if binary: + return get_binary_stdout(), False + return get_text_stdout(encoding=encoding, errors=errors), False + if binary: + return get_binary_stdin(), False + return get_text_stdin(encoding=encoding, errors=errors), False + + # Non-atomic writes directly go out through the regular open functions. + if not atomic: + return _wrap_io_open(filename, mode, encoding, errors), True + + # Some usability stuff for atomic writes + if "a" in mode: + raise ValueError( + "Appending to an existing file is not supported, because that" + " would involve an expensive `copy`-operation to a temporary" + " file. Open the file in normal `w`-mode and copy explicitly" + " if that's what you're after." + ) + if "x" in mode: + raise ValueError("Use the `overwrite`-parameter instead.") + if "w" not in mode: + raise ValueError("Atomic writes only make sense with `w`-mode.") + + # Atomic writes are more complicated. They work by opening a file + # as a proxy in the same folder and then using the fdopen + # functionality to wrap it in a Python file. Then we wrap it in an + # atomic file that moves the file over on close. + import errno + import random + + try: + perm: t.Optional[int] = os.stat(filename).st_mode + except OSError: + perm = None + + flags = os.O_RDWR | os.O_CREAT | os.O_EXCL + + if binary: + flags |= getattr(os, "O_BINARY", 0) + + while True: + tmp_filename = os.path.join( + os.path.dirname(filename), + f".__atomic-write{random.randrange(1 << 32):08x}", + ) + try: + fd = os.open(tmp_filename, flags, 0o666 if perm is None else perm) + break + except OSError as e: + if e.errno == errno.EEXIST or ( + os.name == "nt" + and e.errno == errno.EACCES + and os.path.isdir(e.filename) + and os.access(e.filename, os.W_OK) + ): + continue + raise + + if perm is not None: + os.chmod(tmp_filename, perm) # in case perm includes bits in umask + + f = _wrap_io_open(fd, mode, encoding, errors) + af = _AtomicFile(f, tmp_filename, os.path.realpath(filename)) + return t.cast(t.IO, af), True + + +class _AtomicFile: + def __init__(self, f: t.IO, 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, exc_value, tb): # type: ignore + 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) -> bool: + while isinstance(stream, (_FixupStream, _NonClosingTextIOWrapper)): + stream = stream._stream + + return stream.__class__.__module__.startswith("ipykernel.") + + +def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None +) -> bool: + if color is None: + if stream is None: + stream = sys.stdin + return not isatty(stream) and not _is_jupyter_kernel_output(stream) + return not color + + +# On Windows, wrap the output streams with colorama to support ANSI +# color codes. +# NOTE: double check is needed so mypy does not analyze this on Linux +if sys.platform.startswith("win") and WIN: + from ._winconsole import _get_windows_console_stream + + def _get_argv_encoding() -> str: + import locale + + return locale.getpreferredencoding() + + _ansi_stream_wrappers: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def auto_wrap_for_ansi( + stream: t.TextIO, color: t.Optional[bool] = None + ) -> t.TextIO: + """Support ANSI color and style codes on Windows by wrapping a + stream with colorama. + """ + try: + cached = _ansi_stream_wrappers.get(stream) + except Exception: + cached = None + + if cached is not None: + return cached + + import colorama + + strip = should_strip_ansi(stream, color) + ansi_wrapper = colorama.AnsiToWin32(stream, strip=strip) + rv = t.cast(t.TextIO, ansi_wrapper.stream) + _write = rv.write + + def _safe_write(s): + try: + return _write(s) + except BaseException: + ansi_wrapper.reset_all() + raise + + rv.write = _safe_write + + try: + _ansi_stream_wrappers[stream] = rv + except Exception: + pass + + return rv + +else: + + def _get_argv_encoding() -> str: + return getattr(sys.stdin, "encoding", None) or get_filesystem_encoding() + + def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] + ) -> t.Optional[t.TextIO]: + return None + + +def term_len(x: str) -> int: + return len(strip_ansi(x)) + + +def isatty(stream: t.IO) -> bool: + try: + return stream.isatty() + except Exception: + return False + + +def _make_cached_stream_func( + src_func: t.Callable[[], t.TextIO], wrapper_func: t.Callable[[], t.TextIO] +) -> t.Callable[[], t.TextIO]: + cache: t.MutableMapping[t.TextIO, t.TextIO] = WeakKeyDictionary() + + def func() -> t.TextIO: + stream = src_func() + try: + rv = cache.get(stream) + except Exception: + rv = None + if rv is not None: + return rv + rv = wrapper_func() + try: + cache[stream] = rv + except Exception: + pass + return rv + + return func + + +_default_text_stdin = _make_cached_stream_func(lambda: sys.stdin, get_text_stdin) +_default_text_stdout = _make_cached_stream_func(lambda: sys.stdout, get_text_stdout) +_default_text_stderr = _make_cached_stream_func(lambda: sys.stderr, get_text_stderr) + + +binary_streams: t.Mapping[str, t.Callable[[], t.BinaryIO]] = { + "stdin": get_binary_stdin, + "stdout": get_binary_stdout, + "stderr": get_binary_stderr, +} + +text_streams: t.Mapping[ + str, t.Callable[[t.Optional[str], t.Optional[str]], t.TextIO] +] = { + "stdin": get_text_stdin, + "stdout": get_text_stdout, + "stderr": get_text_stderr, +} diff --git a/.vcrunch/Lib/site-packages/click/_termui_impl.py b/.vcrunch/Lib/site-packages/click/_termui_impl.py new file mode 100644 index 0000000..4b979bc --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/_termui_impl.py @@ -0,0 +1,717 @@ +""" +This module contains implementations for the termui module. To keep the +import time of Click down, some infrequently used functionality is +placed in this module and only imported as needed. +""" +import contextlib +import math +import os +import sys +import time +import typing as t +from gettext import gettext as _ + +from ._compat import _default_text_stdout +from ._compat import CYGWIN +from ._compat import get_best_encoding +from ._compat import isatty +from ._compat import open_stream +from ._compat import strip_ansi +from ._compat import term_len +from ._compat import WIN +from .exceptions import ClickException +from .utils import echo + +V = t.TypeVar("V") + +if os.name == "nt": + BEFORE_BAR = "\r" + AFTER_BAR = "\n" +else: + BEFORE_BAR = "\r\033[?25l" + AFTER_BAR = "\033[?25h\n" + + +class ProgressBar(t.Generic[V]): + def __init__( + self, + iterable: t.Optional[t.Iterable[V]], + length: t.Optional[int] = None, + fill_char: str = "#", + empty_char: str = " ", + bar_template: str = "%(bar)s", + info_sep: str = " ", + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + label: t.Optional[str] = None, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, + width: int = 30, + ) -> None: + self.fill_char = fill_char + self.empty_char = empty_char + self.bar_template = bar_template + self.info_sep = info_sep + self.show_eta = show_eta + self.show_percent = show_percent + self.show_pos = show_pos + self.item_show_func = item_show_func + self.label = label or "" + if file is None: + file = _default_text_stdout() + self.file = file + self.color = color + self.update_min_steps = update_min_steps + self._completed_intervals = 0 + self.width = width + self.autowidth = width == 0 + + if length is None: + from operator import length_hint + + length = length_hint(iterable, -1) + + if length == -1: + length = None + if iterable is None: + if length is None: + raise TypeError("iterable or length is required") + iterable = t.cast(t.Iterable[V], range(length)) + self.iter = iter(iterable) + self.length = length + self.pos = 0 + self.avg: t.List[float] = [] + self.start = self.last_eta = time.time() + self.eta_known = False + self.finished = False + self.max_width: t.Optional[int] = None + self.entered = False + self.current_item: t.Optional[V] = None + self.is_hidden = not isatty(self.file) + self._last_line: t.Optional[str] = None + + def __enter__(self) -> "ProgressBar": + self.entered = True + self.render_progress() + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.render_finish() + + def __iter__(self) -> t.Iterator[V]: + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + self.render_progress() + return self.generator() + + def __next__(self) -> V: + # Iteration is defined in terms of a generator function, + # returned by iter(self); use that to define next(). This works + # because `self.iter` is an iterable consumed by that generator, + # so it is re-entry safe. Calling `next(self.generator())` + # twice works and does "what you want". + return next(iter(self)) + + def render_finish(self) -> None: + if self.is_hidden: + return + self.file.write(AFTER_BAR) + self.file.flush() + + @property + def pct(self) -> float: + if self.finished: + return 1.0 + return min(self.pos / (float(self.length or 1) or 1), 1.0) + + @property + def time_per_iteration(self) -> float: + if not self.avg: + return 0.0 + return sum(self.avg) / float(len(self.avg)) + + @property + def eta(self) -> float: + if self.length is not None and not self.finished: + return self.time_per_iteration * (self.length - self.pos) + return 0.0 + + def format_eta(self) -> str: + if self.eta_known: + t = int(self.eta) + seconds = t % 60 + t //= 60 + minutes = t % 60 + t //= 60 + hours = t % 24 + t //= 24 + if t > 0: + return f"{t}d {hours:02}:{minutes:02}:{seconds:02}" + else: + return f"{hours:02}:{minutes:02}:{seconds:02}" + return "" + + def format_pos(self) -> str: + pos = str(self.pos) + if self.length is not None: + pos += f"/{self.length}" + return pos + + def format_pct(self) -> str: + return f"{int(self.pct * 100): 4}%"[1:] + + def format_bar(self) -> str: + if self.length is not None: + bar_length = int(self.pct * self.width) + bar = self.fill_char * bar_length + bar += self.empty_char * (self.width - bar_length) + elif self.finished: + bar = self.fill_char * self.width + else: + chars = list(self.empty_char * (self.width or 1)) + if self.time_per_iteration != 0: + chars[ + int( + (math.cos(self.pos * self.time_per_iteration) / 2.0 + 0.5) + * self.width + ) + ] = self.fill_char + bar = "".join(chars) + return bar + + def format_progress_line(self) -> str: + show_percent = self.show_percent + + info_bits = [] + if self.length is not None and show_percent is None: + show_percent = not self.show_pos + + if self.show_pos: + info_bits.append(self.format_pos()) + if show_percent: + info_bits.append(self.format_pct()) + if self.show_eta and self.eta_known and not self.finished: + info_bits.append(self.format_eta()) + if self.item_show_func is not None: + item_info = self.item_show_func(self.current_item) + if item_info is not None: + info_bits.append(item_info) + + return ( + self.bar_template + % { + "label": self.label, + "bar": self.format_bar(), + "info": self.info_sep.join(info_bits), + } + ).rstrip() + + def render_progress(self) -> None: + import shutil + + if self.is_hidden: + # Only output the label as it changes if the output is not a + # TTY. Use file=stderr if you expect to be piping stdout. + if self._last_line != self.label: + self._last_line = self.label + echo(self.label, file=self.file, color=self.color) + + return + + buf = [] + # Update width in case the terminal has been resized + if self.autowidth: + old_width = self.width + self.width = 0 + clutter_length = term_len(self.format_progress_line()) + new_width = max(0, shutil.get_terminal_size().columns - clutter_length) + if new_width < old_width: + buf.append(BEFORE_BAR) + buf.append(" " * self.max_width) # type: ignore + self.max_width = new_width + self.width = new_width + + clear_width = self.width + if self.max_width is not None: + clear_width = self.max_width + + buf.append(BEFORE_BAR) + line = self.format_progress_line() + line_len = term_len(line) + if self.max_width is None or self.max_width < line_len: + self.max_width = line_len + + buf.append(line) + buf.append(" " * (clear_width - line_len)) + line = "".join(buf) + # Render the line only if it changed. + + if line != self._last_line: + self._last_line = line + echo(line, file=self.file, color=self.color, nl=False) + self.file.flush() + + def make_step(self, n_steps: int) -> None: + self.pos += n_steps + if self.length is not None and self.pos >= self.length: + self.finished = True + + if (time.time() - self.last_eta) < 1.0: + return + + self.last_eta = time.time() + + # self.avg is a rolling list of length <= 7 of steps where steps are + # defined as time elapsed divided by the total progress through + # self.length. + if self.pos: + step = (time.time() - self.start) / self.pos + else: + step = time.time() - self.start + + self.avg = self.avg[-6:] + [step] + + self.eta_known = self.length is not None + + def update(self, n_steps: int, current_item: t.Optional[V] = None) -> None: + """Update the progress bar by advancing a specified number of + steps, and optionally set the ``current_item`` for this new + position. + + :param n_steps: Number of steps to advance. + :param current_item: Optional item to set as ``current_item`` + for the updated position. + + .. versionchanged:: 8.0 + Added the ``current_item`` optional parameter. + + .. versionchanged:: 8.0 + Only render when the number of steps meets the + ``update_min_steps`` threshold. + """ + if current_item is not None: + self.current_item = current_item + + self._completed_intervals += n_steps + + if self._completed_intervals >= self.update_min_steps: + self.make_step(self._completed_intervals) + self.render_progress() + self._completed_intervals = 0 + + def finish(self) -> None: + self.eta_known = False + self.current_item = None + self.finished = True + + def generator(self) -> t.Iterator[V]: + """Return a generator which yields the items added to the bar + during construction, and updates the progress bar *after* the + yielded block returns. + """ + # WARNING: the iterator interface for `ProgressBar` relies on + # this and only works because this is a simple generator which + # doesn't create or manage additional state. If this function + # changes, the impact should be evaluated both against + # `iter(bar)` and `next(bar)`. `next()` in particular may call + # `self.generator()` repeatedly, and this must remain safe in + # order for that interface to work. + if not self.entered: + raise RuntimeError("You need to use progress bars in a with block.") + + if self.is_hidden: + yield from self.iter + else: + for rv in self.iter: + self.current_item = rv + + # This allows show_item_func to be updated before the + # item is processed. Only trigger at the beginning of + # the update interval. + if self._completed_intervals == 0: + self.render_progress() + + yield rv + self.update(1) + + self.finish() + self.render_progress() + + +def pager(generator: t.Iterable[str], color: t.Optional[bool] = None) -> None: + """Decide what method to use for paging through text.""" + stdout = _default_text_stdout() + if not isatty(sys.stdin) or not isatty(stdout): + return _nullpager(stdout, generator, color) + pager_cmd = (os.environ.get("PAGER", None) or "").strip() + if pager_cmd: + if WIN: + return _tempfilepager(generator, pager_cmd, color) + return _pipepager(generator, pager_cmd, color) + if os.environ.get("TERM") in ("dumb", "emacs"): + return _nullpager(stdout, generator, color) + if WIN or sys.platform.startswith("os2"): + return _tempfilepager(generator, "more <", color) + if hasattr(os, "system") and os.system("(less) 2>/dev/null") == 0: + return _pipepager(generator, "less", color) + + import tempfile + + fd, filename = tempfile.mkstemp() + os.close(fd) + try: + if hasattr(os, "system") and os.system(f'more "{filename}"') == 0: + return _pipepager(generator, "more", color) + return _nullpager(stdout, generator, color) + finally: + os.unlink(filename) + + +def _pipepager(generator: t.Iterable[str], cmd: str, color: t.Optional[bool]) -> None: + """Page through text by feeding it to another program. Invoking a + pager through this might support colors. + """ + import subprocess + + env = dict(os.environ) + + # If we're piping to less we might support colors under the + # condition that + cmd_detail = cmd.rsplit("/", 1)[-1].split() + if color is None and cmd_detail[0] == "less": + less_flags = f"{os.environ.get('LESS', '')}{' '.join(cmd_detail[1:])}" + if not less_flags: + env["LESS"] = "-R" + color = True + elif "r" in less_flags or "R" in less_flags: + color = True + + c = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, env=env) + stdin = t.cast(t.BinaryIO, c.stdin) + encoding = get_best_encoding(stdin) + try: + for text in generator: + if not color: + text = strip_ansi(text) + + stdin.write(text.encode(encoding, "replace")) + except (OSError, KeyboardInterrupt): + pass + else: + stdin.close() + + # Less doesn't respect ^C, but catches it for its own UI purposes (aborting + # search or other commands inside less). + # + # That means when the user hits ^C, the parent process (click) terminates, + # but less is still alive, paging the output and messing up the terminal. + # + # If the user wants to make the pager exit on ^C, they should set + # `LESS='-K'`. It's not our decision to make. + while True: + try: + c.wait() + except KeyboardInterrupt: + pass + else: + break + + +def _tempfilepager( + generator: t.Iterable[str], cmd: str, color: t.Optional[bool] +) -> None: + """Page through text by invoking a program on a temporary file.""" + import tempfile + + fd, filename = tempfile.mkstemp() + # TODO: This never terminates if the passed generator never terminates. + text = "".join(generator) + if not color: + text = strip_ansi(text) + encoding = get_best_encoding(sys.stdout) + with open_stream(filename, "wb")[0] as f: + f.write(text.encode(encoding)) + try: + os.system(f'{cmd} "{filename}"') + finally: + os.close(fd) + os.unlink(filename) + + +def _nullpager( + stream: t.TextIO, generator: t.Iterable[str], color: t.Optional[bool] +) -> None: + """Simply print unformatted text. This is the ultimate fallback.""" + for text in generator: + if not color: + text = strip_ansi(text) + stream.write(text) + + +class Editor: + def __init__( + self, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + ) -> None: + self.editor = editor + self.env = env + self.require_save = require_save + self.extension = extension + + def get_editor(self) -> str: + if self.editor is not None: + return self.editor + for key in "VISUAL", "EDITOR": + rv = os.environ.get(key) + if rv: + return rv + if WIN: + return "notepad" + for editor in "sensible-editor", "vim", "nano": + if os.system(f"which {editor} >/dev/null 2>&1") == 0: + return editor + return "vi" + + def edit_file(self, filename: str) -> None: + import subprocess + + editor = self.get_editor() + environ: t.Optional[t.Dict[str, str]] = None + + if self.env: + environ = os.environ.copy() + environ.update(self.env) + + try: + c = subprocess.Popen(f'{editor} "{filename}"', env=environ, shell=True) + exit_code = c.wait() + if exit_code != 0: + raise ClickException( + _("{editor}: Editing failed").format(editor=editor) + ) + except OSError as e: + raise ClickException( + _("{editor}: Editing failed: {e}").format(editor=editor, e=e) + ) from e + + def edit(self, text: t.Optional[t.AnyStr]) -> t.Optional[t.AnyStr]: + import tempfile + + if not text: + data = b"" + elif isinstance(text, (bytes, bytearray)): + data = text + else: + if text and not text.endswith("\n"): + text += "\n" + + if WIN: + data = text.replace("\n", "\r\n").encode("utf-8-sig") + else: + data = text.encode("utf-8") + + fd, name = tempfile.mkstemp(prefix="editor-", suffix=self.extension) + f: t.BinaryIO + + try: + with os.fdopen(fd, "wb") as f: + f.write(data) + + # If the filesystem resolution is 1 second, like Mac OS + # 10.12 Extended, or 2 seconds, like FAT32, and the editor + # closes very fast, require_save can fail. Set the modified + # time to be 2 seconds in the past to work around this. + os.utime(name, (os.path.getatime(name), os.path.getmtime(name) - 2)) + # Depending on the resolution, the exact value might not be + # recorded, so get the new recorded value. + timestamp = os.path.getmtime(name) + + self.edit_file(name) + + if self.require_save and os.path.getmtime(name) == timestamp: + return None + + with open(name, "rb") as f: + rv = f.read() + + if isinstance(text, (bytes, bytearray)): + return rv + + return rv.decode("utf-8-sig").replace("\r\n", "\n") # type: ignore + finally: + os.unlink(name) + + +def open_url(url: str, wait: bool = False, locate: bool = False) -> int: + import subprocess + + def _unquote_file(url: str) -> str: + from urllib.parse import unquote + + if url.startswith("file://"): + url = unquote(url[7:]) + + return url + + if sys.platform == "darwin": + args = ["open"] + if wait: + args.append("-W") + if locate: + args.append("-R") + args.append(_unquote_file(url)) + null = open("/dev/null", "w") + try: + return subprocess.Popen(args, stderr=null).wait() + finally: + null.close() + elif WIN: + if locate: + url = _unquote_file(url.replace('"', "")) + args = f'explorer /select,"{url}"' + else: + url = url.replace('"', "") + wait_str = "/WAIT" if wait else "" + args = f'start {wait_str} "" "{url}"' + return os.system(args) + elif CYGWIN: + if locate: + url = os.path.dirname(_unquote_file(url).replace('"', "")) + args = f'cygstart "{url}"' + else: + url = url.replace('"', "") + wait_str = "-w" if wait else "" + args = f'cygstart {wait_str} "{url}"' + return os.system(args) + + try: + if locate: + url = os.path.dirname(_unquote_file(url)) or "." + else: + url = _unquote_file(url) + c = subprocess.Popen(["xdg-open", url]) + if wait: + return c.wait() + return 0 + except OSError: + if url.startswith(("http://", "https://")) and not locate and not wait: + import webbrowser + + webbrowser.open(url) + return 0 + return 1 + + +def _translate_ch_to_exc(ch: str) -> t.Optional[BaseException]: + if ch == "\x03": + raise KeyboardInterrupt() + + if ch == "\x04" and not WIN: # Unix-like, Ctrl+D + raise EOFError() + + if ch == "\x1a" and WIN: # Windows, Ctrl+Z + raise EOFError() + + return None + + +if WIN: + import msvcrt + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + yield -1 + + def getchar(echo: bool) -> str: + # The function `getch` will return a bytes object corresponding to + # the pressed character. Since Windows 10 build 1803, it will also + # return \x00 when called a second time after pressing a regular key. + # + # `getwch` does not share this probably-bugged behavior. Moreover, it + # returns a Unicode object by default, which is what we want. + # + # Either of these functions will return \x00 or \xe0 to indicate + # a special key, and you need to call the same function again to get + # the "rest" of the code. The fun part is that \u00e0 is + # "latin small letter a with grave", so if you type that on a French + # keyboard, you _also_ get a \xe0. + # E.g., consider the Up arrow. This returns \xe0 and then \x48. The + # resulting Unicode string reads as "a with grave" + "capital H". + # This is indistinguishable from when the user actually types + # "a with grave" and then "capital H". + # + # When \xe0 is returned, we assume it's part of a special-key sequence + # and call `getwch` again, but that means that when the user types + # the \u00e0 character, `getchar` doesn't return until a second + # character is typed. + # The alternative is returning immediately, but that would mess up + # cross-platform handling of arrow keys and others that start with + # \xe0. Another option is using `getch`, but then we can't reliably + # read non-ASCII characters, because return values of `getch` are + # limited to the current 8-bit codepage. + # + # Anyway, Click doesn't claim to do this Right(tm), and using `getwch` + # is doing the right thing in more situations than with `getch`. + func: t.Callable[[], str] + + if echo: + func = msvcrt.getwche # type: ignore + else: + func = msvcrt.getwch # type: ignore + + rv = func() + + if rv in ("\x00", "\xe0"): + # \x00 and \xe0 are control characters that indicate special key, + # see above. + rv += func() + + _translate_ch_to_exc(rv) + return rv + +else: + import tty + import termios + + @contextlib.contextmanager + def raw_terminal() -> t.Iterator[int]: + f: t.Optional[t.TextIO] + fd: int + + if not isatty(sys.stdin): + f = open("/dev/tty") + fd = f.fileno() + else: + fd = sys.stdin.fileno() + f = None + + try: + old_settings = termios.tcgetattr(fd) + + try: + tty.setraw(fd) + yield fd + finally: + termios.tcsetattr(fd, termios.TCSADRAIN, old_settings) + sys.stdout.flush() + + if f is not None: + f.close() + except termios.error: + pass + + def getchar(echo: bool) -> str: + with raw_terminal() as fd: + ch = os.read(fd, 32).decode(get_best_encoding(sys.stdin), "replace") + + if echo and isatty(sys.stdout): + sys.stdout.write(ch) + + _translate_ch_to_exc(ch) + return ch diff --git a/.vcrunch/Lib/site-packages/click/_textwrap.py b/.vcrunch/Lib/site-packages/click/_textwrap.py new file mode 100644 index 0000000..b47dcbd --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/_textwrap.py @@ -0,0 +1,49 @@ +import textwrap +import typing as t +from contextlib import contextmanager + + +class TextWrapper(textwrap.TextWrapper): + def _handle_long_word( + self, + reversed_chunks: t.List[str], + cur_line: t.List[str], + cur_len: int, + width: int, + ) -> None: + space_left = max(width - cur_len, 1) + + if self.break_long_words: + last = reversed_chunks[-1] + cut = last[:space_left] + res = last[space_left:] + cur_line.append(cut) + reversed_chunks[-1] = res + elif not cur_line: + cur_line.append(reversed_chunks.pop()) + + @contextmanager + def extra_indent(self, indent: str) -> t.Iterator[None]: + old_initial_indent = self.initial_indent + old_subsequent_indent = self.subsequent_indent + self.initial_indent += indent + self.subsequent_indent += indent + + try: + yield + finally: + self.initial_indent = old_initial_indent + self.subsequent_indent = old_subsequent_indent + + def indent_only(self, text: str) -> str: + rv = [] + + for idx, line in enumerate(text.splitlines()): + indent = self.initial_indent + + if idx > 0: + indent = self.subsequent_indent + + rv.append(f"{indent}{line}") + + return "\n".join(rv) diff --git a/.vcrunch/Lib/site-packages/click/_winconsole.py b/.vcrunch/Lib/site-packages/click/_winconsole.py new file mode 100644 index 0000000..6b20df3 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/_winconsole.py @@ -0,0 +1,279 @@ +# This module is based on the excellent work by Adam Bartoš who +# provided a lot of what went into the implementation here in +# the discussion to issue1602 in the Python bug tracker. +# +# There are some general differences in regards to how this works +# compared to the original patches as we do not need to patch +# the entire interpreter but just work in our little world of +# echo and prompt. +import io +import sys +import time +import typing as t +from ctypes import byref +from ctypes import c_char +from ctypes import c_char_p +from ctypes import c_int +from ctypes import c_ssize_t +from ctypes import c_ulong +from ctypes import c_void_p +from ctypes import POINTER +from ctypes import py_object +from ctypes import Structure +from ctypes.wintypes import DWORD +from ctypes.wintypes import HANDLE +from ctypes.wintypes import LPCWSTR +from ctypes.wintypes import LPWSTR + +from ._compat import _NonClosingTextIOWrapper + +assert sys.platform == "win32" +import msvcrt # noqa: E402 +from ctypes import windll # noqa: E402 +from ctypes import WINFUNCTYPE # noqa: E402 + +c_ssize_p = POINTER(c_ssize_t) + +kernel32 = windll.kernel32 +GetStdHandle = kernel32.GetStdHandle +ReadConsoleW = kernel32.ReadConsoleW +WriteConsoleW = kernel32.WriteConsoleW +GetConsoleMode = kernel32.GetConsoleMode +GetLastError = kernel32.GetLastError +GetCommandLineW = WINFUNCTYPE(LPWSTR)(("GetCommandLineW", windll.kernel32)) +CommandLineToArgvW = WINFUNCTYPE(POINTER(LPWSTR), LPCWSTR, POINTER(c_int))( + ("CommandLineToArgvW", windll.shell32) +) +LocalFree = WINFUNCTYPE(c_void_p, c_void_p)(("LocalFree", windll.kernel32)) + +STDIN_HANDLE = GetStdHandle(-10) +STDOUT_HANDLE = GetStdHandle(-11) +STDERR_HANDLE = GetStdHandle(-12) + +PyBUF_SIMPLE = 0 +PyBUF_WRITABLE = 1 + +ERROR_SUCCESS = 0 +ERROR_NOT_ENOUGH_MEMORY = 8 +ERROR_OPERATION_ABORTED = 995 + +STDIN_FILENO = 0 +STDOUT_FILENO = 1 +STDERR_FILENO = 2 + +EOF = b"\x1a" +MAX_BYTES_WRITTEN = 32767 + +try: + from ctypes import pythonapi +except ImportError: + # On PyPy we cannot get buffers so our ability to operate here is + # severely limited. + get_buffer = None +else: + + class Py_buffer(Structure): + _fields_ = [ + ("buf", c_void_p), + ("obj", py_object), + ("len", c_ssize_t), + ("itemsize", c_ssize_t), + ("readonly", c_int), + ("ndim", c_int), + ("format", c_char_p), + ("shape", c_ssize_p), + ("strides", c_ssize_p), + ("suboffsets", c_ssize_p), + ("internal", c_void_p), + ] + + PyObject_GetBuffer = pythonapi.PyObject_GetBuffer + PyBuffer_Release = pythonapi.PyBuffer_Release + + def get_buffer(obj, writable=False): + buf = Py_buffer() + flags = PyBUF_WRITABLE if writable else PyBUF_SIMPLE + PyObject_GetBuffer(py_object(obj), byref(buf), flags) + + try: + buffer_type = c_char * buf.len + return buffer_type.from_address(buf.buf) + finally: + PyBuffer_Release(byref(buf)) + + +class _WindowsConsoleRawIOBase(io.RawIOBase): + def __init__(self, handle): + self.handle = handle + + def isatty(self): + super().isatty() + return True + + +class _WindowsConsoleReader(_WindowsConsoleRawIOBase): + def readable(self): + return True + + def readinto(self, b): + bytes_to_be_read = len(b) + if not bytes_to_be_read: + return 0 + elif bytes_to_be_read % 2: + raise ValueError( + "cannot read odd number of bytes from UTF-16-LE encoded console" + ) + + buffer = get_buffer(b, writable=True) + code_units_to_be_read = bytes_to_be_read // 2 + code_units_read = c_ulong() + + rv = ReadConsoleW( + HANDLE(self.handle), + buffer, + code_units_to_be_read, + byref(code_units_read), + None, + ) + if GetLastError() == ERROR_OPERATION_ABORTED: + # wait for KeyboardInterrupt + time.sleep(0.1) + if not rv: + raise OSError(f"Windows error: {GetLastError()}") + + if buffer[0] == EOF: + return 0 + return 2 * code_units_read.value + + +class _WindowsConsoleWriter(_WindowsConsoleRawIOBase): + def writable(self): + return True + + @staticmethod + def _get_error_message(errno): + if errno == ERROR_SUCCESS: + return "ERROR_SUCCESS" + elif errno == ERROR_NOT_ENOUGH_MEMORY: + return "ERROR_NOT_ENOUGH_MEMORY" + return f"Windows error {errno}" + + def write(self, b): + bytes_to_be_written = len(b) + buf = get_buffer(b) + code_units_to_be_written = min(bytes_to_be_written, MAX_BYTES_WRITTEN) // 2 + code_units_written = c_ulong() + + WriteConsoleW( + HANDLE(self.handle), + buf, + code_units_to_be_written, + byref(code_units_written), + None, + ) + bytes_written = 2 * code_units_written.value + + if bytes_written == 0 and bytes_to_be_written > 0: + raise OSError(self._get_error_message(GetLastError())) + return bytes_written + + +class ConsoleStream: + def __init__(self, text_stream: t.TextIO, byte_stream: t.BinaryIO) -> None: + self._text_stream = text_stream + self.buffer = byte_stream + + @property + def name(self) -> str: + return self.buffer.name + + def write(self, x: t.AnyStr) -> int: + if isinstance(x, str): + return self._text_stream.write(x) + try: + self.flush() + except Exception: + pass + return self.buffer.write(x) + + def writelines(self, lines: t.Iterable[t.AnyStr]) -> None: + for line in lines: + self.write(line) + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._text_stream, name) + + def isatty(self) -> bool: + return self.buffer.isatty() + + def __repr__(self): + return f"" + + +def _get_text_stdin(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedReader(_WindowsConsoleReader(STDIN_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stdout(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDOUT_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +def _get_text_stderr(buffer_stream: t.BinaryIO) -> t.TextIO: + text_stream = _NonClosingTextIOWrapper( + io.BufferedWriter(_WindowsConsoleWriter(STDERR_HANDLE)), + "utf-16-le", + "strict", + line_buffering=True, + ) + return t.cast(t.TextIO, ConsoleStream(text_stream, buffer_stream)) + + +_stream_factories: t.Mapping[int, t.Callable[[t.BinaryIO], t.TextIO]] = { + 0: _get_text_stdin, + 1: _get_text_stdout, + 2: _get_text_stderr, +} + + +def _is_console(f: t.TextIO) -> bool: + if not hasattr(f, "fileno"): + return False + + try: + fileno = f.fileno() + except (OSError, io.UnsupportedOperation): + return False + + handle = msvcrt.get_osfhandle(fileno) + return bool(GetConsoleMode(handle, byref(DWORD()))) + + +def _get_windows_console_stream( + f: t.TextIO, encoding: t.Optional[str], errors: t.Optional[str] +) -> t.Optional[t.TextIO]: + if ( + get_buffer is not None + and encoding in {"utf-16-le", None} + and errors in {"strict", None} + and _is_console(f) + ): + func = _stream_factories.get(f.fileno()) + if func is not None: + b = getattr(f, "buffer", None) + + if b is None: + return None + + return func(b) diff --git a/.vcrunch/Lib/site-packages/click/core.py b/.vcrunch/Lib/site-packages/click/core.py new file mode 100644 index 0000000..5abfb0f --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/core.py @@ -0,0 +1,2998 @@ +import enum +import errno +import inspect +import os +import sys +import typing as t +from collections import abc +from contextlib import contextmanager +from contextlib import ExitStack +from functools import partial +from functools import update_wrapper +from gettext import gettext as _ +from gettext import ngettext +from itertools import repeat + +from . import types +from .exceptions import Abort +from .exceptions import BadParameter +from .exceptions import ClickException +from .exceptions import Exit +from .exceptions import MissingParameter +from .exceptions import UsageError +from .formatting import HelpFormatter +from .formatting import join_options +from .globals import pop_context +from .globals import push_context +from .parser import _flag_needs_value +from .parser import OptionParser +from .parser import split_opt +from .termui import confirm +from .termui import prompt +from .termui import style +from .utils import _detect_program_name +from .utils import _expand_args +from .utils import echo +from .utils import make_default_short_help +from .utils import make_str +from .utils import PacifyFlushWrapper + +if t.TYPE_CHECKING: + import typing_extensions as te + from .shell_completion import CompletionItem + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +V = t.TypeVar("V") + + +def _complete_visible_commands( + ctx: "Context", incomplete: str +) -> t.Iterator[t.Tuple[str, "Command"]]: + """List all the subcommands of a group that start with the + incomplete value and aren't hidden. + + :param ctx: Invocation context for the group. + :param incomplete: Value being completed. May be empty. + """ + multi = t.cast(MultiCommand, ctx.command) + + for name in multi.list_commands(ctx): + if name.startswith(incomplete): + command = multi.get_command(ctx, name) + + if command is not None and not command.hidden: + yield name, command + + +def _check_multicommand( + base_command: "MultiCommand", cmd_name: str, cmd: "Command", register: bool = False +) -> None: + if not base_command.chain or not isinstance(cmd, MultiCommand): + return + if register: + hint = ( + "It is not possible to add multi commands as children to" + " another multi command that is in chain mode." + ) + else: + hint = ( + "Found a multi command as subcommand to a multi command" + " that is in chain mode. This is not supported." + ) + raise RuntimeError( + f"{hint}. Command {base_command.name!r} is set to chain and" + f" {cmd_name!r} was added as a subcommand but it in itself is a" + f" multi command. ({cmd_name!r} is a {type(cmd).__name__}" + f" within a chained {type(base_command).__name__} named" + f" {base_command.name!r})." + ) + + +def batch(iterable: t.Iterable[V], batch_size: int) -> t.List[t.Tuple[V, ...]]: + return list(zip(*repeat(iter(iterable), batch_size))) + + +@contextmanager +def augment_usage_errors( + ctx: "Context", param: t.Optional["Parameter"] = None +) -> t.Iterator[None]: + """Context manager that attaches extra information to exceptions.""" + try: + yield + except BadParameter as e: + if e.ctx is None: + e.ctx = ctx + if param is not None and e.param is None: + e.param = param + raise + except UsageError as e: + if e.ctx is None: + e.ctx = ctx + raise + + +def iter_params_for_processing( + invocation_order: t.Sequence["Parameter"], + declaration_order: t.Sequence["Parameter"], +) -> t.List["Parameter"]: + """Given a sequence of parameters in the order as should be considered + for processing and an iterable of parameters that exist, this returns + a list in the correct order as they should be processed. + """ + + def sort_key(item: "Parameter") -> t.Tuple[bool, float]: + try: + idx: float = invocation_order.index(item) + except ValueError: + idx = float("inf") + + return not item.is_eager, idx + + return sorted(declaration_order, key=sort_key) + + +class ParameterSource(enum.Enum): + """This is an :class:`~enum.Enum` that indicates the source of a + parameter's value. + + Use :meth:`click.Context.get_parameter_source` to get the + source for a parameter by name. + + .. versionchanged:: 8.0 + Use :class:`~enum.Enum` and drop the ``validate`` method. + + .. versionchanged:: 8.0 + Added the ``PROMPT`` value. + """ + + COMMANDLINE = enum.auto() + """The value was provided by the command line args.""" + ENVIRONMENT = enum.auto() + """The value was provided with an environment variable.""" + DEFAULT = enum.auto() + """Used the default specified by the parameter.""" + DEFAULT_MAP = enum.auto() + """Used a default provided by :attr:`Context.default_map`.""" + PROMPT = enum.auto() + """Used a prompt to confirm a default or provide a value.""" + + +class Context: + """The context is a special internal object that holds state relevant + for the script execution at every single level. It's normally invisible + to commands unless they opt-in to getting access to it. + + The context is useful as it can pass internal objects around and can + control special execution features such as reading data from + environment variables. + + A context can be used as context manager in which case it will call + :meth:`close` on teardown. + + :param command: the command class for this context. + :param parent: the parent context. + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it is usually + the name of the script, for commands below it it's + the name of the script. + :param obj: an arbitrary object of user data. + :param auto_envvar_prefix: the prefix to use for automatic environment + variables. If this is `None` then reading + from environment variables is disabled. This + does not affect manually set environment + variables which are always read. + :param default_map: a dictionary (like object) with default values + for parameters. + :param terminal_width: the width of the terminal. The default is + inherit from parent context. If no context + defines the terminal width then auto + detection will be applied. + :param max_content_width: the maximum width for content rendered by + Click (this currently only affects help + pages). This defaults to 80 characters if + not overridden. In other words: even if the + terminal is larger than that, Click will not + format things wider than 80 characters by + default. In addition to that, formatters might + add some safety mapping on the right. + :param resilient_parsing: if this flag is enabled then Click will + parse without any interactivity or callback + invocation. Default values will also be + ignored. This is useful for implementing + things such as completion support. + :param allow_extra_args: if this is set to `True` then extra arguments + at the end will not raise an error and will be + kept on the context. The default is to inherit + from the command. + :param allow_interspersed_args: if this is set to `False` then options + and arguments cannot be mixed. The + default is to inherit from the command. + :param ignore_unknown_options: instructs click to ignore options it does + not know and keeps them for later + processing. + :param help_option_names: optionally a list of strings that define how + the default help parameter is named. The + default is ``['--help']``. + :param token_normalize_func: an optional function that is used to + normalize tokens (options, choices, + etc.). This for instance can be used to + implement case insensitive behavior. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are used in texts that Click prints which is by + default not the case. This for instance would affect + help output. + :param show_default: Show the default value for commands. If this + value is not set, it defaults to the value from the parent + context. ``Command.show_default`` overrides this default for the + specific command. + + .. versionchanged:: 8.1 + The ``show_default`` parameter is overridden by + ``Command.show_default``, instead of the other way around. + + .. versionchanged:: 8.0 + The ``show_default`` parameter defaults to the value from the + parent context. + + .. versionchanged:: 7.1 + Added the ``show_default`` parameter. + + .. versionchanged:: 4.0 + Added the ``color``, ``ignore_unknown_options``, and + ``max_content_width`` parameters. + + .. versionchanged:: 3.0 + Added the ``allow_extra_args`` and ``allow_interspersed_args`` + parameters. + + .. versionchanged:: 2.0 + Added the ``resilient_parsing``, ``help_option_names``, and + ``token_normalize_func`` parameters. + """ + + #: The formatter class to create with :meth:`make_formatter`. + #: + #: .. versionadded:: 8.0 + formatter_class: t.Type["HelpFormatter"] = HelpFormatter + + def __init__( + self, + command: "Command", + parent: t.Optional["Context"] = None, + info_name: t.Optional[str] = None, + obj: t.Optional[t.Any] = None, + auto_envvar_prefix: t.Optional[str] = None, + default_map: t.Optional[t.Dict[str, t.Any]] = None, + terminal_width: t.Optional[int] = None, + max_content_width: t.Optional[int] = None, + resilient_parsing: bool = False, + allow_extra_args: t.Optional[bool] = None, + allow_interspersed_args: t.Optional[bool] = None, + ignore_unknown_options: t.Optional[bool] = None, + help_option_names: t.Optional[t.List[str]] = None, + token_normalize_func: t.Optional[t.Callable[[str], str]] = None, + color: t.Optional[bool] = None, + show_default: t.Optional[bool] = None, + ) -> None: + #: the parent context or `None` if none exists. + self.parent = parent + #: the :class:`Command` for this context. + self.command = command + #: the descriptive information name + self.info_name = info_name + #: Map of parameter names to their parsed values. Parameters + #: with ``expose_value=False`` are not stored. + self.params: t.Dict[str, t.Any] = {} + #: the leftover arguments. + self.args: t.List[str] = [] + #: protected arguments. These are arguments that are prepended + #: to `args` when certain parsing scenarios are encountered but + #: must be never propagated to another arguments. This is used + #: to implement nested parsing. + self.protected_args: t.List[str] = [] + #: the collected prefixes of the command's options. + self._opt_prefixes: t.Set[str] = set(parent._opt_prefixes) if parent else set() + + if obj is None and parent is not None: + obj = parent.obj + + #: the user object stored. + self.obj: t.Any = obj + self._meta: t.Dict[str, t.Any] = getattr(parent, "meta", {}) + + #: A dictionary (-like object) with defaults for parameters. + if ( + default_map is None + and info_name is not None + and parent is not None + and parent.default_map is not None + ): + default_map = parent.default_map.get(info_name) + + self.default_map: t.Optional[t.Dict[str, t.Any]] = default_map + + #: This flag indicates if a subcommand is going to be executed. A + #: group callback can use this information to figure out if it's + #: being executed directly or because the execution flow passes + #: onwards to a subcommand. By default it's None, but it can be + #: the name of the subcommand to execute. + #: + #: If chaining is enabled this will be set to ``'*'`` in case + #: any commands are executed. It is however not possible to + #: figure out which ones. If you require this knowledge you + #: should use a :func:`result_callback`. + self.invoked_subcommand: t.Optional[str] = None + + if terminal_width is None and parent is not None: + terminal_width = parent.terminal_width + + #: The width of the terminal (None is autodetection). + self.terminal_width: t.Optional[int] = terminal_width + + if max_content_width is None and parent is not None: + max_content_width = parent.max_content_width + + #: The maximum width of formatted content (None implies a sensible + #: default which is 80 for most things). + self.max_content_width: t.Optional[int] = max_content_width + + if allow_extra_args is None: + allow_extra_args = command.allow_extra_args + + #: Indicates if the context allows extra args or if it should + #: fail on parsing. + #: + #: .. versionadded:: 3.0 + self.allow_extra_args = allow_extra_args + + if allow_interspersed_args is None: + allow_interspersed_args = command.allow_interspersed_args + + #: Indicates if the context allows mixing of arguments and + #: options or not. + #: + #: .. versionadded:: 3.0 + self.allow_interspersed_args: bool = allow_interspersed_args + + if ignore_unknown_options is None: + ignore_unknown_options = command.ignore_unknown_options + + #: Instructs click to ignore options that a command does not + #: understand and will store it on the context for later + #: processing. This is primarily useful for situations where you + #: want to call into external programs. Generally this pattern is + #: strongly discouraged because it's not possibly to losslessly + #: forward all arguments. + #: + #: .. versionadded:: 4.0 + self.ignore_unknown_options: bool = ignore_unknown_options + + if help_option_names is None: + if parent is not None: + help_option_names = parent.help_option_names + else: + help_option_names = ["--help"] + + #: The names for the help options. + self.help_option_names: t.List[str] = help_option_names + + if token_normalize_func is None and parent is not None: + token_normalize_func = parent.token_normalize_func + + #: An optional normalization function for tokens. This is + #: options, choices, commands etc. + self.token_normalize_func: t.Optional[ + t.Callable[[str], str] + ] = token_normalize_func + + #: Indicates if resilient parsing is enabled. In that case Click + #: will do its best to not cause any failures and default values + #: will be ignored. Useful for completion. + self.resilient_parsing: bool = resilient_parsing + + # If there is no envvar prefix yet, but the parent has one and + # the command on this level has a name, we can expand the envvar + # prefix automatically. + if auto_envvar_prefix is None: + if ( + parent is not None + and parent.auto_envvar_prefix is not None + and self.info_name is not None + ): + auto_envvar_prefix = ( + f"{parent.auto_envvar_prefix}_{self.info_name.upper()}" + ) + else: + auto_envvar_prefix = auto_envvar_prefix.upper() + + if auto_envvar_prefix is not None: + auto_envvar_prefix = auto_envvar_prefix.replace("-", "_") + + self.auto_envvar_prefix: t.Optional[str] = auto_envvar_prefix + + if color is None and parent is not None: + color = parent.color + + #: Controls if styling output is wanted or not. + self.color: t.Optional[bool] = color + + if show_default is None and parent is not None: + show_default = parent.show_default + + #: Show option default values when formatting help text. + self.show_default: t.Optional[bool] = show_default + + self._close_callbacks: t.List[t.Callable[[], t.Any]] = [] + self._depth = 0 + self._parameter_source: t.Dict[str, ParameterSource] = {} + self._exit_stack = ExitStack() + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire CLI + structure. + + .. code-block:: python + + with Context(cli) as ctx: + info = ctx.to_info_dict() + + .. versionadded:: 8.0 + """ + return { + "command": self.command.to_info_dict(self), + "info_name": self.info_name, + "allow_extra_args": self.allow_extra_args, + "allow_interspersed_args": self.allow_interspersed_args, + "ignore_unknown_options": self.ignore_unknown_options, + "auto_envvar_prefix": self.auto_envvar_prefix, + } + + def __enter__(self) -> "Context": + self._depth += 1 + push_context(self) + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self._depth -= 1 + if self._depth == 0: + self.close() + pop_context() + + @contextmanager + def scope(self, cleanup: bool = True) -> t.Iterator["Context"]: + """This helper method can be used with the context object to promote + it to the current thread local (see :func:`get_current_context`). + The default behavior of this is to invoke the cleanup functions which + can be disabled by setting `cleanup` to `False`. The cleanup + functions are typically used for things such as closing file handles. + + If the cleanup is intended the context object can also be directly + used as a context manager. + + Example usage:: + + with ctx.scope(): + assert get_current_context() is ctx + + This is equivalent:: + + with ctx: + assert get_current_context() is ctx + + .. versionadded:: 5.0 + + :param cleanup: controls if the cleanup functions should be run or + not. The default is to run these functions. In + some situations the context only wants to be + temporarily pushed in which case this can be disabled. + Nested pushes automatically defer the cleanup. + """ + if not cleanup: + self._depth += 1 + try: + with self as rv: + yield rv + finally: + if not cleanup: + self._depth -= 1 + + @property + def meta(self) -> t.Dict[str, t.Any]: + """This is a dictionary which is shared with all the contexts + that are nested. It exists so that click utilities can store some + state here if they need to. It is however the responsibility of + that code to manage this dictionary well. + + The keys are supposed to be unique dotted strings. For instance + module paths are a good choice for it. What is stored in there is + irrelevant for the operation of click. However what is important is + that code that places data here adheres to the general semantics of + the system. + + Example usage:: + + LANG_KEY = f'{__name__}.lang' + + def set_language(value): + ctx = get_current_context() + ctx.meta[LANG_KEY] = value + + def get_language(): + return get_current_context().meta.get(LANG_KEY, 'en_US') + + .. versionadded:: 5.0 + """ + return self._meta + + def make_formatter(self) -> HelpFormatter: + """Creates the :class:`~click.HelpFormatter` for the help and + usage output. + + To quickly customize the formatter class used without overriding + this method, set the :attr:`formatter_class` attribute. + + .. versionchanged:: 8.0 + Added the :attr:`formatter_class` attribute. + """ + return self.formatter_class( + width=self.terminal_width, max_width=self.max_content_width + ) + + def with_resource(self, context_manager: t.ContextManager[V]) -> V: + """Register a resource as if it were used in a ``with`` + statement. The resource will be cleaned up when the context is + popped. + + Uses :meth:`contextlib.ExitStack.enter_context`. It calls the + resource's ``__enter__()`` method and returns the result. When + the context is popped, it closes the stack, which calls the + resource's ``__exit__()`` method. + + To register a cleanup function for something that isn't a + context manager, use :meth:`call_on_close`. Or use something + from :mod:`contextlib` to turn it into a context manager first. + + .. code-block:: python + + @click.group() + @click.option("--name") + @click.pass_context + def cli(ctx): + ctx.obj = ctx.with_resource(connect_db(name)) + + :param context_manager: The context manager to enter. + :return: Whatever ``context_manager.__enter__()`` returns. + + .. versionadded:: 8.0 + """ + return self._exit_stack.enter_context(context_manager) + + def call_on_close(self, f: t.Callable[..., t.Any]) -> t.Callable[..., t.Any]: + """Register a function to be called when the context tears down. + + This can be used to close resources opened during the script + execution. Resources that support Python's context manager + protocol which would be used in a ``with`` statement should be + registered with :meth:`with_resource` instead. + + :param f: The function to execute on teardown. + """ + return self._exit_stack.callback(f) + + def close(self) -> None: + """Invoke all close callbacks registered with + :meth:`call_on_close`, and exit all context managers entered + with :meth:`with_resource`. + """ + self._exit_stack.close() + # In case the context is reused, create a new exit stack. + self._exit_stack = ExitStack() + + @property + def command_path(self) -> str: + """The computed command path. This is used for the ``usage`` + information on the help page. It's automatically created by + combining the info names of the chain of contexts to the root. + """ + rv = "" + if self.info_name is not None: + rv = self.info_name + if self.parent is not None: + parent_command_path = [self.parent.command_path] + + if isinstance(self.parent.command, Command): + for param in self.parent.command.get_params(self): + parent_command_path.extend(param.get_usage_pieces(self)) + + rv = f"{' '.join(parent_command_path)} {rv}" + return rv.lstrip() + + def find_root(self) -> "Context": + """Finds the outermost context.""" + node = self + while node.parent is not None: + node = node.parent + return node + + def find_object(self, object_type: t.Type[V]) -> t.Optional[V]: + """Finds the closest object of a given type.""" + node: t.Optional["Context"] = self + + while node is not None: + if isinstance(node.obj, object_type): + return node.obj + + node = node.parent + + return None + + def ensure_object(self, object_type: t.Type[V]) -> V: + """Like :meth:`find_object` but sets the innermost object to a + new instance of `object_type` if it does not exist. + """ + rv = self.find_object(object_type) + if rv is None: + self.obj = rv = object_type() + return rv + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def lookup_default( + self, name: str, call: "te.Literal[False]" = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def lookup_default(self, name: str, call: bool = True) -> t.Optional[t.Any]: + """Get the default for a parameter from :attr:`default_map`. + + :param name: Name of the parameter. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + if self.default_map is not None: + value = self.default_map.get(name) + + if call and callable(value): + return value() + + return value + + return None + + def fail(self, message: str) -> "te.NoReturn": + """Aborts the execution of the program with a specific error + message. + + :param message: the error message to fail with. + """ + raise UsageError(message, self) + + def abort(self) -> "te.NoReturn": + """Aborts the script.""" + raise Abort() + + def exit(self, code: int = 0) -> "te.NoReturn": + """Exits the application with a given exit code.""" + raise Exit(code) + + def get_usage(self) -> str: + """Helper method to get formatted usage string for the current + context and command. + """ + return self.command.get_usage(self) + + def get_help(self) -> str: + """Helper method to get formatted help page for the current + context and command. + """ + return self.command.get_help(self) + + def _make_sub_context(self, command: "Command") -> "Context": + """Create a new context of the same type as this context, but + for a new command. + + :meta private: + """ + return type(self)(command, info_name=command.name, parent=self) + + def invoke( + __self, # noqa: B902 + __callback: t.Union["Command", t.Callable[..., t.Any]], + *args: t.Any, + **kwargs: t.Any, + ) -> t.Any: + """Invokes a command callback in exactly the way it expects. There + are two ways to invoke this method: + + 1. the first argument can be a callback and all other arguments and + keyword arguments are forwarded directly to the function. + 2. the first argument is a click command object. In that case all + arguments are forwarded as well but proper click parameters + (options and click arguments) must be keyword arguments and Click + will fill in defaults. + + Note that before Click 3.2 keyword arguments were not properly filled + in against the intention of this code and no context was created. For + more information about this change and why it was done in a bugfix + release see :ref:`upgrade-to-3.2`. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if :meth:`forward` is called at multiple levels. + """ + if isinstance(__callback, Command): + other_cmd = __callback + + if other_cmd.callback is None: + raise TypeError( + "The given command does not have a callback that can be invoked." + ) + else: + __callback = other_cmd.callback + + ctx = __self._make_sub_context(other_cmd) + + for param in other_cmd.params: + if param.name not in kwargs and param.expose_value: + kwargs[param.name] = param.type_cast_value( # type: ignore + ctx, param.get_default(ctx) + ) + + # Track all kwargs as params, so that forward() will pass + # them on in subsequent calls. + ctx.params.update(kwargs) + else: + ctx = __self + + with augment_usage_errors(__self): + with ctx: + return __callback(*args, **kwargs) + + def forward( + __self, __cmd: "Command", *args: t.Any, **kwargs: t.Any # noqa: B902 + ) -> t.Any: + """Similar to :meth:`invoke` but fills in default keyword + arguments from the current context if the other command expects + it. This cannot invoke callbacks directly, only other commands. + + .. versionchanged:: 8.0 + All ``kwargs`` are tracked in :attr:`params` so they will be + passed if ``forward`` is called at multiple levels. + """ + # Can only forward to other commands, not direct callbacks. + if not isinstance(__cmd, Command): + raise TypeError("Callback is not a command.") + + for param in __self.params: + if param not in kwargs: + kwargs[param] = __self.params[param] + + return __self.invoke(__cmd, *args, **kwargs) + + def set_parameter_source(self, name: str, source: ParameterSource) -> None: + """Set the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + :param name: The name of the parameter. + :param source: A member of :class:`~click.core.ParameterSource`. + """ + self._parameter_source[name] = source + + def get_parameter_source(self, name: str) -> t.Optional[ParameterSource]: + """Get the source of a parameter. This indicates the location + from which the value of the parameter was obtained. + + This can be useful for determining when a user specified a value + on the command line that is the same as the default value. It + will be :attr:`~click.core.ParameterSource.DEFAULT` only if the + value was actually taken from the default. + + :param name: The name of the parameter. + :rtype: ParameterSource + + .. versionchanged:: 8.0 + Returns ``None`` if the parameter was not provided from any + source. + """ + return self._parameter_source.get(name) + + +class BaseCommand: + """The base command implements the minimal API contract of commands. + Most code will never use this as it does not implement a lot of useful + functionality but it can act as the direct subclass of alternative + parsing methods that do not depend on the Click parser. + + For instance, this can be used to bridge Click and other systems like + argparse or docopt. + + Because base commands do not implement a lot of the API that other + parts of Click take for granted, they are not supported for all + operations. For instance, they cannot be used with the decorators + usually and they have no built-in callback system. + + .. versionchanged:: 2.0 + Added the `context_settings` parameter. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + """ + + #: The context class to create with :meth:`make_context`. + #: + #: .. versionadded:: 8.0 + context_class: t.Type[Context] = Context + #: the default for the :attr:`Context.allow_extra_args` flag. + allow_extra_args = False + #: the default for the :attr:`Context.allow_interspersed_args` flag. + allow_interspersed_args = True + #: the default for the :attr:`Context.ignore_unknown_options` flag. + ignore_unknown_options = False + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + ) -> None: + #: the name the command thinks it has. Upon registering a command + #: on a :class:`Group` the group will default the command name + #: with this information. You should instead use the + #: :class:`Context`\'s :attr:`~Context.info_name` attribute. + self.name = name + + if context_settings is None: + context_settings = {} + + #: an optional dictionary with defaults passed to the context. + self.context_settings: t.Dict[str, t.Any] = context_settings + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. This traverses the entire structure + below this command. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + :param ctx: A :class:`Context` representing this command. + + .. versionadded:: 8.0 + """ + return {"name": self.name} + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def get_usage(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get usage") + + def get_help(self, ctx: Context) -> str: + raise NotImplementedError("Base commands cannot get help") + + def make_context( + self, + info_name: t.Optional[str], + args: t.List[str], + parent: t.Optional[Context] = None, + **extra: t.Any, + ) -> Context: + """This function when given an info name and arguments will kick + off the parsing and create a new :class:`Context`. It does not + invoke the actual command callback though. + + To quickly customize the context class used without overriding + this method, set the :attr:`context_class` attribute. + + :param info_name: the info name for this invocation. Generally this + is the most descriptive name for the script or + command. For the toplevel script it's usually + the name of the script, for commands below it it's + the name of the command. + :param args: the arguments to parse as list of strings. + :param parent: the parent context if available. + :param extra: extra keyword arguments forwarded to the context + constructor. + + .. versionchanged:: 8.0 + Added the :attr:`context_class` attribute. + """ + for key, value in self.context_settings.items(): + if key not in extra: + extra[key] = value + + ctx = self.context_class( + self, info_name=info_name, parent=parent, **extra # type: ignore + ) + + with ctx.scope(cleanup=False): + self.parse_args(ctx, args) + return ctx + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + """Given a context and a list of arguments this creates the parser + and parses the arguments, then modifies the context as necessary. + This is automatically invoked by :meth:`make_context`. + """ + raise NotImplementedError("Base commands do not know how to parse arguments.") + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the command. The default + implementation is raising a not implemented error. + """ + raise NotImplementedError("Base commands are not invokable by default") + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of chained multi-commands. + + Any command could be part of a chained multi-command, so sibling + commands are valid at any point during command completion. Other + command classes will return more completions. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + while ctx.parent is not None: + ctx = ctx.parent + + if isinstance(ctx.command, MultiCommand) and ctx.command.chain: + results.extend( + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + if name not in ctx.protected_args + ) + + return results + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: "te.Literal[True]" = True, + **extra: t.Any, + ) -> "te.NoReturn": + ... + + @t.overload + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = ..., + **extra: t.Any, + ) -> t.Any: + ... + + def main( + self, + args: t.Optional[t.Sequence[str]] = None, + prog_name: t.Optional[str] = None, + complete_var: t.Optional[str] = None, + standalone_mode: bool = True, + windows_expand_args: bool = True, + **extra: t.Any, + ) -> t.Any: + """This is the way to invoke a script with all the bells and + whistles as a command line application. This will always terminate + the application after a call. If this is not wanted, ``SystemExit`` + needs to be caught. + + This method is also available by directly calling the instance of + a :class:`Command`. + + :param args: the arguments that should be used for parsing. If not + provided, ``sys.argv[1:]`` is used. + :param prog_name: the program name that should be used. By default + the program name is constructed by taking the file + name from ``sys.argv[0]``. + :param complete_var: the environment variable that controls the + bash completion support. The default is + ``"__COMPLETE"`` with prog_name in + uppercase. + :param standalone_mode: the default behavior is to invoke the script + in standalone mode. Click will then + handle exceptions and convert them into + error messages and the function will never + return but shut down the interpreter. If + this is set to `False` they will be + propagated to the caller and the return + value of this function is the return value + of :meth:`invoke`. + :param windows_expand_args: Expand glob patterns, user dir, and + env vars in command line args on Windows. + :param extra: extra keyword arguments are forwarded to the context + constructor. See :class:`Context` for more information. + + .. versionchanged:: 8.0.1 + Added the ``windows_expand_args`` parameter to allow + disabling command line arg expansion on Windows. + + .. versionchanged:: 8.0 + When taking arguments from ``sys.argv`` on Windows, glob + patterns, user dir, and env vars are expanded. + + .. versionchanged:: 3.0 + Added the ``standalone_mode`` parameter. + """ + if args is None: + args = sys.argv[1:] + + if os.name == "nt" and windows_expand_args: + args = _expand_args(args) + else: + args = list(args) + + if prog_name is None: + prog_name = _detect_program_name() + + # Process shell completion requests and exit early. + self._main_shell_completion(extra, prog_name, complete_var) + + try: + try: + with self.make_context(prog_name, args, **extra) as ctx: + rv = self.invoke(ctx) + if not standalone_mode: + return rv + # it's not safe to `ctx.exit(rv)` here! + # note that `rv` may actually contain data like "1" which + # has obvious effects + # more subtle case: `rv=[None, None]` can come out of + # chained commands which all returned `None` -- so it's not + # even always obvious that `rv` indicates success/failure + # by its truthiness/falsiness + ctx.exit() + except (EOFError, KeyboardInterrupt): + echo(file=sys.stderr) + raise Abort() from None + except ClickException as e: + if not standalone_mode: + raise + e.show() + sys.exit(e.exit_code) + except OSError as e: + if e.errno == errno.EPIPE: + sys.stdout = t.cast(t.TextIO, PacifyFlushWrapper(sys.stdout)) + sys.stderr = t.cast(t.TextIO, PacifyFlushWrapper(sys.stderr)) + sys.exit(1) + else: + raise + except Exit as e: + if standalone_mode: + sys.exit(e.exit_code) + else: + # in non-standalone mode, return the exit code + # note that this is only reached if `self.invoke` above raises + # an Exit explicitly -- thus bypassing the check there which + # would return its result + # the results of non-standalone execution may therefore be + # somewhat ambiguous: if there are codepaths which lead to + # `ctx.exit(1)` and to `return 1`, the caller won't be able to + # tell the difference between the two + return e.exit_code + except Abort: + if not standalone_mode: + raise + echo(_("Aborted!"), file=sys.stderr) + sys.exit(1) + + def _main_shell_completion( + self, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: t.Optional[str] = None, + ) -> None: + """Check if the shell is asking for tab completion, process + that, then exit early. Called from :meth:`main` before the + program is invoked. + + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. Defaults to + ``_{PROG_NAME}_COMPLETE``. + """ + if complete_var is None: + complete_var = f"_{prog_name}_COMPLETE".replace("-", "_").upper() + + instruction = os.environ.get(complete_var) + + if not instruction: + return + + from .shell_completion import shell_complete + + rv = shell_complete(self, ctx_args, prog_name, complete_var, instruction) + sys.exit(rv) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Any: + """Alias for :meth:`main`.""" + return self.main(*args, **kwargs) + + +class Command(BaseCommand): + """Commands are the basic building block of command line interfaces in + Click. A basic command handles command line parsing and might dispatch + more parsing to commands nested below it. + + :param name: the name of the command to use unless a group overrides it. + :param context_settings: an optional dictionary with defaults that are + passed to the context object. + :param callback: the callback to invoke. This is optional. + :param params: the parameters to register with this command. This can + be either :class:`Option` or :class:`Argument` objects. + :param help: the help string to use for this command. + :param epilog: like the help string but it's printed at the end of the + help page after everything else. + :param short_help: the short help to use for this command. This is + shown on the command listing of the parent command. + :param add_help_option: by default each command registers a ``--help`` + option. This can be disabled by this parameter. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is disabled by default. + If enabled this will add ``--help`` as argument + if no arguments are passed + :param hidden: hide this command from help outputs. + + :param deprecated: issues a message indicating that + the command is deprecated. + + .. versionchanged:: 8.1 + ``help``, ``epilog``, and ``short_help`` are stored unprocessed, + all formatting is done when outputting help text, not at init, + and is done even if not using the ``@command`` decorator. + + .. versionchanged:: 8.0 + Added a ``repr`` showing the command name. + + .. versionchanged:: 7.1 + Added the ``no_args_is_help`` parameter. + + .. versionchanged:: 2.0 + Added the ``context_settings`` parameter. + """ + + def __init__( + self, + name: t.Optional[str], + context_settings: t.Optional[t.Dict[str, t.Any]] = None, + callback: t.Optional[t.Callable[..., t.Any]] = None, + params: t.Optional[t.List["Parameter"]] = None, + help: t.Optional[str] = None, + epilog: t.Optional[str] = None, + short_help: t.Optional[str] = None, + options_metavar: t.Optional[str] = "[OPTIONS]", + add_help_option: bool = True, + no_args_is_help: bool = False, + hidden: bool = False, + deprecated: bool = False, + ) -> None: + super().__init__(name, context_settings) + #: the callback to execute when the command fires. This might be + #: `None` in which case nothing happens. + self.callback = callback + #: the list of parameters for this command in the order they + #: should show up in the help page and execute. Eager parameters + #: will automatically be handled before non eager ones. + self.params: t.List["Parameter"] = params or [] + self.help = help + self.epilog = epilog + self.options_metavar = options_metavar + self.short_help = short_help + self.add_help_option = add_help_option + self.no_args_is_help = no_args_is_help + self.hidden = hidden + self.deprecated = deprecated + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + info_dict.update( + params=[param.to_info_dict() for param in self.get_params(ctx)], + help=self.help, + epilog=self.epilog, + short_help=self.short_help, + hidden=self.hidden, + deprecated=self.deprecated, + ) + return info_dict + + def get_usage(self, ctx: Context) -> str: + """Formats the usage line into a string and returns it. + + Calls :meth:`format_usage` internally. + """ + formatter = ctx.make_formatter() + self.format_usage(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_params(self, ctx: Context) -> t.List["Parameter"]: + rv = self.params + help_option = self.get_help_option(ctx) + + if help_option is not None: + rv = [*rv, help_option] + + return rv + + def format_usage(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the usage line into the formatter. + + This is a low-level method called by :meth:`get_usage`. + """ + pieces = self.collect_usage_pieces(ctx) + formatter.write_usage(ctx.command_path, " ".join(pieces)) + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + """Returns all the pieces that go into the usage line and returns + it as a list of strings. + """ + rv = [self.options_metavar] if self.options_metavar else [] + + for param in self.get_params(ctx): + rv.extend(param.get_usage_pieces(ctx)) + + return rv + + def get_help_option_names(self, ctx: Context) -> t.List[str]: + """Returns the names for the help option.""" + all_names = set(ctx.help_option_names) + for param in self.params: + all_names.difference_update(param.opts) + all_names.difference_update(param.secondary_opts) + return list(all_names) + + def get_help_option(self, ctx: Context) -> t.Optional["Option"]: + """Returns the help option object.""" + help_options = self.get_help_option_names(ctx) + + if not help_options or not self.add_help_option: + return None + + def show_help(ctx: Context, param: "Parameter", value: str) -> None: + if value and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + return Option( + help_options, + is_flag=True, + is_eager=True, + expose_value=False, + callback=show_help, + help=_("Show this message and exit."), + ) + + def make_parser(self, ctx: Context) -> OptionParser: + """Creates the underlying option parser for this command.""" + parser = OptionParser(ctx) + for param in self.get_params(ctx): + param.add_to_parser(parser, ctx) + return parser + + def get_help(self, ctx: Context) -> str: + """Formats the help into a string and returns it. + + Calls :meth:`format_help` internally. + """ + formatter = ctx.make_formatter() + self.format_help(ctx, formatter) + return formatter.getvalue().rstrip("\n") + + def get_short_help_str(self, limit: int = 45) -> str: + """Gets short help for the command or makes it by shortening the + long help string. + """ + if self.short_help: + text = inspect.cleandoc(self.short_help) + elif self.help: + text = make_default_short_help(self.help, limit) + else: + text = "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + return text.strip() + + def format_help(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help into the formatter if it exists. + + This is a low-level method called by :meth:`get_help`. + + This calls the following methods: + + - :meth:`format_usage` + - :meth:`format_help_text` + - :meth:`format_options` + - :meth:`format_epilog` + """ + self.format_usage(ctx, formatter) + self.format_help_text(ctx, formatter) + self.format_options(ctx, formatter) + self.format_epilog(ctx, formatter) + + def format_help_text(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the help text to the formatter if it exists.""" + text = self.help if self.help is not None else "" + + if self.deprecated: + text = _("(Deprecated) {text}").format(text=text) + + if text: + text = inspect.cleandoc(text).partition("\f")[0] + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(text) + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes all the options into the formatter if they exist.""" + opts = [] + for param in self.get_params(ctx): + rv = param.get_help_record(ctx) + if rv is not None: + opts.append(rv) + + if opts: + with formatter.section(_("Options")): + formatter.write_dl(opts) + + def format_epilog(self, ctx: Context, formatter: HelpFormatter) -> None: + """Writes the epilog into the formatter if it exists.""" + if self.epilog: + epilog = inspect.cleandoc(self.epilog) + formatter.write_paragraph() + + with formatter.indentation(): + formatter.write_text(epilog) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + parser = self.make_parser(ctx) + opts, args, param_order = parser.parse_args(args=args) + + for param in iter_params_for_processing(param_order, self.get_params(ctx)): + value, args = param.handle_parse_result(ctx, opts, args) + + if args and not ctx.allow_extra_args and not ctx.resilient_parsing: + ctx.fail( + ngettext( + "Got unexpected extra argument ({args})", + "Got unexpected extra arguments ({args})", + len(args), + ).format(args=" ".join(map(str, args))) + ) + + ctx.args = args + ctx._opt_prefixes.update(parser._opt_prefixes) + return args + + def invoke(self, ctx: Context) -> t.Any: + """Given a context, this invokes the attached callback (if it exists) + in the right way. + """ + if self.deprecated: + message = _( + "DeprecationWarning: The command {name!r} is deprecated." + ).format(name=self.name) + echo(style(message, fg="red"), err=True) + + if self.callback is not None: + return ctx.invoke(self.callback, **ctx.params) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options and chained multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results: t.List["CompletionItem"] = [] + + if incomplete and not incomplete[0].isalnum(): + for param in self.get_params(ctx): + if ( + not isinstance(param, Option) + or param.hidden + or ( + not param.multiple + and ctx.get_parameter_source(param.name) # type: ignore + is ParameterSource.COMMANDLINE + ) + ): + continue + + results.extend( + CompletionItem(name, help=param.help) + for name in [*param.opts, *param.secondary_opts] + if name.startswith(incomplete) + ) + + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class MultiCommand(Command): + """A multi command is the basic implementation of a command that + dispatches to subcommands. The most common version is the + :class:`Group`. + + :param invoke_without_command: this controls how the multi command itself + is invoked. By default it's only invoked + if a subcommand is provided. + :param no_args_is_help: this controls what happens if no arguments are + provided. This option is enabled by default if + `invoke_without_command` is disabled or disabled + if it's enabled. If enabled this will add + ``--help`` as argument if no arguments are + passed. + :param subcommand_metavar: the string that is used in the documentation + to indicate the subcommand place. + :param chain: if this is set to `True` chaining of multiple subcommands + is enabled. This restricts the form of commands in that + they cannot have optional arguments but it allows + multiple commands to be chained together. + :param result_callback: The result callback to attach to this multi + command. This can be set or changed later with the + :meth:`result_callback` decorator. + """ + + allow_extra_args = True + allow_interspersed_args = False + + def __init__( + self, + name: t.Optional[str] = None, + invoke_without_command: bool = False, + no_args_is_help: t.Optional[bool] = None, + subcommand_metavar: t.Optional[str] = None, + chain: bool = False, + result_callback: t.Optional[t.Callable[..., t.Any]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if no_args_is_help is None: + no_args_is_help = not invoke_without_command + + self.no_args_is_help = no_args_is_help + self.invoke_without_command = invoke_without_command + + if subcommand_metavar is None: + if chain: + subcommand_metavar = "COMMAND1 [ARGS]... [COMMAND2 [ARGS]...]..." + else: + subcommand_metavar = "COMMAND [ARGS]..." + + self.subcommand_metavar = subcommand_metavar + self.chain = chain + # The result callback that is stored. This can be set or + # overridden with the :func:`result_callback` decorator. + self._result_callback = result_callback + + if self.chain: + for param in self.params: + if isinstance(param, Argument) and not param.required: + raise RuntimeError( + "Multi commands in chain mode cannot have" + " optional arguments." + ) + + def to_info_dict(self, ctx: Context) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict(ctx) + commands = {} + + for name in self.list_commands(ctx): + command = self.get_command(ctx, name) + + if command is None: + continue + + sub_ctx = ctx._make_sub_context(command) + + with sub_ctx.scope(cleanup=False): + commands[name] = command.to_info_dict(sub_ctx) + + info_dict.update(commands=commands, chain=self.chain) + return info_dict + + def collect_usage_pieces(self, ctx: Context) -> t.List[str]: + rv = super().collect_usage_pieces(ctx) + rv.append(self.subcommand_metavar) + return rv + + def format_options(self, ctx: Context, formatter: HelpFormatter) -> None: + super().format_options(ctx, formatter) + self.format_commands(ctx, formatter) + + def result_callback(self, replace: bool = False) -> t.Callable[[F], F]: + """Adds a result callback to the command. By default if a + result callback is already registered this will chain them but + this can be disabled with the `replace` parameter. The result + callback is invoked with the return value of the subcommand + (or the list of return values from all subcommands if chaining + is enabled) as well as the parameters as they would be passed + to the main callback. + + Example:: + + @click.group() + @click.option('-i', '--input', default=23) + def cli(input): + return 42 + + @cli.result_callback() + def process_result(result, input): + return result + input + + :param replace: if set to `True` an already existing result + callback will be removed. + + .. versionchanged:: 8.0 + Renamed from ``resultcallback``. + + .. versionadded:: 3.0 + """ + + def decorator(f: F) -> F: + old_callback = self._result_callback + + if old_callback is None or replace: + self._result_callback = f + return f + + def function(__value, *args, **kwargs): # type: ignore + inner = old_callback(__value, *args, **kwargs) # type: ignore + return f(inner, *args, **kwargs) + + self._result_callback = rv = update_wrapper(t.cast(F, function), f) + return rv + + return decorator + + def format_commands(self, ctx: Context, formatter: HelpFormatter) -> None: + """Extra format methods for multi methods that adds all the commands + after the options. + """ + commands = [] + for subcommand in self.list_commands(ctx): + cmd = self.get_command(ctx, subcommand) + # What is this, the tool lied about a command. Ignore it + if cmd is None: + continue + if cmd.hidden: + continue + + commands.append((subcommand, cmd)) + + # allow for 3 times the default spacing + if len(commands): + limit = formatter.width - 6 - max(len(cmd[0]) for cmd in commands) + + rows = [] + for subcommand, cmd in commands: + help = cmd.get_short_help_str(limit) + rows.append((subcommand, help)) + + if rows: + with formatter.section(_("Commands")): + formatter.write_dl(rows) + + def parse_args(self, ctx: Context, args: t.List[str]) -> t.List[str]: + if not args and self.no_args_is_help and not ctx.resilient_parsing: + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + rest = super().parse_args(ctx, args) + + if self.chain: + ctx.protected_args = rest + ctx.args = [] + elif rest: + ctx.protected_args, ctx.args = rest[:1], rest[1:] + + return ctx.args + + def invoke(self, ctx: Context) -> t.Any: + def _process_result(value: t.Any) -> t.Any: + if self._result_callback is not None: + value = ctx.invoke(self._result_callback, value, **ctx.params) + return value + + if not ctx.protected_args: + if self.invoke_without_command: + # No subcommand was invoked, so the result callback is + # invoked with the group return value for regular + # groups, or an empty list for chained groups. + with ctx: + rv = super().invoke(ctx) + return _process_result([] if self.chain else rv) + ctx.fail(_("Missing command.")) + + # Fetch args back out + args = [*ctx.protected_args, *ctx.args] + ctx.args = [] + ctx.protected_args = [] + + # If we're not in chain mode, we only allow the invocation of a + # single command but we also inform the current context about the + # name of the command to invoke. + if not self.chain: + # Make sure the context is entered so we do not clean up + # resources until the result processor has worked. + with ctx: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + ctx.invoked_subcommand = cmd_name + super().invoke(ctx) + sub_ctx = cmd.make_context(cmd_name, args, parent=ctx) + with sub_ctx: + return _process_result(sub_ctx.command.invoke(sub_ctx)) + + # In chain mode we create the contexts step by step, but after the + # base command has been invoked. Because at that point we do not + # know the subcommands yet, the invoked subcommand attribute is + # set to ``*`` to inform the command that subcommands are executed + # but nothing else. + with ctx: + ctx.invoked_subcommand = "*" if args else None + super().invoke(ctx) + + # Otherwise we make every single context and invoke them in a + # chain. In that case the return value to the result processor + # is the list of all invoked subcommand's results. + contexts = [] + while args: + cmd_name, cmd, args = self.resolve_command(ctx, args) + assert cmd is not None + sub_ctx = cmd.make_context( + cmd_name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + ) + contexts.append(sub_ctx) + args, sub_ctx.args = sub_ctx.args, [] + + rv = [] + for sub_ctx in contexts: + with sub_ctx: + rv.append(sub_ctx.command.invoke(sub_ctx)) + return _process_result(rv) + + def resolve_command( + self, ctx: Context, args: t.List[str] + ) -> t.Tuple[t.Optional[str], t.Optional[Command], t.List[str]]: + cmd_name = make_str(args[0]) + original_cmd_name = cmd_name + + # Get the command + cmd = self.get_command(ctx, cmd_name) + + # If we can't find the command but there is a normalization + # function available, we try with that one. + if cmd is None and ctx.token_normalize_func is not None: + cmd_name = ctx.token_normalize_func(cmd_name) + cmd = self.get_command(ctx, cmd_name) + + # If we don't find the command we want to show an error message + # to the user that it was not provided. However, there is + # something else we should do: if the first argument looks like + # an option we want to kick off parsing again for arguments to + # resolve things like --help which now should go to the main + # place. + if cmd is None and not ctx.resilient_parsing: + if split_opt(cmd_name)[0]: + self.parse_args(ctx, ctx.args) + ctx.fail(_("No such command {name!r}.").format(name=original_cmd_name)) + return cmd_name if cmd else None, cmd, args[1:] + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + """Given a context and a command name, this returns a + :class:`Command` object if it exists or returns `None`. + """ + raise NotImplementedError + + def list_commands(self, ctx: Context) -> t.List[str]: + """Returns a list of subcommand names in the order they should + appear. + """ + return [] + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. Looks + at the names of options, subcommands, and chained + multi-commands. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + results = [ + CompletionItem(name, help=command.get_short_help_str()) + for name, command in _complete_visible_commands(ctx, incomplete) + ] + results.extend(super().shell_complete(ctx, incomplete)) + return results + + +class Group(MultiCommand): + """A group allows a command to have subcommands attached. This is + the most common way to implement nesting in Click. + + :param name: The name of the group command. + :param commands: A dict mapping names to :class:`Command` objects. + Can also be a list of :class:`Command`, which will use + :attr:`Command.name` to create the dict. + :param attrs: Other command arguments described in + :class:`MultiCommand`, :class:`Command`, and + :class:`BaseCommand`. + + .. versionchanged:: 8.0 + The ``commmands`` argument can be a list of command objects. + """ + + #: If set, this is used by the group's :meth:`command` decorator + #: as the default :class:`Command` class. This is useful to make all + #: subcommands use a custom command class. + #: + #: .. versionadded:: 8.0 + command_class: t.Optional[t.Type[Command]] = None + + #: If set, this is used by the group's :meth:`group` decorator + #: as the default :class:`Group` class. This is useful to make all + #: subgroups use a custom group class. + #: + #: If set to the special value :class:`type` (literally + #: ``group_class = type``), this group's class will be used as the + #: default class. This makes a custom group class continue to make + #: custom groups. + #: + #: .. versionadded:: 8.0 + group_class: t.Optional[t.Union[t.Type["Group"], t.Type[type]]] = None + # Literal[type] isn't valid, so use Type[type] + + def __init__( + self, + name: t.Optional[str] = None, + commands: t.Optional[t.Union[t.Dict[str, Command], t.Sequence[Command]]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + + if commands is None: + commands = {} + elif isinstance(commands, abc.Sequence): + commands = {c.name: c for c in commands if c.name is not None} + + #: The registered subcommands by their exported names. + self.commands: t.Dict[str, Command] = commands + + def add_command(self, cmd: Command, name: t.Optional[str] = None) -> None: + """Registers another :class:`Command` with this group. If the name + is not provided, the name of the command is used. + """ + name = name or cmd.name + if name is None: + raise TypeError("Command has no name.") + _check_multicommand(self, name, cmd, register=True) + self.commands[name] = cmd + + @t.overload + def command(self, __func: t.Callable[..., t.Any]) -> Command: + ... + + @t.overload + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], Command]: + ... + + def command( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], Command], Command]: + """A shortcut decorator for declaring and attaching a command to + the group. This takes the same arguments as :func:`command` and + immediately registers the created command with this group by + calling :meth:`add_command`. + + To customize the command class used, set the + :attr:`command_class` attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`command_class` attribute. + """ + from .decorators import command + + if self.command_class and kwargs.get("cls") is None: + kwargs["cls"] = self.command_class + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'command(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + def decorator(f: t.Callable[..., t.Any]) -> Command: + cmd: Command = command(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + @t.overload + def group(self, __func: t.Callable[..., t.Any]) -> "Group": + ... + + @t.overload + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[t.Callable[..., t.Any]], "Group"]: + ... + + def group( + self, *args: t.Any, **kwargs: t.Any + ) -> t.Union[t.Callable[[t.Callable[..., t.Any]], "Group"], "Group"]: + """A shortcut decorator for declaring and attaching a group to + the group. This takes the same arguments as :func:`group` and + immediately registers the created group with this group by + calling :meth:`add_command`. + + To customize the group class used, set the :attr:`group_class` + attribute. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.0 + Added the :attr:`group_class` attribute. + """ + from .decorators import group + + func: t.Optional[t.Callable] = None + + if args and callable(args[0]): + assert ( + len(args) == 1 and not kwargs + ), "Use 'group(**kwargs)(callable)' to provide arguments." + (func,) = args + args = () + + if self.group_class is not None and kwargs.get("cls") is None: + if self.group_class is type: + kwargs["cls"] = type(self) + else: + kwargs["cls"] = self.group_class + + def decorator(f: t.Callable[..., t.Any]) -> "Group": + cmd: Group = group(*args, **kwargs)(f) + self.add_command(cmd) + return cmd + + if func is not None: + return decorator(func) + + return decorator + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + return self.commands.get(cmd_name) + + def list_commands(self, ctx: Context) -> t.List[str]: + return sorted(self.commands) + + +class CommandCollection(MultiCommand): + """A command collection is a multi command that merges multiple multi + commands together into one. This is a straightforward implementation + that accepts a list of different multi commands as sources and + provides all the commands for each of them. + """ + + def __init__( + self, + name: t.Optional[str] = None, + sources: t.Optional[t.List[MultiCommand]] = None, + **attrs: t.Any, + ) -> None: + super().__init__(name, **attrs) + #: The list of registered multi commands. + self.sources: t.List[MultiCommand] = sources or [] + + def add_source(self, multi_cmd: MultiCommand) -> None: + """Adds a new multi command to the chain dispatcher.""" + self.sources.append(multi_cmd) + + def get_command(self, ctx: Context, cmd_name: str) -> t.Optional[Command]: + for source in self.sources: + rv = source.get_command(ctx, cmd_name) + + if rv is not None: + if self.chain: + _check_multicommand(self, cmd_name, rv) + + return rv + + return None + + def list_commands(self, ctx: Context) -> t.List[str]: + rv: t.Set[str] = set() + + for source in self.sources: + rv.update(source.list_commands(ctx)) + + return sorted(rv) + + +def _check_iter(value: t.Any) -> t.Iterator[t.Any]: + """Check if the value is iterable but not a string. Raises a type + error, or return an iterator over the value. + """ + if isinstance(value, str): + raise TypeError + + return iter(value) + + +class Parameter: + r"""A parameter to a command comes in two versions: they are either + :class:`Option`\s or :class:`Argument`\s. Other subclasses are currently + not supported by design as some of the internals for parsing are + intentionally not finalized. + + Some settings are supported by both options and arguments. + + :param param_decls: the parameter declarations for this option or + argument. This is a list of flags or argument + names. + :param type: the type that should be used. Either a :class:`ParamType` + or a Python type. The later is converted into the former + automatically if supported. + :param required: controls if this is optional or not. + :param default: the default value if omitted. This can also be a callable, + in which case it's invoked when the default is needed + without any arguments. + :param callback: A function to further process or validate the value + after type conversion. It is called as ``f(ctx, param, value)`` + and must return the value. It is called for all sources, + including prompts. + :param nargs: the number of arguments to match. If not ``1`` the return + value is a tuple instead of single value. The default for + nargs is ``1`` (except if the type is a tuple, then it's + the arity of the tuple). If ``nargs=-1``, all remaining + parameters are collected. + :param metavar: how the value is represented in the help page. + :param expose_value: if this is `True` then the value is passed onwards + to the command callback and stored on the context, + otherwise it's skipped. + :param is_eager: eager values are processed before non eager ones. This + should not be set for arguments or it will inverse the + order of processing. + :param envvar: a string or list of strings that are environment variables + that should be checked. + :param shell_complete: A function that returns custom shell + completions. Used instead of the param's type completion if + given. Takes ``ctx, param, incomplete`` and must return a list + of :class:`~click.shell_completion.CompletionItem` or a list of + strings. + + .. versionchanged:: 8.0 + ``process_value`` validates required parameters and bounded + ``nargs``, and invokes the parameter callback before returning + the value. This allows the callback to validate prompts. + ``full_process_value`` is removed. + + .. versionchanged:: 8.0 + ``autocompletion`` is renamed to ``shell_complete`` and has new + semantics described above. The old name is deprecated and will + be removed in 8.1, until then it will be wrapped to match the + new requirements. + + .. versionchanged:: 8.0 + For ``multiple=True, nargs>1``, the default must be a list of + tuples. + + .. versionchanged:: 8.0 + Setting a default is no longer required for ``nargs>1``, it will + default to ``None``. ``multiple=True`` or ``nargs=-1`` will + default to ``()``. + + .. versionchanged:: 7.1 + Empty environment variables are ignored rather than taking the + empty string value. This makes it possible for scripts to clear + variables if they can't unset them. + + .. versionchanged:: 2.0 + Changed signature for parameter callback to also be passed the + parameter. The old callback format will still work, but it will + raise a warning to give you a chance to migrate the code easier. + """ + + param_type_name = "parameter" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + required: bool = False, + default: t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]] = None, + callback: t.Optional[t.Callable[[Context, "Parameter", t.Any], t.Any]] = None, + nargs: t.Optional[int] = None, + multiple: bool = False, + metavar: t.Optional[str] = None, + expose_value: bool = True, + is_eager: bool = False, + envvar: t.Optional[t.Union[str, t.Sequence[str]]] = None, + shell_complete: t.Optional[ + t.Callable[ + [Context, "Parameter", str], + t.Union[t.List["CompletionItem"], t.List[str]], + ] + ] = None, + ) -> None: + self.name, self.opts, self.secondary_opts = self._parse_decls( + param_decls or (), expose_value + ) + self.type = types.convert_type(type, default) + + # Default nargs to what the type tells us if we have that + # information available. + if nargs is None: + if self.type.is_composite: + nargs = self.type.arity + else: + nargs = 1 + + self.required = required + self.callback = callback + self.nargs = nargs + self.multiple = multiple + self.expose_value = expose_value + self.default = default + self.is_eager = is_eager + self.metavar = metavar + self.envvar = envvar + self._custom_shell_complete = shell_complete + + if __debug__: + if self.type.is_composite and nargs != self.type.arity: + raise ValueError( + f"'nargs' must be {self.type.arity} (or None) for" + f" type {self.type!r}, but it was {nargs}." + ) + + # Skip no default or callable default. + check_default = default if not callable(default) else None + + if check_default is not None: + if multiple: + try: + # Only check the first value against nargs. + check_default = next(_check_iter(check_default), None) + except TypeError: + raise ValueError( + "'default' must be a list when 'multiple' is true." + ) from None + + # Can be None for multiple with empty default. + if nargs != 1 and check_default is not None: + try: + _check_iter(check_default) + except TypeError: + if multiple: + message = ( + "'default' must be a list of lists when 'multiple' is" + " true and 'nargs' != 1." + ) + else: + message = "'default' must be a list when 'nargs' != 1." + + raise ValueError(message) from None + + if nargs > 1 and len(check_default) != nargs: + subject = "item length" if multiple else "length" + raise ValueError( + f"'default' {subject} must match nargs={nargs}." + ) + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + return { + "name": self.name, + "param_type_name": self.param_type_name, + "opts": self.opts, + "secondary_opts": self.secondary_opts, + "type": self.type.to_info_dict(), + "required": self.required, + "nargs": self.nargs, + "multiple": self.multiple, + "default": self.default, + "envvar": self.envvar, + } + + def __repr__(self) -> str: + return f"<{self.__class__.__name__} {self.name}>" + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + raise NotImplementedError() + + @property + def human_readable_name(self) -> str: + """Returns the human readable name of this parameter. This is the + same as the name for options, but the metavar for arguments. + """ + return self.name # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + + metavar = self.type.get_metavar(self) + + if metavar is None: + metavar = self.type.name.upper() + + if self.nargs != 1: + metavar += "..." + + return metavar + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + """Get the default for the parameter. Tries + :meth:`Context.lookup_default` first, then the local default. + + :param ctx: Current context. + :param call: If the default is a callable, call it. Disable to + return the callable instead. + + .. versionchanged:: 8.0.2 + Type casting is no longer performed when getting a default. + + .. versionchanged:: 8.0.1 + Type casting can fail in resilient parsing mode. Invalid + defaults will not prevent showing help text. + + .. versionchanged:: 8.0 + Looks at ``ctx.default_map`` first. + + .. versionchanged:: 8.0 + Added the ``call`` parameter. + """ + value = ctx.lookup_default(self.name, call=False) # type: ignore + + if value is None: + value = self.default + + if call and callable(value): + value = value() + + return value + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + raise NotImplementedError() + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, t.Any] + ) -> t.Tuple[t.Any, ParameterSource]: + value = opts.get(self.name) # type: ignore + source = ParameterSource.COMMANDLINE + + if value is None: + value = self.value_from_envvar(ctx) + source = ParameterSource.ENVIRONMENT + + if value is None: + value = ctx.lookup_default(self.name) # type: ignore + source = ParameterSource.DEFAULT_MAP + + if value is None: + value = self.get_default(ctx) + source = ParameterSource.DEFAULT + + return value, source + + def type_cast_value(self, ctx: Context, value: t.Any) -> t.Any: + """Convert and validate a value against the option's + :attr:`type`, :attr:`multiple`, and :attr:`nargs`. + """ + if value is None: + return () if self.multiple or self.nargs == -1 else None + + def check_iter(value: t.Any) -> t.Iterator: + 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: + convert: t.Callable[[t.Any], t.Any] = partial( + self.type, param=self, ctx=ctx + ) + elif self.nargs == -1: + + def convert(value: t.Any) -> t.Tuple: + return tuple(self.type(x, self, ctx) for x in check_iter(value)) + + else: # nargs > 1 + + def convert(value: t.Any) -> t.Tuple: + value = tuple(check_iter(value)) + + if len(value) != self.nargs: + raise BadParameter( + ngettext( + "Takes {nargs} values but 1 was given.", + "Takes {nargs} values but {len} were given.", + len(value), + ).format(nargs=self.nargs, len=len(value)), + ctx=ctx, + param=self, + ) + + return tuple(self.type(x, self, ctx) for x in value) + + if self.multiple: + return tuple(convert(x) for x in check_iter(value)) + + return convert(value) + + def value_is_missing(self, value: t.Any) -> bool: + if value is None: + return True + + if (self.nargs != 1 or self.multiple) and value == (): + return True + + return False + + def process_value(self, ctx: Context, value: t.Any) -> t.Any: + value = self.type_cast_value(ctx, value) + + if self.required and self.value_is_missing(value): + raise MissingParameter(ctx=ctx, param=self) + + if self.callback is not None: + value = self.callback(ctx, self, value) + + return value + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + if self.envvar is None: + return None + + if isinstance(self.envvar, str): + rv = os.environ.get(self.envvar) + + if rv: + return rv + else: + for envvar in self.envvar: + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is not None and self.nargs != 1: + rv = self.type.split_envvar_value(rv) + + return rv + + def handle_parse_result( + self, ctx: Context, opts: t.Mapping[str, t.Any], args: t.List[str] + ) -> t.Tuple[t.Any, t.List[str]]: + with augment_usage_errors(ctx, param=self): + value, source = self.consume_value(ctx, opts) + ctx.set_parameter_source(self.name, source) # type: ignore + + try: + value = self.process_value(ctx, value) + except Exception: + if not ctx.resilient_parsing: + raise + + value = None + + if self.expose_value: + ctx.params[self.name] = value # type: ignore + + return value, args + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + pass + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [] + + def get_error_hint(self, ctx: Context) -> str: + """Get a stringified version of the param for use in error messages to + indicate which param caused the error. + """ + hint_list = self.opts or [self.human_readable_name] + return " / ".join(f"'{x}'" for x in hint_list) + + def shell_complete(self, ctx: Context, incomplete: str) -> t.List["CompletionItem"]: + """Return a list of completions for the incomplete value. If a + ``shell_complete`` function was given during init, it is used. + Otherwise, the :attr:`type` + :meth:`~click.types.ParamType.shell_complete` function is used. + + :param ctx: Invocation context for this command. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + if self._custom_shell_complete is not None: + results = self._custom_shell_complete(ctx, self, incomplete) + + if results and isinstance(results[0], str): + from click.shell_completion import CompletionItem + + results = [CompletionItem(c) for c in results] + + return t.cast(t.List["CompletionItem"], results) + + return self.type.shell_complete(ctx, self, incomplete) + + +class Option(Parameter): + """Options are usually optional values on the command line and + have some extra features that arguments don't have. + + All other parameters are passed onwards to the parameter constructor. + + :param show_default: Show the default value for this option in its + help text. Values are not shown by default, unless + :attr:`Context.show_default` is ``True``. If this value is a + string, it shows that string in parentheses instead of the + actual value. This is particularly useful for dynamic options. + For single option boolean flags, the default remains hidden if + its value is ``False``. + :param show_envvar: Controls if an environment variable should be + shown on the help page. Normally, environment variables are not + shown. + :param prompt: If set to ``True`` or a non empty string then the + user will be prompted for input. If set to ``True`` the prompt + will be the option name capitalized. + :param confirmation_prompt: Prompt a second time to confirm the + value if it was prompted for. Can be set to a string instead of + ``True`` to customize the message. + :param prompt_required: If set to ``False``, the user will be + prompted for input only when the option was specified as a flag + without a value. + :param hide_input: If this is ``True`` then the input on the prompt + will be hidden from the user. This is useful for password input. + :param is_flag: forces this option to act as a flag. The default is + auto detection. + :param flag_value: which value should be used for this flag if it's + enabled. This is set to a boolean automatically if + the option string contains a slash to mark two options. + :param multiple: if this is set to `True` then the argument is accepted + multiple times and recorded. This is similar to ``nargs`` + in how it works but supports arbitrary number of + arguments. + :param count: this flag makes an option increment an integer. + :param allow_from_autoenv: if this is enabled then the value of this + parameter will be pulled from an environment + variable in case a prefix is defined on the + context. + :param help: the help string. + :param hidden: hide this option from help outputs. + + .. versionchanged:: 8.1.0 + Help text indentation is cleaned here instead of only in the + ``@option`` decorator. + + .. versionchanged:: 8.1.0 + The ``show_default`` parameter overrides + ``Context.show_default``. + + .. versionchanged:: 8.1.0 + The default of a single option boolean flag is not shown if the + default value is ``False``. + + .. versionchanged:: 8.0.1 + ``type`` is detected from ``flag_value`` if given. + """ + + param_type_name = "option" + + def __init__( + self, + param_decls: t.Optional[t.Sequence[str]] = None, + show_default: t.Union[bool, str, None] = None, + prompt: t.Union[bool, str] = False, + confirmation_prompt: t.Union[bool, str] = False, + prompt_required: bool = True, + hide_input: bool = False, + is_flag: t.Optional[bool] = None, + flag_value: t.Optional[t.Any] = None, + multiple: bool = False, + count: bool = False, + allow_from_autoenv: bool = True, + type: t.Optional[t.Union[types.ParamType, t.Any]] = None, + help: t.Optional[str] = None, + hidden: bool = False, + show_choices: bool = True, + show_envvar: bool = False, + **attrs: t.Any, + ) -> None: + if help: + help = inspect.cleandoc(help) + + default_is_missing = "default" not in attrs + super().__init__(param_decls, type=type, multiple=multiple, **attrs) + + if prompt is True: + if self.name is None: + raise TypeError("'name' is required with 'prompt=True'.") + + prompt_text: t.Optional[str] = self.name.replace("_", " ").capitalize() + elif prompt is False: + prompt_text = None + else: + prompt_text = prompt + + self.prompt = prompt_text + self.confirmation_prompt = confirmation_prompt + self.prompt_required = prompt_required + self.hide_input = hide_input + self.hidden = hidden + + # If prompt is enabled but not required, then the option can be + # used as a flag to indicate using prompt or flag_value. + self._flag_needs_value = self.prompt is not None and not self.prompt_required + + if is_flag is None: + if flag_value is not None: + # Implicitly a flag because flag_value was set. + is_flag = True + elif self._flag_needs_value: + # Not a flag, but when used as a flag it shows a prompt. + is_flag = False + else: + # Implicitly a flag because flag options were given. + is_flag = bool(self.secondary_opts) + elif is_flag is False and not self._flag_needs_value: + # Not a flag, and prompt is not enabled, can be used as a + # flag if flag_value is set. + self._flag_needs_value = flag_value is not None + + if is_flag and default_is_missing and not self.required: + self.default: t.Union[t.Any, t.Callable[[], t.Any]] = False + + if flag_value is None: + flag_value = not self.default + + 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 = is_flag and isinstance(self.type, types.BoolParamType) + self.flag_value: t.Any = flag_value + + # Counting + self.count = count + if count: + if type is None: + self.type = types.IntRange(min=0) + if default_is_missing: + self.default = 0 + + self.allow_from_autoenv = allow_from_autoenv + self.help = help + self.show_default = show_default + self.show_choices = show_choices + self.show_envvar = show_envvar + + if __debug__: + if self.nargs == -1: + raise TypeError("nargs=-1 is not supported for options.") + + if self.prompt and self.is_flag and not self.is_bool_flag: + raise TypeError("'prompt' is not valid for non-boolean flag.") + + if not self.is_bool_flag and self.secondary_opts: + raise TypeError("Secondary flag is not valid for non-boolean flag.") + + if self.is_bool_flag and self.hide_input and self.prompt is not None: + raise TypeError( + "'prompt' with 'hide_input' is not valid for boolean flag." + ) + + if self.count: + if self.multiple: + raise TypeError("'count' is not valid with 'multiple'.") + + if self.is_flag: + raise TypeError("'count' is not valid with 'is_flag'.") + + if self.multiple and self.is_flag: + raise TypeError("'multiple' is not valid with 'is_flag', use 'count'.") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + help=self.help, + prompt=self.prompt, + is_flag=self.is_flag, + flag_value=self.flag_value, + count=self.count, + hidden=self.hidden, + ) + return info_dict + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + opts = [] + secondary_opts = [] + name = None + possible_names = [] + + for decl in decls: + if decl.isidentifier(): + if name is not None: + raise TypeError(f"Name '{name}' defined twice") + name = decl + else: + split_char = ";" if decl[:1] == "/" else "/" + if split_char in decl: + first, second = decl.split(split_char, 1) + first = first.rstrip() + if first: + possible_names.append(split_opt(first)) + opts.append(first) + second = second.lstrip() + if second: + secondary_opts.append(second.lstrip()) + if first == second: + raise ValueError( + f"Boolean option {decl!r} cannot use the" + " same flag for true/false." + ) + else: + possible_names.append(split_opt(decl)) + opts.append(decl) + + if name is None and possible_names: + possible_names.sort(key=lambda x: -len(x[0])) # group long options first + name = possible_names[0][1].replace("-", "_").lower() + if not name.isidentifier(): + name = None + + if name is None: + if not expose_value: + return None, opts, secondary_opts + raise TypeError("Could not determine name for option") + + if not opts and not secondary_opts: + raise TypeError( + f"No options defined but a name was passed ({name})." + " Did you mean to declare an argument instead? Did" + f" you mean to pass '--{name}'?" + ) + + return name, opts, secondary_opts + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + if self.multiple: + action = "append" + elif self.count: + action = "count" + else: + action = "store" + + if self.is_flag: + action = f"{action}_const" + + if self.is_bool_flag and self.secondary_opts: + parser.add_option( + obj=self, opts=self.opts, dest=self.name, action=action, const=True + ) + parser.add_option( + obj=self, + opts=self.secondary_opts, + dest=self.name, + action=action, + const=False, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + const=self.flag_value, + ) + else: + parser.add_option( + obj=self, + opts=self.opts, + dest=self.name, + action=action, + nargs=self.nargs, + ) + + def get_help_record(self, ctx: Context) -> t.Optional[t.Tuple[str, str]]: + if self.hidden: + return None + + any_prefix_is_slash = False + + def _write_opts(opts: t.Sequence[str]) -> str: + nonlocal any_prefix_is_slash + + rv, any_slashes = join_options(opts) + + if any_slashes: + any_prefix_is_slash = True + + if not self.is_flag and not self.count: + rv += f" {self.make_metavar()}" + + return rv + + rv = [_write_opts(self.opts)] + + if self.secondary_opts: + rv.append(_write_opts(self.secondary_opts)) + + help = self.help or "" + extra = [] + + if self.show_envvar: + envvar = self.envvar + + if envvar is None: + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + + if envvar is not None: + var_str = ( + envvar + if isinstance(envvar, str) + else ", ".join(str(d) for d in envvar) + ) + extra.append(_("env var: {var}").format(var=var_str)) + + # Temporarily enable resilient parsing to avoid type casting + # failing for the default. Might be possible to extend this to + # help formatting in general. + resilient = ctx.resilient_parsing + ctx.resilient_parsing = True + + try: + default_value = self.get_default(ctx, call=False) + finally: + ctx.resilient_parsing = resilient + + show_default = False + show_default_is_str = False + + if self.show_default is not None: + if isinstance(self.show_default, str): + show_default_is_str = show_default = True + else: + show_default = self.show_default + elif ctx.show_default is not None: + show_default = ctx.show_default + + if show_default_is_str or (show_default and (default_value is not None)): + if show_default_is_str: + default_string = f"({self.show_default})" + elif isinstance(default_value, (list, tuple)): + default_string = ", ".join(str(d) for d in default_value) + elif inspect.isfunction(default_value): + default_string = _("(dynamic)") + elif self.is_bool_flag and self.secondary_opts: + # For boolean flags that have distinct True/False opts, + # use the opt without prefix instead of the value. + default_string = split_opt( + (self.opts if self.default else self.secondary_opts)[0] + )[1] + elif self.is_bool_flag and not self.secondary_opts and not default_value: + default_string = "" + else: + default_string = str(default_value) + + if default_string: + extra.append(_("default: {default}").format(default=default_string)) + + if ( + isinstance(self.type, types._NumberRangeBase) + # skip count with default range type + and not (self.count and self.type.min == 0 and self.type.max is None) + ): + range_str = self.type._describe_range() + + if range_str: + extra.append(range_str) + + if self.required: + extra.append(_("required")) + + if extra: + extra_str = "; ".join(extra) + help = f"{help} [{extra_str}]" if help else f"[{extra_str}]" + + return ("; " if any_prefix_is_slash else " / ").join(rv), help + + @t.overload + def get_default( + self, ctx: Context, call: "te.Literal[True]" = True + ) -> t.Optional[t.Any]: + ... + + @t.overload + def get_default( + self, ctx: Context, call: bool = ... + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + ... + + def get_default( + self, ctx: Context, call: bool = True + ) -> t.Optional[t.Union[t.Any, t.Callable[[], t.Any]]]: + # If we're a non boolean flag our default is more complex because + # we need to look at all flags in the same group to figure out + # if we're the default one in which case we return the flag + # value as default. + if self.is_flag and not self.is_bool_flag: + for param in ctx.command.params: + if param.name == self.name and param.default: + return param.flag_value # type: ignore + + return None + + return super().get_default(ctx, call=call) + + def prompt_for_value(self, ctx: Context) -> t.Any: + """This is an alternative flow that can be activated in the full + value processing if a value does not exist. It will prompt the + user until a valid value exists and then returns the processed + value as result. + """ + assert self.prompt is not None + + # Calculate the default before prompting anything to be stable. + default = self.get_default(ctx) + + # If this is a prompt for a flag we need to handle this + # differently. + if self.is_bool_flag: + return confirm(self.prompt, default) + + return prompt( + self.prompt, + default=default, + type=self.type, + hide_input=self.hide_input, + show_choices=self.show_choices, + confirmation_prompt=self.confirmation_prompt, + value_proc=lambda x: self.process_value(ctx, x), + ) + + def resolve_envvar_value(self, ctx: Context) -> t.Optional[str]: + rv = super().resolve_envvar_value(ctx) + + if rv is not None: + return rv + + if ( + self.allow_from_autoenv + and ctx.auto_envvar_prefix is not None + and self.name is not None + ): + envvar = f"{ctx.auto_envvar_prefix}_{self.name.upper()}" + rv = os.environ.get(envvar) + + if rv: + return rv + + return None + + def value_from_envvar(self, ctx: Context) -> t.Optional[t.Any]: + rv: t.Optional[t.Any] = self.resolve_envvar_value(ctx) + + if rv is None: + return None + + value_depth = (self.nargs != 1) + bool(self.multiple) + + if value_depth > 0: + rv = self.type.split_envvar_value(rv) + + if self.multiple and self.nargs != 1: + rv = batch(rv, self.nargs) + + return rv + + def consume_value( + self, ctx: Context, opts: t.Mapping[str, "Parameter"] + ) -> t.Tuple[t.Any, ParameterSource]: + value, source = super().consume_value(ctx, opts) + + # The parser will emit a sentinel value if the option can be + # given as a flag without a value. This is different from None + # to distinguish from the flag not being given at all. + if value is _flag_needs_value: + if self.prompt is not None and not ctx.resilient_parsing: + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + else: + value = self.flag_value + source = ParameterSource.COMMANDLINE + + elif ( + self.multiple + and value is not None + and any(v is _flag_needs_value for v in value) + ): + value = [self.flag_value if v is _flag_needs_value else v for v in value] + source = ParameterSource.COMMANDLINE + + # The value wasn't set, or used the param's default, prompt if + # prompting is enabled. + elif ( + source in {None, ParameterSource.DEFAULT} + and self.prompt is not None + and (self.required or self.prompt_required) + and not ctx.resilient_parsing + ): + value = self.prompt_for_value(ctx) + source = ParameterSource.PROMPT + + return value, source + + +class Argument(Parameter): + """Arguments are positional parameters to a command. They generally + provide fewer features than options but can have infinite ``nargs`` + and are required by default. + + All parameters are passed onwards to the parameter constructor. + """ + + param_type_name = "argument" + + def __init__( + self, + param_decls: t.Sequence[str], + required: t.Optional[bool] = None, + **attrs: t.Any, + ) -> None: + if required is None: + if attrs.get("default") is not None: + required = False + else: + required = attrs.get("nargs", 1) > 0 + + if "multiple" in attrs: + raise TypeError("__init__() got an unexpected keyword argument 'multiple'.") + + super().__init__(param_decls, required=required, **attrs) + + if __debug__: + if self.default is not None and self.nargs == -1: + raise TypeError("'default' is not supported for nargs=-1.") + + @property + def human_readable_name(self) -> str: + if self.metavar is not None: + return self.metavar + return self.name.upper() # type: ignore + + def make_metavar(self) -> str: + if self.metavar is not None: + return self.metavar + var = self.type.get_metavar(self) + if not var: + var = self.name.upper() # type: ignore + if not self.required: + var = f"[{var}]" + if self.nargs != 1: + var += "..." + return var + + def _parse_decls( + self, decls: t.Sequence[str], expose_value: bool + ) -> t.Tuple[t.Optional[str], t.List[str], t.List[str]]: + if not decls: + if not expose_value: + return None, [], [] + raise TypeError("Could not determine name for argument") + if len(decls) == 1: + name = arg = decls[0] + name = name.replace("-", "_").lower() + else: + raise TypeError( + "Arguments take exactly one parameter declaration, got" + f" {len(decls)}." + ) + return name, [arg], [] + + def get_usage_pieces(self, ctx: Context) -> t.List[str]: + return [self.make_metavar()] + + def get_error_hint(self, ctx: Context) -> str: + return f"'{self.make_metavar()}'" + + def add_to_parser(self, parser: OptionParser, ctx: Context) -> None: + parser.add_argument(dest=self.name, nargs=self.nargs, obj=self) diff --git a/.vcrunch/Lib/site-packages/click/decorators.py b/.vcrunch/Lib/site-packages/click/decorators.py new file mode 100644 index 0000000..28618dc --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/decorators.py @@ -0,0 +1,497 @@ +import inspect +import types +import typing as t +from functools import update_wrapper +from gettext import gettext as _ + +from .core import Argument +from .core import Command +from .core import Context +from .core import Group +from .core import Option +from .core import Parameter +from .globals import get_current_context +from .utils import echo + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) +FC = t.TypeVar("FC", bound=t.Union[t.Callable[..., t.Any], Command]) + + +def pass_context(f: F) -> F: + """Marks a callback as wanting to receive the current context + object as first argument. + """ + + def new_func(*args, **kwargs): # type: ignore + return f(get_current_context(), *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def pass_obj(f: F) -> F: + """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, **kwargs): # type: ignore + return f(get_current_context().obj, *args, **kwargs) + + return update_wrapper(t.cast(F, new_func), f) + + +def make_pass_decorator( + object_type: t.Type, ensure: bool = False +) -> "t.Callable[[F], F]": + """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: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + + 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(t.cast(F, new_func), f) + + return decorator + + +def pass_meta_key( + key: str, *, doc_description: t.Optional[str] = None +) -> "t.Callable[[F], F]": + """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: F) -> F: + def new_func(*args, **kwargs): # type: ignore + ctx = get_current_context() + obj = ctx.meta[key] + return ctx.invoke(f, obj, *args, **kwargs) + + return update_wrapper(t.cast(F, 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) + + +@t.overload +def command( + __func: t.Callable[..., t.Any], +) -> Command: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[..., Command]: + ... + + +@t.overload +def command( + name: t.Optional[str] = None, + cls: t.Type[CmdType] = ..., + **attrs: t.Any, +) -> t.Callable[..., CmdType]: + ... + + +def command( + name: t.Union[str, t.Callable[..., t.Any], None] = None, + cls: t.Optional[t.Type[Command]] = None, + **attrs: t.Any, +) -> t.Union[Command, t.Callable[..., Command]]: + r"""Creates a new :class:`Command` and uses the decorated function as + callback. This will also automatically attach all decorated + :func:`option`\s and :func:`argument`\s as parameters to the command. + + The name of the command defaults to the name of the function with + underscores replaced by dashes. If you want to change that, you can + pass the intended name as the first argument. + + All keyword arguments are forwarded to the underlying command class. + For the ``params`` argument, any decorated params are appended to + the end of the list. + + Once decorated the function turns into a :class:`Command` instance + that can be invoked as a command line utility or be attached to a + command :class:`Group`. + + :param name: the name of the command. This defaults to the function + name with underscores replaced by dashes. + :param cls: the command class to instantiate. This defaults to + :class:`Command`. + + .. versionchanged:: 8.1 + This decorator can be applied without parentheses. + + .. versionchanged:: 8.1 + The ``params`` argument can be used. Decorated params are + appended to the end of the list. + """ + + func: t.Optional[t.Callable[..., t.Any]] = None + + if callable(name): + func = name + name = None + assert cls is None, "Use 'command(cls=cls)(callable)' to specify a class." + assert not attrs, "Use 'command(**kwargs)(callable)' to provide arguments." + + if cls is None: + cls = Command + + def decorator(f: t.Callable[..., t.Any]) -> Command: + 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__ + + cmd = cls( # type: ignore[misc] + name=name or f.__name__.lower().replace("_", "-"), # type: ignore[arg-type] + callback=f, + params=params, + **attrs, + ) + cmd.__doc__ = f.__doc__ + return cmd + + if func is not None: + return decorator(func) + + return decorator + + +@t.overload +def group( + __func: t.Callable[..., t.Any], +) -> Group: + ... + + +@t.overload +def group( + name: t.Optional[str] = None, + **attrs: t.Any, +) -> t.Callable[[F], Group]: + ... + + +def group( + name: t.Union[str, t.Callable[..., t.Any], None] = None, **attrs: t.Any +) -> t.Union[Group, t.Callable[[F], Group]]: + """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 attrs.get("cls") is None: + attrs["cls"] = Group + + if callable(name): + grp: t.Callable[[F], Group] = t.cast(Group, command(**attrs)) + return grp(name) + + return t.cast(Group, command(name, **attrs)) + + +def _param_memo(f: FC, 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, **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. + + :param cls: the argument class to instantiate. This defaults to + :class:`Argument`. + """ + + def decorator(f: FC) -> FC: + ArgumentClass = attrs.pop("cls", None) or Argument + _param_memo(f, ArgumentClass(param_decls, **attrs)) + return f + + return decorator + + +def option(*param_decls: str, **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. + + :param cls: the option class to instantiate. This defaults to + :class:`Option`. + """ + + def decorator(f: FC) -> FC: + # Issue 926, copy attrs, so pre-defined options can re-use the same cls= + option_attrs = attrs.copy() + OptionClass = option_attrs.pop("cls", None) or Option + _param_memo(f, OptionClass(param_decls, **option_attrs)) + return f + + return decorator + + +def confirmation_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--yes`` option which shows a prompt before continuing if + not passed. If the prompt is declined, the program will exit. + + :param param_decls: One or more option names. Defaults to the single + value ``"--yes"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value: + ctx.abort() + + if not param_decls: + param_decls = ("--yes",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("callback", callback) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("prompt", "Do you want to continue?") + kwargs.setdefault("help", "Confirm the action without prompting.") + return option(*param_decls, **kwargs) + + +def password_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--password`` option which prompts for a password, hiding + input and asking to enter the value again for confirmation. + + :param param_decls: One or more option names. Defaults to the single + value ``"--password"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + if not param_decls: + param_decls = ("--password",) + + kwargs.setdefault("prompt", True) + kwargs.setdefault("confirmation_prompt", True) + kwargs.setdefault("hide_input", True) + return option(*param_decls, **kwargs) + + +def version_option( + version: t.Optional[str] = None, + *param_decls: str, + package_name: t.Optional[str] = None, + prog_name: t.Optional[str] = None, + message: t.Optional[str] = None, + **kwargs: t.Any, +) -> t.Callable[[FC], FC]: + """Add a ``--version`` option which immediately prints the version + number and exits the program. + + If ``version`` is not provided, Click will try to detect it using + :func:`importlib.metadata.version` to get the version for the + ``package_name``. On Python < 3.8, the ``importlib_metadata`` + backport must be installed. + + If ``package_name`` is not provided, Click will try to detect it by + inspecting the stack frames. This will be used to detect the + version, so it must match the name of the installed package. + + :param version: The version number to show. If not provided, Click + will try to detect it. + :param param_decls: One or more option names. Defaults to the single + value ``"--version"``. + :param package_name: The package name to detect the version from. If + not provided, Click will try to detect it. + :param prog_name: The name of the CLI to show in the message. If not + provided, it will be detected from the command. + :param message: The message to show. The values ``%(prog)s``, + ``%(package)s``, and ``%(version)s`` are available. Defaults to + ``"%(prog)s, version %(version)s"``. + :param kwargs: Extra arguments are passed to :func:`option`. + :raise RuntimeError: ``version`` could not be detected. + + .. versionchanged:: 8.0 + Add the ``package_name`` parameter, and the ``%(package)s`` + value for messages. + + .. versionchanged:: 8.0 + Use :mod:`importlib.metadata` instead of ``pkg_resources``. The + version is detected based on the package name, not the entry + point name. The Python package name must match the installed + package name, or be passed with ``package_name=``. + """ + if message is None: + message = _("%(prog)s, version %(version)s") + + if version is None and package_name is None: + frame = inspect.currentframe() + f_back = frame.f_back if frame is not None else None + f_globals = f_back.f_globals if f_back is not None else None + # break reference cycle + # https://docs.python.org/3/library/inspect.html#the-interpreter-stack + del frame + + if f_globals is not None: + package_name = f_globals.get("__name__") + + if package_name == "__main__": + package_name = f_globals.get("__package__") + + if package_name: + package_name = package_name.partition(".")[0] + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + nonlocal prog_name + nonlocal version + + if prog_name is None: + prog_name = ctx.find_root().info_name + + if version is None and package_name is not None: + metadata: t.Optional[types.ModuleType] + + try: + from importlib import metadata # type: ignore + except ImportError: + # Python < 3.8 + import importlib_metadata as metadata # type: ignore + + try: + version = metadata.version(package_name) # type: ignore + except metadata.PackageNotFoundError: # type: ignore + raise RuntimeError( + f"{package_name!r} is not installed. Try passing" + " 'package_name' instead." + ) from None + + if version is None: + raise RuntimeError( + f"Could not determine the version for {package_name!r} automatically." + ) + + echo( + t.cast(str, message) + % {"prog": prog_name, "package": package_name, "version": version}, + color=ctx.color, + ) + ctx.exit() + + if not param_decls: + param_decls = ("--version",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show the version and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) + + +def help_option(*param_decls: str, **kwargs: t.Any) -> t.Callable[[FC], FC]: + """Add a ``--help`` option which immediately prints the help page + and exits the program. + + This is usually unnecessary, as the ``--help`` option is added to + each command automatically unless ``add_help_option=False`` is + passed. + + :param param_decls: One or more option names. Defaults to the single + value ``"--help"``. + :param kwargs: Extra arguments are passed to :func:`option`. + """ + + def callback(ctx: Context, param: Parameter, value: bool) -> None: + if not value or ctx.resilient_parsing: + return + + echo(ctx.get_help(), color=ctx.color) + ctx.exit() + + if not param_decls: + param_decls = ("--help",) + + kwargs.setdefault("is_flag", True) + kwargs.setdefault("expose_value", False) + kwargs.setdefault("is_eager", True) + kwargs.setdefault("help", _("Show this message and exit.")) + kwargs["callback"] = callback + return option(*param_decls, **kwargs) diff --git a/.vcrunch/Lib/site-packages/click/exceptions.py b/.vcrunch/Lib/site-packages/click/exceptions.py new file mode 100644 index 0000000..9e20b3e --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/exceptions.py @@ -0,0 +1,287 @@ +import os +import typing as t +from gettext import gettext as _ +from gettext import ngettext + +from ._compat import get_text_stderr +from .utils import echo + +if t.TYPE_CHECKING: + from .core import Context + from .core import Parameter + + +def _join_param_hints( + param_hint: t.Optional[t.Union[t.Sequence[str], str]] +) -> t.Optional[str]: + if param_hint is not None and not isinstance(param_hint, str): + return " / ".join(repr(x) for x in param_hint) + + return param_hint + + +class ClickException(Exception): + """An exception that Click can handle and show to the user.""" + + #: The exit code for this exception. + exit_code = 1 + + def __init__(self, message: str) -> None: + super().__init__(message) + self.message = message + + def format_message(self) -> str: + return self.message + + def __str__(self) -> str: + return self.message + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + + echo(_("Error: {message}").format(message=self.format_message()), file=file) + + +class UsageError(ClickException): + """An internal exception that signals a usage error. This typically + aborts any further handling. + + :param message: the error message to display. + :param ctx: optionally the context that caused this error. Click will + fill in the context automatically in some situations. + """ + + exit_code = 2 + + def __init__(self, message: str, ctx: t.Optional["Context"] = None) -> None: + super().__init__(message) + self.ctx = ctx + self.cmd = self.ctx.command if self.ctx else None + + def show(self, file: t.Optional[t.IO] = None) -> None: + if file is None: + file = get_text_stderr() + color = None + hint = "" + if ( + self.ctx is not None + and self.ctx.command.get_help_option(self.ctx) is not None + ): + hint = _("Try '{command} {option}' for help.").format( + command=self.ctx.command_path, option=self.ctx.help_option_names[0] + ) + hint = f"{hint}\n" + if self.ctx is not None: + color = self.ctx.color + echo(f"{self.ctx.get_usage()}\n{hint}", file=file, color=color) + echo( + _("Error: {message}").format(message=self.format_message()), + file=file, + color=color, + ) + + +class BadParameter(UsageError): + """An exception that formats out a standardized error message for a + bad parameter. This is useful when thrown from a callback or type as + Click will attach contextual information to it (for instance, which + parameter it is). + + .. versionadded:: 2.0 + + :param param: the parameter object that caused this error. This can + be left out, and Click will attach this info itself + if possible. + :param param_hint: a string that shows up as parameter name. This + can be used as alternative to `param` in cases + where custom validation should happen. If it is + a string it's used as such, if it's a list then + each item is quoted and separated. + """ + + def __init__( + self, + message: str, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + ) -> None: + super().__init__(message, ctx) + self.param = param + self.param_hint = param_hint + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + return _("Invalid value: {message}").format(message=self.message) + + return _("Invalid value for {param_hint}: {message}").format( + param_hint=_join_param_hints(param_hint), message=self.message + ) + + +class MissingParameter(BadParameter): + """Raised if click required an option or argument but it was not + provided when invoking the script. + + .. versionadded:: 4.0 + + :param param_type: a string that indicates the type of the parameter. + The default is to inherit the parameter type from + the given `param`. Valid values are ``'parameter'``, + ``'option'`` or ``'argument'``. + """ + + def __init__( + self, + message: t.Optional[str] = None, + ctx: t.Optional["Context"] = None, + param: t.Optional["Parameter"] = None, + param_hint: t.Optional[str] = None, + param_type: t.Optional[str] = None, + ) -> None: + super().__init__(message or "", ctx, param, param_hint) + self.param_type = param_type + + def format_message(self) -> str: + if self.param_hint is not None: + param_hint: t.Optional[str] = self.param_hint + elif self.param is not None: + param_hint = self.param.get_error_hint(self.ctx) # type: ignore + else: + param_hint = None + + param_hint = _join_param_hints(param_hint) + param_hint = f" {param_hint}" if param_hint else "" + + param_type = self.param_type + if param_type is None and self.param is not None: + param_type = self.param.param_type_name + + msg = self.message + if self.param is not None: + msg_extra = self.param.type.get_missing_message(self.param) + if msg_extra: + if msg: + msg += f". {msg_extra}" + else: + msg = msg_extra + + msg = f" {msg}" if msg else "" + + # Translate param_type for known types. + if param_type == "argument": + missing = _("Missing argument") + elif param_type == "option": + missing = _("Missing option") + elif param_type == "parameter": + missing = _("Missing parameter") + else: + missing = _("Missing {param_type}").format(param_type=param_type) + + return f"{missing}{param_hint}.{msg}" + + def __str__(self) -> str: + if not self.message: + param_name = self.param.name if self.param else None + return _("Missing parameter: {param_name}").format(param_name=param_name) + else: + return self.message + + +class NoSuchOption(UsageError): + """Raised if click attempted to handle an option that does not + exist. + + .. versionadded:: 4.0 + """ + + def __init__( + self, + option_name: str, + message: t.Optional[str] = None, + possibilities: t.Optional[t.Sequence[str]] = None, + ctx: t.Optional["Context"] = None, + ) -> None: + if message is None: + message = _("No such option: {name}").format(name=option_name) + + super().__init__(message, ctx) + self.option_name = option_name + self.possibilities = possibilities + + def format_message(self) -> str: + if not self.possibilities: + return self.message + + possibility_str = ", ".join(sorted(self.possibilities)) + suggest = ngettext( + "Did you mean {possibility}?", + "(Possible options: {possibilities})", + len(self.possibilities), + ).format(possibility=possibility_str, possibilities=possibility_str) + return f"{self.message} {suggest}" + + +class BadOptionUsage(UsageError): + """Raised if an option is generally supplied but the use of the option + was incorrect. This is for instance raised if the number of arguments + for an option is not correct. + + .. versionadded:: 4.0 + + :param option_name: the name of the option being used incorrectly. + """ + + def __init__( + self, option_name: str, message: str, ctx: t.Optional["Context"] = None + ) -> None: + super().__init__(message, ctx) + self.option_name = option_name + + +class BadArgumentUsage(UsageError): + """Raised if an argument is generally supplied but the use of the argument + was incorrect. This is for instance raised if the number of values + for an argument is not correct. + + .. versionadded:: 6.0 + """ + + +class FileError(ClickException): + """Raised if a file cannot be opened.""" + + def __init__(self, filename: str, hint: t.Optional[str] = None) -> None: + if hint is None: + hint = _("unknown error") + + super().__init__(hint) + self.ui_filename = os.fsdecode(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 = code diff --git a/.vcrunch/Lib/site-packages/click/formatting.py b/.vcrunch/Lib/site-packages/click/formatting.py new file mode 100644 index 0000000..ddd2a2f --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/formatting.py @@ -0,0 +1,301 @@ +import typing as t +from contextlib import contextmanager +from gettext import gettext as _ + +from ._compat import term_len +from .parser import split_opt + +# Can force a width. This is used by the test system +FORCED_WIDTH: t.Optional[int] = None + + +def measure_table(rows: t.Iterable[t.Tuple[str, str]]) -> t.Tuple[int, ...]: + widths: t.Dict[int, int] = {} + + for row in rows: + for idx, col in enumerate(row): + widths[idx] = max(widths.get(idx, 0), term_len(col)) + + return tuple(y for x, y in sorted(widths.items())) + + +def iter_rows( + rows: t.Iterable[t.Tuple[str, str]], col_count: int +) -> t.Iterator[t.Tuple[str, ...]]: + for row in rows: + yield row + ("",) * (col_count - len(row)) + + +def wrap_text( + text: str, + width: int = 78, + initial_indent: str = "", + subsequent_indent: str = "", + preserve_paragraphs: bool = False, +) -> str: + """A helper function that intelligently wraps text. By default, it + assumes that it operates on a single paragraph of text but if the + `preserve_paragraphs` parameter is provided it will intelligently + handle paragraphs (defined by two empty lines). + + If paragraphs are handled, a paragraph can be prefixed with an empty + line containing the ``\\b`` character (``\\x08``) to indicate that + no rewrapping should happen in that block. + + :param text: the text that should be rewrapped. + :param width: the maximum width for the text. + :param initial_indent: the initial indent that should be placed on the + first line as a string. + :param subsequent_indent: the indent string that should be placed on + each consecutive line. + :param preserve_paragraphs: if this flag is set then the wrapping will + intelligently handle paragraphs. + """ + from ._textwrap import TextWrapper + + text = text.expandtabs() + wrapper = TextWrapper( + width, + initial_indent=initial_indent, + subsequent_indent=subsequent_indent, + replace_whitespace=False, + ) + if not preserve_paragraphs: + return wrapper.fill(text) + + p: t.List[t.Tuple[int, bool, str]] = [] + buf: t.List[str] = [] + indent = None + + def _flush_par() -> None: + if not buf: + return + if buf[0].strip() == "\b": + p.append((indent or 0, True, "\n".join(buf[1:]))) + else: + p.append((indent or 0, False, " ".join(buf))) + del buf[:] + + for line in text.splitlines(): + if not line: + _flush_par() + indent = None + else: + if indent is None: + orig_len = term_len(line) + line = line.lstrip() + indent = orig_len - term_len(line) + buf.append(line) + _flush_par() + + rv = [] + for indent, raw, text in p: + with wrapper.extra_indent(" " * indent): + if raw: + rv.append(wrapper.indent_only(text)) + else: + rv.append(wrapper.fill(text)) + + return "\n\n".join(rv) + + +class HelpFormatter: + """This class helps with formatting text-based help pages. It's + usually just needed for very special internal cases, but it's also + exposed so that developers can write their own fancy outputs. + + At present, it always writes into memory. + + :param indent_increment: the additional increment for each level. + :param width: the width for the text. This defaults to the terminal + width clamped to a maximum of 78. + """ + + def __init__( + self, + indent_increment: int = 2, + width: t.Optional[int] = None, + max_width: t.Optional[int] = None, + ) -> None: + import shutil + + self.indent_increment = indent_increment + if max_width is None: + max_width = 80 + if width is None: + width = FORCED_WIDTH + if width is None: + width = max(min(shutil.get_terminal_size().columns, max_width) - 2, 50) + self.width = width + self.current_indent = 0 + self.buffer: t.List[str] = [] + + def write(self, string: str) -> None: + """Writes a unicode string into the internal buffer.""" + self.buffer.append(string) + + def indent(self) -> None: + """Increases the indentation.""" + self.current_indent += self.indent_increment + + def dedent(self) -> None: + """Decreases the indentation.""" + self.current_indent -= self.indent_increment + + def write_usage( + self, prog: str, args: str = "", prefix: t.Optional[str] = None + ) -> None: + """Writes a usage line into the buffer. + + :param prog: the program name. + :param args: whitespace separated list of arguments. + :param prefix: The prefix for the first line. Defaults to + ``"Usage: "``. + """ + if prefix is None: + prefix = f"{_('Usage:')} " + + usage_prefix = f"{prefix:>{self.current_indent}}{prog} " + text_width = self.width - self.current_indent + + if text_width >= (term_len(usage_prefix) + 20): + # The arguments will fit to the right of the prefix. + indent = " " * term_len(usage_prefix) + self.write( + wrap_text( + args, + text_width, + initial_indent=usage_prefix, + subsequent_indent=indent, + ) + ) + else: + # The prefix is too long, put the arguments on the next line. + self.write(usage_prefix) + self.write("\n") + indent = " " * (max(self.current_indent, term_len(prefix)) + 4) + self.write( + wrap_text( + args, text_width, initial_indent=indent, subsequent_indent=indent + ) + ) + + self.write("\n") + + def write_heading(self, heading: str) -> None: + """Writes a heading into the buffer.""" + self.write(f"{'':>{self.current_indent}}{heading}:\n") + + def write_paragraph(self) -> None: + """Writes a paragraph into the buffer.""" + if self.buffer: + self.write("\n") + + def write_text(self, text: str) -> None: + """Writes re-indented text into the buffer. This rewraps and + preserves paragraphs. + """ + indent = " " * self.current_indent + self.write( + wrap_text( + text, + self.width, + initial_indent=indent, + subsequent_indent=indent, + preserve_paragraphs=True, + ) + ) + self.write("\n") + + def write_dl( + self, + rows: t.Sequence[t.Tuple[str, str]], + col_max: int = 30, + col_spacing: int = 2, + ) -> None: + """Writes a definition list into the buffer. This is how options + and commands are usually formatted. + + :param rows: a list of two item tuples for the terms and values. + :param col_max: the maximum width of the first column. + :param col_spacing: the number of spaces between the first and + second column. + """ + rows = list(rows) + widths = measure_table(rows) + if len(widths) != 2: + raise TypeError("Expected two columns for definition list") + + first_col = min(widths[0], col_max) + col_spacing + + for first, second in iter_rows(rows, len(widths)): + self.write(f"{'':>{self.current_indent}}{first}") + if not second: + self.write("\n") + continue + if term_len(first) <= first_col - col_spacing: + self.write(" " * (first_col - term_len(first))) + else: + self.write("\n") + self.write(" " * (first_col + self.current_indent)) + + text_width = max(self.width - first_col - 2, 10) + wrapped_text = wrap_text(second, text_width, preserve_paragraphs=True) + lines = wrapped_text.splitlines() + + if lines: + self.write(f"{lines[0]}\n") + + for line in lines[1:]: + self.write(f"{'':>{first_col + self.current_indent}}{line}\n") + else: + self.write("\n") + + @contextmanager + def section(self, name: str) -> t.Iterator[None]: + """Helpful context manager that writes a paragraph, a heading, + and the indents. + + :param name: the section name that is written as heading. + """ + self.write_paragraph() + self.write_heading(name) + self.indent() + try: + yield + finally: + self.dedent() + + @contextmanager + def indentation(self) -> t.Iterator[None]: + """A context manager that increases the indentation.""" + self.indent() + try: + yield + finally: + self.dedent() + + def getvalue(self) -> str: + """Returns the buffer contents.""" + return "".join(self.buffer) + + +def join_options(options: t.Sequence[str]) -> t.Tuple[str, bool]: + """Given a list of option strings this joins them in the most appropriate + way and returns them in the form ``(formatted_string, + any_prefix_is_slash)`` where the second item in the tuple is a flag that + indicates if any of the option prefixes was a slash. + """ + rv = [] + any_prefix_is_slash = False + + for opt in options: + prefix = split_opt(opt)[0] + + if prefix == "/": + any_prefix_is_slash = True + + rv.append((len(prefix), opt)) + + rv.sort(key=lambda x: x[0]) + return ", ".join(x[1] for x in rv), any_prefix_is_slash diff --git a/.vcrunch/Lib/site-packages/click/globals.py b/.vcrunch/Lib/site-packages/click/globals.py new file mode 100644 index 0000000..480058f --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/globals.py @@ -0,0 +1,68 @@ +import typing as t +from threading import local + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + +_local = local() + + +@t.overload +def get_current_context(silent: "te.Literal[False]" = False) -> "Context": + ... + + +@t.overload +def get_current_context(silent: bool = ...) -> t.Optional["Context"]: + ... + + +def get_current_context(silent: bool = False) -> t.Optional["Context"]: + """Returns the current click context. This can be used as a way to + access the current context object from anywhere. This is a more implicit + alternative to the :func:`pass_context` decorator. This function is + primarily useful for helpers such as :func:`echo` which might be + interested in changing its behavior based on the current context. + + To push the current context, :meth:`Context.scope` can be used. + + .. versionadded:: 5.0 + + :param silent: if set to `True` the return value is `None` if no context + is available. The default behavior is to raise a + :exc:`RuntimeError`. + """ + try: + return t.cast("Context", _local.stack[-1]) + except (AttributeError, IndexError) as e: + if not silent: + raise RuntimeError("There is no active click context.") from e + + return None + + +def push_context(ctx: "Context") -> None: + """Pushes a new context to the current stack.""" + _local.__dict__.setdefault("stack", []).append(ctx) + + +def pop_context() -> None: + """Removes the top level from the stack.""" + _local.stack.pop() + + +def resolve_color_default(color: t.Optional[bool] = None) -> t.Optional[bool]: + """Internal helper to get the default value of the color flag. If a + value is passed it's returned unchanged, otherwise it's looked up from + the current context. + """ + if color is not None: + return color + + ctx = get_current_context(silent=True) + + if ctx is not None: + return ctx.color + + return None diff --git a/.vcrunch/Lib/site-packages/click/parser.py b/.vcrunch/Lib/site-packages/click/parser.py new file mode 100644 index 0000000..2d5a2ed --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/parser.py @@ -0,0 +1,529 @@ +""" +This module started out as largely a copy paste from the stdlib's +optparse module with the features removed that we do not need from +optparse because we implement them in Click on a higher level (for +instance type handling, help formatting and a lot more). + +The plan is to remove more and more from here over time. + +The reason this is a different module and not optparse from the stdlib +is that there are differences in 2.x and 3.x about the error messages +generated and optparse in the stdlib uses gettext for no good reason +and might cause us issues. + +Click uses parts of optparse written by Gregory P. Ward and maintained +by the Python Software Foundation. This is limited to code in parser.py. + +Copyright 2001-2006 Gregory P. Ward. All rights reserved. +Copyright 2002-2006 Python Software Foundation. All rights reserved. +""" +# This code uses parts of optparse written by Gregory P. Ward and +# maintained by the Python Software Foundation. +# Copyright 2001-2006 Gregory P. Ward +# Copyright 2002-2006 Python Software Foundation +import typing as t +from collections import deque +from gettext import gettext as _ +from gettext import ngettext + +from .exceptions import BadArgumentUsage +from .exceptions import BadOptionUsage +from .exceptions import NoSuchOption +from .exceptions import UsageError + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Argument as CoreArgument + from .core import Context + from .core import Option as CoreOption + from .core import Parameter as CoreParameter + +V = t.TypeVar("V") + +# Sentinel value that indicates an option was passed as a flag without a +# value but is not a flag option. Option.consume_value uses this to +# prompt or use the flag_value. +_flag_needs_value = object() + + +def _unpack_args( + args: t.Sequence[str], nargs_spec: t.Sequence[int] +) -> t.Tuple[t.Sequence[t.Union[str, t.Sequence[t.Optional[str]], None]], t.List[str]]: + """Given an iterable of arguments and an iterable of nargs specifications, + it returns a tuple with all the unpacked arguments at the first index + and all remaining arguments as the second. + + The nargs specification is the number of arguments that should be consumed + or `-1` to indicate that this position should eat up all the remainders. + + Missing items are filled with `None`. + """ + args = deque(args) + nargs_spec = deque(nargs_spec) + rv: t.List[t.Union[str, t.Tuple[t.Optional[str], ...], None]] = [] + spos: t.Optional[int] = None + + def _fetch(c: "te.Deque[V]") -> t.Optional[V]: + try: + if spos is None: + return c.popleft() + else: + return c.pop() + except IndexError: + return None + + while nargs_spec: + nargs = _fetch(nargs_spec) + + if nargs is None: + continue + + if nargs == 1: + rv.append(_fetch(args)) + elif nargs > 1: + x = [_fetch(args) for _ in range(nargs)] + + # If we're reversed, we're pulling in the arguments in reverse, + # so we need to turn them around. + if spos is not None: + x.reverse() + + rv.append(tuple(x)) + elif nargs < 0: + if spos is not None: + raise TypeError("Cannot have two nargs < 0") + + spos = len(rv) + rv.append(None) + + # spos is the position of the wildcard (star). If it's not `None`, + # we fill it with the remainder. + if spos is not None: + rv[spos] = tuple(args) + args = [] + rv[spos + 1 :] = reversed(rv[spos + 1 :]) + + return tuple(rv), list(args) + + +def split_opt(opt: str) -> t.Tuple[str, str]: + first = opt[:1] + if first.isalnum(): + return "", opt + if opt[1:2] == first: + return opt[:2], opt[2:] + return first, opt[1:] + + +def normalize_opt(opt: str, ctx: t.Optional["Context"]) -> str: + if ctx is None or ctx.token_normalize_func is None: + return opt + prefix, opt = split_opt(opt) + return f"{prefix}{ctx.token_normalize_func(opt)}" + + +def split_arg_string(string: str) -> t.List[str]: + """Split an argument string as with :func:`shlex.split`, but don't + fail if the string is incomplete. Ignores a missing closing quote or + incomplete escape sequence and uses the partial token as-is. + + .. code-block:: python + + split_arg_string("example 'my file") + ["example", "my file"] + + split_arg_string("example my\\") + ["example", "my"] + + :param string: String to split. + """ + import shlex + + lex = shlex.shlex(string, posix=True) + lex.whitespace_split = True + lex.commenters = "" + out = [] + + try: + for token in lex: + out.append(token) + except ValueError: + # Raised when end-of-string is reached in an invalid state. Use + # the partial token as-is. The quote or escape character is in + # lex.state, not lex.token. + out.append(lex.token) + + return out + + +class Option: + def __init__( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ): + self._short_opts = [] + self._long_opts = [] + self.prefixes = 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: str, state: "ParsingState") -> None: + if self.action == "store": + state.opts[self.dest] = value # type: ignore + elif self.action == "store_const": + state.opts[self.dest] = self.const # type: ignore + elif self.action == "append": + state.opts.setdefault(self.dest, []).append(value) # type: ignore + elif self.action == "append_const": + state.opts.setdefault(self.dest, []).append(self.const) # type: ignore + elif self.action == "count": + state.opts[self.dest] = state.opts.get(self.dest, 0) + 1 # type: ignore + else: + raise ValueError(f"unknown action '{self.action}'") + state.order.append(self.obj) + + +class Argument: + def __init__(self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1): + self.dest = dest + self.nargs = nargs + self.obj = obj + + def process( + self, + value: t.Union[t.Optional[str], t.Sequence[t.Optional[str]]], + state: "ParsingState", + ) -> None: + if self.nargs > 1: + assert value is not None + holes = sum(1 for x in value if x is None) + if holes == len(value): + value = None + elif holes != 0: + raise BadArgumentUsage( + _("Argument {name!r} takes {nargs} values.").format( + name=self.dest, nargs=self.nargs + ) + ) + + if self.nargs == -1 and self.obj.envvar is not None and value == (): + # Replace empty tuple with None so that a value from the + # environment may be tried. + value = None + + state.opts[self.dest] = value # type: ignore + state.order.append(self.obj) + + +class ParsingState: + def __init__(self, rargs: t.List[str]) -> None: + self.opts: t.Dict[str, t.Any] = {} + self.largs: t.List[str] = [] + self.rargs = rargs + self.order: t.List["CoreParameter"] = [] + + +class OptionParser: + """The option parser is an internal class that is ultimately used to + parse options and arguments. It's modelled after optparse and brings + a similar but vastly simplified API. It should generally not be used + directly as the high level Click classes wrap it for you. + + It's not nearly as extensible as optparse or argparse as it does not + implement features that are implemented on a higher level (such as + types or defaults). + + :param ctx: optionally the :class:`~click.Context` where this parser + should go with. + """ + + def __init__(self, ctx: t.Optional["Context"] = None) -> None: + #: The :class:`~click.Context` for this parser. This might be + #: `None` for some advanced use cases. + self.ctx = ctx + #: This controls how the parser deals with interspersed arguments. + #: If this is set to `False`, the parser will stop on the first + #: non-option. Click uses this to implement nested subcommands + #: safely. + self.allow_interspersed_args = 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 = False + + if ctx is not None: + self.allow_interspersed_args = ctx.allow_interspersed_args + self.ignore_unknown_options = ctx.ignore_unknown_options + + self._short_opt: t.Dict[str, Option] = {} + self._long_opt: t.Dict[str, Option] = {} + self._opt_prefixes = {"-", "--"} + self._args: t.List[Argument] = [] + + def add_option( + self, + obj: "CoreOption", + opts: t.Sequence[str], + dest: t.Optional[str], + action: t.Optional[str] = None, + nargs: int = 1, + const: t.Optional[t.Any] = None, + ) -> None: + """Adds a new option named `dest` to the parser. The destination + is not inferred (unlike with optparse) and needs to be explicitly + provided. Action can be any of ``store``, ``store_const``, + ``append``, ``append_const`` or ``count``. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + opts = [normalize_opt(opt, self.ctx) for opt in opts] + option = Option(obj, opts, dest, action=action, nargs=nargs, const=const) + self._opt_prefixes.update(option.prefixes) + for opt in option._short_opts: + self._short_opt[opt] = option + for opt in option._long_opts: + self._long_opt[opt] = option + + def add_argument( + self, obj: "CoreArgument", dest: t.Optional[str], nargs: int = 1 + ) -> None: + """Adds a positional argument named `dest` to the parser. + + The `obj` can be used to identify the option in the order list + that is returned from the parser. + """ + self._args.append(Argument(obj, dest=dest, nargs=nargs)) + + def parse_args( + self, args: t.List[str] + ) -> t.Tuple[t.Dict[str, t.Any], t.List[str], t.List["CoreParameter"]]: + """Parses positional arguments and returns ``(values, args, order)`` + for the parsed options and arguments as well as the leftover + arguments if there are any. The order is a list of objects as they + appear on the command line. If arguments appear multiple times they + will be memorized multiple times as well. + """ + state = ParsingState(args) + try: + self._process_args_for_options(state) + self._process_args_for_args(state) + except UsageError: + if self.ctx is None or not self.ctx.resilient_parsing: + raise + return state.opts, state.largs, state.order + + def _process_args_for_args(self, state: ParsingState) -> None: + pargs, args = _unpack_args( + state.largs + state.rargs, [x.nargs for x in self._args] + ) + + for idx, arg in enumerate(self._args): + arg.process(pargs[idx], state) + + state.largs = args + state.rargs = [] + + def _process_args_for_options(self, state: ParsingState) -> None: + while state.rargs: + arg = state.rargs.pop(0) + arglen = len(arg) + # Double dashes always handled explicitly regardless of what + # prefixes are valid. + if arg == "--": + return + elif arg[:1] in self._opt_prefixes and arglen > 1: + self._process_opts(arg, state) + elif self.allow_interspersed_args: + state.largs.append(arg) + else: + state.rargs.insert(0, arg) + return + + # Say this is the original argument list: + # [arg0, arg1, ..., arg(i-1), arg(i), arg(i+1), ..., arg(N-1)] + # ^ + # (we are about to process arg(i)). + # + # Then rargs is [arg(i), ..., arg(N-1)] and largs is a *subset* of + # [arg0, ..., arg(i-1)] (any options and their arguments will have + # been removed from largs). + # + # The while loop will usually consume 1 or more arguments per pass. + # If it consumes 1 (eg. arg is an option that takes no arguments), + # then after _process_arg() is done the situation is: + # + # largs = subset of [arg0, ..., arg(i)] + # rargs = [arg(i+1), ..., arg(N-1)] + # + # If allow_interspersed_args is false, largs will always be + # *empty* -- still a subset of [arg0, ..., arg(i-1)], but + # not a very interesting subset! + + def _match_long_opt( + self, opt: str, explicit_value: t.Optional[str], state: ParsingState + ) -> None: + if opt not in self._long_opt: + from difflib import get_close_matches + + possibilities = get_close_matches(opt, self._long_opt) + raise NoSuchOption(opt, possibilities=possibilities, ctx=self.ctx) + + option = self._long_opt[opt] + if option.takes_value: + # At this point it's safe to modify rargs by injecting the + # explicit value, because no exception is raised in this + # branch. This means that the inserted value will be fully + # consumed. + if explicit_value is not None: + state.rargs.insert(0, explicit_value) + + value = self._get_value_from_state(opt, option, state) + + elif explicit_value is not None: + raise BadOptionUsage( + opt, _("Option {name!r} does not take a value.").format(name=opt) + ) + + else: + value = None + + option.process(value, state) + + def _match_short_opt(self, arg: str, state: ParsingState) -> None: + stop = False + i = 1 + prefix = arg[0] + unknown_options = [] + + for ch in arg[1:]: + opt = normalize_opt(f"{prefix}{ch}", self.ctx) + option = self._short_opt.get(opt) + i += 1 + + if not option: + if self.ignore_unknown_options: + unknown_options.append(ch) + continue + raise NoSuchOption(opt, ctx=self.ctx) + if option.takes_value: + # Any characters left in arg? Pretend they're the + # next arg, and stop consuming characters of arg. + if i < len(arg): + state.rargs.insert(0, arg[i:]) + stop = True + + value = self._get_value_from_state(opt, option, state) + + else: + value = None + + option.process(value, state) + + if stop: + break + + # If we got any unknown options we re-combinate the string of the + # remaining options and re-attach the prefix, then report that + # to the state as new larg. This way there is basic combinatorics + # that can be achieved while still ignoring unknown arguments. + if self.ignore_unknown_options and unknown_options: + state.largs.append(f"{prefix}{''.join(unknown_options)}") + + def _get_value_from_state( + self, option_name: str, option: Option, state: ParsingState + ) -> t.Any: + nargs = option.nargs + + if len(state.rargs) < nargs: + if option.obj._flag_needs_value: + # Option allows omitting the value. + value = _flag_needs_value + else: + raise BadOptionUsage( + option_name, + ngettext( + "Option {name!r} requires an argument.", + "Option {name!r} requires {nargs} arguments.", + nargs, + ).format(name=option_name, nargs=nargs), + ) + elif nargs == 1: + next_rarg = state.rargs[0] + + if ( + option.obj._flag_needs_value + and isinstance(next_rarg, str) + and next_rarg[:1] in self._opt_prefixes + and len(next_rarg) > 1 + ): + # The next arg looks like the start of an option, don't + # use it as the value if omitting the value is allowed. + value = _flag_needs_value + else: + value = state.rargs.pop(0) + else: + value = tuple(state.rargs[:nargs]) + del state.rargs[:nargs] + + return value + + def _process_opts(self, arg: str, state: ParsingState) -> None: + explicit_value = None + # Long option handling happens in two parts. The first part is + # supporting explicitly attached values. In any case, we will try + # to long match the option first. + if "=" in arg: + long_opt, explicit_value = arg.split("=", 1) + else: + long_opt = arg + norm_long_opt = normalize_opt(long_opt, self.ctx) + + # At this point we will match the (assumed) long option through + # the long option matching code. Note that this allows options + # like "-foo" to be matched as long options. + try: + self._match_long_opt(norm_long_opt, explicit_value, state) + except NoSuchOption: + # At this point the long option matching failed, and we need + # to try with short options. However there is a special rule + # which says, that if we have a two character options prefix + # (applies to "--foo" for instance), we do not dispatch to the + # short option code and will instead raise the no option + # error. + if arg[:2] not in self._opt_prefixes: + self._match_short_opt(arg, state) + return + + if not self.ignore_unknown_options: + raise + + state.largs.append(arg) diff --git a/.vcrunch/Lib/site-packages/click/py.typed b/.vcrunch/Lib/site-packages/click/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.vcrunch/Lib/site-packages/click/shell_completion.py b/.vcrunch/Lib/site-packages/click/shell_completion.py new file mode 100644 index 0000000..c17a8e6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/shell_completion.py @@ -0,0 +1,580 @@ +import os +import re +import typing as t +from gettext import gettext as _ + +from .core import Argument +from .core import BaseCommand +from .core import Context +from .core import MultiCommand +from .core import Option +from .core import Parameter +from .core import ParameterSource +from .parser import split_arg_string +from .utils import echo + + +def shell_complete( + cli: BaseCommand, + ctx_args: t.Dict[str, t.Any], + prog_name: str, + complete_var: str, + instruction: str, +) -> int: + """Perform shell completion for the given CLI program. + + :param cli: Command being called. + :param ctx_args: Extra arguments to pass to + ``cli.make_context``. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + :param instruction: Value of ``complete_var`` with the completion + instruction and shell, in the form ``instruction_shell``. + :return: Status code to exit with. + """ + shell, _, instruction = instruction.partition("_") + comp_cls = get_completion_class(shell) + + if comp_cls is None: + return 1 + + comp = comp_cls(cli, ctx_args, prog_name, complete_var) + + if instruction == "source": + echo(comp.source()) + return 0 + + if instruction == "complete": + echo(comp.complete()) + return 0 + + return 1 + + +class CompletionItem: + """Represents a completion value and metadata about the value. The + default metadata is ``type`` to indicate special shell handling, + and ``help`` if a shell supports showing a help string next to the + value. + + Arbitrary parameters can be passed when creating the object, and + accessed using ``item.attr``. If an attribute wasn't passed, + accessing it returns ``None``. + + :param value: The completion suggestion. + :param type: Tells the shell script to provide special completion + support for the type. Click uses ``"dir"`` and ``"file"``. + :param help: String shown next to the value if supported. + :param kwargs: Arbitrary metadata. The built-in implementations + don't use this, but custom type completions paired with custom + shell support could use it. + """ + + __slots__ = ("value", "type", "help", "_info") + + def __init__( + self, + value: t.Any, + type: str = "plain", + help: t.Optional[str] = None, + **kwargs: t.Any, + ) -> None: + self.value = value + self.type = type + self.help = 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 +} + +compdef %(complete_func)s %(prog_name)s; +""" + +_SOURCE_FISH = """\ +function %(complete_func)s; + set -l response; + + for value in (env %(complete_var)s=fish_complete COMP_WORDS=(commandline -cp) \ +COMP_CWORD=(commandline -t) %(prog_name)s); + set response $response $value; + end; + + for completion in $response; + set -l metadata (string split "," $completion); + + if test $metadata[1] = "dir"; + __fish_complete_directories $metadata[2]; + else if test $metadata[1] = "file"; + __fish_complete_path $metadata[2]; + else if test $metadata[1] = "plain"; + echo $metadata[2]; + end; + end; +end; + +complete --no-files --command %(prog_name)s --arguments \ +"(%(complete_func)s)"; +""" + + +class ShellComplete: + """Base class for providing shell completion support. A subclass for + a given shell will override attributes and methods to implement the + completion instructions (``source`` and ``complete``). + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param complete_var: Name of the environment variable that holds + the completion instruction. + + .. versionadded:: 8.0 + """ + + name: t.ClassVar[str] + """Name to register the shell as with :func:`add_completion_class`. + This is used in completion instructions (``{name}_source`` and + ``{name}_complete``). + """ + + source_template: t.ClassVar[str] + """Completion script template formatted by :meth:`source`. This must + be provided by subclasses. + """ + + def __init__( + self, + cli: BaseCommand, + ctx_args: t.Dict[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("-", "_"), re.ASCII) + return f"_{safe_name}_completion" + + def source_vars(self) -> t.Dict[str, t.Any]: + """Vars for formatting :attr:`source_template`. + + By default this provides ``complete_func``, ``complete_var``, + and ``prog_name``. + """ + return { + "complete_func": self.func_name, + "complete_var": self.complete_var, + "prog_name": self.prog_name, + } + + def source(self) -> str: + """Produce the shell script that defines the completion + function. By default this ``%``-style formats + :attr:`source_template` with the dict returned by + :meth:`source_vars`. + """ + return self.source_template % self.source_vars() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + """Use the env vars defined by the shell script to return a + tuple of ``args, incomplete``. This must be implemented by + subclasses. + """ + raise NotImplementedError + + def get_completions( + self, args: t.List[str], incomplete: str + ) -> t.List[CompletionItem]: + """Determine the context and last complete command or parameter + from the complete args. Call that object's ``shell_complete`` + method to get the completions for the incomplete value. + + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + ctx = _resolve_context(self.cli, self.ctx_args, self.prog_name, args) + obj, incomplete = _resolve_incomplete(ctx, args, incomplete) + return obj.shell_complete(ctx, incomplete) + + def format_completion(self, item: CompletionItem) -> str: + """Format a completion item into the form recognized by the + shell script. This must be implemented by subclasses. + + :param item: Completion item to format. + """ + raise NotImplementedError + + def complete(self) -> str: + """Produce the completion data to send back to the shell. + + By default this calls :meth:`get_completion_args`, gets the + completions, then calls :meth:`format_completion` for each + completion. + """ + args, incomplete = self.get_completion_args() + completions = self.get_completions(args, incomplete) + out = [self.format_completion(item) for item in completions] + return "\n".join(out) + + +class BashComplete(ShellComplete): + """Shell completion for Bash.""" + + name = "bash" + source_template = _SOURCE_BASH + + def _check_version(self) -> None: + import subprocess + + output = subprocess.run( + ["bash", "-c", "echo ${BASH_VERSION}"], stdout=subprocess.PIPE + ) + match = re.search(r"^(\d+)\.(\d+)\.\d+", output.stdout.decode()) + + if match is not None: + major, minor = match.groups() + + if major < "4" or major == "4" and minor < "4": + raise RuntimeError( + _( + "Shell completion is not supported for Bash" + " versions older than 4.4." + ) + ) + else: + raise RuntimeError( + _("Couldn't detect Bash version, shell completion is not supported.") + ) + + def source(self) -> str: + self._check_version() + return super().source() + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type},{item.value}" + + +class ZshComplete(ShellComplete): + """Shell completion for Zsh.""" + + name = "zsh" + source_template = _SOURCE_ZSH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + cword = int(os.environ["COMP_CWORD"]) + args = cwords[1:cword] + + try: + incomplete = cwords[cword] + except IndexError: + incomplete = "" + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + return f"{item.type}\n{item.value}\n{item.help if item.help else '_'}" + + +class FishComplete(ShellComplete): + """Shell completion for Fish.""" + + name = "fish" + source_template = _SOURCE_FISH + + def get_completion_args(self) -> t.Tuple[t.List[str], str]: + cwords = split_arg_string(os.environ["COMP_WORDS"]) + incomplete = os.environ["COMP_CWORD"] + args = cwords[1:] + + # Fish stores the partial word in both COMP_WORDS and + # COMP_CWORD, remove it from complete args. + if incomplete and args and args[-1] == incomplete: + args.pop() + + return args, incomplete + + def format_completion(self, item: CompletionItem) -> str: + if item.help: + return f"{item.type},{item.value}\t{item.help}" + + return f"{item.type},{item.value}" + + +_available_shells: t.Dict[str, t.Type[ShellComplete]] = { + "bash": BashComplete, + "fish": FishComplete, + "zsh": ZshComplete, +} + + +def add_completion_class( + cls: t.Type[ShellComplete], name: t.Optional[str] = None +) -> None: + """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 + + +def get_completion_class(shell: str) -> t.Optional[t.Type[ShellComplete]]: + """Look up a registered :class:`ShellComplete` subclass by the name + provided by the completion instruction environment variable. If the + name isn't registered, returns ``None``. + + :param shell: Name the class is registered under. + """ + return _available_shells.get(shell) + + +def _is_incomplete_argument(ctx: Context, param: Parameter) -> bool: + """Determine if the given parameter is an argument that can still + accept values. + + :param ctx: Invocation context for the command represented by the + parsed complete args. + :param param: Argument object being checked. + """ + if not isinstance(param, Argument): + return False + + assert param.name is not None + value = ctx.params[param.name] + return ( + param.nargs == -1 + or ctx.get_parameter_source(param.name) is not ParameterSource.COMMANDLINE + or ( + param.nargs > 1 + and isinstance(value, (tuple, list)) + and len(value) < param.nargs + ) + ) + + +def _start_of_option(ctx: Context, value: str) -> bool: + """Check if the value looks like the start of an option.""" + if not value: + return False + + c = value[0] + return c in ctx._opt_prefixes + + +def _is_incomplete_option(ctx: Context, args: t.List[str], param: Parameter) -> bool: + """Determine if the given parameter is an option that needs a value. + + :param args: List of complete args before the incomplete value. + :param param: Option object being checked. + """ + if not isinstance(param, Option): + return False + + if param.is_flag or param.count: + return False + + last_option = None + + for index, arg in enumerate(reversed(args)): + if index + 1 > param.nargs: + break + + if _start_of_option(ctx, arg): + last_option = arg + + return last_option is not None and last_option in param.opts + + +def _resolve_context( + cli: BaseCommand, ctx_args: t.Dict[str, t.Any], prog_name: str, args: t.List[str] +) -> Context: + """Produce the context hierarchy starting with the command and + traversing the complete arguments. This only follows the commands, + it doesn't trigger input prompts or callbacks. + + :param cli: Command being called. + :param prog_name: Name of the executable in the shell. + :param args: List of complete args before the incomplete value. + """ + ctx_args["resilient_parsing"] = True + ctx = cli.make_context(prog_name, args.copy(), **ctx_args) + args = ctx.protected_args + ctx.args + + while args: + command = ctx.command + + if isinstance(command, MultiCommand): + if not command.chain: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + ctx = cmd.make_context(name, args, parent=ctx, resilient_parsing=True) + args = ctx.protected_args + ctx.args + else: + while args: + name, cmd, args = command.resolve_command(ctx, args) + + if cmd is None: + return ctx + + sub_ctx = cmd.make_context( + name, + args, + parent=ctx, + allow_extra_args=True, + allow_interspersed_args=False, + resilient_parsing=True, + ) + args = sub_ctx.args + + ctx = sub_ctx + args = [*sub_ctx.protected_args, *sub_ctx.args] + else: + break + + return ctx + + +def _resolve_incomplete( + ctx: Context, args: t.List[str], incomplete: str +) -> t.Tuple[t.Union[BaseCommand, Parameter], str]: + """Find the Click object that will handle the completion of the + incomplete value. Return the object and the incomplete value. + + :param ctx: Invocation context for the command represented by + the parsed complete args. + :param args: List of complete args before the incomplete value. + :param incomplete: Value being completed. May be empty. + """ + # Different shells treat an "=" between a long option name and + # value differently. Might keep the value joined, return the "=" + # as a separate item, or return the split name and value. Always + # split and discard the "=" to make completion easier. + if incomplete == "=": + incomplete = "" + elif "=" in incomplete and _start_of_option(ctx, incomplete): + name, _, incomplete = incomplete.partition("=") + args.append(name) + + # The "--" marker tells Click to stop treating values as options + # even if they start with the option character. If it hasn't been + # given and the incomplete arg looks like an option, the current + # command will provide option name completions. + if "--" not in args and _start_of_option(ctx, incomplete): + return ctx.command, incomplete + + params = ctx.command.get_params(ctx) + + # If the last complete arg is an option name with an incomplete + # value, the option will provide value completions. + for param in params: + if _is_incomplete_option(ctx, args, param): + return param, incomplete + + # It's not an option name or value. The first argument without a + # parsed value will provide value completions. + for param in params: + if _is_incomplete_argument(ctx, param): + return param, incomplete + + # There were no unparsed arguments, the command may be a group that + # will provide command name completions. + return ctx.command, incomplete diff --git a/.vcrunch/Lib/site-packages/click/termui.py b/.vcrunch/Lib/site-packages/click/termui.py new file mode 100644 index 0000000..bfb2f5a --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/termui.py @@ -0,0 +1,787 @@ +import inspect +import io +import itertools +import os +import sys +import typing as t +from gettext import gettext as _ + +from ._compat import isatty +from ._compat import strip_ansi +from ._compat import WIN +from .exceptions import Abort +from .exceptions import UsageError +from .globals import resolve_color_default +from .types import Choice +from .types import convert_type +from .types import ParamType +from .utils import echo +from .utils import LazyFile + +if t.TYPE_CHECKING: + from ._termui_impl import ProgressBar + +V = t.TypeVar("V") + +# The prompt functions to use. The doc tools currently override these +# functions to customize how they work. +visible_prompt_func: t.Callable[[str], str] = input + +_ansi_colors = { + "black": 30, + "red": 31, + "green": 32, + "yellow": 33, + "blue": 34, + "magenta": 35, + "cyan": 36, + "white": 37, + "reset": 39, + "bright_black": 90, + "bright_red": 91, + "bright_green": 92, + "bright_yellow": 93, + "bright_blue": 94, + "bright_magenta": 95, + "bright_cyan": 96, + "bright_white": 97, +} +_ansi_reset_all = "\033[0m" + + +def hidden_prompt_func(prompt: str) -> str: + import getpass + + return getpass.getpass(prompt) + + +def _build_prompt( + text: str, + suffix: str, + show_default: bool = False, + default: t.Optional[t.Any] = None, + show_choices: bool = True, + type: t.Optional[ParamType] = None, +) -> str: + prompt = text + if type is not None and show_choices and isinstance(type, Choice): + prompt += f" ({', '.join(map(str, type.choices))})" + if default is not None and show_default: + prompt = f"{prompt} [{_format_default(default)}]" + return f"{prompt}{suffix}" + + +def _format_default(default: t.Any) -> t.Any: + if isinstance(default, (io.IOBase, LazyFile)) and hasattr(default, "name"): + return default.name # type: ignore + + return default + + +def prompt( + text: str, + default: t.Optional[t.Any] = None, + hide_input: bool = False, + confirmation_prompt: t.Union[bool, str] = False, + type: t.Optional[t.Union[ParamType, t.Any]] = None, + value_proc: t.Optional[t.Callable[[str], t.Any]] = None, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, + show_choices: bool = True, +) -> t.Any: + """Prompts a user for input. This is a convenience function that can + be used to prompt a user for input later. + + If the user aborts the input by sending an interrupt signal, this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the text to show for the prompt. + :param default: the default value to use if no input happens. If this + is not given it will prompt until it's aborted. + :param hide_input: if this is set to true then the input value will + be hidden. + :param confirmation_prompt: Prompt a second time to confirm the + value. Can be set to a string instead of ``True`` to customize + the message. + :param type: the type to use to check the value against. + :param value_proc: if this parameter is provided it's a function that + is invoked instead of the type conversion to + convert a value. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + :param show_choices: Show or hide choices if the passed type is a Choice. + For example if type is a Choice of either day or week, + show_choices is true and text is "Group by" then the + prompt will be "Group by (day, week): ". + + .. versionadded:: 8.0 + ``confirmation_prompt`` can be a custom string. + + .. versionadded:: 7.0 + Added the ``show_choices`` parameter. + + .. versionadded:: 6.0 + Added unicode support for cmd.exe on Windows. + + .. versionadded:: 4.0 + Added the `err` parameter. + + """ + + def prompt_func(text: str) -> str: + f = hidden_prompt_func if hide_input else visible_prompt_func + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(text.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + return f(" ") + except (KeyboardInterrupt, EOFError): + # getpass doesn't print a newline if the user aborts input with ^C. + # Allegedly this behavior is inherited from getpass(3). + # A doc bug has been filed at https://bugs.python.org/issue24711 + if hide_input: + echo(None, err=err) + raise Abort() from None + + if value_proc is None: + value_proc = convert_type(type, default) + + prompt = _build_prompt( + text, prompt_suffix, show_default, default, show_choices, type + ) + + if confirmation_prompt: + if confirmation_prompt is True: + confirmation_prompt = _("Repeat for confirmation") + + confirmation_prompt = _build_prompt(confirmation_prompt, prompt_suffix) + + while True: + while True: + value = prompt_func(prompt) + if value: + break + elif default is not None: + value = default + break + try: + result = value_proc(value) + except UsageError as e: + if hide_input: + echo(_("Error: The value you entered was invalid."), err=err) + else: + echo(_("Error: {e.message}").format(e=e), err=err) # noqa: B306 + continue + if not confirmation_prompt: + return result + while True: + value2 = prompt_func(confirmation_prompt) + is_empty = not value and not value2 + if value2 or is_empty: + break + if value == value2: + return result + echo(_("Error: The two entered values do not match."), err=err) + + +def confirm( + text: str, + default: t.Optional[bool] = False, + abort: bool = False, + prompt_suffix: str = ": ", + show_default: bool = True, + err: bool = False, +) -> bool: + """Prompts for confirmation (yes/no question). + + If the user aborts the input by sending a interrupt signal this + function will catch it and raise a :exc:`Abort` exception. + + :param text: the question to ask. + :param default: The default value to use when no input is given. If + ``None``, repeat until input is given. + :param abort: if this is set to `True` a negative answer aborts the + exception by raising :exc:`Abort`. + :param prompt_suffix: a suffix that should be added to the prompt. + :param show_default: shows or hides the default value in the prompt. + :param err: if set to true the file defaults to ``stderr`` instead of + ``stdout``, the same as with echo. + + .. versionchanged:: 8.0 + Repeat until input is given if ``default`` is ``None``. + + .. versionadded:: 4.0 + Added the ``err`` parameter. + """ + prompt = _build_prompt( + text, + prompt_suffix, + show_default, + "y/n" if default is None else ("Y/n" if default else "y/N"), + ) + + while True: + try: + # Write the prompt separately so that we get nice + # coloring through colorama on Windows + echo(prompt.rstrip(" "), nl=False, err=err) + # Echo a space to stdout to work around an issue where + # readline causes backspace to clear the whole line. + value = visible_prompt_func(" ").lower().strip() + except (KeyboardInterrupt, EOFError): + raise Abort() from None + if value in ("y", "yes"): + rv = True + elif value in ("n", "no"): + rv = False + elif default is not None and value == "": + rv = default + else: + echo(_("Error: invalid input"), err=err) + continue + break + if abort and not rv: + raise Abort() + return rv + + +def echo_via_pager( + text_or_generator: t.Union[t.Iterable[str], t.Callable[[], t.Iterable[str]], str], + color: t.Optional[bool] = None, +) -> None: + """This function takes a text and shows it via an environment specific + pager on stdout. + + .. versionchanged:: 3.0 + Added the `color` flag. + + :param text_or_generator: the text to page, or alternatively, a + generator emitting the text to page. + :param color: controls if the pager supports ANSI colors or not. The + default is autodetection. + """ + color = resolve_color_default(color) + + if inspect.isgeneratorfunction(text_or_generator): + i = t.cast(t.Callable[[], t.Iterable[str]], text_or_generator)() + elif isinstance(text_or_generator, str): + i = [text_or_generator] + else: + i = iter(t.cast(t.Iterable[str], text_or_generator)) + + # convert every element of i to a text type if necessary + text_generator = (el if isinstance(el, str) else str(el) for el in i) + + from ._termui_impl import pager + + return pager(itertools.chain(text_generator, "\n"), color) + + +def progressbar( + iterable: t.Optional[t.Iterable[V]] = None, + length: t.Optional[int] = None, + label: t.Optional[str] = None, + show_eta: bool = True, + show_percent: t.Optional[bool] = None, + show_pos: bool = False, + item_show_func: t.Optional[t.Callable[[t.Optional[V]], t.Optional[str]]] = None, + fill_char: str = "#", + empty_char: str = "-", + bar_template: str = "%(label)s [%(bar)s] %(info)s", + info_sep: str = " ", + width: int = 36, + file: t.Optional[t.TextIO] = None, + color: t.Optional[bool] = None, + update_min_steps: int = 1, +) -> "ProgressBar[V]": + """This function creates an iterable context manager that can be used + to iterate over something while showing a progress bar. It will + either iterate over the `iterable` or `length` items (that are counted + up). While iteration happens, this function will print a rendered + progress bar to the given `file` (defaults to stdout) and will attempt + to calculate remaining time and more. By default, this progress bar + will not be rendered if the file is not a terminal. + + The context manager creates the progress bar. When the context + manager is entered the progress bar is already created. With every + iteration over the progress bar, the iterable passed to the bar is + advanced and the bar is updated. When the context manager exits, + a newline is printed and the progress bar is finalized on screen. + + Note: The progress bar is currently designed for use cases where the + total progress can be expected to take at least several seconds. + Because of this, the ProgressBar class object won't display + progress that is considered too fast, and progress where the time + between steps is less than a second. + + No printing must happen or the progress bar will be unintentionally + destroyed. + + Example usage:: + + with progressbar(items) as bar: + for item in bar: + do_something_with(item) + + Alternatively, if no iterable is specified, one can manually update the + progress bar through the `update()` method instead of directly + iterating over the progress bar. The update method accepts the number + of steps to increment the bar with:: + + with progressbar(length=chunks.total_bytes) as bar: + for chunk in chunks: + process_chunk(chunk) + bar.update(chunks.bytes) + + The ``update()`` method also takes an optional value specifying the + ``current_item`` at the new position. This is useful when used + together with ``item_show_func`` to customize the output for each + manual step:: + + with click.progressbar( + length=total_size, + label='Unzipping archive', + item_show_func=lambda a: a.filename + ) as bar: + for archive in zip_file: + archive.extract() + bar.update(archive.size, archive) + + :param iterable: an iterable to iterate over. If not provided the length + is required. + :param length: the number of items to iterate over. By default the + progressbar will attempt to ask the iterator about its + length, which might or might not work. If an iterable is + also provided this parameter can be used to override the + length. If an iterable is not provided the progress bar + will iterate over a range of that length. + :param label: the label to show next to the progress bar. + :param show_eta: enables or disables the estimated time display. This is + automatically disabled if the length cannot be + determined. + :param show_percent: enables or disables the percentage display. The + default is `True` if the iterable has a length or + `False` if not. + :param show_pos: enables or disables the absolute position display. The + default is `False`. + :param item_show_func: A function called with the current item which + can return a string to show next to the progress bar. If the + function returns ``None`` nothing is shown. The current item can + be ``None``, such as when entering and exiting the bar. + :param fill_char: the character to use to show the filled part of the + progress bar. + :param empty_char: the character to use to show the non-filled part of + the progress bar. + :param bar_template: the format string to use as template for the bar. + The parameters in it are ``label`` for the label, + ``bar`` for the progress bar and ``info`` for the + info section. + :param info_sep: the separator between multiple info items (eta etc.) + :param width: the width of the progress bar in characters, 0 means full + terminal width + :param file: The file to write to. If this is not a terminal then + only the label is printed. + :param color: controls if the terminal supports ANSI colors or not. The + default is autodetection. This is only needed if ANSI + codes are included anywhere in the progress bar output + which is not the case by default. + :param update_min_steps: Render only when this many updates have + completed. This allows tuning for very fast iterators. + + .. versionchanged:: 8.0 + Output is shown even if execution time is less than 0.5 seconds. + + .. versionchanged:: 8.0 + ``item_show_func`` shows the current item, not the previous one. + + .. versionchanged:: 8.0 + Labels are echoed if the output is not a TTY. Reverts a change + in 7.0 that removed all output. + + .. versionadded:: 8.0 + Added the ``update_min_steps`` parameter. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. Added the ``update`` method to + the object. + + .. versionadded:: 2.0 + """ + from ._termui_impl import ProgressBar + + color = resolve_color_default(color) + return ProgressBar( + iterable=iterable, + length=length, + show_eta=show_eta, + show_percent=show_percent, + show_pos=show_pos, + item_show_func=item_show_func, + fill_char=fill_char, + empty_char=empty_char, + bar_template=bar_template, + info_sep=info_sep, + file=file, + label=label, + width=width, + color=color, + update_min_steps=update_min_steps, + ) + + +def clear() -> None: + """Clears the terminal screen. This will have the effect of clearing + the whole visible space of the terminal and moving the cursor to the + top left. This does not do anything if not connected to a terminal. + + .. versionadded:: 2.0 + """ + if not isatty(sys.stdout): + return + if WIN: + os.system("cls") + else: + sys.stdout.write("\033[2J\033[1;1H") + + +def _interpret_color( + color: t.Union[int, t.Tuple[int, int, int], str], offset: int = 0 +) -> str: + if isinstance(color, int): + return f"{38 + offset};5;{color:d}" + + if isinstance(color, (tuple, list)): + r, g, b = color + return f"{38 + offset};2;{r:d};{g:d};{b:d}" + + return str(_ansi_colors[color] + offset) + + +def style( + text: t.Any, + fg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bg: t.Optional[t.Union[int, t.Tuple[int, int, int], str]] = None, + bold: t.Optional[bool] = None, + dim: t.Optional[bool] = None, + underline: t.Optional[bool] = None, + overline: t.Optional[bool] = None, + italic: t.Optional[bool] = None, + blink: t.Optional[bool] = None, + reverse: t.Optional[bool] = None, + strikethrough: t.Optional[bool] = None, + reset: bool = True, +) -> str: + """Styles a text with ANSI styles and returns the new string. By + default the styling is self contained which means that at the end + of the string a reset code is issued. This can be prevented by + passing ``reset=False``. + + Examples:: + + click.echo(click.style('Hello World!', fg='green')) + click.echo(click.style('ATTENTION!', blink=True)) + click.echo(click.style('Some things', reverse=True, fg='cyan')) + click.echo(click.style('More colors', fg=(255, 12, 128), bg=117)) + + Supported color names: + + * ``black`` (might be a gray) + * ``red`` + * ``green`` + * ``yellow`` (might be an orange) + * ``blue`` + * ``magenta`` + * ``cyan`` + * ``white`` (might be light gray) + * ``bright_black`` + * ``bright_red`` + * ``bright_green`` + * ``bright_yellow`` + * ``bright_blue`` + * ``bright_magenta`` + * ``bright_cyan`` + * ``bright_white`` + * ``reset`` (reset the color code only) + + If the terminal supports it, color may also be specified as: + + - An integer in the interval [0, 255]. The terminal must support + 8-bit/256-color mode. + - An RGB tuple of three integers in [0, 255]. The terminal must + support 24-bit/true-color mode. + + See https://en.wikipedia.org/wiki/ANSI_color and + https://gist.github.com/XVilka/8346728 for more information. + + :param text: the string to style with ansi codes. + :param fg: if provided this will become the foreground color. + :param bg: if provided this will become the background color. + :param bold: if provided this will enable or disable bold mode. + :param dim: if provided this will enable or disable dim mode. This is + badly supported. + :param underline: if provided this will enable or disable underline. + :param overline: if provided this will enable or disable overline. + :param italic: if provided this will enable or disable italic. + :param blink: if provided this will enable or disable blinking. + :param reverse: if provided this will enable or disable inverse + rendering (foreground becomes background and the + other way round). + :param strikethrough: if provided this will enable or disable + striking through text. + :param reset: by default a reset-all code is added at the end of the + string which means that styles do not carry over. This + can be disabled to compose styles. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. + + .. versionchanged:: 8.0 + Added support for 256 and RGB color codes. + + .. versionchanged:: 8.0 + Added the ``strikethrough``, ``italic``, and ``overline`` + parameters. + + .. versionchanged:: 7.0 + Added support for bright colors. + + .. versionadded:: 2.0 + """ + if not isinstance(text, str): + text = str(text) + + bits = [] + + if fg: + try: + bits.append(f"\033[{_interpret_color(fg)}m") + except KeyError: + raise TypeError(f"Unknown color {fg!r}") from None + + if bg: + try: + bits.append(f"\033[{_interpret_color(bg, 10)}m") + except KeyError: + raise TypeError(f"Unknown color {bg!r}") from None + + if bold is not None: + bits.append(f"\033[{1 if bold else 22}m") + if dim is not None: + bits.append(f"\033[{2 if dim else 22}m") + if underline is not None: + bits.append(f"\033[{4 if underline else 24}m") + if overline is not None: + bits.append(f"\033[{53 if overline else 55}m") + if italic is not None: + bits.append(f"\033[{3 if italic else 23}m") + if blink is not None: + bits.append(f"\033[{5 if blink else 25}m") + if reverse is not None: + bits.append(f"\033[{7 if reverse else 27}m") + if strikethrough is not None: + bits.append(f"\033[{9 if strikethrough else 29}m") + bits.append(text) + if reset: + bits.append(_ansi_reset_all) + return "".join(bits) + + +def unstyle(text: str) -> str: + """Removes ANSI styling information from a string. Usually it's not + necessary to use this function as Click's echo function will + automatically remove styling if necessary. + + .. versionadded:: 2.0 + + :param text: the text to remove style information from. + """ + return strip_ansi(text) + + +def secho( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.AnyStr]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, + **styles: t.Any, +) -> None: + """This function combines :func:`echo` and :func:`style` into one + call. As such the following two calls are the same:: + + click.secho('Hello World!', fg='green') + click.echo(click.style('Hello World!', fg='green')) + + All keyword arguments are forwarded to the underlying functions + depending on which one they go with. + + Non-string types will be converted to :class:`str`. However, + :class:`bytes` are passed directly to :meth:`echo` without applying + style. If you want to style bytes that represent text, call + :meth:`bytes.decode` first. + + .. versionchanged:: 8.0 + A non-string ``message`` is converted to a string. Bytes are + passed through without style applied. + + .. versionadded:: 2.0 + """ + if message is not None and not isinstance(message, (bytes, bytearray)): + message = style(message, **styles) + + return echo(message, file=file, nl=nl, err=err, color=color) + + +def edit( + text: t.Optional[t.AnyStr] = None, + editor: t.Optional[str] = None, + env: t.Optional[t.Mapping[str, str]] = None, + require_save: bool = True, + extension: str = ".txt", + filename: t.Optional[str] = None, +) -> t.Optional[t.AnyStr]: + r"""Edits the given text in the defined editor. If an editor is given + (should be the full path to the executable but the regular operating + system search path is used for finding the executable) it overrides + the detected editor. Optionally, some environment variables can be + used. If the editor is closed without changes, `None` is returned. In + case a file is edited directly the return value is always `None` and + `require_save` and `extension` are ignored. + + If the editor cannot be opened a :exc:`UsageError` is raised. + + Note for Windows: to simplify cross-platform usage, the newlines are + automatically converted from POSIX to Windows and vice versa. As such, + the message here will have ``\n`` as newline markers. + + :param text: the text to edit. + :param editor: optionally the editor to use. Defaults to automatic + detection. + :param env: environment variables to forward to the editor. + :param require_save: if this is true, then not saving in the editor + will make the return value become `None`. + :param extension: the extension to tell the editor about. This defaults + to `.txt` but changing this might change syntax + highlighting. + :param filename: if provided it will edit this file instead of the + provided text contents. It will not use a temporary + file as an indirection in that case. + """ + from ._termui_impl import Editor + + ed = Editor(editor=editor, env=env, require_save=require_save, extension=extension) + + if filename is None: + return ed.edit(text) + + ed.edit_file(filename) + return None + + +def launch(url: str, wait: bool = False, locate: bool = False) -> int: + """This function launches the given URL (or filename) in the default + viewer application for this file type. If this is an executable, it + might launch the executable in a new session. The return value is + the exit code of the launched application. Usually, ``0`` indicates + success. + + Examples:: + + click.launch('https://click.palletsprojects.com/') + click.launch('/my/downloaded/file', locate=True) + + .. versionadded:: 2.0 + + :param url: URL or filename of the thing to launch. + :param wait: Wait for the program to exit before returning. This + only works if the launched program blocks. In particular, + ``xdg-open`` on Linux does not block. + :param locate: if this is set to `True` then instead of launching the + application associated with the URL it will attempt to + launch a file manager with the file located. This + might have weird effects if the URL does not point to + the filesystem. + """ + from ._termui_impl import open_url + + return open_url(url, wait=wait, locate=locate) + + +# If this is provided, getchar() calls into this instead. This is used +# for unittesting purposes. +_getchar: t.Optional[t.Callable[[bool], str]] = None + + +def getchar(echo: bool = False) -> str: + """Fetches a single character from the terminal and returns it. This + will always return a unicode character and under certain rare + circumstances this might return more than one character. The + situations which more than one character is returned is when for + whatever reason multiple characters end up in the terminal buffer or + standard input was not actually a terminal. + + Note that this will always read from the terminal, even if something + is piped into the standard input. + + Note for Windows: in rare cases when typing non-ASCII characters, this + function might wait for a second character and then return both at once. + This is because certain Unicode characters look like special-key markers. + + .. versionadded:: 2.0 + + :param echo: if set to `True`, the character read will also show up on + the terminal. The default is to not show it. + """ + global _getchar + + if _getchar is None: + from ._termui_impl import getchar as f + + _getchar = f + + return _getchar(echo) + + +def raw_terminal() -> t.ContextManager[int]: + from ._termui_impl import raw_terminal as f + + return f() + + +def pause(info: t.Optional[str] = None, err: bool = False) -> None: + """This command stops execution and waits for the user to press any + key to continue. This is similar to the Windows batch "pause" + command. If the program is not run through a terminal, this command + will instead do nothing. + + .. versionadded:: 2.0 + + .. versionadded:: 4.0 + Added the `err` parameter. + + :param info: The message to print before pausing. Defaults to + ``"Press any key to continue..."``. + :param err: if set to message goes to ``stderr`` instead of + ``stdout``, the same as with echo. + """ + if not isatty(sys.stdin) or not isatty(sys.stdout): + return + + if info is None: + info = _("Press any key to continue...") + + try: + if info: + echo(info, nl=False, err=err) + try: + getchar() + except (KeyboardInterrupt, EOFError): + pass + finally: + if info: + echo(err=err) diff --git a/.vcrunch/Lib/site-packages/click/testing.py b/.vcrunch/Lib/site-packages/click/testing.py new file mode 100644 index 0000000..e395c2e --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/testing.py @@ -0,0 +1,479 @@ +import contextlib +import io +import os +import shlex +import shutil +import sys +import tempfile +import typing as t +from types import TracebackType + +from . import formatting +from . import termui +from . import utils +from ._compat import _find_binary_reader + +if t.TYPE_CHECKING: + from .core import BaseCommand + + +class EchoingStdin: + def __init__(self, input: t.BinaryIO, output: t.BinaryIO) -> None: + self._input = input + self._output = output + self._paused = False + + def __getattr__(self, x: str) -> t.Any: + return getattr(self._input, x) + + def _echo(self, rv: bytes) -> bytes: + if not self._paused: + self._output.write(rv) + + return rv + + def read(self, n: int = -1) -> bytes: + return self._echo(self._input.read(n)) + + def read1(self, n: int = -1) -> bytes: + return self._echo(self._input.read1(n)) # type: ignore + + def readline(self, n: int = -1) -> bytes: + return self._echo(self._input.readline(n)) + + def readlines(self) -> t.List[bytes]: + return [self._echo(x) for x in self._input.readlines()] + + def __iter__(self) -> t.Iterator[bytes]: + return iter(self._echo(x) for x in self._input) + + def __repr__(self) -> str: + return repr(self._input) + + +@contextlib.contextmanager +def _pause_echo(stream: t.Optional[EchoingStdin]) -> t.Iterator[None]: + if stream is None: + yield + else: + stream._paused = True + yield + stream._paused = False + + +class _NamedTextIOWrapper(io.TextIOWrapper): + def __init__( + self, buffer: t.BinaryIO, name: str, mode: str, **kwargs: t.Any + ) -> None: + super().__init__(buffer, **kwargs) + self._name = name + self._mode = mode + + @property + def name(self) -> str: + return self._name + + @property + def mode(self) -> str: + return self._mode + + +def make_input_stream( + input: t.Optional[t.Union[str, bytes, t.IO]], charset: str +) -> t.BinaryIO: + # Is already an input stream. + if hasattr(input, "read"): + rv = _find_binary_reader(t.cast(t.IO, 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(t.cast(bytes, input)) + + +class Result: + """Holds the captured result of an invoked CLI script.""" + + def __init__( + self, + runner: "CliRunner", + stdout_bytes: bytes, + stderr_bytes: t.Optional[bytes], + return_value: t.Any, + exit_code: int, + exception: t.Optional[BaseException], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = None, + ): + #: The runner that created the result + self.runner = runner + #: The standard output as bytes. + self.stdout_bytes = stdout_bytes + #: The standard error as bytes, or None if not available + self.stderr_bytes = stderr_bytes + #: The value returned from the invoked command. + #: + #: .. versionadded:: 8.0 + self.return_value = return_value + #: The exit code as integer. + self.exit_code = exit_code + #: The exception that happened if one did. + self.exception = exception + #: The traceback + self.exc_info = exc_info + + @property + def output(self) -> str: + """The (standard) output as unicode string.""" + return self.stdout + + @property + def stdout(self) -> str: + """The standard output as unicode string.""" + return self.stdout_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + @property + def stderr(self) -> str: + """The standard error as unicode string.""" + if self.stderr_bytes is None: + raise ValueError("stderr not separately captured") + return self.stderr_bytes.decode(self.runner.charset, "replace").replace( + "\r\n", "\n" + ) + + def __repr__(self) -> str: + exc_str = repr(self.exception) if self.exception else "okay" + return f"<{type(self).__name__} {exc_str}>" + + +class CliRunner: + """The CLI runner provides functionality to invoke a Click command line + script for unittesting purposes in a isolated environment. This only + works in single-threaded systems without any concurrency as it changes the + global interpreter state. + + :param charset: the character set for the input and output data. + :param env: a dictionary with environment variables for overriding. + :param echo_stdin: if this is set to `True`, then reading from stdin writes + to stdout. This is useful for showing examples in + some circumstances. Note that regular prompts + will automatically echo the input. + :param mix_stderr: if this is set to `False`, then stdout and stderr are + preserved as independent streams. This is useful for + Unix-philosophy apps that have predictable stdout and + noisy stderr, such that each may be measured + independently + """ + + def __init__( + self, + charset: str = "utf-8", + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + echo_stdin: bool = False, + mix_stderr: bool = True, + ) -> None: + self.charset = charset + self.env = env or {} + self.echo_stdin = echo_stdin + self.mix_stderr = mix_stderr + + def get_default_prog_name(self, cli: "BaseCommand") -> str: + """Given a command object it will return the default program name + for it. The default is the `name` attribute or ``"root"`` if not + set. + """ + return cli.name or "root" + + def make_env( + self, overrides: t.Optional[t.Mapping[str, t.Optional[str]]] = None + ) -> t.Mapping[str, t.Optional[str]]: + """Returns the environment overrides for invoking a script.""" + rv = dict(self.env) + if overrides: + rv.update(overrides) + return rv + + @contextlib.contextmanager + def isolation( + self, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + color: bool = False, + ) -> t.Iterator[t.Tuple[io.BytesIO, t.Optional[io.BytesIO]]]: + """A context manager that sets up the isolation for invoking of a + command line tool. This sets up stdin with the given input data + and `os.environ` with the overrides from the given dictionary. + This also rebinds some internals in Click to be mocked (like the + prompt functionality). + + This is automatically done in the :meth:`invoke` method. + + :param input: the input stream to put into sys.stdin. + :param env: the environment overrides as dictionary. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + ``stderr`` is opened with ``errors="backslashreplace"`` + instead of the default ``"strict"``. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + """ + bytes_input = make_input_stream(input, self.charset) + echo_input = None + + old_stdin = sys.stdin + old_stdout = sys.stdout + old_stderr = sys.stderr + old_forced_width = formatting.FORCED_WIDTH + formatting.FORCED_WIDTH = 80 + + env = self.make_env(env) + + bytes_output = io.BytesIO() + + if self.echo_stdin: + bytes_input = echo_input = t.cast( + t.BinaryIO, EchoingStdin(bytes_input, bytes_output) + ) + + sys.stdin = text_input = _NamedTextIOWrapper( + bytes_input, encoding=self.charset, name="", mode="r" + ) + + if self.echo_stdin: + # Force unbuffered reads, otherwise TextIOWrapper reads a + # large chunk which is echoed early. + text_input._CHUNK_SIZE = 1 # type: ignore + + sys.stdout = _NamedTextIOWrapper( + bytes_output, encoding=self.charset, name="", mode="w" + ) + + bytes_error = None + if self.mix_stderr: + sys.stderr = sys.stdout + else: + bytes_error = io.BytesIO() + sys.stderr = _NamedTextIOWrapper( + bytes_error, + encoding=self.charset, + name="", + mode="w", + errors="backslashreplace", + ) + + @_pause_echo(echo_input) # type: ignore + def visible_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(prompt or "") + val = text_input.readline().rstrip("\r\n") + sys.stdout.write(f"{val}\n") + sys.stdout.flush() + return val + + @_pause_echo(echo_input) # type: ignore + def hidden_input(prompt: t.Optional[str] = None) -> str: + sys.stdout.write(f"{prompt or ''}\n") + sys.stdout.flush() + return text_input.readline().rstrip("\r\n") + + @_pause_echo(echo_input) # type: ignore + def _getchar(echo: bool) -> str: + char = sys.stdin.read(1) + + if echo: + sys.stdout.write(char) + + sys.stdout.flush() + return char + + default_color = color + + def should_strip_ansi( + stream: t.Optional[t.IO] = None, color: t.Optional[bool] = None + ) -> bool: + if color is None: + return not default_color + return not color + + old_visible_prompt_func = termui.visible_prompt_func + old_hidden_prompt_func = termui.hidden_prompt_func + old__getchar_func = termui._getchar + old_should_strip_ansi = utils.should_strip_ansi # type: ignore + termui.visible_prompt_func = visible_input + termui.hidden_prompt_func = hidden_input + termui._getchar = _getchar + utils.should_strip_ansi = should_strip_ansi # type: ignore + + old_env = {} + try: + for key, value in env.items(): + old_env[key] = os.environ.get(key) + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + yield (bytes_output, bytes_error) + finally: + for key, value in old_env.items(): + if value is None: + try: + del os.environ[key] + except Exception: + pass + else: + os.environ[key] = value + sys.stdout = old_stdout + sys.stderr = old_stderr + sys.stdin = old_stdin + termui.visible_prompt_func = old_visible_prompt_func + termui.hidden_prompt_func = old_hidden_prompt_func + termui._getchar = old__getchar_func + utils.should_strip_ansi = old_should_strip_ansi # type: ignore + formatting.FORCED_WIDTH = old_forced_width + + def invoke( + self, + cli: "BaseCommand", + args: t.Optional[t.Union[str, t.Sequence[str]]] = None, + input: t.Optional[t.Union[str, bytes, t.IO]] = None, + env: t.Optional[t.Mapping[str, t.Optional[str]]] = None, + catch_exceptions: bool = True, + color: bool = False, + **extra: t.Any, + ) -> Result: + """Invokes a command in an isolated environment. The arguments are + forwarded directly to the command line script, the `extra` keyword + arguments are passed to the :meth:`~clickpkg.Command.main` function of + the command. + + This returns a :class:`Result` object. + + :param cli: the command to invoke + :param args: the arguments to invoke. It may be given as an iterable + or a string. When given as string it will be interpreted + as a Unix shell command. More details at + :func:`shlex.split`. + :param input: the input data for `sys.stdin`. + :param env: the environment overrides. + :param catch_exceptions: Whether to catch any other exceptions than + ``SystemExit``. + :param extra: the keyword arguments to pass to :meth:`main`. + :param color: whether the output should contain color codes. The + application can still override this explicitly. + + .. versionchanged:: 8.0 + The result object has the ``return_value`` attribute with + the value returned from the invoked command. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionchanged:: 3.0 + Added the ``catch_exceptions`` parameter. + + .. versionchanged:: 3.0 + The result object has the ``exc_info`` attribute with the + traceback if available. + """ + exc_info = None + with self.isolation(input=input, env=env, color=color) as outstreams: + return_value = None + exception: t.Optional[BaseException] = None + exit_code = 0 + + if isinstance(args, str): + args = shlex.split(args) + + try: + prog_name = extra.pop("prog_name") + except KeyError: + prog_name = self.get_default_prog_name(cli) + + try: + return_value = cli.main(args=args or (), prog_name=prog_name, **extra) + except SystemExit as e: + exc_info = sys.exc_info() + e_code = t.cast(t.Optional[t.Union[int, t.Any]], e.code) + + if e_code is None: + e_code = 0 + + if e_code != 0: + exception = e + + if not isinstance(e_code, int): + sys.stdout.write(str(e_code)) + sys.stdout.write("\n") + e_code = 1 + + exit_code = e_code + + except Exception as e: + if not catch_exceptions: + raise + exception = e + exit_code = 1 + exc_info = sys.exc_info() + finally: + sys.stdout.flush() + stdout = outstreams[0].getvalue() + if self.mix_stderr: + stderr = None + else: + stderr = outstreams[1].getvalue() # type: ignore + + return Result( + runner=self, + stdout_bytes=stdout, + stderr_bytes=stderr, + return_value=return_value, + exit_code=exit_code, + exception=exception, + exc_info=exc_info, # type: ignore + ) + + @contextlib.contextmanager + def isolated_filesystem( + self, temp_dir: t.Optional[t.Union[str, os.PathLike]] = None + ) -> t.Iterator[str]: + """A context manager that creates a temporary directory and + changes the current working directory to it. This isolates tests + that affect the contents of the CWD to prevent them from + interfering with each other. + + :param temp_dir: Create the temporary directory under this + directory. If given, the created directory is not removed + when exiting. + + .. versionchanged:: 8.0 + Added the ``temp_dir`` parameter. + """ + cwd = os.getcwd() + dt = tempfile.mkdtemp(dir=temp_dir) # type: ignore[type-var] + os.chdir(dt) + + try: + yield t.cast(str, dt) + finally: + os.chdir(cwd) + + if temp_dir is None: + try: + shutil.rmtree(dt) + except OSError: # noqa: B014 + pass diff --git a/.vcrunch/Lib/site-packages/click/types.py b/.vcrunch/Lib/site-packages/click/types.py new file mode 100644 index 0000000..b45ee53 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/types.py @@ -0,0 +1,1073 @@ +import os +import stat +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 get_filesystem_encoding +from ._compat import open_stream +from .exceptions import BadParameter +from .utils import LazyFile +from .utils import safecall + +if t.TYPE_CHECKING: + import typing_extensions as te + from .core import Context + from .core import Parameter + from .shell_completion import CompletionItem + + +class ParamType: + """Represents the type of a parameter. Validates and converts values + from the command line or Python into the correct type. + + To implement a custom type, subclass and implement at least the + following: + + - The :attr:`name` class attribute must be set. + - Calling an instance of the type with ``None`` must return + ``None``. This is already implemented by default. + - :meth:`convert` must convert string values to the correct type. + - :meth:`convert` must accept values that are already the correct + type. + - It must be able to convert a value if the ``ctx`` and ``param`` + arguments are ``None``. This can occur when converting prompt + input. + """ + + is_composite: t.ClassVar[bool] = False + arity: t.ClassVar[int] = 1 + + #: the descriptive name of this type + name: str + + #: if a list of this type is expected and the value is pulled from a + #: string environment variable, this is what splits it up. `None` + #: means any whitespace. For all parameters the general rule is that + #: whitespace splits them up. The exception are paths and files which + #: are split by ``os.path.pathsep`` by default (":" on Unix and ";" on + #: Windows). + envvar_list_splitter: t.ClassVar[t.Optional[str]] = None + + def to_info_dict(self) -> t.Dict[str, t.Any]: + """Gather information that could be useful for a tool generating + user-facing documentation. + + Use :meth:`click.Context.to_info_dict` to traverse the entire + CLI structure. + + .. versionadded:: 8.0 + """ + # The class name without the "ParamType" suffix. + param_type = type(self).__name__.partition("ParamType")[0] + param_type = param_type.partition("ParameterType")[0] + + # Custom subclasses might not remember to set a name. + if hasattr(self, "name"): + name = self.name + else: + name = param_type + + return {"param_type": param_type, "name": name} + + def __call__( + self, + value: t.Any, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> t.Any: + if value is not None: + return self.convert(value, param, ctx) + + def get_metavar(self, param: "Parameter") -> t.Optional[str]: + """Returns the metavar default for this param if it provides one.""" + + def get_missing_message(self, param: "Parameter") -> t.Optional[str]: + """Optionally might return extra information about a missing + parameter. + + .. versionadded:: 2.0 + """ + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + """Convert the value to the correct type. This is not called if + the value is ``None`` (the missing value). + + This must accept string values from the command line, as well as + values that are already the correct type. It may also convert + other compatible types. + + The ``param`` and ``ctx`` arguments may be ``None`` in certain + situations, such as when converting prompt input. + + If the value cannot be converted, call :meth:`fail` with a + descriptive message. + + :param value: The value to convert. + :param param: The parameter that is using this type to convert + its value. May be ``None``. + :param ctx: The current context that arrived at this value. May + be ``None``. + """ + return value + + def split_envvar_value(self, rv: str) -> t.Sequence[str]: + """Given a value from an environment variable this splits it up + into small chunks depending on the defined envvar list splitter. + + If the splitter is set to `None`, which means that whitespace splits, + then leading and trailing whitespace is ignored. Otherwise, leading + and trailing splitters usually lead to empty items being included. + """ + return (rv or "").split(self.envvar_list_splitter) + + def fail( + self, + message: str, + param: t.Optional["Parameter"] = None, + ctx: t.Optional["Context"] = None, + ) -> "t.NoReturn": + """Helper method to fail with an invalid value message.""" + raise BadParameter(message, ctx=ctx, param=param) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a list of + :class:`~click.shell_completion.CompletionItem` objects for the + incomplete value. Most types do not provide completions, but + some do, and this allows custom types to provide custom + completions as well. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + return [] + + +class CompositeParamType(ParamType): + is_composite = True + + @property + def arity(self) -> int: # type: ignore + raise NotImplementedError() + + +class FuncParamType(ParamType): + def __init__(self, func: t.Callable[[t.Any], t.Any]) -> None: + self.name = func.__name__ + self.func = func + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["func"] = self.func + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self.func(value) + except ValueError: + try: + value = str(value) + except UnicodeError: + value = value.decode("utf-8", "replace") + + self.fail(value, param, ctx) + + +class UnprocessedParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + return value + + def __repr__(self) -> str: + return "UNPROCESSED" + + +class StringParamType(ParamType): + name = "text" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, bytes): + enc = _get_argv_encoding() + try: + value = value.decode(enc) + except UnicodeError: + fs_enc = get_filesystem_encoding() + if fs_enc != enc: + try: + value = value.decode(fs_enc) + except UnicodeError: + value = value.decode("utf-8", "replace") + else: + value = value.decode("utf-8", "replace") + return value + return str(value) + + def __repr__(self) -> str: + return "STRING" + + +class Choice(ParamType): + """The choice type allows a value to be checked against a fixed set + of supported values. All of these values have to be strings. + + You should only pass a list or tuple of choices. Other iterables + (like generators) may lead to surprising results. + + The resulting value will always be one of the originally passed choices + regardless of ``case_sensitive`` or any ``ctx.token_normalize_func`` + being specified. + + See :ref:`choice-opts` for an example. + + :param case_sensitive: Set to false to make choices case + insensitive. Defaults to true. + """ + + name = "choice" + + def __init__(self, choices: t.Sequence[str], case_sensitive: bool = True) -> None: + self.choices = choices + self.case_sensitive = case_sensitive + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["choices"] = self.choices + info_dict["case_sensitive"] = self.case_sensitive + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + choices_str = "|".join(self.choices) + + # Use curly braces to indicate a required argument. + if param.required and param.param_type_name == "argument": + return f"{{{choices_str}}}" + + # Use square braces to indicate an option or optional argument. + return f"[{choices_str}]" + + def get_missing_message(self, param: "Parameter") -> str: + return _("Choose from:\n\t{choices}").format(choices=",\n\t".join(self.choices)) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + # Match through normalization and case sensitivity + # first do token_normalize_func, then lowercase + # preserve original `value` to produce an accurate message in + # `self.fail` + normed_value = value + normed_choices = {choice: choice for choice in self.choices} + + if ctx is not None and ctx.token_normalize_func is not None: + normed_value = ctx.token_normalize_func(value) + normed_choices = { + ctx.token_normalize_func(normed_choice): original + for normed_choice, original in normed_choices.items() + } + + if not self.case_sensitive: + normed_value = normed_value.casefold() + normed_choices = { + normed_choice.casefold(): original + for normed_choice, original in normed_choices.items() + } + + if normed_value in normed_choices: + return normed_choices[normed_value] + + choices_str = ", ".join(map(repr, self.choices)) + self.fail( + ngettext( + "{value!r} is not {choice}.", + "{value!r} is not one of {choices}.", + len(self.choices), + ).format(value=value, choice=choices_str, choices=choices_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return f"Choice({list(self.choices)})" + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Complete choices that start with the incomplete value. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + str_choices = map(str, self.choices) + + if self.case_sensitive: + matched = (c for c in str_choices if c.startswith(incomplete)) + else: + incomplete = incomplete.lower() + matched = (c for c in str_choices if c.lower().startswith(incomplete)) + + return [CompletionItem(c) for c in matched] + + +class DateTime(ParamType): + """The DateTime type converts date strings into `datetime` objects. + + The format strings which are checked are configurable, but default to some + common (non-timezone aware) ISO 8601 formats. + + When specifying *DateTime* formats, you should only pass a list or a tuple. + Other iterables, like generators, may lead to surprising results. + + The format strings are processed using ``datetime.strptime``, and this + consequently defines the format strings which are allowed. + + Parsing is tried using each format, in order, and the first format which + parses successfully is used. + + :param formats: A list or tuple of date format strings, in the order in + which they should be tried. Defaults to + ``'%Y-%m-%d'``, ``'%Y-%m-%dT%H:%M:%S'``, + ``'%Y-%m-%d %H:%M:%S'``. + """ + + name = "datetime" + + def __init__(self, formats: t.Optional[t.Sequence[str]] = None): + self.formats = formats or ["%Y-%m-%d", "%Y-%m-%dT%H:%M:%S", "%Y-%m-%d %H:%M:%S"] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["formats"] = self.formats + return info_dict + + def get_metavar(self, param: "Parameter") -> str: + return f"[{'|'.join(self.formats)}]" + + def _try_to_convert_date(self, value: t.Any, format: str) -> t.Optional[datetime]: + try: + return datetime.strptime(value, format) + except ValueError: + return None + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if isinstance(value, datetime): + return value + + for format in self.formats: + converted = self._try_to_convert_date(value, format) + + if converted is not None: + return converted + + formats_str = ", ".join(map(repr, self.formats)) + self.fail( + ngettext( + "{value!r} does not match the format {format}.", + "{value!r} does not match the formats {formats}.", + len(self.formats), + ).format(value=value, format=formats_str, formats=formats_str), + param, + ctx, + ) + + def __repr__(self) -> str: + return "DateTime" + + +class _NumberParamTypeBase(ParamType): + _number_class: t.ClassVar[t.Type] + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + return self._number_class(value) + except ValueError: + self.fail( + _("{value!r} is not a valid {number_type}.").format( + value=value, number_type=self.name + ), + param, + ctx, + ) + + +class _NumberRangeBase(_NumberParamTypeBase): + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + self.min = min + self.max = max + self.min_open = min_open + self.max_open = max_open + self.clamp = clamp + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + min=self.min, + max=self.max, + min_open=self.min_open, + max_open=self.max_open, + clamp=self.clamp, + ) + return info_dict + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import operator + + rv = super().convert(value, param, ctx) + lt_min: bool = self.min is not None and ( + operator.le if self.min_open else operator.lt + )(rv, self.min) + gt_max: bool = self.max is not None and ( + operator.ge if self.max_open else operator.gt + )(rv, self.max) + + if self.clamp: + if lt_min: + return self._clamp(self.min, 1, self.min_open) # type: ignore + + if gt_max: + return self._clamp(self.max, -1, self.max_open) # type: ignore + + if lt_min or gt_max: + self.fail( + _("{value} is not in the range {range}.").format( + value=rv, range=self._describe_range() + ), + param, + ctx, + ) + + return rv + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + """Find the valid value to clamp to bound in the given + direction. + + :param bound: The boundary value. + :param dir: 1 or -1 indicating the direction to move. + :param open: If true, the range does not include the bound. + """ + raise NotImplementedError + + def _describe_range(self) -> str: + """Describe the range for use in help text.""" + if self.min is None: + op = "<" if self.max_open else "<=" + return f"x{op}{self.max}" + + if self.max is None: + op = ">" if self.min_open else ">=" + return f"x{op}{self.min}" + + lop = "<" if self.min_open else "<=" + rop = "<" if self.max_open else "<=" + return f"{self.min}{lop}x{rop}{self.max}" + + def __repr__(self) -> str: + clamp = " clamped" if self.clamp else "" + return f"<{type(self).__name__} {self._describe_range()}{clamp}>" + + +class IntParamType(_NumberParamTypeBase): + name = "integer" + _number_class = int + + def __repr__(self) -> str: + return "INT" + + +class IntRange(_NumberRangeBase, IntParamType): + """Restrict an :data:`click.INT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "integer range" + + def _clamp( # type: ignore + self, bound: int, dir: "te.Literal[1, -1]", open: bool + ) -> int: + if not open: + return bound + + return bound + dir + + +class FloatParamType(_NumberParamTypeBase): + name = "float" + _number_class = float + + def __repr__(self) -> str: + return "FLOAT" + + +class FloatRange(_NumberRangeBase, FloatParamType): + """Restrict a :data:`click.FLOAT` value to a range of accepted + values. See :ref:`ranges`. + + If ``min`` or ``max`` are not passed, any value is accepted in that + direction. If ``min_open`` or ``max_open`` are enabled, the + corresponding boundary is not included in the range. + + If ``clamp`` is enabled, a value outside the range is clamped to the + boundary instead of failing. This is not supported if either + boundary is marked ``open``. + + .. versionchanged:: 8.0 + Added the ``min_open`` and ``max_open`` parameters. + """ + + name = "float range" + + def __init__( + self, + min: t.Optional[float] = None, + max: t.Optional[float] = None, + min_open: bool = False, + max_open: bool = False, + clamp: bool = False, + ) -> None: + super().__init__( + min=min, max=max, min_open=min_open, max_open=max_open, clamp=clamp + ) + + if (min_open or max_open) and clamp: + raise TypeError("Clamping is not supported for open bounds.") + + def _clamp(self, bound: float, dir: "te.Literal[1, -1]", open: bool) -> float: + if not open: + return bound + + # Could use Python 3.9's math.nextafter here, but clamping an + # open float range doesn't seem to be particularly useful. It's + # left up to the user to write a callback to do it if needed. + raise RuntimeError("Clamping is not supported for open bounds.") + + +class BoolParamType(ParamType): + name = "boolean" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + if value in {False, True}: + return bool(value) + + norm = value.strip().lower() + + if norm in {"1", "true", "t", "yes", "y", "on"}: + return True + + if norm in {"0", "false", "f", "no", "n", "off"}: + return False + + self.fail( + _("{value!r} is not a valid boolean.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "BOOL" + + +class UUIDParameterType(ParamType): + name = "uuid" + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + import uuid + + if isinstance(value, uuid.UUID): + return value + + value = value.strip() + + try: + return uuid.UUID(value) + except ValueError: + self.fail( + _("{value!r} is not a valid UUID.").format(value=value), param, ctx + ) + + def __repr__(self) -> str: + return "UUID" + + +class File(ParamType): + """Declares a parameter to be a file for reading or writing. The file + is automatically closed once the context tears down (after the command + finished working). + + Files can be opened for reading or writing. The special value ``-`` + indicates stdin or stdout depending on the mode. + + By default, the file is opened for reading text data, but it can also be + opened in binary mode or for writing. The encoding parameter can be used + to force a specific encoding. + + The `lazy` flag controls if the file should be opened immediately or upon + first IO. The default is to be non-lazy for standard input and output + streams as well as files opened for reading, `lazy` otherwise. When opening a + file lazily for reading, it is still opened temporarily for validation, but + will not be held open until first IO. lazy is mainly useful when opening + for writing to avoid creating the file until it is needed. + + Starting with Click 2.0, files can also be opened atomically in which + case all writes go into a separate file in the same folder and upon + completion the file will be moved over to the original location. This + is useful if a file regularly read by other users is modified. + + See :ref:`file-args` for more information. + """ + + name = "filename" + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: t.Optional[bool] = None, + atomic: bool = False, + ) -> None: + self.mode = mode + self.encoding = encoding + self.errors = errors + self.lazy = lazy + self.atomic = atomic + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update(mode=self.mode, encoding=self.encoding) + return info_dict + + def resolve_lazy_flag(self, value: t.Any) -> bool: + if self.lazy is not None: + return self.lazy + if value == "-": + return False + elif "w" in self.mode: + return True + return False + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + try: + if hasattr(value, "read") or hasattr(value, "write"): + return value + + lazy = self.resolve_lazy_flag(value) + + if lazy: + f: t.IO = t.cast( + t.IO, + LazyFile( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ), + ) + + if ctx is not None: + ctx.call_on_close(f.close_intelligently) # type: ignore + + return f + + f, should_close = open_stream( + value, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + + # If a context is provided, we automatically close the file + # at the end of the context execution (or flush out). If a + # context does not exist, it's the caller's responsibility to + # properly close the file. This for instance happens when the + # type is used with prompts. + if ctx is not None: + if should_close: + ctx.call_on_close(safecall(f.close)) + else: + ctx.call_on_close(safecall(f.flush)) + + return f + except OSError as e: # noqa: B014 + self.fail(f"'{os.fsdecode(value)}': {e.strerror}", param, ctx) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide file path completions. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + return [CompletionItem(incomplete, type="file")] + + +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 ``type=pathlib.Path``. + + .. versionchanged:: 6.0 + Added the ``allow_dash`` parameter. + """ + + envvar_list_splitter = os.path.pathsep + + def __init__( + self, + exists: bool = False, + file_okay: bool = True, + dir_okay: bool = True, + writable: bool = False, + readable: bool = True, + resolve_path: bool = False, + allow_dash: bool = False, + path_type: t.Optional[t.Type] = 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 = _("file") + elif self.dir_okay and not self.file_okay: + self.name = _("directory") + else: + self.name = _("path") + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict.update( + exists=self.exists, + file_okay=self.file_okay, + dir_okay=self.dir_okay, + writable=self.writable, + readable=self.readable, + allow_dash=self.allow_dash, + ) + return info_dict + + def coerce_path_result(self, rv: t.Any) -> t.Any: + if self.type is not None and not isinstance(rv, self.type): + if self.type is str: + rv = os.fsdecode(rv) + elif self.type is bytes: + rv = os.fsencode(rv) + else: + rv = self.type(rv) + + return rv + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + rv = value + + is_dash = self.file_okay and self.allow_dash and rv in (b"-", "-") + + if not is_dash: + if self.resolve_path: + # os.path.realpath doesn't resolve symlinks on Windows + # until Python 3.8. Use pathlib for now. + import pathlib + + rv = os.fsdecode(pathlib.Path(rv).resolve()) + + try: + st = os.stat(rv) + except OSError: + if not self.exists: + return self.coerce_path_result(rv) + self.fail( + _("{name} {filename!r} does not exist.").format( + name=self.name.title(), filename=os.fsdecode(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=os.fsdecode(value) + ), + param, + ctx, + ) + if not self.dir_okay and stat.S_ISDIR(st.st_mode): + self.fail( + _("{name} '{filename}' is a directory.").format( + name=self.name.title(), filename=os.fsdecode(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=os.fsdecode(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=os.fsdecode(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=os.fsdecode(value) + ), + param, + ctx, + ) + + return self.coerce_path_result(rv) + + def shell_complete( + self, ctx: "Context", param: "Parameter", incomplete: str + ) -> t.List["CompletionItem"]: + """Return a special completion marker that tells the completion + system to use the shell to provide path completions for only + directories or any paths. + + :param ctx: Invocation context for this command. + :param param: The parameter that is requesting completion. + :param incomplete: Value being completed. May be empty. + + .. versionadded:: 8.0 + """ + from click.shell_completion import CompletionItem + + type = "dir" if self.dir_okay and not self.file_okay else "file" + return [CompletionItem(incomplete, type=type)] + + +class Tuple(CompositeParamType): + """The default behavior of Click is to apply a type on a value directly. + This works well in most cases, except for when `nargs` is set to a fixed + count and different types should be used for different items. In this + case the :class:`Tuple` type can be used. This type can only be used + if `nargs` is set to a fixed number. + + For more information see :ref:`tuple-type`. + + This can be selected by using a Python tuple literal as a type. + + :param types: a list of types that should be used for the tuple items. + """ + + def __init__(self, types: t.Sequence[t.Union[t.Type, ParamType]]) -> None: + self.types = [convert_type(ty) for ty in types] + + def to_info_dict(self) -> t.Dict[str, t.Any]: + info_dict = super().to_info_dict() + info_dict["types"] = [t.to_info_dict() for t in self.types] + return info_dict + + @property + def name(self) -> str: # type: ignore + return f"<{' '.join(ty.name for ty in self.types)}>" + + @property + def arity(self) -> int: # type: ignore + return len(self.types) + + def convert( + self, value: t.Any, param: t.Optional["Parameter"], ctx: t.Optional["Context"] + ) -> t.Any: + len_type = len(self.types) + len_value = len(value) + + if len_value != len_type: + self.fail( + ngettext( + "{len_type} values are required, but {len_value} was given.", + "{len_type} values are required, but {len_value} were given.", + len_value, + ).format(len_type=len_type, len_value=len_value), + param=param, + ctx=ctx, + ) + + return tuple(ty(x, param, ctx) for ty, x in zip(self.types, value)) + + +def convert_type(ty: t.Optional[t.Any], default: t.Optional[t.Any] = None) -> ParamType: + """Find the most appropriate :class:`ParamType` for the given Python + type. If the type isn't provided, it can be inferred from a default + value. + """ + guessed_type = False + + if ty is None and default is not None: + if isinstance(default, (tuple, list)): + # If the default is empty, ty will remain None and will + # return STRING. + if default: + item = default[0] + + # A tuple of tuples needs to detect the inner types. + # Can't call convert recursively because that would + # incorrectly unwind the tuple to a single type. + if isinstance(item, (tuple, list)): + ty = tuple(map(type, item)) + else: + ty = type(item) + else: + ty = type(default) + + guessed_type = True + + if isinstance(ty, tuple): + return Tuple(ty) + + if isinstance(ty, ParamType): + return ty + + if ty is str or ty is None: + return STRING + + if ty is int: + return INT + + if ty is float: + return FLOAT + + if ty is bool: + return BOOL + + if guessed_type: + return STRING + + if __debug__: + try: + if issubclass(ty, ParamType): + raise AssertionError( + f"Attempted to use an uninstantiated parameter type ({ty})." + ) + except TypeError: + # ty is an instance (correct), so issubclass fails. + pass + + return FuncParamType(ty) + + +#: A dummy parameter type that just does nothing. From a user's +#: perspective this appears to just be the same as `STRING` but +#: internally no string conversion takes place if the input was bytes. +#: This is usually useful when working with file paths as they can +#: appear in bytes and unicode. +#: +#: For path related uses the :class:`Path` type is a better choice but +#: there are situations where an unprocessed type is useful which is why +#: it is is provided. +#: +#: .. versionadded:: 4.0 +UNPROCESSED = UnprocessedParamType() + +#: A unicode string parameter type which is the implicit default. This +#: can also be selected by using ``str`` as type. +STRING = StringParamType() + +#: An integer parameter. This can also be selected by using ``int`` as +#: type. +INT = IntParamType() + +#: A floating point value parameter. This can also be selected by using +#: ``float`` as type. +FLOAT = FloatParamType() + +#: A boolean parameter. This is the default for boolean flags. This can +#: also be selected by using ``bool`` as a type. +BOOL = BoolParamType() + +#: A UUID parameter. +UUID = UUIDParameterType() diff --git a/.vcrunch/Lib/site-packages/click/utils.py b/.vcrunch/Lib/site-packages/click/utils.py new file mode 100644 index 0000000..8283788 --- /dev/null +++ b/.vcrunch/Lib/site-packages/click/utils.py @@ -0,0 +1,580 @@ +import os +import re +import sys +import typing as t +from functools import update_wrapper +from types import ModuleType + +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 get_filesystem_encoding +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 + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def _posixify(name: str) -> str: + return "-".join(name.split()).lower() + + +def safecall(func: F) -> F: + """Wraps a function so that it swallows exceptions.""" + + def wrapper(*args, **kwargs): # type: ignore + try: + return func(*args, **kwargs) + except Exception: + pass + + return update_wrapper(t.cast(F, wrapper), func) + + +def make_str(value: t.Any) -> str: + """Converts a value into a valid string.""" + if isinstance(value, bytes): + try: + return value.decode(get_filesystem_encoding()) + 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, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + atomic: bool = False, + ): + self.name = filename + self.mode = mode + self.encoding = encoding + self.errors = errors + self.atomic = atomic + self._f: t.Optional[t.IO] + + if filename == "-": + 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: + """Opens the file if it's not yet open. This call might fail with + a :exc:`FileError`. Not handling this error will produce an error + that Click shows. + """ + if self._f is not None: + return self._f + try: + rv, self.should_close = open_stream( + self.name, self.mode, self.encoding, self.errors, atomic=self.atomic + ) + except OSError as e: # noqa: E402 + from .exceptions import FileError + + raise FileError(self.name, hint=e.strerror) from e + self._f = rv + return rv + + def close(self) -> None: + """Closes the underlying file, no matter what.""" + if self._f is not None: + self._f.close() + + def close_intelligently(self) -> None: + """This function only closes the file if it was opened by the lazy + file wrapper. For instance this will never close stdin. + """ + if self.should_close: + self.close() + + def __enter__(self) -> "LazyFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close_intelligently() + + def __iter__(self) -> t.Iterator[t.AnyStr]: + self.open() + return iter(self._f) # type: ignore + + +class KeepOpenFile: + def __init__(self, file: t.IO) -> None: + self._file = file + + def __getattr__(self, name: str) -> t.Any: + return getattr(self._file, name) + + def __enter__(self) -> "KeepOpenFile": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + pass + + def __repr__(self) -> str: + return repr(self._file) + + def __iter__(self) -> t.Iterator[t.AnyStr]: + return iter(self._file) + + +def echo( + message: t.Optional[t.Any] = None, + file: t.Optional[t.IO[t.Any]] = None, + nl: bool = True, + err: bool = False, + color: t.Optional[bool] = None, +) -> None: + """Print a message and newline to stdout or a file. This should be + used instead of :func:`print` because it provides better support + for different data, files, and environments. + + Compared to :func:`print`, this does the following: + + - Ensures that the output encoding is not misconfigured on Linux. + - Supports Unicode in the Windows console. + - Supports writing to binary outputs, and supports writing bytes + to text outputs. + - Supports colors and styles on Windows. + - Removes ANSI color and style codes if the output does not look + like an interactive terminal. + - Always flushes the output. + + :param message: The string or bytes to output. Other objects are + converted to strings. + :param file: The file to write to. Defaults to ``stdout``. + :param err: Write to ``stderr`` instead of ``stdout``. + :param nl: Print a newline after the message. Enabled by default. + :param color: Force showing or hiding colors and other styles. By + default Click will remove color if the output does not look like + an interactive terminal. + + .. versionchanged:: 6.0 + Support Unicode output on the Windows console. Click does not + modify ``sys.stdout``, so ``sys.stdout.write()`` and ``print()`` + will still not support Unicode. + + .. versionchanged:: 4.0 + Added the ``color`` parameter. + + .. versionadded:: 3.0 + Added the ``err`` parameter. + + .. versionchanged:: 2.0 + Support colors on Windows if colorama is installed. + """ + if file is None: + if err: + file = _default_text_stderr() + else: + file = _default_text_stdout() + + # Convert non bytes/text into the native string type. + if message is not None and not isinstance(message, (str, bytes, bytearray)): + out: t.Optional[t.Union[str, bytes]] = str(message) + else: + out = message + + if nl: + out = out or "" + if isinstance(out, str): + out += "\n" + else: + out += b"\n" + + if not out: + file.flush() + return + + # If there is a message and the value looks like bytes, we manually + # need to find the binary stream and write the message in there. + # This is done separately so that most stream types will work as you + # would expect. Eg: you can write to StringIO for other cases. + if isinstance(out, (bytes, bytearray)): + binary_file = _find_binary_writer(file) + + if binary_file is not None: + file.flush() + binary_file.write(out) + binary_file.flush() + return + + # ANSI style code support. For no message or bytes, nothing happens. + # When outputting to a file instead of a terminal, strip codes. + else: + color = resolve_color_default(color) + + if should_strip_ansi(file, color): + out = strip_ansi(out) + elif WIN: + if auto_wrap_for_ansi is not None: + file = auto_wrap_for_ansi(file) # type: ignore + elif not color: + out = strip_ansi(out) + + file.write(out) # type: ignore + file.flush() + + +def get_binary_stream(name: "te.Literal['stdin', 'stdout', 'stderr']") -> t.BinaryIO: + """Returns a system stream for byte processing. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + """ + opener = binary_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener() + + +def get_text_stream( + name: "te.Literal['stdin', 'stdout', 'stderr']", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", +) -> t.TextIO: + """Returns a system stream for text processing. This usually returns + a wrapped stream around a binary stream returned from + :func:`get_binary_stream` but it also can take shortcuts for already + correctly configured streams. + + :param name: the name of the stream to open. Valid names are ``'stdin'``, + ``'stdout'`` and ``'stderr'`` + :param encoding: overrides the detected default encoding. + :param errors: overrides the default error mode. + """ + opener = text_streams.get(name) + if opener is None: + raise TypeError(f"Unknown standard stream '{name}'") + return opener(encoding, errors) + + +def open_file( + filename: str, + mode: str = "r", + encoding: t.Optional[str] = None, + errors: t.Optional[str] = "strict", + lazy: bool = False, + atomic: bool = False, +) -> t.IO: + """Open a file, with extra behavior to handle ``'-'`` to indicate + a standard stream, lazy open on write, and atomic write. Similar to + the behavior of the :class:`~click.File` param type. + + If ``'-'`` is given to open ``stdout`` or ``stdin``, the stream is + wrapped so that using it in a context manager will not close it. + This makes it possible to use the function without accidentally + closing a standard stream: + + .. code-block:: python + + with open_file(filename) as f: + ... + + :param filename: The name of the file to open, or ``'-'`` for + ``stdin``/``stdout``. + :param mode: The mode in which to open the file. + :param encoding: The encoding to decode or encode a file opened in + text mode. + :param errors: The error handling mode. + :param lazy: Wait to open the file until it is accessed. For read + mode, the file is temporarily opened to raise access errors + early, then closed until it is read again. + :param atomic: Write to a temporary file and replace the given file + on close. + + .. versionadded:: 3.0 + """ + if lazy: + return t.cast(t.IO, 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, KeepOpenFile(f)) + + return f + + +def format_filename( + filename: t.Union[str, bytes, os.PathLike], shorten: bool = False +) -> str: + """Formats a filename for user display. The main purpose of this + function is to ensure that the filename can be displayed at all. This + will decode the filename to unicode if necessary in a way that it will + not fail. Optionally, it can shorten the filename to not include the + full path to the filename. + + :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) + + return os.fsdecode(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 affect 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) -> None: + self.wrapped = wrapped + + def flush(self) -> None: + try: + self.wrapped.flush() + except OSError as e: + import errno + + if e.errno != errno.EPIPE: + raise + + def __getattr__(self, attr: str) -> t.Any: + return getattr(self.wrapped, attr) + + +def _detect_program_name( + path: t.Optional[str] = None, _main: t.Optional[ModuleType] = None +) -> str: + """Determine the command used to run the program, for use in help + text. If a file or entry point was executed, the file name is + returned. If ``python -m`` was used to execute a module or package, + ``python -m name`` is returned. + + This doesn't try to be too precise, the goal is to give a concise + name for help text. Files are only shown as their name without the + path. ``python`` is only shown for modules, and the full path to + ``sys.executable`` is not shown. + + :param path: The Python file being executed. Python puts this in + ``sys.argv[0]``, which is used by default. + :param _main: The ``__main__`` module. This should only be passed + during internal testing. + + .. versionadded:: 8.0 + Based on command args detection in the Werkzeug reloader. + + :meta private: + """ + if _main is None: + _main = sys.modules["__main__"] + + if not path: + path = sys.argv[0] + + # The value of __package__ indicates how Python was called. It may + # not exist if a setuptools script is installed as an egg. It may be + # set incorrectly for entry points created with pip on Windows. + if getattr(_main, "__package__", None) is None or ( + os.name == "nt" + and _main.__package__ == "" + and not os.path.exists(path) + and os.path.exists(f"{path}.exe") + ): + # Executed a file, like "python app.py". + return os.path.basename(path) + + # Executed a module, like "python -m example". + # Rewritten by Python from "-m script" to "/path/to/script.py". + # Need to look at main module to determine how it was executed. + py_module = t.cast(str, _main.__package__) + name = os.path.splitext(os.path.basename(path))[0] + + # A submodule like "example.cli". + if name != "__main__": + py_module = f"{py_module}.{name}" + + return f"python -m {py_module.lstrip('.')}" + + +def _expand_args( + args: t.Iterable[str], + *, + user: bool = True, + env: bool = True, + glob_recursive: bool = True, +) -> t.List[str]: + """Simulate Unix shell expansion with Python functions. + + See :func:`glob.glob`, :func:`os.path.expanduser`, and + :func:`os.path.expandvars`. + + This is intended for use on Windows, where the shell does not do any + expansion. It may not exactly match what a Unix shell would do. + + :param args: List of command line arguments to expand. + :param user: Expand user home directory. + :param env: Expand environment variables. + :param glob_recursive: ``**`` matches directories recursively. + + .. versionchanged:: 8.1 + Invalid glob patterns are treated as empty expansions rather + than raising an error. + + .. versionadded:: 8.0 + + :meta private: + """ + from glob import glob + + out = [] + + for arg in args: + if user: + arg = os.path.expanduser(arg) + + if env: + arg = os.path.expandvars(arg) + + try: + matches = glob(arg, recursive=glob_recursive) + except re.error: + matches = [] + + if not matches: + out.append(arg) + else: + out.extend(matches) + + return out diff --git a/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/INSTALLER b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/INSTALLER new file mode 100644 index 0000000..a1b589e --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/INSTALLER @@ -0,0 +1 @@ +pip diff --git a/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/LICENSE.txt b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/LICENSE.txt new file mode 100644 index 0000000..3105888 --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/LICENSE.txt @@ -0,0 +1,27 @@ +Copyright (c) 2010 Jonathan Hartley +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* 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. + +* Neither the name of the copyright holders, nor those 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/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/METADATA b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/METADATA new file mode 100644 index 0000000..cd93935 --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/METADATA @@ -0,0 +1,411 @@ +Metadata-Version: 2.1 +Name: colorama +Version: 0.4.5 +Summary: Cross-platform colored terminal text. +Home-page: https://github.com/tartley/colorama +Author: Jonathan Hartley +Author-email: tartley@tartley.com +Maintainer: Arnon Yaari +License: BSD +Keywords: color colour terminal text ansi windows crossplatform xplatform +Classifier: Development Status :: 5 - Production/Stable +Classifier: Environment :: Console +Classifier: Intended Audience :: Developers +Classifier: License :: OSI Approved :: BSD License +Classifier: Operating System :: OS Independent +Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3 +Classifier: Programming Language :: Python :: 3.5 +Classifier: Programming Language :: Python :: 3.6 +Classifier: Programming Language :: Python :: 3.7 +Classifier: Programming Language :: Python :: 3.8 +Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 +Classifier: Programming Language :: Python :: Implementation :: CPython +Classifier: Programming Language :: Python :: Implementation :: PyPy +Classifier: Topic :: Terminals +Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.* +License-File: LICENSE.txt + +.. image:: https://img.shields.io/pypi/v/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Latest Version + +.. image:: https://img.shields.io/pypi/pyversions/colorama.svg + :target: https://pypi.org/project/colorama/ + :alt: Supported Python versions + +.. image:: https://github.com/tartley/colorama/actions/workflows/test.yml/badge.svg + :target: https://github.com/tartley/colorama/actions/workflows/test.yml + :alt: Build Status + +Colorama +======== + +Makes ANSI escape character sequences (for producing colored terminal text and +cursor positioning) work under MS Windows. + +.. |donate| image:: https://www.paypalobjects.com/en_US/i/btn/btn_donate_SM.gif + :target: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=2MZ9D2GMLYCUJ&item_name=Colorama¤cy_code=USD + :alt: Donate with Paypal + +`PyPI for releases `_ | +`Github for source `_ | +`Colorama for enterprise on Tidelift `_ + +If you find Colorama useful, please |donate| to the authors. Thank you! + + +Installation +------------ + +Tested on CPython 2.7, 3.5, 3.6, 3.7, 3.8, 3.9 and 3.10 and Pypy 2.7 and 3.6. + +No requirements other than the standard library. + +.. code-block:: bash + + pip install colorama + # or + conda install -c anaconda colorama + + +Description +----------- + +ANSI escape character sequences have long been used to produce colored terminal +text and cursor positioning on Unix and Macs. Colorama makes this work on +Windows, too, by wrapping ``stdout``, stripping ANSI sequences it finds (which +would appear as gobbledygook in the output), and converting them into the +appropriate win32 calls to modify the state of the terminal. On other platforms, +Colorama does nothing. + +This has the upshot of providing a simple cross-platform API for printing +colored terminal text from Python, and has the happy side-effect that existing +applications or libraries which use ANSI sequences to produce colored output on +Linux or Macs can now also work on Windows, simply by calling +``colorama.init()``. + +An alternative approach is to install ``ansi.sys`` on Windows machines, which +provides the same behaviour for all applications running in terminals. Colorama +is intended for situations where that isn't easy (e.g., maybe your app doesn't +have an installer.) + +Demo scripts in the source code repository print some colored text using +ANSI sequences. Compare their output under Gnome-terminal's built in ANSI +handling, versus on Windows Command-Prompt using Colorama: + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/ubuntu-demo.png + :width: 661 + :height: 357 + :alt: ANSI sequences on Ubuntu under gnome-terminal. + +.. image:: https://github.com/tartley/colorama/raw/master/screenshots/windows-demo.png + :width: 668 + :height: 325 + :alt: Same ANSI sequences on Windows, using Colorama. + +These screenshots show that, on Windows, Colorama does not support ANSI 'dim +text'; it looks the same as 'normal text'. + +Usage +----- + +Initialisation +.............. + +Applications should initialise Colorama using: + +.. code-block:: python + + from colorama import init + init() + +On Windows, calling ``init()`` will filter ANSI escape sequences out of any +text sent to ``stdout`` or ``stderr``, and replace them with equivalent Win32 +calls. + +On other platforms, calling ``init()`` has no effect (unless you request other +optional functionality, see "Init Keyword Args" below; or if output +is redirected). By design, this permits applications to call ``init()`` +unconditionally on all platforms, after which ANSI output should just work. + +On all platforms, if output is redirected, ANSI escape sequences are completely +stripped out. + +To stop using Colorama before your program exits, simply call ``deinit()``. +This will restore ``stdout`` and ``stderr`` to their original values, so that +Colorama is disabled. To resume using Colorama again, call ``reinit()``; it is +cheaper than calling ``init()`` again (but does the same thing). + + +Colored Output +.............. + +Cross-platform printing of colored text can then be done using Colorama's +constant shorthand for ANSI escape sequences. These are deliberately +rudimentary, see below. + +.. code-block:: python + + from colorama import Fore, Back, Style + print(Fore.RED + 'some red text') + print(Back.GREEN + 'and with a green background') + print(Style.DIM + 'and in dim text') + print(Style.RESET_ALL) + print('back to normal now') + +...or simply by manually printing ANSI sequences from your own code: + +.. code-block:: python + + print('\033[31m' + 'some red text') + print('\033[39m') # and reset to default color + +...or, Colorama can be used in conjunction with existing ANSI libraries +such as the venerable `Termcolor `_ +the fabulous `Blessings `_, +or the incredible `_Rich `_. + +If you wish Colorama's Fore, Back and Style constants were more capable, +then consider using one of the above highly capable libraries to generate +colors, etc, and use Colorama just for its primary purpose: to convert +those ANSI sequences to also work on Windows: + +.. code-block:: python + + from colorama import init + from termcolor import colored + + # use Colorama to make Termcolor work on Windows too + init() + + # then use Termcolor for all colored text output + print(colored('Hello, World!', 'green', 'on_red')) + +Available formatting constants are:: + + Fore: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Back: BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE, RESET. + Style: DIM, NORMAL, BRIGHT, RESET_ALL + +``Style.RESET_ALL`` resets foreground, background, and brightness. Colorama will +perform this reset automatically on program exit. + +These are fairly well supported, but not part of the standard:: + + Fore: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + Back: LIGHTBLACK_EX, LIGHTRED_EX, LIGHTGREEN_EX, LIGHTYELLOW_EX, LIGHTBLUE_EX, LIGHTMAGENTA_EX, LIGHTCYAN_EX, LIGHTWHITE_EX + + +Cursor Positioning +.................. + +ANSI codes to reposition the cursor are supported. See ``demos/demo06.py`` for +an example of how to generate them. + + +Init Keyword Args +................. + +``init()`` accepts some ``**kwargs`` to override default behaviour. + +init(autoreset=False): + If you find yourself repeatedly sending reset sequences to turn off color + changes at the end of every print, then ``init(autoreset=True)`` will + automate that: + + .. code-block:: python + + from colorama import init + init(autoreset=True) + print(Fore.RED + 'some red text') + print('automatically back to default color again') + +init(strip=None): + Pass ``True`` or ``False`` to override whether ANSI codes should be + stripped from the output. The default behaviour is to strip if on Windows + or if output is redirected (not a tty). + +init(convert=None): + Pass ``True`` or ``False`` to override whether to convert ANSI codes in the + output into win32 calls. The default behaviour is to convert if on Windows + and output is to a tty (terminal). + +init(wrap=True): + On Windows, Colorama works by replacing ``sys.stdout`` and ``sys.stderr`` + with proxy objects, which override the ``.write()`` method to do their work. + If this wrapping causes you problems, then this can be disabled by passing + ``init(wrap=False)``. The default behaviour is to wrap if ``autoreset`` or + ``strip`` or ``convert`` are True. + + When wrapping is disabled, colored printing on non-Windows platforms will + continue to work as normal. To do cross-platform colored output, you can + use Colorama's ``AnsiToWin32`` proxy directly: + + .. code-block:: python + + import sys + from colorama import init, AnsiToWin32 + init(wrap=False) + stream = AnsiToWin32(sys.stderr).stream + + # Python 2 + print >>stream, Fore.BLUE + 'blue text on stderr' + + # Python 3 + print(Fore.BLUE + 'blue text on stderr', file=stream) + + +Recognised ANSI Sequences +......................... + +ANSI sequences generally take the form:: + + ESC [ ; ... + +Where ```` is an integer, and ```` is a single letter. Zero or +more params are passed to a ````. If no params are passed, it is +generally synonymous with passing a single zero. No spaces exist in the +sequence; they have been inserted here simply to read more easily. + +The only ANSI sequences that Colorama converts into win32 calls are:: + + ESC [ 0 m # reset all (colors and brightness) + ESC [ 1 m # bright + ESC [ 2 m # dim (looks same as normal brightness) + ESC [ 22 m # normal brightness + + # FOREGROUND: + ESC [ 30 m # black + ESC [ 31 m # red + ESC [ 32 m # green + ESC [ 33 m # yellow + ESC [ 34 m # blue + ESC [ 35 m # magenta + ESC [ 36 m # cyan + ESC [ 37 m # white + ESC [ 39 m # reset + + # BACKGROUND + ESC [ 40 m # black + ESC [ 41 m # red + ESC [ 42 m # green + ESC [ 43 m # yellow + ESC [ 44 m # blue + ESC [ 45 m # magenta + ESC [ 46 m # cyan + ESC [ 47 m # white + ESC [ 49 m # reset + + # cursor positioning + ESC [ y;x H # position cursor at x across, y down + ESC [ y;x f # position cursor at x across, y down + ESC [ n A # move cursor n lines up + ESC [ n B # move cursor n lines down + ESC [ n C # move cursor n characters forward + ESC [ n D # move cursor n characters backward + + # clear the screen + ESC [ mode J # clear the screen + + # clear the line + ESC [ mode K # clear the line + +Multiple numeric params to the ``'m'`` command can be combined into a single +sequence:: + + ESC [ 36 ; 45 ; 1 m # bright cyan text on magenta background + +All other ANSI sequences of the form ``ESC [ ; ... `` +are silently stripped from the output on Windows. + +Any other form of ANSI sequence, such as single-character codes or alternative +initial characters, are not recognised or stripped. It would be cool to add +them though. Let me know if it would be useful for you, via the Issues on +GitHub. + + +Status & Known Problems +----------------------- + +I've personally only tested it on Windows XP (CMD, Console2), Ubuntu +(gnome-terminal, xterm), and OS X. + +Some presumably valid ANSI sequences aren't recognised (see details below), +but to my knowledge nobody has yet complained about this. Puzzling. + +See outstanding issues and wish-list: +https://github.com/tartley/colorama/issues + +If anything doesn't work for you, or doesn't do what you expected or hoped for, +I'd love to hear about it on that issues list, would be delighted by patches, +and would be happy to grant commit access to anyone who submits a working patch +or two. + +If you're hacking on the code, see `README-hacking.md`_. + +.. _README-hacking.md: README-hacking.md + + +License +------- + +Copyright Jonathan Hartley & Arnon Yaari, 2013-2020. BSD 3-Clause license; see +LICENSE file. + + +Professional support +-------------------- + +.. |tideliftlogo| image:: https://cdn2.hubspot.net/hubfs/4008838/website/logos/logos_for_download/Tidelift_primary-shorthand-logo.png + :alt: Tidelift + :target: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + +.. list-table:: + :widths: 10 100 + + * - |tideliftlogo| + - Professional support for colorama is available as part of the + `Tidelift Subscription`_. + Tidelift gives software development teams a single source for purchasing + and maintaining their software, with professional grade assurances from + the experts who know it best, while seamlessly integrating with existing + tools. + +.. _Tidelift Subscription: https://tidelift.com/subscription/pkg/pypi-colorama?utm_source=pypi-colorama&utm_medium=referral&utm_campaign=readme + + +Thanks +------ + +* Marc Schlaich (schlamar) for a ``setup.py`` fix for Python2.5. +* Marc Abramowitz, reported & fixed a crash on exit with closed ``stdout``, + providing a solution to issue #7's setuptools/distutils debate, + and other fixes. +* User 'eryksun', for guidance on correctly instantiating ``ctypes.windll``. +* Matthew McCormick for politely pointing out a longstanding crash on non-Win. +* Ben Hoyt, for a magnificent fix under 64-bit Windows. +* Jesse at Empty Square for submitting a fix for examples in the README. +* User 'jamessp', an observant documentation fix for cursor positioning. +* User 'vaal1239', Dave Mckee & Lackner Kristof for a tiny but much-needed Win7 + fix. +* Julien Stuyck, for wisely suggesting Python3 compatible updates to README. +* Daniel Griffith for multiple fabulous patches. +* Oscar Lesta for a valuable fix to stop ANSI chars being sent to non-tty + output. +* Roger Binns, for many suggestions, valuable feedback, & bug reports. +* Tim Golden for thought and much appreciated feedback on the initial idea. +* User 'Zearin' for updates to the README file. +* John Szakmeister for adding support for light colors +* Charles Merriam for adding documentation to demos +* Jurko for a fix on 64-bit Windows CPython2.5 w/o ctypes +* Florian Bruhin for a fix when stdout or stderr are None +* Thomas Weininger for fixing ValueError on Windows +* Remi Rampin for better Github integration and fixes to the README file +* Simeon Visser for closing a file handle using 'with' and updating classifiers + to include Python 3.3 and 3.4 +* Andy Neff for fixing RESET of LIGHT_EX colors. +* Jonathan Hartley for the initial idea and implementation. diff --git a/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/RECORD b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/RECORD new file mode 100644 index 0000000..59f4d9f --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/RECORD @@ -0,0 +1,18 @@ +colorama-0.4.5.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4 +colorama-0.4.5.dist-info/LICENSE.txt,sha256=ysNcAmhuXQSlpxQL-zs25zrtSWZW6JEQLkKIhteTAxg,1491 +colorama-0.4.5.dist-info/METADATA,sha256=Kb6MoYzWBmkPhFCf0SW7a-5Eeyssj-szefJmxokQFSU,15128 +colorama-0.4.5.dist-info/RECORD,, +colorama-0.4.5.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110 +colorama-0.4.5.dist-info/top_level.txt,sha256=_Kx6-Cni2BT1PEATPhrSRxo0d7kSgfBbHf5o7IF1ABw,9 +colorama/__init__.py,sha256=ihDoWQOkapwF7sqQ99AoDoEF3vGYm40OtmgW211cLZw,239 +colorama/__pycache__/__init__.cpython-310.pyc,, +colorama/__pycache__/ansi.cpython-310.pyc,, +colorama/__pycache__/ansitowin32.cpython-310.pyc,, +colorama/__pycache__/initialise.cpython-310.pyc,, +colorama/__pycache__/win32.cpython-310.pyc,, +colorama/__pycache__/winterm.cpython-310.pyc,, +colorama/ansi.py,sha256=Top4EeEuaQdBWdteKMEcGOTeKeF19Q-Wo_6_Cj5kOzQ,2522 +colorama/ansitowin32.py,sha256=gGrO7MVtwc-j1Sq3jKfZpERT1JWmYSOsTVDiTnFbZU4,10830 +colorama/initialise.py,sha256=PprovDNxMTrvoNHFcL2NZjpH2XzDc8BLxLxiErfUl4k,1915 +colorama/win32.py,sha256=bJ8Il9jwaBN5BJ8bmN6FoYZ1QYuMKv2j8fGrXh7TJjw,5404 +colorama/winterm.py,sha256=2y_2b7Zsv34feAsP67mLOVc-Bgq51mdYGo571VprlrM,6438 diff --git a/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/WHEEL b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/WHEEL new file mode 100644 index 0000000..0b18a28 --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/WHEEL @@ -0,0 +1,6 @@ +Wheel-Version: 1.0 +Generator: bdist_wheel (0.37.1) +Root-Is-Purelib: true +Tag: py2-none-any +Tag: py3-none-any + diff --git a/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/top_level.txt b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/top_level.txt new file mode 100644 index 0000000..3fcfb51 --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama-0.4.5.dist-info/top_level.txt @@ -0,0 +1 @@ +colorama diff --git a/.vcrunch/Lib/site-packages/colorama/__init__.py b/.vcrunch/Lib/site-packages/colorama/__init__.py new file mode 100644 index 0000000..9138a8c --- /dev/null +++ b/.vcrunch/Lib/site-packages/colorama/__init__.py @@ -0,0 +1,6 @@ +# Copyright Jonathan Hartley 2013. BSD 3-Clause license, see LICENSE file. +from .initialise import init, deinit, reinit, colorama_text +from .ansi import Fore, Back, Style, Cursor +from .ansitowin32 import AnsiToWin32 + +__version__ = '0.4.5' diff --git a/.vcrunch/Lib/site-packages/colorama/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/colorama/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a85d02ad6ae015b50263f39cbbdacf80dce1be7d GIT binary patch literal 422 zcmYjNy-ve05RMZkO`ArneT57J#Lt2d0*aVW2MR*6ELm=1fkhlwb^??);vskuuS`tr z3Hvx%5!!x^Ki0+{eO56Es0% Gl!o7e?s5bG literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/colorama/__pycache__/ansi.cpython-310.pyc b/.vcrunch/Lib/site-packages/colorama/__pycache__/ansi.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..78e8141316592ae3e60d9532576cba6627bd83da GIT binary patch literal 2983 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/colorama/__pycache__/win32.cpython-310.pyc b/.vcrunch/Lib/site-packages/colorama/__pycache__/win32.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e6b760dcc26d65eb0a7133541408a649ea56323a GIT binary patch literal 3930 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 4) & 7 + self._style = value & (WinStyle.BRIGHT | WinStyle.BRIGHT_BACKGROUND) + + def reset_all(self, on_stderr=None): + self.set_attrs(self._default) + self.set_console(attrs=self._default) + self._light = 0 + + def fore(self, fore=None, light=False, on_stderr=False): + if fore is None: + fore = self._default_fore + self._fore = fore + # Emulate LIGHT_EX with BRIGHT Style + if light: + self._light |= WinStyle.BRIGHT + else: + self._light &= ~WinStyle.BRIGHT + self.set_console(on_stderr=on_stderr) + + def back(self, back=None, light=False, on_stderr=False): + if back is None: + back = self._default_back + self._back = back + # Emulate LIGHT_EX with BRIGHT_BACKGROUND Style + if light: + self._light |= WinStyle.BRIGHT_BACKGROUND + else: + self._light &= ~WinStyle.BRIGHT_BACKGROUND + self.set_console(on_stderr=on_stderr) + + def style(self, style=None, on_stderr=False): + if style is None: + style = self._default_style + self._style = style + self.set_console(on_stderr=on_stderr) + + def set_console(self, attrs=None, on_stderr=False): + if attrs is None: + attrs = self.get_attrs() + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleTextAttribute(handle, attrs) + + def get_position(self, handle): + position = win32.GetConsoleScreenBufferInfo(handle).dwCursorPosition + # Because Windows coordinates are 0-based, + # and win32.SetConsoleCursorPosition expects 1-based. + position.X += 1 + position.Y += 1 + return position + + def set_cursor_position(self, position=None, on_stderr=False): + if position is None: + # I'm not currently tracking the position, so there is no default. + # position = self.get_position() + return + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + win32.SetConsoleCursorPosition(handle, position) + + def cursor_adjust(self, x, y, on_stderr=False): + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + position = self.get_position(handle) + adjusted_position = (position.Y + y, position.X + x) + win32.SetConsoleCursorPosition(handle, adjusted_position, adjust=False) + + def erase_screen(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the screen. + # 1 should clear from the cursor to the beginning of the screen. + # 2 should clear the entire screen, and move cursor to (1,1) + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + # get the number of character cells in the current buffer + cells_in_screen = csbi.dwSize.X * csbi.dwSize.Y + # get number of character cells before current cursor position + cells_before_cursor = csbi.dwSize.X * csbi.dwCursorPosition.Y + csbi.dwCursorPosition.X + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = cells_in_screen - cells_before_cursor + elif mode == 1: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_before_cursor + elif mode == 2: + from_coord = win32.COORD(0, 0) + cells_to_erase = cells_in_screen + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + if mode == 2: + # put the cursor where needed + win32.SetConsoleCursorPosition(handle, (1, 1)) + + def erase_line(self, mode=0, on_stderr=False): + # 0 should clear from the cursor to the end of the line. + # 1 should clear from the cursor to the beginning of the line. + # 2 should clear the entire line. + handle = win32.STDOUT + if on_stderr: + handle = win32.STDERR + csbi = win32.GetConsoleScreenBufferInfo(handle) + if mode == 0: + from_coord = csbi.dwCursorPosition + cells_to_erase = csbi.dwSize.X - csbi.dwCursorPosition.X + elif mode == 1: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwCursorPosition.X + elif mode == 2: + from_coord = win32.COORD(0, csbi.dwCursorPosition.Y) + cells_to_erase = csbi.dwSize.X + else: + # invalid mode + return + # fill the entire screen with blanks + win32.FillConsoleOutputCharacter(handle, ' ', cells_to_erase, from_coord) + # now set the buffer's attributes accordingly + win32.FillConsoleOutputAttribute(handle, self.get_attrs(), cells_to_erase, from_coord) + + def set_title(self, title): + win32.SetConsoleTitle(title) diff --git a/.vcrunch/Lib/site-packages/distutils-precedence.pth b/.vcrunch/Lib/site-packages/distutils-precedence.pth new file mode 100644 index 0000000..6de4198 --- /dev/null +++ b/.vcrunch/Lib/site-packages/distutils-precedence.pth @@ -0,0 +1 @@ +import os; var = 'SETUPTOOLS_USE_DISTUTILS'; enabled = os.environ.get(var, 'stdlib') == 'local'; enabled and __import__('_distutils_hack').add_shim(); diff --git a/.vcrunch/Lib/site-packages/flask/__init__.py b/.vcrunch/Lib/site-packages/flask/__init__.py new file mode 100644 index 0000000..e02531c --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/__init__.py @@ -0,0 +1,71 @@ +from markupsafe import escape +from markupsafe import Markup + +from . import json as json +from .app import Flask as Flask +from .app import Request as Request +from .app import Response as Response +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 signals_available as signals_available +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 + +__version__ = "2.2.2" + + +def __getattr__(name): + if name == "_app_ctx_stack": + import warnings + from .globals import __app_ctx_stack + + warnings.warn( + "'_app_ctx_stack' is deprecated and will be removed in Flask 2.3.", + DeprecationWarning, + stacklevel=2, + ) + return __app_ctx_stack + + if name == "_request_ctx_stack": + import warnings + from .globals import __request_ctx_stack + + warnings.warn( + "'_request_ctx_stack' is deprecated and will be removed in Flask 2.3.", + DeprecationWarning, + stacklevel=2, + ) + return __request_ctx_stack + + raise AttributeError(name) diff --git a/.vcrunch/Lib/site-packages/flask/__main__.py b/.vcrunch/Lib/site-packages/flask/__main__.py new file mode 100644 index 0000000..4e28416 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/__main__.py @@ -0,0 +1,3 @@ +from .cli import main + +main() diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c32c4bc9ac0bc80e099e372a4421eae95da8a8c1 GIT binary patch literal 2380 zcmb`I%Wm676oyHP5@}hsEX$Vfw(QuJ<%{Aty`w1FChek^ED{tg1_A~YIg%I;FP))m zCrCDJw|$VlL?1-kuJQ^63iO;KDN&qNfr{XdkN+GF&z!j^nVTyb@H78>?0++B7=Piz z^v{Ba&*9cCP+$b6G$NCkCb9)=F$*{s*fJN{%qGsud{kfs;sUV49AXF9WiGKRXQCo2 z63@ulsKiRdML8GEvw7lK;4&){mw*@80`VMhg;j{>O}0tA0=&hxh*yEP**5VS@DAG{UI(tT zI`IbZF54yEly9;6rvuTnBEj2JtTN5j!H@18%Y=@g3k} zc1*kve8NtM4}eeEDe)oj89O6x0Jm6+_($bM^YgO+QJWaettch_i{${UpxB z4ZdIQdzyP`I%QSS8uu_|&rUjlXn4`YZ#r*2082fQae5E| zk08+N2@QS?{Y*ru^fJM{EK^};kl`TbBJWZ_7OzL`DiMTA_}K4^7IDD4p~T4Q=s_hB z9|a`p8QGZiV|;NcKKI1P3NMUb&0oys>?1ZmTHe_WBo8) zB_vyXvzsPaKtz?lYd?S3c-Q>TIW(Q2d+n(hrcMu?o=iHhAk-NoHnh(C+Up91^PqAdLqp-(V>#Hls(`M8;-XjVOpa2m zX22L0;1q!4RN+7TFz07C3jW~@RYI9VnMb)mDWfc)R8ST{n9~g`k0>*to$#OvYF^GclUSUsA0H30AUTZlX-=vg$nIj0B|HpVOaRw_GQj`< literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/app.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/app.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8ef87be775663a3cba88888613b5b922cce9ddff GIT binary patch literal 74894 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 UCmiaetTIHYrBLqNQ7rfT7iL#hYXATM literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/blueprints.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/blueprints.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..12e8b9c93b82b055d86b63bbe83baf2c69785421 GIT binary patch literal 24185 zcmd^nYj7M_cHVSP&tM(^h&M@)qFNFq2rFtN>ao&dDN1~ZTCKE@Oj4_OLU}NlZV&?w zX29+NDNKg0wMkpps>s=t9k1=RY%p2dVeB}LHxDOqCHa#|od2mx^&eNVzqXuIekiuH z(n`$to!fo82N;mjYBx@m$(oCMZ{I%man3#G+;h(D*3eKPg@4AsJzIOWo=Sa}h2%dA zg%|Mi7mZZPNjXL%RaSqEvLR)&oW@_XVXbD$8H3N#jqK_`c>sCK$ux4SW;rkUY@@JR zEEgp|fc#*2Q1UtChsr~e&m%uv9yU^LdS#FIJRlSrBdeq3QK=boiWdz$8Cx><%3clMfn~nACmGI%J)jymhw2t z_euGFDNmsMfRqnQc@pIZrTmbTr%;}e^21Wzi}I|LKlf6~+2<5*q@3b)v-}83`<-c& zrrn|I>GBcBIG36|@I9{n{Hzfa9e1g^-e^1ZS{udT^);v3b}LuC>e`y?eGlkJp*q{% zSgSWLBDb&NHl4Lrz1glTd9BsTmAZSivb5f;;aR@oyUljJ={8WvovT%smRb!5`J(T( z*Vk6v_Hv8G%$Y{jzZ8t0Y^=L$9zdPr<8y6v9PBw?sV=o$uj09v*Il1u$}G0ln@%uw zzOv{pwLG`7RQLRL)F2qq_2Dao;d)-nt1MTWPQ&$r!ud+ut$I%DYBM;<{OVeRv#hn6 zZTIbVWzB2VT;Feb!D!;?QoVtJ^i*AJv=*xkcA#OjG00%}d}ZBhRKm6NgMF%erHUB> zI%XMmP~*BM{}oYq0YBeC;-*OLWz#W0?WU6^Wjk5dTFE#AZq~^;`K5wW0B)`FKpy{` zQP5@18A6M^o7Kwz0&v=U%M)m^^T9SM9|JPxjS%d)aO;y9FEnKp~BKt=g`)nkCyl(X{JLzg=zC zT)VY|Ms?q=0nfh8jOSv#9eZ&@zdc8Cm|OViCDKAklR{~=ddUSHfgmb?)^-}sQ-$7|P6TCCPC*(6Dh%r8m1Ag?D8n>tQ@zbH0{A)9Bv-GFkji;phK0lCIfJRZ?98snJa%HMm z*D~FVlUh%C)2K66GAyG7e$v83i)=S5Egq2;S(ecPKWUNf8Y=@g+0Q^&0}7FHuAP@R z3fI|x5&7cQVAv+>;GLTWIA03*&&>yUe|^zutyb&Jpg_6>g)Y_K4y+$=Ld^r_moJpAgqc_C zix>QQ+kJEmWKq57`WJ-a9@F&Tm)16dT%}TP*4vfJBLME(NV2(XI%{RKgJ#ai8Cfg* zn;tVqjA3iq=p58!6tk~V1SYV&^@bbdB4!!nHKVLi*hT+HKqRDB@biBk2~Y;{w{Cd* zyM{OAm|H;SN@~k=fWWS?1-5Y0SR$bqO%hh>n$fjDT+D+I3=kpSPI(Wvv)%M{;~Ge1 zW#C%IvAWiklsDJTbu&vwJ%xAjj&;-cw($!j%G63>rAWeE8T?ktVR=aYn%_#jmqDKy z^qpP;JL+cY=#OuKm?%iHo$s8mm)!zd zi;|__U2vCeoaH=fqID!Qsjjy{yKP{duoUfrxAgEP0@E0t@omzy;sks$|AFzCP*srA zEZZo}4h!)H)(XTM_B^(KeJ#i~)ZYSlQrK7#BvB_c>^+2BkX~!8$<_!4tBxb$fOD5! zAp2o9>&^0&BTOD;Qeq-x{y1}*xV_J@_zaSt#Lp-ALeVk~8Ci1}vV4#&sFj%QvUavO7Cj*s=)2gA` zXb0&N&5giXY_%F5H%O4ingqGmgk?e==1u_>)kVyfgHB9DrX;hW%wfrY3P~R=vc>)FApZ34keyuj-}jTNY6g+E}71Nle=MEH_Ch5Ju4$l zzF#XRi=LoS>XyCGbYFm0bOr_5s5`n1nr;)|od=x5?q26X_Yl_mUd-enX9jwT zjkg|#hJP3k?-PhwXV&?gym`NVi>sV<9&wJK{|DUZe478Av(BR!TPYg1^O)oguRMr( zJudk}$irT8O zWBR=FjI{dPE)X99#79Di&pKa_wnq{WAKd|Q&iSIWD(wRCF+hAQgm}z(PTD@6fOvEV z#N*EM(&`DU_0#T?SpO$6zZaYnvdT|M?bE1z8nq{#Q&RhRseJ~u&!G0S^Pn91zFnS6AUI-? za0G=~tI>eM3nh^XtJhkGDlb}Q3o^)yRNO~Bms+QzrIim6Rc%AlY}$*i7IkOwzGEFb9)Q51xWkaq;pO$ZQq<9Z zqIn3my6jdlHfZE^h(P=0w!Q9So{rxyQr?wrpcLzHNlvTo)nOx2+?6~}pe#H@ z5REbnFM$&ofh-^o8(2g<6MbOYT(nBy$0v?hds|QoyX-b)hPpBF6sa^Jo_m%$oW?oV zwdWu*=N1ym<$_Fo6~|T_kFZ=+TyS1ev@o|;^{T6)oXpu&b0~V%>B)`Bq-4KY#~BC2 z#*-v8A&dcvl3T4U%YdoTX#FTwbVA^Dp7Pov?(fhC&Qziu9|3hh1!!z&$O{XRuCTCB z!XU90)c1V5(Zbo!m6cjp@LDY#qpR)Z1vTM_yf`+!j!FRw$Hl{4y;h-x!1dAysTQAH?3k0a6`32^Px#6|96hQpTM?*$dy69nB$Q;V?3VMG#^A3P#=1 z6U0z^-sV)~g;K0dMIhCHsz9bw_o?uxQ>e^xgJellO228!DGP&8C_srAlo|AbrcEW* zQ%@^^*l;a-VWDTmh>Vwc%uWp6c3N1jCWgOUy%H}}74J&_a>`r4R_0q^72B2yI|gLd z#`&9sR&yN}XZa&~ov6e2bQiy_mgQ=zInySYR%^7T)UiB0OQB6B{c#>W4*9D_xDEX^ zvCi=k0sTksU@5C!Z8=2S`TiK^==E$gQ36U|j7OlsZxZMRxoHp)x)Wp)zeEgxQ-Pb) zV4;^2V}RTM=l0{F)D^o?2#F!6Rq9#67>nF6LeyA}kSmZ#uyc2?4@~flv#@>11HXb zx*xG}EmmQT;>;En63kXMXw$B_UK@568zzW#Vf`fUy00N<*cf9w)JCXUELH1`Bet*3 z!-DBh;qceoT79XW*b%GMrm$?Wzd_iC!lhKQuRvHs+SEXE7hPv=&OTZ?T6$dfeKJB6 zSh^zDg@sz94i&1GM zg0EqJ`P^&s5WCVrXz0XxLANT|&?pqgo^Lf>%tO`7zrMJW;VMCl2Q z9zNHi-*Z=66n7vcQOMBp$&!6)-G?ot-ieusyfjyBx4pRqSrV9@uhg*!718Pzwh;-N z$Al6u?9rG?JTBb)2i=*)wNi4CXDCqP!HecB+eNhEJC4?#!8#~ly~CTap-}3F=m8dG zQuOzTuvH!rmXu>0A-~>S!UM+ zWtpHXn9+o?Xs3lw3)GdFmo@fYM04*9lb4vhjO12Y4gGai^clZ5j|YE(pBgp{LD8@a z*w=~_IC!Cn>-eB=8litp~ucGeHSbvU*jU*^0BwjGoqoD?S!lGy` z(0zkFk#ZAi{mNG$UV{e+EU!g!kcS*n!lXvaVf2rAn#;M%`~@WK)OC1L;CV^I*OKYx z9phbkhs~}5bN4uR+jZk-!PU9f#FJum;W?>fE`qbetCAC6%Y*gQwOlucnt^TsX-=Nz zWp7&Zvl;JA^yK{wCN#);WhQ@<$x$SoM`n2Fnt@WaA<8!;9z{ORsZhmdN;5VDuve`? z8kS}YLB?N)wOrXz3ty#&@I^W+Wj*5+3C5tapqcB4cU62--VFP^fFvkZw2tD>78Q@M z`Ly3q#U-PcS&f`fz) z!RU;|3{rbQvP*L4+(Cm`0406T*UPb8s906H2q483#^H5R1XjF?51 zVfv^xV83xT@Cs}Ik?sSj3$3={R;d^BNCZ*0L7W1*uMSN-bMfFq^9!1T0(|;Uo9)I% zsqhsl+x|LE5me9BhVhR;bVf#(Be7}ci0!s(C1_hXeaR^wle4Lc^$c51B+xC;CmrH? zq_m*aasHH3dMFk32Obb{S_wAZ1cKcpc;(OduB6nsp!9?XEj`Q*SE1Y(MN7-l_ z6zP5o#q4Y-rfLMzM@$8imD;jfyA(QhY25OcUFQH6-=DxcbZA&`w1J>*n>o`c{Dt*V z=iUTS^?N(8Xe;WWFG^xgMCfY-8PXSAXz;y;4lA?s-_C~4ZCaAFwQ0NYsGku?Yi9Av zQ0*sf1oPS#F6*yBZ!<}uxducIiI;iCytuv!dSPBUn}Pn&v=MsBcR0p16h->6*#iR5EHRgt3J(AJWEYOn2E(Px zLtF&dtTzVfcib}C*wCA)>&o@4)aZ}iYDYjQ+ zk)^__p9#`L=X9I0!H5d|6zkq##$*Yq=NK{I{Y1E&N9KFfGwRq}{&B7#Z;$j-#zD z-LzOMT0xUJ>9D8}DBzxErxqSfZDzr~+yp2_W2#1ir zZb4l(JKsGe@g&$by+J3vF(n$ccQE#noRao;AWoU7Lqy`}Mw*HULonJezJzejtuM+M z3qpYc2*)+g!^sN(09DS?3?c#3fxSdU#z>q@B*26;Vp<`hiHTWDZQgA$5rPCs1PLSC zxx=YwLk|yhrei#8Zzk~;JN7p*@CtsS08n{CL_rR_+z@373fC5dbk}4Y0+lV`BwhVe zbQp0~%yFCHU5{Wv?Io;;Mo-Cp#of3HCZxAh#0`De5g6*j)ss~Wg}iL}#QM^MA*NT@ zeiPQ2?c%=o+`Yp%@G6scMsaO>c*!dj_jrZ!?Bx z9xUUhKt0|9lRA=!hr~fc+sJn;f*7l{uSWbUH=HvjlHoR`osDbcRM9^w6gm7@=l>6I z)vmcE2A-SdwY22Zn=tdBWOYTw>{^I(Nh8Jv5iws+f#(`4X&fI;@b4yE=$i)U|3N3y zG@LA=WvtEArL=d{8Q4rgLCw9FM!k703pF)QNKT=fL0ar)kq*8$z&+E>ykjgG&X6;F zBS)xP*_)};;Oy6p!PGUtksgg}xlJ0N&?f>E_G}uJflXrz?ZNp5Zl;4Powc@qGZqb>RrsOX|YY~Yx-W?BneYQKgav#bJ<(*tNFphKb zOyy9!b-#n2oaw!(?l|ZTdE~~N{l`+xN!{|T?s!;NOh8&@Ue$wM#vJ2Vsyn*%0H|Y( zabMpsEnn8cgzvM7knBi1h%u$Hoj_Ei6X^9P#+7~m%I|Nv z*H!|Wq>>hbqp@bHLK^RfbX7Jh8o>gK`dOz4n^#0e9n+rqz?kX48WB2vW;zGOz#3Uu z;%z4?Nv9CcrvsY|>IYd|cc4W87YG*DD)gb%EOhW9p-Z*nQ9UX2*j#)x5k+`0cw%c1(~J?s)i zJei)uPmUM}NKU;qj2Y4f2!DxVKm~!)rj(>#G%xdrVfLV!Ft}0zg9m1TF%ZG%n(8ez zc%l?K=sNxcc^JTy%`mF*zZq$u*;D~`sm{?m%`<+j6lXzFR})=Z zbQYG2Ov7OKcz7!2_ZnJnvD-mpvZ<_<`zVXUJ38+O&oui+Ew98{S=*G8g zD)dmxyglwmiH+pAV%VHwD$`fAM5gWH3jQ3pq2`i_ft2@z+pRj&15h)Pc$b-GC z76R_Mc;g2LwD*Aq`kre)zL?9DWjzhgLy!wy&%XCCr$CoOxyU%`uwITf0r0uDp%(i| zvt2-4pCg1xZE8mG`P@vXGt! zVgZs(>1}YB;v|&F@?{xLWYQT!tYA(V``|0hF%g zKgtaZnq!%1aVEflU|Bz~J|4`EnS;hK0^9L6|9?De4dcCnSwJmQ^Z@Jd2;2>*M=uKU zl)2B$-7cgHux{ZwE@fE%E9r)aP_ZrCKG+|Mk%|tyh!&vdau3-Pu}%w&PhZ$($}2dK zA~+WoXz%2yZqxFn+eqPLGQDX$wN^|#pT={9h{Nra+DgBZddGOjd?)>mwUpsyt{XYB zXJ-HmE!Ww4HDL!;sv(JtSm50OWfSFTJ#o&436la<2mIl&7Vy*y=4gwYlYlRt?t9Fk zFi_y0PeM0T8eM3H(wre7>M7ehkIh8AeKIGP_blIfdPeX08P(4xagg;ec@SDG4ru_R zRdf^Q<4p^??_IP2%Y6oa;My|$TN!oFLd=YOsE9#CZ_M#?#~Rhu zMW=fF&q&u}XlA99!z;R2k^QjqaLoIY7)r3<5Xe02bu@ki1K^Ut|R(t{Ezj92pfesGl3{X70Bx6SIcGBUS98Zrj5s66teV@0ql%>9nKz33kt{)&2 zL2UIDui4JWXG0Ye1Z&n@&>xrNw=n>gkEl@PB|1sLbnt7?;ei5gPJ`#cfRqqM@yr?4EZ z!N0VUhOH4)EGHuHE^^r*zfy0mR1r;gB^Xc?>?=05il%p=BY?xN1P?ekKBRe z=lwkD^X0{s?~!y3GB z!_gfOrqIv(9Pqv&@WKNLno06u_O&Y$^xnhkpqA>7ky?6~8%NWhVty#rroib1Ofa_p zAIa_#F?wgV=lurTG>8?&-n`#LKFDyQ3AW}5_YevZ7DBf249V^vAk&#kkivHUML;p> z?ciSCw*kQWEhYk8`jIYv8+Egq;)cPc5+N^rH^^Oi)S)|5o%(*oXXjE1PJgP4`OuGs zV4^Yq6>+MaI-MHOuDt4H5{>Yx-SjvGASM~T*{H`&kWl(@t6tqr!8pdg{vqDjRc}-6 z?#iv|KUTWw;a6%z{b}ci;#d(ty^KF{o~3#?V*jW}@Q3GG18OLD;ahKMzI7+POM!~X z@KbQE-v!CN#!mhbY41+DmFlF2Z{a;1LH53ib=pda&l-MoWgppuMmlSCer~6Iq}OhU zOK=FgfqyU&$p_zt`?g!dZQeMbB#e_3S7K;#M5N^v1bNn%Y}}&t8K(m?NYc)tPm;Tu zB*MW{orW_vbuo3*+=6l9CO(YOBX7Qj342d7VK9XE3rs}QiKWfoMcpzMM)YO47!qnu zIAiK6;m~80MW%~+oG?W@4kP_UI~M5Dk7zq%I{_`SN80kO3~Y3_t#sm}CZ(Otd$7n; zMFv0q^=VQGuh6KA4n0?BXaz&`13p8Oz;3RJ&vK=9MR4>L9{C7Ve>7_ZMd*&gVR>qk z_u<%;_f`B*kIkZ&N5sysK6h~53~%4|zk+ji9hbW#0-1Jw`zixR<#R`HEb9@{62Vac ziTaXsbhkw}QWtGHzdVyz`JQF?^tThlg_elV0|a%WM&i->j6C82^on!9i?OHc3~(#~ z!aMc@Nq`!@7^>9qatnc<@jgh)v9dfJPON8A%9?-Yo$)o$sYIs^r#er?n%HjZv~zzz z^ZPP~{|b{=nQ*s6VM(%EmgV%2Q#%<;T`$`1aJ$u_Kw?s)w=JNakqBzdHh&&(w{xhr1& zU?*O-`=;)U8oiF%9+^aqunq#`=Hs{O?usT2@3W)pXStAfN7pZDbS0Eqy$FfL+_?wm zcgNU7KM3!lD{(Yia3+axIuuh#zZdR`zi;lu-ws#cXF=dy)r-%Lrl0#{Xxh?fN;s{F zogMT2RCt=~3*uKaq6R`lC6BTFI`w`U)967LMF@Eb|AzLq&fnRIE^##D;tjv*xErPz z)1)^>*p~6O60s}JG~B`o6$4zu>7xbif~GszxTpw;1QZi1A{XHFOTod?tI(!*x6O($ zq3GO#kMSnFTGzD_3D+W^<8xJXvWN2#9THI_Tt_u5;epiiJgSoam?*(7HInK)AMYBX zF9{|_etdS)7Xl*PQf*u6k+8!`hvE*_ilrFnevcgzffICKBw6|0yX2{tvNRIM(nsvQ z_*ZzOVlzgzkN?|IulsT^*CoQ-w>RveHLgpfxke)Q*f~0u`0*QM?e8B%phynDwGt#9D{XH}y} z{m;IZ*FV`>{(HTaM|Mss8qKF#L7_vgVD$DMqYEXf5RV|DY8x#k8_ybNX4CWY^GaJf zqZ}(=;9TaIe36OE2Um5K!Bs}D@z zF6Sw}B~4D_78AdSkVD)9uAR0wcA#gPRLUAfXL;Vs_t?Ck}{*J4mIea9-8NYut(XN#%x z;Rkuoh?iM6qZh}UWb!*~HW4*D4}+_2L?fy)n*AOdX;?4Gr+RfWS}eRhOuoZ}E_Lsp zGZ|#^FPMxn`Ik)S==J^xNsxarx-J={@u6bjQ{KPkQ&rYbwvYOjy zL^o=MF<03{xbuGGHt_RL;`CdsSVAz5)R?+PKOfuiTx#z0 ze8MpEGPm0TZ;EC73W++b$5=E1bsJf=%^$>PQn8k^k9z-(3;Z9Lkh7~@gFw6J18=^B zq6K-;yYUrEU#_-!_p|MPL{iTA;n%9YEb9iC&@dwO9t@rT$=6@3ochv>r(St^{-wkP zHg1ISb*Cck5THUU}jKPa0>HDMAw@>8?C|QZDeG;Rmg^Hz0|Y zCsl*(&q&DSi5IC6d`W3T8ZISidE|Wfxocfb;x60K4mzbG;9ieDORbv;<^LzNm3RX0 zKQlMM}e?9TRYu!Zli!ceIOr6mxNLon{mw=YmtmMI9x&aJ0 zm;qlm2%#^7?X zT$Hx##?bO`c{pizS9uqnXB#8SyUV-fp3@jz-c#Nq=efq-<(tYk$$7r9Z~5l(%{U+M z3XT2C2g(QJe6VqF`Iho6a$dywt>s&dj9*x~P1R9ysB!!99pyWW%o7=J*xPkEY$U z|8eiM_XK+OkoUvhk9eQ*p1zzdf2a41_bl#BqU@CS9Lhe2_CA5q4|`|4Pvgla@#L&G zjVIH56P`SRzmIw|-t*pPuJG-TdFQ0{t55n*d0#khe$h~W>_54g0fn2>@;m~RD<(1enjsNTYQWnh_cAflnpNfv135w;KRqQczCLHd}Za-rJBFO zFOI(bY_%Tvo?D-Ht4$a0Z`5lt7H&<(#hvrr`PORFb6d)l&+tl9<93{{RGJutN+m8- zD$6ZzwZZdZrE+1l+DM+{D(G&lQh7V0_M$g(xOV!)HV*kr-jF*r zet-Jo;A9xT5XMGuKc097#4tqin2whC?gs-a$wcD3!zOiy2C+vd59?#;Q(g;RDW99;ii zBeRh;GSPvsh|)&Td@Y0b725{hHk7<=IQhFv?v8wUVAE)4Uo$;>Bl}8r%~(TQsIz-p zA4hc`$M-~QPt-5^APHB`u3K*gVYONF-EgrUxS(Gj$Cf)^2W^ClJ_scU-IZ1l)aM$0 z!NpH6HPxF^C}|6{q)2xGiOx@nu_U$B0H#b0;V^E-7TPEe_B1rrH^U}MW%0X*Gkg#y z3z>H2r2&jB=2T|VY#TplUI6V2^?{WN^&tHcv~QM<#KuK=o2Jp5&`4Z(xKR(nT5Eab zkrJ*0zUE*ix|82p;dhczOAj|%wQ3`H1Se@}Me>V|oP>0!h2W~?)kau{RB(k^dj}-I zc%~ye7UjoEE||g{iw;eadB!-h!HQq2&#%k4)mjh`wa{%f{Svxes41T^ildWXuAY~( zXteX*`D!g}sdcnBG}iZ`qhp8Nxz*6EwN@LR3%Lh2Z#3L`=&sen#TK4a)xzpBWKodx z=$bJZ-F6@D2IGCb>XwT>e!5z3;A>NA*zvKH9ch<(KYQQKkChJ`iZhCg8|NVRD16n; zyn@W}>a`GZ#<^H+tolK0HT#t6^=?4}=IS$w$P7uc?Jps)S^Q`e?(&{ouQC zDB5|eXcWx6VP4;F7xA}fnD}QK_I2BEuG`o1IX*WH2gd^L4zsLbnj?m7+8>yv^MQHY z%$o1!Up3z|ubI1h>#FoZv(Y;z7X8|JcWu!JvnwGRXfTL}bf7gy zd$=<@+ZpoNS;&Q2bv4iufpS6!ZeCLi=puRS1}*5+MK+m;ij-hPP>6^T@!)eNO9eTf zT%js<=O^76G~DS(xL5@}R|9#K?`g3zsr+zNH7D6Swd$i|Pqf5R+cAq*uGw#Gz zupY#D2&hWEIp2!&;T$wN_%n9qE47yAlO*{UB$>mrrhh2}cN+7t8O~`65yeLeQTO2R zJbnY-D&|eh^DySw8F0Rlf7i?xY$;LW%hMlv8~l~o{IwnhwqZi}7emgWv1Ma^EziDU zV)m?andS&ogtLCgfC4k97P3$PrssT_>MHk|xt0m@Z3}e=py-aat);?-y#RGm&ulo& zlgYC|JX_}Z65oQ7!D&%wY-xZky=L$k>qetq!5h4s!S#@+#;jNLhU9u!t{wDgKl-$5 zz0v8@u=GhMh)}wYQyvO8uA7Ks(pQ_qCm$HQq8d2GE|1_HJ7L7fE}g;l6ebYV_Ad zjqaAdjV3Mcp+f9$xt-e>z}O75O^nhXwFjX1bKYJlpYd)Ib-OQ7qc=xyX}(E_Z9#OZ zw*FkG(W-l~s_Io}OqX(>g0jm|CHDlxl~$!a)ZKC+6@_#m{yS>muH=Jy*f2V zV|}}Jjcp%N6dKWn=<}nIt`G-TK^H}1E?9_0AtYiQN~7Dw4yTcqOHBdHBhrpr+pQgZ~#1##mqXyrCD7xCGy=e~wVO(s$EL7D- zMLxh(`%w)~)WUX_qeXB9zoNkRWukjUNMqD0bL)u-ej_cuql1*F(m@)Wprg!71diE4D1+%d(0j?A&r_|57z4kN7r8PGT@ z)EQ^VLo2a8*Yeim!Rhs8SiK}lUYi4AFW6HQ)n?s`Z8B19lWt?18b8jT_t)22$_wJc zXE-jp?(KL@JbXMQczu(mg*wE;T|C^)1BLl`LEVc#ah?Q4?$tJn?O$3^u`M@F@wsz; zOD23y)s7CoC+%TRQ+2J#VRJd9^hN z1(>-Ch3Pq41N7AJFaLS#0NxCbcp&=W)X$lR5i3Gi9GtZ}?BWnMG^|=sd2O`;gIj2P zWgV7s(_N{Ci-+B+2j4jq8I6LpCj!5!YK!t1($nje$>1n>$En$$ybHDp6ak1vTm~(r zBMUArjf;A-4tsYd8ca{=`qIfz-+{x_JJ<0uUX0CF5ZmlfoQGr3&}RXB`4ARKoS&-( z@?~)j%7Cv0`|x4xfOP$)7d!qXxG-pAsa0>P!)Q8oU`zWd9M7t=yv)u^J&WxPYFk;; z{L}1A$Gz9a@bHTA!KQviqaDAEB7uuT(H?=-V;du85!Nkm@rSbrcfE6goRo4QN3x--mrphB1i@YJ_* zS2JJAd>Njymw63Ts1D;PXb(@bViw`<3jk@SGcX&>CHUOkm*npc%3@R1A&itAXL?wKL=zaF3h(SoRkWz)HtVSCJ@I!n04G%^h4BB ztTihAsMO~xkhv9sbwq@1pT7bswmoV%runtP zP#!Z|Fx5PY_DvuKL=L|)fuF$%h93;MluhwHhroUMTNYeo$}J3B^&(U`FHoT2fFeq6IXM@<7SX!+@$S z!YNpRWZ)dc!&)+=FIIJyg*vE%i(;!5UJ~V1T~?ELpq6-GbK6IMkYHcZ`M= zf;dklE~JzLaybvgG0x+}2j-?~XuI!+{P-AokwT&uUmP&;&+>L76hQMoi{Qo{Z3ECSMrfbmI;Zty>s-K4tdlG$tE7_V`BD4YV=|OgBTVe-<05}3p9t0)+TMZyZ z8|#EGMDRBKnjZvJEvxHI*oN>Oeccf3pL#gPIxsHeSySpJPNr86AS`S2J5w1hbBnh< z)r8Frm(h2V0Sw&Md}6|ghDiD?iekA1YqwE9@1t9whxNp0pQ|rm5M9-3`0W4s3J_2B zT)Lz&99T-LVG9hLJem{0N9s@30C)zIvoaV@C;+AKrUB8cw^pH&V3;?8mb+YS>e0~6 z5z3*~SwYQIF}0d7Ks?y;@Q6vc$%t!JGc^EQVbNaa=6KGkrjdrF2$$+Cl z`?_L6)MhG{$8$uK8)Nh!09#nf}C zhwxY?pm*)$91H)Ti=sVU3N57?SFE}Zw|RaUEl`|!27nbJzUVBDK!$M*Cz9~XhS5BR zdq9dqYs;oyT7tN{YI(+jaWh4r{dx011~!rjTsaH3(%69bYs2D!`)f4!dRf7$&E99I znR_2R zR9fQe@GbRtj`x@^q$N-=i6CVa0K8}d?AQT0!}>B1UEzl%dVdh6z(46d@Kx0YOcQTC zX`EOnSYGIyEy0)2Ea?O)DtAnGWDI~fEdu?`NnFR(J~$BB()gfy4gC}%79x#J<*ReN zMdL^Gr*>gT+iDPpI4iLrkpCuciSIz0Owsg;2NTAndA5zr<2)ylY;iYf{RoN|;4~0t zbj-b`W8^;|I!VnvOtcZMfermm_2T66mV-Ne9Fev*ZcRGcNB zUg6<$IKc0fbNX=Ojv%#aHy@7j0O&p={HR{%S=W;6B4?NIpujI+3;7KCSzs@V?+x!( zd^T>B9lsesRQItdB@88vMRi4ok`9A}bKr7Z29rn#M#2P8Pj>b1@QQN?`Vo~$RU%+X z5HC%1Dv^a%;Em8P8tVqh`j`9~fDy0b01G__qUKN@BcGBS+-6j~6eh^!3GfFTU3mPE z-{8gjD6>J3b*Muj!eAWyumGbRaEj+5{suKNJ4+ga2%nt=#mTE?XXoI&t{|8gCJ%)D zs*Sbkdf+ZrFM{tRte3vutzHE5N7e8d;3h!{}2QV1yj!YW`RYE1q4HFyw7 z*Gr{TA=VbF%?00^oOF+sj&(SBhP)2uPCi&rE+Fyf35+B+Se@&9H1yG$4=)RU@#&og zlHTC$=`56>`gb;}zp?W@z0#z2q>|SqS}_UTcA5^f7VIM&5)FUvAmI?e2{QqJ#x2AO zuNw3*;2UJN=#L^ANPiUa+<7Cj07?AQ##sVHCV@u8oL)uc@tmTTiH9_aR>}- zPi>Q~|9&$%BrihqDJ^y)Se;5!7*vqE842-F`^QuUDL2uhI2j`rVb*7od<$+CmE5L zoJ|O57UpTnCS9o@RNHUCF>ydQnBt_+o=ta>SCg~bMrtMZ3bhYQAZ`o_XDP-F)4ew;3k5oCozH*fZ`#f6+6B{w07D zuuN&g%E$BDTZsDWp$MQ|5`>x|;bf3IESvW72BYli;YeBeqlTi>+-kD{gI>#ASm=~i zo(sd6G)XUecKaxP@-%E=#B}t~&~y-zo9Sa~5RI@kG!D`MI7pUCzyv^55)pgDT!22% zO#FsHCMML7GO{g=3V*~|A*DE%5Qic!ylwZe=O%8Hi~M*v+Ddr0!=;KmwBF$nc+|HW z(OoHdmy$NS&~%6Jn4e;;v{vBNv;Cgeb-D5f`9LC0U*uW(mST3)w6oF3_P6v6k%bzR ze6WuV@%q~)=_oXapE2CD1k_}woEx{IpZ)(rOP)Vpg-NNoYk?jS_?(_jk0qJXV)~&y zL;)wffgGP~T!6!pw58tSC{gCAFW?YorCErU+wWxQxt+<55;j@3QmMvuB<=I}?44ioWBN zbc`p+-2d` z?i5Ab4*O>wQiykH-XnK{f6`v@vYUs2E3`M3CS%}|CLP^$ym^e)c~26Bc<0>+2`DlL zc?(lUsenVf#zV-%Di5@$uMN_vPCV`ppVmiElv9bQl%7lrQ)~coXT+Dk_Plu!v?o)J zfRtx6p(euYlH*wq!*HP`JQW*9W8+A9P`g1VPd)zp6XUt^UgA=K#qcSxN-Nr25hp}t z@zywZ^3>_$&p$I$9!yRu&mKRcJ}r+DFKQ?0I7u`8>;*8i11bC*$!7$u6fFiM5Ty73 zsG|)cx{908=){D$M-NO)G+X*K+BFR)R_+pON5+h$hqW`JJI0UfCTwvAC%tR|C7Nl# z;EQrF_oz@|?g4majNM$nGXb6<7Co4ROe4F3@s=37xbZLzIigvOO~#JS-isd8K;eYG z?1V}sFNygnDQ(ks$H)nlBJHQkc1TSa&_vv*&&6p{p{9LR#V2SbReZeaok=Gw9u)sg zzjMb#sGni2ZL=_1!P_h35lNgOM)-T24Hsqe76C~Uwk5E9cw^!>zHcIUWM0n?V0L~1 zg}~x|RG64RGZSnE-|zx%$9Xu!mDc&{di3-&;NcrO*@2D)3dF#=CHI?*T8a2(h-9A| z@lXw~?fW6g;s?2NIQCkfgfRuoG`+jLyTxB5j5!2*6yPT9QMtFr+j}`*cI5mfZy(Nc zfIsi??v*>pZbpr~HzrriY%Z1uUWaZi7eEj9#Tthe8=`syU72RC7r;-tN21VD6EuMU zQ{6J_YONkDv^d!n!abfy?PAR<|nMm+x_ za#ab+dM!XXbOptSgsk0$tID+Kt`d@jxs2B$sjnFzE;J}AfjvNCR<>Ek3XjeN(t>`2n z2thgI&x)x47e>3-lRDoAq8$G*1BiXrC{0q-MFJ{?w!E7*WB{?~XE+z_CQcRRzwlC-=q zE8&efxa6K=6jg9)?Py8o>9zHuh#ho{jj=P`8}w9>7(l}2gZa8bANgXPl-&1W9gQI| zj7gVDfR(7ZgG3$RD;B;*9OF2rSsK6$9*25CJF~Ng;e71WILUnRzZQlmPn^bLOI^f`Gm!X_EXY643w%fE3>nYZFez|>PB9MxdgZd(TEh> zAt%DgBWET|@)2D!_b$FXtPPs%}Sj;EM?Z(v6X-;xJzB%E^yeD|g z%v8MhMqDnYQWuVlM_H(!HPz2U;0sO}X938m>a}cGI^JCG0+ux*7wHcz1L}%F>Izmx z_}PIa0K4F-xsvw?*5}%}EhLYJc9@+Xuo7(@^tQz^C)F|7;%=%0dZHyrNLpcBqUI%m7( zO^A+GMkOAan~EJV)&kM$@kj#t(69=@PeFN%39@ z177|r4sRRr05CRc-%3SWLiA&#n;)cB&)$KNtPT8}nE8mg&vf9HLX@_cOfz&v7V^cC61z+FrSc5Q$o^tRRIX4Aehmb(@nSE<);1 zvvzC(vEF8C-lUheY@5BifDwxAPp7c}TQi>>G56vu(oUinP^BAI?KAOncq<11qhSQU zh!eUGMF|5~3(VroI14hvg@n6@ljvuE)pF!SSRiwqU_=T?F_iHs=?{cd6gU=cs>zLoA5{2}AVw>=IW2 zGMG38*+9}3hUqUOZ3H2^fRTOAO&dHjP~^~ zkaR{fcwb&L`KL3TzlDqLbcQA-6lpqF4aj9o>=tA)L5*kxoPrz@rUEVHbqPw$a~b3r zLxxYoHV+5ZPhw(`ffC(})UiQKti4tI(22EQvD3PkTwJXgXk%#o#l$N_3*qqAuB1LV zIwg!3I`3S|sDFj-kMEXQM7p^j>Zu%}^i73Z(4EZK(W}#Ru2NNH=4IU#nb0FZ;YN%;32CJd5HPK@YnCP@=pHM z;=8wEF3oqN{XMhR*LC=*uu*lYn4nUp(A2d7mia97%S)o9AULk=?L)TG?1LXe>Autf zPCap~L2_~#CqO3|Z8sl=Lk>}jOf5AOTASc)s9hUs*QIN|Bxi`9BT|Fk9Mk37aN1ET z59K>R2{4aru(kySZ0qO^vb^9=!c!=ZY9Qq7^HY`6XPcUDwN8~srK z83)Kt;vMRzcqsB9issjNc8P~>apBmaz(t8>PABF+vLJ^^n$!wv8$8S1{RSE=??I5z1AxGMDj!QBnG&FW6Hhdu7xaB5 z$fhbn2vfd)+gJY==^)6FHd(g4Q()mDm7sPv%F? zWD?~}OoCrw4T)PbhOLp%f|9xE(6RbYe8h=Yf5yYMiX>j3!16sj*OMxBq+y;RA7F%! zcJnaGLpLD)`@E#=RAfZONmm>LSX$anslh)@Z55HWzsn*ba(@YDU!m1%k{KjX8cbJ#WX&u=wq6Bc zoF~d@N(ck6K_Cpol!h#sM8&+TXi&hp2bHg z3J-NB4zbhF$>b2fD`06pjkEF%+pUz{AY-f?1A(V+d7WIy5xdt`Utx=^eQm!^plSuB zGbsNIV`@5`s)i}){7{Z{fJc&K zw+NClubFlStPU(mS%XrP#a@%T9`mTxLx6>IxQ_)pS1@HP=M8L_UJ(Z6O|X9qMUtO-M2l~q1#iXcZzi&MoX{-mD5x4^gkU(yd)P$^7=>@8CjCIC2 ze7Xb<(I8O&N;j-3B5J}_aoSPpc0Mujd$T#Zu0HtE-I2wVjzm%=g>5>0)8J*tzt=C6 z4t$GmJx6K4YANsoFI5v4<~xCPQq&H#)zal!?(;LJCm#BUcN{JC!Wd^|MPL8{l7x>n z)Y3OU>8ExkUBWzsWICTmnWWcsapF*+IR>J;@#n(5m4unJ8{(BsU9*X|T^lIPGaC)3 z(RaJ|yEF9_S=gw7RhLB=V(Jvq147aUehLwKvgICHsV6JK0K4^l$01G35>}oha@erNFbWrj9FZukhaA2AhTBxmg;{)oadAG`g7(5~~ z9jv+qk?CNn7^Bp##B3x{ljaT* zGr54?`m)AwU|PaGyIY<9>4KAJV#%}BnxBU?MXy&+MgwP<%FpwLakX&tb0;KWM}tQ$!#ENtAafCMt)VdNg#MVCU2t8E zb!-#Fe<4=VfEkbpfE;BBXGX|uM#dW~{xGneX;H6+ONU3 z8PDmEYV_#yk`Z)BQ^=td+z#9`ddUZ*-kjjuE1-!aPZN`iK%2zQN^w>QBYIf3Q}rf5 zCN8P1K97uiK#bicNl-Plz7n<;kk+%vWT`oYWe24hibgCPff&X@9t#B24Z^CQ!%(aL zg+uI2&zyZ~>WMfD+Vxdj>}^ZY5Y*co6uQKhf-RGLc!39TCjORZU*#d@VH-0eC#eZO z4*!Y-@;C}0RkkNcYbHTjGdBY9NxtUl!F;~>jWmp#mM9Kz!vYB0zlm<@C$QuVQ|RA~ zyqBlhtLJ$5T7Un#^8J6{!Jo5(1)R`7v9nm-VkzFQSvaIWB-@UW{10(K_mud%q^f{S z&zpqkC}bL@Ky-s3O=}&yS@EBj-EdyWG;>(kMIy^CWsy?vAi{4$wtuQ^s|UEwh^Q$r zBMYnA9rcjhftj4#v4Z1r2P}}@Ay~kEc*esL;RoJ-u5AbB+D>pz%3@h!QkJH2A$n^j zkz-hP+7V-&z<+nuti*bH?BZ49 zc-Kl5NyRW{n@C$ugeMp~Eh2qOC)zDa6Q5DVp3- z9zwNCxrx+FEBDuBi|oK5JpvLR1ebP(p%mSAHVsnAh^+Q8c?qEYucGU*1%OZqGl(T} zGe775@Nk|7G9Cz2I7WC!xaj}lZkg+w#3?G)dqZKD1Tuic?G6FT3S0V`Pp%!19AZOIzQ zQiH_1r@5>WLJ3(N;i9O`-`J@(C0tysafc`RGvWimA{TF&vG$}1CRBoq#QJz{8WB<| zo%AuZ;(fETlRB>X2~unmvD~Hyr8{17PgN1Um-aBP(m*;$2siVcsV>!+9y>cLDqU0Y z4nU9NfL|lH4=2QO!8=?618{!HeACnktn*kd!@T{r&0Qrh9@bQ?*PEs)bnpxO#0d7| zM0OI$Zy0aDtb2oL{#MUUKr+uTiC7T%YoWgk<=i2a@{ok6NEDQ$nkd9BJ&5ujLtjPn z?$1OMJEjEQo>c0lZ+7B==swA(!QM&LUR5r3Vd@7xIWu!+nwep5 z^W*sv$+}}gA{br$4c~fUE*9@ZOX((K*YfBb}a_HeW&o|`;#iSH-CDVa$)VJC#U2R9tY6Iv} z`cuToAb!DgMzDnwL?0m#VNrA2ntQ}b|271vupSD#zaiMAZs(f9t1xxig*P*zI7Cct z3^c8F!Lwe&?r}f_t&PGfg=SX&l_+EuyUYy&?X!>p{IT{R&_8%;IR6CBx%zOBagt5u zeZwAy-H%o9NJhxQ9?!Lrx^QKH5f+HyY!zGbWV9$C0@S#XK+yP>fNWjom%dl8@K{+@ zT$YS=woPnT<35EP&NK^cMYS&0J*})T9rUv2uuwZ(CmsZRO3u(6@(Lub$sK3}eMADV zYy;+=n||Ucl%lO9sQ{H{qC*G0y?ux8aCyTF4T~AI$`htzqo=?*)njb895Dw|48a zf^al6u$QliZ7#EIEXarVvlbPlw|h1ib|`S4;EkMQHxEF}>{~ydw$&U!Fu~cn8H|re z`O<#I&D#(kIA)d(P&hE00C7NHr&yg##Q{NT&`+YN5{JBRaFc;0t5!9JDooVDxYAU6 zE}jS5fxgo_TKZxsOm|=RB?uEnFEgbUal~#+P;ik`IKBcTI2tTG#mECh+oW3_I`hKJlg~{}&m2EH^ZXg^ zGU3wKjGGmKHN8yOzf?CGg zB_l+AFV4zCf_~%0f>rf|xWCSF0_gsCoW(X$hnwm_o^oLnA(z;uL7@H}n;Dg0v`j=Q zcoZ{2WYZcC3(I|^d^K26I;)`LG{y{boM|cPgK|DSg(H`IFI>VQ79Zq+c6>RPAhEJ) zu{@F%gwa&t$f!}4lvi{uUy&=nh1$PJxpE9A`NAk9ir#Mn%cHZ{!Ukx`e&g2b!&VWH z1%vJ*8eO?Ql6A~cQ?Y*8(fMi7t)0y{^oLSTbvZrJ<2v*-= zLmq{Vb>pm99%?Uo94$Pn7v_O}SrvOrFb@t|s^lJ$V&bP$N$D7z7*3j@#9+}zOj1j1 z*`7Txz=g~XMf|j58H>F{^O)utNPhzPUhG;BNG{2qK9b5~1{7xi?J0gJYG9)n z>L$+uD36_e-h?pnvRK-3PY5vun}vaDVu)t5h$lH2O?5UE%iFnF0e1i?bu)NN(G(WSw5_AO+9 zvEOY6SN2;OCKT}t(tFq?h3~=+51YnY`bmK(D_ePK6njEoLqlB_Y9Y5Y)Xw8L43rhh zfbCrP9=*Ft^c^xE6iz)0$J2R+l7)MqsSCz2Y@KwTqJvYdl!$;z(jrQiotLH(BPF&u z&2cW7V@&N{GS5C7AYLr`OF)h@eeO7}Wsi?(PA5S=Zrikk;Y$-nO!XgdS1JPKW?MZj zC>b%%KisG;&w15HzDjPSAyvpkNndvwKWX85PP2|9?OiP^dnrSz0x7yli@Jn-;>kDW_b)Fbbq-LEocV7>}ys8$zo7LoWgO8O) zKR`Wo7pnC2pN(blD+EimB&0H^cdnx>;#bh{>Oqm9Pp#$ZCH*Ou29u1%*x0_oqvAYe zFtS3$w`Zb5FTZ?b^5K_{Y;0_}?#nM9#re_X{20!U;k>VNy~bZzh>?qGIMX zVP0Mj~ZS+WSZ;Aj@Z^QG~#_ZG6H*ac&Wo0t}F{ zBOS)>&Z@PhXOhxIe}Ky~VYJ`IYyKRQCV1@d2og#WAIAQ23{^rUBfS)RC)>yu9>JCU z{@!c>JIozKp4{yWW3qNREAjT|Pmg0qRfIg@x~_)eRi^7}=%MZ~M(I8tm&F<#V-(6* z@Q8HNQ=Jab>n=jwclMVld`tVwNbQf>WTudKC_Bn&&%(KHh%;69_h{eK=kBu-MkOjzCiW|tT7;&D<<+yi> z5_VwZpcrECE9(4fhV09Q=b6(jdE+`i_b5bzrh9^g8qlvqCSFeFQXuwX8T6GhENn`%fY}65rujQO+D3N3Fb_|5*ND z{+YsU`TaJeP8UpYt_>H4Pv))B1BE;6AxGz`Wcl3rT49&HJ1y(HSIFB3xN&P**SR)Q z$b2q8R?Ou;IXav#jowo%iqt|0UCVyYc97qa)Ue;Rv2`o|+3)lIjx%{HYI1eTb(9{E q61=8NeAg`8ZWKSk_KFYa_VpI9Hoic%h`pQToev7df(@y9{r>@Qh4!NW literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/config.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/config.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cd04c22a285d5da519acaa4517c380a4948e808c GIT binary patch literal 12425 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 a2%a+wNv>d5awpzD@nWS~aVq7d*Zv2EKHj4M literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/debughelpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..044982db2e6494afd5de16d982ad1f336edbd047 GIT binary patch literal 5922 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/helpers.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/helpers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cbe548dbad22ab5ddf1a5f3f7634a0747842516b GIT binary patch literal 24015 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 z

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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/logging.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/logging.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7878a6ad0713fd34ff38254eaa9541d143e70ad2 GIT binary patch literal 2451 zcmZuzPj4GV6rWkI|He+5kX9{4XbM!VrQjkVI9O4HNRze@g^HvgOsed7XVzY4z3a}5 zlR63&sFi>Zzy)zgj{OFl_#k`b)DOS`4#0b}>og^-wBw!G_ujnso8SAblSZRP;G(~M z?*CCC3tMM^|LxKU|X?vyE!g+WDK zgOy@b9o9NESSgAUtj+|ED2vK7_bKhvMOBhP1J-8)SJcGJGq*D*$?*kQKcSs@Ie)wW zv)2U7PAJ50h*_`&53rsS7r=T^&@IxOe*qbi%_dE28;Q@O`zm=nc|lpNf~f0ZESTv_HcYf( zd^A$YNQK-;CY4GQ(?&@?WC1*)6&OUJ&rO)bEp{(poaGtS7+j%d+&AIATw+nuV+Oo;r<*|sQg5c;jXwPATv4&_Y2qVd$ zP7(U%baz`SgB@%zpT{>03x}gb!3G#rgi87*nq-^9djKSm09L|6z*Ac{&y$Z$`_`=h zkE}J#9+BD2klD?WLI@DY!<^?dn&+Q5~ z>>!My+zd@Dz&+q-j2wmRZ)nyYO4Dz9G6>)-;T4PIzKq!NlPMk>*0R-;W^HP-fhH^Y zft^DDtA8I6cpZlCp!SCqtYtucAba!+LdhdXKr1%s=5uIeyIs>soz{D4Ij=~~f@gNN zGw_sFmwPgnk4I|dEsTp0JKtU=hwt>c-n9XCbI;atguzmDDI)5(zw7}y@ zTFD)CTE+I~J!t>5G=k2EP18|$>}lB_E1YK;+1zYe^XIn5iuENJDy~ai=Q4F^$#JOb zmi~7CbgSwLygK~w>+3hU2C#>+sUNcIH*Ezm$0?rW^_#;)j3bz}@mXpOENyDY7ZeJ` z{C^Q&#jV>g7;;RH$iO+FfI1lz)B<4dY8a1;AcQ4UU{gK<-s!8bRxwpvIYRw)_^&|c zI}-a_GApvEdccy5E~o{k>Hs7JIS5!RrH~@muWj(lZLy$?fL&A}$uutHs?g@fsI~{e zTbZKlTJz;hCG5^ETtSjq)_&Os(&k=I&RPlC9rrwJ2pRKkB*hZbc>#GM7T&2Owgor* zrHbBO`}n~f@D6M-n#GAh_m^r6iD&H=C#U^3Rnsg!p!1*RSz=rW#%(naOmY}V3p?wMAB?;EyrQx}0uixwy~ z2MkFoP~ryma9XqgSYDsD$ZgvXFGW|`HfZ?pnKW`YgX06_ zAu43OQFrRJ;?$rK)Z4Joyr`~X4ET=%@@Xa`s4%6bGkYM_-k}`#;OhXrt58MLaxY4{ z(8!tmH@3gJzqY%2cWw34dz*K%RIn4$(l&fu?tPX^^0eS?l0;cejaT4SC?9DZs$aLb z8L86h>7z~ZOmX(xVk@jHXC1kMVz1wXp+YLOLZLvX1VuW91-e+TU36j1{pWJ=Us$uf Aq5uE@ literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/scaffold.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/scaffold.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9c7f0788435211d39187c86ac6e51244f223b6d2 GIT binary patch literal 24710 zcmdUXTaX-AnpS02)}^a2YPIgNET`JG)IFBUvTTn%ZCPVkYT2?qEv?kHXKFN4m0g+L zs#bMX&&g~_-O-xavBZvsWd>N5&C5Mmo+n1Vu^`l(wclnb26!G!~ zzTy9{aydWeTkTxUl3%-K%WuAxmtUvm$Zw%mkl$jhD8Hpz8NYUWV5w58Sga%89$Xr# z4au|99$p%$jmUGMy=`f_V%T*+L%0-@Vuk81J7lDpuKacRNE!bmG4|m!7CSA^ zKj=So$Ekhgt(@=rhwkM3L$~ePls}FVhmqqoYCAc$k^A;z2){_g31G-)cs9 z9f(>>fgiLZ4=*Dt%f1%{^&84tUJevuM$fg{!R6I33YOmMdcMSsB{kH8o6TT3YIQpy zat^;eJ9}|DjrlzQS`M+rXmz>OS-?~I^z!mss=Km`=fUQRQb8xGqZt-m2%@^`cBA^T z7hOff?sm6%E%572uXzI5e6N)w16sJaTivl4_+JUUyS3+B5jFfqsy zDAiTAmeMPm?&V}(_{eInRuLQ^z z^m3MFF#{_RdN&^zRS>PHPLp$(er!Atjq~`1QwZ+n7IQzed@HgRZQqtK&v3r@gWL}+ zEWhIy?hM^R`n`PQM1^(hZtk{y-v%%gXJW@w3t?Qmc7wm_0P5>&jjcHNK80`SB3RGe z%iXo^TNc_~&n;N%)~{Qaa;@CD{nxA?1HeAE2wS`ASg+=_dWiln*XLWER*3bR%*Rd` zwCB~6s7M_|@Ug9)z)xJ9uXntq;N#q<@1B{u@_rbo@JgUsP47wwK$+`$(UqoJ=`^oi zsa{VW-fPWW30qNcY}spG^A>{e%6!`kuRR|&z4`fW+pjLK#zP7G*5^_7I2sB$mWs98 zT010NTMDA9UB7w~VCJ>MQ`Kz#$zoitOSkIv*oxx(>CS5GG`%oV+fj>RRg=2^>M$do zVKC0%Sp@N5riEjO2)SxSYup}l)N^=j;@kHb!P^`7hO9ae!d$c82a&Gj11Bi>_DK-i zS}`asmIG&B4l$0z3}j*o5>r9UAihJv@ZtyvU7q9)`HPaeEt5K$NiChs4dnHo|8*a2 z__}7+ zxr+XA{{?C7xkuzX;lC*Pjy@vaOa9A}@7N>qec69S@>L&^?^XXRlJEIP0_f>(OH*0 zB$&Kv2D&?DDFJLqf(X~Tj zk~crlZ-bdeZb(0Trr>b~-|$xvtXu23I;1az)_NYH zz3w2)uS0EH$*Elt-WGGWty_il0^$o%@iyePdI=I+u3nA?e9O1*ARTX&XdoJtry=t+ zY@SB=L3`AuKA2m5`yB7&}x% zv=AkdlmsG4l~1<4r8(a_#Q}%RT+XdMozkjmy$-OB>h+!&m*$_`p-v#TdXd3P3|?k1 z#Nf*es4d6&X1f)STyF(8L{1bvMt5nfPu#DE%Rw`C+ASytJNs1wDHz5(`ZS0na(AjC zq7yKOC6KY<+qz-j-)_VYh20BoF@Ppy-mTJERTDXI$47z1?#MHI#7k1ajA&4Zx! zRImR&@(66~xB5D!Q`OT*ZW46T51-jNcI*=eL6rN*5`g>|+T~0)IuB(oSb}mI_|w$- z0H-p&tSJMggiz%o`0w~i2OMkdU~gu&QiS?cEOvtJ%M7`AAj10Ails)V#@z!_FA5S< zWfL9VUb{;E=*@-QHZ(<76WFeB2!PRiYhi`7Fku#&BUC{JXS$uB(J-X3H4j4CpDW>7 zJ(e&tSx|(G*zSh0!-isKvD@ls^m!X88>fP}_CN6zb*EAovmASEx0#N9GFTAc-n1-v z6qnf;$HO}8Q<#gPD0dIa=6&m)?IXN}XON)0kQ;ku&A#&dq@%uu{Lm#s>1R8_KHZq=)U>=h*h((j5LmnoxiOnvQh;mzXH zC=$tH@5|k?*I__{&@kwO(nNTR^0#fZ8zKZ2{61(l0E1?uy!Rv^2v!=%TM)0wfTkMS z9)|`S6pH--rnDu<;X;%ejV1499Yz|UNt32LvtU91M7;If1*~UBgg{NvfKVD5I!7YJ zgd(e(l5eh3(x(9v@+1XrZ7U1iDOfJOsmA5$nX~nC=ii&If9>?w>!;tEuAiMgcl!PJ zW*hw=LoiJt4YDQ_9?1Af9f@j_F;X@lhO)7w>CkisV@?U|QRpYFCPdz#-G+vM`sY;l z2Gj&j3^Wcl=eO9D*G8|!+Sse8)q#!GgA6 zfL&bF(;in^A)E3#%|H<_<2>}lcsS}tUK^?*981Sq^m8cc)W|IV*`Wr1m2!C zcsf$H9pJae*+Aa}P2$(o6Rd zM}+zjb!%ts_c`elGTl^Q6YbMzkcmS11<09u+SLRVi{-6E-6g85q8F)P0m7*$LeS;R zVhDOj)6l{CNn}c)9?HHp0OA*{MRLML?2ECyHK6&s8(wk%RVKT*{RdRX1KWkbqriYIW8Hk9a{0tZ^F zew@W7PK#^zjfW+3n}xely?(JcbP@V=8A1K7nf6uLF~XF z6f{XR(hr{vsvgD*P|&(=sd5BugUH&qG!~H5zD=Iyc<+LzU04PO^7<_jStCS>Jw`bP zGsz&D0^z3VMBBAUY0tr=65RBtNqYbSx>-fHwjy`*Bo$CN9}n$9cunid$CR&_6Q zU{FdH4)fSof4H(tn`Gc0bs?yFb`zi03bNsE1$pRVV6cm}cu_BRg} zxo**9w4T=+gfI?)$jiQ4xb`Z9NCEgG!qJXEDrt6=hs|7K0%awx+L0vt5lsBT3RUvz zq#X~y9+=EeK}tgbJcN#@MF!Uxv>9xik-Dx;@3MwwMv7%?Z+1rdvTZ31yo=gDAur;d zD2KUj-zTrnuU)x(6<`C%msOo&gHsLZBT$$q1%X)4!0X=}e`|Vn{9DEeN&Og>FTzvmA`<_RMhjcx^yb}G` z^t?Cgh<;?p>yI<*XQ$tro}GR?2rBAA59xjpo*+=+e$9+vo0)r^^2kAa`*8+w@$~GO zw;yi|1u658ArxQ*YF_=zW&|T<1d`Ap|NtMWfBgBVUB+zd?pC)M{e<`SD59 zR}vp+jo_btaC2gEGt1W+xI6wf6yNSq_rtDg`-jGR%>Hr^xKq$sry5W@j!6s0^gMy& z(|ai0nqf<`7zU*8Wf&VHy$7hJWQYZHk4g1ch{{@I%5D=<*D>8T>Q*9tH5zHP5U51_ zpsfO|e@in1yJ4txUxCyFzz#GTJvxq;x2I2^Mc#BTl*4H>E?k^Fe_`e_;~_o>W$#zt zGRu^TMOb#dheqR?zzS`elrUK*KS|C6e5Ty#o00M$`N@1HR+D6kOc^Pc?%v)A)U~x> zWkFV)RbL{kC7MXD9r4rIY~CkVA@b}X;!xbaE4jT{YZ$&+)ArW1;ng0zy=y5VYpuiF;hUz!Q+Ow7FPhuv?PFrWF%pcSV&bG4Kp@@ z;zSl>{gBiM)#ywMGBPBz$5b@_$TX)~&7jQ}p>7YQV12a_O-Kr}U`dJyWgy)vd|hZ^ zMxXirhs3$3JFaYR8emCX6O`AYX&2-YZV$=kqD!XZwW**`X@QoUGB}#xDXwRXx+!93 zR)!$>Mb(A>05`lvexuB(}gX-m^;?PmfW0|Q+PQU@3_CN4o?sDSB2Y5tbj z$4nitcz2sEl=2fje1nuhhl(zIV>F9QvD6e#Fg|Ug(bKIm1O6fyvo#K+^}aqXH~=}p zv`oYigiiBJm^@5MKVKXZ&(Ck5Jpzr0BlUy#ub(JuA;}V)eOg!%*jr%F2zydeqH$%o zZz4J9WfTHxK*UXQix*6*=U#)UkecFn+7$E+(4HGF7!>fOy45XszF+3$N-(H2#!}t01O;s8z^Bs+yulXLAt{H zJ*ziqL{7_~7rZtovDNF;eAE2N7!7&VUGM7wQEzkCO%1H6Z>XCp-@I~0b~^0?vxQLg zWHr64eWD!OfN2Uo{FcbC_;INzn^e3vtMz7cdS;MU}hDy={HdQ7gd{5d0(_9 zv%=}>CZH%>N~mp0?**O#o8Vp0)pb(m~q8*T)mf?;~hqFBc&z z{g65)DO>4UeUeIoH)+FP9OH>vW=hy{%I|w1`vAco>nMvZg13|*}yVDInwSY?1tV>sYmro+L zGog~!zjw@WGTuRH{nEcaxE2gR$uszVvKIk&aqhvGxd6>Z@Ag5H!JZCe^#(F$Wc73k zNvUvV0fGVm8KN=vy;EsD18CCdQG|ZAy9?O&rL2KUlx%lPd`P#8ZYR_F7h(Ux$@|^i`ap(&%BJgVY%5R&ijFg_ z-tx!UsiYg5?FR(Fg{t)Vb=RM(ru~Jbaw2*Drm5*$8G(b+rJ43rjHM!zh)zNcI;+Nf z44nuf1(SmF);0*z#OKI#0sJda64C* z2c~Hmb$&%5J3VbhbJG=yPS@Lf2%|2}T_vu`oR%5D`Rf3~xPooDM0SXakjwzWsdJO) z%c2=eKM0aSSE;9f^Dy< zw;W8f3HGL2qS$)q$+>``jD{p?6Lb!U_37a^_LiGVOWN_;^c6dL*`sFQO}(xO_)_VB zf}tlv6nL1;Kt;5xi>U{CJ001R+&~pAaj-M!yR?Q6;L6HqP>maW*bs6 zCr_NPfg11QHDQk%T~}qhQ|j$82!iG*z=itb41SrxpJ1>75{LVS{Hg)OVE|&!Kd>*; zBjNC0=O0LU&FpDml_;Dd9Cjw@X`9{bgZYW*mT@r`QhZeq3~Q>bs=zh6 zlA2+j^<-;rd4kK4cQ$N{(wLKhs4qf~MbV>9#^T1OIB9w-`r9We zd`Quqv(adQI~lGZ2H|IJFw^Y(pzc zQ)V}g7r?~H^saZY|4bS~R$-daoDB7^ng$bGm(6`aRd=bia1~pT*dt(1R&|9TPTun1 ztIk4C0IdjmrlLk8QgAwW9tLwEXa-g|B*+*-+{A>G^$VL7OyjZDbhjKRV+P-&bA*=G zLI*@`1DpHmqiM-#T3-tOZyR#5ALOLxzq2vlCW-o+)x2NJ{WN$K7R;Q%A}gqqZ75hLh1@@~rbz#*tVh0VXk= z#9Bx?lwrLA4j`?{%s*%XKz5iZ60yA^RM=eO1n)K}lS&&N>0ShaOoRxlT_2xsTaflO> z4&@_Ep86H!&lp#-=`kn+HjHq`fFbdHGe~+xD#2g%O9-$P{R$#d5(NrnkOwMZ!kILY zrn9!tc~Lo&8ymC-VFvt8_w2-)H2?%fvZOlO+mSM@=soQW=aj~zp{k4RNb!A}%4`Qw zozd3e3~!xy>G(^Vcbb=hWOYcla83lLnvj|wyzhKumY&%x;~L97#F{WVa@0ljJ<;MD z-4&rMIP#wvQ^MsFXj5}7Y@`A^%{qjS9>m#1NuQSULI#{TVrt1eKh}azv#Bz@NaB$r zODiVV!Da->u<-N1$Jkyze!Mp}NRS&&H6E|N($|xWc%QCk|Fss7b9$cNn)+t<6gis2 z@lF;b9fTZ@!!Co|#?f9qs#*iX?{YmFN1A~to#04BIAaCe&Z*Y?*ai+)a zO#hNLAvr<+HuLTBNLf$I#y~_x^1Gr!Wp{aSoQO@^=%%r- z+IJBOPCoFwbY_%^)ov5QPYK}>OohS#_lIDCRvch0c|bBdPX9jo_g}GZR_fMU6oNvEkP9xyp^Eef;ABKKDM*O2Kq)5#wh z!lf%cVPR{yiMN|7$pTqvlZNK>gUWF9H(41P8F-WwM~Q89V6BJ)OSqlnmi1w-Gv?%? z{3@=D;$P&zH#5h>ra#T!w*34@_6?N6eK=UtsDQFx!g&n~hftlLY6tO>jt^gzlGb7w zWeY3|=W(VDpv;@__Ouo&^VrqE@h#l1BD))d=^LcLosB-2$`D z$y86lB_PA^biYYwXw%B{)l^TC!+z7Cge(cA>d8i*T1VEteS{_iTBtm9y4hXmwALV~ zOLZDYSc5h?^;6ou;cMMg5JFl^I8=3J?JDb+)-hTfAv&5grm3y_Hs%9YHTAn(r_e_g z0>hi`Un*?+r;F3;VOU*jXNHol1!YiEy!wB!waG#C4FI^RF`$P~Tz)rLou*)+7Wg_~ znpGXX;}lieDSc?V#F9Tj0B!Uy@%b+@*np#d0dfC?IC>Nhm0{Z&!k=wbEc^u>x*pxL9eZ zUjGh^V|p(*F4gOPw^^^NI?BY`>L5V?9qk;5*eYV>;7?q>ARcb;NRh*w$C@`g#WS0y9YrcOXHp#G^hgUxbqOUh7(*NbuEp1}?Lfq1wxJ zV{*7CF2eE-`W`!T-ELdXCh02$WQF8hQiDZ@8IXl24?%37zYrIJSC?@{sm0h=7+a>& z!-IR`eN%!PGFV}7lffE;bq3#MKo_*wp2y+1OW4u~OeNoEB6q{|4jXM5>PHO7 zz}1f#>}K#M8SG*3ry1;H@MjoshfDn`gTKOnOjiAQ1o2LRxCDtzd!+2~kUkfsH^}3{ z>A~^SUOm;3pPN`wwzCG+x~24-u`(RpjR%~ zKPwk2pXRgaM-eoqn2I5^S1rg!Q$9ndu+Gm4%vHH(nd)F?MR{WGkXwu zOIv)OLJqd|GnOc$1WtWPTTapb)GiJEfqllc>^(azdl$aj@I8S1Qv1-)?Q-UM2h#99 z22>fbhd#3p;~DuJ>BZ0=+9Nt`uRZ#i;^<}by^o!dwUMQXpuq)NhbXaPh2?jWvr05b zfwAP*!t;;?Tn#dm1hYTXLpW2zDxiKq(VFDRHF&@g%oO zQ^m5NDfrCV^TADMEc8DzE*SJzF;<9#uqPfBK927Re&gp3$J*f0;GllkM46Sx^H=6(B`t@h)| z@$-E09i$ih0%O3+i<*^Bme>CNX(05{GEFi#am7m$T<#QNh@29w*os>*ISdp_xo1xJ zVR8{s!c;Xwok}jo(Yx>ZP@7(-gy~DItWVEx!iGT!Gj|?Ib6U;FHmJ#^E=Nj_8-k=W z@pjJT8qQ|v%VyfGx!SfFG=VD+n!$T=QO~UUDJE_0WVKgpVzPG{)3}N!%<$s$Mfb(y zC(_%Ou6DcELRd75aS6UpbgokW5Y?%-7~E%Y1VKE4snl*)LNIWBM^Vo}Tuukbdsf1Y zKrxAvx-i{AG)j&E)?tO~TnkeM(d+a7B9u@Usg%fnb~=t_JLE^|ci4*=_QK%~c^~i) zy^O?o7%ywM;Xq6CR_;TQ+#xGktGJq!f8PM&UC!MgyP7=*iFh!*fT)fmNo2d=rEE$4 zV+I=le5c&oR7aOHrMBhK?IGm0d8Y~(Xc6>6{ZmBrkplK{0AJ+Jh2I8Y&}WLEbL4LU ztZ&(CI8(aF%RqR}7>5w#p#C06s3Mm_<{iX13K4GHTYWkmOXnR(y7|ST@8Dq8*VD^H zP~KU0P~KASt~-k*^=?$YHxN}82k#B>{XSawVeSVx9Nof=fp^NNp>&qWRp=C=VZQNM z@{dH@)(f`<0U596lUUX@!j@SVkT3I&x6ymsWfaBrB1aLfL4qy;QNJ5i?v33C!Haev zr3?iB;d=4jPRU#9Y?D~Z-oLV5T-Tw@7TQPA$6D`WB~B&>hZYDTPbPk!G$zK zNpA$iG~hjpobkZP1)TA`xvWmTKtLNooc)UqfURtS8CsRk*Pi9|o47hv6AUTeQ>{&D zUUkV`YD#2O0@Ir#;*zI;p4WrP{qcY}va&<*fFU=r1Bdi>JRptGz@??r!SiyPn-GJz z*j25CRwv#M0aZ^WPU^E>;JhAT7?-#TAYZXVajbXNF|KH%JCkDv_kF6k1QQb{9oKYW z8y6+7El3|K?07cT;Dpcr%sm+7zxAtpF_ege5` z!*a0H&@ZcA)3yZl+DghT4~Zfhi8$&W$;;iU$oh(pd!o4FlZ{YN&&A@o6H z2@!0+D*Cs;|Qn z>8Hn$!Jg#;3Gw%Vp*T?5O@v&Wiz@PuHm2Zqne^^I4GQFXy-R3jSwgpw2u9{|VVYje z1$xLvZPTYA#^jJ@uC{O^2S9t(od7h$J)i|YEx=-RGPzKXUDAR?B0lxHuB}5-O(-`l zyA$bc4Xa^Q_p33f1(5446+v$bI@jF^oF&g*gxhFL9+gTOsUH(s(y}7=S|v#aim9RU z%xS`j4cNM|y^(DY>9{h0lIB)~QR<Yu)K zk!Hd`LZ=?59LR#Aw2EGZ#iGitN+YioQX&D^k9fp z5B@kp08nk^`r%xy zs4tTcRkpUnoDwsJrckUBibN&Oso!KnUtv&TL}{Vjor5i2E_$hzw9*pli}yr9CZnoV zlFKKsrfM6D4bOh#;&lDY+tX*>JwNkSTu!cI4&_D`uo1cIGaleQFL0a*+Hr}x{s*2? ze}_$r@=P_jw(~Uot1f8|JEOKz8?NnoQ#`3QrtM?}e~$r`-`Z&EhhYj+KdZU3$-NwB z^zQ$~^n!1bjoNi>44dv}wcoo*po(2PfP@dYWqUDm<+sTq`uN{PK5Z2cgMes`w1$Xc zq-EXz#Mj?oKxsk4Il&_XW5RQU-IPyimV1iYX4pVb&Xr-%N&jf@!5^5233UvZ45Zck le%y$r{~XA!#m`6c>F-#6q>}qy`nU6Bxx9B@d0_19{|3B5*pC1J literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/sessions.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/sessions.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1aeb90c240499805b8a683395272f000e9cef756 GIT binary patch literal 13611 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/signals.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/signals.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4ad9f7e6939eab3e2fa98a5debb21789cb2da338 GIT binary patch literal 2387 zcmZuy-HsbI6!!dNGCN6jlkGpMkOdd8s2lDPLPZrtMQAH^L4b*5O~%gdbZ2K$+q2t5 zy<+!4;Ic2#2bo*0cm$9Toa6Z+p>^bw<74~S=R4o=6r)i@pgC`zB|nCQ{Emao1~&2# zx_$#f5aDEmIqL{CH*?QD<~c-o%>RMp_k1FItB)LlKjAa~Ya)6gxF#aFa+wFCz6fCy z!YKHO$7&I1k<|vE4XicU-q zJn290N$(y6D0+)P1fqZ4V}W(Qqg>cP-rzd%wB_6D5 z8|v5}LD!fGLtZ(r+$;B(ymsKGDgfJSuky9b77AA?A1y@T;=jIm^x5otEtQ^0l_v2_ z7v*wZ#AcSLGEYut(~Cy=Hl5FOYUClrd={TbJzHe4KKoSLE9vQSRRy&^0KXaoiJbMg zgK1h%D#YfXUxl1wkepW$=jVkeGt`HizbNCZnentym1C;#>C&VH1g?g#+1`6Y;Bgi= zj7MW^A^E_umIMY{txL=`n7hO{%oDqq7~#v_^FaELoStyI`7Jidt2 zES_ib0Zo*QjifPM010RUz-xM$np0{{CDnjqM4Oi8MydtS5~gB9<18yKHPtc~X?{YB z1#R+0=cNG`Sq3iCtacXXog1lCp=goQIA57l+$u9Ir<6X)wUMzvPohA3w*VI7F%M{J zIyd%!=cP6jSW+mw6hxs;%5#|;4SNN6p?Ogsk=DMa-S(sZ_^Nu4vA2kiEVINPg95ZC zoV;>DLctxAnrg1~QS~{8a^hU!bM!yq~4WE^{Nzdh1$PRUI+&csnk$*e^a372z9 z`qoKdz;qZeS zRbW<2IMwEb^&7(2hn7v6XN7l1`xc)hHaTFHmt>lH`u(3A658y l{aO10p9KA}C5h_}oe;Y3?7I8D`)BZB)QjM$+5GJ~{{ju6azX$A literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/templating.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/templating.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..95c7afbfd4a46a916562c02fff8fc325a8748cda GIT binary patch literal 6955 zcmdT|&2JmW72lm*k}Hb(u)ZwWj=la4TSskOv}g?@wIeHz6Gus7IZhTT)+^3XBE90$ zvrEYqDAcI~*q7!~pl7M*q5cDU?YW2EdfP)U1q$SxTZ<(9y_sE#bnV0m3KU&phHrLe z-psuBdmppW$Vl11WB%#A+P{t%#^0&Y{|upV2_^oUX&Bt#W@vaO{#nR2EYC9Oodw$V z3W~Nt7rmmQ3!qD033QQ{LT6*h8&b3by6lw|Jp_8#8&-4~bj7PEdN>@}81+UKT?xlF z#=UVxkAObl9WV`HHYemwa2^dOH>SKP)jJkWZ_IczpvTdFP|Tv9tFt+y&iDa7@v-e4 zx@z!AKJ~G|r$phQ<=JRY^BJ^fgoXBDevr@dIZ@*h0y z{4_sP;?$LyqRZ)+m0E-s(<0t#8AIRyfPjCz`ydDPe9T3iqT2QY?Ay11^BpunR z(ed)f0zqW~C4LiCV(gmS+%tEKgk_Z3Fm_lMpzoM+x@$D8F5~Q?(Zx8tIoUOvHr`nD zrda@GgJKY5Vf)4vQ4cy{;^sSav-7xZ8P!A_M{?eEueF+@mc;JuOa`~lm0diyV+?3S zt=n$U;_mIW+w9qL9$YlomOpqWqvawt~XX!;zlA~X$Q4C z!J3Fy>LlXtWoK)&*5=#y(_=o@XYOgp$AW(EytHOayDHmd(>5KmtP0WcAYKn>2W_K> zatS4V8I@3O$79^|EDo7-TiDG4FYsa=&V@Swagi4x`yokM-Tuq1NZyIvuyIGYfh)yY zCk&+fW~0>%&bwkC&+cj`ao2;`jiU{W$hq(Uz;AbvAZa z!;WanMk{f*)G~48ChI}sHWIfMw4h_r23YY4aRaDt)&`6oj-JL8|5vO`1`21*=3uiEO*UaV-LvW z=0zhhn?Q6O$nLV=o1d5_u-i3!iyM#~TS|+ewt9HV8jLX!{#qEV2BF_1(fPVJ9V7qH z=M_@N_ZzK7;`?$I3sTG*o0bPx?nO|<3=^Fs5d_JjB{MllIyQlO|*x3efXuJ(I?c8bVI@zC}rcmWWY zNoTG!;&zbK)?wGmUUVGTUb*aQ?Q5uqQ3U&fW9~<8OF*Ub z^U(;`NFjtj1K0#|DhntvDMdjRna2&|iHUHfF~{Uf=+caoviCJkX!|iuCN99)v1cE# z2f1{(&qJh6ZkjbhPW}*0)}}T^a6)`AnurW@hOBgrU4~7vJwyZ0R!+mhyxGMM-o1YL z+LFJ#_%?{;MgRIcm#~i>=F=iVMZK|>PWy1{KD@H5318ep$ZfO)PsjUT*8{{< zOP~AZKp(z`rq7MBDh&5veu4Bi>A>mN= z%qzw(&aAMV!cK8}v|HRY^}%;aU7H&nLmujucI;b5YuHARy?@3u=!f~G4~>?&Wppiw zs@N@bOLc1xuIcU&H<4-D8-*PQj>>_Ei(S@5o`x22H046qz5!lc_R##5S+$lV88w3c z@l0U*!HB>MNc%xT`b=W@l@T9NO=eClmfyuxSwNLi)Pw_v{fX7i+PVnaK&m`P{mQ=$ zJtc9^$+>z~A~(}wENjtfQy!ujQ&g$BgL;uwbX-D-2|l*PZ1%;3&7c+sG0}cN|Ln^N zR$-&eVH7d9&pk(7{gCJ(Wk7Rute)m*(LRmMKx5X9y*<>mbB*1C!I`ixrKiJMPahh0 z3tK%|%hO;2=)Ho!eaTe|PfMoc_silb2~Y^|P-3$D35y{NRB(3orNg$*zQ9=t{&Ea+ z2Ld6PC7EXpMWuEhWyXnQjw#fPk+F7JoxP7!61~gz3}AP3$Ld;5vp4QU7b%|}b$5#V zO@3-ZL0TD%i3&@-%pit2D~F^kl7Ns7^*W!jP$fi8yCtl!2aZJ{ag-HRhQuD&pKqUf zo;3OqT%+VWe@Nq0l&!9UNQ{TZ4uX9XDM0Up6G#ql#$9{QAd92k-GY+Ew35aC$a8uW zqy!trtYX(zHhSvr!KBnRAL0g~rQ@VljC_EM`(ll$o#I#uXOaO zPRgUS?lG!ds*Y1dVMJvLIA9{>2{hBfa;F`N)OkmxWkHxa3kY|?YACc(kc~@%c{+4e zw1f4Sta5|yfuV<0KT7g15FQnneagndcn2rGZVN&~G!1FbT( zW-)5EB8ih$i3+kL(X^D^Nd_DR8BY&3KS3jR6lRt?l1u02ugL`~=-|d=B{pT1eLWUJ zGh2GXwCa8aHq}CUP~)J7fc%apE3_MAj4gFlqg$RFp(#2b?(@*DbkK+3rl~K6zr+lc z9hA*+B$MOtBXW@#Pv`MlCy@~xK7>ACD|BcolsbRrqN2;-9$o%elfgb<8+1sDJwQ4R zS7iYrlJTCplDa`J2Xa^MyDHnKJFH5E)*73lmEZp6%j!OGp&iIzqc>?_Ul-hE+!Fe4 z4Egq5bzvas%)8g>ijj*az$GWf)gyM*Qs>mF^@hYd#Rap(JsPpq2t#*O;L<@n1lO5Y zwwDYFdiBjfHVDEoEx8fU6>2kRC{()*o#W-3%C4rcU5YO0q>4oO4Id#8_uF(x`$^|S06iTJCsrswKd zUd5;?+y3i+DzGjiXa*|Kiqni-7%6fGh_GL)N(GtV1~sc^X<=p@Y7y_<0dwK?X|x{~ z{~cY(H*iLIjl?lbhw}9qa#1f)?^la@<|$EU9Da+L`tDRx68|~c11=yT2rk~%k}xd8`PwIzz6Cze}{(3rOMX0d4v^h8<~X7 zkr5j#gz;4O8K>ye34g*8*BJ18f)i8*;zWW z{NcNc{=yrJ3vc1;#eQ<>IdS&kU0uym`%0shNafp35_kI8tMgHno)vDkfO`2Vy`^9w zDW1q>s+2eguIhMwIG?6>3hd5B{XOti;MIsfK;;+}MmWbW|5vS|Y8|r1$Hqs_EHURO hl4F~(FPK&Se0B`C>@2Mw#lJ(T^<+N6!H5%+{|43vtwI0* literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/testing.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/testing.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..eae4c497bad8a2593ba424dc3e10ab16327d8a9b GIT binary patch literal 9397 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 L;60zMo!|d2RF=fw literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/__pycache__/wrappers.cpython-310.pyc b/.vcrunch/Lib/site-packages/flask/__pycache__/wrappers.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f2f0700db70f144b7e7bea5f8c19e2009ec1c515 GIT binary patch literal 5074 zcmai2>u%h}6(+gV-n6>t1DUfV@m6oS##ah2G$vu3e z=i`XUy{_YI@DU&Fa3LKv04psDu>ip8^!gKHR`Q7kg8l4!ZjSt_X~} zh4*e(qDU33##kgz!+_)aC~}fMq3Muj;ZCYB`lJv=CJ18;jH8s+>H}7-vlb%9+z>{QQyLS z2e({CqYTkd#;zHdE5;-EKm4aQ{qY88!L=lgCb_YTJ#24(diyutork^6_1>oUV7>Rr z=H2aW$4}yZIB@p(r0XufIit5~i3V26>iNX4a9Smg`d=Ah3B&)qe`js$u>_)9T!cQ` zl1Vz=NtoL5MH>6Vt?tvJ^B~;WlA+?)#?0Si11`6;S6#0xGM;41BlgV0I*K?W;_*NY ze?VKUqp@pk)3&CU3d42ZoceaCz_rGKu?y-*P0^y>E~rh@o5et@`lMB-MA0!Q&(2YI ze!TIZa5y?$o8-UyA)I7~JKNhmSQ>DK{rpoH)9JG?!tqOlGsJ0%6NQ;P*3Liz;D`N0 zj4)%u)k(oP*nTqF31ddyfOXW+DGo^GHZUFz6js-)ppr_m-~dr7k%BR31Coun1MNu_ z=8Td6u8C#!en=C#$j}s>vStZ{SiqyUa^8@`iL+>K;np^3x0_^>#nL9_m&YtY4qL;m zo%Va^5dNQ=2XIz%6%%_G}J}_UIf%V!XIxlQvv)zgX2ccA4KGBt zX;el*!r<7c#_8gtv6?s$ypNm!b`d;x8s`n?Bh;%kPWPB2{@Lw1PeGf2mIVP1*4CWw zcW-oWRs!feULeE?&I0|+rX8PzzkRro-(hZ!f4gbfX49H3zk$Cz)c|xtOEOA9yyEWm!D0X1()x>+~&B*ry3u$P5)cD*qjRW(*c!A%5PVI?%)$UEtjF6{< z4XGP5g)tIQvIJoeRO%snndB0T*;5c+Dhna#))G?^`UQNjX`1bAA2 z4oNcs-$@5qa}vhzvoQFg7Dr;H&F zGJ@9Afm*zaUb)}*Xw;#Gg0;{L{vGt56LPSr>_ISbNH;c zdO2%)9(kkZWo^$xOhHP6e#i4ZOIcLBX?R|c_<)%rcs8pQ&!^_G##CAJq0V<$1S5Ma z1~KZ0C-KoNePsU}o{-fL&9d6DTJc>$p&{#S2jRuTNNTE>DP}{IgyR+Q6VlUS%>%3_- zaL?mjK5x!1ez2gkcOMgvUF7d{$seI9OBpI;P_oz@%w3b^w$tn5V1eQ(m4(0HCI^~=&S|d?0-}UPZF^w!DV}#h)gq$C@Qy7N?#Ls}xxtNEu0-E)s$yzN+$%AtaAqSRZnW znuaoZN+}V+d21>Xwis0&MzK4?4ckTj}xRL07yp$ zg8rzwA66DD>#S}bwQ}S4)2NcSKZFfXv`}e5Vg_VL?3{)iKME-dRwxj!Qq@OF6yUv0 z-)e!|6uL@8@{By$3%Mu5Dc{Z$i)l;oXX^S;jiQe=cN_~pWko}0Oj4SDyrLm0+^y-V z=1-?rHEX2yT2b0Oynk=qdvwoTKUUV{B`)Fni1Sj}=cko~xe<%f;&3CVva21J<=<85 zfZ2-Dj%2$FdGS=~&|9^0LY~LAa`Ij{0a2b|JM{jLpMQwQSGe=4r_nZ>wduu;!dFk~ zw%QTz)92r%<^yW3qH!0ChE?AyJ}QkD4NKm0!dQN-7D>kUyeBK+PU5jUwJ zH3U^(N74<49yKQt75x#nq|G&n6PIiY;nI4?)HJoaoYfJM;df#cGu$&3+*O4ub? zsyAgNs43K)EdtR;4Amtq=XOdEXecxCn9>+T$qtL8hT3hEL7$SQY;No%|Q|Kxvl% literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/flask/app.py b/.vcrunch/Lib/site-packages/flask/app.py new file mode 100644 index 0000000..db442c9 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/app.py @@ -0,0 +1,2548 @@ +import functools +import inspect +import json +import logging +import os +import sys +import typing as t +import weakref +from collections.abc import Iterator as _abc_Iterator +from datetime import timedelta +from itertools import chain +from threading import Lock +from types import TracebackType + +import click +from werkzeug.datastructures import Headers +from werkzeug.datastructures import ImmutableDict +from werkzeug.exceptions import Aborter +from werkzeug.exceptions import BadRequest +from werkzeug.exceptions import BadRequestKeyError +from werkzeug.exceptions import HTTPException +from werkzeug.exceptions import InternalServerError +from werkzeug.routing import BuildError +from werkzeug.routing import Map +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.urls import url_quote +from werkzeug.utils import redirect as _wz_redirect +from werkzeug.wrappers import Response as BaseResponse + +from . import cli +from . import typing as ft +from .config import Config +from .config import ConfigAttribute +from .ctx import _AppCtxGlobals +from .ctx import AppContext +from .ctx import RequestContext +from .globals import _cv_app +from .globals import _cv_request +from .globals import g +from .globals import request +from .globals import request_ctx +from .globals import session +from .helpers import _split_blueprint_path +from .helpers import get_debug_flag +from .helpers import get_flashed_messages +from .helpers import get_load_dotenv +from .helpers import locked_cached_property +from .json.provider import DefaultJSONProvider +from .json.provider import JSONProvider +from .logging import create_logger +from .scaffold import _endpoint_from_view_func +from .scaffold import _sentinel +from .scaffold import find_package +from .scaffold import Scaffold +from .scaffold import setupmethod +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 DispatchingJinjaLoader +from .templating import Environment +from .wrappers import Request +from .wrappers import Response + +if t.TYPE_CHECKING: # pragma: no cover + import typing_extensions as te + from .blueprints import Blueprint + from .testing import FlaskClient + from .testing import FlaskCliRunner + +T_before_first_request = t.TypeVar( + "T_before_first_request", bound=ft.BeforeFirstRequestCallable +) +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) + +if sys.version_info >= (3, 8): + iscoroutinefunction = inspect.iscoroutinefunction +else: + + def iscoroutinefunction(func: t.Any) -> bool: + while inspect.ismethod(func): + func = func.__func__ + + while isinstance(func, functools.partial): + func = func.func + + return inspect.iscoroutinefunction(func) + + +def _make_timedelta(value: t.Union[timedelta, int, None]) -> t.Optional[timedelta]: + if value is None or isinstance(value, timedelta): + return value + + return timedelta(seconds=value) + + +class Flask(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 that is used for request objects. See :class:`~flask.Request` + #: for more information. + request_class = Request + + #: The class that is used for response objects. See + #: :class:`~flask.Response` for more information. + response_class = Response + + #: 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("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("SECRET_KEY") + + @property + def session_cookie_name(self) -> str: + """The name of the cookie set by the session interface. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.config["SESSION_COOKIE_NAME"]`` + instead. + """ + import warnings + + warnings.warn( + "'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use" + " 'SESSION_COOKIE_NAME' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.config["SESSION_COOKIE_NAME"] + + @session_cookie_name.setter + def session_cookie_name(self, value: str) -> None: + import warnings + + warnings.warn( + "'session_cookie_name' is deprecated and will be removed in Flask 2.3. Use" + " 'SESSION_COOKIE_NAME' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + self.config["SESSION_COOKIE_NAME"] = value + + #: 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( + "PERMANENT_SESSION_LIFETIME", get_converter=_make_timedelta + ) + + @property + def send_file_max_age_default(self) -> t.Optional[timedelta]: + """The default value for ``max_age`` for :func:`~flask.send_file`. The default + is ``None``, which tells the browser to use conditional requests instead of a + timed cache. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use + ``app.config["SEND_FILE_MAX_AGE_DEFAULT"]`` instead. + + .. versionchanged:: 2.0 + Defaults to ``None`` instead of 12 hours. + """ + import warnings + + warnings.warn( + "'send_file_max_age_default' is deprecated and will be removed in Flask" + " 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + return _make_timedelta(self.config["SEND_FILE_MAX_AGE_DEFAULT"]) + + @send_file_max_age_default.setter + def send_file_max_age_default(self, value: t.Union[int, timedelta, None]) -> None: + import warnings + + warnings.warn( + "'send_file_max_age_default' is deprecated and will be removed in Flask" + " 2.3. Use 'SEND_FILE_MAX_AGE_DEFAULT' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + self.config["SEND_FILE_MAX_AGE_DEFAULT"] = _make_timedelta(value) + + @property + def use_x_sendfile(self) -> bool: + """Enable this to use the ``X-Sendfile`` feature, assuming the server supports + it, from :func:`~flask.send_file`. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.config["USE_X_SENDFILE"]`` instead. + """ + import warnings + + warnings.warn( + "'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use" + " 'USE_X_SENDFILE' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.config["USE_X_SENDFILE"] + + @use_x_sendfile.setter + def use_x_sendfile(self, value: bool) -> None: + import warnings + + warnings.warn( + "'use_x_sendfile' is deprecated and will be removed in Flask 2.3. Use" + " 'USE_X_SENDFILE' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + self.config["USE_X_SENDFILE"] = value + + _json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None + _json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None + + @property # type: ignore[override] + def json_encoder(self) -> t.Type[json.JSONEncoder]: # type: ignore[override] + """The JSON encoder class to use. Defaults to + :class:`~flask.json.JSONEncoder`. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'app.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if self._json_encoder is None: + from . import json + + return json.JSONEncoder + + return self._json_encoder + + @json_encoder.setter + def json_encoder(self, value: t.Type[json.JSONEncoder]) -> None: + import warnings + + warnings.warn( + "'app.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_encoder = value + + @property # type: ignore[override] + def json_decoder(self) -> t.Type[json.JSONDecoder]: # type: ignore[override] + """The JSON decoder class to use. Defaults to + :class:`~flask.json.JSONDecoder`. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'app.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + + if self._json_decoder is None: + from . import json + + return json.JSONDecoder + + return self._json_decoder + + @json_decoder.setter + def json_decoder(self, value: t.Type[json.JSONDecoder]) -> None: + import warnings + + warnings.warn( + "'app.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_decoder = value + + json_provider_class: t.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 = {} + + #: Default configuration parameters. + default_config = ImmutableDict( + { + "ENV": None, + "DEBUG": None, + "TESTING": False, + "PROPAGATE_EXCEPTIONS": None, + "SECRET_KEY": None, + "PERMANENT_SESSION_LIFETIME": timedelta(days=31), + "USE_X_SENDFILE": False, + "SERVER_NAME": None, + "APPLICATION_ROOT": "/", + "SESSION_COOKIE_NAME": "session", + "SESSION_COOKIE_DOMAIN": None, + "SESSION_COOKIE_PATH": None, + "SESSION_COOKIE_HTTPONLY": True, + "SESSION_COOKIE_SECURE": False, + "SESSION_COOKIE_SAMESITE": None, + "SESSION_REFRESH_EACH_REQUEST": True, + "MAX_CONTENT_LENGTH": None, + "SEND_FILE_MAX_AGE_DEFAULT": None, + "TRAP_BAD_REQUEST_ERRORS": None, + "TRAP_HTTP_EXCEPTIONS": False, + "EXPLAIN_TEMPLATE_LOADING": False, + "PREFERRED_URL_SCHEME": "http", + "JSON_AS_ASCII": None, + "JSON_SORT_KEYS": None, + "JSONIFY_PRETTYPRINT_REGULAR": None, + "JSONIFY_MIMETYPE": None, + "TEMPLATES_AUTO_RELOAD": None, + "MAX_COOKIE_SIZE": 4093, + } + ) + + #: 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: t.Optional[t.Type["FlaskClient"]] = 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: t.Optional[t.Type["FlaskCliRunner"]] = None + + #: 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: t.Optional[str] = None, + static_folder: t.Optional[t.Union[str, os.PathLike]] = "static", + static_host: t.Optional[str] = None, + host_matching: bool = False, + subdomain_matching: bool = False, + template_folder: t.Optional[str] = "templates", + instance_path: t.Optional[str] = None, + instance_relative_config: bool = False, + root_path: t.Optional[str] = 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: t.List[ + t.Callable[[Exception, str, t.Dict[str, t.Any]], str] + ] = [] + + #: A list of functions that will be called at the beginning of the + #: first request to this instance. To register a function, use the + #: :meth:`before_first_request` decorator. + #: + #: .. deprecated:: 2.2 + #: Will be removed in Flask 2.3. Run setup code when + #: creating the application instead. + #: + #: .. versionadded:: 0.8 + self.before_first_request_funcs: t.List[ft.BeforeFirstRequestCallable] = [] + + #: 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: t.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: t.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: t.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 = {} + + #: 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() + + self.url_map.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 + self._before_request_lock = Lock() + + # 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 + ) + + # 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 _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." + ) + + @locked_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 = 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 + + @property + def propagate_exceptions(self) -> bool: + """Returns the value of the ``PROPAGATE_EXCEPTIONS`` configuration + value in case it's set, otherwise a sensible default is returned. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. + + .. versionadded:: 0.7 + """ + import warnings + + warnings.warn( + "'propagate_exceptions' is deprecated and will be removed in Flask 2.3.", + DeprecationWarning, + stacklevel=2, + ) + rv = self.config["PROPAGATE_EXCEPTIONS"] + if rv is not None: + return rv + return self.testing or self.debug + + @locked_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) + + @locked_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() + + @property + def got_first_request(self) -> bool: + """This attribute is set to ``True`` if the application started + handling the first request. + + .. versionadded:: 0.8 + """ + return self._got_first_request + + 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["ENV"] = os.environ.get("FLASK_ENV") or "production" + 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 open_instance_resource(self, resource: str, mode: str = "rb") -> t.IO[t.AnyStr]: + """Opens a resource from the application's instance folder + (:attr:`instance_path`). Otherwise works like + :meth:`open_resource`. Instance resources can also be opened for + writing. + + :param resource: the name of the resource. To access resources within + subfolders use forward slashes as separator. + :param mode: resource file opening mode, default is 'rb'. + """ + return open(os.path.join(self.instance_path, resource), mode) + + @property + def templates_auto_reload(self) -> bool: + """Reload templates when they are changed. Used by + :meth:`create_jinja_environment`. It is enabled by default in debug mode. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.config["TEMPLATES_AUTO_RELOAD"]`` + instead. + + .. versionadded:: 1.0 + This property was added but the underlying config and behavior + already existed. + """ + import warnings + + warnings.warn( + "'templates_auto_reload' is deprecated and will be removed in Flask 2.3." + " Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + rv = self.config["TEMPLATES_AUTO_RELOAD"] + return rv if rv is not None else self.debug + + @templates_auto_reload.setter + def templates_auto_reload(self, value: bool) -> None: + import warnings + + warnings.warn( + "'templates_auto_reload' is deprecated and will be removed in Flask 2.3." + " Use 'TEMPLATES_AUTO_RELOAD' in 'app.config' instead.", + DeprecationWarning, + stacklevel=2, + ) + self.config["TEMPLATES_AUTO_RELOAD"] = value + + 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_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`. + + .. versionadded:: 0.5 + """ + if filename is None: + return True + return filename.endswith((".html", ".htm", ".xml", ".xhtml")) + + def update_template_context(self, context: dict) -> 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[t.Optional[str]] = (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(func()) + + context.update(orig_ctx) + + def make_shell_context(self) -> dict: + """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 + + @property + def env(self) -> str: + """What environment the app is running in. This maps to the :data:`ENV` config + key. + + **Do not enable development when deploying in production.** + + Default: ``'production'`` + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. + """ + import warnings + + warnings.warn( + "'app.env' is deprecated and will be removed in Flask 2.3." + " Use 'app.debug' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self.config["ENV"] + + @env.setter + def env(self, value: str) -> None: + import warnings + + warnings.warn( + "'app.env' is deprecated and will be removed in Flask 2.3." + " Use 'app.debug' instead.", + DeprecationWarning, + stacklevel=2, + ) + self.config["ENV"] = value + + @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"] + + @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 + + def run( + self, + host: t.Optional[str] = None, + port: t.Optional[int] = None, + debug: t.Optional[bool] = 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, let env vars override previous values + if "FLASK_ENV" in os.environ: + print( + "'FLASK_ENV' is deprecated and will not be used in" + " Flask 2.3. Use 'FLASK_DEBUG' instead.", + file=sys.stderr, + ) + self.config["ENV"] = os.environ.get("FLASK_ENV") or "production" + self.debug = get_debug_flag() + elif "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 # type: ignore + 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 # type: ignore + + return cls(self, **kwargs) # type: ignore + + @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: t.Optional[str] = None, + view_func: t.Optional[ft.RouteCallable] = None, + provide_automatic_options: t.Optional[bool] = None, + **options: t.Any, + ) -> None: + if endpoint is None: + endpoint = _endpoint_from_view_func(view_func) # type: ignore + options["endpoint"] = endpoint + methods = options.pop("methods", None) + + # if the methods are not given and the view_func object knows its + # methods we can use that instead. If neither exists, we go with + # a tuple of only ``GET`` as default. + if methods is None: + methods = getattr(view_func, "methods", None) or ("GET",) + if isinstance(methods, str): + raise TypeError( + "Allowed methods must be a list of strings, for" + ' example: @app.route(..., methods=["POST"])' + ) + methods = {item.upper() for item in methods} + + # Methods that should always be added + required_methods = set(getattr(view_func, "required_methods", ())) + + # starting with Flask 0.8 the view_func object can disable and + # force-enable the automatic options handling. + if provide_automatic_options is None: + provide_automatic_options = getattr( + view_func, "provide_automatic_options", None + ) + + if provide_automatic_options is None: + if "OPTIONS" not in methods: + provide_automatic_options = True + required_methods.add("OPTIONS") + else: + provide_automatic_options = False + + # Add the required methods now. + methods |= required_methods + + rule = self.url_rule_class(rule, methods=methods, **options) + rule.provide_automatic_options = provide_automatic_options # type: ignore + + self.url_map.add(rule) + 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: t.Optional[str] = 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: t.Optional[str] = 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: t.Optional[str] = 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: t.Optional[str] = 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: t.Optional[str] = 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: t.Optional[str] = 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 before_first_request(self, f: T_before_first_request) -> T_before_first_request: + """Registers a function to be run before the first request to this + instance of the application. + + The function will be called without any arguments and its return + value is ignored. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Run setup code when creating + the application instead. + + .. versionadded:: 0.8 + """ + import warnings + + warnings.warn( + "'before_first_request' is deprecated and will be removed" + " in Flask 2.3. Run setup code while creating the" + " application instead.", + DeprecationWarning, + stacklevel=2, + ) + self.before_first_request_funcs.append(f) + return 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) -> t.Optional[ft.ErrorHandlerCallable]: + """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 = (*request.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 handle_http_exception( + self, e: HTTPException + ) -> t.Union[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) + if handler is None: + return e + return self.ensure_sync(handler)(e) + + 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 handle_user_exception( + self, e: Exception + ) -> t.Union[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) + + if handler is None: + raise + + return self.ensure_sync(handler)(e) + + 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 :attr:`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, 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: t.Union[InternalServerError, ft.ResponseReturnValue] + server_error = InternalServerError(original_exception=e) + handler = self._find_error_handler(server_error) + + 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: t.Union[ + t.Tuple[type, BaseException, TracebackType], t.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 raise_routing_exception(self, request: Request) -> "te.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 + + from .debughelpers import FormDataRoutingRedirect + + raise FormDataRoutingRedirect(request) + + 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: t.Dict[str, t.Any] = req.view_args # type: ignore[assignment] + return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) + + 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 + """ + # Run before_first_request functions if this is the thread's first request. + # Inlined to avoid a method call on subsequent requests. + # This is deprecated, will be removed in Flask 2.3. + if not self._got_first_request: + with self._before_request_lock: + if not self._got_first_request: + for func in self.before_first_request_funcs: + self.ensure_sync(func)() + + self._got_first_request = True + + try: + request_started.send(self) + 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: t.Union[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, 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 should_ignore_error(self, error: t.Optional[BaseException]) -> 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 ensure_sync(self, func: t.Callable) -> t.Callable: + """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.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: t.Optional[str] = None, + _method: t.Optional[str] = None, + _scheme: t.Optional[str] = None, + _external: t.Optional[bool] = 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: + rv = f"{rv}#{url_quote(_anchor)}" + + return rv + + 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) + + def make_response(self, rv: ft.ResponseReturnValue) -> Response: + """Convert the return value from a view function to an instance of + :attr:`response_class`. + + :param rv: the return value from the view function. The view function + must return a response. Returning ``None``, or the view ending + without returning, is not allowed. The following types are allowed + for ``view_rv``: + + ``str`` + A response object is created with the string encoded to UTF-8 + as the body. + + ``bytes`` + A response object is created with the bytes as the body. + + ``dict`` + A dictionary that will be jsonify'd before being returned. + + ``list`` + A list that will be jsonify'd before being returned. + + ``generator`` or ``iterator`` + A generator that returns ``str`` or ``bytes`` to be + streamed as the response. + + ``tuple`` + Either ``(body, status, headers)``, ``(body, status)``, or + ``(body, headers)``, where ``body`` is any of the other types + allowed here, ``status`` is a string or an integer, and + ``headers`` is a dictionary or a list of ``(key, value)`` + tuples. If ``body`` is a :attr:`response_class` instance, + ``status`` overwrites the exiting value and ``headers`` are + extended. + + :attr:`response_class` + The object is returned unchanged. + + other :class:`~werkzeug.wrappers.Response` class + The object is coerced to :attr:`response_class`. + + :func:`callable` + The function is called as a WSGI application. The result is + used to create a response object. + + .. versionchanged:: 2.2 + A generator will be converted to a streaming response. + A list will be converted to a JSON response. + + .. versionchanged:: 1.1 + A dict will be converted to a JSON response. + + .. versionchanged:: 0.9 + Previously a tuple was interpreted as the arguments for the + response object. + """ + + status = headers = None + + # unpack tuple returns + if isinstance(rv, tuple): + len_rv = len(rv) + + # a 3-tuple is unpacked directly + if len_rv == 3: + rv, status, headers = rv # type: ignore[misc] + # decide if a 2-tuple has status or headers + elif len_rv == 2: + if isinstance(rv[1], (Headers, dict, tuple, list)): + rv, headers = rv + else: + rv, status = rv # type: ignore[assignment,misc] + # other sized tuples are not allowed + else: + raise TypeError( + "The view function did not return a valid response tuple." + " The tuple must have the form (body, status, headers)," + " (body, status), or (body, headers)." + ) + + # the body must not be None + if rv is None: + raise TypeError( + f"The view function for {request.endpoint!r} did not" + " return a valid response. The function either returned" + " None or ended without a return statement." + ) + + # make sure the body is an instance of the response class + if not isinstance(rv, self.response_class): + if isinstance(rv, (str, bytes, bytearray)) or isinstance(rv, _abc_Iterator): + # let the response class set the status and headers instead of + # waiting to do it manually, so that the class can handle any + # special logic + rv = self.response_class( + rv, + status=status, + headers=headers, # type: ignore[arg-type] + ) + status = headers = None + elif isinstance(rv, (dict, list)): + rv = self.json.response(rv) + elif isinstance(rv, BaseResponse) or callable(rv): + # evaluate a WSGI callable, or coerce a different response + # class to the correct type + try: + rv = self.response_class.force_type( + rv, request.environ # type: ignore[arg-type] + ) + except TypeError as e: + raise TypeError( + f"{e}\nThe view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it" + f" was a {type(rv).__name__}." + ).with_traceback(sys.exc_info()[2]) from None + else: + raise TypeError( + "The view function did not return a valid" + " response. The return type must be a string," + " dict, list, tuple with headers or status," + " Response instance, or WSGI callable, but it was a" + f" {type(rv).__name__}." + ) + + rv = t.cast(Response, rv) + # prefer the status if it was provided + if status is not None: + if isinstance(status, (str, bytes, bytearray)): + rv.status = status + else: + rv.status_code = status + + # extend existing headers with provided headers + if headers: + rv.headers.update(headers) # type: ignore[arg-type] + + return rv + + def create_url_adapter( + self, request: t.Optional[Request] + ) -> t.Optional[MapAdapter]: + """Creates a URL adapter for the given request. The URL adapter + is created at a point where the request context is not yet set + up so the request is passed explicitly. + + .. versionadded:: 0.6 + + .. versionchanged:: 0.9 + This can now also be called without a request object when the + URL adapter is created for the application context. + + .. versionchanged:: 1.0 + :data:`SERVER_NAME` no longer implicitly enables subdomain + matching. Use :attr:`subdomain_matching` instead. + """ + if request is not None: + # If subdomain matching is disabled (the default), use the + # default subdomain in all cases. This should be the default + # in Werkzeug but it currently does not have that feature. + if not self.subdomain_matching: + subdomain = self.url_map.default_subdomain or None + else: + subdomain = None + + return self.url_map.bind_to_environ( + request.environ, + server_name=self.config["SERVER_NAME"], + subdomain=subdomain, + ) + # We need at the very least the server name to be set for this + # to work. + if self.config["SERVER_NAME"] is not None: + return self.url_map.bind( + self.config["SERVER_NAME"], + script_name=self.config["APPLICATION_ROOT"], + url_scheme=self.config["PREFERRED_URL_SCHEME"], + ) + + return None + + def inject_url_defaults(self, endpoint: str, values: dict) -> 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[t.Optional[str]] = (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: t.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 + + def preprocess_request(self) -> t.Optional[ft.ResponseReturnValue]: + """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 + + 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: t.Optional[BaseException] = _sentinel # type: ignore + ) -> 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, exc=exc) + + def do_teardown_appcontext( + self, exc: t.Optional[BaseException] = _sentinel # type: ignore + ) -> 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, 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: dict) -> 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 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: dict, start_response: t.Callable) -> t.Any: + """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: t.Optional[BaseException] = 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: dict, start_response: t.Callable) -> t.Any: + """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/.vcrunch/Lib/site-packages/flask/blueprints.py b/.vcrunch/Lib/site-packages/flask/blueprints.py new file mode 100644 index 0000000..104f8ac --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/blueprints.py @@ -0,0 +1,706 @@ +import json +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 Flask + +DeferredSetupFunction = t.Callable[["BlueprintSetupState"], t.Callable] +T_after_request = t.TypeVar("T_after_request", bound=ft.AfterRequestCallable) +T_before_first_request = t.TypeVar( + "T_before_first_request", bound=ft.BeforeFirstRequestCallable +) +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: "Flask", + 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: t.Optional[str] = None, + view_func: t.Optional[t.Callable] = 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 + + _json_encoder: t.Union[t.Type[json.JSONEncoder], None] = None + _json_decoder: t.Union[t.Type[json.JSONDecoder], None] = None + + @property # type: ignore[override] + def json_encoder( # type: ignore[override] + self, + ) -> t.Union[t.Type[json.JSONEncoder], None]: + """Blueprint-local JSON encoder class to use. Set to ``None`` to use the app's. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'bp.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._json_encoder + + @json_encoder.setter + def json_encoder(self, value: t.Union[t.Type[json.JSONEncoder], None]) -> None: + import warnings + + warnings.warn( + "'bp.json_encoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_encoder = value + + @property # type: ignore[override] + def json_decoder( # type: ignore[override] + self, + ) -> t.Union[t.Type[json.JSONDecoder], None]: + """Blueprint-local JSON decoder class to use. Set to ``None`` to use the app's. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Customize + :attr:`json_provider_class` instead. + + .. versionadded:: 0.10 + """ + import warnings + + warnings.warn( + "'bp.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + return self._json_decoder + + @json_decoder.setter + def json_decoder(self, value: t.Union[t.Type[json.JSONDecoder], None]) -> None: + import warnings + + warnings.warn( + "'bp.json_decoder' is deprecated and will be removed in Flask 2.3." + " Customize 'app.json_provider_class' or 'app.json' instead.", + DeprecationWarning, + stacklevel=2, + ) + self._json_decoder = value + + def __init__( + self, + name: str, + import_name: str, + static_folder: t.Optional[t.Union[str, os.PathLike]] = None, + static_url_path: t.Optional[str] = None, + template_folder: t.Optional[str] = None, + url_prefix: t.Optional[str] = None, + subdomain: t.Optional[str] = None, + url_defaults: t.Optional[dict] = None, + root_path: t.Optional[str] = None, + cli_group: t.Optional[str] = _sentinel, # type: ignore + ): + 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 "." 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: t.List[DeferredSetupFunction] = [] + + if url_defaults is None: + url_defaults = {} + + self.url_values_defaults = url_defaults + self.cli_group = cli_group + self._blueprints: t.List[t.Tuple["Blueprint", dict]] = [] + + def _check_setup_finished(self, f_name: str) -> None: + if self._got_registered_once: + import warnings + + warnings.warn( + f"The setup method '{f_name}' can no longer be called on" + f" the blueprint '{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.\n" + "This warning will become an exception in Flask 2.3.", + UserWarning, + stacklevel=3, + ) + + @setupmethod + def record(self, func: t.Callable) -> 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: t.Callable) -> 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: "Flask", options: dict, 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: "Flask", options: dict) -> 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.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``. + + .. versionchanged:: 2.0.1 + Registering the same blueprint with the same name multiple + times is deprecated and will become an error in Flask 2.1. + """ + 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, + endpoint="static", + ) + + # Merge blueprint data into parent. + if first_bp_registration or first_name_registration: + + def extend(bp_dict, parent_dict): + 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) + + 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") + + 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) + + @setupmethod + def add_url_rule( + self, + rule: str, + endpoint: t.Optional[str] = None, + view_func: t.Optional[ft.RouteCallable] = None, + provide_automatic_options: t.Optional[bool] = None, + **options: t.Any, + ) -> None: + """Like :meth:`Flask.add_url_rule` but for a blueprint. The endpoint for + the :func:`url_for` function is prefixed with the name of the blueprint. + """ + 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: t.Optional[str] = None + ) -> t.Callable[[T_template_filter], T_template_filter]: + """Register a custom template filter, available application wide. Like + :meth:`Flask.template_filter` but for a blueprint. + + :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: t.Optional[str] = None + ) -> None: + """Register a custom template filter, available application wide. Like + :meth:`Flask.add_template_filter` but for a blueprint. Works exactly + like the :meth:`app_template_filter` decorator. + + :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: t.Optional[str] = None + ) -> t.Callable[[T_template_test], T_template_test]: + """Register a custom template test, available application wide. Like + :meth:`Flask.template_test` but for a blueprint. + + .. 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: t.Optional[str] = None + ) -> None: + """Register a custom template test, available application wide. Like + :meth:`Flask.add_template_test` but for a blueprint. Works exactly + like the :meth:`app_template_test` decorator. + + .. 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: t.Optional[str] = None + ) -> t.Callable[[T_template_global], T_template_global]: + """Register a custom template global, available application wide. Like + :meth:`Flask.template_global` but for a blueprint. + + .. 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: t.Optional[str] = None + ) -> None: + """Register a custom template global, available application wide. Like + :meth:`Flask.add_template_global` but for a blueprint. Works exactly + like the :meth:`app_template_global` decorator. + + .. 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:`Flask.before_request`. Such a function is executed + before each request, even if outside of a blueprint. + """ + self.record_once( + lambda s: s.app.before_request_funcs.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def before_app_first_request( + self, f: T_before_first_request + ) -> T_before_first_request: + """Like :meth:`Flask.before_first_request`. Such a function is + executed before the first request to the application. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Run setup code when creating + the application instead. + """ + import warnings + + warnings.warn( + "'before_app_first_request' is deprecated and will be" + " removed in Flask 2.3. Use 'record_once' instead to run" + " setup code when registering the blueprint.", + DeprecationWarning, + stacklevel=2, + ) + self.record_once(lambda s: s.app.before_first_request_funcs.append(f)) + return f + + @setupmethod + def after_app_request(self, f: T_after_request) -> T_after_request: + """Like :meth:`Flask.after_request` but for a blueprint. Such a function + is executed after each request, even if outside of the blueprint. + """ + 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:`Flask.teardown_request` but for a blueprint. Such a + function is executed when tearing down each request, even if outside of + the blueprint. + """ + 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:`Flask.context_processor` but for a blueprint. Such a + function is executed each request, even if outside of the blueprint. + """ + self.record_once( + lambda s: s.app.template_context_processors.setdefault(None, []).append(f) + ) + return f + + @setupmethod + def app_errorhandler( + self, code: t.Union[t.Type[Exception], int] + ) -> t.Callable[[T_error_handler], T_error_handler]: + """Like :meth:`Flask.errorhandler` but for a blueprint. This + handler is used for all requests, even if outside of the blueprint. + """ + + def decorator(f: T_error_handler) -> T_error_handler: + self.record_once(lambda s: s.app.errorhandler(code)(f)) + return f + + return decorator + + @setupmethod + def app_url_value_preprocessor( + self, f: T_url_value_preprocessor + ) -> T_url_value_preprocessor: + """Same as :meth:`url_value_preprocessor` but application wide.""" + 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: + """Same as :meth:`url_defaults` but application wide.""" + self.record_once( + lambda s: s.app.url_default_functions.setdefault(None, []).append(f) + ) + return f diff --git a/.vcrunch/Lib/site-packages/flask/cli.py b/.vcrunch/Lib/site-packages/flask/cli.py new file mode 100644 index 0000000..82fe819 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/cli.py @@ -0,0 +1,1051 @@ +from __future__ import annotations + +import ast +import inspect +import os +import platform +import re +import sys +import traceback +import typing as t +from functools import update_wrapper +from operator import attrgetter + +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: + from .app import Flask + + +class NoAppException(click.UsageError): + """Raised if an application cannot be found or loaded.""" + + +def find_best_app(module): + """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): + """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, app_name): + """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} + 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): + """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]) + + +def locate_app(module_name, app_name, raise_if_not_found=True): + 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: + 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 + + 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, param, value): + if not value or ctx.resilient_parsing: + return + + import werkzeug + from . import __version__ + + click.echo( + f"Python {platform.python_version()}\n" + f"Flask {__version__}\n" + f"Werkzeug {werkzeug.__version__}", + color=ctx.color, + ) + ctx.exit() + + +version_option = click.Option( + ["--version"], + help="Show the Flask version.", + expose_value=False, + callback=get_version, + is_flag=True, + is_eager=True, +) + + +class ScriptInfo: + """Helper object to deal with Flask applications. This is usually not + necessary to interface with as it's used internally in the dispatching + to click. In future versions of Flask this object will most likely play + a bigger role. Typically it's created automatically by the + :class:`FlaskGroup` but you can also manually create it and pass it + onwards as click object. + """ + + def __init__( + self, + app_import_path: str | None = None, + create_app: t.Callable[..., Flask] | None = None, + set_debug_flag: bool = True, + ) -> None: + #: Optionally the import path for the Flask application. + self.app_import_path = app_import_path + #: Optionally a function that is passed the script info to create + #: the instance of the application. + self.create_app = create_app + #: A dictionary with arbitrary data that can be associated with + #: this script info. + self.data: t.Dict[t.Any, t.Any] = {} + self.set_debug_flag = set_debug_flag + self._loaded_app: Flask | None = None + + def load_app(self) -> Flask: + """Loads the Flask app (if not yet loaded) and returns it. Calling + this multiple times will just result in the already loaded app to + be returned. + """ + if self._loaded_app is not None: + return self._loaded_app + + if self.create_app is not None: + app = self.create_app() + else: + if self.app_import_path: + path, name = ( + re.split(r":(?![\\/])", self.app_import_path, 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: + break + + if not app: + 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) + + +def with_appcontext(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, *args, **kwargs): + 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) + + +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(self, *args, **kwargs): + """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): + if wrap_for_ctx: + f = with_appcontext(f) + return click.Group.command(self, *args, **kwargs)(f) + + return decorator + + def group(self, *args, **kwargs): + """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 click.Group.group(self, *args, **kwargs) + + +def _set_app(ctx: click.Context, param: click.Option, value: str | None) -> str | None: + if value is None: + return None + + info = ctx.ensure_object(ScriptInfo) + info.app_import_path = value + return value + + +# This option is eager so the app will be available if --help is given. +# --help is also eager, so --app must be before it in the param list. +# no_args_is_help bypasses eager processing, so this option must be +# processed manually in that case to ensure FLASK_APP gets picked up. +_app_option = click.Option( + ["-A", "--app"], + metavar="IMPORT", + help=( + "The Flask application or factory function to load, in the form 'module:name'." + " Module can be a dotted import or file path. Name is not required if it is" + " 'app', 'application', 'create_app', or 'make_app', and can be 'name(args)' to" + " pass arguments." + ), + is_eager=True, + expose_value=False, + callback=_set_app, +) + + +def _set_debug(ctx: click.Context, param: click.Option, value: bool) -> bool | None: + # If the flag isn't provided, it will default to False. Don't use + # that, let debug be set by env in that case. + source = ctx.get_parameter_source(param.name) # type: ignore[arg-type] + + if source is not None and source in ( + ParameterSource.DEFAULT, + ParameterSource.DEFAULT_MAP, + ): + return None + + # Set with env var instead of ScriptInfo.load so that it can be + # accessed early during a factory function. + os.environ["FLASK_DEBUG"] = "1" if value else "0" + return value + + +_debug_option = click.Option( + ["--debug/--no-debug"], + help="Set debug mode.", + expose_value=False, + callback=_set_debug, +) + + +def _env_file_callback( + ctx: click.Context, param: click.Option, value: str | None +) -> str | None: + if value is None: + return None + + import importlib + + try: + importlib.import_module("dotenv") + except ImportError: + raise click.BadParameter( + "python-dotenv must be installed to load an env file.", + ctx=ctx, + param=param, + ) from None + + # Don't check FLASK_SKIP_DOTENV, that only disables automatically + # loading .env and .flaskenv files. + load_dotenv(value) + return value + + +# This option is eager so env vars are loaded as early as possible to be +# used by other options. +_env_file_option = click.Option( + ["-e", "--env-file"], + type=click.Path(exists=True, dir_okay=False), + help="Load environment variables from this file. python-dotenv must be installed.", + is_eager=True, + expose_value=False, + callback=_env_file_callback, +) + + +class FlaskGroup(AppGroup): + """Special subclass of the :class:`AppGroup` group that supports + loading more commands from the configured Flask app. Normally a + developer does not have to interface with this class but there are + some very advanced use cases for which it makes sense to create an + instance of this. see :ref:`custom-scripts`. + + :param add_default_commands: if this is True then the default run and + shell commands will be added. + :param add_version_option: adds the ``--version`` option. + :param create_app: an optional callback that is passed the script info and + returns the loaded app. + :param load_dotenv: Load the nearest :file:`.env` and :file:`.flaskenv` + files to set environment variables. Will also change the working + directory to the directory containing the first file found. + :param set_debug_flag: Set the app's debug flag. + + .. versionchanged:: 2.2 + Added the ``-A/--app``, ``--debug/--no-debug``, ``-e/--env-file`` options. + + .. versionchanged:: 2.2 + An app context is pushed when running ``app.cli`` commands, so + ``@with_appcontext`` is no longer required for those commands. + + .. versionchanged:: 1.0 + If installed, python-dotenv will be used to load environment variables + from :file:`.env` and :file:`.flaskenv` files. + """ + + def __init__( + self, + add_default_commands: bool = True, + create_app: t.Callable[..., Flask] | None = None, + add_version_option: bool = True, + load_dotenv: bool = True, + set_debug_flag: bool = True, + **extra: t.Any, + ) -> None: + params = list(extra.pop("params", None) or ()) + # Processing is done with option callbacks instead of a group + # callback. This allows users to make a custom group callback + # without losing the behavior. --env-file must come first so + # that it is eagerly evaluated before --app. + params.extend((_env_file_option, _app_option, _debug_option)) + + if add_version_option: + params.append(version_option) + + if "context_settings" not in extra: + extra["context_settings"] = {} + + extra["context_settings"].setdefault("auto_envvar_prefix", "FLASK") + + super().__init__(params=params, **extra) + + self.create_app = create_app + self.load_dotenv = load_dotenv + self.set_debug_flag = set_debug_flag + + if add_default_commands: + self.add_command(run_command) + self.add_command(shell_command) + self.add_command(routes_command) + + self._loaded_plugin_commands = False + + def _load_plugin_commands(self): + if self._loaded_plugin_commands: + return + + if sys.version_info >= (3, 10): + from importlib import metadata + else: + # Use a backport on Python < 3.10. We technically have + # importlib.metadata on 3.8+, but the API changed in 3.10, + # so use the backport for consistency. + import importlib_metadata as metadata + + for ep in metadata.entry_points(group="flask.commands"): + self.add_command(ep.load(), ep.name) + + self._loaded_plugin_commands = True + + def get_command(self, ctx, name): + 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: + ctx.with_resource(app.app_context()) + + return app.cli.get_command(ctx, name) + + def list_commands(self, ctx): + self._load_plugin_commands() + # Start with the built-in and plugin commands. + rv = set(super().list_commands(ctx)) + info = ctx.ensure_object(ScriptInfo) + + # Add commands provided by the app, showing an error and + # continuing if the app couldn't be loaded. + try: + rv.update(info.load_app().cli.list_commands(ctx)) + except NoAppException as e: + # When an app couldn't be loaded, show the error message + # without the traceback. + click.secho(f"Error: {e.format_message()}\n", err=True, fg="red") + except Exception: + # When any other errors occurred during loading, show the + # full traceback. + click.secho(f"{traceback.format_exc()}\n", err=True, fg="red") + + return sorted(rv) + + def make_context( + self, + info_name: str | None, + args: list[str], + parent: click.Context | None = None, + **extra: t.Any, + ) -> click.Context: + # Set a flag to tell app.run to become a no-op. If app.run was + # not in a __name__ == __main__ guard, it would start the server + # when importing, blocking whatever command is being called. + os.environ["FLASK_RUN_FROM_CLI"] = "true" + + # Attempt to load .env and .flask env files. The --env-file + # option can cause another file to be loaded. + if get_load_dotenv(self.load_dotenv): + load_dotenv() + + if "obj" not in extra and "obj" not in self.context_settings: + extra["obj"] = ScriptInfo( + create_app=self.create_app, set_debug_flag=self.set_debug_flag + ) + + return super().make_context(info_name, args, parent=parent, **extra) + + def parse_args(self, ctx: click.Context, args: list[str]) -> list[str]: + if not args and self.no_args_is_help: + # Attempt to load --env-file and --app early in case they + # were given as env vars. Otherwise no_args_is_help will not + # see commands from app.cli. + _env_file_option.handle_parse_result(ctx, {}, []) + _app_option.handle_parse_result(ctx, {}, []) + + return super().parse_args(ctx, args) + + +def _path_is_ancestor(path, other): + """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 | None = None) -> bool: + """Load "dotenv" files in order of precedence to set environment variables. + + If an env var is already set it is not overwritten, so earlier files in the + list are preferred over later files. + + This is a no-op if `python-dotenv`_ is not installed. + + .. _python-dotenv: https://github.com/theskumar/python-dotenv#readme + + :param path: Load the file at this location instead of searching. + :return: ``True`` if a file was loaded. + + .. versionchanged:: 2.0 + The current directory is not changed to the location of the + loaded file. + + .. versionchanged:: 2.0 + When loading the env files, set the default encoding to UTF-8. + + .. versionchanged:: 1.1.0 + Returns ``False`` when python-dotenv is not installed, or when + the given path isn't a file. + + .. versionadded:: 1.0 + """ + try: + import dotenv + except ImportError: + if path or os.path.isfile(".env") or os.path.isfile(".flaskenv"): + click.secho( + " * Tip: There are .env or .flaskenv files present." + ' Do "pip install python-dotenv" to use them.', + fg="yellow", + err=True, + ) + + return False + + # Always return after attempting to load a given path, don't load + # the default files. + if path is not None: + if os.path.isfile(path): + return dotenv.load_dotenv(path, encoding="utf-8") + + return False + + loaded = False + + for name in (".env", ".flaskenv"): + path = dotenv.find_dotenv(name, usecwd=True) + + if not path: + continue + + dotenv.load_dotenv(path, encoding="utf-8") + loaded = True + + return loaded # True if at least one file was located and loaded. + + +def show_server_banner(debug, app_import_path): + """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): + self.path_type = click.Path(exists=True, dir_okay=False, resolve_path=True) + + def convert(self, value, param, ctx): + 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, param, value): + """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, param, ctx): + items = self.split_envvar_value(value) + 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, + host, + port, + reload, + debugger, + with_threads, + cert, + extra_files, + exclude_patterns, +): + """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 = info.load_app() + except Exception as e: + if is_running_from_reloader(): + # When reloading, print out the error immediately, but raise + # it later so the debugger or server can handle it. + traceback.print_exc() + err = e + + def app(environ, start_response): + 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, + ) + + +@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 = {} + + # 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", "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")) + + if sort in ("endpoint", "rule"): + rules = sorted(rules, key=attrgetter(sort)) + elif sort == "methods": + rules = sorted(rules, key=lambda rule: sorted(rule.methods)) # type: ignore + + rule_methods = [ + ", ".join(sorted(rule.methods - ignored_methods)) # type: ignore + for rule in rules + ] + + headers = ("Endpoint", "Methods", "Rule") + widths = ( + max(len(rule.endpoint) for rule in rules), + max(len(methods) for methods in rule_methods), + max(len(rule.rule) for rule in rules), + ) + widths = [max(len(h), w) for h, w in zip(headers, widths)] + row = "{{0:<{0}}} {{1:<{1}}} {{2:<{2}}}".format(*widths) + + click.echo(row.format(*headers).strip()) + click.echo(row.format(*("-" * width for width in widths))) + + for rule, methods in zip(rules, rule_methods): + click.echo(row.format(rule.endpoint, methods, rule.rule).rstrip()) + + +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/.vcrunch/Lib/site-packages/flask/config.py b/.vcrunch/Lib/site-packages/flask/config.py new file mode 100644 index 0000000..7b6a137 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/config.py @@ -0,0 +1,337 @@ +import errno +import json +import os +import types +import typing as t + +from werkzeug.utils import import_string + + +class ConfigAttribute: + """Makes an attribute forward to the config""" + + def __init__(self, name: str, get_converter: t.Optional[t.Callable] = None) -> None: + self.__name__ = name + self.get_converter = get_converter + + def __get__(self, obj: t.Any, owner: t.Any = None) -> t.Any: + 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 + + def __set__(self, obj: t.Any, value: t.Any) -> None: + obj.config[self.__name__] = value + + +class Config(dict): + """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, defaults: t.Optional[dict] = None) -> None: + super().__init__(defaults or {}) + self.root_path = root_path + + def from_envvar(self, variable_name: str, silent: bool = False) -> bool: + """Loads a configuration from an environment variable pointing to + a configuration file. This is basically just a shortcut with nicer + error messages for this line of code:: + + app.config.from_pyfile(os.environ['YOURAPPLICATION_SETTINGS']) + + :param variable_name: name of the environment variable + :param silent: set to ``True`` if you want silent failure for missing + files. + :return: ``True`` if the file was loaded successfully. + """ + rv = os.environ.get(variable_name) + if not rv: + if silent: + return False + raise RuntimeError( + f"The environment variable {variable_name!r} is not set" + " and as such configuration could not be loaded. Set" + " this variable and make it point to a configuration" + " file" + ) + return self.from_pyfile(rv, silent=silent) + + def from_prefixed_env( + self, prefix: str = "FLASK", *, loads: t.Callable[[str], t.Any] = json.loads + ) -> bool: + """Load any environment variables that start with ``FLASK_``, + dropping the prefix from the env key for the config key. Values + are passed through a loading function to attempt to convert them + to more specific types than strings. + + Keys are loaded in :func:`sorted` order. + + The default loading function attempts to parse values as any + valid JSON type, including dicts and lists. + + Specific items in nested dicts can be set by separating the + keys with double underscores (``__``). If an intermediate key + doesn't exist, it will be initialized to an empty dict. + + :param prefix: Load env vars that start with this prefix, + separated with an underscore (``_``). + :param loads: Pass each string value to this function and use + the returned value as the config value. If any error is + raised it is ignored and the value remains a string. The + default is :func:`json.loads`. + + .. versionadded:: 2.1 + """ + prefix = f"{prefix}_" + len_prefix = len(prefix) + + for key in sorted(os.environ): + if not key.startswith(prefix): + continue + + value = os.environ[key] + + try: + value = loads(value) + except Exception: + # Keep the value as a string if loading failed. + pass + + # Change to key.removeprefix(prefix) on Python >= 3.9. + key = key[len_prefix:] + + if "__" not in key: + # A non-nested key, set directly. + self[key] = value + continue + + # Traverse nested dictionaries with keys separated by "__". + current = self + *parts, tail = key.split("__") + + for part in parts: + # If an intermediate dict does not exist, create it. + if part not in current: + current[part] = {} + + current = current[part] + + current[tail] = value + + return True + + def from_pyfile(self, filename: str, 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: t.Union[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, + load: t.Callable[[t.IO[t.Any]], t.Mapping], + silent: bool = False, + ) -> 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 toml + app.config.from_file("config.toml", load=toml.load) + + :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. + :return: ``True`` if the file was loaded successfully. + + .. versionadded:: 2.0 + """ + filename = os.path.join(self.root_path, filename) + + try: + with open(filename) 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.Optional[t.Mapping[str, t.Any]] = 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: t.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 + ) -> t.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/.vcrunch/Lib/site-packages/flask/ctx.py b/.vcrunch/Lib/site-packages/flask/ctx.py new file mode 100644 index 0000000..ca28449 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/ctx.py @@ -0,0 +1,438 @@ +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 .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.Optional[t.Any] = 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) -> ft.AfterRequestCallable: + """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 + + +def copy_current_request_context(f: t.Callable) -> t.Callable: + """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, **kwargs): + with ctx: + return ctx.app.ensure_sync(f)(*args, **kwargs) + + return update_wrapper(wrapper, f) + + +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: t.List[contextvars.Token] = [] + + 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) + + def pop(self, exc: t.Optional[BaseException] = _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) + + def __enter__(self) -> "AppContext": + self.push() + return self + + def __exit__( + self, + exc_type: t.Optional[type], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> 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: dict, + request: t.Optional["Request"] = None, + session: t.Optional["SessionMixin"] = None, + ) -> None: + self.app = app + if request is None: + request = app.request_class(environ) + request.json_module = app.json # type: ignore[misc] + 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: t.Optional[t.List[t.Tuple[str, str]]] = None + self.session: t.Optional["SessionMixin"] = 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: t.List[ft.AfterRequestCallable] = [] + + self._cv_tokens: t.List[t.Tuple[contextvars.Token, t.Optional[AppContext]]] = [] + + 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: t.Optional[BaseException] = _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: t.Optional[type], + exc_value: t.Optional[BaseException], + tb: t.Optional[TracebackType], + ) -> 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/.vcrunch/Lib/site-packages/flask/debughelpers.py b/.vcrunch/Lib/site-packages/flask/debughelpers.py new file mode 100644 index 0000000..b063989 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/debughelpers.py @@ -0,0 +1,158 @@ +import typing as t + +from .app import Flask +from .blueprints import Blueprint +from .globals import request_ctx + + +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, key): + 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): + 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): + exc = request.routing_exception + 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): + """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): + def __getitem__(self, key): + 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) -> t.Generator: + 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: Flask, template, attempts) -> 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, Flask): + 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/.vcrunch/Lib/site-packages/flask/globals.py b/.vcrunch/Lib/site-packages/flask/globals.py new file mode 100644 index 0000000..b230ef7 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/globals.py @@ -0,0 +1,107 @@ +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 + + +class _FakeStack: + def __init__(self, name: str, cv: ContextVar[t.Any]) -> None: + self.name = name + self.cv = cv + + def _warn(self): + import warnings + + warnings.warn( + f"'_{self.name}_ctx_stack' is deprecated and will be" + " removed in Flask 2.3. Use 'g' to store data, or" + f" '{self.name}_ctx' to access the current context.", + DeprecationWarning, + stacklevel=3, + ) + + def push(self, obj: t.Any) -> None: + self._warn() + self.cv.set(obj) + + def pop(self) -> t.Any: + self._warn() + ctx = self.cv.get(None) + self.cv.set(None) + return ctx + + @property + def top(self) -> t.Optional[t.Any]: + self._warn() + return self.cv.get(None) + + +_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_stack = _FakeStack("app", _cv_app) +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_stack = _FakeStack("request", _cv_request) +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 +) + + +def __getattr__(name: str) -> t.Any: + if name == "_app_ctx_stack": + import warnings + + warnings.warn( + "'_app_ctx_stack' is deprecated and will be remoevd in Flask 2.3.", + DeprecationWarning, + stacklevel=2, + ) + return __app_ctx_stack + + if name == "_request_ctx_stack": + import warnings + + warnings.warn( + "'_request_ctx_stack' is deprecated and will be remoevd in Flask 2.3.", + DeprecationWarning, + stacklevel=2, + ) + return __request_ctx_stack + + raise AttributeError(name) diff --git a/.vcrunch/Lib/site-packages/flask/helpers.py b/.vcrunch/Lib/site-packages/flask/helpers.py new file mode 100644 index 0000000..15990d0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/helpers.py @@ -0,0 +1,705 @@ +import os +import pkgutil +import socket +import sys +import typing as t +from datetime import datetime +from functools import lru_cache +from functools import update_wrapper +from threading import RLock + +import werkzeug.utils +from werkzeug.exceptions import abort as _wz_abort +from werkzeug.utils import redirect as _wz_redirect + +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 werkzeug.wrappers import Response as BaseResponse + from .wrappers import Response + import typing_extensions as te + + +def get_env() -> str: + """Get the environment the app is running in, indicated by the + :envvar:`FLASK_ENV` environment variable. The default is + ``'production'``. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. + """ + import warnings + + warnings.warn( + "'FLASK_ENV' and 'get_env' are deprecated and will be removed" + " in Flask 2.3. Use 'FLASK_DEBUG' instead.", + DeprecationWarning, + stacklevel=2, + ) + return os.environ.get("FLASK_ENV") or "production" + + +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") + + if not val: + env = os.environ.get("FLASK_ENV") + + if env is not None: + print( + "'FLASK_ENV' is deprecated and will not be used in" + " Flask 2.3. Use 'FLASK_DEBUG' instead.", + file=sys.stderr, + ) + return env == "development" + + return False + + return val.lower() not in {"0", "false", "no"} + + +def get_load_dotenv(default: bool = True) -> bool: + """Get whether the user has disabled loading default dotenv files by + setting :envvar:`FLASK_SKIP_DOTENV`. The default is ``True``, load + the files. + + :param default: What to return if the env var isn't set. + """ + val = os.environ.get("FLASK_SKIP_DOTENV") + + if not val: + return default + + return val.lower() in ("0", "false", "no") + + +def stream_with_context( + generator_or_function: t.Union[ + 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 + except TypeError: + + def decorator(*args: t.Any, **kwargs: t.Any) -> t.Any: + gen = generator_or_function(*args, **kwargs) # type: ignore + return stream_with_context(gen) + + return update_wrapper(decorator, generator_or_function) # type: ignore + + def generator() -> t.Generator: + 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() # type: ignore + + # 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 + + +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) # type: ignore + + +def url_for( + endpoint: str, + *, + _anchor: t.Optional[str] = None, + _method: t.Optional[str] = None, + _scheme: t.Optional[str] = None, + _external: t.Optional[bool] = 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: t.Optional[t.Type["BaseResponse"]] = 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( # type: ignore[misc] + code: t.Union[int, "BaseResponse"], *args: t.Any, **kwargs: t.Any +) -> "te.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 + message_flashed.send( + current_app._get_current_object(), # type: ignore + message=message, + category=category, + ) + + +def get_flashed_messages( + with_categories: bool = False, category_filter: t.Iterable[str] = () +) -> t.Union[t.List[str], t.List[t.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) -> t.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: t.Union[os.PathLike, str, t.BinaryIO], + mimetype: t.Optional[str] = None, + as_attachment: bool = False, + download_name: t.Optional[str] = None, + conditional: bool = True, + etag: t.Union[bool, str] = True, + last_modified: t.Optional[t.Union[datetime, int, float]] = None, + max_age: t.Optional[ + t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]] + ] = 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 + deprecated 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: t.Union[os.PathLike, str], + path: t.Union[os.PathLike, str], + **kwargs: t.Any, +) -> "Response": + """Send a file from within a directory using :func:`send_file`. + + .. code-block:: python + + @app.route("/uploads/") + def download_file(name): + return send_from_directory( + app.config['UPLOAD_FOLDER'], name, as_attachment=True + ) + + This is a secure way to serve files from a folder, such as static + files or uploads. Uses :func:`~werkzeug.security.safe_join` to + ensure the path coming from the client is not maliciously crafted to + point outside the specified directory. + + If the final path does not point to an existing regular file, + raises a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under, + relative to the current application's root path. + :param path: The path to the file to send, relative to + ``directory``. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionchanged:: 2.0 + ``path`` replaces the ``filename`` parameter. + + .. versionadded:: 2.0 + Moved the implementation to Werkzeug. This is now a wrapper to + pass some Flask-specific arguments. + + .. versionadded:: 0.5 + """ + return werkzeug.utils.send_from_directory( # type: ignore[return-value] + directory, path, **_prepare_send_file_kwargs(**kwargs) + ) + + +def get_root_path(import_name: str) -> str: + """Find the root path of a package, or the path that contains a + module. If it cannot be found, returns the current working + directory. + + Not to be confused with the value returned by :func:`find_package`. + + :meta private: + """ + # Module already imported and has a file attribute. Use that first. + mod = sys.modules.get(import_name) + + if mod is not None and hasattr(mod, "__file__") and mod.__file__ is not None: + return os.path.dirname(os.path.abspath(mod.__file__)) + + # Next attempt: check the loader. + loader = pkgutil.get_loader(import_name) + + # 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 or import_name == "__main__": + return os.getcwd() + + if hasattr(loader, "get_filename"): + filepath = loader.get_filename(import_name) # type: 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)) + + +class locked_cached_property(werkzeug.utils.cached_property): + """A :func:`property` that is only evaluated once. Like + :class:`werkzeug.utils.cached_property` except access uses a lock + for thread safety. + + .. versionchanged:: 2.0 + Inherits from Werkzeug's ``cached_property`` (and ``property``). + """ + + def __init__( + self, + fget: t.Callable[[t.Any], t.Any], + name: t.Optional[str] = None, + doc: t.Optional[str] = None, + ) -> None: + super().__init__(fget, name=name, doc=doc) + self.lock = RLock() + + def __get__(self, obj: object, type: type = None) -> t.Any: # type: ignore + if obj is None: + return self + + with self.lock: + return super().__get__(obj, type=type) + + def __set__(self, obj: object, value: t.Any) -> None: + with self.lock: + super().__set__(obj, value) + + def __delete__(self, obj: object) -> None: + with self.lock: + super().__delete__(obj) + + +def is_ip(value: str) -> bool: + """Determine if the given string is an IP address. + + :param value: value to check + :type value: str + + :return: True if string is an IP address + :rtype: bool + """ + for family in (socket.AF_INET, socket.AF_INET6): + try: + socket.inet_pton(family, value) + except OSError: + pass + else: + return True + + return False + + +@lru_cache(maxsize=None) +def _split_blueprint_path(name: str) -> t.List[str]: + out: t.List[str] = [name] + + if "." in name: + out.extend(_split_blueprint_path(name.rpartition(".")[0])) + + return out diff --git a/.vcrunch/Lib/site-packages/flask/json/__init__.py b/.vcrunch/Lib/site-packages/flask/json/__init__.py new file mode 100644 index 0000000..65d8829 --- /dev/null +++ b/.vcrunch/Lib/site-packages/flask/json/__init__.py @@ -0,0 +1,342 @@ +from __future__ import annotations + +import json as _json +import typing as t + +from jinja2.utils import htmlsafe_json_dumps as _jinja_htmlsafe_dumps + +from ..globals import current_app +from .provider import _default + +if t.TYPE_CHECKING: # pragma: no cover + from ..app import Flask + from ..wrappers import Response + + +class JSONEncoder(_json.JSONEncoder): + """The default JSON encoder. Handles extra types compared to the + built-in :class:`json.JSONEncoder`. + + - :class:`datetime.datetime` and :class:`datetime.date` are + serialized to :rfc:`822` strings. This is the same as the HTTP + date format. + - :class:`decimal.Decimal` is serialized to a string. + - :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. + + Assign a subclass of this to :attr:`flask.Flask.json_encoder` or + :attr:`flask.Blueprint.json_encoder` to override the default. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.json`` instead. + """ + + def __init__(self, **kwargs) -> None: + import warnings + + warnings.warn( + "'JSONEncoder' is deprecated and will be removed in" + " Flask 2.3. Use 'Flask.json' to provide an alternate" + " JSON implementation instead.", + DeprecationWarning, + stacklevel=3, + ) + super().__init__(**kwargs) + + def default(self, o: t.Any) -> t.Any: + """Convert ``o`` to a JSON serializable type. See + :meth:`json.JSONEncoder.default`. Python does not support + overriding how basic types like ``str`` or ``list`` are + serialized, they are handled before this method. + """ + return _default(o) + + +class JSONDecoder(_json.JSONDecoder): + """The default JSON decoder. + + This does not change any behavior from the built-in + :class:`json.JSONDecoder`. + + Assign a subclass of this to :attr:`flask.Flask.json_decoder` or + :attr:`flask.Blueprint.json_decoder` to override the default. + + .. deprecated:: 2.2 + Will be removed in Flask 2.3. Use ``app.json`` instead. + """ + + def __init__(self, **kwargs) -> None: + import warnings + + warnings.warn( + "'JSONDecoder' is deprecated and will be removed in" + " Flask 2.3. Use 'Flask.json' to provide an alternate" + " JSON implementation instead.", + DeprecationWarning, + stacklevel=3, + ) + super().__init__(**kwargs) + + +def dumps(obj: t.Any, *, app: Flask | None = None, **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.2 + Calls ``current_app.json.dumps``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. 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 app is not None: + import warnings + + warnings.warn( + "The 'app' parameter is deprecated and will be removed in" + " Flask 2.3. Call 'app.json.dumps' directly instead.", + DeprecationWarning, + stacklevel=2, + ) + else: + app = current_app + + if app: + return app.json.dumps(obj, **kwargs) + + kwargs.setdefault("default", _default) + return _json.dumps(obj, **kwargs) + + +def dump( + obj: t.Any, fp: t.IO[str], *, app: Flask | None = None, **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.2 + Calls ``current_app.json.dump``, allowing an app to override + the behavior. + + .. versionchanged:: 2.2 + The ``app`` parameter will be removed in Flask 2.3. + + .. versionchanged:: 2.0 + Writing to a binary file, and the ``encoding`` argument, will be + removed in Flask 2.1. + """ + if app is not None: + import warnings + + warnings.warn( + "The 'app' parameter is deprecated and will be removed in" + " Flask 2.3. Call 'app.json.dump' directly instead.", + DeprecationWarning, + stacklevel=2, + ) + else: + app = current_app + + if app: + app.json.dump(obj, fp, **kwargs) + else: + kwargs.setdefault("default", _default) + _json.dump(obj, fp, **kwargs) + + +def loads(s: str | bytes, *, app: Flask | None = None, **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.2 + Calls ``current_app.json.loads``, 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 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 app is not None: + import warnings + + warnings.warn( + "The 'app' parameter is deprecated and will be removed in" + " Flask 2.3. Call 'app.json.loads' directly instead.", + DeprecationWarning, + stacklevel=2, + ) + else: + app = current_app + + if app: + return app.json.loads(s, **kwargs) + + return _json.loads(s, **kwargs) + + +def load(fp: t.IO[t.AnyStr], *, app: Flask | None = None, **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.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 app is not None: + import warnings + + warnings.warn( + "The 'app' parameter is deprecated and will be removed in" + " Flask 2.3. Call 'app.json.load' directly instead.", + DeprecationWarning, + stacklevel=2, + ) + else: + app = current_app + + if app: + return app.json.load(fp, **kwargs) + + return _json.load(fp, **kwargs) + + +def htmlsafe_dumps(obj: t.Any, **kwargs: t.Any) -> str: + """Serialize an object to a string of JSON with :func:`dumps`, then + replace HTML-unsafe characters with Unicode escapes and mark the + result safe with :class:`~markupsafe.Markup`. + + This is available in templates as the ``|tojson`` filter. + + The returned string is safe to render in HTML documents and + ``') + # => <script> do_nasty_stuff() </script> + # sanitize_html('Click here for $100') + # => Click here for $100 + def sanitize_token(self, token): + + # accommodate filters which use token_type differently + token_type = token["type"] + if token_type in ("StartTag", "EndTag", "EmptyTag"): + name = token["name"] + namespace = token["namespace"] + if ((namespace, name) in self.allowed_elements or + (namespace is None and + (namespaces["html"], name) in self.allowed_elements)): + return self.allowed_token(token) + else: + return self.disallowed_token(token) + elif token_type == "Comment": + pass + else: + return token + + def allowed_token(self, token): + if "data" in token: + attrs = token["data"] + attr_names = set(attrs.keys()) + + # Remove forbidden attributes + for to_remove in (attr_names - self.allowed_attributes): + del token["data"][to_remove] + attr_names.remove(to_remove) + + # Remove attributes with disallowed URL values + for attr in (attr_names & self.attr_val_is_uri): + assert attr in attrs + # I don't have a clue where this regexp comes from or why it matches those + # characters, nor why we call unescape. I just know it's always been here. + # Should you be worried by this comment in a sanitizer? Yes. On the other hand, all + # this will do is remove *more* than it otherwise would. + val_unescaped = re.sub("[`\x00-\x20\x7f-\xa0\\s]+", '', + unescape(attrs[attr])).lower() + # remove replacement characters from unescaped characters + val_unescaped = val_unescaped.replace("\ufffd", "") + try: + uri = urlparse.urlparse(val_unescaped) + except ValueError: + uri = None + del attrs[attr] + if uri and uri.scheme: + if uri.scheme not in self.allowed_protocols: + del attrs[attr] + if uri.scheme == 'data': + m = data_content_type.match(uri.path) + if not m: + del attrs[attr] + elif m.group('content_type') not in self.allowed_content_types: + del attrs[attr] + + for attr in self.svg_attr_val_allows_ref: + if attr in attrs: + attrs[attr] = re.sub(r'url\s*\(\s*[^#\s][^)]+?\)', + ' ', + unescape(attrs[attr])) + if (token["name"] in self.svg_allow_local_href and + (namespaces['xlink'], 'href') in attrs and re.search(r'^\s*[^#\s].*', + attrs[(namespaces['xlink'], 'href')])): + del attrs[(namespaces['xlink'], 'href')] + if (None, 'style') in attrs: + attrs[(None, 'style')] = self.sanitize_css(attrs[(None, 'style')]) + token["data"] = attrs + return token + + def disallowed_token(self, token): + token_type = token["type"] + if token_type == "EndTag": + token["data"] = "" % token["name"] + elif token["data"]: + assert token_type in ("StartTag", "EmptyTag") + attrs = [] + for (ns, name), v in token["data"].items(): + attrs.append(' %s="%s"' % (name if ns is None else "%s:%s" % (prefixes[ns], name), escape(v))) + token["data"] = "<%s%s>" % (token["name"], ''.join(attrs)) + else: + token["data"] = "<%s>" % token["name"] + if token.get("selfClosing"): + token["data"] = token["data"][:-1] + "/>" + + token["type"] = "Characters" + + del token["name"] + return token + + def sanitize_css(self, style): + # disallow urls + style = re.compile(r'url\s*\(\s*[^\s)]+?\s*\)\s*').sub(' ', style) + + # gauntlet + if not re.match(r"""^([:,;#%.\sa-zA-Z0-9!]|\w-\w|'[\s\w]+'|"[\s\w]+"|\([\d,\s]+\))*$""", style): + return '' + if not re.match(r"^\s*([-\w]+\s*:[^:;]*(;\s*|$))*$", style): + return '' + + clean = [] + for prop, value in re.findall(r"([-\w]+)\s*:\s*([^:;]*)", style): + if not value: + continue + if prop.lower() in self.allowed_css_properties: + clean.append(prop + ': ' + value + ';') + elif prop.split('-')[0].lower() in ['background', 'border', 'margin', + 'padding']: + for keyword in value.split(): + if keyword not in self.allowed_css_keywords and \ + not re.match(r"^(#[0-9a-fA-F]+|rgb\(\d+%?,\d*%?,?\d*%?\)?|\d{0,2}\.?\d{0,2}(cm|em|ex|in|mm|pc|pt|px|%|,|\))?)$", keyword): # noqa + break + else: + clean.append(prop + ': ' + value + ';') + elif prop.lower() in self.allowed_svg_properties: + clean.append(prop + ': ' + value + ';') + + return ' '.join(clean) diff --git a/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/whitespace.py b/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/whitespace.py new file mode 100644 index 0000000..0d12584 --- /dev/null +++ b/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/filters/whitespace.py @@ -0,0 +1,38 @@ +from __future__ import absolute_import, division, unicode_literals + +import re + +from . import base +from ..constants import rcdataElements, spaceCharacters +spaceCharacters = "".join(spaceCharacters) + +SPACES_REGEX = re.compile("[%s]+" % spaceCharacters) + + +class Filter(base.Filter): + """Collapses whitespace except in pre, textarea, and script elements""" + spacePreserveElements = frozenset(["pre", "textarea"] + list(rcdataElements)) + + def __iter__(self): + preserve = 0 + for token in base.Filter.__iter__(self): + type = token["type"] + if type == "StartTag" \ + and (preserve or token["name"] in self.spacePreserveElements): + preserve += 1 + + elif type == "EndTag" and preserve: + preserve -= 1 + + elif not preserve and type == "SpaceCharacters" and token["data"]: + # Test on token["data"] above to not introduce spaces where there were not + token["data"] = " " + + elif not preserve and type == "Characters": + token["data"] = collapse_spaces(token["data"]) + + yield token + + +def collapse_spaces(text): + return SPACES_REGEX.sub(' ', text) diff --git a/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/html5parser.py b/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/html5parser.py new file mode 100644 index 0000000..d06784f --- /dev/null +++ b/.vcrunch/Lib/site-packages/pip/_vendor/html5lib/html5parser.py @@ -0,0 +1,2795 @@ +from __future__ import absolute_import, division, unicode_literals +from pip._vendor.six import with_metaclass, viewkeys + +import types + +from . import _inputstream +from . import _tokenizer + +from . import treebuilders +from .treebuilders.base import Marker + +from . import _utils +from .constants import ( + spaceCharacters, asciiUpper2Lower, + specialElements, headingElements, cdataElements, rcdataElements, + tokenTypes, tagTokenTypes, + namespaces, + htmlIntegrationPointElements, mathmlTextIntegrationPointElements, + adjustForeignAttributes as adjustForeignAttributesMap, + adjustMathMLAttributes, adjustSVGAttributes, + E, + _ReparseException +) + + +def parse(doc, treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML document as a string or file-like object into a tree + + :arg doc: the document to parse as a string or file-like object + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import parse + >>> parse('

This is a doc

') + + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parse(doc, **kwargs) + + +def parseFragment(doc, container="div", treebuilder="etree", namespaceHTMLElements=True, **kwargs): + """Parse an HTML fragment as a string or file-like object into a tree + + :arg doc: the fragment to parse as a string or file-like object + + :arg container: the container context to parse the fragment in + + :arg treebuilder: the treebuilder to use when parsing + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import parseFragment + >>> parseFragment('this is a fragment') + + + """ + tb = treebuilders.getTreeBuilder(treebuilder) + p = HTMLParser(tb, namespaceHTMLElements=namespaceHTMLElements) + return p.parseFragment(doc, container=container, **kwargs) + + +def method_decorator_metaclass(function): + class Decorated(type): + def __new__(meta, classname, bases, classDict): + for attributeName, attribute in classDict.items(): + if isinstance(attribute, types.FunctionType): + attribute = function(attribute) + + classDict[attributeName] = attribute + return type.__new__(meta, classname, bases, classDict) + return Decorated + + +class HTMLParser(object): + """HTML parser + + Generates a tree structure from a stream of (possibly malformed) HTML. + + """ + + def __init__(self, tree=None, strict=False, namespaceHTMLElements=True, debug=False): + """ + :arg tree: a treebuilder class controlling the type of tree that will be + returned. Built in treebuilders can be accessed through + html5lib.treebuilders.getTreeBuilder(treeType) + + :arg strict: raise an exception when a parse error is encountered + + :arg namespaceHTMLElements: whether or not to namespace HTML elements + + :arg debug: whether or not to enable debug mode which logs things + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() # generates parser with etree builder + >>> parser = HTMLParser('lxml', strict=True) # generates parser with lxml builder which is strict + + """ + + # Raise an exception on the first error encountered + self.strict = strict + + if tree is None: + tree = treebuilders.getTreeBuilder("etree") + self.tree = tree(namespaceHTMLElements) + self.errors = [] + + self.phases = {name: cls(self, self.tree) for name, cls in + getPhases(debug).items()} + + def _parse(self, stream, innerHTML=False, container="div", scripting=False, **kwargs): + + self.innerHTMLMode = innerHTML + self.container = container + self.scripting = scripting + self.tokenizer = _tokenizer.HTMLTokenizer(stream, parser=self, **kwargs) + self.reset() + + try: + self.mainLoop() + except _ReparseException: + self.reset() + self.mainLoop() + + def reset(self): + self.tree.reset() + self.firstStartTag = False + self.errors = [] + self.log = [] # only used with debug mode + # "quirks" / "limited quirks" / "no quirks" + self.compatMode = "no quirks" + + if self.innerHTMLMode: + self.innerHTML = self.container.lower() + + if self.innerHTML in cdataElements: + self.tokenizer.state = self.tokenizer.rcdataState + elif self.innerHTML in rcdataElements: + self.tokenizer.state = self.tokenizer.rawtextState + elif self.innerHTML == 'plaintext': + self.tokenizer.state = self.tokenizer.plaintextState + else: + # state already is data state + # self.tokenizer.state = self.tokenizer.dataState + pass + self.phase = self.phases["beforeHtml"] + self.phase.insertHtmlElement() + self.resetInsertionMode() + else: + self.innerHTML = False # pylint:disable=redefined-variable-type + self.phase = self.phases["initial"] + + self.lastPhase = None + + self.beforeRCDataPhase = None + + self.framesetOK = True + + @property + def documentEncoding(self): + """Name of the character encoding that was used to decode the input stream, or + :obj:`None` if that is not determined yet + + """ + if not hasattr(self, 'tokenizer'): + return None + return self.tokenizer.stream.charEncoding[0].name + + def isHTMLIntegrationPoint(self, element): + if (element.name == "annotation-xml" and + element.namespace == namespaces["mathml"]): + return ("encoding" in element.attributes and + element.attributes["encoding"].translate( + asciiUpper2Lower) in + ("text/html", "application/xhtml+xml")) + else: + return (element.namespace, element.name) in htmlIntegrationPointElements + + def isMathMLTextIntegrationPoint(self, element): + return (element.namespace, element.name) in mathmlTextIntegrationPointElements + + def mainLoop(self): + CharactersToken = tokenTypes["Characters"] + SpaceCharactersToken = tokenTypes["SpaceCharacters"] + StartTagToken = tokenTypes["StartTag"] + EndTagToken = tokenTypes["EndTag"] + CommentToken = tokenTypes["Comment"] + DoctypeToken = tokenTypes["Doctype"] + ParseErrorToken = tokenTypes["ParseError"] + + for token in self.tokenizer: + prev_token = None + new_token = token + while new_token is not None: + prev_token = new_token + currentNode = self.tree.openElements[-1] if self.tree.openElements else None + currentNodeNamespace = currentNode.namespace if currentNode else None + currentNodeName = currentNode.name if currentNode else None + + type = new_token["type"] + + if type == ParseErrorToken: + self.parseError(new_token["data"], new_token.get("datavars", {})) + new_token = None + else: + if (len(self.tree.openElements) == 0 or + currentNodeNamespace == self.tree.defaultNamespace or + (self.isMathMLTextIntegrationPoint(currentNode) and + ((type == StartTagToken and + token["name"] not in frozenset(["mglyph", "malignmark"])) or + type in (CharactersToken, SpaceCharactersToken))) or + (currentNodeNamespace == namespaces["mathml"] and + currentNodeName == "annotation-xml" and + type == StartTagToken and + token["name"] == "svg") or + (self.isHTMLIntegrationPoint(currentNode) and + type in (StartTagToken, CharactersToken, SpaceCharactersToken))): + phase = self.phase + else: + phase = self.phases["inForeignContent"] + + if type == CharactersToken: + new_token = phase.processCharacters(new_token) + elif type == SpaceCharactersToken: + new_token = phase.processSpaceCharacters(new_token) + elif type == StartTagToken: + new_token = phase.processStartTag(new_token) + elif type == EndTagToken: + new_token = phase.processEndTag(new_token) + elif type == CommentToken: + new_token = phase.processComment(new_token) + elif type == DoctypeToken: + new_token = phase.processDoctype(new_token) + + if (type == StartTagToken and prev_token["selfClosing"] and + not prev_token["selfClosingAcknowledged"]): + self.parseError("non-void-element-with-trailing-solidus", + {"name": prev_token["name"]}) + + # When the loop finishes it's EOF + reprocess = True + phases = [] + while reprocess: + phases.append(self.phase) + reprocess = self.phase.processEOF() + if reprocess: + assert self.phase not in phases + + def parse(self, stream, *args, **kwargs): + """Parse a HTML document into a well-formed tree + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element). + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5parser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parse('

This is a doc

') + + + """ + self._parse(stream, False, None, *args, **kwargs) + return self.tree.getDocument() + + def parseFragment(self, stream, *args, **kwargs): + """Parse a HTML fragment into a well-formed tree fragment + + :arg container: name of the element we're setting the innerHTML + property if set to None, default to 'div' + + :arg stream: a file-like object or string containing the HTML to be parsed + + The optional encoding parameter must be a string that indicates + the encoding. If specified, that encoding will be used, + regardless of any BOM or later declaration (such as in a meta + element) + + :arg scripting: treat noscript elements as if JavaScript was turned on + + :returns: parsed tree + + Example: + + >>> from html5lib.html5libparser import HTMLParser + >>> parser = HTMLParser() + >>> parser.parseFragment('this is a fragment') + + + """ + self._parse(stream, True, *args, **kwargs) + return self.tree.getFragment() + + def parseError(self, errorcode="XXX-undefined-error", datavars=None): + # XXX The idea is to make errorcode mandatory. + if datavars is None: + datavars = {} + self.errors.append((self.tokenizer.stream.position(), errorcode, datavars)) + if self.strict: + raise ParseError(E[errorcode] % datavars) + + def adjustMathMLAttributes(self, token): + adjust_attributes(token, adjustMathMLAttributes) + + def adjustSVGAttributes(self, token): + adjust_attributes(token, adjustSVGAttributes) + + def adjustForeignAttributes(self, token): + adjust_attributes(token, adjustForeignAttributesMap) + + def reparseTokenNormal(self, token): + # pylint:disable=unused-argument + self.parser.phase() + + def resetInsertionMode(self): + # The name of this method is mostly historical. (It's also used in the + # specification.) + last = False + newModes = { + "select": "inSelect", + "td": "inCell", + "th": "inCell", + "tr": "inRow", + "tbody": "inTableBody", + "thead": "inTableBody", + "tfoot": "inTableBody", + "caption": "inCaption", + "colgroup": "inColumnGroup", + "table": "inTable", + "head": "inBody", + "body": "inBody", + "frameset": "inFrameset", + "html": "beforeHead" + } + for node in self.tree.openElements[::-1]: + nodeName = node.name + new_phase = None + if node == self.tree.openElements[0]: + assert self.innerHTML + last = True + nodeName = self.innerHTML + # Check for conditions that should only happen in the innerHTML + # case + if nodeName in ("select", "colgroup", "head", "html"): + assert self.innerHTML + + if not last and node.namespace != self.tree.defaultNamespace: + continue + + if nodeName in newModes: + new_phase = self.phases[newModes[nodeName]] + break + elif last: + new_phase = self.phases["inBody"] + break + + self.phase = new_phase + + def parseRCDataRawtext(self, token, contentType): + # Generic RCDATA/RAWTEXT Parsing algorithm + assert contentType in ("RAWTEXT", "RCDATA") + + self.tree.insertElement(token) + + if contentType == "RAWTEXT": + self.tokenizer.state = self.tokenizer.rawtextState + else: + self.tokenizer.state = self.tokenizer.rcdataState + + self.originalPhase = self.phase + + self.phase = self.phases["text"] + + +@_utils.memoize +def getPhases(debug): + def log(function): + """Logger that records which phase processes each token""" + type_names = {value: key for key, value in tokenTypes.items()} + + def wrapped(self, *args, **kwargs): + if function.__name__.startswith("process") and len(args) > 0: + token = args[0] + info = {"type": type_names[token['type']]} + if token['type'] in tagTokenTypes: + info["name"] = token['name'] + + self.parser.log.append((self.parser.tokenizer.state.__name__, + self.parser.phase.__class__.__name__, + self.__class__.__name__, + function.__name__, + info)) + return function(self, *args, **kwargs) + else: + return function(self, *args, **kwargs) + return wrapped + + def getMetaclass(use_metaclass, metaclass_func): + if use_metaclass: + return method_decorator_metaclass(metaclass_func) + else: + return type + + # pylint:disable=unused-argument + class Phase(with_metaclass(getMetaclass(debug, log))): + """Base class for helper object that implements each phase of processing + """ + __slots__ = ("parser", "tree", "__startTagCache", "__endTagCache") + + def __init__(self, parser, tree): + self.parser = parser + self.tree = tree + self.__startTagCache = {} + self.__endTagCache = {} + + def processEOF(self): + raise NotImplementedError + + def processComment(self, token): + # For most phases the following is correct. Where it's not it will be + # overridden. + self.tree.insertComment(token, self.tree.openElements[-1]) + + def processDoctype(self, token): + self.parser.parseError("unexpected-doctype") + + def processCharacters(self, token): + self.tree.insertText(token["data"]) + + def processSpaceCharacters(self, token): + self.tree.insertText(token["data"]) + + def processStartTag(self, token): + # Note the caching is done here rather than BoundMethodDispatcher as doing it there + # requires a circular reference to the Phase, and this ends up with a significant + # (CPython 2.7, 3.8) GC cost when parsing many short inputs + name = token["name"] + # In Py2, using `in` is quicker in general than try/except KeyError + # In Py3, `in` is quicker when there are few cache hits (typically short inputs) + if name in self.__startTagCache: + func = self.__startTagCache[name] + else: + func = self.__startTagCache[name] = self.startTagHandler[name] + # bound the cache size in case we get loads of unknown tags + while len(self.__startTagCache) > len(self.startTagHandler) * 1.1: + # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 + self.__startTagCache.pop(next(iter(self.__startTagCache))) + return func(token) + + def startTagHtml(self, token): + if not self.parser.firstStartTag and token["name"] == "html": + self.parser.parseError("non-html-root") + # XXX Need a check here to see if the first start tag token emitted is + # this token... If it's not, invoke self.parser.parseError(). + for attr, value in token["data"].items(): + if attr not in self.tree.openElements[0].attributes: + self.tree.openElements[0].attributes[attr] = value + self.parser.firstStartTag = False + + def processEndTag(self, token): + # Note the caching is done here rather than BoundMethodDispatcher as doing it there + # requires a circular reference to the Phase, and this ends up with a significant + # (CPython 2.7, 3.8) GC cost when parsing many short inputs + name = token["name"] + # In Py2, using `in` is quicker in general than try/except KeyError + # In Py3, `in` is quicker when there are few cache hits (typically short inputs) + if name in self.__endTagCache: + func = self.__endTagCache[name] + else: + func = self.__endTagCache[name] = self.endTagHandler[name] + # bound the cache size in case we get loads of unknown tags + while len(self.__endTagCache) > len(self.endTagHandler) * 1.1: + # this makes the eviction policy random on Py < 3.7 and FIFO >= 3.7 + self.__endTagCache.pop(next(iter(self.__endTagCache))) + return func(token) + + class InitialPhase(Phase): + __slots__ = tuple() + + def processSpaceCharacters(self, token): + pass + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processDoctype(self, token): + name = token["name"] + publicId = token["publicId"] + systemId = token["systemId"] + correct = token["correct"] + + if (name != "html" or publicId is not None or + systemId is not None and systemId != "about:legacy-compat"): + self.parser.parseError("unknown-doctype") + + if publicId is None: + publicId = "" + + self.tree.insertDoctype(token) + + if publicId != "": + publicId = publicId.translate(asciiUpper2Lower) + + if (not correct or token["name"] != "html" or + publicId.startswith( + ("+//silmaril//dtd html pro v0r11 19970101//", + "-//advasoft ltd//dtd html 3.0 aswedit + extensions//", + "-//as//dtd html 3.0 aswedit + extensions//", + "-//ietf//dtd html 2.0 level 1//", + "-//ietf//dtd html 2.0 level 2//", + "-//ietf//dtd html 2.0 strict level 1//", + "-//ietf//dtd html 2.0 strict level 2//", + "-//ietf//dtd html 2.0 strict//", + "-//ietf//dtd html 2.0//", + "-//ietf//dtd html 2.1e//", + "-//ietf//dtd html 3.0//", + "-//ietf//dtd html 3.2 final//", + "-//ietf//dtd html 3.2//", + "-//ietf//dtd html 3//", + "-//ietf//dtd html level 0//", + "-//ietf//dtd html level 1//", + "-//ietf//dtd html level 2//", + "-//ietf//dtd html level 3//", + "-//ietf//dtd html strict level 0//", + "-//ietf//dtd html strict level 1//", + "-//ietf//dtd html strict level 2//", + "-//ietf//dtd html strict level 3//", + "-//ietf//dtd html strict//", + "-//ietf//dtd html//", + "-//metrius//dtd metrius presentational//", + "-//microsoft//dtd internet explorer 2.0 html strict//", + "-//microsoft//dtd internet explorer 2.0 html//", + "-//microsoft//dtd internet explorer 2.0 tables//", + "-//microsoft//dtd internet explorer 3.0 html strict//", + "-//microsoft//dtd internet explorer 3.0 html//", + "-//microsoft//dtd internet explorer 3.0 tables//", + "-//netscape comm. corp.//dtd html//", + "-//netscape comm. corp.//dtd strict html//", + "-//o'reilly and associates//dtd html 2.0//", + "-//o'reilly and associates//dtd html extended 1.0//", + "-//o'reilly and associates//dtd html extended relaxed 1.0//", + "-//softquad software//dtd hotmetal pro 6.0::19990601::extensions to html 4.0//", + "-//softquad//dtd hotmetal pro 4.0::19971010::extensions to html 4.0//", + "-//spyglass//dtd html 2.0 extended//", + "-//sq//dtd html 2.0 hotmetal + extensions//", + "-//sun microsystems corp.//dtd hotjava html//", + "-//sun microsystems corp.//dtd hotjava strict html//", + "-//w3c//dtd html 3 1995-03-24//", + "-//w3c//dtd html 3.2 draft//", + "-//w3c//dtd html 3.2 final//", + "-//w3c//dtd html 3.2//", + "-//w3c//dtd html 3.2s draft//", + "-//w3c//dtd html 4.0 frameset//", + "-//w3c//dtd html 4.0 transitional//", + "-//w3c//dtd html experimental 19960712//", + "-//w3c//dtd html experimental 970421//", + "-//w3c//dtd w3 html//", + "-//w3o//dtd w3 html 3.0//", + "-//webtechs//dtd mozilla html 2.0//", + "-//webtechs//dtd mozilla html//")) or + publicId in ("-//w3o//dtd w3 html strict 3.0//en//", + "-/w3c/dtd html 4.0 transitional/en", + "html") or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is None or + systemId and systemId.lower() == "http://www.ibm.com/data/dtd/v11/ibmxhtml1-transitional.dtd"): + self.parser.compatMode = "quirks" + elif (publicId.startswith( + ("-//w3c//dtd xhtml 1.0 frameset//", + "-//w3c//dtd xhtml 1.0 transitional//")) or + publicId.startswith( + ("-//w3c//dtd html 4.01 frameset//", + "-//w3c//dtd html 4.01 transitional//")) and + systemId is not None): + self.parser.compatMode = "limited quirks" + + self.parser.phase = self.parser.phases["beforeHtml"] + + def anythingElse(self): + self.parser.compatMode = "quirks" + self.parser.phase = self.parser.phases["beforeHtml"] + + def processCharacters(self, token): + self.parser.parseError("expected-doctype-but-got-chars") + self.anythingElse() + return token + + def processStartTag(self, token): + self.parser.parseError("expected-doctype-but-got-start-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEndTag(self, token): + self.parser.parseError("expected-doctype-but-got-end-tag", + {"name": token["name"]}) + self.anythingElse() + return token + + def processEOF(self): + self.parser.parseError("expected-doctype-but-got-eof") + self.anythingElse() + return True + + class BeforeHtmlPhase(Phase): + __slots__ = tuple() + + # helper methods + def insertHtmlElement(self): + self.tree.insertRoot(impliedTagToken("html", "StartTag")) + self.parser.phase = self.parser.phases["beforeHead"] + + # other + def processEOF(self): + self.insertHtmlElement() + return True + + def processComment(self, token): + self.tree.insertComment(token, self.tree.document) + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.insertHtmlElement() + return token + + def processStartTag(self, token): + if token["name"] == "html": + self.parser.firstStartTag = True + self.insertHtmlElement() + return token + + def processEndTag(self, token): + if token["name"] not in ("head", "body", "html", "br"): + self.parser.parseError("unexpected-end-tag-before-html", + {"name": token["name"]}) + else: + self.insertHtmlElement() + return token + + class BeforeHeadPhase(Phase): + __slots__ = tuple() + + def processEOF(self): + self.startTagHead(impliedTagToken("head", "StartTag")) + return True + + def processSpaceCharacters(self, token): + pass + + def processCharacters(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.tree.insertElement(token) + self.tree.headPointer = self.tree.openElements[-1] + self.parser.phase = self.parser.phases["inHead"] + + def startTagOther(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagImplyHead(self, token): + self.startTagHead(impliedTagToken("head", "StartTag")) + return token + + def endTagOther(self, token): + self.parser.parseError("end-tag-after-implied-root", + {"name": token["name"]}) + + startTagHandler = _utils.MethodDispatcher([ + ("html", startTagHtml), + ("head", startTagHead) + ]) + startTagHandler.default = startTagOther + + endTagHandler = _utils.MethodDispatcher([ + (("head", "body", "html", "br"), endTagImplyHead) + ]) + endTagHandler.default = endTagOther + + class InHeadPhase(Phase): + __slots__ = tuple() + + # the real thing + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagHead(self, token): + self.parser.parseError("two-heads-are-not-better-than-one") + + def startTagBaseLinkCommand(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + def startTagMeta(self, token): + self.tree.insertElement(token) + self.tree.openElements.pop() + token["selfClosingAcknowledged"] = True + + attributes = token["data"] + if self.parser.tokenizer.stream.charEncoding[1] == "tentative": + if "charset" in attributes: + self.parser.tokenizer.stream.changeEncoding(attributes["charset"]) + elif ("content" in attributes and + "http-equiv" in attributes and + attributes["http-equiv"].lower() == "content-type"): + # Encoding it as UTF-8 here is a hack, as really we should pass + # the abstract Unicode string, and just use the + # ContentAttrParser on that, but using UTF-8 allows all chars + # to be encoded and as a ASCII-superset works. + data = _inputstream.EncodingBytes(attributes["content"].encode("utf-8")) + parser = _inputstream.ContentAttrParser(data) + codec = parser.parse() + self.parser.tokenizer.stream.changeEncoding(codec) + + def startTagTitle(self, token): + self.parser.parseRCDataRawtext(token, "RCDATA") + + def startTagNoFramesStyle(self, token): + # Need to decide whether to implement the scripting-disabled case + self.parser.parseRCDataRawtext(token, "RAWTEXT") + + def startTagNoscript(self, token): + if self.parser.scripting: + self.parser.parseRCDataRawtext(token, "RAWTEXT") + else: + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inHeadNoscript"] + + def startTagScript(self, token): + self.tree.insertElement(token) + self.parser.tokenizer.state = self.parser.tokenizer.scriptDataState + self.parser.originalPhase = self.parser.phase + self.parser.phase = self.parser.phases["text"] + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHead(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "head", "Expected head got %s" % node.name + self.parser.phase = self.parser.phases["afterHead"] + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.endTagHead(impliedTagToken("head")) + + startTagHandler = _utils.MethodDispatcher([ + ("html", startTagHtml), + ("title", startTagTitle), + (("noframes", "style"), startTagNoFramesStyle), + ("noscript", startTagNoscript), + ("script", startTagScript), + (("base", "basefont", "bgsound", "command", "link"), + startTagBaseLinkCommand), + ("meta", startTagMeta), + ("head", startTagHead) + ]) + startTagHandler.default = startTagOther + + endTagHandler = _utils.MethodDispatcher([ + ("head", endTagHead), + (("br", "html", "body"), endTagHtmlBodyBr) + ]) + endTagHandler.default = endTagOther + + class InHeadNoscriptPhase(Phase): + __slots__ = tuple() + + def processEOF(self): + self.parser.parseError("eof-in-head-noscript") + self.anythingElse() + return True + + def processComment(self, token): + return self.parser.phases["inHead"].processComment(token) + + def processCharacters(self, token): + self.parser.parseError("char-in-head-noscript") + self.anythingElse() + return token + + def processSpaceCharacters(self, token): + return self.parser.phases["inHead"].processSpaceCharacters(token) + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBaseLinkCommand(self, token): + return self.parser.phases["inHead"].processStartTag(token) + + def startTagHeadNoscript(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagNoscript(self, token): + node = self.parser.tree.openElements.pop() + assert node.name == "noscript", "Expected noscript got %s" % node.name + self.parser.phase = self.parser.phases["inHead"] + + def endTagBr(self, token): + self.parser.parseError("unexpected-inhead-noscript-tag", {"name": token["name"]}) + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + # Caller must raise parse error first! + self.endTagNoscript(impliedTagToken("noscript")) + + startTagHandler = _utils.MethodDispatcher([ + ("html", startTagHtml), + (("basefont", "bgsound", "link", "meta", "noframes", "style"), startTagBaseLinkCommand), + (("head", "noscript"), startTagHeadNoscript), + ]) + startTagHandler.default = startTagOther + + endTagHandler = _utils.MethodDispatcher([ + ("noscript", endTagNoscript), + ("br", endTagBr), + ]) + endTagHandler.default = endTagOther + + class AfterHeadPhase(Phase): + __slots__ = tuple() + + def processEOF(self): + self.anythingElse() + return True + + def processCharacters(self, token): + self.anythingElse() + return token + + def startTagHtml(self, token): + return self.parser.phases["inBody"].processStartTag(token) + + def startTagBody(self, token): + self.parser.framesetOK = False + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inBody"] + + def startTagFrameset(self, token): + self.tree.insertElement(token) + self.parser.phase = self.parser.phases["inFrameset"] + + def startTagFromHead(self, token): + self.parser.parseError("unexpected-start-tag-out-of-my-head", + {"name": token["name"]}) + self.tree.openElements.append(self.tree.headPointer) + self.parser.phases["inHead"].processStartTag(token) + for node in self.tree.openElements[::-1]: + if node.name == "head": + self.tree.openElements.remove(node) + break + + def startTagHead(self, token): + self.parser.parseError("unexpected-start-tag", {"name": token["name"]}) + + def startTagOther(self, token): + self.anythingElse() + return token + + def endTagHtmlBodyBr(self, token): + self.anythingElse() + return token + + def endTagOther(self, token): + self.parser.parseError("unexpected-end-tag", {"name": token["name"]}) + + def anythingElse(self): + self.tree.insertElement(impliedTagToken("body", "StartTag")) + self.parser.phase = self.parser.phases["inBody"] + self.parser.framesetOK = True + + startTagHandler = _utils.MethodDispatcher([ + ("html", startTagHtml), + ("body", startTagBody), + ("frameset", startTagFrameset), + (("base", "basefont", "bgsound", "link", "meta", "noframes", "script", + "style", "title"), + startTagFromHead), + ("head", startTagHead) + ]) + startTagHandler.default = startTagOther + endTagHandler = _utils.MethodDispatcher([(("body", "html", "br"), + endTagHtmlBodyBr)]) + endTagHandler.default = endTagOther + + class InBodyPhase(Phase): + # http://www.whatwg.org/specs/web-apps/current-work/#parsing-main-inbody + # the really-really-really-very crazy mode + __slots__ = ("processSpaceCharacters",) + + def __init__(self, *args, **kwargs): + super(InBodyPhase, self).__init__(*args, **kwargs) + # Set this to the default handler + self.processSpaceCharacters = self.processSpaceCharactersNonPre + + def isMatchingFormattingElement(self, node1, node2): + return (node1.name == node2.name and + node1.namespace == node2.namespace and + node1.attributes == node2.attributes) + + # helper + def addFormattingElement(self, token): + self.tree.insertElement(token) + element = self.tree.openElements[-1] + + matchingElements = [] + for node in self.tree.activeFormattingElements[::-1]: + if node is Marker: + break + elif self.isMatchingFormattingElement(node, element): + matchingElements.append(node) + + assert len(matchingElements) <= 3 + if len(matchingElements) == 3: + self.tree.activeFormattingElements.remove(matchingElements[-1]) + self.tree.activeFormattingElements.append(element) + + # the real deal + def processEOF(self): + allowed_elements = frozenset(("dd", "dt", "li", "p", "tbody", "td", + "tfoot", "th", "thead", "tr", "body", + "html")) + for node in self.tree.openElements[::-1]: + if node.name not in allowed_elements: + self.parser.parseError("expected-closing-tag-but-got-eof") + break + # Stop parsing + + def processSpaceCharactersDropNewline(self, token): + # Sometimes (start of
, , and 
+
+
+ The debugger caught an exception in your WSGI application. You can now + look at the traceback which led to the error. + If you enable JavaScript you can also use additional features such as code + execution (if the evalex feature is enabled), automatic pasting of the + exceptions and much more. +
+""" + + FOOTER + + """ + +""" +) + +CONSOLE_HTML = ( + HEADER + + """\ +

Interactive Console

+
+In this console you can execute Python expressions in the context of the +application. The initial namespace was created by the debugger automatically. +
+
The Console requires JavaScript.
+""" + + FOOTER +) + +SUMMARY_HTML = """\ +
+ %(title)s +
    %(frames)s
+ %(description)s +
+""" + +FRAME_HTML = """\ +
+

File "%(filename)s", + line %(lineno)s, + in %(function_name)s

+
%(lines)s
+
+""" + + +def _process_traceback( + exc: BaseException, + te: t.Optional[traceback.TracebackException] = None, + *, + skip: int = 0, + hide: bool = True, +) -> traceback.TracebackException: + if te is None: + te = traceback.TracebackException.from_exception(exc, lookup_lines=False) + + # Get the frames the same way StackSummary.extract did, in order + # to match each frame with the FrameSummary to augment. + frame_gen = traceback.walk_tb(exc.__traceback__) + limit = getattr(sys, "tracebacklimit", None) + + if limit is not None: + if limit < 0: + limit = 0 + + frame_gen = itertools.islice(frame_gen, limit) + + if skip: + frame_gen = itertools.islice(frame_gen, skip, None) + del te.stack[:skip] + + new_stack: t.List[DebugFrameSummary] = [] + hidden = False + + # Match each frame with the FrameSummary that was generated. + # Hide frames using Paste's __traceback_hide__ rules. Replace + # all visible FrameSummary with DebugFrameSummary. + for (f, _), fs in zip(frame_gen, te.stack): + if hide: + hide_value = f.f_locals.get("__traceback_hide__", False) + + if hide_value in {"before", "before_and_this"}: + new_stack = [] + hidden = False + + if hide_value == "before_and_this": + continue + elif hide_value in {"reset", "reset_and_this"}: + hidden = False + + if hide_value == "reset_and_this": + continue + elif hide_value in {"after", "after_and_this"}: + hidden = True + + if hide_value == "after_and_this": + continue + elif hide_value or hidden: + continue + + frame_args: t.Dict[str, t.Any] = { + "filename": fs.filename, + "lineno": fs.lineno, + "name": fs.name, + "locals": f.f_locals, + "globals": f.f_globals, + } + + if hasattr(fs, "colno"): + frame_args["colno"] = fs.colno # type: ignore[attr-defined] + frame_args["end_colno"] = fs.end_colno # type: ignore[attr-defined] + + new_stack.append(DebugFrameSummary(**frame_args)) + + # The codeop module is used to compile code from the interactive + # debugger. Hide any codeop frames from the bottom of the traceback. + while new_stack: + module = new_stack[0].global_ns.get("__name__") + + if module is None: + module = new_stack[0].local_ns.get("__name__") + + if module == "codeop": + del new_stack[0] + else: + break + + te.stack[:] = new_stack + + if te.__context__: + context_exc = t.cast(BaseException, exc.__context__) + te.__context__ = _process_traceback(context_exc, te.__context__, hide=hide) + + if te.__cause__: + cause_exc = t.cast(BaseException, exc.__cause__) + te.__cause__ = _process_traceback(cause_exc, te.__cause__, hide=hide) + + return te + + +class DebugTraceback: + __slots__ = ("_te", "_cache_all_tracebacks", "_cache_all_frames") + + def __init__( + self, + exc: BaseException, + te: t.Optional[traceback.TracebackException] = None, + *, + skip: int = 0, + hide: bool = True, + ) -> None: + self._te = _process_traceback(exc, te, skip=skip, hide=hide) + + def __str__(self) -> str: + return f"<{type(self).__name__} {self._te}>" + + @cached_property + def all_tracebacks( + self, + ) -> t.List[t.Tuple[t.Optional[str], traceback.TracebackException]]: + out = [] + current = self._te + + while current is not None: + if current.__cause__ is not None: + chained_msg = ( + "The above exception was the direct cause of the" + " following exception" + ) + chained_exc = current.__cause__ + elif current.__context__ is not None and not current.__suppress_context__: + chained_msg = ( + "During handling of the above exception, another" + " exception occurred" + ) + chained_exc = current.__context__ + else: + chained_msg = None + chained_exc = None + + out.append((chained_msg, current)) + current = chained_exc + + return out + + @cached_property + def all_frames(self) -> t.List["DebugFrameSummary"]: + return [ + f for _, te in self.all_tracebacks for f in te.stack # type: ignore[misc] + ] + + def render_traceback_text(self) -> str: + return "".join(self._te.format()) + + def render_traceback_html(self, include_title: bool = True) -> str: + library_frames = [f.is_library for f in self.all_frames] + mark_library = 0 < sum(library_frames) < len(library_frames) + rows = [] + + if not library_frames: + classes = "traceback noframe-traceback" + else: + classes = "traceback" + + for msg, current in reversed(self.all_tracebacks): + row_parts = [] + + if msg is not None: + row_parts.append(f'
  • {msg}:
    ') + + for frame in current.stack: + frame = t.cast(DebugFrameSummary, frame) + info = f' title="{escape(frame.info)}"' if frame.info else "" + row_parts.append(f"{frame.render_html(mark_library)}") + + rows.append("\n".join(row_parts)) + + is_syntax_error = issubclass(self._te.exc_type, SyntaxError) + + if include_title: + if is_syntax_error: + title = "Syntax Error" + else: + title = "Traceback (most recent call last):" + else: + title = "" + + exc_full = escape("".join(self._te.format_exception_only())) + + if is_syntax_error: + description = f"
    {exc_full}
    " + else: + description = f"
    {exc_full}
    " + + return SUMMARY_HTML % { + "classes": classes, + "title": f"

    {title}

    ", + "frames": "\n".join(rows), + "description": description, + } + + def render_debugger_html( + self, evalex: bool, secret: str, evalex_trusted: bool + ) -> str: + exc_lines = list(self._te.format_exception_only()) + plaintext = "".join(self._te.format()) + return PAGE_HTML % { + "evalex": "true" if evalex else "false", + "evalex_trusted": "true" if evalex_trusted else "false", + "console": "false", + "title": exc_lines[0], + "exception": escape("".join(exc_lines)), + "exception_type": escape(self._te.exc_type.__name__), + "summary": self.render_traceback_html(include_title=False), + "plaintext": escape(plaintext), + "plaintext_cs": re.sub("-{2,}", "-", plaintext), + "secret": secret, + } + + +class DebugFrameSummary(traceback.FrameSummary): + """A :class:`traceback.FrameSummary` that can evaluate code in the + frame's namespace. + """ + + __slots__ = ( + "local_ns", + "global_ns", + "_cache_info", + "_cache_is_library", + "_cache_console", + ) + + def __init__( + self, + *, + locals: t.Dict[str, t.Any], + globals: t.Dict[str, t.Any], + **kwargs: t.Any, + ) -> None: + super().__init__(locals=None, **kwargs) + self.local_ns = locals + self.global_ns = globals + + @cached_property + def info(self) -> t.Optional[str]: + return self.local_ns.get("__traceback_info__") + + @cached_property + def is_library(self) -> bool: + return any( + self.filename.startswith((path, os.path.realpath(path))) + for path in sysconfig.get_paths().values() + ) + + @cached_property + def console(self) -> Console: + return Console(self.global_ns, self.local_ns) + + def eval(self, code: str) -> t.Any: + return self.console.eval(code) + + def render_html(self, mark_library: bool) -> str: + context = 5 + lines = linecache.getlines(self.filename) + line_idx = self.lineno - 1 # type: ignore[operator] + start_idx = max(0, line_idx - context) + stop_idx = min(len(lines), line_idx + context + 1) + rendered_lines = [] + + def render_line(line: str, cls: str) -> None: + line = line.expandtabs().rstrip() + stripped_line = line.strip() + prefix = len(line) - len(stripped_line) + colno = getattr(self, "colno", 0) + end_colno = getattr(self, "end_colno", 0) + + if cls == "current" and colno and end_colno: + arrow = ( + f'\n{" " * prefix}' + f'{" " * (colno - prefix)}{"^" * (end_colno - colno)}' + ) + else: + arrow = "" + + rendered_lines.append( + f'
    {" " * prefix}'
    +                f"{escape(stripped_line) if stripped_line else ' '}"
    +                f"{arrow if arrow else ''}
    " + ) + + if lines: + for line in lines[start_idx:line_idx]: + render_line(line, "before") + + render_line(lines[line_idx], "current") + + for line in lines[line_idx + 1 : stop_idx]: + render_line(line, "after") + + return FRAME_HTML % { + "id": id(self), + "filename": escape(self.filename), + "lineno": self.lineno, + "function_name": escape(self.name), + "lines": "\n".join(rendered_lines), + "library": "library" if mark_library and self.is_library else "", + } + + +def render_console_html(secret: str, evalex_trusted: bool) -> str: + return CONSOLE_HTML % { + "evalex": "true", + "evalex_trusted": "true" if evalex_trusted else "false", + "console": "true", + "title": "Console", + "secret": secret, + } diff --git a/.vcrunch/Lib/site-packages/werkzeug/exceptions.py b/.vcrunch/Lib/site-packages/werkzeug/exceptions.py new file mode 100644 index 0000000..013df72 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/exceptions.py @@ -0,0 +1,884 @@ +"""Implements a number of Python exceptions which can be raised from within +a view to trigger a standard HTTP non-200 response. + +Usage Example +------------- + +.. code-block:: python + + from werkzeug.wrappers.request import Request + from werkzeug.exceptions import HTTPException, NotFound + + def view(request): + raise NotFound() + + @Request.application + def application(request): + try: + return view(request) + except HTTPException as e: + return e + +As you can see from this example those exceptions are callable WSGI +applications. However, they are not Werkzeug response objects. You +can get a response object by calling ``get_response()`` on a HTTP +exception. + +Keep in mind that you may have to pass an environ (WSGI) or scope +(ASGI) to ``get_response()`` because some errors fetch additional +information relating to the request. + +If you want to hook in a different exception page to say, a 404 status +code, you can add a second except for a specific subclass of an error: + +.. code-block:: python + + @Request.application + def application(request): + try: + return view(request) + except NotFound as e: + return not_found(request) + except HTTPException as e: + return e + +""" +import typing as t +from datetime import datetime + +from markupsafe import escape +from markupsafe import Markup + +from ._internal import _get_environ + +if t.TYPE_CHECKING: + import typing_extensions as te + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + from .datastructures import WWWAuthenticate + from .sansio.response import Response + from .wrappers.request import Request as WSGIRequest # noqa: F401 + from .wrappers.response import Response as WSGIResponse # noqa: F401 + + +class HTTPException(Exception): + """The base class for all HTTP exceptions. This exception can be called as a WSGI + application to render a default error page or you can catch the subclasses + of it independently and render nicer error messages. + + .. versionchanged:: 2.1 + Removed the ``wrap`` class method. + """ + + code: t.Optional[int] = None + description: t.Optional[str] = None + + def __init__( + self, + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + ) -> None: + super().__init__() + if description is not None: + self.description = description + self.response = response + + @property + def name(self) -> str: + """The status name.""" + from .http import HTTP_STATUS_CODES + + return HTTP_STATUS_CODES.get(self.code, "Unknown Error") # type: ignore + + def get_description( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> str: + """Get the description.""" + if self.description is None: + description = "" + elif not isinstance(self.description, str): + description = str(self.description) + else: + description = self.description + + description = escape(description).replace("\n", Markup("
    ")) + return f"

    {description}

    " + + def get_body( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> str: + """Get the HTML body.""" + return ( + "\n" + "\n" + f"{self.code} {escape(self.name)}\n" + f"

    {escape(self.name)}

    \n" + f"{self.get_description(environ)}\n" + ) + + def get_headers( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> t.List[t.Tuple[str, str]]: + """Get a list of headers.""" + return [("Content-Type", "text/html; charset=utf-8")] + + def get_response( + self, + environ: t.Optional[t.Union["WSGIEnvironment", "WSGIRequest"]] = None, + scope: t.Optional[dict] = None, + ) -> "Response": + """Get a response object. If one was passed to the exception + it's returned directly. + + :param environ: the optional environ for the request. This + can be used to modify the response depending + on how the request looked like. + :return: a :class:`Response` object or a subclass thereof. + """ + from .wrappers.response import Response as WSGIResponse # noqa: F811 + + if self.response is not None: + return self.response + if environ is not None: + environ = _get_environ(environ) + headers = self.get_headers(environ, scope) + return WSGIResponse(self.get_body(environ, scope), self.code, headers) + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + """Call the exception as WSGI application. + + :param environ: the WSGI environment. + :param start_response: the response callable provided by the WSGI + server. + """ + response = t.cast("WSGIResponse", self.get_response(environ)) + return response(environ, start_response) + + def __str__(self) -> str: + code = self.code if self.code is not None else "???" + return f"{code} {self.name}: {self.description}" + + def __repr__(self) -> str: + code = self.code if self.code is not None else "???" + return f"<{type(self).__name__} '{code}: {self.name}'>" + + +class BadRequest(HTTPException): + """*400* `Bad Request` + + Raise if the browser sends something to the application the application + or server cannot handle. + """ + + code = 400 + description = ( + "The browser (or proxy) sent a request that this server could " + "not understand." + ) + + +class BadRequestKeyError(BadRequest, KeyError): + """An exception that is used to signal both a :exc:`KeyError` and a + :exc:`BadRequest`. Used by many of the datastructures. + """ + + _description = BadRequest.description + #: Show the KeyError along with the HTTP error message in the + #: response. This should be disabled in production, but can be + #: useful in a debug mode. + show_exception = False + + def __init__(self, arg: t.Optional[str] = None, *args: t.Any, **kwargs: t.Any): + super().__init__(*args, **kwargs) + + if arg is None: + KeyError.__init__(self) + else: + KeyError.__init__(self, arg) + + @property # type: ignore + def description(self) -> str: # type: ignore + if self.show_exception: + return ( + f"{self._description}\n" + f"{KeyError.__name__}: {KeyError.__str__(self)}" + ) + + return self._description + + @description.setter + def description(self, value: str) -> None: + self._description = value + + +class ClientDisconnected(BadRequest): + """Internal exception that is raised if Werkzeug detects a disconnected + client. Since the client is already gone at that point attempting to + send the error message to the client might not work and might ultimately + result in another exception in the server. Mainly this is here so that + it is silenced by default as far as Werkzeug is concerned. + + Since disconnections cannot be reliably detected and are unspecified + by WSGI to a large extent this might or might not be raised if a client + is gone. + + .. versionadded:: 0.8 + """ + + +class SecurityError(BadRequest): + """Raised if something triggers a security error. This is otherwise + exactly like a bad request error. + + .. versionadded:: 0.9 + """ + + +class BadHost(BadRequest): + """Raised if the submitted host is badly formatted. + + .. versionadded:: 0.11.2 + """ + + +class Unauthorized(HTTPException): + """*401* ``Unauthorized`` + + Raise if the user is not authorized to access a resource. + + The ``www_authenticate`` argument should be used to set the + ``WWW-Authenticate`` header. This is used for HTTP basic auth and + other schemes. Use :class:`~werkzeug.datastructures.WWWAuthenticate` + to create correctly formatted values. Strictly speaking a 401 + response is invalid if it doesn't provide at least one value for + this header, although real clients typically don't care. + + :param description: Override the default message used for the body + of the response. + :param www-authenticate: A single value, or list of values, for the + WWW-Authenticate header(s). + + .. versionchanged:: 2.0 + Serialize multiple ``www_authenticate`` items into multiple + ``WWW-Authenticate`` headers, rather than joining them + into a single value, for better interoperability. + + .. versionchanged:: 0.15.3 + If the ``www_authenticate`` argument is not set, the + ``WWW-Authenticate`` header is not set. + + .. versionchanged:: 0.15.3 + The ``response`` argument was restored. + + .. versionchanged:: 0.15.1 + ``description`` was moved back as the first argument, restoring + its previous position. + + .. versionchanged:: 0.15.0 + ``www_authenticate`` was added as the first argument, ahead of + ``description``. + """ + + code = 401 + description = ( + "The server could not verify that you are authorized to access" + " the URL requested. You either supplied the wrong credentials" + " (e.g. a bad password), or your browser doesn't understand" + " how to supply the credentials required." + ) + + def __init__( + self, + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + www_authenticate: t.Optional[ + t.Union["WWWAuthenticate", t.Iterable["WWWAuthenticate"]] + ] = None, + ) -> None: + super().__init__(description, response) + + from .datastructures import WWWAuthenticate + + if isinstance(www_authenticate, WWWAuthenticate): + www_authenticate = (www_authenticate,) + + self.www_authenticate = www_authenticate + + def get_headers( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> t.List[t.Tuple[str, str]]: + headers = super().get_headers(environ, scope) + if self.www_authenticate: + headers.extend(("WWW-Authenticate", str(x)) for x in self.www_authenticate) + return headers + + +class Forbidden(HTTPException): + """*403* `Forbidden` + + Raise if the user doesn't have the permission for the requested resource + but was authenticated. + """ + + code = 403 + description = ( + "You don't have the permission to access the requested" + " resource. It is either read-protected or not readable by the" + " server." + ) + + +class NotFound(HTTPException): + """*404* `Not Found` + + Raise if a resource does not exist and never existed. + """ + + code = 404 + description = ( + "The requested URL was not found on the server. If you entered" + " the URL manually please check your spelling and try again." + ) + + +class MethodNotAllowed(HTTPException): + """*405* `Method Not Allowed` + + Raise if the server used a method the resource does not handle. For + example `POST` if the resource is view only. Especially useful for REST. + + The first argument for this exception should be a list of allowed methods. + Strictly speaking the response would be invalid if you don't provide valid + methods in the header which you can do with that list. + """ + + code = 405 + description = "The method is not allowed for the requested URL." + + def __init__( + self, + valid_methods: t.Optional[t.Iterable[str]] = None, + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + ) -> None: + """Takes an optional list of valid http methods + starting with werkzeug 0.3 the list will be mandatory.""" + super().__init__(description=description, response=response) + self.valid_methods = valid_methods + + def get_headers( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> t.List[t.Tuple[str, str]]: + headers = super().get_headers(environ, scope) + if self.valid_methods: + headers.append(("Allow", ", ".join(self.valid_methods))) + return headers + + +class NotAcceptable(HTTPException): + """*406* `Not Acceptable` + + Raise if the server can't return any content conforming to the + `Accept` headers of the client. + """ + + code = 406 + description = ( + "The resource identified by the request is only capable of" + " generating response entities which have content" + " characteristics not acceptable according to the accept" + " headers sent in the request." + ) + + +class RequestTimeout(HTTPException): + """*408* `Request Timeout` + + Raise to signalize a timeout. + """ + + code = 408 + description = ( + "The server closed the network connection because the browser" + " didn't finish the request within the specified time." + ) + + +class Conflict(HTTPException): + """*409* `Conflict` + + Raise to signal that a request cannot be completed because it conflicts + with the current state on the server. + + .. versionadded:: 0.7 + """ + + code = 409 + description = ( + "A conflict happened while processing the request. The" + " resource might have been modified while the request was being" + " processed." + ) + + +class Gone(HTTPException): + """*410* `Gone` + + Raise if a resource existed previously and went away without new location. + """ + + code = 410 + description = ( + "The requested URL is no longer available on this server and" + " there is no forwarding address. If you followed a link from a" + " foreign page, please contact the author of this page." + ) + + +class LengthRequired(HTTPException): + """*411* `Length Required` + + Raise if the browser submitted data but no ``Content-Length`` header which + is required for the kind of processing the server does. + """ + + code = 411 + description = ( + "A request with this method requires a valid Content-" + "Length header." + ) + + +class PreconditionFailed(HTTPException): + """*412* `Precondition Failed` + + Status code used in combination with ``If-Match``, ``If-None-Match``, or + ``If-Unmodified-Since``. + """ + + code = 412 + description = ( + "The precondition on the request for the URL failed positive evaluation." + ) + + +class RequestEntityTooLarge(HTTPException): + """*413* `Request Entity Too Large` + + The status code one should return if the data submitted exceeded a given + limit. + """ + + code = 413 + description = "The data value transmitted exceeds the capacity limit." + + +class RequestURITooLarge(HTTPException): + """*414* `Request URI Too Large` + + Like *413* but for too long URLs. + """ + + code = 414 + description = ( + "The length of the requested URL exceeds the capacity limit for" + " this server. The request cannot be processed." + ) + + +class UnsupportedMediaType(HTTPException): + """*415* `Unsupported Media Type` + + The status code returned if the server is unable to handle the media type + the client transmitted. + """ + + code = 415 + description = ( + "The server does not support the media type transmitted in the request." + ) + + +class RequestedRangeNotSatisfiable(HTTPException): + """*416* `Requested Range Not Satisfiable` + + The client asked for an invalid part of the file. + + .. versionadded:: 0.7 + """ + + code = 416 + description = "The server cannot provide the requested range." + + def __init__( + self, + length: t.Optional[int] = None, + units: str = "bytes", + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + ) -> None: + """Takes an optional `Content-Range` header value based on ``length`` + parameter. + """ + super().__init__(description=description, response=response) + self.length = length + self.units = units + + def get_headers( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> t.List[t.Tuple[str, str]]: + headers = super().get_headers(environ, scope) + if self.length is not None: + headers.append(("Content-Range", f"{self.units} */{self.length}")) + return headers + + +class ExpectationFailed(HTTPException): + """*417* `Expectation Failed` + + The server cannot meet the requirements of the Expect request-header. + + .. versionadded:: 0.7 + """ + + code = 417 + description = "The server could not meet the requirements of the Expect header" + + +class ImATeapot(HTTPException): + """*418* `I'm a teapot` + + The server should return this if it is a teapot and someone attempted + to brew coffee with it. + + .. versionadded:: 0.7 + """ + + code = 418 + description = "This server is a teapot, not a coffee machine" + + +class UnprocessableEntity(HTTPException): + """*422* `Unprocessable Entity` + + Used if the request is well formed, but the instructions are otherwise + incorrect. + """ + + code = 422 + description = ( + "The request was well-formed but was unable to be followed due" + " to semantic errors." + ) + + +class Locked(HTTPException): + """*423* `Locked` + + Used if the resource that is being accessed is locked. + """ + + code = 423 + description = "The resource that is being accessed is locked." + + +class FailedDependency(HTTPException): + """*424* `Failed Dependency` + + Used if the method could not be performed on the resource + because the requested action depended on another action and that action failed. + """ + + code = 424 + description = ( + "The method could not be performed on the resource because the" + " requested action depended on another action and that action" + " failed." + ) + + +class PreconditionRequired(HTTPException): + """*428* `Precondition Required` + + The server requires this request to be conditional, typically to prevent + the lost update problem, which is a race condition between two or more + clients attempting to update a resource through PUT or DELETE. By requiring + each client to include a conditional header ("If-Match" or "If-Unmodified- + Since") with the proper value retained from a recent GET request, the + server ensures that each client has at least seen the previous revision of + the resource. + """ + + code = 428 + description = ( + "This request is required to be conditional; try using" + ' "If-Match" or "If-Unmodified-Since".' + ) + + +class _RetryAfter(HTTPException): + """Adds an optional ``retry_after`` parameter which will set the + ``Retry-After`` header. May be an :class:`int` number of seconds or + a :class:`~datetime.datetime`. + """ + + def __init__( + self, + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + retry_after: t.Optional[t.Union[datetime, int]] = None, + ) -> None: + super().__init__(description, response) + self.retry_after = retry_after + + def get_headers( + self, + environ: t.Optional["WSGIEnvironment"] = None, + scope: t.Optional[dict] = None, + ) -> t.List[t.Tuple[str, str]]: + headers = super().get_headers(environ, scope) + + if self.retry_after: + if isinstance(self.retry_after, datetime): + from .http import http_date + + value = http_date(self.retry_after) + else: + value = str(self.retry_after) + + headers.append(("Retry-After", value)) + + return headers + + +class TooManyRequests(_RetryAfter): + """*429* `Too Many Requests` + + The server is limiting the rate at which this user receives + responses, and this request exceeds that rate. (The server may use + any convenient method to identify users and their request rates). + The server may include a "Retry-After" header to indicate how long + the user should wait before retrying. + + :param retry_after: If given, set the ``Retry-After`` header to this + value. May be an :class:`int` number of seconds or a + :class:`~datetime.datetime`. + + .. versionchanged:: 1.0 + Added ``retry_after`` parameter. + """ + + code = 429 + description = "This user has exceeded an allotted request count. Try again later." + + +class RequestHeaderFieldsTooLarge(HTTPException): + """*431* `Request Header Fields Too Large` + + The server refuses to process the request because the header fields are too + large. One or more individual fields may be too large, or the set of all + headers is too large. + """ + + code = 431 + description = "One or more header fields exceeds the maximum size." + + +class UnavailableForLegalReasons(HTTPException): + """*451* `Unavailable For Legal Reasons` + + This status code indicates that the server is denying access to the + resource as a consequence of a legal demand. + """ + + code = 451 + description = "Unavailable for legal reasons." + + +class InternalServerError(HTTPException): + """*500* `Internal Server Error` + + Raise if an internal server error occurred. This is a good fallback if an + unknown error occurred in the dispatcher. + + .. versionchanged:: 1.0.0 + Added the :attr:`original_exception` attribute. + """ + + code = 500 + description = ( + "The server encountered an internal error and was unable to" + " complete your request. Either the server is overloaded or" + " there is an error in the application." + ) + + def __init__( + self, + description: t.Optional[str] = None, + response: t.Optional["Response"] = None, + original_exception: t.Optional[BaseException] = None, + ) -> None: + #: The original exception that caused this 500 error. Can be + #: used by frameworks to provide context when handling + #: unexpected errors. + self.original_exception = original_exception + super().__init__(description=description, response=response) + + +class NotImplemented(HTTPException): + """*501* `Not Implemented` + + Raise if the application does not support the action requested by the + browser. + """ + + code = 501 + description = "The server does not support the action requested by the browser." + + +class BadGateway(HTTPException): + """*502* `Bad Gateway` + + If you do proxying in your application you should return this status code + if you received an invalid response from the upstream server it accessed + in attempting to fulfill the request. + """ + + code = 502 + description = ( + "The proxy server received an invalid response from an upstream server." + ) + + +class ServiceUnavailable(_RetryAfter): + """*503* `Service Unavailable` + + Status code you should return if a service is temporarily + unavailable. + + :param retry_after: If given, set the ``Retry-After`` header to this + value. May be an :class:`int` number of seconds or a + :class:`~datetime.datetime`. + + .. versionchanged:: 1.0 + Added ``retry_after`` parameter. + """ + + code = 503 + description = ( + "The server is temporarily unable to service your request due" + " to maintenance downtime or capacity problems. Please try" + " again later." + ) + + +class GatewayTimeout(HTTPException): + """*504* `Gateway Timeout` + + Status code you should return if a connection to an upstream server + times out. + """ + + code = 504 + description = "The connection to an upstream server timed out." + + +class HTTPVersionNotSupported(HTTPException): + """*505* `HTTP Version Not Supported` + + The server does not support the HTTP protocol version used in the request. + """ + + code = 505 + description = ( + "The server does not support the HTTP protocol version used in the request." + ) + + +default_exceptions: t.Dict[int, t.Type[HTTPException]] = {} + + +def _find_exceptions() -> None: + for obj in globals().values(): + try: + is_http_exception = issubclass(obj, HTTPException) + except TypeError: + is_http_exception = False + if not is_http_exception or obj.code is None: + continue + old_obj = default_exceptions.get(obj.code, None) + if old_obj is not None and issubclass(obj, old_obj): + continue + default_exceptions[obj.code] = obj + + +_find_exceptions() +del _find_exceptions + + +class Aborter: + """When passed a dict of code -> exception items it can be used as + callable that raises exceptions. If the first argument to the + callable is an integer it will be looked up in the mapping, if it's + a WSGI application it will be raised in a proxy exception. + + The rest of the arguments are forwarded to the exception constructor. + """ + + def __init__( + self, + mapping: t.Optional[t.Dict[int, t.Type[HTTPException]]] = None, + extra: t.Optional[t.Dict[int, t.Type[HTTPException]]] = None, + ) -> None: + if mapping is None: + mapping = default_exceptions + self.mapping = dict(mapping) + if extra is not None: + self.mapping.update(extra) + + def __call__( + self, code: t.Union[int, "Response"], *args: t.Any, **kwargs: t.Any + ) -> "te.NoReturn": + from .sansio.response import Response + + if isinstance(code, Response): + raise HTTPException(response=code) + + if code not in self.mapping: + raise LookupError(f"no exception for {code!r}") + + raise self.mapping[code](*args, **kwargs) + + +def abort( + status: t.Union[int, "Response"], *args: t.Any, **kwargs: t.Any +) -> "te.NoReturn": + """Raises an :py:exc:`HTTPException` for the given status code or WSGI + application. + + If a status code is given, it will be looked up in the list of + exceptions and will raise that exception. If passed a WSGI application, + it will wrap it in a proxy WSGI exception and raise that:: + + abort(404) # 404 Not Found + abort(Response('Hello World')) + + """ + _aborter(status, *args, **kwargs) + + +_aborter: Aborter = Aborter() diff --git a/.vcrunch/Lib/site-packages/werkzeug/formparser.py b/.vcrunch/Lib/site-packages/werkzeug/formparser.py new file mode 100644 index 0000000..10d58ca --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/formparser.py @@ -0,0 +1,455 @@ +import typing as t +from functools import update_wrapper +from io import BytesIO +from itertools import chain +from typing import Union + +from . import exceptions +from .datastructures import FileStorage +from .datastructures import Headers +from .datastructures import MultiDict +from .http import parse_options_header +from .sansio.multipart import Data +from .sansio.multipart import Epilogue +from .sansio.multipart import Field +from .sansio.multipart import File +from .sansio.multipart import MultipartDecoder +from .sansio.multipart import NeedData +from .urls import url_decode_stream +from .wsgi import _make_chunk_iter +from .wsgi import get_content_length +from .wsgi import get_input_stream + +# there are some platforms where SpooledTemporaryFile is not available. +# In that case we need to provide a fallback. +try: + from tempfile import SpooledTemporaryFile +except ImportError: + from tempfile import TemporaryFile + + SpooledTemporaryFile = None # type: ignore + +if t.TYPE_CHECKING: + import typing as te + from _typeshed.wsgi import WSGIEnvironment + + t_parse_result = t.Tuple[t.IO[bytes], MultiDict, MultiDict] + + class TStreamFactory(te.Protocol): + def __call__( + self, + total_content_length: t.Optional[int], + content_type: t.Optional[str], + filename: t.Optional[str], + content_length: t.Optional[int] = None, + ) -> t.IO[bytes]: + ... + + +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def _exhaust(stream: t.IO[bytes]) -> None: + bts = stream.read(64 * 1024) + while bts: + bts = stream.read(64 * 1024) + + +def default_stream_factory( + total_content_length: t.Optional[int], + content_type: t.Optional[str], + filename: t.Optional[str], + content_length: t.Optional[int] = None, +) -> t.IO[bytes]: + max_size = 1024 * 500 + + if SpooledTemporaryFile is not None: + return t.cast(t.IO[bytes], SpooledTemporaryFile(max_size=max_size, mode="rb+")) + elif total_content_length is None or total_content_length > max_size: + return t.cast(t.IO[bytes], TemporaryFile("rb+")) + + return BytesIO() + + +def parse_form_data( + environ: "WSGIEnvironment", + stream_factory: t.Optional["TStreamFactory"] = None, + charset: str = "utf-8", + errors: str = "replace", + max_form_memory_size: t.Optional[int] = None, + max_content_length: t.Optional[int] = None, + cls: t.Optional[t.Type[MultiDict]] = None, + silent: bool = True, +) -> "t_parse_result": + """Parse the form data in the environ and return it as tuple in the form + ``(stream, form, files)``. You should only call this method if the + transport method is `POST`, `PUT`, or `PATCH`. + + If the mimetype of the data transmitted is `multipart/form-data` the + files multidict will be filled with `FileStorage` objects. If the + mimetype is unknown the input stream is wrapped and returned as first + argument, else the stream is empty. + + This is a shortcut for the common usage of :class:`FormDataParser`. + + Have a look at :doc:`/request_data` for more details. + + .. versionadded:: 0.5 + The `max_form_memory_size`, `max_content_length` and + `cls` parameters were added. + + .. versionadded:: 0.5.1 + The optional `silent` flag was added. + + :param environ: the WSGI environment to be used for parsing. + :param stream_factory: An optional callable that returns a new read and + writeable file descriptor. This callable works + the same as :meth:`Response._get_file_stream`. + :param charset: The character set for URL and url encoded form data. + :param errors: The encoding error behavior. + :param max_form_memory_size: the maximum number of bytes to be accepted for + in-memory stored form data. If the data + exceeds the value specified an + :exc:`~exceptions.RequestEntityTooLarge` + exception is raised. + :param max_content_length: If this is provided and the transmitted data + is longer than this value an + :exc:`~exceptions.RequestEntityTooLarge` + exception is raised. + :param cls: an optional dict class to use. If this is not specified + or `None` the default :class:`MultiDict` is used. + :param silent: If set to False parsing errors will not be caught. + :return: A tuple in the form ``(stream, form, files)``. + """ + return FormDataParser( + stream_factory, + charset, + errors, + max_form_memory_size, + max_content_length, + cls, + silent, + ).parse_from_environ(environ) + + +def exhaust_stream(f: F) -> F: + """Helper decorator for methods that exhausts the stream on return.""" + + def wrapper(self, stream, *args, **kwargs): # type: ignore + try: + return f(self, stream, *args, **kwargs) + finally: + exhaust = getattr(stream, "exhaust", None) + + if exhaust is not None: + exhaust() + else: + while True: + chunk = stream.read(1024 * 64) + + if not chunk: + break + + return update_wrapper(t.cast(F, wrapper), f) + + +class FormDataParser: + """This class implements parsing of form data for Werkzeug. By itself + it can parse multipart and url encoded form data. It can be subclassed + and extended but for most mimetypes it is a better idea to use the + untouched stream and expose it as separate attributes on a request + object. + + .. versionadded:: 0.8 + + :param stream_factory: An optional callable that returns a new read and + writeable file descriptor. This callable works + the same as :meth:`Response._get_file_stream`. + :param charset: The character set for URL and url encoded form data. + :param errors: The encoding error behavior. + :param max_form_memory_size: the maximum number of bytes to be accepted for + in-memory stored form data. If the data + exceeds the value specified an + :exc:`~exceptions.RequestEntityTooLarge` + exception is raised. + :param max_content_length: If this is provided and the transmitted data + is longer than this value an + :exc:`~exceptions.RequestEntityTooLarge` + exception is raised. + :param cls: an optional dict class to use. If this is not specified + or `None` the default :class:`MultiDict` is used. + :param silent: If set to False parsing errors will not be caught. + """ + + def __init__( + self, + stream_factory: t.Optional["TStreamFactory"] = None, + charset: str = "utf-8", + errors: str = "replace", + max_form_memory_size: t.Optional[int] = None, + max_content_length: t.Optional[int] = None, + cls: t.Optional[t.Type[MultiDict]] = None, + silent: bool = True, + ) -> None: + if stream_factory is None: + stream_factory = default_stream_factory + + self.stream_factory = stream_factory + self.charset = charset + self.errors = errors + self.max_form_memory_size = max_form_memory_size + self.max_content_length = max_content_length + + if cls is None: + cls = MultiDict + + self.cls = cls + self.silent = silent + + def get_parse_func( + self, mimetype: str, options: t.Dict[str, str] + ) -> t.Optional[ + t.Callable[ + ["FormDataParser", t.IO[bytes], str, t.Optional[int], t.Dict[str, str]], + "t_parse_result", + ] + ]: + return self.parse_functions.get(mimetype) + + def parse_from_environ(self, environ: "WSGIEnvironment") -> "t_parse_result": + """Parses the information from the environment as form data. + + :param environ: the WSGI environment to be used for parsing. + :return: A tuple in the form ``(stream, form, files)``. + """ + content_type = environ.get("CONTENT_TYPE", "") + content_length = get_content_length(environ) + mimetype, options = parse_options_header(content_type) + return self.parse(get_input_stream(environ), mimetype, content_length, options) + + def parse( + self, + stream: t.IO[bytes], + mimetype: str, + content_length: t.Optional[int], + options: t.Optional[t.Dict[str, str]] = None, + ) -> "t_parse_result": + """Parses the information from the given stream, mimetype, + content length and mimetype parameters. + + :param stream: an input stream + :param mimetype: the mimetype of the data + :param content_length: the content length of the incoming data + :param options: optional mimetype parameters (used for + the multipart boundary for instance) + :return: A tuple in the form ``(stream, form, files)``. + """ + if ( + self.max_content_length is not None + and content_length is not None + and content_length > self.max_content_length + ): + # if the input stream is not exhausted, firefox reports Connection Reset + _exhaust(stream) + raise exceptions.RequestEntityTooLarge() + + if options is None: + options = {} + + parse_func = self.get_parse_func(mimetype, options) + + if parse_func is not None: + try: + return parse_func(self, stream, mimetype, content_length, options) + except ValueError: + if not self.silent: + raise + + return stream, self.cls(), self.cls() + + @exhaust_stream + def _parse_multipart( + self, + stream: t.IO[bytes], + mimetype: str, + content_length: t.Optional[int], + options: t.Dict[str, str], + ) -> "t_parse_result": + parser = MultiPartParser( + self.stream_factory, + self.charset, + self.errors, + max_form_memory_size=self.max_form_memory_size, + cls=self.cls, + ) + boundary = options.get("boundary", "").encode("ascii") + + if not boundary: + raise ValueError("Missing boundary") + + form, files = parser.parse(stream, boundary, content_length) + return stream, form, files + + @exhaust_stream + def _parse_urlencoded( + self, + stream: t.IO[bytes], + mimetype: str, + content_length: t.Optional[int], + options: t.Dict[str, str], + ) -> "t_parse_result": + if ( + self.max_form_memory_size is not None + and content_length is not None + and content_length > self.max_form_memory_size + ): + # if the input stream is not exhausted, firefox reports Connection Reset + _exhaust(stream) + raise exceptions.RequestEntityTooLarge() + + form = url_decode_stream(stream, self.charset, errors=self.errors, cls=self.cls) + return stream, form, self.cls() + + #: mapping of mimetypes to parsing functions + parse_functions: t.Dict[ + str, + t.Callable[ + ["FormDataParser", t.IO[bytes], str, t.Optional[int], t.Dict[str, str]], + "t_parse_result", + ], + ] = { + "multipart/form-data": _parse_multipart, + "application/x-www-form-urlencoded": _parse_urlencoded, + "application/x-url-encoded": _parse_urlencoded, + } + + +def _line_parse(line: str) -> t.Tuple[str, bool]: + """Removes line ending characters and returns a tuple (`stripped_line`, + `is_terminated`). + """ + if line[-2:] == "\r\n": + return line[:-2], True + + elif line[-1:] in {"\r", "\n"}: + return line[:-1], True + + return line, False + + +class MultiPartParser: + def __init__( + self, + stream_factory: t.Optional["TStreamFactory"] = None, + charset: str = "utf-8", + errors: str = "replace", + max_form_memory_size: t.Optional[int] = None, + cls: t.Optional[t.Type[MultiDict]] = None, + buffer_size: int = 64 * 1024, + ) -> None: + self.charset = charset + self.errors = errors + self.max_form_memory_size = max_form_memory_size + + if stream_factory is None: + stream_factory = default_stream_factory + + self.stream_factory = stream_factory + + if cls is None: + cls = MultiDict + + self.cls = cls + + self.buffer_size = buffer_size + + def fail(self, message: str) -> "te.NoReturn": + raise ValueError(message) + + def get_part_charset(self, headers: Headers) -> str: + # Figure out input charset for current part + content_type = headers.get("content-type") + + if content_type: + mimetype, ct_params = parse_options_header(content_type) + return ct_params.get("charset", self.charset) + + return self.charset + + def start_file_streaming( + self, event: File, total_content_length: t.Optional[int] + ) -> t.IO[bytes]: + content_type = event.headers.get("content-type") + + try: + content_length = int(event.headers["content-length"]) + except (KeyError, ValueError): + content_length = 0 + + container = self.stream_factory( + total_content_length=total_content_length, + filename=event.filename, + content_type=content_type, + content_length=content_length, + ) + return container + + def parse( + self, stream: t.IO[bytes], boundary: bytes, content_length: t.Optional[int] + ) -> t.Tuple[MultiDict, MultiDict]: + container: t.Union[t.IO[bytes], t.List[bytes]] + _write: t.Callable[[bytes], t.Any] + + iterator = chain( + _make_chunk_iter( + stream, + limit=content_length, + buffer_size=self.buffer_size, + ), + [None], + ) + + parser = MultipartDecoder(boundary, self.max_form_memory_size) + + fields = [] + files = [] + + current_part: Union[Field, File] + for data in iterator: + parser.receive_data(data) + event = parser.next_event() + while not isinstance(event, (Epilogue, NeedData)): + if isinstance(event, Field): + current_part = event + container = [] + _write = container.append + elif isinstance(event, File): + current_part = event + container = self.start_file_streaming(event, content_length) + _write = container.write + elif isinstance(event, Data): + _write(event.data) + if not event.more_data: + if isinstance(current_part, Field): + value = b"".join(container).decode( + self.get_part_charset(current_part.headers), self.errors + ) + fields.append((current_part.name, value)) + else: + container = t.cast(t.IO[bytes], container) + container.seek(0) + files.append( + ( + current_part.name, + FileStorage( + container, + current_part.filename, + current_part.name, + headers=current_part.headers, + ), + ) + ) + + event = parser.next_event() + + return self.cls(fields), self.cls(files) diff --git a/.vcrunch/Lib/site-packages/werkzeug/http.py b/.vcrunch/Lib/site-packages/werkzeug/http.py new file mode 100644 index 0000000..9777685 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/http.py @@ -0,0 +1,1311 @@ +import base64 +import email.utils +import re +import typing +import typing as t +import warnings +from datetime import date +from datetime import datetime +from datetime import time +from datetime import timedelta +from datetime import timezone +from enum import Enum +from hashlib import sha1 +from time import mktime +from time import struct_time +from urllib.parse import unquote_to_bytes as _unquote +from urllib.request import parse_http_list as _parse_list_header + +from ._internal import _cookie_quote +from ._internal import _dt_as_utc +from ._internal import _make_cookie_domain +from ._internal import _to_bytes +from ._internal import _to_str +from ._internal import _wsgi_decoding_dance + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIEnvironment + +# for explanation of "media-range", etc. see Sections 5.3.{1,2} of RFC 7231 +_accept_re = re.compile( + r""" + ( # media-range capturing-parenthesis + [^\s;,]+ # type/subtype + (?:[ \t]*;[ \t]* # ";" + (?: # parameter non-capturing-parenthesis + [^\s;,q][^\s;,]* # token that doesn't start with "q" + | # or + q[^\s;,=][^\s;,]* # token that is more than just "q" + ) + )* # zero or more parameters + ) # end of media-range + (?:[ \t]*;[ \t]*q= # weight is a "q" parameter + (\d*(?:\.\d+)?) # qvalue capturing-parentheses + [^,]* # "extension" accept params: who cares? + )? # accept params are optional + """, + re.VERBOSE, +) +_token_chars = frozenset( + "!#$%&'*+-.0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ^_`abcdefghijklmnopqrstuvwxyz|~" +) +_etag_re = re.compile(r'([Ww]/)?(?:"(.*?)"|(.*?))(?:\s*,\s*|$)') +_option_header_piece_re = re.compile( + r""" + ;\s*,?\s* # newlines were replaced with commas + (?P + "[^"\\]*(?:\\.[^"\\]*)*" # quoted string + | + [^\s;,=*]+ # token + ) + (?:\*(?P\d+))? # *1, optional continuation index + \s* + (?: # optionally followed by =value + (?: # equals sign, possibly with encoding + \*\s*=\s* # * indicates extended notation + (?: # optional encoding + (?P[^\s]+?) + '(?P[^\s]*?)' + )? + | + =\s* # basic notation + ) + (?P + "[^"\\]*(?:\\.[^"\\]*)*" # quoted string + | + [^;,]+ # token + )? + )? + \s* + """, + flags=re.VERBOSE, +) +_option_header_start_mime_type = re.compile(r",\s*([^;,\s]+)([;,]\s*.+)?") +_entity_headers = frozenset( + [ + "allow", + "content-encoding", + "content-language", + "content-length", + "content-location", + "content-md5", + "content-range", + "content-type", + "expires", + "last-modified", + ] +) +_hop_by_hop_headers = frozenset( + [ + "connection", + "keep-alive", + "proxy-authenticate", + "proxy-authorization", + "te", + "trailer", + "transfer-encoding", + "upgrade", + ] +) +HTTP_STATUS_CODES = { + 100: "Continue", + 101: "Switching Protocols", + 102: "Processing", + 103: "Early Hints", # see RFC 8297 + 200: "OK", + 201: "Created", + 202: "Accepted", + 203: "Non Authoritative Information", + 204: "No Content", + 205: "Reset Content", + 206: "Partial Content", + 207: "Multi Status", + 208: "Already Reported", # see RFC 5842 + 226: "IM Used", # see RFC 3229 + 300: "Multiple Choices", + 301: "Moved Permanently", + 302: "Found", + 303: "See Other", + 304: "Not Modified", + 305: "Use Proxy", + 306: "Switch Proxy", # unused + 307: "Temporary Redirect", + 308: "Permanent Redirect", + 400: "Bad Request", + 401: "Unauthorized", + 402: "Payment Required", # unused + 403: "Forbidden", + 404: "Not Found", + 405: "Method Not Allowed", + 406: "Not Acceptable", + 407: "Proxy Authentication Required", + 408: "Request Timeout", + 409: "Conflict", + 410: "Gone", + 411: "Length Required", + 412: "Precondition Failed", + 413: "Request Entity Too Large", + 414: "Request URI Too Long", + 415: "Unsupported Media Type", + 416: "Requested Range Not Satisfiable", + 417: "Expectation Failed", + 418: "I'm a teapot", # see RFC 2324 + 421: "Misdirected Request", # see RFC 7540 + 422: "Unprocessable Entity", + 423: "Locked", + 424: "Failed Dependency", + 425: "Too Early", # see RFC 8470 + 426: "Upgrade Required", + 428: "Precondition Required", # see RFC 6585 + 429: "Too Many Requests", + 431: "Request Header Fields Too Large", + 449: "Retry With", # proprietary MS extension + 451: "Unavailable For Legal Reasons", + 500: "Internal Server Error", + 501: "Not Implemented", + 502: "Bad Gateway", + 503: "Service Unavailable", + 504: "Gateway Timeout", + 505: "HTTP Version Not Supported", + 506: "Variant Also Negotiates", # see RFC 2295 + 507: "Insufficient Storage", + 508: "Loop Detected", # see RFC 5842 + 510: "Not Extended", + 511: "Network Authentication Failed", +} + + +class COEP(Enum): + """Cross Origin Embedder Policies""" + + UNSAFE_NONE = "unsafe-none" + REQUIRE_CORP = "require-corp" + + +class COOP(Enum): + """Cross Origin Opener Policies""" + + UNSAFE_NONE = "unsafe-none" + SAME_ORIGIN_ALLOW_POPUPS = "same-origin-allow-popups" + SAME_ORIGIN = "same-origin" + + +def quote_header_value( + value: t.Union[str, int], extra_chars: str = "", allow_token: bool = True +) -> str: + """Quote a header value if necessary. + + .. versionadded:: 0.5 + + :param value: the value to quote. + :param extra_chars: a list of extra characters to skip quoting. + :param allow_token: if this is enabled token values are returned + unchanged. + """ + if isinstance(value, bytes): + value = value.decode("latin1") + value = str(value) + if allow_token: + token_chars = _token_chars | set(extra_chars) + if set(value).issubset(token_chars): + return value + value = value.replace("\\", "\\\\").replace('"', '\\"') + return f'"{value}"' + + +def unquote_header_value(value: str, is_filename: bool = False) -> str: + r"""Unquotes a header value. (Reversal of :func:`quote_header_value`). + This does not use the real unquoting but what browsers are actually + using for quoting. + + .. versionadded:: 0.5 + + :param value: the header value to unquote. + :param is_filename: The value represents a filename or path. + """ + if value and value[0] == value[-1] == '"': + # this is not the real unquoting, but fixing this so that the + # RFC is met will result in bugs with internet explorer and + # probably some other browsers as well. IE for example is + # uploading files with "C:\foo\bar.txt" as filename + value = value[1:-1] + + # if this is a filename and the starting characters look like + # a UNC path, then just return the value without quotes. Using the + # replace sequence below on a UNC path has the effect of turning + # the leading double slash into a single slash and then + # _fix_ie_filename() doesn't work correctly. See #458. + if not is_filename or value[:2] != "\\\\": + return value.replace("\\\\", "\\").replace('\\"', '"') + return value + + +def dump_options_header( + header: t.Optional[str], options: t.Mapping[str, t.Optional[t.Union[str, int]]] +) -> str: + """The reverse function to :func:`parse_options_header`. + + :param header: the header to dump + :param options: a dict of options to append. + """ + segments = [] + if header is not None: + segments.append(header) + for key, value in options.items(): + if value is None: + segments.append(key) + else: + segments.append(f"{key}={quote_header_value(value)}") + return "; ".join(segments) + + +def dump_header( + iterable: t.Union[t.Dict[str, t.Union[str, int]], t.Iterable[str]], + allow_token: bool = True, +) -> str: + """Dump an HTTP header again. This is the reversal of + :func:`parse_list_header`, :func:`parse_set_header` and + :func:`parse_dict_header`. This also quotes strings that include an + equals sign unless you pass it as dict of key, value pairs. + + >>> dump_header({'foo': 'bar baz'}) + 'foo="bar baz"' + >>> dump_header(('foo', 'bar baz')) + 'foo, "bar baz"' + + :param iterable: the iterable or dict of values to quote. + :param allow_token: if set to `False` tokens as values are disallowed. + See :func:`quote_header_value` for more details. + """ + if isinstance(iterable, dict): + items = [] + for key, value in iterable.items(): + if value is None: + items.append(key) + else: + items.append( + f"{key}={quote_header_value(value, allow_token=allow_token)}" + ) + else: + items = [quote_header_value(x, allow_token=allow_token) for x in iterable] + return ", ".join(items) + + +def dump_csp_header(header: "ds.ContentSecurityPolicy") -> str: + """Dump a Content Security Policy header. + + These are structured into policies such as "default-src 'self'; + script-src 'self'". + + .. versionadded:: 1.0.0 + Support for Content Security Policy headers was added. + + """ + return "; ".join(f"{key} {value}" for key, value in header.items()) + + +def parse_list_header(value: str) -> t.List[str]: + """Parse lists as described by RFC 2068 Section 2. + + In particular, parse comma-separated lists where the elements of + the list may include quoted-strings. A quoted-string could + contain a comma. A non-quoted string could have quotes in the + middle. Quotes are removed automatically after parsing. + + It basically works like :func:`parse_set_header` just that items + may appear multiple times and case sensitivity is preserved. + + The return value is a standard :class:`list`: + + >>> parse_list_header('token, "quoted value"') + ['token', 'quoted value'] + + To create a header from the :class:`list` again, use the + :func:`dump_header` function. + + :param value: a string with a list header. + :return: :class:`list` + """ + result = [] + for item in _parse_list_header(value): + if item[:1] == item[-1:] == '"': + item = unquote_header_value(item[1:-1]) + result.append(item) + return result + + +def parse_dict_header(value: str, cls: t.Type[dict] = dict) -> t.Dict[str, str]: + """Parse lists of key, value pairs as described by RFC 2068 Section 2 and + convert them into a python dict (or any other mapping object created from + the type with a dict like interface provided by the `cls` argument): + + >>> d = parse_dict_header('foo="is a fish", bar="as well"') + >>> type(d) is dict + True + >>> sorted(d.items()) + [('bar', 'as well'), ('foo', 'is a fish')] + + If there is no value for a key it will be `None`: + + >>> parse_dict_header('key_without_value') + {'key_without_value': None} + + To create a header from the :class:`dict` again, use the + :func:`dump_header` function. + + .. versionchanged:: 0.9 + Added support for `cls` argument. + + :param value: a string with a dict header. + :param cls: callable to use for storage of parsed results. + :return: an instance of `cls` + """ + result = cls() + if isinstance(value, bytes): + value = value.decode("latin1") + for item in _parse_list_header(value): + if "=" not in item: + result[item] = None + continue + name, value = item.split("=", 1) + if value[:1] == value[-1:] == '"': + value = unquote_header_value(value[1:-1]) + result[name] = value + return result + + +def parse_options_header(value: t.Optional[str]) -> t.Tuple[str, t.Dict[str, str]]: + """Parse a ``Content-Type``-like header into a tuple with the + value and any options: + + >>> parse_options_header('text/html; charset=utf8') + ('text/html', {'charset': 'utf8'}) + + This should is not for ``Cache-Control``-like headers, which use a + different format. For those, use :func:`parse_dict_header`. + + :param value: The header value to parse. + + .. versionchanged:: 2.2 + Option names are always converted to lowercase. + + .. versionchanged:: 2.1 + The ``multiple`` parameter is deprecated and will be removed in + Werkzeug 2.2. + + .. versionchanged:: 0.15 + :rfc:`2231` parameter continuations are handled. + + .. versionadded:: 0.5 + """ + if not value: + return "", {} + + result: t.List[t.Any] = [] + + value = "," + value.replace("\n", ",") + while value: + match = _option_header_start_mime_type.match(value) + if not match: + break + result.append(match.group(1)) # mimetype + options: t.Dict[str, str] = {} + # Parse options + rest = match.group(2) + encoding: t.Optional[str] + continued_encoding: t.Optional[str] = None + while rest: + optmatch = _option_header_piece_re.match(rest) + if not optmatch: + break + option, count, encoding, language, option_value = optmatch.groups() + # Continuations don't have to supply the encoding after the + # first line. If we're in a continuation, track the current + # encoding to use for subsequent lines. Reset it when the + # continuation ends. + if not count: + continued_encoding = None + else: + if not encoding: + encoding = continued_encoding + continued_encoding = encoding + option = unquote_header_value(option).lower() + + if option_value is not None: + option_value = unquote_header_value(option_value, option == "filename") + + if encoding is not None: + option_value = _unquote(option_value).decode(encoding) + + if count: + # Continuations append to the existing value. For + # simplicity, this ignores the possibility of + # out-of-order indices, which shouldn't happen anyway. + if option_value is not None: + options[option] = options.get(option, "") + option_value + else: + options[option] = option_value # type: ignore[assignment] + + rest = rest[optmatch.end() :] + result.append(options) + return tuple(result) # type: ignore[return-value] + + return tuple(result) if result else ("", {}) # type: ignore[return-value] + + +_TAnyAccept = t.TypeVar("_TAnyAccept", bound="ds.Accept") + + +@typing.overload +def parse_accept_header(value: t.Optional[str]) -> "ds.Accept": + ... + + +@typing.overload +def parse_accept_header( + value: t.Optional[str], cls: t.Type[_TAnyAccept] +) -> _TAnyAccept: + ... + + +def parse_accept_header( + value: t.Optional[str], cls: t.Optional[t.Type[_TAnyAccept]] = None +) -> _TAnyAccept: + """Parses an HTTP Accept-* header. This does not implement a complete + valid algorithm but one that supports at least value and quality + extraction. + + Returns a new :class:`Accept` object (basically a list of ``(value, quality)`` + tuples sorted by the quality with some additional accessor methods). + + The second parameter can be a subclass of :class:`Accept` that is created + with the parsed values and returned. + + :param value: the accept header string to be parsed. + :param cls: the wrapper class for the return value (can be + :class:`Accept` or a subclass thereof) + :return: an instance of `cls`. + """ + if cls is None: + cls = t.cast(t.Type[_TAnyAccept], ds.Accept) + + if not value: + return cls(None) + + result = [] + for match in _accept_re.finditer(value): + quality_match = match.group(2) + if not quality_match: + quality: float = 1 + else: + quality = max(min(float(quality_match), 1), 0) + result.append((match.group(1), quality)) + return cls(result) + + +_TAnyCC = t.TypeVar("_TAnyCC", bound="ds._CacheControl") +_t_cc_update = t.Optional[t.Callable[[_TAnyCC], None]] + + +@typing.overload +def parse_cache_control_header( + value: t.Optional[str], on_update: _t_cc_update, cls: None = None +) -> "ds.RequestCacheControl": + ... + + +@typing.overload +def parse_cache_control_header( + value: t.Optional[str], on_update: _t_cc_update, cls: t.Type[_TAnyCC] +) -> _TAnyCC: + ... + + +def parse_cache_control_header( + value: t.Optional[str], + on_update: _t_cc_update = None, + cls: t.Optional[t.Type[_TAnyCC]] = None, +) -> _TAnyCC: + """Parse a cache control header. The RFC differs between response and + request cache control, this method does not. It's your responsibility + to not use the wrong control statements. + + .. versionadded:: 0.5 + The `cls` was added. If not specified an immutable + :class:`~werkzeug.datastructures.RequestCacheControl` is returned. + + :param value: a cache control header to be parsed. + :param on_update: an optional callable that is called every time a value + on the :class:`~werkzeug.datastructures.CacheControl` + object is changed. + :param cls: the class for the returned object. By default + :class:`~werkzeug.datastructures.RequestCacheControl` is used. + :return: a `cls` object. + """ + if cls is None: + cls = t.cast(t.Type[_TAnyCC], ds.RequestCacheControl) + + if not value: + return cls((), on_update) + + return cls(parse_dict_header(value), on_update) + + +_TAnyCSP = t.TypeVar("_TAnyCSP", bound="ds.ContentSecurityPolicy") +_t_csp_update = t.Optional[t.Callable[[_TAnyCSP], None]] + + +@typing.overload +def parse_csp_header( + value: t.Optional[str], on_update: _t_csp_update, cls: None = None +) -> "ds.ContentSecurityPolicy": + ... + + +@typing.overload +def parse_csp_header( + value: t.Optional[str], on_update: _t_csp_update, cls: t.Type[_TAnyCSP] +) -> _TAnyCSP: + ... + + +def parse_csp_header( + value: t.Optional[str], + on_update: _t_csp_update = None, + cls: t.Optional[t.Type[_TAnyCSP]] = None, +) -> _TAnyCSP: + """Parse a Content Security Policy header. + + .. versionadded:: 1.0.0 + Support for Content Security Policy headers was added. + + :param value: a csp header to be parsed. + :param on_update: an optional callable that is called every time a value + on the object is changed. + :param cls: the class for the returned object. By default + :class:`~werkzeug.datastructures.ContentSecurityPolicy` is used. + :return: a `cls` object. + """ + if cls is None: + cls = t.cast(t.Type[_TAnyCSP], ds.ContentSecurityPolicy) + + if value is None: + return cls((), on_update) + + items = [] + + for policy in value.split(";"): + policy = policy.strip() + + # Ignore badly formatted policies (no space) + if " " in policy: + directive, value = policy.strip().split(" ", 1) + items.append((directive.strip(), value.strip())) + + return cls(items, on_update) + + +def parse_set_header( + value: t.Optional[str], + on_update: t.Optional[t.Callable[["ds.HeaderSet"], None]] = None, +) -> "ds.HeaderSet": + """Parse a set-like header and return a + :class:`~werkzeug.datastructures.HeaderSet` object: + + >>> hs = parse_set_header('token, "quoted value"') + + The return value is an object that treats the items case-insensitively + and keeps the order of the items: + + >>> 'TOKEN' in hs + True + >>> hs.index('quoted value') + 1 + >>> hs + HeaderSet(['token', 'quoted value']) + + To create a header from the :class:`HeaderSet` again, use the + :func:`dump_header` function. + + :param value: a set header to be parsed. + :param on_update: an optional callable that is called every time a + value on the :class:`~werkzeug.datastructures.HeaderSet` + object is changed. + :return: a :class:`~werkzeug.datastructures.HeaderSet` + """ + if not value: + return ds.HeaderSet(None, on_update) + return ds.HeaderSet(parse_list_header(value), on_update) + + +def parse_authorization_header( + value: t.Optional[str], +) -> t.Optional["ds.Authorization"]: + """Parse an HTTP basic/digest authorization header transmitted by the web + browser. The return value is either `None` if the header was invalid or + not given, otherwise an :class:`~werkzeug.datastructures.Authorization` + object. + + :param value: the authorization header to parse. + :return: a :class:`~werkzeug.datastructures.Authorization` object or `None`. + """ + if not value: + return None + value = _wsgi_decoding_dance(value) + try: + auth_type, auth_info = value.split(None, 1) + auth_type = auth_type.lower() + except ValueError: + return None + if auth_type == "basic": + try: + username, password = base64.b64decode(auth_info).split(b":", 1) + except Exception: + return None + try: + return ds.Authorization( + "basic", + { + "username": _to_str(username, "utf-8"), + "password": _to_str(password, "utf-8"), + }, + ) + except UnicodeDecodeError: + return None + elif auth_type == "digest": + auth_map = parse_dict_header(auth_info) + for key in "username", "realm", "nonce", "uri", "response": + if key not in auth_map: + return None + if "qop" in auth_map: + if not auth_map.get("nc") or not auth_map.get("cnonce"): + return None + return ds.Authorization("digest", auth_map) + return None + + +def parse_www_authenticate_header( + value: t.Optional[str], + on_update: t.Optional[t.Callable[["ds.WWWAuthenticate"], None]] = None, +) -> "ds.WWWAuthenticate": + """Parse an HTTP WWW-Authenticate header into a + :class:`~werkzeug.datastructures.WWWAuthenticate` object. + + :param value: a WWW-Authenticate header to parse. + :param on_update: an optional callable that is called every time a value + on the :class:`~werkzeug.datastructures.WWWAuthenticate` + object is changed. + :return: a :class:`~werkzeug.datastructures.WWWAuthenticate` object. + """ + if not value: + return ds.WWWAuthenticate(on_update=on_update) + try: + auth_type, auth_info = value.split(None, 1) + auth_type = auth_type.lower() + except (ValueError, AttributeError): + return ds.WWWAuthenticate(value.strip().lower(), on_update=on_update) + return ds.WWWAuthenticate(auth_type, parse_dict_header(auth_info), on_update) + + +def parse_if_range_header(value: t.Optional[str]) -> "ds.IfRange": + """Parses an if-range header which can be an etag or a date. Returns + a :class:`~werkzeug.datastructures.IfRange` object. + + .. versionchanged:: 2.0 + If the value represents a datetime, it is timezone-aware. + + .. versionadded:: 0.7 + """ + if not value: + return ds.IfRange() + date = parse_date(value) + if date is not None: + return ds.IfRange(date=date) + # drop weakness information + return ds.IfRange(unquote_etag(value)[0]) + + +def parse_range_header( + value: t.Optional[str], make_inclusive: bool = True +) -> t.Optional["ds.Range"]: + """Parses a range header into a :class:`~werkzeug.datastructures.Range` + object. If the header is missing or malformed `None` is returned. + `ranges` is a list of ``(start, stop)`` tuples where the ranges are + non-inclusive. + + .. versionadded:: 0.7 + """ + if not value or "=" not in value: + return None + + ranges = [] + last_end = 0 + units, rng = value.split("=", 1) + units = units.strip().lower() + + for item in rng.split(","): + item = item.strip() + if "-" not in item: + return None + if item.startswith("-"): + if last_end < 0: + return None + try: + begin = int(item) + except ValueError: + return None + end = None + last_end = -1 + elif "-" in item: + begin_str, end_str = item.split("-", 1) + begin_str = begin_str.strip() + end_str = end_str.strip() + + try: + begin = int(begin_str) + except ValueError: + return None + + if begin < last_end or last_end < 0: + return None + if end_str: + try: + end = int(end_str) + 1 + except ValueError: + return None + + if begin >= end: + return None + else: + end = None + last_end = end if end is not None else -1 + ranges.append((begin, end)) + + return ds.Range(units, ranges) + + +def parse_content_range_header( + value: t.Optional[str], + on_update: t.Optional[t.Callable[["ds.ContentRange"], None]] = None, +) -> t.Optional["ds.ContentRange"]: + """Parses a range header into a + :class:`~werkzeug.datastructures.ContentRange` object or `None` if + parsing is not possible. + + .. versionadded:: 0.7 + + :param value: a content range header to be parsed. + :param on_update: an optional callable that is called every time a value + on the :class:`~werkzeug.datastructures.ContentRange` + object is changed. + """ + if value is None: + return None + try: + units, rangedef = (value or "").strip().split(None, 1) + except ValueError: + return None + + if "/" not in rangedef: + return None + rng, length_str = rangedef.split("/", 1) + if length_str == "*": + length = None + else: + try: + length = int(length_str) + except ValueError: + return None + + if rng == "*": + return ds.ContentRange(units, None, None, length, on_update=on_update) + elif "-" not in rng: + return None + + start_str, stop_str = rng.split("-", 1) + try: + start = int(start_str) + stop = int(stop_str) + 1 + except ValueError: + return None + + if is_byte_range_valid(start, stop, length): + return ds.ContentRange(units, start, stop, length, on_update=on_update) + + return None + + +def quote_etag(etag: str, weak: bool = False) -> str: + """Quote an etag. + + :param etag: the etag to quote. + :param weak: set to `True` to tag it "weak". + """ + if '"' in etag: + raise ValueError("invalid etag") + etag = f'"{etag}"' + if weak: + etag = f"W/{etag}" + return etag + + +def unquote_etag( + etag: t.Optional[str], +) -> t.Union[t.Tuple[str, bool], t.Tuple[None, None]]: + """Unquote a single etag: + + >>> unquote_etag('W/"bar"') + ('bar', True) + >>> unquote_etag('"bar"') + ('bar', False) + + :param etag: the etag identifier to unquote. + :return: a ``(etag, weak)`` tuple. + """ + if not etag: + return None, None + etag = etag.strip() + weak = False + if etag.startswith(("W/", "w/")): + weak = True + etag = etag[2:] + if etag[:1] == etag[-1:] == '"': + etag = etag[1:-1] + return etag, weak + + +def parse_etags(value: t.Optional[str]) -> "ds.ETags": + """Parse an etag header. + + :param value: the tag header to parse + :return: an :class:`~werkzeug.datastructures.ETags` object. + """ + if not value: + return ds.ETags() + strong = [] + weak = [] + end = len(value) + pos = 0 + while pos < end: + match = _etag_re.match(value, pos) + if match is None: + break + is_weak, quoted, raw = match.groups() + if raw == "*": + return ds.ETags(star_tag=True) + elif quoted: + raw = quoted + if is_weak: + weak.append(raw) + else: + strong.append(raw) + pos = match.end() + return ds.ETags(strong, weak) + + +def generate_etag(data: bytes) -> str: + """Generate an etag for some data. + + .. versionchanged:: 2.0 + Use SHA-1. MD5 may not be available in some environments. + """ + return sha1(data).hexdigest() + + +def parse_date(value: t.Optional[str]) -> t.Optional[datetime]: + """Parse an :rfc:`2822` date into a timezone-aware + :class:`datetime.datetime` object, or ``None`` if parsing fails. + + This is a wrapper for :func:`email.utils.parsedate_to_datetime`. It + returns ``None`` if parsing fails instead of raising an exception, + and always returns a timezone-aware datetime object. If the string + doesn't have timezone information, it is assumed to be UTC. + + :param value: A string with a supported date format. + + .. versionchanged:: 2.0 + Return a timezone-aware datetime object. Use + ``email.utils.parsedate_to_datetime``. + """ + if value is None: + return None + + try: + dt = email.utils.parsedate_to_datetime(value) + except (TypeError, ValueError): + return None + + if dt.tzinfo is None: + return dt.replace(tzinfo=timezone.utc) + + return dt + + +def http_date( + timestamp: t.Optional[t.Union[datetime, date, int, float, struct_time]] = None +) -> str: + """Format a datetime object or timestamp into an :rfc:`2822` date + string. + + This is a wrapper for :func:`email.utils.format_datetime`. It + assumes naive datetime objects are in UTC instead of raising an + exception. + + :param timestamp: The datetime or timestamp to format. Defaults to + the current time. + + .. versionchanged:: 2.0 + Use ``email.utils.format_datetime``. Accept ``date`` objects. + """ + if isinstance(timestamp, date): + if not isinstance(timestamp, datetime): + # Assume plain date is midnight UTC. + timestamp = datetime.combine(timestamp, time(), tzinfo=timezone.utc) + else: + # Ensure datetime is timezone-aware. + timestamp = _dt_as_utc(timestamp) + + return email.utils.format_datetime(timestamp, usegmt=True) + + if isinstance(timestamp, struct_time): + timestamp = mktime(timestamp) + + return email.utils.formatdate(timestamp, usegmt=True) + + +def parse_age(value: t.Optional[str] = None) -> t.Optional[timedelta]: + """Parses a base-10 integer count of seconds into a timedelta. + + If parsing fails, the return value is `None`. + + :param value: a string consisting of an integer represented in base-10 + :return: a :class:`datetime.timedelta` object or `None`. + """ + if not value: + return None + try: + seconds = int(value) + except ValueError: + return None + if seconds < 0: + return None + try: + return timedelta(seconds=seconds) + except OverflowError: + return None + + +def dump_age(age: t.Optional[t.Union[timedelta, int]] = None) -> t.Optional[str]: + """Formats the duration as a base-10 integer. + + :param age: should be an integer number of seconds, + a :class:`datetime.timedelta` object, or, + if the age is unknown, `None` (default). + """ + if age is None: + return None + if isinstance(age, timedelta): + age = int(age.total_seconds()) + else: + age = int(age) + + if age < 0: + raise ValueError("age cannot be negative") + + return str(age) + + +def is_resource_modified( + environ: "WSGIEnvironment", + etag: t.Optional[str] = None, + data: t.Optional[bytes] = None, + last_modified: t.Optional[t.Union[datetime, str]] = None, + ignore_if_range: bool = True, +) -> bool: + """Convenience method for conditional requests. + + :param environ: the WSGI environment of the request to be checked. + :param etag: the etag for the response for comparison. + :param data: or alternatively the data of the response to automatically + generate an etag using :func:`generate_etag`. + :param last_modified: an optional date of the last modification. + :param ignore_if_range: If `False`, `If-Range` header will be taken into + account. + :return: `True` if the resource was modified, otherwise `False`. + + .. versionchanged:: 2.0 + SHA-1 is used to generate an etag value for the data. MD5 may + not be available in some environments. + + .. versionchanged:: 1.0.0 + The check is run for methods other than ``GET`` and ``HEAD``. + """ + return _sansio_http.is_resource_modified( + http_range=environ.get("HTTP_RANGE"), + http_if_range=environ.get("HTTP_IF_RANGE"), + http_if_modified_since=environ.get("HTTP_IF_MODIFIED_SINCE"), + http_if_none_match=environ.get("HTTP_IF_NONE_MATCH"), + http_if_match=environ.get("HTTP_IF_MATCH"), + etag=etag, + data=data, + last_modified=last_modified, + ignore_if_range=ignore_if_range, + ) + + +def remove_entity_headers( + headers: t.Union["ds.Headers", t.List[t.Tuple[str, str]]], + allowed: t.Iterable[str] = ("expires", "content-location"), +) -> None: + """Remove all entity headers from a list or :class:`Headers` object. This + operation works in-place. `Expires` and `Content-Location` headers are + by default not removed. The reason for this is :rfc:`2616` section + 10.3.5 which specifies some entity headers that should be sent. + + .. versionchanged:: 0.5 + added `allowed` parameter. + + :param headers: a list or :class:`Headers` object. + :param allowed: a list of headers that should still be allowed even though + they are entity headers. + """ + allowed = {x.lower() for x in allowed} + headers[:] = [ + (key, value) + for key, value in headers + if not is_entity_header(key) or key.lower() in allowed + ] + + +def remove_hop_by_hop_headers( + headers: t.Union["ds.Headers", t.List[t.Tuple[str, str]]] +) -> None: + """Remove all HTTP/1.1 "Hop-by-Hop" headers from a list or + :class:`Headers` object. This operation works in-place. + + .. versionadded:: 0.5 + + :param headers: a list or :class:`Headers` object. + """ + headers[:] = [ + (key, value) for key, value in headers if not is_hop_by_hop_header(key) + ] + + +def is_entity_header(header: str) -> bool: + """Check if a header is an entity header. + + .. versionadded:: 0.5 + + :param header: the header to test. + :return: `True` if it's an entity header, `False` otherwise. + """ + return header.lower() in _entity_headers + + +def is_hop_by_hop_header(header: str) -> bool: + """Check if a header is an HTTP/1.1 "Hop-by-Hop" header. + + .. versionadded:: 0.5 + + :param header: the header to test. + :return: `True` if it's an HTTP/1.1 "Hop-by-Hop" header, `False` otherwise. + """ + return header.lower() in _hop_by_hop_headers + + +def parse_cookie( + header: t.Union["WSGIEnvironment", str, bytes, None], + charset: str = "utf-8", + errors: str = "replace", + cls: t.Optional[t.Type["ds.MultiDict"]] = None, +) -> "ds.MultiDict[str, str]": + """Parse a cookie from a string or WSGI environ. + + The same key can be provided multiple times, the values are stored + in-order. The default :class:`MultiDict` will have the first value + first, and all values can be retrieved with + :meth:`MultiDict.getlist`. + + :param header: The cookie header as a string, or a WSGI environ dict + with a ``HTTP_COOKIE`` key. + :param charset: The charset for the cookie values. + :param errors: The error behavior for the charset decoding. + :param cls: A dict-like class to store the parsed cookies in. + Defaults to :class:`MultiDict`. + + .. versionchanged:: 1.0.0 + Returns a :class:`MultiDict` instead of a + ``TypeConversionDict``. + + .. versionchanged:: 0.5 + Returns a :class:`TypeConversionDict` instead of a regular dict. + The ``cls`` parameter was added. + """ + if isinstance(header, dict): + cookie = header.get("HTTP_COOKIE", "") + elif header is None: + cookie = "" + else: + cookie = header + + return _sansio_http.parse_cookie( + cookie=cookie, charset=charset, errors=errors, cls=cls + ) + + +def dump_cookie( + key: str, + value: t.Union[bytes, str] = "", + max_age: t.Optional[t.Union[timedelta, int]] = None, + expires: t.Optional[t.Union[str, datetime, int, float]] = None, + path: t.Optional[str] = "/", + domain: t.Optional[str] = None, + secure: bool = False, + httponly: bool = False, + charset: str = "utf-8", + sync_expires: bool = True, + max_size: int = 4093, + samesite: t.Optional[str] = None, +) -> str: + """Create a Set-Cookie header without the ``Set-Cookie`` prefix. + + The return value is usually restricted to ascii as the vast majority + of values are properly escaped, but that is no guarantee. It's + tunneled through latin1 as required by :pep:`3333`. + + The return value is not ASCII safe if the key contains unicode + characters. This is technically against the specification but + happens in the wild. It's strongly recommended to not use + non-ASCII values for the keys. + + :param max_age: should be a number of seconds, or `None` (default) if + the cookie should last only as long as the client's + browser session. Additionally `timedelta` objects + are accepted, too. + :param expires: should be a `datetime` object or unix timestamp. + :param path: limits the cookie to a given path, per default it will + span the whole domain. + :param domain: Use this if you want to set a cross-domain cookie. For + example, ``domain=".example.com"`` will set a cookie + that is readable by the domain ``www.example.com``, + ``foo.example.com`` etc. Otherwise, a cookie will only + be readable by the domain that set it. + :param secure: The cookie will only be available via HTTPS + :param httponly: disallow JavaScript to access the cookie. This is an + extension to the cookie standard and probably not + supported by all browsers. + :param charset: the encoding for string values. + :param sync_expires: automatically set expires if max_age is defined + but expires not. + :param max_size: Warn if the final header value exceeds this size. The + default, 4093, should be safely `supported by most browsers + `_. Set to 0 to disable this check. + :param samesite: Limits the scope of the cookie such that it will + only be attached to requests if those requests are same-site. + + .. _`cookie`: http://browsercookielimits.squawky.net/ + + .. versionchanged:: 1.0.0 + The string ``'None'`` is accepted for ``samesite``. + """ + key = _to_bytes(key, charset) + value = _to_bytes(value, charset) + + if path is not None: + from .urls import iri_to_uri + + path = iri_to_uri(path, charset) + + domain = _make_cookie_domain(domain) + + if isinstance(max_age, timedelta): + max_age = int(max_age.total_seconds()) + + if expires is not None: + if not isinstance(expires, str): + expires = http_date(expires) + elif max_age is not None and sync_expires: + expires = http_date(datetime.now(tz=timezone.utc).timestamp() + max_age) + + if samesite is not None: + samesite = samesite.title() + + if samesite not in {"Strict", "Lax", "None"}: + raise ValueError("SameSite must be 'Strict', 'Lax', or 'None'.") + + buf = [key + b"=" + _cookie_quote(value)] + + # XXX: In theory all of these parameters that are not marked with `None` + # should be quoted. Because stdlib did not quote it before I did not + # want to introduce quoting there now. + for k, v, q in ( + (b"Domain", domain, True), + (b"Expires", expires, False), + (b"Max-Age", max_age, False), + (b"Secure", secure, None), + (b"HttpOnly", httponly, None), + (b"Path", path, False), + (b"SameSite", samesite, False), + ): + if q is None: + if v: + buf.append(k) + continue + + if v is None: + continue + + tmp = bytearray(k) + if not isinstance(v, (bytes, bytearray)): + v = _to_bytes(str(v), charset) + if q: + v = _cookie_quote(v) + tmp += b"=" + v + buf.append(bytes(tmp)) + + # The return value will be an incorrectly encoded latin1 header for + # consistency with the headers object. + rv = b"; ".join(buf) + rv = rv.decode("latin1") + + # Warn if the final value of the cookie is larger than the limit. If the + # cookie is too large, then it may be silently ignored by the browser, + # which can be quite hard to debug. + cookie_size = len(rv) + + if max_size and cookie_size > max_size: + value_size = len(value) + warnings.warn( + f"The {key.decode(charset)!r} cookie is too large: the value was" + f" {value_size} bytes but the" + f" header required {cookie_size - value_size} extra bytes. The final size" + f" was {cookie_size} bytes but the limit is {max_size} bytes. Browsers may" + f" silently ignore cookies larger than this.", + stacklevel=2, + ) + + return rv + + +def is_byte_range_valid( + start: t.Optional[int], stop: t.Optional[int], length: t.Optional[int] +) -> bool: + """Checks if a given byte content range is valid for the given length. + + .. versionadded:: 0.7 + """ + if (start is None) != (stop is None): + return False + elif start is None: + return length is None or length >= 0 + elif length is None: + return 0 <= start < stop # type: ignore + elif start >= stop: # type: ignore + return False + return 0 <= start < length + + +# circular dependencies +from . import datastructures as ds +from .sansio import http as _sansio_http diff --git a/.vcrunch/Lib/site-packages/werkzeug/local.py b/.vcrunch/Lib/site-packages/werkzeug/local.py new file mode 100644 index 0000000..70e9bf7 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/local.py @@ -0,0 +1,648 @@ +import copy +import math +import operator +import typing as t +from contextvars import ContextVar +from functools import partial +from functools import update_wrapper +from operator import attrgetter + +from .wsgi import ClosingIterator + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + +T = t.TypeVar("T") +F = t.TypeVar("F", bound=t.Callable[..., t.Any]) + + +def release_local(local: t.Union["Local", "LocalStack"]) -> None: + """Release the data for the current context in a :class:`Local` or + :class:`LocalStack` without using a :class:`LocalManager`. + + This should not be needed for modern use cases, and may be removed + in the future. + + .. versionadded:: 0.6.1 + """ + local.__release_local__() + + +class Local: + """Create a namespace of context-local data. This wraps a + :class:`ContextVar` containing a :class:`dict` value. + + This may incur a performance penalty compared to using individual + context vars, as it has to copy data to avoid mutating the dict + between nested contexts. + + :param context_var: The :class:`~contextvars.ContextVar` to use as + storage for this local. If not given, one will be created. + Context vars not created at the global scope may interfere with + garbage collection. + + .. versionchanged:: 2.0 + Uses ``ContextVar`` instead of a custom storage implementation. + """ + + __slots__ = ("__storage",) + + def __init__( + self, context_var: t.Optional[ContextVar[t.Dict[str, t.Any]]] = None + ) -> None: + if context_var is None: + # A ContextVar not created at global scope interferes with + # Python's garbage collection. However, a local only makes + # sense defined at the global scope as well, in which case + # the GC issue doesn't seem relevant. + context_var = ContextVar(f"werkzeug.Local<{id(self)}>.storage") + + object.__setattr__(self, "_Local__storage", context_var) + + def __iter__(self) -> t.Iterator[t.Tuple[str, t.Any]]: + return iter(self.__storage.get({}).items()) + + def __call__( + self, name: str, *, unbound_message: t.Optional[str] = None + ) -> "LocalProxy": + """Create a :class:`LocalProxy` that access an attribute on this + local namespace. + + :param name: Proxy this attribute. + :param unbound_message: The error message that the proxy will + show if the attribute isn't set. + """ + return LocalProxy(self, name, unbound_message=unbound_message) + + def __release_local__(self) -> None: + self.__storage.set({}) + + def __getattr__(self, name: str) -> t.Any: + values = self.__storage.get({}) + + if name in values: + return values[name] + + raise AttributeError(name) + + def __setattr__(self, name: str, value: t.Any) -> None: + values = self.__storage.get({}).copy() + values[name] = value + self.__storage.set(values) + + def __delattr__(self, name: str) -> None: + values = self.__storage.get({}) + + if name in values: + values = values.copy() + del values[name] + self.__storage.set(values) + else: + raise AttributeError(name) + + +class LocalStack(t.Generic[T]): + """Create a stack of context-local data. This wraps a + :class:`ContextVar` containing a :class:`list` value. + + This may incur a performance penalty compared to using individual + context vars, as it has to copy data to avoid mutating the list + between nested contexts. + + :param context_var: The :class:`~contextvars.ContextVar` to use as + storage for this local. If not given, one will be created. + Context vars not created at the global scope may interfere with + garbage collection. + + .. versionchanged:: 2.0 + Uses ``ContextVar`` instead of a custom storage implementation. + + .. versionadded:: 0.6.1 + """ + + __slots__ = ("_storage",) + + def __init__(self, context_var: t.Optional[ContextVar[t.List[T]]] = None) -> None: + if context_var is None: + # A ContextVar not created at global scope interferes with + # Python's garbage collection. However, a local only makes + # sense defined at the global scope as well, in which case + # the GC issue doesn't seem relevant. + context_var = ContextVar(f"werkzeug.LocalStack<{id(self)}>.storage") + + self._storage = context_var + + def __release_local__(self) -> None: + self._storage.set([]) + + def push(self, obj: T) -> t.List[T]: + """Add a new item to the top of the stack.""" + stack = self._storage.get([]).copy() + stack.append(obj) + self._storage.set(stack) + return stack + + def pop(self) -> t.Optional[T]: + """Remove the top item from the stack and return it. If the + stack is empty, return ``None``. + """ + stack = self._storage.get([]) + + if len(stack) == 0: + return None + + rv = stack[-1] + self._storage.set(stack[:-1]) + return rv + + @property + def top(self) -> t.Optional[T]: + """The topmost item on the stack. If the stack is empty, + `None` is returned. + """ + stack = self._storage.get([]) + + if len(stack) == 0: + return None + + return stack[-1] + + def __call__( + self, name: t.Optional[str] = None, *, unbound_message: t.Optional[str] = None + ) -> "LocalProxy": + """Create a :class:`LocalProxy` that accesses the top of this + local stack. + + :param name: If given, the proxy access this attribute of the + top item, rather than the item itself. + :param unbound_message: The error message that the proxy will + show if the stack is empty. + """ + return LocalProxy(self, name, unbound_message=unbound_message) + + +class LocalManager: + """Manage releasing the data for the current context in one or more + :class:`Local` and :class:`LocalStack` objects. + + This should not be needed for modern use cases, and may be removed + in the future. + + :param locals: A local or list of locals to manage. + + .. versionchanged:: 2.0 + ``ident_func`` is deprecated and will be removed in Werkzeug + 2.1. + + .. versionchanged:: 0.7 + The ``ident_func`` parameter was added. + + .. versionchanged:: 0.6.1 + The :func:`release_local` function can be used instead of a + manager. + """ + + __slots__ = ("locals",) + + def __init__( + self, + locals: t.Optional[ + t.Union[Local, LocalStack, t.Iterable[t.Union[Local, LocalStack]]] + ] = None, + ) -> None: + if locals is None: + self.locals = [] + elif isinstance(locals, Local): + self.locals = [locals] + else: + self.locals = list(locals) # type: ignore[arg-type] + + def cleanup(self) -> None: + """Release the data in the locals for this context. Call this at + the end of each request or use :meth:`make_middleware`. + """ + for local in self.locals: + release_local(local) + + def make_middleware(self, app: "WSGIApplication") -> "WSGIApplication": + """Wrap a WSGI application so that local data is released + automatically after the response has been sent for a request. + """ + + def application( + environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + return ClosingIterator(app(environ, start_response), self.cleanup) + + return application + + def middleware(self, func: "WSGIApplication") -> "WSGIApplication": + """Like :meth:`make_middleware` but used as a decorator on the + WSGI application function. + + .. code-block:: python + + @manager.middleware + def application(environ, start_response): + ... + """ + return update_wrapper(self.make_middleware(func), func) + + def __repr__(self) -> str: + return f"<{type(self).__name__} storages: {len(self.locals)}>" + + +class _ProxyLookup: + """Descriptor that handles proxied attribute lookup for + :class:`LocalProxy`. + + :param f: The built-in function this attribute is accessed through. + Instead of looking up the special method, the function call + is redone on the object. + :param fallback: Return this function if the proxy is unbound + instead of raising a :exc:`RuntimeError`. + :param is_attr: This proxied name is an attribute, not a function. + Call the fallback immediately to get the value. + :param class_value: Value to return when accessed from the + ``LocalProxy`` class directly. Used for ``__doc__`` so building + docs still works. + """ + + __slots__ = ("bind_f", "fallback", "is_attr", "class_value", "name") + + def __init__( + self, + f: t.Optional[t.Callable] = None, + fallback: t.Optional[t.Callable] = None, + class_value: t.Optional[t.Any] = None, + is_attr: bool = False, + ) -> None: + bind_f: t.Optional[t.Callable[["LocalProxy", t.Any], t.Callable]] + + if hasattr(f, "__get__"): + # A Python function, can be turned into a bound method. + + def bind_f(instance: "LocalProxy", obj: t.Any) -> t.Callable: + return f.__get__(obj, type(obj)) # type: ignore + + elif f is not None: + # A C function, use partial to bind the first argument. + + def bind_f(instance: "LocalProxy", obj: t.Any) -> t.Callable: + return partial(f, obj) # type: ignore + + else: + # Use getattr, which will produce a bound method. + bind_f = None + + self.bind_f = bind_f + self.fallback = fallback + self.class_value = class_value + self.is_attr = is_attr + + def __set_name__(self, owner: "LocalProxy", name: str) -> None: + self.name = name + + def __get__(self, instance: "LocalProxy", owner: t.Optional[type] = None) -> t.Any: + if instance is None: + if self.class_value is not None: + return self.class_value + + return self + + try: + obj = instance._get_current_object() # type: ignore[misc] + except RuntimeError: + if self.fallback is None: + raise + + fallback = self.fallback.__get__(instance, owner) + + if self.is_attr: + # __class__ and __doc__ are attributes, not methods. + # Call the fallback to get the value. + return fallback() + + return fallback + + if self.bind_f is not None: + return self.bind_f(instance, obj) + + return getattr(obj, self.name) + + def __repr__(self) -> str: + return f"proxy {self.name}" + + def __call__(self, instance: "LocalProxy", *args: t.Any, **kwargs: t.Any) -> t.Any: + """Support calling unbound methods from the class. For example, + this happens with ``copy.copy``, which does + ``type(x).__copy__(x)``. ``type(x)`` can't be proxied, so it + returns the proxy type and descriptor. + """ + return self.__get__(instance, type(instance))(*args, **kwargs) + + +class _ProxyIOp(_ProxyLookup): + """Look up an augmented assignment method on a proxied object. The + method is wrapped to return the proxy instead of the object. + """ + + __slots__ = () + + def __init__( + self, f: t.Optional[t.Callable] = None, fallback: t.Optional[t.Callable] = None + ) -> None: + super().__init__(f, fallback) + + def bind_f(instance: "LocalProxy", obj: t.Any) -> t.Callable: + def i_op(self: t.Any, other: t.Any) -> "LocalProxy": + f(self, other) # type: ignore + return instance + + return i_op.__get__(obj, type(obj)) # type: ignore + + self.bind_f = bind_f + + +def _l_to_r_op(op: F) -> F: + """Swap the argument order to turn an l-op into an r-op.""" + + def r_op(obj: t.Any, other: t.Any) -> t.Any: + return op(other, obj) + + return t.cast(F, r_op) + + +def _identity(o: T) -> T: + return o + + +class LocalProxy(t.Generic[T]): + """A proxy to the object bound to a context-local object. All + operations on the proxy are forwarded to the bound object. If no + object is bound, a ``RuntimeError`` is raised. + + :param local: The context-local object that provides the proxied + object. + :param name: Proxy this attribute from the proxied object. + :param unbound_message: The error message to show if the + context-local object is unbound. + + Proxy a :class:`~contextvars.ContextVar` to make it easier to + access. Pass a name to proxy that attribute. + + .. code-block:: python + + _request_var = ContextVar("request") + request = LocalProxy(_request_var) + session = LocalProxy(_request_var, "session") + + Proxy an attribute on a :class:`Local` namespace by calling the + local with the attribute name: + + .. code-block:: python + + data = Local() + user = data("user") + + Proxy the top item on a :class:`LocalStack` by calling the local. + Pass a name to proxy that attribute. + + .. code-block:: + + app_stack = LocalStack() + current_app = app_stack() + g = app_stack("g") + + Pass a function to proxy the return value from that function. This + was previously used to access attributes of local objects before + that was supported directly. + + .. code-block:: python + + session = LocalProxy(lambda: request.session) + + ``__repr__`` and ``__class__`` are proxied, so ``repr(x)`` and + ``isinstance(x, cls)`` will look like the proxied object. Use + ``issubclass(type(x), LocalProxy)`` to check if an object is a + proxy. + + .. code-block:: python + + repr(user) # + isinstance(user, User) # True + issubclass(type(user), LocalProxy) # True + + .. versionchanged:: 2.2.2 + ``__wrapped__`` is set when wrapping an object, not only when + wrapping a function, to prevent doctest from failing. + + .. versionchanged:: 2.2 + Can proxy a ``ContextVar`` or ``LocalStack`` directly. + + .. versionchanged:: 2.2 + The ``name`` parameter can be used with any proxied object, not + only ``Local``. + + .. versionchanged:: 2.2 + Added the ``unbound_message`` parameter. + + .. versionchanged:: 2.0 + Updated proxied attributes and methods to reflect the current + data model. + + .. versionchanged:: 0.6.1 + The class can be instantiated with a callable. + """ + + __slots__ = ("__wrapped", "_get_current_object") + + _get_current_object: t.Callable[[], T] + """Return the current object this proxy is bound to. If the proxy is + unbound, this raises a ``RuntimeError``. + + This should be used if you need to pass the object to something that + doesn't understand the proxy. It can also be useful for performance + if you are accessing the object multiple times in a function, rather + than going through the proxy multiple times. + """ + + def __init__( + self, + local: t.Union[ContextVar[T], Local, LocalStack[T], t.Callable[[], T]], + name: t.Optional[str] = None, + *, + unbound_message: t.Optional[str] = None, + ) -> None: + if name is None: + get_name = _identity + else: + get_name = attrgetter(name) # type: ignore[assignment] + + if unbound_message is None: + unbound_message = "object is not bound" + + if isinstance(local, Local): + if name is None: + raise TypeError("'name' is required when proxying a 'Local' object.") + + def _get_current_object() -> T: + try: + return get_name(local) # type: ignore[return-value] + except AttributeError: + raise RuntimeError(unbound_message) from None + + elif isinstance(local, LocalStack): + + def _get_current_object() -> T: + obj = local.top # type: ignore[union-attr] + + if obj is None: + raise RuntimeError(unbound_message) + + return get_name(obj) + + elif isinstance(local, ContextVar): + + def _get_current_object() -> T: + try: + obj = local.get() # type: ignore[union-attr] + except LookupError: + raise RuntimeError(unbound_message) from None + + return get_name(obj) + + elif callable(local): + + def _get_current_object() -> T: + return get_name(local()) # type: ignore + + else: + raise TypeError(f"Don't know how to proxy '{type(local)}'.") + + object.__setattr__(self, "_LocalProxy__wrapped", local) + object.__setattr__(self, "_get_current_object", _get_current_object) + + __doc__ = _ProxyLookup( # type: ignore + class_value=__doc__, fallback=lambda self: type(self).__doc__, is_attr=True + ) + __wrapped__ = _ProxyLookup( + fallback=lambda self: self._LocalProxy__wrapped, is_attr=True + ) + # __del__ should only delete the proxy + __repr__ = _ProxyLookup( # type: ignore + repr, fallback=lambda self: f"<{type(self).__name__} unbound>" + ) + __str__ = _ProxyLookup(str) # type: ignore + __bytes__ = _ProxyLookup(bytes) + __format__ = _ProxyLookup() # type: ignore + __lt__ = _ProxyLookup(operator.lt) + __le__ = _ProxyLookup(operator.le) + __eq__ = _ProxyLookup(operator.eq) # type: ignore + __ne__ = _ProxyLookup(operator.ne) # type: ignore + __gt__ = _ProxyLookup(operator.gt) + __ge__ = _ProxyLookup(operator.ge) + __hash__ = _ProxyLookup(hash) # type: ignore + __bool__ = _ProxyLookup(bool, fallback=lambda self: False) + __getattr__ = _ProxyLookup(getattr) + # __getattribute__ triggered through __getattr__ + __setattr__ = _ProxyLookup(setattr) # type: ignore + __delattr__ = _ProxyLookup(delattr) # type: ignore + __dir__ = _ProxyLookup(dir, fallback=lambda self: []) # type: ignore + # __get__ (proxying descriptor not supported) + # __set__ (descriptor) + # __delete__ (descriptor) + # __set_name__ (descriptor) + # __objclass__ (descriptor) + # __slots__ used by proxy itself + # __dict__ (__getattr__) + # __weakref__ (__getattr__) + # __init_subclass__ (proxying metaclass not supported) + # __prepare__ (metaclass) + __class__ = _ProxyLookup( + fallback=lambda self: type(self), is_attr=True + ) # type: ignore + __instancecheck__ = _ProxyLookup(lambda self, other: isinstance(other, self)) + __subclasscheck__ = _ProxyLookup(lambda self, other: issubclass(other, self)) + # __class_getitem__ triggered through __getitem__ + __call__ = _ProxyLookup(lambda self, *args, **kwargs: self(*args, **kwargs)) + __len__ = _ProxyLookup(len) + __length_hint__ = _ProxyLookup(operator.length_hint) + __getitem__ = _ProxyLookup(operator.getitem) + __setitem__ = _ProxyLookup(operator.setitem) + __delitem__ = _ProxyLookup(operator.delitem) + # __missing__ triggered through __getitem__ + __iter__ = _ProxyLookup(iter) + __next__ = _ProxyLookup(next) + __reversed__ = _ProxyLookup(reversed) + __contains__ = _ProxyLookup(operator.contains) + __add__ = _ProxyLookup(operator.add) + __sub__ = _ProxyLookup(operator.sub) + __mul__ = _ProxyLookup(operator.mul) + __matmul__ = _ProxyLookup(operator.matmul) + __truediv__ = _ProxyLookup(operator.truediv) + __floordiv__ = _ProxyLookup(operator.floordiv) + __mod__ = _ProxyLookup(operator.mod) + __divmod__ = _ProxyLookup(divmod) + __pow__ = _ProxyLookup(pow) + __lshift__ = _ProxyLookup(operator.lshift) + __rshift__ = _ProxyLookup(operator.rshift) + __and__ = _ProxyLookup(operator.and_) + __xor__ = _ProxyLookup(operator.xor) + __or__ = _ProxyLookup(operator.or_) + __radd__ = _ProxyLookup(_l_to_r_op(operator.add)) + __rsub__ = _ProxyLookup(_l_to_r_op(operator.sub)) + __rmul__ = _ProxyLookup(_l_to_r_op(operator.mul)) + __rmatmul__ = _ProxyLookup(_l_to_r_op(operator.matmul)) + __rtruediv__ = _ProxyLookup(_l_to_r_op(operator.truediv)) + __rfloordiv__ = _ProxyLookup(_l_to_r_op(operator.floordiv)) + __rmod__ = _ProxyLookup(_l_to_r_op(operator.mod)) + __rdivmod__ = _ProxyLookup(_l_to_r_op(divmod)) + __rpow__ = _ProxyLookup(_l_to_r_op(pow)) + __rlshift__ = _ProxyLookup(_l_to_r_op(operator.lshift)) + __rrshift__ = _ProxyLookup(_l_to_r_op(operator.rshift)) + __rand__ = _ProxyLookup(_l_to_r_op(operator.and_)) + __rxor__ = _ProxyLookup(_l_to_r_op(operator.xor)) + __ror__ = _ProxyLookup(_l_to_r_op(operator.or_)) + __iadd__ = _ProxyIOp(operator.iadd) + __isub__ = _ProxyIOp(operator.isub) + __imul__ = _ProxyIOp(operator.imul) + __imatmul__ = _ProxyIOp(operator.imatmul) + __itruediv__ = _ProxyIOp(operator.itruediv) + __ifloordiv__ = _ProxyIOp(operator.ifloordiv) + __imod__ = _ProxyIOp(operator.imod) + __ipow__ = _ProxyIOp(operator.ipow) + __ilshift__ = _ProxyIOp(operator.ilshift) + __irshift__ = _ProxyIOp(operator.irshift) + __iand__ = _ProxyIOp(operator.iand) + __ixor__ = _ProxyIOp(operator.ixor) + __ior__ = _ProxyIOp(operator.ior) + __neg__ = _ProxyLookup(operator.neg) + __pos__ = _ProxyLookup(operator.pos) + __abs__ = _ProxyLookup(abs) + __invert__ = _ProxyLookup(operator.invert) + __complex__ = _ProxyLookup(complex) + __int__ = _ProxyLookup(int) + __float__ = _ProxyLookup(float) + __index__ = _ProxyLookup(operator.index) + __round__ = _ProxyLookup(round) + __trunc__ = _ProxyLookup(math.trunc) + __floor__ = _ProxyLookup(math.floor) + __ceil__ = _ProxyLookup(math.ceil) + __enter__ = _ProxyLookup() + __exit__ = _ProxyLookup() + __await__ = _ProxyLookup() + __aiter__ = _ProxyLookup() + __anext__ = _ProxyLookup() + __aenter__ = _ProxyLookup() + __aexit__ = _ProxyLookup() + __copy__ = _ProxyLookup(copy.copy) + __deepcopy__ = _ProxyLookup(copy.deepcopy) + # __getnewargs_ex__ (pickle through proxy not supported) + # __getnewargs__ (pickle) + # __getstate__ (pickle) + # __setstate__ (pickle) + # __reduce__ (pickle) + # __reduce_ex__ (pickle) diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/__init__.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/__init__.py new file mode 100644 index 0000000..6ddcf7f --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/__init__.py @@ -0,0 +1,22 @@ +""" +Middleware +========== + +A WSGI middleware is a WSGI application that wraps another application +in order to observe or change its behavior. Werkzeug provides some +middleware for common use cases. + +.. toctree:: + :maxdepth: 1 + + proxy_fix + shared_data + dispatcher + http_proxy + lint + profiler + +The :doc:`interactive debugger ` is also a middleware that can +be applied manually, although it is typically used automatically with +the :doc:`development server `. +""" diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..8b322b88478e4749c79a7dbda8cb65c83512182f GIT binary patch literal 690 zcmYjPO^XyU5bfEELty_yT^Fi43me$K^tFjl?fFD-e|)z?ZdZmO#b{KbTL zZ?zt1kCDWS#}MKb+}^x-3*#dTHUU0>7{Xu`X6qefgBkV_1GCO&LlMqsVIBCW8O$Dh zmniOt0Z;~APhfL`jtuUsk2TyfEEks@O z@hV56rV+r=jCjx#vT5MCC5 zwszo6;*%k0v{%iBIf|&VWnr4Ssqb0r^{S-nO)+gqo}D|BQ9M)VL`M&1k%kf7gu`%r z3OHorr{1tTb9+7p_L`YlvId;8AKCf`Xm7I-Z2D;!O*1^59Z_ui^zihqCWHUVrsP3?* j)b3AzZS`N^N=oZ&ma-1V`{niM^)%3WeuZhia#{TYMOfd* literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/dispatcher.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..444131565c6cf80240ae71588ca7278721406c17 GIT binary patch literal 2774 zcmZ`*TW{M&7UoSCGqMvD!4~NS8000Z!cmI$VFC4mx=uEBHgOHh?V?%(#E3Jpm{KG& zGqR&rerlfg4-^H`$Nq@^5x(}Re<9em`<To13A7=l7qE;_I0G zOpEo$$Kn&bdJltehK_KBm%2kwdXIheCRTnLOdG?7OD6&5&0*8d8<@9-E!Vm4h^A;g zb42S~Z`c;z!0ER6mx1GiJ4KNuF*iw`vAc;bxQQoHg&)203B%(_qS-VNB9-S{Nfs-~ zjns@Yon)t}Wd9!A-)DSHsF`rXL@ik}lZVq;YLWuPxq+@fu|PpS%ZwDva*oGR$;`0N zj~+6ZH_^Q?++lG(ox)`Klut<#tU6bTfekQaP?>VbPbFLPZ=0P%on-TT#wPqsG9He2 z{FTfE+c|{M_;NN@IaFgx;xJ)J#vbr9K8RIP7*=_c!(*7vR6Zk>A!ukhQu(=tLkd>n z1KNx!`D7-wHB2P6D+Mgmq-tvUz;h;555biy{qX2AsC&nc9$Nbz4A?kR7IdD*enw;y<*y?11_d;4;c+F zk7(y69U@@%XlW0*Vcn`CNS0zrMx|+$>u?zk-S3AX!vneOqcz|?x`fu>ty58*k8Spi zWgwhPi)hWi;SR4!&QVSU@8V49px3^J^ZJ0YfB8#wMM! z(fp5Y0T{g=<1>@TDc8u$E0Yn1{Wve?isIF0@4fr(KiDCXDvb{NXdg1uvd=yp+`aw& z?cJ2mvr~P|NeiXnUgltbwMtAwqFQbVL(W8#27% z;A~TDJqw0cY(uUj|yH zdtQ8J+0F$lC>O2I|r$ z=Td$3wVa*aS>1YfYOm0=i+S0Oq9jX96ul2s8kefmY;3t-zkRp9^wbJXy_&Xc$qMg^ z7|JcwuQHKZmWd+QUy27+08!d_{1=mj``rE!_`$pIg?AAMf8n1w>YatZa2~suy-weS zf5W+GJb7>7Kli9ke(+8}f6)YW^E+n|eCK@c*Sxwz9M2sq!H3+2)zJ_h=B-6*;lB>8 zqVXa4@OAM8#lriR{!TOxh8u@F$9vKK!9PDMofqz%Ur;yB@XBEKX#emyI@o!1uN##9 zsWdiMNV-M|8JnwaThU)2wMD~K3}sW>`*yfN07Q6ki%^<}8)#A{LV~8l>p9v{lJPXE zXrqizrA>D=bVv?z6QfZ@(Fa)Rw=i`4z-@b>8@ir*&D(O@FRryaUdL@?=Pz?s$xs{M z?{-Ki>58HGGr%MIw)}?V7UvSwVLWPs`wL5}VT3MyX9}-oBBF zk5XASMsxg+Qh&qlnhykCMUJQjhAv)x6GPhxT(1-S>UrL8ule4uUJ(AzYkRKuJH2gh z>$i%2L%jj&vT5c83Q)aCi_PON5AQ|0d-rz#wSRDbxE0}0>WLJ+bA6gv;MwZ5xU^zk aWl!1uuyXuk%Ce@!1x}ka5lH&I=KmikJu-X% literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/http_proxy.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e3e34fb9de2fd77539e567a6adefc9eb64a2e86a GIT binary patch literal 6865 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/middleware/__pycache__/shared_data.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..d9cacb2b8e1cc9b05ba62c6b7c76cf7e25669c16 GIT binary patch literal 9148 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 Sla|2e;LkBG==tn<%KRVh&!7VU literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/dispatcher.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/dispatcher.py new file mode 100644 index 0000000..ace1c75 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/dispatcher.py @@ -0,0 +1,78 @@ +""" +Application Dispatcher +====================== + +This middleware creates a single WSGI application that dispatches to +multiple other WSGI applications mounted at different URL paths. + +A common example is writing a Single Page Application, where you have a +backend API and a frontend written in JavaScript that does the routing +in the browser rather than requesting different pages from the server. +The frontend is a single HTML and JS file that should be served for any +path besides "/api". + +This example dispatches to an API app under "/api", an admin app +under "/admin", and an app that serves frontend files for all other +requests:: + + app = DispatcherMiddleware(serve_frontend, { + '/api': api_app, + '/admin': admin_app, + }) + +In production, you might instead handle this at the HTTP server level, +serving files or proxying to application servers based on location. The +API and admin apps would each be deployed with a separate WSGI server, +and the static files would be served directly by the HTTP server. + +.. autoclass:: DispatcherMiddleware + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import typing as t + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class DispatcherMiddleware: + """Combine multiple applications as a single WSGI application. + Requests are dispatched to an application based on the path it is + mounted under. + + :param app: The WSGI application to dispatch to if the request + doesn't match a mounted path. + :param mounts: Maps path prefixes to applications for dispatching. + """ + + def __init__( + self, + app: "WSGIApplication", + mounts: t.Optional[t.Dict[str, "WSGIApplication"]] = None, + ) -> None: + self.app = app + self.mounts = mounts or {} + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + script = environ.get("PATH_INFO", "") + path_info = "" + + while "/" in script: + if script in self.mounts: + app = self.mounts[script] + break + + script, last_item = script.rsplit("/", 1) + path_info = f"/{last_item}{path_info}" + else: + app = self.mounts.get(script, self.app) + + original_script_name = environ.get("SCRIPT_NAME", "") + environ["SCRIPT_NAME"] = original_script_name + script + environ["PATH_INFO"] = path_info + return app(environ, start_response) diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/http_proxy.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/http_proxy.py new file mode 100644 index 0000000..1cde458 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/http_proxy.py @@ -0,0 +1,230 @@ +""" +Basic HTTP Proxy +================ + +.. autoclass:: ProxyMiddleware + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import typing as t +from http import client + +from ..datastructures import EnvironHeaders +from ..http import is_hop_by_hop_header +from ..urls import url_parse +from ..urls import url_quote +from ..wsgi import get_input_stream + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class ProxyMiddleware: + """Proxy requests under a path to an external server, routing other + requests to the app. + + This middleware can only proxy HTTP requests, as HTTP is the only + protocol handled by the WSGI server. Other protocols, such as + WebSocket requests, cannot be proxied at this layer. This should + only be used for development, in production a real proxy server + should be used. + + The middleware takes a dict mapping a path prefix to a dict + describing the host to be proxied to:: + + app = ProxyMiddleware(app, { + "/static/": { + "target": "http://127.0.0.1:5001/", + } + }) + + Each host has the following options: + + ``target``: + The target URL to dispatch to. This is required. + ``remove_prefix``: + Whether to remove the prefix from the URL before dispatching it + to the target. The default is ``False``. + ``host``: + ``""`` (default): + The host header is automatically rewritten to the URL of the + target. + ``None``: + The host header is unmodified from the client request. + Any other value: + The host header is overwritten with the value. + ``headers``: + A dictionary of headers to be sent with the request to the + target. The default is ``{}``. + ``ssl_context``: + A :class:`ssl.SSLContext` defining how to verify requests if the + target is HTTPS. The default is ``None``. + + In the example above, everything under ``"/static/"`` is proxied to + the server on port 5001. The host header is rewritten to the target, + and the ``"/static/"`` prefix is removed from the URLs. + + :param app: The WSGI application to wrap. + :param targets: Proxy target configurations. See description above. + :param chunk_size: Size of chunks to read from input stream and + write to target. + :param timeout: Seconds before an operation to a target fails. + + .. versionadded:: 0.14 + """ + + def __init__( + self, + app: "WSGIApplication", + targets: t.Mapping[str, t.Dict[str, t.Any]], + chunk_size: int = 2 << 13, + timeout: int = 10, + ) -> None: + def _set_defaults(opts: t.Dict[str, t.Any]) -> t.Dict[str, t.Any]: + opts.setdefault("remove_prefix", False) + opts.setdefault("host", "") + opts.setdefault("headers", {}) + opts.setdefault("ssl_context", None) + return opts + + self.app = app + self.targets = { + f"/{k.strip('/')}/": _set_defaults(v) for k, v in targets.items() + } + self.chunk_size = chunk_size + self.timeout = timeout + + def proxy_to( + self, opts: t.Dict[str, t.Any], path: str, prefix: str + ) -> "WSGIApplication": + target = url_parse(opts["target"]) + host = t.cast(str, target.ascii_host) + + def application( + environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + headers = list(EnvironHeaders(environ).items()) + headers[:] = [ + (k, v) + for k, v in headers + if not is_hop_by_hop_header(k) + and k.lower() not in ("content-length", "host") + ] + headers.append(("Connection", "close")) + + if opts["host"] == "": + headers.append(("Host", host)) + elif opts["host"] is None: + headers.append(("Host", environ["HTTP_HOST"])) + else: + headers.append(("Host", opts["host"])) + + headers.extend(opts["headers"].items()) + remote_path = path + + if opts["remove_prefix"]: + remote_path = remote_path[len(prefix) :].lstrip("/") + remote_path = f"{target.path.rstrip('/')}/{remote_path}" + + content_length = environ.get("CONTENT_LENGTH") + chunked = False + + if content_length not in ("", None): + headers.append(("Content-Length", content_length)) # type: ignore + elif content_length is not None: + headers.append(("Transfer-Encoding", "chunked")) + chunked = True + + try: + if target.scheme == "http": + con = client.HTTPConnection( + host, target.port or 80, timeout=self.timeout + ) + elif target.scheme == "https": + con = client.HTTPSConnection( + host, + target.port or 443, + timeout=self.timeout, + context=opts["ssl_context"], + ) + else: + raise RuntimeError( + "Target scheme must be 'http' or 'https', got" + f" {target.scheme!r}." + ) + + con.connect() + remote_url = url_quote(remote_path) + querystring = environ["QUERY_STRING"] + + if querystring: + remote_url = f"{remote_url}?{querystring}" + + con.putrequest(environ["REQUEST_METHOD"], remote_url, skip_host=True) + + for k, v in headers: + if k.lower() == "connection": + v = "close" + + con.putheader(k, v) + + con.endheaders() + stream = get_input_stream(environ) + + while True: + data = stream.read(self.chunk_size) + + if not data: + break + + if chunked: + con.send(b"%x\r\n%s\r\n" % (len(data), data)) + else: + con.send(data) + + resp = con.getresponse() + except OSError: + from ..exceptions import BadGateway + + return BadGateway()(environ, start_response) + + start_response( + f"{resp.status} {resp.reason}", + [ + (k.title(), v) + for k, v in resp.getheaders() + if not is_hop_by_hop_header(k) + ], + ) + + def read() -> t.Iterator[bytes]: + while True: + try: + data = resp.read(self.chunk_size) + except OSError: + break + + if not data: + break + + yield data + + return read() + + return application + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + path = environ["PATH_INFO"] + app = self.app + + for prefix, opts in self.targets.items(): + if path.startswith(prefix): + app = self.proxy_to(opts, path, prefix) + break + + return app(environ, start_response) diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/lint.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/lint.py new file mode 100644 index 0000000..6b54630 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/lint.py @@ -0,0 +1,420 @@ +""" +WSGI Protocol Linter +==================== + +This module provides a middleware that performs sanity checks on the +behavior of the WSGI server and application. It checks that the +:pep:`3333` WSGI spec is properly implemented. It also warns on some +common HTTP errors such as non-empty responses for 304 status codes. + +.. autoclass:: LintMiddleware + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import typing as t +from types import TracebackType +from urllib.parse import urlparse +from warnings import warn + +from ..datastructures import Headers +from ..http import is_entity_header +from ..wsgi import FileWrapper + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class WSGIWarning(Warning): + """Warning class for WSGI warnings.""" + + +class HTTPWarning(Warning): + """Warning class for HTTP warnings.""" + + +def check_type(context: str, obj: object, need: t.Type = str) -> None: + if type(obj) is not need: + warn( + f"{context!r} requires {need.__name__!r}, got {type(obj).__name__!r}.", + WSGIWarning, + stacklevel=3, + ) + + +class InputStream: + def __init__(self, stream: t.IO[bytes]) -> None: + self._stream = stream + + def read(self, *args: t.Any) -> bytes: + if len(args) == 0: + warn( + "WSGI does not guarantee an EOF marker on the input stream, thus making" + " calls to 'wsgi.input.read()' unsafe. Conforming servers may never" + " return from this call.", + WSGIWarning, + stacklevel=2, + ) + elif len(args) != 1: + warn( + "Too many parameters passed to 'wsgi.input.read()'.", + WSGIWarning, + stacklevel=2, + ) + return self._stream.read(*args) + + def readline(self, *args: t.Any) -> bytes: + if len(args) == 0: + warn( + "Calls to 'wsgi.input.readline()' without arguments are unsafe. Use" + " 'wsgi.input.read()' instead.", + WSGIWarning, + stacklevel=2, + ) + elif len(args) == 1: + warn( + "'wsgi.input.readline()' was called with a size hint. WSGI does not" + " support this, although it's available on all major servers.", + WSGIWarning, + stacklevel=2, + ) + else: + raise TypeError("Too many arguments passed to 'wsgi.input.readline()'.") + return self._stream.readline(*args) + + def __iter__(self) -> t.Iterator[bytes]: + try: + return iter(self._stream) + except TypeError: + warn("'wsgi.input' is not iterable.", WSGIWarning, stacklevel=2) + return iter(()) + + def close(self) -> None: + warn("The application closed the input stream!", WSGIWarning, stacklevel=2) + self._stream.close() + + +class ErrorStream: + def __init__(self, stream: t.IO[str]) -> None: + self._stream = stream + + def write(self, s: str) -> None: + check_type("wsgi.error.write()", s, str) + self._stream.write(s) + + def flush(self) -> None: + self._stream.flush() + + def writelines(self, seq: t.Iterable[str]) -> None: + for line in seq: + self.write(line) + + def close(self) -> None: + warn("The application closed the error stream!", WSGIWarning, stacklevel=2) + self._stream.close() + + +class GuardedWrite: + def __init__(self, write: t.Callable[[bytes], object], chunks: t.List[int]) -> None: + self._write = write + self._chunks = chunks + + def __call__(self, s: bytes) -> None: + check_type("write()", s, bytes) + self._write(s) + self._chunks.append(len(s)) + + +class GuardedIterator: + def __init__( + self, + iterator: t.Iterable[bytes], + headers_set: t.Tuple[int, Headers], + chunks: t.List[int], + ) -> None: + self._iterator = iterator + self._next = iter(iterator).__next__ + self.closed = False + self.headers_set = headers_set + self.chunks = chunks + + def __iter__(self) -> "GuardedIterator": + return self + + def __next__(self) -> bytes: + if self.closed: + warn("Iterated over closed 'app_iter'.", WSGIWarning, stacklevel=2) + + rv = self._next() + + if not self.headers_set: + warn( + "The application returned before it started the response.", + WSGIWarning, + stacklevel=2, + ) + + check_type("application iterator items", rv, bytes) + self.chunks.append(len(rv)) + return rv + + def close(self) -> None: + self.closed = True + + if hasattr(self._iterator, "close"): + self._iterator.close() # type: ignore + + if self.headers_set: + status_code, headers = self.headers_set + bytes_sent = sum(self.chunks) + content_length = headers.get("content-length", type=int) + + if status_code == 304: + for key, _value in headers: + key = key.lower() + if key not in ("expires", "content-location") and is_entity_header( + key + ): + warn( + f"Entity header {key!r} found in 304 response.", HTTPWarning + ) + if bytes_sent: + warn("304 responses must not have a body.", HTTPWarning) + elif 100 <= status_code < 200 or status_code == 204: + if content_length != 0: + warn( + f"{status_code} responses must have an empty content length.", + HTTPWarning, + ) + if bytes_sent: + warn(f"{status_code} responses must not have a body.", HTTPWarning) + elif content_length is not None and content_length != bytes_sent: + warn( + "Content-Length and the number of bytes sent to the" + " client do not match.", + WSGIWarning, + ) + + def __del__(self) -> None: + if not self.closed: + try: + warn( + "Iterator was garbage collected before it was closed.", WSGIWarning + ) + except Exception: + pass + + +class LintMiddleware: + """Warns about common errors in the WSGI and HTTP behavior of the + server and wrapped application. Some of the issues it checks are: + + - invalid status codes + - non-bytes sent to the WSGI server + - strings returned from the WSGI application + - non-empty conditional responses + - unquoted etags + - relative URLs in the Location header + - unsafe calls to wsgi.input + - unclosed iterators + + Error information is emitted using the :mod:`warnings` module. + + :param app: The WSGI application to wrap. + + .. code-block:: python + + from werkzeug.middleware.lint import LintMiddleware + app = LintMiddleware(app) + """ + + def __init__(self, app: "WSGIApplication") -> None: + self.app = app + + def check_environ(self, environ: "WSGIEnvironment") -> None: + if type(environ) is not dict: + warn( + "WSGI environment is not a standard Python dict.", + WSGIWarning, + stacklevel=4, + ) + for key in ( + "REQUEST_METHOD", + "SERVER_NAME", + "SERVER_PORT", + "wsgi.version", + "wsgi.input", + "wsgi.errors", + "wsgi.multithread", + "wsgi.multiprocess", + "wsgi.run_once", + ): + if key not in environ: + warn( + f"Required environment key {key!r} not found", + WSGIWarning, + stacklevel=3, + ) + if environ["wsgi.version"] != (1, 0): + warn("Environ is not a WSGI 1.0 environ.", WSGIWarning, stacklevel=3) + + script_name = environ.get("SCRIPT_NAME", "") + path_info = environ.get("PATH_INFO", "") + + if script_name and script_name[0] != "/": + warn( + f"'SCRIPT_NAME' does not start with a slash: {script_name!r}", + WSGIWarning, + stacklevel=3, + ) + + if path_info and path_info[0] != "/": + warn( + f"'PATH_INFO' does not start with a slash: {path_info!r}", + WSGIWarning, + stacklevel=3, + ) + + def check_start_response( + self, + status: str, + headers: t.List[t.Tuple[str, str]], + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ], + ) -> t.Tuple[int, Headers]: + check_type("status", status, str) + status_code_str = status.split(None, 1)[0] + + if len(status_code_str) != 3 or not status_code_str.isdecimal(): + warn("Status code must be three digits.", WSGIWarning, stacklevel=3) + + if len(status) < 4 or status[3] != " ": + warn( + f"Invalid value for status {status!r}. Valid status strings are three" + " digits, a space and a status explanation.", + WSGIWarning, + stacklevel=3, + ) + + status_code = int(status_code_str) + + if status_code < 100: + warn("Status code < 100 detected.", WSGIWarning, stacklevel=3) + + if type(headers) is not list: + warn("Header list is not a list.", WSGIWarning, stacklevel=3) + + for item in headers: + if type(item) is not tuple or len(item) != 2: + warn("Header items must be 2-item tuples.", WSGIWarning, stacklevel=3) + name, value = item + if type(name) is not str or type(value) is not str: + warn( + "Header keys and values must be strings.", WSGIWarning, stacklevel=3 + ) + if name.lower() == "status": + warn( + "The status header is not supported due to" + " conflicts with the CGI spec.", + WSGIWarning, + stacklevel=3, + ) + + if exc_info is not None and not isinstance(exc_info, tuple): + warn("Invalid value for exc_info.", WSGIWarning, stacklevel=3) + + headers = Headers(headers) + self.check_headers(headers) + + return status_code, headers + + def check_headers(self, headers: Headers) -> None: + etag = headers.get("etag") + + if etag is not None: + if etag.startswith(("W/", "w/")): + if etag.startswith("w/"): + warn( + "Weak etag indicator should be upper case.", + HTTPWarning, + stacklevel=4, + ) + + etag = etag[2:] + + if not (etag[:1] == etag[-1:] == '"'): + warn("Unquoted etag emitted.", HTTPWarning, stacklevel=4) + + location = headers.get("location") + + if location is not None: + if not urlparse(location).netloc: + warn( + "Absolute URLs required for location header.", + HTTPWarning, + stacklevel=4, + ) + + def check_iterator(self, app_iter: t.Iterable[bytes]) -> None: + if isinstance(app_iter, bytes): + warn( + "The application returned a bytestring. The response will send one" + " character at a time to the client, which will kill performance." + " Return a list or iterable instead.", + WSGIWarning, + stacklevel=3, + ) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> t.Iterable[bytes]: + if len(args) != 2: + warn("A WSGI app takes two arguments.", WSGIWarning, stacklevel=2) + + if kwargs: + warn( + "A WSGI app does not take keyword arguments.", WSGIWarning, stacklevel=2 + ) + + environ: "WSGIEnvironment" = args[0] + start_response: "StartResponse" = args[1] + + self.check_environ(environ) + environ["wsgi.input"] = InputStream(environ["wsgi.input"]) + environ["wsgi.errors"] = ErrorStream(environ["wsgi.errors"]) + + # Hook our own file wrapper in so that applications will always + # iterate to the end and we can check the content length. + environ["wsgi.file_wrapper"] = FileWrapper + + headers_set: t.List[t.Any] = [] + chunks: t.List[int] = [] + + def checking_start_response( + *args: t.Any, **kwargs: t.Any + ) -> t.Callable[[bytes], None]: + if len(args) not in {2, 3}: + warn( + f"Invalid number of arguments: {len(args)}, expected 2 or 3.", + WSGIWarning, + stacklevel=2, + ) + + if kwargs: + warn("'start_response' does not take keyword arguments.", WSGIWarning) + + status: str = args[0] + headers: t.List[t.Tuple[str, str]] = args[1] + exc_info: t.Optional[ + t.Tuple[t.Type[BaseException], BaseException, TracebackType] + ] = (args[2] if len(args) == 3 else None) + + headers_set[:] = self.check_start_response(status, headers, exc_info) + return GuardedWrite(start_response(status, headers, exc_info), chunks) + + app_iter = self.app(environ, t.cast("StartResponse", checking_start_response)) + self.check_iterator(app_iter) + return GuardedIterator( + app_iter, t.cast(t.Tuple[int, Headers], headers_set), chunks + ) diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/profiler.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/profiler.py new file mode 100644 index 0000000..200dae0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/profiler.py @@ -0,0 +1,139 @@ +""" +Application Profiler +==================== + +This module provides a middleware that profiles each request with the +:mod:`cProfile` module. This can help identify bottlenecks in your code +that may be slowing down your application. + +.. autoclass:: ProfilerMiddleware + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import os.path +import sys +import time +import typing as t +from pstats import Stats + +try: + from cProfile import Profile +except ImportError: + from profile import Profile # type: ignore + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class ProfilerMiddleware: + """Wrap a WSGI application and profile the execution of each + request. Responses are buffered so that timings are more exact. + + If ``stream`` is given, :class:`pstats.Stats` are written to it + after each request. If ``profile_dir`` is given, :mod:`cProfile` + data files are saved to that directory, one file per request. + + The filename can be customized by passing ``filename_format``. If + it is a string, it will be formatted using :meth:`str.format` with + the following fields available: + + - ``{method}`` - The request method; GET, POST, etc. + - ``{path}`` - The request path or 'root' should one not exist. + - ``{elapsed}`` - The elapsed time of the request. + - ``{time}`` - The time of the request. + + If it is a callable, it will be called with the WSGI ``environ`` + dict and should return a filename. + + :param app: The WSGI application to wrap. + :param stream: Write stats to this stream. Disable with ``None``. + :param sort_by: A tuple of columns to sort stats by. See + :meth:`pstats.Stats.sort_stats`. + :param restrictions: A tuple of restrictions to filter stats by. See + :meth:`pstats.Stats.print_stats`. + :param profile_dir: Save profile data files to this directory. + :param filename_format: Format string for profile data file names, + or a callable returning a name. See explanation above. + + .. code-block:: python + + from werkzeug.middleware.profiler import ProfilerMiddleware + app = ProfilerMiddleware(app) + + .. versionchanged:: 0.15 + Stats are written even if ``profile_dir`` is given, and can be + disable by passing ``stream=None``. + + .. versionadded:: 0.15 + Added ``filename_format``. + + .. versionadded:: 0.9 + Added ``restrictions`` and ``profile_dir``. + """ + + def __init__( + self, + app: "WSGIApplication", + stream: t.IO[str] = sys.stdout, + sort_by: t.Iterable[str] = ("time", "calls"), + restrictions: t.Iterable[t.Union[str, int, float]] = (), + profile_dir: t.Optional[str] = None, + filename_format: str = "{method}.{path}.{elapsed:.0f}ms.{time:.0f}.prof", + ) -> None: + self._app = app + self._stream = stream + self._sort_by = sort_by + self._restrictions = restrictions + self._profile_dir = profile_dir + self._filename_format = filename_format + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + response_body: t.List[bytes] = [] + + def catching_start_response(status, headers, exc_info=None): # type: ignore + start_response(status, headers, exc_info) + return response_body.append + + def runapp() -> None: + app_iter = self._app( + environ, t.cast("StartResponse", catching_start_response) + ) + response_body.extend(app_iter) + + if hasattr(app_iter, "close"): + app_iter.close() # type: ignore + + profile = Profile() + start = time.time() + profile.runcall(runapp) + body = b"".join(response_body) + elapsed = time.time() - start + + if self._profile_dir is not None: + if callable(self._filename_format): + filename = self._filename_format(environ) + else: + filename = self._filename_format.format( + method=environ["REQUEST_METHOD"], + path=environ["PATH_INFO"].strip("/").replace("/", ".") or "root", + elapsed=elapsed * 1000.0, + time=time.time(), + ) + filename = os.path.join(self._profile_dir, filename) + profile.dump_stats(filename) + + if self._stream is not None: + stats = Stats(profile, stream=self._stream) + stats.sort_stats(*self._sort_by) + print("-" * 80, file=self._stream) + path_info = environ.get("PATH_INFO", "") + print(f"PATH: {path_info!r}", file=self._stream) + stats.print_stats(*self._restrictions) + print(f"{'-' * 80}\n", file=self._stream) + + return [body] diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/proxy_fix.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/proxy_fix.py new file mode 100644 index 0000000..4cef7cc --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/proxy_fix.py @@ -0,0 +1,187 @@ +""" +X-Forwarded-For Proxy Fix +========================= + +This module provides a middleware that adjusts the WSGI environ based on +``X-Forwarded-`` headers that proxies in front of an application may +set. + +When an application is running behind a proxy server, WSGI may see the +request as coming from that server rather than the real client. Proxies +set various headers to track where the request actually came from. + +This middleware should only be used if the application is actually +behind such a proxy, and should be configured with the number of proxies +that are chained in front of it. Not all proxies set all the headers. +Since incoming headers can be faked, you must set how many proxies are +setting each header so the middleware knows what to trust. + +.. autoclass:: ProxyFix + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import typing as t + +from ..http import parse_list_header + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class ProxyFix: + """Adjust the WSGI environ based on ``X-Forwarded-`` that proxies in + front of the application may set. + + - ``X-Forwarded-For`` sets ``REMOTE_ADDR``. + - ``X-Forwarded-Proto`` sets ``wsgi.url_scheme``. + - ``X-Forwarded-Host`` sets ``HTTP_HOST``, ``SERVER_NAME``, and + ``SERVER_PORT``. + - ``X-Forwarded-Port`` sets ``HTTP_HOST`` and ``SERVER_PORT``. + - ``X-Forwarded-Prefix`` sets ``SCRIPT_NAME``. + + You must tell the middleware how many proxies set each header so it + knows what values to trust. It is a security issue to trust values + that came from the client rather than a proxy. + + The original values of the headers are stored in the WSGI + environ as ``werkzeug.proxy_fix.orig``, a dict. + + :param app: The WSGI application to wrap. + :param x_for: Number of values to trust for ``X-Forwarded-For``. + :param x_proto: Number of values to trust for ``X-Forwarded-Proto``. + :param x_host: Number of values to trust for ``X-Forwarded-Host``. + :param x_port: Number of values to trust for ``X-Forwarded-Port``. + :param x_prefix: Number of values to trust for + ``X-Forwarded-Prefix``. + + .. code-block:: python + + from werkzeug.middleware.proxy_fix import ProxyFix + # App is behind one proxy that sets the -For and -Host headers. + app = ProxyFix(app, x_for=1, x_host=1) + + .. versionchanged:: 1.0 + Deprecated code has been removed: + + * The ``num_proxies`` argument and attribute. + * The ``get_remote_addr`` method. + * The environ keys ``orig_remote_addr``, + ``orig_wsgi_url_scheme``, and ``orig_http_host``. + + .. versionchanged:: 0.15 + All headers support multiple values. The ``num_proxies`` + argument is deprecated. Each header is configured with a + separate number of trusted proxies. + + .. versionchanged:: 0.15 + Original WSGI environ values are stored in the + ``werkzeug.proxy_fix.orig`` dict. ``orig_remote_addr``, + ``orig_wsgi_url_scheme``, and ``orig_http_host`` are deprecated + and will be removed in 1.0. + + .. versionchanged:: 0.15 + Support ``X-Forwarded-Port`` and ``X-Forwarded-Prefix``. + + .. versionchanged:: 0.15 + ``X-Forwarded-Host`` and ``X-Forwarded-Port`` modify + ``SERVER_NAME`` and ``SERVER_PORT``. + """ + + def __init__( + self, + app: "WSGIApplication", + x_for: int = 1, + x_proto: int = 1, + x_host: int = 0, + x_port: int = 0, + x_prefix: int = 0, + ) -> None: + self.app = app + self.x_for = x_for + self.x_proto = x_proto + self.x_host = x_host + self.x_port = x_port + self.x_prefix = x_prefix + + def _get_real_value(self, trusted: int, value: t.Optional[str]) -> t.Optional[str]: + """Get the real value from a list header based on the configured + number of trusted proxies. + + :param trusted: Number of values to trust in the header. + :param value: Comma separated list header value to parse. + :return: The real value, or ``None`` if there are fewer values + than the number of trusted proxies. + + .. versionchanged:: 1.0 + Renamed from ``_get_trusted_comma``. + + .. versionadded:: 0.15 + """ + if not (trusted and value): + return None + values = parse_list_header(value) + if len(values) >= trusted: + return values[-trusted] + return None + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + """Modify the WSGI environ based on the various ``Forwarded`` + headers before calling the wrapped application. Store the + original environ values in ``werkzeug.proxy_fix.orig_{key}``. + """ + environ_get = environ.get + orig_remote_addr = environ_get("REMOTE_ADDR") + orig_wsgi_url_scheme = environ_get("wsgi.url_scheme") + orig_http_host = environ_get("HTTP_HOST") + environ.update( + { + "werkzeug.proxy_fix.orig": { + "REMOTE_ADDR": orig_remote_addr, + "wsgi.url_scheme": orig_wsgi_url_scheme, + "HTTP_HOST": orig_http_host, + "SERVER_NAME": environ_get("SERVER_NAME"), + "SERVER_PORT": environ_get("SERVER_PORT"), + "SCRIPT_NAME": environ_get("SCRIPT_NAME"), + } + } + ) + + x_for = self._get_real_value(self.x_for, environ_get("HTTP_X_FORWARDED_FOR")) + if x_for: + environ["REMOTE_ADDR"] = x_for + + x_proto = self._get_real_value( + self.x_proto, environ_get("HTTP_X_FORWARDED_PROTO") + ) + if x_proto: + environ["wsgi.url_scheme"] = x_proto + + x_host = self._get_real_value(self.x_host, environ_get("HTTP_X_FORWARDED_HOST")) + if x_host: + environ["HTTP_HOST"] = environ["SERVER_NAME"] = x_host + # "]" to check for IPv6 address without port + if ":" in x_host and not x_host.endswith("]"): + environ["SERVER_NAME"], environ["SERVER_PORT"] = x_host.rsplit(":", 1) + + x_port = self._get_real_value(self.x_port, environ_get("HTTP_X_FORWARDED_PORT")) + if x_port: + host = environ.get("HTTP_HOST") + if host: + # "]" to check for IPv6 address without port + if ":" in host and not host.endswith("]"): + host = host.rsplit(":", 1)[0] + environ["HTTP_HOST"] = f"{host}:{x_port}" + environ["SERVER_PORT"] = x_port + + x_prefix = self._get_real_value( + self.x_prefix, environ_get("HTTP_X_FORWARDED_PREFIX") + ) + if x_prefix: + environ["SCRIPT_NAME"] = x_prefix + + return self.app(environ, start_response) diff --git a/.vcrunch/Lib/site-packages/werkzeug/middleware/shared_data.py b/.vcrunch/Lib/site-packages/werkzeug/middleware/shared_data.py new file mode 100644 index 0000000..2ec396c --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/middleware/shared_data.py @@ -0,0 +1,280 @@ +""" +Serve Shared Static Files +========================= + +.. autoclass:: SharedDataMiddleware + :members: is_allowed + +:copyright: 2007 Pallets +:license: BSD-3-Clause +""" +import mimetypes +import os +import pkgutil +import posixpath +import typing as t +from datetime import datetime +from datetime import timezone +from io import BytesIO +from time import time +from zlib import adler32 + +from ..http import http_date +from ..http import is_resource_modified +from ..security import safe_join +from ..utils import get_content_type +from ..wsgi import get_path_info +from ..wsgi import wrap_file + +_TOpener = t.Callable[[], t.Tuple[t.IO[bytes], datetime, int]] +_TLoader = t.Callable[[t.Optional[str]], t.Tuple[t.Optional[str], t.Optional[_TOpener]]] + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class SharedDataMiddleware: + + """A WSGI middleware which provides static content for development + environments or simple server setups. Its usage is quite simple:: + + import os + from werkzeug.middleware.shared_data import SharedDataMiddleware + + app = SharedDataMiddleware(app, { + '/shared': os.path.join(os.path.dirname(__file__), 'shared') + }) + + The contents of the folder ``./shared`` will now be available on + ``http://example.com/shared/``. This is pretty useful during development + because a standalone media server is not required. Files can also be + mounted on the root folder and still continue to use the application because + the shared data middleware forwards all unhandled requests to the + application, even if the requests are below one of the shared folders. + + If `pkg_resources` is available you can also tell the middleware to serve + files from package data:: + + app = SharedDataMiddleware(app, { + '/static': ('myapplication', 'static') + }) + + This will then serve the ``static`` folder in the `myapplication` + Python package. + + The optional `disallow` parameter can be a list of :func:`~fnmatch.fnmatch` + rules for files that are not accessible from the web. If `cache` is set to + `False` no caching headers are sent. + + Currently the middleware does not support non-ASCII filenames. If the + encoding on the file system happens to match the encoding of the URI it may + work but this could also be by accident. We strongly suggest using ASCII + only file names for static files. + + The middleware will guess the mimetype using the Python `mimetype` + module. If it's unable to figure out the charset it will fall back + to `fallback_mimetype`. + + :param app: the application to wrap. If you don't want to wrap an + application you can pass it :exc:`NotFound`. + :param exports: a list or dict of exported files and folders. + :param disallow: a list of :func:`~fnmatch.fnmatch` rules. + :param cache: enable or disable caching headers. + :param cache_timeout: the cache timeout in seconds for the headers. + :param fallback_mimetype: The fallback mimetype for unknown files. + + .. versionchanged:: 1.0 + The default ``fallback_mimetype`` is + ``application/octet-stream``. If a filename looks like a text + mimetype, the ``utf-8`` charset is added to it. + + .. versionadded:: 0.6 + Added ``fallback_mimetype``. + + .. versionchanged:: 0.5 + Added ``cache_timeout``. + """ + + def __init__( + self, + app: "WSGIApplication", + exports: t.Union[ + t.Dict[str, t.Union[str, t.Tuple[str, str]]], + t.Iterable[t.Tuple[str, t.Union[str, t.Tuple[str, str]]]], + ], + disallow: None = None, + cache: bool = True, + cache_timeout: int = 60 * 60 * 12, + fallback_mimetype: str = "application/octet-stream", + ) -> None: + self.app = app + self.exports: t.List[t.Tuple[str, _TLoader]] = [] + self.cache = cache + self.cache_timeout = cache_timeout + + if isinstance(exports, dict): + exports = exports.items() + + for key, value in exports: + if isinstance(value, tuple): + loader = self.get_package_loader(*value) + elif isinstance(value, str): + if os.path.isfile(value): + loader = self.get_file_loader(value) + else: + loader = self.get_directory_loader(value) + else: + raise TypeError(f"unknown def {value!r}") + + self.exports.append((key, loader)) + + if disallow is not None: + from fnmatch import fnmatch + + self.is_allowed = lambda x: not fnmatch(x, disallow) + + self.fallback_mimetype = fallback_mimetype + + def is_allowed(self, filename: str) -> bool: + """Subclasses can override this method to disallow the access to + certain files. However by providing `disallow` in the constructor + this method is overwritten. + """ + return True + + def _opener(self, filename: str) -> _TOpener: + return lambda: ( + open(filename, "rb"), + datetime.fromtimestamp(os.path.getmtime(filename), tz=timezone.utc), + int(os.path.getsize(filename)), + ) + + def get_file_loader(self, filename: str) -> _TLoader: + return lambda x: (os.path.basename(filename), self._opener(filename)) + + def get_package_loader(self, package: str, package_path: str) -> _TLoader: + load_time = datetime.now(timezone.utc) + provider = pkgutil.get_loader(package) + reader = provider.get_resource_reader(package) # type: ignore + + def loader( + path: t.Optional[str], + ) -> t.Tuple[t.Optional[str], t.Optional[_TOpener]]: + if path is None: + return None, None + + path = safe_join(package_path, path) + + if path is None: + return None, None + + basename = posixpath.basename(path) + + try: + resource = reader.open_resource(path) + except OSError: + return None, None + + if isinstance(resource, BytesIO): + return ( + basename, + lambda: (resource, load_time, len(resource.getvalue())), + ) + + return ( + basename, + lambda: ( + resource, + datetime.fromtimestamp( + os.path.getmtime(resource.name), tz=timezone.utc + ), + os.path.getsize(resource.name), + ), + ) + + return loader + + def get_directory_loader(self, directory: str) -> _TLoader: + def loader( + path: t.Optional[str], + ) -> t.Tuple[t.Optional[str], t.Optional[_TOpener]]: + if path is not None: + path = safe_join(directory, path) + + if path is None: + return None, None + else: + path = directory + + if os.path.isfile(path): + return os.path.basename(path), self._opener(path) + + return None, None + + return loader + + def generate_etag(self, mtime: datetime, file_size: int, real_filename: str) -> str: + real_filename = os.fsencode(real_filename) + timestamp = mtime.timestamp() + checksum = adler32(real_filename) & 0xFFFFFFFF + return f"wzsdm-{timestamp}-{file_size}-{checksum}" + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + path = get_path_info(environ) + file_loader = None + + for search_path, loader in self.exports: + if search_path == path: + real_filename, file_loader = loader(None) + + if file_loader is not None: + break + + if not search_path.endswith("/"): + search_path += "/" + + if path.startswith(search_path): + real_filename, file_loader = loader(path[len(search_path) :]) + + if file_loader is not None: + break + + if file_loader is None or not self.is_allowed(real_filename): # type: ignore + return self.app(environ, start_response) + + guessed_type = mimetypes.guess_type(real_filename) # type: ignore + mime_type = get_content_type(guessed_type[0] or self.fallback_mimetype, "utf-8") + f, mtime, file_size = file_loader() + + headers = [("Date", http_date())] + + if self.cache: + timeout = self.cache_timeout + etag = self.generate_etag(mtime, file_size, real_filename) # type: ignore + headers += [ + ("Etag", f'"{etag}"'), + ("Cache-Control", f"max-age={timeout}, public"), + ] + + if not is_resource_modified(environ, etag, last_modified=mtime): + f.close() + start_response("304 Not Modified", headers) + return [] + + headers.append(("Expires", http_date(time() + timeout))) + else: + headers.append(("Cache-Control", "public")) + + headers.extend( + ( + ("Content-Type", mime_type), + ("Content-Length", str(file_size)), + ("Last-Modified", http_date(mtime)), + ) + ) + start_response("200 OK", headers) + return wrap_file(environ, f) diff --git a/.vcrunch/Lib/site-packages/werkzeug/py.typed b/.vcrunch/Lib/site-packages/werkzeug/py.typed new file mode 100644 index 0000000..e69de29 diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/__init__.py b/.vcrunch/Lib/site-packages/werkzeug/routing/__init__.py new file mode 100644 index 0000000..84b043f --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/routing/__init__.py @@ -0,0 +1,133 @@ +"""When it comes to combining multiple controller or view functions +(however you want to call them) you need a dispatcher. A simple way +would be applying regular expression tests on the ``PATH_INFO`` and +calling registered callback functions that return the value then. + +This module implements a much more powerful system than simple regular +expression matching because it can also convert values in the URLs and +build URLs. + +Here a simple example that creates a URL map for an application with +two subdomains (www and kb) and some URL rules: + +.. code-block:: python + + m = Map([ + # Static URLs + Rule('/', endpoint='static/index'), + Rule('/about', endpoint='static/about'), + Rule('/help', endpoint='static/help'), + # Knowledge Base + Subdomain('kb', [ + Rule('/', endpoint='kb/index'), + Rule('/browse/', endpoint='kb/browse'), + Rule('/browse//', endpoint='kb/browse'), + Rule('/browse//', endpoint='kb/browse') + ]) + ], default_subdomain='www') + +If the application doesn't use subdomains it's perfectly fine to not set +the default subdomain and not use the `Subdomain` rule factory. The +endpoint in the rules can be anything, for example import paths or +unique identifiers. The WSGI application can use those endpoints to get the +handler for that URL. It doesn't have to be a string at all but it's +recommended. + +Now it's possible to create a URL adapter for one of the subdomains and +build URLs: + +.. code-block:: python + + c = m.bind('example.com') + + c.build("kb/browse", dict(id=42)) + 'http://kb.example.com/browse/42/' + + c.build("kb/browse", dict()) + 'http://kb.example.com/browse/' + + c.build("kb/browse", dict(id=42, page=3)) + 'http://kb.example.com/browse/42/3' + + c.build("static/about") + '/about' + + c.build("static/index", force_external=True) + 'http://www.example.com/' + + c = m.bind('example.com', subdomain='kb') + + c.build("static/about") + 'http://www.example.com/about' + +The first argument to bind is the server name *without* the subdomain. +Per default it will assume that the script is mounted on the root, but +often that's not the case so you can provide the real mount point as +second argument: + +.. code-block:: python + + c = m.bind('example.com', '/applications/example') + +The third argument can be the subdomain, if not given the default +subdomain is used. For more details about binding have a look at the +documentation of the `MapAdapter`. + +And here is how you can match URLs: + +.. code-block:: python + + c = m.bind('example.com') + + c.match("/") + ('static/index', {}) + + c.match("/about") + ('static/about', {}) + + c = m.bind('example.com', '/', 'kb') + + c.match("/") + ('kb/index', {}) + + c.match("/browse/42/23") + ('kb/browse', {'id': 42, 'page': 23}) + +If matching fails you get a ``NotFound`` exception, if the rule thinks +it's a good idea to redirect (for example because the URL was defined +to have a slash at the end but the request was missing that slash) it +will raise a ``RequestRedirect`` exception. Both are subclasses of +``HTTPException`` so you can use those errors as responses in the +application. + +If matching succeeded but the URL rule was incompatible to the given +method (for example there were only rules for ``GET`` and ``HEAD`` but +routing tried to match a ``POST`` request) a ``MethodNotAllowed`` +exception is raised. +""" +from .converters import AnyConverter as AnyConverter +from .converters import BaseConverter as BaseConverter +from .converters import FloatConverter as FloatConverter +from .converters import IntegerConverter as IntegerConverter +from .converters import PathConverter as PathConverter +from .converters import UnicodeConverter as UnicodeConverter +from .converters import UUIDConverter as UUIDConverter +from .converters import ValidationError as ValidationError +from .exceptions import BuildError as BuildError +from .exceptions import NoMatch as NoMatch +from .exceptions import RequestAliasRedirect as RequestAliasRedirect +from .exceptions import RequestPath as RequestPath +from .exceptions import RequestRedirect as RequestRedirect +from .exceptions import RoutingException as RoutingException +from .exceptions import WebsocketMismatch as WebsocketMismatch +from .map import Map as Map +from .map import MapAdapter as MapAdapter +from .matcher import StateMachineMatcher as StateMachineMatcher +from .rules import EndpointPrefix as EndpointPrefix +from .rules import parse_converter_args as parse_converter_args +from .rules import Rule as Rule +from .rules import RuleFactory as RuleFactory +from .rules import RuleTemplate as RuleTemplate +from .rules import RuleTemplateFactory as RuleTemplateFactory +from .rules import Subdomain as Subdomain +from .rules import Submount as Submount diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f874b3ad91a03451c615f4466493c478c7957e42 GIT binary patch literal 4620 zcmbtYU2hz>6z$v(O=Owz4obpp)c*ZcV<>2*@4qkhN(jiKQ1rtIhT}KTnuXX`On|?qJP}1 z)&5D9>dzHazQ%v|^;E4E*TPyn6<wL2VMvl7%u=XhKr0BftSK1#!JA<;WFc8 z;FWNN@e1&b@CM@>$<5(vxXSn@@LIUWcs02-ydBC}wGSf-vQkx3%_ zKn>TqIaMkaQpDP2(nkYjn_^oyJ*3IU@-!HmQ4));5;Dt@Q(D`q{wR@FsFTbp=dhCS z%6TUU43y|}cDD~+wRhgU{GrnkGL3@>OBN%w^U7jHYU;}9=-gV2l^&D(kRU*S?ZEutacZx-ZG+$coq_8=t*gT}|l2u(5 z$&tgf@H9rq#F3{{_{|Hp!3mvP^mgxiEQt+uM;cC{DolHY4Z)DYXX-?lT8UzAAL$M`Z%dGKdu2IY9V&7x6h;5#Sr+^?n6Se?|@H!k;;T{H3@8jyc@f51Q`*@yabd!_s5;!mj=Co1kM@mxAJS$Mzn zN~3<%#Z2d$qK$oM3rF4e&9C(BS~GU);;u0yZ?10n{V`v`MVmT)_Wup$Su)vI&n`Ho zV#8$fKdm$TX+y-SCqer5BuKXEh>`kw5bX4rcGZxIjdE$-3kvJW0EDrxJCT7TD)Pyx z=;;*vG9oozIOPK(Z?VkzD2_hrL31&^CkN6I6pW%LBX8_!QydIbPzF*-84g$G6-h{n zAO+<%m&n^qBg7QLeVikk$Z_K#x zq=EW%;Q^9nW_m$%8OsbZ$EzCn*yJZvIf;uR@)0^mp!2W^<&PWn!f8zyL}yPS8Z}vt z8jmIc^a$aiBj3>R*3-x9c?i`9-e;Sw)={@vnWKpM*3-wW`p0JbO%r`|7Pe^vr`=au zPkz&suDrEOI841Pf%M5?V$a6G9@whrt_UGxt~b-_X9%D-|3 z8|O^fB7M4iCLc1iIEl+EmF9y+pr&;QLfaovo}&Px;}^(*L_w!4W%X1dCwxKa1DgCr z{-qSlX0VGMC7Y4j#u^bVox_AV6L_M?>I^|nsdbckNDl23<>486pnfdheHez~9D8SfjS-m0jaYZZY^PA8{9 zTkQEFrReZJOSfzY-Q!*K^)YX2qIkiCo#YP4N(`NN3EAMgMXbEk2@*M_KRyf63DyoN z5@U`?Gq6$+n~0ArPwfTqJ4nXcxh8ZVAlq;SE?ST{CvZcXc#&@;oS}cGgC@bpGc_Ky z3TiYiX7vs6%U|E?TBXvYe;$(6{=Z5CzD8VNz;X4$Ps%V7KCClk9Tl7>wA zOI^qHP4V`0*3k2ofMqLPyf$W1_gE6d-XKePjGf1b2+Ps5*&MMt3d_0}2dI zV3d=NT)^2;ioP)*TC60o4p&tT_4lGd8Klfu<&BYMpo`sDI-(lVX&his5f(0yZcxMp zWhc%jyr@Ec1HEb3P$P%HZca`-VjamPV76MRK{MLJUOr;4u%^0|rg&~VmO(fnf+MWy zaN#t)pwoGEaIpKL+%m>g2wO>;)*6ezcG#=S@M^&5{JI-dxQ3{$dfAPl2=4~y1?9-n z4eU(XlunVJkk8BHNFA7P!B9c0;)~wIR~V1GI}&AzYe{}(Ab)o{-@Q1<-w?pBUTlAh z3W<^h3)yQ{!v?sV&!1hj`@=pBvAM@^dB(`syea}=J4x_JKq%lLP=o@JkR6TG{x7^; zYwJ^I3)|`GH~9-dS=1NlLRxKDdYKsMt1T-#kk7ud)wac5TxqHeD{oUxm-cGg;@h`7 z-&Pxzf0T)iSwCLT*uvP@dcA}*#qXX^pMLQXQ>hh)dLDR}! z?!rlYpzX#x)pdAHDF0eJ_9z;sp(ID4r3!7Hl{{ z%UUL_Q|+j9W*aHMp?zi#H%I)Qr{6F03nZ!wR6S65Kw)~+SF82&Zr3MQQ1qEYg|pY2 zb#XS^ZbO0F?XzIAq_gz52|G>23>8bDAlwAyX_y}-BI&Fu7S?yLO${EVX9{Sn1XZQ*EP>VNyUGWB2Y)}Gk_ literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/converters.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6a5ab284de8d8162640b1146d3fd04a4ff355dac GIT binary patch literal 8737 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 LwosjaZPEE3u%`7A literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/map.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..462509bc934543a5f765798cec26151fe43eee50 GIT binary patch literal 30976 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 SE*tUN6Y12qQ{SHc`u_!93-YJ{ literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/routing/__pycache__/matcher.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9435784fd6f3da8e8d00a6c5b0bba3147ed4d0d6 GIT binary patch literal 4531 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 vjdAC9^ZUujJ44PN438a79~(L~GP-AMc None: + self.map = map + + def to_python(self, value: str) -> t.Any: + return value + + def to_url(self, value: t.Any) -> str: + if isinstance(value, (bytes, bytearray)): + return _fast_url_quote(value) + return _fast_url_quote(str(value).encode(self.map.charset)) + + +class UnicodeConverter(BaseConverter): + """This converter is the default converter and accepts any string but + only one path segment. Thus the string can not include a slash. + + This is the default validator. + + Example:: + + Rule('/pages/'), + Rule('/') + + :param map: the :class:`Map`. + :param minlength: the minimum length of the string. Must be greater + or equal 1. + :param maxlength: the maximum length of the string. + :param length: the exact length of the string. + """ + + part_isolating = True + + def __init__( + self, + map: "Map", + minlength: int = 1, + maxlength: t.Optional[int] = None, + length: t.Optional[int] = None, + ) -> None: + super().__init__(map) + if length is not None: + length_regex = f"{{{int(length)}}}" + else: + if maxlength is None: + maxlength_value = "" + else: + maxlength_value = str(int(maxlength)) + length_regex = f"{{{int(minlength)},{maxlength_value}}}" + self.regex = f"[^/]{length_regex}" + + +class AnyConverter(BaseConverter): + """Matches one of the items provided. Items can either be Python + identifiers or strings:: + + Rule('/') + + :param map: the :class:`Map`. + :param items: this function accepts the possible items as positional + arguments. + + .. versionchanged:: 2.2 + Value is validated when building a URL. + """ + + part_isolating = True + + def __init__(self, map: "Map", *items: str) -> None: + super().__init__(map) + self.items = set(items) + self.regex = f"(?:{'|'.join([re.escape(x) for x in items])})" + + def to_url(self, value: t.Any) -> str: + if value in self.items: + return str(value) + + valid_values = ", ".join(f"'{item}'" for item in sorted(self.items)) + raise ValueError(f"'{value}' is not one of {valid_values}") + + +class PathConverter(BaseConverter): + """Like the default :class:`UnicodeConverter`, but it also matches + slashes. This is useful for wikis and similar applications:: + + Rule('/') + Rule('//edit') + + :param map: the :class:`Map`. + """ + + regex = "[^/].*?" + weight = 200 + part_isolating = False + + +class NumberConverter(BaseConverter): + """Baseclass for `IntegerConverter` and `FloatConverter`. + + :internal: + """ + + weight = 50 + num_convert: t.Callable = int + part_isolating = True + + def __init__( + self, + map: "Map", + fixed_digits: int = 0, + min: t.Optional[int] = None, + max: t.Optional[int] = None, + signed: bool = False, + ) -> None: + if signed: + self.regex = self.signed_regex + super().__init__(map) + self.fixed_digits = fixed_digits + self.min = min + self.max = max + self.signed = signed + + def to_python(self, value: str) -> t.Any: + if self.fixed_digits and len(value) != self.fixed_digits: + raise ValidationError() + value = self.num_convert(value) + if (self.min is not None and value < self.min) or ( + self.max is not None and value > self.max + ): + raise ValidationError() + return value + + def to_url(self, value: t.Any) -> str: + value = str(self.num_convert(value)) + if self.fixed_digits: + value = value.zfill(self.fixed_digits) + return value + + @property + def signed_regex(self) -> str: + return f"-?{self.regex}" + + +class IntegerConverter(NumberConverter): + """This converter only accepts integer values:: + + Rule("/page/") + + By default it only accepts unsigned, positive values. The ``signed`` + parameter will enable signed, negative values. :: + + Rule("/page/") + + :param map: The :class:`Map`. + :param fixed_digits: The number of fixed digits in the URL. If you + set this to ``4`` for example, the rule will only match if the + URL looks like ``/0001/``. The default is variable length. + :param min: The minimal value. + :param max: The maximal value. + :param signed: Allow signed (negative) values. + + .. versionadded:: 0.15 + The ``signed`` parameter. + """ + + regex = r"\d+" + part_isolating = True + + +class FloatConverter(NumberConverter): + """This converter only accepts floating point values:: + + Rule("/probability/") + + By default it only accepts unsigned, positive values. The ``signed`` + parameter will enable signed, negative values. :: + + Rule("/offset/") + + :param map: The :class:`Map`. + :param min: The minimal value. + :param max: The maximal value. + :param signed: Allow signed (negative) values. + + .. versionadded:: 0.15 + The ``signed`` parameter. + """ + + regex = r"\d+\.\d+" + num_convert = float + part_isolating = True + + def __init__( + self, + map: "Map", + min: t.Optional[float] = None, + max: t.Optional[float] = None, + signed: bool = False, + ) -> None: + super().__init__(map, min=min, max=max, signed=signed) # type: ignore + + +class UUIDConverter(BaseConverter): + """This converter only accepts UUID strings:: + + Rule('/object/') + + .. versionadded:: 0.10 + + :param map: the :class:`Map`. + """ + + regex = ( + r"[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-" + r"[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}" + ) + part_isolating = True + + def to_python(self, value: str) -> uuid.UUID: + return uuid.UUID(value) + + def to_url(self, value: uuid.UUID) -> str: + return str(value) + + +#: the default converter mapping for the map. +DEFAULT_CONVERTERS: t.Mapping[str, t.Type[BaseConverter]] = { + "default": UnicodeConverter, + "string": UnicodeConverter, + "any": AnyConverter, + "path": PathConverter, + "int": IntegerConverter, + "float": FloatConverter, + "uuid": UUIDConverter, +} diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/exceptions.py b/.vcrunch/Lib/site-packages/werkzeug/routing/exceptions.py new file mode 100644 index 0000000..7cbe6e9 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/routing/exceptions.py @@ -0,0 +1,146 @@ +import difflib +import typing as t + +from ..exceptions import BadRequest +from ..exceptions import HTTPException +from ..utils import cached_property +from ..utils import redirect + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIEnvironment + from .map import MapAdapter + from .rules import Rule # noqa: F401 + from ..wrappers.request import Request + from ..wrappers.response import Response + + +class RoutingException(Exception): + """Special exceptions that require the application to redirect, notifying + about missing urls, etc. + + :internal: + """ + + +class RequestRedirect(HTTPException, RoutingException): + """Raise if the map requests a redirect. This is for example the case if + `strict_slashes` are activated and an url that requires a trailing slash. + + The attribute `new_url` contains the absolute destination url. + """ + + code = 308 + + def __init__(self, new_url: str) -> None: + super().__init__(new_url) + self.new_url = new_url + + def get_response( + self, + environ: t.Optional[t.Union["WSGIEnvironment", "Request"]] = None, + scope: t.Optional[dict] = None, + ) -> "Response": + return redirect(self.new_url, self.code) + + +class RequestPath(RoutingException): + """Internal exception.""" + + __slots__ = ("path_info",) + + def __init__(self, path_info: str) -> None: + super().__init__() + self.path_info = path_info + + +class RequestAliasRedirect(RoutingException): # noqa: B903 + """This rule is an alias and wants to redirect to the canonical URL.""" + + def __init__(self, matched_values: t.Mapping[str, t.Any], endpoint: str) -> None: + super().__init__() + self.matched_values = matched_values + self.endpoint = endpoint + + +class BuildError(RoutingException, LookupError): + """Raised if the build system cannot find a URL for an endpoint with the + values provided. + """ + + def __init__( + self, + endpoint: str, + values: t.Mapping[str, t.Any], + method: t.Optional[str], + adapter: t.Optional["MapAdapter"] = None, + ) -> None: + super().__init__(endpoint, values, method) + self.endpoint = endpoint + self.values = values + self.method = method + self.adapter = adapter + + @cached_property + def suggested(self) -> t.Optional["Rule"]: + return self.closest_rule(self.adapter) + + def closest_rule(self, adapter: t.Optional["MapAdapter"]) -> t.Optional["Rule"]: + def _score_rule(rule: "Rule") -> float: + return sum( + [ + 0.98 + * difflib.SequenceMatcher( + None, rule.endpoint, self.endpoint + ).ratio(), + 0.01 * bool(set(self.values or ()).issubset(rule.arguments)), + 0.01 * bool(rule.methods and self.method in rule.methods), + ] + ) + + if adapter and adapter.map._rules: + return max(adapter.map._rules, key=_score_rule) + + return None + + def __str__(self) -> str: + message = [f"Could not build url for endpoint {self.endpoint!r}"] + if self.method: + message.append(f" ({self.method!r})") + if self.values: + message.append(f" with values {sorted(self.values)!r}") + message.append(".") + if self.suggested: + if self.endpoint == self.suggested.endpoint: + if ( + self.method + and self.suggested.methods is not None + and self.method not in self.suggested.methods + ): + message.append( + " Did you mean to use methods" + f" {sorted(self.suggested.methods)!r}?" + ) + missing_values = self.suggested.arguments.union( + set(self.suggested.defaults or ()) + ) - set(self.values.keys()) + if missing_values: + message.append( + f" Did you forget to specify values {sorted(missing_values)!r}?" + ) + else: + message.append(f" Did you mean {self.suggested.endpoint!r} instead?") + return "".join(message) + + +class WebsocketMismatch(BadRequest): + """The only matched rule is either a WebSocket and the request is + HTTP, or the rule is HTTP and the request is a WebSocket. + """ + + +class NoMatch(Exception): + __slots__ = ("have_match_for", "websocket_mismatch") + + def __init__(self, have_match_for: t.Set[str], websocket_mismatch: bool) -> None: + self.have_match_for = have_match_for + self.websocket_mismatch = websocket_mismatch diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/map.py b/.vcrunch/Lib/site-packages/werkzeug/routing/map.py new file mode 100644 index 0000000..daf94b6 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/routing/map.py @@ -0,0 +1,944 @@ +import posixpath +import typing as t +import warnings +from pprint import pformat +from threading import Lock + +from .._internal import _encode_idna +from .._internal import _get_environ +from .._internal import _to_str +from .._internal import _wsgi_decoding_dance +from ..datastructures import ImmutableDict +from ..datastructures import MultiDict +from ..exceptions import BadHost +from ..exceptions import HTTPException +from ..exceptions import MethodNotAllowed +from ..exceptions import NotFound +from ..urls import url_encode +from ..urls import url_join +from ..urls import url_quote +from ..wsgi import get_host +from .converters import DEFAULT_CONVERTERS +from .exceptions import BuildError +from .exceptions import NoMatch +from .exceptions import RequestAliasRedirect +from .exceptions import RequestPath +from .exceptions import RequestRedirect +from .exceptions import WebsocketMismatch +from .matcher import StateMachineMatcher +from .rules import _simple_rule_re +from .rules import Rule + +if t.TYPE_CHECKING: + import typing_extensions as te + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + from .converters import BaseConverter + from .rules import RuleFactory + from ..wrappers.request import Request + + +class Map: + """The map class stores all the URL rules and some configuration + parameters. Some of the configuration values are only stored on the + `Map` instance since those affect all rules, others are just defaults + and can be overridden for each rule. Note that you have to specify all + arguments besides the `rules` as keyword arguments! + + :param rules: sequence of url rules for this map. + :param default_subdomain: The default subdomain for rules without a + subdomain defined. + :param charset: charset of the url. defaults to ``"utf-8"`` + :param strict_slashes: If a rule ends with a slash but the matched + URL does not, redirect to the URL with a trailing slash. + :param merge_slashes: Merge consecutive slashes when matching or + building URLs. Matches will redirect to the normalized URL. + Slashes in variable parts are not merged. + :param redirect_defaults: This will redirect to the default rule if it + wasn't visited that way. This helps creating + unique URLs. + :param converters: A dict of converters that adds additional converters + to the list of converters. If you redefine one + converter this will override the original one. + :param sort_parameters: If set to `True` the url parameters are sorted. + See `url_encode` for more details. + :param sort_key: The sort key function for `url_encode`. + :param encoding_errors: the error method to use for decoding + :param host_matching: if set to `True` it enables the host matching + feature and disables the subdomain one. If + enabled the `host` parameter to rules is used + instead of the `subdomain` one. + + .. versionchanged:: 1.0 + If ``url_scheme`` is ``ws`` or ``wss``, only WebSocket rules + will match. + + .. versionchanged:: 1.0 + Added ``merge_slashes``. + + .. versionchanged:: 0.7 + Added ``encoding_errors`` and ``host_matching``. + + .. versionchanged:: 0.5 + Added ``sort_parameters`` and ``sort_key``. + """ + + #: A dict of default converters to be used. + default_converters = ImmutableDict(DEFAULT_CONVERTERS) + + #: The type of lock to use when updating. + #: + #: .. versionadded:: 1.0 + lock_class = Lock + + def __init__( + self, + rules: t.Optional[t.Iterable["RuleFactory"]] = None, + default_subdomain: str = "", + charset: str = "utf-8", + strict_slashes: bool = True, + merge_slashes: bool = True, + redirect_defaults: bool = True, + converters: t.Optional[t.Mapping[str, t.Type["BaseConverter"]]] = None, + sort_parameters: bool = False, + sort_key: t.Optional[t.Callable[[t.Any], t.Any]] = None, + encoding_errors: str = "replace", + host_matching: bool = False, + ) -> None: + self._matcher = StateMachineMatcher(merge_slashes) + self._rules_by_endpoint: t.Dict[str, t.List[Rule]] = {} + self._remap = True + self._remap_lock = self.lock_class() + + self.default_subdomain = default_subdomain + self.charset = charset + self.encoding_errors = encoding_errors + self.strict_slashes = strict_slashes + self.merge_slashes = merge_slashes + self.redirect_defaults = redirect_defaults + self.host_matching = host_matching + + self.converters = self.default_converters.copy() + if converters: + self.converters.update(converters) + + self.sort_parameters = sort_parameters + self.sort_key = sort_key + + for rulefactory in rules or (): + self.add(rulefactory) + + def is_endpoint_expecting(self, endpoint: str, *arguments: str) -> bool: + """Iterate over all rules and check if the endpoint expects + the arguments provided. This is for example useful if you have + some URLs that expect a language code and others that do not and + you want to wrap the builder a bit so that the current language + code is automatically added if not provided but endpoints expect + it. + + :param endpoint: the endpoint to check. + :param arguments: this function accepts one or more arguments + as positional arguments. Each one of them is + checked. + """ + self.update() + arguments = set(arguments) + for rule in self._rules_by_endpoint[endpoint]: + if arguments.issubset(rule.arguments): + return True + return False + + @property + def _rules(self) -> t.List[Rule]: + return [rule for rules in self._rules_by_endpoint.values() for rule in rules] + + def iter_rules(self, endpoint: t.Optional[str] = None) -> t.Iterator[Rule]: + """Iterate over all rules or the rules of an endpoint. + + :param endpoint: if provided only the rules for that endpoint + are returned. + :return: an iterator + """ + self.update() + if endpoint is not None: + return iter(self._rules_by_endpoint[endpoint]) + return iter(self._rules) + + def add(self, rulefactory: "RuleFactory") -> None: + """Add a new rule or factory to the map and bind it. Requires that the + rule is not bound to another map. + + :param rulefactory: a :class:`Rule` or :class:`RuleFactory` + """ + for rule in rulefactory.get_rules(self): + rule.bind(self) + if not rule.build_only: + self._matcher.add(rule) + self._rules_by_endpoint.setdefault(rule.endpoint, []).append(rule) + self._remap = True + + def bind( + self, + server_name: str, + script_name: t.Optional[str] = None, + subdomain: t.Optional[str] = None, + url_scheme: str = "http", + default_method: str = "GET", + path_info: t.Optional[str] = None, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + ) -> "MapAdapter": + """Return a new :class:`MapAdapter` with the details specified to the + call. Note that `script_name` will default to ``'/'`` if not further + specified or `None`. The `server_name` at least is a requirement + because the HTTP RFC requires absolute URLs for redirects and so all + redirect exceptions raised by Werkzeug will contain the full canonical + URL. + + If no path_info is passed to :meth:`match` it will use the default path + info passed to bind. While this doesn't really make sense for + manual bind calls, it's useful if you bind a map to a WSGI + environment which already contains the path info. + + `subdomain` will default to the `default_subdomain` for this map if + no defined. If there is no `default_subdomain` you cannot use the + subdomain feature. + + .. versionchanged:: 1.0 + If ``url_scheme`` is ``ws`` or ``wss``, only WebSocket rules + will match. + + .. versionchanged:: 0.15 + ``path_info`` defaults to ``'/'`` if ``None``. + + .. versionchanged:: 0.8 + ``query_args`` can be a string. + + .. versionchanged:: 0.7 + Added ``query_args``. + """ + server_name = server_name.lower() + if self.host_matching: + if subdomain is not None: + raise RuntimeError("host matching enabled and a subdomain was provided") + elif subdomain is None: + subdomain = self.default_subdomain + if script_name is None: + script_name = "/" + if path_info is None: + path_info = "/" + + try: + server_name = _encode_idna(server_name) # type: ignore + except UnicodeError as e: + raise BadHost() from e + + return MapAdapter( + self, + server_name, + script_name, + subdomain, + url_scheme, + path_info, + default_method, + query_args, + ) + + def bind_to_environ( + self, + environ: t.Union["WSGIEnvironment", "Request"], + server_name: t.Optional[str] = None, + subdomain: t.Optional[str] = None, + ) -> "MapAdapter": + """Like :meth:`bind` but you can pass it an WSGI environment and it + will fetch the information from that dictionary. Note that because of + limitations in the protocol there is no way to get the current + subdomain and real `server_name` from the environment. If you don't + provide it, Werkzeug will use `SERVER_NAME` and `SERVER_PORT` (or + `HTTP_HOST` if provided) as used `server_name` with disabled subdomain + feature. + + If `subdomain` is `None` but an environment and a server name is + provided it will calculate the current subdomain automatically. + Example: `server_name` is ``'example.com'`` and the `SERVER_NAME` + in the wsgi `environ` is ``'staging.dev.example.com'`` the calculated + subdomain will be ``'staging.dev'``. + + If the object passed as environ has an environ attribute, the value of + this attribute is used instead. This allows you to pass request + objects. Additionally `PATH_INFO` added as a default of the + :class:`MapAdapter` so that you don't have to pass the path info to + the match method. + + .. versionchanged:: 1.0.0 + If the passed server name specifies port 443, it will match + if the incoming scheme is ``https`` without a port. + + .. versionchanged:: 1.0.0 + A warning is shown when the passed server name does not + match the incoming WSGI server name. + + .. versionchanged:: 0.8 + This will no longer raise a ValueError when an unexpected server + name was passed. + + .. versionchanged:: 0.5 + previously this method accepted a bogus `calculate_subdomain` + parameter that did not have any effect. It was removed because + of that. + + :param environ: a WSGI environment. + :param server_name: an optional server name hint (see above). + :param subdomain: optionally the current subdomain (see above). + """ + env = _get_environ(environ) + wsgi_server_name = get_host(env).lower() + scheme = env["wsgi.url_scheme"] + upgrade = any( + v.strip() == "upgrade" + for v in env.get("HTTP_CONNECTION", "").lower().split(",") + ) + + if upgrade and env.get("HTTP_UPGRADE", "").lower() == "websocket": + scheme = "wss" if scheme == "https" else "ws" + + if server_name is None: + server_name = wsgi_server_name + else: + server_name = server_name.lower() + + # strip standard port to match get_host() + if scheme in {"http", "ws"} and server_name.endswith(":80"): + server_name = server_name[:-3] + elif scheme in {"https", "wss"} and server_name.endswith(":443"): + server_name = server_name[:-4] + + if subdomain is None and not self.host_matching: + cur_server_name = wsgi_server_name.split(".") + real_server_name = server_name.split(".") + offset = -len(real_server_name) + + if cur_server_name[offset:] != real_server_name: + # This can happen even with valid configs if the server was + # accessed directly by IP address under some situations. + # Instead of raising an exception like in Werkzeug 0.7 or + # earlier we go by an invalid subdomain which will result + # in a 404 error on matching. + warnings.warn( + f"Current server name {wsgi_server_name!r} doesn't match configured" + f" server name {server_name!r}", + stacklevel=2, + ) + subdomain = "" + else: + subdomain = ".".join(filter(None, cur_server_name[:offset])) + + def _get_wsgi_string(name: str) -> t.Optional[str]: + val = env.get(name) + if val is not None: + return _wsgi_decoding_dance(val, self.charset) + return None + + script_name = _get_wsgi_string("SCRIPT_NAME") + path_info = _get_wsgi_string("PATH_INFO") + query_args = _get_wsgi_string("QUERY_STRING") + return Map.bind( + self, + server_name, + script_name, + subdomain, + scheme, + env["REQUEST_METHOD"], + path_info, + query_args=query_args, + ) + + def update(self) -> None: + """Called before matching and building to keep the compiled rules + in the correct order after things changed. + """ + if not self._remap: + return + + with self._remap_lock: + if not self._remap: + return + + self._matcher.update() + for rules in self._rules_by_endpoint.values(): + rules.sort(key=lambda x: x.build_compare_key()) + self._remap = False + + def __repr__(self) -> str: + rules = self.iter_rules() + return f"{type(self).__name__}({pformat(list(rules))})" + + +class MapAdapter: + + """Returned by :meth:`Map.bind` or :meth:`Map.bind_to_environ` and does + the URL matching and building based on runtime information. + """ + + def __init__( + self, + map: Map, + server_name: str, + script_name: str, + subdomain: t.Optional[str], + url_scheme: str, + path_info: str, + default_method: str, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + ): + self.map = map + self.server_name = _to_str(server_name) + script_name = _to_str(script_name) + if not script_name.endswith("/"): + script_name += "/" + self.script_name = script_name + self.subdomain = _to_str(subdomain) + self.url_scheme = _to_str(url_scheme) + self.path_info = _to_str(path_info) + self.default_method = _to_str(default_method) + self.query_args = query_args + self.websocket = self.url_scheme in {"ws", "wss"} + + def dispatch( + self, + view_func: t.Callable[[str, t.Mapping[str, t.Any]], "WSGIApplication"], + path_info: t.Optional[str] = None, + method: t.Optional[str] = None, + catch_http_exceptions: bool = False, + ) -> "WSGIApplication": + """Does the complete dispatching process. `view_func` is called with + the endpoint and a dict with the values for the view. It should + look up the view function, call it, and return a response object + or WSGI application. http exceptions are not caught by default + so that applications can display nicer error messages by just + catching them by hand. If you want to stick with the default + error messages you can pass it ``catch_http_exceptions=True`` and + it will catch the http exceptions. + + Here a small example for the dispatch usage:: + + from werkzeug.wrappers import Request, Response + from werkzeug.wsgi import responder + from werkzeug.routing import Map, Rule + + def on_index(request): + return Response('Hello from the index') + + url_map = Map([Rule('/', endpoint='index')]) + views = {'index': on_index} + + @responder + def application(environ, start_response): + request = Request(environ) + urls = url_map.bind_to_environ(environ) + return urls.dispatch(lambda e, v: views[e](request, **v), + catch_http_exceptions=True) + + Keep in mind that this method might return exception objects, too, so + use :class:`Response.force_type` to get a response object. + + :param view_func: a function that is called with the endpoint as + first argument and the value dict as second. Has + to dispatch to the actual view function with this + information. (see above) + :param path_info: the path info to use for matching. Overrides the + path info specified on binding. + :param method: the HTTP method used for matching. Overrides the + method specified on binding. + :param catch_http_exceptions: set to `True` to catch any of the + werkzeug :class:`HTTPException`\\s. + """ + try: + try: + endpoint, args = self.match(path_info, method) + except RequestRedirect as e: + return e + return view_func(endpoint, args) + except HTTPException as e: + if catch_http_exceptions: + return e + raise + + @t.overload + def match( # type: ignore + self, + path_info: t.Optional[str] = None, + method: t.Optional[str] = None, + return_rule: "te.Literal[False]" = False, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + websocket: t.Optional[bool] = None, + ) -> t.Tuple[str, t.Mapping[str, t.Any]]: + ... + + @t.overload + def match( + self, + path_info: t.Optional[str] = None, + method: t.Optional[str] = None, + return_rule: "te.Literal[True]" = True, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + websocket: t.Optional[bool] = None, + ) -> t.Tuple[Rule, t.Mapping[str, t.Any]]: + ... + + def match( + self, + path_info: t.Optional[str] = None, + method: t.Optional[str] = None, + return_rule: bool = False, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + websocket: t.Optional[bool] = None, + ) -> t.Tuple[t.Union[str, Rule], t.Mapping[str, t.Any]]: + """The usage is simple: you just pass the match method the current + path info as well as the method (which defaults to `GET`). The + following things can then happen: + + - you receive a `NotFound` exception that indicates that no URL is + matching. A `NotFound` exception is also a WSGI application you + can call to get a default page not found page (happens to be the + same object as `werkzeug.exceptions.NotFound`) + + - you receive a `MethodNotAllowed` exception that indicates that there + is a match for this URL but not for the current request method. + This is useful for RESTful applications. + + - you receive a `RequestRedirect` exception with a `new_url` + attribute. This exception is used to notify you about a request + Werkzeug requests from your WSGI application. This is for example the + case if you request ``/foo`` although the correct URL is ``/foo/`` + You can use the `RequestRedirect` instance as response-like object + similar to all other subclasses of `HTTPException`. + + - you receive a ``WebsocketMismatch`` exception if the only + match is a WebSocket rule but the bind is an HTTP request, or + if the match is an HTTP rule but the bind is a WebSocket + request. + + - you get a tuple in the form ``(endpoint, arguments)`` if there is + a match (unless `return_rule` is True, in which case you get a tuple + in the form ``(rule, arguments)``) + + If the path info is not passed to the match method the default path + info of the map is used (defaults to the root URL if not defined + explicitly). + + All of the exceptions raised are subclasses of `HTTPException` so they + can be used as WSGI responses. They will all render generic error or + redirect pages. + + Here is a small example for matching: + + >>> m = Map([ + ... Rule('/', endpoint='index'), + ... Rule('/downloads/', endpoint='downloads/index'), + ... Rule('/downloads/', endpoint='downloads/show') + ... ]) + >>> urls = m.bind("example.com", "/") + >>> urls.match("/", "GET") + ('index', {}) + >>> urls.match("/downloads/42") + ('downloads/show', {'id': 42}) + + And here is what happens on redirect and missing URLs: + + >>> urls.match("/downloads") + Traceback (most recent call last): + ... + RequestRedirect: http://example.com/downloads/ + >>> urls.match("/missing") + Traceback (most recent call last): + ... + NotFound: 404 Not Found + + :param path_info: the path info to use for matching. Overrides the + path info specified on binding. + :param method: the HTTP method used for matching. Overrides the + method specified on binding. + :param return_rule: return the rule that matched instead of just the + endpoint (defaults to `False`). + :param query_args: optional query arguments that are used for + automatic redirects as string or dictionary. It's + currently not possible to use the query arguments + for URL matching. + :param websocket: Match WebSocket instead of HTTP requests. A + websocket request has a ``ws`` or ``wss`` + :attr:`url_scheme`. This overrides that detection. + + .. versionadded:: 1.0 + Added ``websocket``. + + .. versionchanged:: 0.8 + ``query_args`` can be a string. + + .. versionadded:: 0.7 + Added ``query_args``. + + .. versionadded:: 0.6 + Added ``return_rule``. + """ + self.map.update() + if path_info is None: + path_info = self.path_info + else: + path_info = _to_str(path_info, self.map.charset) + if query_args is None: + query_args = self.query_args or {} + method = (method or self.default_method).upper() + + if websocket is None: + websocket = self.websocket + + domain_part = self.server_name if self.map.host_matching else self.subdomain + path_part = f"/{path_info.lstrip('/')}" if path_info else "" + + try: + result = self.map._matcher.match(domain_part, path_part, method, websocket) + except RequestPath as e: + raise RequestRedirect( + self.make_redirect_url( + url_quote(e.path_info, self.map.charset, safe="/:|+"), + query_args, + ) + ) from None + except RequestAliasRedirect as e: + raise RequestRedirect( + self.make_alias_redirect_url( + f"{domain_part}|{path_part}", + e.endpoint, + e.matched_values, + method, + query_args, + ) + ) from None + except NoMatch as e: + if e.have_match_for: + raise MethodNotAllowed(valid_methods=list(e.have_match_for)) from None + + if e.websocket_mismatch: + raise WebsocketMismatch() from None + + raise NotFound() from None + else: + rule, rv = result + + if self.map.redirect_defaults: + redirect_url = self.get_default_redirect(rule, method, rv, query_args) + if redirect_url is not None: + raise RequestRedirect(redirect_url) + + if rule.redirect_to is not None: + if isinstance(rule.redirect_to, str): + + def _handle_match(match: t.Match[str]) -> str: + value = rv[match.group(1)] + return rule._converters[match.group(1)].to_url(value) + + redirect_url = _simple_rule_re.sub(_handle_match, rule.redirect_to) + else: + redirect_url = rule.redirect_to(self, **rv) + + if self.subdomain: + netloc = f"{self.subdomain}.{self.server_name}" + else: + netloc = self.server_name + + raise RequestRedirect( + url_join( + f"{self.url_scheme or 'http'}://{netloc}{self.script_name}", + redirect_url, + ) + ) + + if return_rule: + return rule, rv + else: + return rule.endpoint, rv + + def test( + self, path_info: t.Optional[str] = None, method: t.Optional[str] = None + ) -> bool: + """Test if a rule would match. Works like `match` but returns `True` + if the URL matches, or `False` if it does not exist. + + :param path_info: the path info to use for matching. Overrides the + path info specified on binding. + :param method: the HTTP method used for matching. Overrides the + method specified on binding. + """ + try: + self.match(path_info, method) + except RequestRedirect: + pass + except HTTPException: + return False + return True + + def allowed_methods(self, path_info: t.Optional[str] = None) -> t.Iterable[str]: + """Returns the valid methods that match for a given path. + + .. versionadded:: 0.7 + """ + try: + self.match(path_info, method="--") + except MethodNotAllowed as e: + return e.valid_methods # type: ignore + except HTTPException: + pass + return [] + + def get_host(self, domain_part: t.Optional[str]) -> str: + """Figures out the full host name for the given domain part. The + domain part is a subdomain in case host matching is disabled or + a full host name. + """ + if self.map.host_matching: + if domain_part is None: + return self.server_name + return _to_str(domain_part, "ascii") + subdomain = domain_part + if subdomain is None: + subdomain = self.subdomain + else: + subdomain = _to_str(subdomain, "ascii") + + if subdomain: + return f"{subdomain}.{self.server_name}" + else: + return self.server_name + + def get_default_redirect( + self, + rule: Rule, + method: str, + values: t.MutableMapping[str, t.Any], + query_args: t.Union[t.Mapping[str, t.Any], str], + ) -> t.Optional[str]: + """A helper that returns the URL to redirect to if it finds one. + This is used for default redirecting only. + + :internal: + """ + assert self.map.redirect_defaults + for r in self.map._rules_by_endpoint[rule.endpoint]: + # every rule that comes after this one, including ourself + # has a lower priority for the defaults. We order the ones + # with the highest priority up for building. + if r is rule: + break + if r.provides_defaults_for(rule) and r.suitable_for(values, method): + values.update(r.defaults) # type: ignore + domain_part, path = r.build(values) # type: ignore + return self.make_redirect_url(path, query_args, domain_part=domain_part) + return None + + def encode_query_args(self, query_args: t.Union[t.Mapping[str, t.Any], str]) -> str: + if not isinstance(query_args, str): + return url_encode(query_args, self.map.charset) + return query_args + + def make_redirect_url( + self, + path_info: str, + query_args: t.Optional[t.Union[t.Mapping[str, t.Any], str]] = None, + domain_part: t.Optional[str] = None, + ) -> str: + """Creates a redirect URL. + + :internal: + """ + if query_args: + suffix = f"?{self.encode_query_args(query_args)}" + else: + suffix = "" + + scheme = self.url_scheme or "http" + host = self.get_host(domain_part) + path = posixpath.join(self.script_name.strip("/"), path_info.lstrip("/")) + return f"{scheme}://{host}/{path}{suffix}" + + def make_alias_redirect_url( + self, + path: str, + endpoint: str, + values: t.Mapping[str, t.Any], + method: str, + query_args: t.Union[t.Mapping[str, t.Any], str], + ) -> str: + """Internally called to make an alias redirect URL.""" + url = self.build( + endpoint, values, method, append_unknown=False, force_external=True + ) + if query_args: + url += f"?{self.encode_query_args(query_args)}" + assert url != path, "detected invalid alias setting. No canonical URL found" + return url + + def _partial_build( + self, + endpoint: str, + values: t.Mapping[str, t.Any], + method: t.Optional[str], + append_unknown: bool, + ) -> t.Optional[t.Tuple[str, str, bool]]: + """Helper for :meth:`build`. Returns subdomain and path for the + rule that accepts this endpoint, values and method. + + :internal: + """ + # in case the method is none, try with the default method first + if method is None: + rv = self._partial_build( + endpoint, values, self.default_method, append_unknown + ) + if rv is not None: + return rv + + # Default method did not match or a specific method is passed. + # Check all for first match with matching host. If no matching + # host is found, go with first result. + first_match = None + + for rule in self.map._rules_by_endpoint.get(endpoint, ()): + if rule.suitable_for(values, method): + build_rv = rule.build(values, append_unknown) + + if build_rv is not None: + rv = (build_rv[0], build_rv[1], rule.websocket) + if self.map.host_matching: + if rv[0] == self.server_name: + return rv + elif first_match is None: + first_match = rv + else: + return rv + + return first_match + + def build( + self, + endpoint: str, + values: t.Optional[t.Mapping[str, t.Any]] = None, + method: t.Optional[str] = None, + force_external: bool = False, + append_unknown: bool = True, + url_scheme: t.Optional[str] = None, + ) -> str: + """Building URLs works pretty much the other way round. Instead of + `match` you call `build` and pass it the endpoint and a dict of + arguments for the placeholders. + + The `build` function also accepts an argument called `force_external` + which, if you set it to `True` will force external URLs. Per default + external URLs (include the server name) will only be used if the + target URL is on a different subdomain. + + >>> m = Map([ + ... Rule('/', endpoint='index'), + ... Rule('/downloads/', endpoint='downloads/index'), + ... Rule('/downloads/', endpoint='downloads/show') + ... ]) + >>> urls = m.bind("example.com", "/") + >>> urls.build("index", {}) + '/' + >>> urls.build("downloads/show", {'id': 42}) + '/downloads/42' + >>> urls.build("downloads/show", {'id': 42}, force_external=True) + 'http://example.com/downloads/42' + + Because URLs cannot contain non ASCII data you will always get + bytes back. Non ASCII characters are urlencoded with the + charset defined on the map instance. + + Additional values are converted to strings and appended to the URL as + URL querystring parameters: + + >>> urls.build("index", {'q': 'My Searchstring'}) + '/?q=My+Searchstring' + + When processing those additional values, lists are furthermore + interpreted as multiple values (as per + :py:class:`werkzeug.datastructures.MultiDict`): + + >>> urls.build("index", {'q': ['a', 'b', 'c']}) + '/?q=a&q=b&q=c' + + Passing a ``MultiDict`` will also add multiple values: + + >>> urls.build("index", MultiDict((('p', 'z'), ('q', 'a'), ('q', 'b')))) + '/?p=z&q=a&q=b' + + If a rule does not exist when building a `BuildError` exception is + raised. + + The build method accepts an argument called `method` which allows you + to specify the method you want to have an URL built for if you have + different methods for the same endpoint specified. + + :param endpoint: the endpoint of the URL to build. + :param values: the values for the URL to build. Unhandled values are + appended to the URL as query parameters. + :param method: the HTTP method for the rule if there are different + URLs for different methods on the same endpoint. + :param force_external: enforce full canonical external URLs. If the URL + scheme is not provided, this will generate + a protocol-relative URL. + :param append_unknown: unknown parameters are appended to the generated + URL as query string argument. Disable this + if you want the builder to ignore those. + :param url_scheme: Scheme to use in place of the bound + :attr:`url_scheme`. + + .. versionchanged:: 2.0 + Added the ``url_scheme`` parameter. + + .. versionadded:: 0.6 + Added the ``append_unknown`` parameter. + """ + self.map.update() + + if values: + if isinstance(values, MultiDict): + values = { + k: (v[0] if len(v) == 1 else v) + for k, v in dict.items(values) + if len(v) != 0 + } + else: # plain dict + values = {k: v for k, v in values.items() if v is not None} + else: + values = {} + + rv = self._partial_build(endpoint, values, method, append_unknown) + if rv is None: + raise BuildError(endpoint, values, method, self) + + domain_part, path, websocket = rv + host = self.get_host(domain_part) + + if url_scheme is None: + url_scheme = self.url_scheme + + # Always build WebSocket routes with the scheme (browsers + # require full URLs). If bound to a WebSocket, ensure that HTTP + # routes are built with an HTTP scheme. + secure = url_scheme in {"https", "wss"} + + if websocket: + force_external = True + url_scheme = "wss" if secure else "ws" + elif url_scheme: + url_scheme = "https" if secure else "http" + + # shortcut this. + if not force_external and ( + (self.map.host_matching and host == self.server_name) + or (not self.map.host_matching and domain_part == self.subdomain) + ): + return f"{self.script_name.rstrip('/')}/{path.lstrip('/')}" + + scheme = f"{url_scheme}:" if url_scheme else "" + return f"{scheme}//{host}{self.script_name[:-1]}/{path.lstrip('/')}" diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/matcher.py b/.vcrunch/Lib/site-packages/werkzeug/routing/matcher.py new file mode 100644 index 0000000..d22b05a --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/routing/matcher.py @@ -0,0 +1,185 @@ +import re +import typing as t +from dataclasses import dataclass +from dataclasses import field + +from .converters import ValidationError +from .exceptions import NoMatch +from .exceptions import RequestAliasRedirect +from .exceptions import RequestPath +from .rules import Rule +from .rules import RulePart + + +class SlashRequired(Exception): + pass + + +@dataclass +class State: + """A representation of a rule state. + + This includes the *rules* that correspond to the state and the + possible *static* and *dynamic* transitions to the next state. + """ + + dynamic: t.List[t.Tuple[RulePart, "State"]] = field(default_factory=list) + rules: t.List[Rule] = field(default_factory=list) + static: t.Dict[str, "State"] = field(default_factory=dict) + + +class StateMachineMatcher: + def __init__(self, merge_slashes: bool) -> None: + self._root = State() + self.merge_slashes = merge_slashes + + def add(self, rule: Rule) -> None: + state = self._root + for part in rule._parts: + if part.static: + state.static.setdefault(part.content, State()) + state = state.static[part.content] + else: + for test_part, new_state in state.dynamic: + if test_part == part: + state = new_state + break + else: + new_state = State() + state.dynamic.append((part, new_state)) + state = new_state + state.rules.append(rule) + + def update(self) -> None: + # For every state the dynamic transitions should be sorted by + # the weight of the transition + state = self._root + + def _update_state(state: State) -> None: + state.dynamic.sort(key=lambda entry: entry[0].weight) + for new_state in state.static.values(): + _update_state(new_state) + for _, new_state in state.dynamic: + _update_state(new_state) + + _update_state(state) + + def match( + self, domain: str, path: str, method: str, websocket: bool + ) -> t.Tuple[Rule, t.MutableMapping[str, t.Any]]: + # To match to a rule we need to start at the root state and + # try to follow the transitions until we find a match, or find + # there is no transition to follow. + + have_match_for = set() + websocket_mismatch = False + + def _match( + state: State, parts: t.List[str], values: t.List[str] + ) -> t.Optional[t.Tuple[Rule, t.List[str]]]: + # This function is meant to be called recursively, and will attempt + # to match the head part to the state's transitions. + nonlocal have_match_for, websocket_mismatch + + # The base case is when all parts have been matched via + # transitions. Hence if there is a rule with methods & + # websocket that work return it and the dynamic values + # extracted. + if parts == []: + for rule in state.rules: + if rule.methods is not None and method not in rule.methods: + have_match_for.update(rule.methods) + elif rule.websocket != websocket: + websocket_mismatch = True + else: + return rule, values + + # Test if there is a match with this path with a + # trailing slash, if so raise an exception to report + # that matching is possible with an additional slash + if "" in state.static: + for rule in state.static[""].rules: + if websocket == rule.websocket and ( + rule.methods is None or method in rule.methods + ): + if rule.strict_slashes: + raise SlashRequired() + else: + return rule, values + return None + + part = parts[0] + # To match this part try the static transitions first + if part in state.static: + rv = _match(state.static[part], parts[1:], values) + if rv is not None: + return rv + # No match via the static transitions, so try the dynamic + # ones. + for test_part, new_state in state.dynamic: + target = part + remaining = parts[1:] + # A final part indicates a transition that always + # consumes the remaining parts i.e. transitions to a + # final state. + if test_part.final: + target = "/".join(parts) + remaining = [] + match = re.compile(test_part.content).match(target) + if match is not None: + rv = _match(new_state, remaining, values + list(match.groups())) + if rv is not None: + return rv + + # If there is no match and the only part left is a + # trailing slash ("") consider rules that aren't + # strict-slashes as these should match if there is a final + # slash part. + if parts == [""]: + for rule in state.rules: + if rule.strict_slashes: + continue + if rule.methods is not None and method not in rule.methods: + have_match_for.update(rule.methods) + elif rule.websocket != websocket: + websocket_mismatch = True + else: + return rule, values + + return None + + try: + rv = _match(self._root, [domain, *path.split("/")], []) + except SlashRequired: + raise RequestPath(f"{path}/") from None + + if self.merge_slashes and rv is None: + # Try to match again, but with slashes merged + path = re.sub("/{2,}?", "/", path) + try: + rv = _match(self._root, [domain, *path.split("/")], []) + except SlashRequired: + raise RequestPath(f"{path}/") from None + if rv is None: + raise NoMatch(have_match_for, websocket_mismatch) + else: + raise RequestPath(f"{path}") + elif rv is not None: + rule, values = rv + + result = {} + for name, value in zip(rule._converters.keys(), values): + try: + value = rule._converters[name].to_python(value) + except ValidationError: + raise NoMatch(have_match_for, websocket_mismatch) from None + result[str(name)] = value + if rule.defaults: + result.update(rule.defaults) + + if rule.alias and rule.map.redirect_defaults: + raise RequestAliasRedirect(result, rule.endpoint) + + return rule, result + + raise NoMatch(have_match_for, websocket_mismatch) diff --git a/.vcrunch/Lib/site-packages/werkzeug/routing/rules.py b/.vcrunch/Lib/site-packages/werkzeug/routing/rules.py new file mode 100644 index 0000000..a61717a --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/routing/rules.py @@ -0,0 +1,879 @@ +import ast +import re +import typing as t +from dataclasses import dataclass +from string import Template +from types import CodeType + +from .._internal import _to_bytes +from ..urls import url_encode +from ..urls import url_quote +from .converters import ValidationError + +if t.TYPE_CHECKING: + from .converters import BaseConverter + from .map import Map + + +class Weighting(t.NamedTuple): + number_static_weights: int + static_weights: t.List[t.Tuple[int, int]] + number_argument_weights: int + argument_weights: t.List[int] + + +@dataclass +class RulePart: + """A part of a rule. + + Rules can be represented by parts as delimited by `/` with + instances of this class representing those parts. The *content* is + either the raw content if *static* or a regex string to match + against. The *weight* can be used to order parts when matching. + + """ + + content: str + final: bool + static: bool + weight: Weighting + + +_part_re = re.compile( + r""" + (?: + (?P\/) # a slash + | + (?P[^<\/]+) # static rule data + | + (?: + < + (?: + (?P[a-zA-Z_][a-zA-Z0-9_]*) # converter name + (?:\((?P.*?)\))? # converter arguments + \: # variable delimiter + )? + (?P[a-zA-Z_][a-zA-Z0-9_]*) # variable name + > + ) + ) + """, + re.VERBOSE, +) + +_simple_rule_re = re.compile(r"<([^>]+)>") +_converter_args_re = re.compile( + r""" + ((?P\w+)\s*=\s*)? + (?P + True|False| + \d+.\d+| + \d+.| + \d+| + [\w\d_.]+| + [urUR]?(?P"[^"]*?"|'[^']*') + )\s*, + """, + re.VERBOSE, +) + + +_PYTHON_CONSTANTS = {"None": None, "True": True, "False": False} + + +def _find(value: str, target: str, pos: int) -> int: + """Find the *target* in *value* after *pos*. + + Returns the *value* length if *target* isn't found. + """ + try: + return value.index(target, pos) + except ValueError: + return len(value) + + +def _pythonize(value: str) -> t.Union[None, bool, int, float, str]: + if value in _PYTHON_CONSTANTS: + return _PYTHON_CONSTANTS[value] + for convert in int, float: + try: + return convert(value) # type: ignore + except ValueError: + pass + if value[:1] == value[-1:] and value[0] in "\"'": + value = value[1:-1] + return str(value) + + +def parse_converter_args(argstr: str) -> t.Tuple[t.Tuple, t.Dict[str, t.Any]]: + argstr += "," + args = [] + kwargs = {} + + for item in _converter_args_re.finditer(argstr): + value = item.group("stringval") + if value is None: + value = item.group("value") + value = _pythonize(value) + if not item.group("name"): + args.append(value) + else: + name = item.group("name") + kwargs[name] = value + + return tuple(args), kwargs + + +class RuleFactory: + """As soon as you have more complex URL setups it's a good idea to use rule + factories to avoid repetitive tasks. Some of them are builtin, others can + be added by subclassing `RuleFactory` and overriding `get_rules`. + """ + + def get_rules(self, map: "Map") -> t.Iterable["Rule"]: + """Subclasses of `RuleFactory` have to override this method and return + an iterable of rules.""" + raise NotImplementedError() + + +class Subdomain(RuleFactory): + """All URLs provided by this factory have the subdomain set to a + specific domain. For example if you want to use the subdomain for + the current language this can be a good setup:: + + url_map = Map([ + Rule('/', endpoint='#select_language'), + Subdomain('', [ + Rule('/', endpoint='index'), + Rule('/about', endpoint='about'), + Rule('/help', endpoint='help') + ]) + ]) + + All the rules except for the ``'#select_language'`` endpoint will now + listen on a two letter long subdomain that holds the language code + for the current request. + """ + + def __init__(self, subdomain: str, rules: t.Iterable[RuleFactory]) -> None: + self.subdomain = subdomain + self.rules = rules + + def get_rules(self, map: "Map") -> t.Iterator["Rule"]: + for rulefactory in self.rules: + for rule in rulefactory.get_rules(map): + rule = rule.empty() + rule.subdomain = self.subdomain + yield rule + + +class Submount(RuleFactory): + """Like `Subdomain` but prefixes the URL rule with a given string:: + + url_map = Map([ + Rule('/', endpoint='index'), + Submount('/blog', [ + Rule('/', endpoint='blog/index'), + Rule('/entry/', endpoint='blog/show') + ]) + ]) + + Now the rule ``'blog/show'`` matches ``/blog/entry/``. + """ + + def __init__(self, path: str, rules: t.Iterable[RuleFactory]) -> None: + self.path = path.rstrip("/") + self.rules = rules + + def get_rules(self, map: "Map") -> t.Iterator["Rule"]: + for rulefactory in self.rules: + for rule in rulefactory.get_rules(map): + rule = rule.empty() + rule.rule = self.path + rule.rule + yield rule + + +class EndpointPrefix(RuleFactory): + """Prefixes all endpoints (which must be strings for this factory) with + another string. This can be useful for sub applications:: + + url_map = Map([ + Rule('/', endpoint='index'), + EndpointPrefix('blog/', [Submount('/blog', [ + Rule('/', endpoint='index'), + Rule('/entry/', endpoint='show') + ])]) + ]) + """ + + def __init__(self, prefix: str, rules: t.Iterable[RuleFactory]) -> None: + self.prefix = prefix + self.rules = rules + + def get_rules(self, map: "Map") -> t.Iterator["Rule"]: + for rulefactory in self.rules: + for rule in rulefactory.get_rules(map): + rule = rule.empty() + rule.endpoint = self.prefix + rule.endpoint + yield rule + + +class RuleTemplate: + """Returns copies of the rules wrapped and expands string templates in + the endpoint, rule, defaults or subdomain sections. + + Here a small example for such a rule template:: + + from werkzeug.routing import Map, Rule, RuleTemplate + + resource = RuleTemplate([ + Rule('/$name/', endpoint='$name.list'), + Rule('/$name/', endpoint='$name.show') + ]) + + url_map = Map([resource(name='user'), resource(name='page')]) + + When a rule template is called the keyword arguments are used to + replace the placeholders in all the string parameters. + """ + + def __init__(self, rules: t.Iterable["Rule"]) -> None: + self.rules = list(rules) + + def __call__(self, *args: t.Any, **kwargs: t.Any) -> "RuleTemplateFactory": + return RuleTemplateFactory(self.rules, dict(*args, **kwargs)) + + +class RuleTemplateFactory(RuleFactory): + """A factory that fills in template variables into rules. Used by + `RuleTemplate` internally. + + :internal: + """ + + def __init__( + self, rules: t.Iterable[RuleFactory], context: t.Dict[str, t.Any] + ) -> None: + self.rules = rules + self.context = context + + def get_rules(self, map: "Map") -> t.Iterator["Rule"]: + for rulefactory in self.rules: + for rule in rulefactory.get_rules(map): + new_defaults = subdomain = None + if rule.defaults: + new_defaults = {} + for key, value in rule.defaults.items(): + if isinstance(value, str): + value = Template(value).substitute(self.context) + new_defaults[key] = value + if rule.subdomain is not None: + subdomain = Template(rule.subdomain).substitute(self.context) + new_endpoint = rule.endpoint + if isinstance(new_endpoint, str): + new_endpoint = Template(new_endpoint).substitute(self.context) + yield Rule( + Template(rule.rule).substitute(self.context), + new_defaults, + subdomain, + rule.methods, + rule.build_only, + new_endpoint, + rule.strict_slashes, + ) + + +def _prefix_names(src: str) -> ast.stmt: + """ast parse and prefix names with `.` to avoid collision with user vars""" + tree = ast.parse(src).body[0] + if isinstance(tree, ast.Expr): + tree = tree.value # type: ignore + for node in ast.walk(tree): + if isinstance(node, ast.Name): + node.id = f".{node.id}" + return tree + + +_CALL_CONVERTER_CODE_FMT = "self._converters[{elem!r}].to_url()" +_IF_KWARGS_URL_ENCODE_CODE = """\ +if kwargs: + params = self._encode_query_vars(kwargs) + q = "?" if params else "" +else: + q = params = "" +""" +_IF_KWARGS_URL_ENCODE_AST = _prefix_names(_IF_KWARGS_URL_ENCODE_CODE) +_URL_ENCODE_AST_NAMES = (_prefix_names("q"), _prefix_names("params")) + + +class Rule(RuleFactory): + """A Rule represents one URL pattern. There are some options for `Rule` + that change the way it behaves and are passed to the `Rule` constructor. + Note that besides the rule-string all arguments *must* be keyword arguments + in order to not break the application on Werkzeug upgrades. + + `string` + Rule strings basically are just normal URL paths with placeholders in + the format ```` where the converter and the + arguments are optional. If no converter is defined the `default` + converter is used which means `string` in the normal configuration. + + URL rules that end with a slash are branch URLs, others are leaves. + If you have `strict_slashes` enabled (which is the default), all + branch URLs that are matched without a trailing slash will trigger a + redirect to the same URL with the missing slash appended. + + The converters are defined on the `Map`. + + `endpoint` + The endpoint for this rule. This can be anything. A reference to a + function, a string, a number etc. The preferred way is using a string + because the endpoint is used for URL generation. + + `defaults` + An optional dict with defaults for other rules with the same endpoint. + This is a bit tricky but useful if you want to have unique URLs:: + + url_map = Map([ + Rule('/all/', defaults={'page': 1}, endpoint='all_entries'), + Rule('/all/page/', endpoint='all_entries') + ]) + + If a user now visits ``http://example.com/all/page/1`` they will be + redirected to ``http://example.com/all/``. If `redirect_defaults` is + disabled on the `Map` instance this will only affect the URL + generation. + + `subdomain` + The subdomain rule string for this rule. If not specified the rule + only matches for the `default_subdomain` of the map. If the map is + not bound to a subdomain this feature is disabled. + + Can be useful if you want to have user profiles on different subdomains + and all subdomains are forwarded to your application:: + + url_map = Map([ + Rule('/', subdomain='', endpoint='user/homepage'), + Rule('/stats', subdomain='', endpoint='user/stats') + ]) + + `methods` + A sequence of http methods this rule applies to. If not specified, all + methods are allowed. For example this can be useful if you want different + endpoints for `POST` and `GET`. If methods are defined and the path + matches but the method matched against is not in this list or in the + list of another rule for that path the error raised is of the type + `MethodNotAllowed` rather than `NotFound`. If `GET` is present in the + list of methods and `HEAD` is not, `HEAD` is added automatically. + + `strict_slashes` + Override the `Map` setting for `strict_slashes` only for this rule. If + not specified the `Map` setting is used. + + `merge_slashes` + Override :attr:`Map.merge_slashes` for this rule. + + `build_only` + Set this to True and the rule will never match but will create a URL + that can be build. This is useful if you have resources on a subdomain + or folder that are not handled by the WSGI application (like static data) + + `redirect_to` + If given this must be either a string or callable. In case of a + callable it's called with the url adapter that triggered the match and + the values of the URL as keyword arguments and has to return the target + for the redirect, otherwise it has to be a string with placeholders in + rule syntax:: + + def foo_with_slug(adapter, id): + # ask the database for the slug for the old id. this of + # course has nothing to do with werkzeug. + return f'foo/{Foo.get_slug_for_id(id)}' + + url_map = Map([ + Rule('/foo/', endpoint='foo'), + Rule('/some/old/url/', redirect_to='foo/'), + Rule('/other/old/url/', redirect_to=foo_with_slug) + ]) + + When the rule is matched the routing system will raise a + `RequestRedirect` exception with the target for the redirect. + + Keep in mind that the URL will be joined against the URL root of the + script so don't use a leading slash on the target URL unless you + really mean root of that domain. + + `alias` + If enabled this rule serves as an alias for another rule with the same + endpoint and arguments. + + `host` + If provided and the URL map has host matching enabled this can be + used to provide a match rule for the whole host. This also means + that the subdomain feature is disabled. + + `websocket` + If ``True``, this rule is only matches for WebSocket (``ws://``, + ``wss://``) requests. By default, rules will only match for HTTP + requests. + + .. versionchanged:: 2.1 + Percent-encoded newlines (``%0a``), which are decoded by WSGI + servers, are considered when routing instead of terminating the + match early. + + .. versionadded:: 1.0 + Added ``websocket``. + + .. versionadded:: 1.0 + Added ``merge_slashes``. + + .. versionadded:: 0.7 + Added ``alias`` and ``host``. + + .. versionchanged:: 0.6.1 + ``HEAD`` is added to ``methods`` if ``GET`` is present. + """ + + def __init__( + self, + string: str, + defaults: t.Optional[t.Mapping[str, t.Any]] = None, + subdomain: t.Optional[str] = None, + methods: t.Optional[t.Iterable[str]] = None, + build_only: bool = False, + endpoint: t.Optional[str] = None, + strict_slashes: t.Optional[bool] = None, + merge_slashes: t.Optional[bool] = None, + redirect_to: t.Optional[t.Union[str, t.Callable[..., str]]] = None, + alias: bool = False, + host: t.Optional[str] = None, + websocket: bool = False, + ) -> None: + if not string.startswith("/"): + raise ValueError("urls must start with a leading slash") + self.rule = string + self.is_leaf = not string.endswith("/") + self.is_branch = string.endswith("/") + + self.map: "Map" = None # type: ignore + self.strict_slashes = strict_slashes + self.merge_slashes = merge_slashes + self.subdomain = subdomain + self.host = host + self.defaults = defaults + self.build_only = build_only + self.alias = alias + self.websocket = websocket + + if methods is not None: + if isinstance(methods, str): + raise TypeError("'methods' should be a list of strings.") + + methods = {x.upper() for x in methods} + + if "HEAD" not in methods and "GET" in methods: + methods.add("HEAD") + + if websocket and methods - {"GET", "HEAD", "OPTIONS"}: + raise ValueError( + "WebSocket rules can only use 'GET', 'HEAD', and 'OPTIONS' methods." + ) + + self.methods = methods + self.endpoint: str = endpoint # type: ignore + self.redirect_to = redirect_to + + if defaults: + self.arguments = set(map(str, defaults)) + else: + self.arguments = set() + + self._converters: t.Dict[str, "BaseConverter"] = {} + self._trace: t.List[t.Tuple[bool, str]] = [] + self._parts: t.List[RulePart] = [] + + def empty(self) -> "Rule": + """ + Return an unbound copy of this rule. + + This can be useful if want to reuse an already bound URL for another + map. See ``get_empty_kwargs`` to override what keyword arguments are + provided to the new copy. + """ + return type(self)(self.rule, **self.get_empty_kwargs()) + + def get_empty_kwargs(self) -> t.Mapping[str, t.Any]: + """ + Provides kwargs for instantiating empty copy with empty() + + Use this method to provide custom keyword arguments to the subclass of + ``Rule`` when calling ``some_rule.empty()``. Helpful when the subclass + has custom keyword arguments that are needed at instantiation. + + Must return a ``dict`` that will be provided as kwargs to the new + instance of ``Rule``, following the initial ``self.rule`` value which + is always provided as the first, required positional argument. + """ + defaults = None + if self.defaults: + defaults = dict(self.defaults) + return dict( + defaults=defaults, + subdomain=self.subdomain, + methods=self.methods, + build_only=self.build_only, + endpoint=self.endpoint, + strict_slashes=self.strict_slashes, + redirect_to=self.redirect_to, + alias=self.alias, + host=self.host, + ) + + def get_rules(self, map: "Map") -> t.Iterator["Rule"]: + yield self + + def refresh(self) -> None: + """Rebinds and refreshes the URL. Call this if you modified the + rule in place. + + :internal: + """ + self.bind(self.map, rebind=True) + + def bind(self, map: "Map", rebind: bool = False) -> None: + """Bind the url to a map and create a regular expression based on + the information from the rule itself and the defaults from the map. + + :internal: + """ + if self.map is not None and not rebind: + raise RuntimeError(f"url rule {self!r} already bound to map {self.map!r}") + self.map = map + if self.strict_slashes is None: + self.strict_slashes = map.strict_slashes + if self.merge_slashes is None: + self.merge_slashes = map.merge_slashes + if self.subdomain is None: + self.subdomain = map.default_subdomain + self.compile() + + def get_converter( + self, + variable_name: str, + converter_name: str, + args: t.Tuple, + kwargs: t.Mapping[str, t.Any], + ) -> "BaseConverter": + """Looks up the converter for the given parameter. + + .. versionadded:: 0.9 + """ + if converter_name not in self.map.converters: + raise LookupError(f"the converter {converter_name!r} does not exist") + return self.map.converters[converter_name](self.map, *args, **kwargs) + + def _encode_query_vars(self, query_vars: t.Mapping[str, t.Any]) -> str: + return url_encode( + query_vars, + charset=self.map.charset, + sort=self.map.sort_parameters, + key=self.map.sort_key, + ) + + def _parse_rule(self, rule: str) -> t.Iterable[RulePart]: + content = "" + static = True + argument_weights = [] + static_weights: t.List[t.Tuple[int, int]] = [] + final = False + + pos = 0 + while pos < len(rule): + match = _part_re.match(rule, pos) + if match is None: + raise ValueError(f"malformed url rule: {rule!r}") + + data = match.groupdict() + if data["static"] is not None: + static_weights.append((len(static_weights), -len(data["static"]))) + self._trace.append((False, data["static"])) + content += data["static"] if static else re.escape(data["static"]) + + if data["variable"] is not None: + if static: + # Switching content to represent regex, hence the need to escape + content = re.escape(content) + static = False + c_args, c_kwargs = parse_converter_args(data["arguments"] or "") + convobj = self.get_converter( + data["variable"], data["converter"] or "default", c_args, c_kwargs + ) + self._converters[data["variable"]] = convobj + self.arguments.add(data["variable"]) + if not convobj.part_isolating: + final = True + content += f"({convobj.regex})" + argument_weights.append(convobj.weight) + self._trace.append((True, data["variable"])) + + if data["slash"] is not None: + self._trace.append((False, "/")) + if final: + content += "/" + else: + if not static: + content += r"\Z" + weight = Weighting( + -len(static_weights), + static_weights, + -len(argument_weights), + argument_weights, + ) + yield RulePart( + content=content, final=final, static=static, weight=weight + ) + content = "" + static = True + argument_weights = [] + static_weights = [] + final = False + + pos = match.end() + + if not static: + content += r"\Z" + weight = Weighting( + -len(static_weights), + static_weights, + -len(argument_weights), + argument_weights, + ) + yield RulePart(content=content, final=final, static=static, weight=weight) + + def compile(self) -> None: + """Compiles the regular expression and stores it.""" + assert self.map is not None, "rule not bound" + + if self.map.host_matching: + domain_rule = self.host or "" + else: + domain_rule = self.subdomain or "" + self._parts = [] + self._trace = [] + self._converters = {} + if domain_rule == "": + self._parts = [ + RulePart( + content="", final=False, static=True, weight=Weighting(0, [], 0, []) + ) + ] + else: + self._parts.extend(self._parse_rule(domain_rule)) + self._trace.append((False, "|")) + rule = self.rule + if self.merge_slashes: + rule = re.sub("/{2,}?", "/", self.rule) + self._parts.extend(self._parse_rule(rule)) + + self._build: t.Callable[..., t.Tuple[str, str]] + self._build = self._compile_builder(False).__get__(self, None) + self._build_unknown: t.Callable[..., t.Tuple[str, str]] + self._build_unknown = self._compile_builder(True).__get__(self, None) + + @staticmethod + def _get_func_code(code: CodeType, name: str) -> t.Callable[..., t.Tuple[str, str]]: + globs: t.Dict[str, t.Any] = {} + locs: t.Dict[str, t.Any] = {} + exec(code, globs, locs) + return locs[name] # type: ignore + + def _compile_builder( + self, append_unknown: bool = True + ) -> t.Callable[..., t.Tuple[str, str]]: + defaults = self.defaults or {} + dom_ops: t.List[t.Tuple[bool, str]] = [] + url_ops: t.List[t.Tuple[bool, str]] = [] + + opl = dom_ops + for is_dynamic, data in self._trace: + if data == "|" and opl is dom_ops: + opl = url_ops + continue + # this seems like a silly case to ever come up but: + # if a default is given for a value that appears in the rule, + # resolve it to a constant ahead of time + if is_dynamic and data in defaults: + data = self._converters[data].to_url(defaults[data]) + opl.append((False, data)) + elif not is_dynamic: + opl.append( + (False, url_quote(_to_bytes(data, self.map.charset), safe="/:|+")) + ) + else: + opl.append((True, data)) + + def _convert(elem: str) -> ast.stmt: + ret = _prefix_names(_CALL_CONVERTER_CODE_FMT.format(elem=elem)) + ret.args = [ast.Name(str(elem), ast.Load())] # type: ignore # str for py2 + return ret + + def _parts(ops: t.List[t.Tuple[bool, str]]) -> t.List[ast.AST]: + parts = [ + _convert(elem) if is_dynamic else ast.Str(s=elem) + for is_dynamic, elem in ops + ] + parts = parts or [ast.Str("")] + # constant fold + ret = [parts[0]] + for p in parts[1:]: + if isinstance(p, ast.Str) and isinstance(ret[-1], ast.Str): + ret[-1] = ast.Str(ret[-1].s + p.s) + else: + ret.append(p) + return ret + + dom_parts = _parts(dom_ops) + url_parts = _parts(url_ops) + if not append_unknown: + body = [] + else: + body = [_IF_KWARGS_URL_ENCODE_AST] + url_parts.extend(_URL_ENCODE_AST_NAMES) + + def _join(parts: t.List[ast.AST]) -> ast.AST: + if len(parts) == 1: # shortcut + return parts[0] + return ast.JoinedStr(parts) + + body.append( + ast.Return(ast.Tuple([_join(dom_parts), _join(url_parts)], ast.Load())) + ) + + pargs = [ + elem + for is_dynamic, elem in dom_ops + url_ops + if is_dynamic and elem not in defaults + ] + kargs = [str(k) for k in defaults] + + func_ast: ast.FunctionDef = _prefix_names("def _(): pass") # type: ignore + func_ast.name = f"" + func_ast.args.args.append(ast.arg(".self", None)) + for arg in pargs + kargs: + func_ast.args.args.append(ast.arg(arg, None)) + func_ast.args.kwarg = ast.arg(".kwargs", None) + for _ in kargs: + func_ast.args.defaults.append(ast.Str("")) + func_ast.body = body + + # use `ast.parse` instead of `ast.Module` for better portability + # Python 3.8 changes the signature of `ast.Module` + module = ast.parse("") + module.body = [func_ast] + + # mark everything as on line 1, offset 0 + # less error-prone than `ast.fix_missing_locations` + # bad line numbers cause an assert to fail in debug builds + for node in ast.walk(module): + if "lineno" in node._attributes: + node.lineno = 1 + if "end_lineno" in node._attributes: + node.end_lineno = node.lineno # type: ignore[attr-defined] + if "col_offset" in node._attributes: + node.col_offset = 0 + if "end_col_offset" in node._attributes: + node.end_col_offset = node.col_offset # type: ignore[attr-defined] + + code = compile(module, "", "exec") + return self._get_func_code(code, func_ast.name) + + def build( + self, values: t.Mapping[str, t.Any], append_unknown: bool = True + ) -> t.Optional[t.Tuple[str, str]]: + """Assembles the relative url for that rule and the subdomain. + If building doesn't work for some reasons `None` is returned. + + :internal: + """ + try: + if append_unknown: + return self._build_unknown(**values) + else: + return self._build(**values) + except ValidationError: + return None + + def provides_defaults_for(self, rule: "Rule") -> bool: + """Check if this rule has defaults for a given rule. + + :internal: + """ + return bool( + not self.build_only + and self.defaults + and self.endpoint == rule.endpoint + and self != rule + and self.arguments == rule.arguments + ) + + def suitable_for( + self, values: t.Mapping[str, t.Any], method: t.Optional[str] = None + ) -> bool: + """Check if the dict of values has enough data for url generation. + + :internal: + """ + # if a method was given explicitly and that method is not supported + # by this rule, this rule is not suitable. + if ( + method is not None + and self.methods is not None + and method not in self.methods + ): + return False + + defaults = self.defaults or () + + # all arguments required must be either in the defaults dict or + # the value dictionary otherwise it's not suitable + for key in self.arguments: + if key not in defaults and key not in values: + return False + + # in case defaults are given we ensure that either the value was + # skipped or the value is the same as the default value. + if defaults: + for key, value in defaults.items(): + if key in values and value != values[key]: + return False + + return True + + def build_compare_key(self) -> t.Tuple[int, int, int]: + """The build compare key for sorting. + + :internal: + """ + return (1 if self.alias else 0, -len(self.arguments), -len(self.defaults or ())) + + def __eq__(self, other: object) -> bool: + return isinstance(other, type(self)) and self._trace == other._trace + + __hash__ = None # type: ignore + + def __str__(self) -> str: + return self.rule + + def __repr__(self) -> str: + if self.map is None: + return f"<{type(self).__name__} (unbound)>" + parts = [] + for is_dynamic, data in self._trace: + if is_dynamic: + parts.append(f"<{data}>") + else: + parts.append(data) + parts = "".join(parts).lstrip("|") + methods = f" ({', '.join(self.methods)})" if self.methods is not None else "" + return f"<{type(self).__name__} {parts!r}{methods} -> {self.endpoint}>" diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/__init__.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..6fa79ad5d7a11d5e9dfd1c0b3104d67dd3f3bf83 GIT binary patch literal 178 zcmd1j<>g`kg8zGil0o!i5P=LBfgA@QE@lA|DGb33nv8xc8Hzx{2;x_$vsFxJacWU< zOlnbPa$-zzerZ8cequ>Xa#3ksaz>0^8I<9ZnG{o;S(2(-keHmEn4Vf3Q=VFsU6opz qu3wy(SDcxzA0MBYmst`YuUAlci^C>2KczG$)edA`F%ytrVE_QECNAUv literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/http.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5b74dfe093fae66ce362dfd02e6586a6bc31d498 GIT binary patch literal 3865 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/request.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..1634cddacae3fef5c5e965f4957972ba1c6649e3 GIT binary patch literal 17056 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 ae-TM8rNcLPWj)UE0{gH0e>A=O;Qs}FWymi8 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/sansio/__pycache__/utils.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..da5e46ace3d1363798273437ae60212f1087ef82 GIT binary patch literal 4569 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 Dhtc^d literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/http.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/http.py new file mode 100644 index 0000000..8288882 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/sansio/http.py @@ -0,0 +1,140 @@ +import re +import typing as t +from datetime import datetime + +from .._internal import _cookie_parse_impl +from .._internal import _dt_as_utc +from .._internal import _to_str +from ..http import generate_etag +from ..http import parse_date +from ..http import parse_etags +from ..http import parse_if_range_header +from ..http import unquote_etag + +_etag_re = re.compile(r'([Ww]/)?(?:"(.*?)"|(.*?))(?:\s*,\s*|$)') + + +def is_resource_modified( + http_range: t.Optional[str] = None, + http_if_range: t.Optional[str] = None, + http_if_modified_since: t.Optional[str] = None, + http_if_none_match: t.Optional[str] = None, + http_if_match: t.Optional[str] = None, + etag: t.Optional[str] = None, + data: t.Optional[bytes] = None, + last_modified: t.Optional[t.Union[datetime, str]] = None, + ignore_if_range: bool = True, +) -> bool: + """Convenience method for conditional requests. + :param http_range: Range HTTP header + :param http_if_range: If-Range HTTP header + :param http_if_modified_since: If-Modified-Since HTTP header + :param http_if_none_match: If-None-Match HTTP header + :param http_if_match: If-Match HTTP header + :param etag: the etag for the response for comparison. + :param data: or alternatively the data of the response to automatically + generate an etag using :func:`generate_etag`. + :param last_modified: an optional date of the last modification. + :param ignore_if_range: If `False`, `If-Range` header will be taken into + account. + :return: `True` if the resource was modified, otherwise `False`. + + .. versionadded:: 2.2 + """ + if etag is None and data is not None: + etag = generate_etag(data) + elif data is not None: + raise TypeError("both data and etag given") + + unmodified = False + if isinstance(last_modified, str): + last_modified = parse_date(last_modified) + + # HTTP doesn't use microsecond, remove it to avoid false positive + # comparisons. Mark naive datetimes as UTC. + if last_modified is not None: + last_modified = _dt_as_utc(last_modified.replace(microsecond=0)) + + if_range = None + if not ignore_if_range and http_range is not None: + # https://tools.ietf.org/html/rfc7233#section-3.2 + # A server MUST ignore an If-Range header field received in a request + # that does not contain a Range header field. + if_range = parse_if_range_header(http_if_range) + + if if_range is not None and if_range.date is not None: + modified_since: t.Optional[datetime] = if_range.date + else: + modified_since = parse_date(http_if_modified_since) + + if modified_since and last_modified and last_modified <= modified_since: + unmodified = True + + if etag: + etag, _ = unquote_etag(etag) + etag = t.cast(str, etag) + + if if_range is not None and if_range.etag is not None: + unmodified = parse_etags(if_range.etag).contains(etag) + else: + if_none_match = parse_etags(http_if_none_match) + if if_none_match: + # https://tools.ietf.org/html/rfc7232#section-3.2 + # "A recipient MUST use the weak comparison function when comparing + # entity-tags for If-None-Match" + unmodified = if_none_match.contains_weak(etag) + + # https://tools.ietf.org/html/rfc7232#section-3.1 + # "Origin server MUST use the strong comparison function when + # comparing entity-tags for If-Match" + if_match = parse_etags(http_if_match) + if if_match: + unmodified = not if_match.is_strong(etag) + + return not unmodified + + +def parse_cookie( + cookie: t.Union[bytes, str, None] = "", + charset: str = "utf-8", + errors: str = "replace", + cls: t.Optional[t.Type["ds.MultiDict"]] = None, +) -> "ds.MultiDict[str, str]": + """Parse a cookie from a string. + + The same key can be provided multiple times, the values are stored + in-order. The default :class:`MultiDict` will have the first value + first, and all values can be retrieved with + :meth:`MultiDict.getlist`. + + :param cookie: The cookie header as a string. + :param charset: The charset for the cookie values. + :param errors: The error behavior for the charset decoding. + :param cls: A dict-like class to store the parsed cookies in. + Defaults to :class:`MultiDict`. + + .. versionadded:: 2.2 + """ + # PEP 3333 sends headers through the environ as latin1 decoded + # strings. Encode strings back to bytes for parsing. + if isinstance(cookie, str): + cookie = cookie.encode("latin1", "replace") + + if cls is None: + cls = ds.MultiDict + + def _parse_pairs() -> t.Iterator[t.Tuple[str, str]]: + for key, val in _cookie_parse_impl(cookie): # type: ignore + key_str = _to_str(key, charset, errors, allow_none_charset=True) + + if not key_str: + continue + + val_str = _to_str(val, charset, errors, allow_none_charset=True) + yield key_str, val_str + + return cls(_parse_pairs()) + + +# circular dependencies +from .. import datastructures as ds diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/multipart.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/multipart.py new file mode 100644 index 0000000..d8abeb3 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/sansio/multipart.py @@ -0,0 +1,279 @@ +import re +from dataclasses import dataclass +from enum import auto +from enum import Enum +from typing import cast +from typing import List +from typing import Optional +from typing import Tuple + +from .._internal import _to_bytes +from .._internal import _to_str +from ..datastructures import Headers +from ..exceptions import RequestEntityTooLarge +from ..http import parse_options_header + + +class Event: + pass + + +@dataclass(frozen=True) +class Preamble(Event): + data: bytes + + +@dataclass(frozen=True) +class Field(Event): + name: str + headers: Headers + + +@dataclass(frozen=True) +class File(Event): + name: str + filename: str + headers: Headers + + +@dataclass(frozen=True) +class Data(Event): + data: bytes + more_data: bool + + +@dataclass(frozen=True) +class Epilogue(Event): + data: bytes + + +class NeedData(Event): + pass + + +NEED_DATA = NeedData() + + +class State(Enum): + PREAMBLE = auto() + PART = auto() + DATA = auto() + EPILOGUE = auto() + COMPLETE = auto() + + +# Multipart line breaks MUST be CRLF (\r\n) by RFC-7578, except that +# many implementations break this and either use CR or LF alone. +LINE_BREAK = b"(?:\r\n|\n|\r)" +BLANK_LINE_RE = re.compile(b"(?:\r\n\r\n|\r\r|\n\n)", re.MULTILINE) +LINE_BREAK_RE = re.compile(LINE_BREAK, re.MULTILINE) +# Header values can be continued via a space or tab after the linebreak, as +# per RFC2231 +HEADER_CONTINUATION_RE = re.compile(b"%s[ \t]" % LINE_BREAK, re.MULTILINE) +# This must be long enough to contain any line breaks plus any +# additional boundary markers (--) such that they will be found in a +# subsequent search +SEARCH_EXTRA_LENGTH = 8 + + +class MultipartDecoder: + """Decodes a multipart message as bytes into Python events. + + The part data is returned as available to allow the caller to save + the data from memory to disk, if desired. + """ + + def __init__( + self, + boundary: bytes, + max_form_memory_size: Optional[int] = None, + ) -> None: + self.buffer = bytearray() + self.complete = False + self.max_form_memory_size = max_form_memory_size + self.state = State.PREAMBLE + self.boundary = boundary + + # Note in the below \h i.e. horizontal whitespace is used + # as [^\S\n\r] as \h isn't supported in python. + + # The preamble must end with a boundary where the boundary is + # prefixed by a line break, RFC2046. Except that many + # implementations including Werkzeug's tests omit the line + # break prefix. In addition the first boundary could be the + # epilogue boundary (for empty form-data) hence the matching + # group to understand if it is an epilogue boundary. + self.preamble_re = re.compile( + rb"%s?--%s(--[^\S\n\r]*%s?|[^\S\n\r]*%s)" + % (LINE_BREAK, re.escape(boundary), LINE_BREAK, LINE_BREAK), + re.MULTILINE, + ) + # A boundary must include a line break prefix and suffix, and + # may include trailing whitespace. In addition the boundary + # could be the epilogue boundary hence the matching group to + # understand if it is an epilogue boundary. + self.boundary_re = re.compile( + rb"%s--%s(--[^\S\n\r]*%s?|[^\S\n\r]*%s)" + % (LINE_BREAK, re.escape(boundary), LINE_BREAK, LINE_BREAK), + re.MULTILINE, + ) + self._search_position = 0 + + def last_newline(self) -> int: + try: + last_nl = self.buffer.rindex(b"\n") + except ValueError: + last_nl = len(self.buffer) + try: + last_cr = self.buffer.rindex(b"\r") + except ValueError: + last_cr = len(self.buffer) + + return min(last_nl, last_cr) + + def receive_data(self, data: Optional[bytes]) -> None: + if data is None: + self.complete = True + elif ( + self.max_form_memory_size is not None + and len(self.buffer) + len(data) > self.max_form_memory_size + ): + raise RequestEntityTooLarge() + else: + self.buffer.extend(data) + + def next_event(self) -> Event: + event: Event = NEED_DATA + + if self.state == State.PREAMBLE: + match = self.preamble_re.search(self.buffer, self._search_position) + if match is not None: + if match.group(1).startswith(b"--"): + self.state = State.EPILOGUE + else: + self.state = State.PART + data = bytes(self.buffer[: match.start()]) + del self.buffer[: match.end()] + event = Preamble(data=data) + self._search_position = 0 + else: + # Update the search start position to be equal to the + # current buffer length (already searched) minus a + # safe buffer for part of the search target. + self._search_position = max( + 0, len(self.buffer) - len(self.boundary) - SEARCH_EXTRA_LENGTH + ) + + elif self.state == State.PART: + match = BLANK_LINE_RE.search(self.buffer, self._search_position) + if match is not None: + headers = self._parse_headers(self.buffer[: match.start()]) + del self.buffer[: match.end()] + + if "content-disposition" not in headers: + raise ValueError("Missing Content-Disposition header") + + disposition, extra = parse_options_header( + headers["content-disposition"] + ) + name = cast(str, extra.get("name")) + filename = extra.get("filename") + if filename is not None: + event = File( + filename=filename, + headers=headers, + name=name, + ) + else: + event = Field( + headers=headers, + name=name, + ) + self.state = State.DATA + self._search_position = 0 + else: + # Update the search start position to be equal to the + # current buffer length (already searched) minus a + # safe buffer for part of the search target. + self._search_position = max(0, len(self.buffer) - SEARCH_EXTRA_LENGTH) + + elif self.state == State.DATA: + if self.buffer.find(b"--" + self.boundary) == -1: + # No complete boundary in the buffer, but there may be + # a partial boundary at the end. As the boundary + # starts with either a nl or cr find the earliest and + # return up to that as data. + data_length = del_index = self.last_newline() + more_data = True + else: + match = self.boundary_re.search(self.buffer) + if match is not None: + if match.group(1).startswith(b"--"): + self.state = State.EPILOGUE + else: + self.state = State.PART + data_length = match.start() + del_index = match.end() + else: + data_length = del_index = self.last_newline() + more_data = match is None + + data = bytes(self.buffer[:data_length]) + del self.buffer[:del_index] + if data or not more_data: + event = Data(data=data, more_data=more_data) + + elif self.state == State.EPILOGUE and self.complete: + event = Epilogue(data=bytes(self.buffer)) + del self.buffer[:] + self.state = State.COMPLETE + + if self.complete and isinstance(event, NeedData): + raise ValueError(f"Invalid form-data cannot parse beyond {self.state}") + + return event + + def _parse_headers(self, data: bytes) -> Headers: + headers: List[Tuple[str, str]] = [] + # Merge the continued headers into one line + data = HEADER_CONTINUATION_RE.sub(b" ", data) + # Now there is one header per line + for line in data.splitlines(): + if line.strip() != b"": + name, value = _to_str(line).strip().split(":", 1) + headers.append((name.strip(), value.strip())) + return Headers(headers) + + +class MultipartEncoder: + def __init__(self, boundary: bytes) -> None: + self.boundary = boundary + self.state = State.PREAMBLE + + def send_event(self, event: Event) -> bytes: + if isinstance(event, Preamble) and self.state == State.PREAMBLE: + self.state = State.PART + return event.data + elif isinstance(event, (Field, File)) and self.state in { + State.PREAMBLE, + State.PART, + State.DATA, + }: + self.state = State.DATA + data = b"\r\n--" + self.boundary + b"\r\n" + data += b'Content-Disposition: form-data; name="%s"' % _to_bytes(event.name) + if isinstance(event, File): + data += b'; filename="%s"' % _to_bytes(event.filename) + data += b"\r\n" + for name, value in cast(Field, event).headers: + if name.lower() != "content-disposition": + data += _to_bytes(f"{name}: {value}\r\n") + data += b"\r\n" + return data + elif isinstance(event, Data) and self.state == State.DATA: + return event.data + elif isinstance(event, Epilogue): + self.state = State.COMPLETE + return b"\r\n--" + self.boundary + b"--\r\n" + event.data + else: + raise ValueError(f"Cannot generate {event} in state: {self.state}") diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/request.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/request.py new file mode 100644 index 0000000..8832baa --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/sansio/request.py @@ -0,0 +1,547 @@ +import typing as t +from datetime import datetime + +from .._internal import _to_str +from ..datastructures import Accept +from ..datastructures import Authorization +from ..datastructures import CharsetAccept +from ..datastructures import ETags +from ..datastructures import Headers +from ..datastructures import HeaderSet +from ..datastructures import IfRange +from ..datastructures import ImmutableList +from ..datastructures import ImmutableMultiDict +from ..datastructures import LanguageAccept +from ..datastructures import MIMEAccept +from ..datastructures import MultiDict +from ..datastructures import Range +from ..datastructures import RequestCacheControl +from ..http import parse_accept_header +from ..http import parse_authorization_header +from ..http import parse_cache_control_header +from ..http import parse_date +from ..http import parse_etags +from ..http import parse_if_range_header +from ..http import parse_list_header +from ..http import parse_options_header +from ..http import parse_range_header +from ..http import parse_set_header +from ..urls import url_decode +from ..user_agent import UserAgent +from ..utils import cached_property +from ..utils import header_property +from .http import parse_cookie +from .utils import get_current_url +from .utils import get_host + + +class Request: + """Represents the non-IO parts of a HTTP request, including the + method, URL info, and headers. + + This class is not meant for general use. It should only be used when + implementing WSGI, ASGI, or another HTTP application spec. Werkzeug + provides a WSGI implementation at :cls:`werkzeug.wrappers.Request`. + + :param method: The method the request was made with, such as + ``GET``. + :param scheme: The URL scheme of the protocol the request used, such + as ``https`` or ``wss``. + :param server: The address of the server. ``(host, port)``, + ``(path, None)`` for unix sockets, or ``None`` if not known. + :param root_path: The prefix that the application is mounted under. + This is prepended to generated URLs, but is not part of route + matching. + :param path: The path part of the URL after ``root_path``. + :param query_string: The part of the URL after the "?". + :param headers: The headers received with the request. + :param remote_addr: The address of the client sending the request. + + .. versionadded:: 2.0 + """ + + #: The charset used to decode most data in the request. + charset = "utf-8" + + #: the error handling procedure for errors, defaults to 'replace' + encoding_errors = "replace" + + #: the class to use for `args` and `form`. The default is an + #: :class:`~werkzeug.datastructures.ImmutableMultiDict` which supports + #: multiple values per key. alternatively it makes sense to use an + #: :class:`~werkzeug.datastructures.ImmutableOrderedMultiDict` which + #: preserves order or a :class:`~werkzeug.datastructures.ImmutableDict` + #: which is the fastest but only remembers the last key. It is also + #: possible to use mutable structures, but this is not recommended. + #: + #: .. versionadded:: 0.6 + parameter_storage_class: t.Type[MultiDict] = ImmutableMultiDict + + #: The type to be used for dict values from the incoming WSGI + #: environment. (For example for :attr:`cookies`.) By default an + #: :class:`~werkzeug.datastructures.ImmutableMultiDict` is used. + #: + #: .. versionchanged:: 1.0.0 + #: Changed to ``ImmutableMultiDict`` to support multiple values. + #: + #: .. versionadded:: 0.6 + dict_storage_class: t.Type[MultiDict] = ImmutableMultiDict + + #: the type to be used for list values from the incoming WSGI environment. + #: By default an :class:`~werkzeug.datastructures.ImmutableList` is used + #: (for example for :attr:`access_list`). + #: + #: .. versionadded:: 0.6 + list_storage_class: t.Type[t.List] = ImmutableList + + user_agent_class: t.Type[UserAgent] = UserAgent + """The class used and returned by the :attr:`user_agent` property to + parse the header. Defaults to + :class:`~werkzeug.user_agent.UserAgent`, which does no parsing. An + extension can provide a subclass that uses a parser to provide other + data. + + .. versionadded:: 2.0 + """ + + #: Valid host names when handling requests. By default all hosts are + #: trusted, which means that whatever the client says the host is + #: will be accepted. + #: + #: Because ``Host`` and ``X-Forwarded-Host`` headers can be set to + #: any value by a malicious client, it is recommended to either set + #: this property or implement similar validation in the proxy (if + #: the application is being run behind one). + #: + #: .. versionadded:: 0.9 + trusted_hosts: t.Optional[t.List[str]] = None + + def __init__( + self, + method: str, + scheme: str, + server: t.Optional[t.Tuple[str, t.Optional[int]]], + root_path: str, + path: str, + query_string: bytes, + headers: Headers, + remote_addr: t.Optional[str], + ) -> None: + #: The method the request was made with, such as ``GET``. + self.method = method.upper() + #: The URL scheme of the protocol the request used, such as + #: ``https`` or ``wss``. + self.scheme = scheme + #: The address of the server. ``(host, port)``, ``(path, None)`` + #: for unix sockets, or ``None`` if not known. + self.server = server + #: The prefix that the application is mounted under, without a + #: trailing slash. :attr:`path` comes after this. + self.root_path = root_path.rstrip("/") + #: The path part of the URL after :attr:`root_path`. This is the + #: path used for routing within the application. + self.path = "/" + path.lstrip("/") + #: The part of the URL after the "?". This is the raw value, use + #: :attr:`args` for the parsed values. + self.query_string = query_string + #: The headers received with the request. + self.headers = headers + #: The address of the client sending the request. + self.remote_addr = remote_addr + + def __repr__(self) -> str: + try: + url = self.url + except Exception as e: + url = f"(invalid URL: {e})" + + return f"<{type(self).__name__} {url!r} [{self.method}]>" + + @property + def url_charset(self) -> str: + """The charset that is assumed for URLs. Defaults to the value + of :attr:`charset`. + + .. versionadded:: 0.6 + """ + return self.charset + + @cached_property + def args(self) -> "MultiDict[str, str]": + """The parsed URL parameters (the part in the URL after the question + mark). + + By default an + :class:`~werkzeug.datastructures.ImmutableMultiDict` + is returned from this function. This can be changed by setting + :attr:`parameter_storage_class` to a different type. This might + be necessary if the order of the form data is important. + """ + return url_decode( + self.query_string, + self.url_charset, + errors=self.encoding_errors, + cls=self.parameter_storage_class, + ) + + @cached_property + def access_route(self) -> t.List[str]: + """If a forwarded header exists this is a list of all ip addresses + from the client ip to the last proxy server. + """ + if "X-Forwarded-For" in self.headers: + return self.list_storage_class( + parse_list_header(self.headers["X-Forwarded-For"]) + ) + elif self.remote_addr is not None: + return self.list_storage_class([self.remote_addr]) + return self.list_storage_class() + + @cached_property + def full_path(self) -> str: + """Requested path, including the query string.""" + return f"{self.path}?{_to_str(self.query_string, self.url_charset)}" + + @property + def is_secure(self) -> bool: + """``True`` if the request was made with a secure protocol + (HTTPS or WSS). + """ + return self.scheme in {"https", "wss"} + + @cached_property + def url(self) -> str: + """The full request URL with the scheme, host, root path, path, + and query string.""" + return get_current_url( + self.scheme, self.host, self.root_path, self.path, self.query_string + ) + + @cached_property + def base_url(self) -> str: + """Like :attr:`url` but without the query string.""" + return get_current_url(self.scheme, self.host, self.root_path, self.path) + + @cached_property + def root_url(self) -> str: + """The request URL scheme, host, and root path. This is the root + that the application is accessed from. + """ + return get_current_url(self.scheme, self.host, self.root_path) + + @cached_property + def host_url(self) -> str: + """The request URL scheme and host only.""" + return get_current_url(self.scheme, self.host) + + @cached_property + def host(self) -> str: + """The host name the request was made to, including the port if + it's non-standard. Validated with :attr:`trusted_hosts`. + """ + return get_host( + self.scheme, self.headers.get("host"), self.server, self.trusted_hosts + ) + + @cached_property + def cookies(self) -> "ImmutableMultiDict[str, str]": + """A :class:`dict` with the contents of all cookies transmitted with + the request.""" + wsgi_combined_cookie = ";".join(self.headers.getlist("Cookie")) + return parse_cookie( # type: ignore + wsgi_combined_cookie, + self.charset, + self.encoding_errors, + cls=self.dict_storage_class, + ) + + # Common Descriptors + + content_type = header_property[str]( + "Content-Type", + doc="""The Content-Type entity-header field indicates the media + type of the entity-body sent to the recipient or, in the case of + the HEAD method, the media type that would have been sent had + the request been a GET.""", + read_only=True, + ) + + @cached_property + def content_length(self) -> t.Optional[int]: + """The Content-Length entity-header field indicates the size of the + entity-body in bytes or, in the case of the HEAD method, the size of + the entity-body that would have been sent had the request been a + GET. + """ + if self.headers.get("Transfer-Encoding", "") == "chunked": + return None + + content_length = self.headers.get("Content-Length") + if content_length is not None: + try: + return max(0, int(content_length)) + except (ValueError, TypeError): + pass + + return None + + content_encoding = header_property[str]( + "Content-Encoding", + doc="""The Content-Encoding entity-header field is used as a + modifier to the media-type. When present, its value indicates + what additional content codings have been applied to the + entity-body, and thus what decoding mechanisms must be applied + in order to obtain the media-type referenced by the Content-Type + header field. + + .. versionadded:: 0.9""", + read_only=True, + ) + content_md5 = header_property[str]( + "Content-MD5", + doc="""The Content-MD5 entity-header field, as defined in + RFC 1864, is an MD5 digest of the entity-body for the purpose of + providing an end-to-end message integrity check (MIC) of the + entity-body. (Note: a MIC is good for detecting accidental + modification of the entity-body in transit, but is not proof + against malicious attacks.) + + .. versionadded:: 0.9""", + read_only=True, + ) + referrer = header_property[str]( + "Referer", + doc="""The Referer[sic] request-header field allows the client + to specify, for the server's benefit, the address (URI) of the + resource from which the Request-URI was obtained (the + "referrer", although the header field is misspelled).""", + read_only=True, + ) + date = header_property( + "Date", + None, + parse_date, + doc="""The Date general-header field represents the date and + time at which the message was originated, having the same + semantics as orig-date in RFC 822. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """, + read_only=True, + ) + max_forwards = header_property( + "Max-Forwards", + None, + int, + doc="""The Max-Forwards request-header field provides a + mechanism with the TRACE and OPTIONS methods to limit the number + of proxies or gateways that can forward the request to the next + inbound server.""", + read_only=True, + ) + + def _parse_content_type(self) -> None: + if not hasattr(self, "_parsed_content_type"): + self._parsed_content_type = parse_options_header( + self.headers.get("Content-Type", "") + ) + + @property + def mimetype(self) -> str: + """Like :attr:`content_type`, but without parameters (eg, without + charset, type etc.) and always lowercase. For example if the content + type is ``text/HTML; charset=utf-8`` the mimetype would be + ``'text/html'``. + """ + self._parse_content_type() + return self._parsed_content_type[0].lower() + + @property + def mimetype_params(self) -> t.Dict[str, str]: + """The mimetype parameters as dict. For example if the content + type is ``text/html; charset=utf-8`` the params would be + ``{'charset': 'utf-8'}``. + """ + self._parse_content_type() + return self._parsed_content_type[1] + + @cached_property + def pragma(self) -> HeaderSet: + """The Pragma general-header field is used to include + implementation-specific directives that might apply to any recipient + along the request/response chain. All pragma directives specify + optional behavior from the viewpoint of the protocol; however, some + systems MAY require that behavior be consistent with the directives. + """ + return parse_set_header(self.headers.get("Pragma", "")) + + # Accept + + @cached_property + def accept_mimetypes(self) -> MIMEAccept: + """List of mimetypes this client supports as + :class:`~werkzeug.datastructures.MIMEAccept` object. + """ + return parse_accept_header(self.headers.get("Accept"), MIMEAccept) + + @cached_property + def accept_charsets(self) -> CharsetAccept: + """List of charsets this client supports as + :class:`~werkzeug.datastructures.CharsetAccept` object. + """ + return parse_accept_header(self.headers.get("Accept-Charset"), CharsetAccept) + + @cached_property + def accept_encodings(self) -> Accept: + """List of encodings this client accepts. Encodings in a HTTP term + are compression encodings such as gzip. For charsets have a look at + :attr:`accept_charset`. + """ + return parse_accept_header(self.headers.get("Accept-Encoding")) + + @cached_property + def accept_languages(self) -> LanguageAccept: + """List of languages this client accepts as + :class:`~werkzeug.datastructures.LanguageAccept` object. + + .. versionchanged 0.5 + In previous versions this was a regular + :class:`~werkzeug.datastructures.Accept` object. + """ + return parse_accept_header(self.headers.get("Accept-Language"), LanguageAccept) + + # ETag + + @cached_property + def cache_control(self) -> RequestCacheControl: + """A :class:`~werkzeug.datastructures.RequestCacheControl` object + for the incoming cache control headers. + """ + cache_control = self.headers.get("Cache-Control") + return parse_cache_control_header(cache_control, None, RequestCacheControl) + + @cached_property + def if_match(self) -> ETags: + """An object containing all the etags in the `If-Match` header. + + :rtype: :class:`~werkzeug.datastructures.ETags` + """ + return parse_etags(self.headers.get("If-Match")) + + @cached_property + def if_none_match(self) -> ETags: + """An object containing all the etags in the `If-None-Match` header. + + :rtype: :class:`~werkzeug.datastructures.ETags` + """ + return parse_etags(self.headers.get("If-None-Match")) + + @cached_property + def if_modified_since(self) -> t.Optional[datetime]: + """The parsed `If-Modified-Since` header as a datetime object. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """ + return parse_date(self.headers.get("If-Modified-Since")) + + @cached_property + def if_unmodified_since(self) -> t.Optional[datetime]: + """The parsed `If-Unmodified-Since` header as a datetime object. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """ + return parse_date(self.headers.get("If-Unmodified-Since")) + + @cached_property + def if_range(self) -> IfRange: + """The parsed ``If-Range`` header. + + .. versionchanged:: 2.0 + ``IfRange.date`` is timezone-aware. + + .. versionadded:: 0.7 + """ + return parse_if_range_header(self.headers.get("If-Range")) + + @cached_property + def range(self) -> t.Optional[Range]: + """The parsed `Range` header. + + .. versionadded:: 0.7 + + :rtype: :class:`~werkzeug.datastructures.Range` + """ + return parse_range_header(self.headers.get("Range")) + + # User Agent + + @cached_property + def user_agent(self) -> UserAgent: + """The user agent. Use ``user_agent.string`` to get the header + value. Set :attr:`user_agent_class` to a subclass of + :class:`~werkzeug.user_agent.UserAgent` to provide parsing for + the other properties or other extended data. + + .. versionchanged:: 2.0 + The built in parser is deprecated and will be removed in + Werkzeug 2.1. A ``UserAgent`` subclass must be set to parse + data from the string. + """ + return self.user_agent_class(self.headers.get("User-Agent", "")) + + # Authorization + + @cached_property + def authorization(self) -> t.Optional[Authorization]: + """The `Authorization` object in parsed form.""" + return parse_authorization_header(self.headers.get("Authorization")) + + # CORS + + origin = header_property[str]( + "Origin", + doc=( + "The host that the request originated from. Set" + " :attr:`~CORSResponseMixin.access_control_allow_origin` on" + " the response to indicate which origins are allowed." + ), + read_only=True, + ) + + access_control_request_headers = header_property( + "Access-Control-Request-Headers", + load_func=parse_set_header, + doc=( + "Sent with a preflight request to indicate which headers" + " will be sent with the cross origin request. Set" + " :attr:`~CORSResponseMixin.access_control_allow_headers`" + " on the response to indicate which headers are allowed." + ), + read_only=True, + ) + + access_control_request_method = header_property[str]( + "Access-Control-Request-Method", + doc=( + "Sent with a preflight request to indicate which method" + " will be used for the cross origin request. Set" + " :attr:`~CORSResponseMixin.access_control_allow_methods`" + " on the response to indicate which methods are allowed." + ), + read_only=True, + ) + + @property + def is_json(self) -> bool: + """Check if the mimetype indicates JSON data, either + :mimetype:`application/json` or :mimetype:`application/*+json`. + """ + mt = self.mimetype + return ( + mt == "application/json" + or mt.startswith("application/") + and mt.endswith("+json") + ) diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/response.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/response.py new file mode 100644 index 0000000..de0bec2 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/sansio/response.py @@ -0,0 +1,704 @@ +import typing as t +from datetime import datetime +from datetime import timedelta +from datetime import timezone +from http import HTTPStatus + +from .._internal import _to_str +from ..datastructures import Headers +from ..datastructures import HeaderSet +from ..http import dump_cookie +from ..http import HTTP_STATUS_CODES +from ..utils import get_content_type +from werkzeug.datastructures import CallbackDict +from werkzeug.datastructures import ContentRange +from werkzeug.datastructures import ContentSecurityPolicy +from werkzeug.datastructures import ResponseCacheControl +from werkzeug.datastructures import WWWAuthenticate +from werkzeug.http import COEP +from werkzeug.http import COOP +from werkzeug.http import dump_age +from werkzeug.http import dump_header +from werkzeug.http import dump_options_header +from werkzeug.http import http_date +from werkzeug.http import parse_age +from werkzeug.http import parse_cache_control_header +from werkzeug.http import parse_content_range_header +from werkzeug.http import parse_csp_header +from werkzeug.http import parse_date +from werkzeug.http import parse_options_header +from werkzeug.http import parse_set_header +from werkzeug.http import parse_www_authenticate_header +from werkzeug.http import quote_etag +from werkzeug.http import unquote_etag +from werkzeug.utils import header_property + + +def _set_property(name: str, doc: t.Optional[str] = None) -> property: + def fget(self: "Response") -> HeaderSet: + def on_update(header_set: HeaderSet) -> None: + if not header_set and name in self.headers: + del self.headers[name] + elif header_set: + self.headers[name] = header_set.to_header() + + return parse_set_header(self.headers.get(name), on_update) + + def fset( + self: "Response", + value: t.Optional[ + t.Union[str, t.Dict[str, t.Union[str, int]], t.Iterable[str]] + ], + ) -> None: + if not value: + del self.headers[name] + elif isinstance(value, str): + self.headers[name] = value + else: + self.headers[name] = dump_header(value) + + return property(fget, fset, doc=doc) + + +class Response: + """Represents the non-IO parts of an HTTP response, specifically the + status and headers but not the body. + + This class is not meant for general use. It should only be used when + implementing WSGI, ASGI, or another HTTP application spec. Werkzeug + provides a WSGI implementation at :cls:`werkzeug.wrappers.Response`. + + :param status: The status code for the response. Either an int, in + which case the default status message is added, or a string in + the form ``{code} {message}``, like ``404 Not Found``. Defaults + to 200. + :param headers: A :class:`~werkzeug.datastructures.Headers` object, + or a list of ``(key, value)`` tuples that will be converted to a + ``Headers`` object. + :param mimetype: The mime type (content type without charset or + other parameters) of the response. If the value starts with + ``text/`` (or matches some other special cases), the charset + will be added to create the ``content_type``. + :param content_type: The full content type of the response. + Overrides building the value from ``mimetype``. + + .. versionadded:: 2.0 + """ + + #: the charset of the response. + charset = "utf-8" + + #: the default status if none is provided. + default_status = 200 + + #: the default mimetype if none is provided. + default_mimetype: t.Optional[str] = "text/plain" + + #: Warn if a cookie header exceeds this size. The default, 4093, should be + #: safely `supported by most browsers `_. A cookie larger than + #: this size will still be sent, but it may be ignored or handled + #: incorrectly by some browsers. Set to 0 to disable this check. + #: + #: .. versionadded:: 0.13 + #: + #: .. _`cookie`: http://browsercookielimits.squawky.net/ + max_cookie_size = 4093 + + # A :class:`Headers` object representing the response headers. + headers: Headers + + def __init__( + self, + status: t.Optional[t.Union[int, str, HTTPStatus]] = None, + headers: t.Optional[ + t.Union[ + t.Mapping[str, t.Union[str, int, t.Iterable[t.Union[str, int]]]], + t.Iterable[t.Tuple[str, t.Union[str, int]]], + ] + ] = None, + mimetype: t.Optional[str] = None, + content_type: t.Optional[str] = None, + ) -> None: + if isinstance(headers, Headers): + self.headers = headers + elif not headers: + self.headers = Headers() + else: + self.headers = Headers(headers) + + if content_type is None: + if mimetype is None and "content-type" not in self.headers: + mimetype = self.default_mimetype + if mimetype is not None: + mimetype = get_content_type(mimetype, self.charset) + content_type = mimetype + if content_type is not None: + self.headers["Content-Type"] = content_type + if status is None: + status = self.default_status + self.status = status # type: ignore + + def __repr__(self) -> str: + return f"<{type(self).__name__} [{self.status}]>" + + @property + def status_code(self) -> int: + """The HTTP status code as a number.""" + return self._status_code + + @status_code.setter + def status_code(self, code: int) -> None: + self.status = code # type: ignore + + @property + def status(self) -> str: + """The HTTP status code as a string.""" + return self._status + + @status.setter + def status(self, value: t.Union[str, int, HTTPStatus]) -> None: + if not isinstance(value, (str, bytes, int, HTTPStatus)): + raise TypeError("Invalid status argument") + + self._status, self._status_code = self._clean_status(value) + + def _clean_status(self, value: t.Union[str, int, HTTPStatus]) -> t.Tuple[str, int]: + if isinstance(value, HTTPStatus): + value = int(value) + status = _to_str(value, self.charset) + split_status = status.split(None, 1) + + if len(split_status) == 0: + raise ValueError("Empty status argument") + + try: + status_code = int(split_status[0]) + except ValueError: + # only message + return f"0 {status}", 0 + + if len(split_status) > 1: + # code and message + return status, status_code + + # only code, look up message + try: + status = f"{status_code} {HTTP_STATUS_CODES[status_code].upper()}" + except KeyError: + status = f"{status_code} UNKNOWN" + + return status, status_code + + def set_cookie( + self, + key: str, + value: str = "", + max_age: t.Optional[t.Union[timedelta, int]] = None, + expires: t.Optional[t.Union[str, datetime, int, float]] = None, + path: t.Optional[str] = "/", + domain: t.Optional[str] = None, + secure: bool = False, + httponly: bool = False, + samesite: t.Optional[str] = None, + ) -> None: + """Sets a cookie. + + A warning is raised if the size of the cookie header exceeds + :attr:`max_cookie_size`, but the header will still be set. + + :param key: the key (name) of the cookie to be set. + :param value: the value of the cookie. + :param max_age: should be a number of seconds, or `None` (default) if + the cookie should last only as long as the client's + browser session. + :param expires: should be a `datetime` object or UNIX timestamp. + :param path: limits the cookie to a given path, per default it will + span the whole domain. + :param domain: if you want to set a cross-domain cookie. For example, + ``domain=".example.com"`` will set a cookie that is + readable by the domain ``www.example.com``, + ``foo.example.com`` etc. Otherwise, a cookie will only + be readable by the domain that set it. + :param secure: If ``True``, the cookie will only be available + via HTTPS. + :param httponly: Disallow JavaScript access to the cookie. + :param samesite: Limit the scope of the cookie to only be + attached to requests that are "same-site". + """ + self.headers.add( + "Set-Cookie", + dump_cookie( + key, + value=value, + max_age=max_age, + expires=expires, + path=path, + domain=domain, + secure=secure, + httponly=httponly, + charset=self.charset, + max_size=self.max_cookie_size, + samesite=samesite, + ), + ) + + def delete_cookie( + self, + key: str, + path: str = "/", + domain: t.Optional[str] = None, + secure: bool = False, + httponly: bool = False, + samesite: t.Optional[str] = None, + ) -> None: + """Delete a cookie. Fails silently if key doesn't exist. + + :param key: the key (name) of the cookie to be deleted. + :param path: if the cookie that should be deleted was limited to a + path, the path has to be defined here. + :param domain: if the cookie that should be deleted was limited to a + domain, that domain has to be defined here. + :param secure: If ``True``, the cookie will only be available + via HTTPS. + :param httponly: Disallow JavaScript access to the cookie. + :param samesite: Limit the scope of the cookie to only be + attached to requests that are "same-site". + """ + self.set_cookie( + key, + expires=0, + max_age=0, + path=path, + domain=domain, + secure=secure, + httponly=httponly, + samesite=samesite, + ) + + @property + def is_json(self) -> bool: + """Check if the mimetype indicates JSON data, either + :mimetype:`application/json` or :mimetype:`application/*+json`. + """ + mt = self.mimetype + return mt is not None and ( + mt == "application/json" + or mt.startswith("application/") + and mt.endswith("+json") + ) + + # Common Descriptors + + @property + def mimetype(self) -> t.Optional[str]: + """The mimetype (content type without charset etc.)""" + ct = self.headers.get("content-type") + + if ct: + return ct.split(";")[0].strip() + else: + return None + + @mimetype.setter + def mimetype(self, value: str) -> None: + self.headers["Content-Type"] = get_content_type(value, self.charset) + + @property + def mimetype_params(self) -> t.Dict[str, str]: + """The mimetype parameters as dict. For example if the + content type is ``text/html; charset=utf-8`` the params would be + ``{'charset': 'utf-8'}``. + + .. versionadded:: 0.5 + """ + + def on_update(d: CallbackDict) -> None: + self.headers["Content-Type"] = dump_options_header(self.mimetype, d) + + d = parse_options_header(self.headers.get("content-type", ""))[1] + return CallbackDict(d, on_update) + + location = header_property[str]( + "Location", + doc="""The Location response-header field is used to redirect + the recipient to a location other than the Request-URI for + completion of the request or identification of a new + resource.""", + ) + age = header_property( + "Age", + None, + parse_age, + dump_age, # type: ignore + doc="""The Age response-header field conveys the sender's + estimate of the amount of time since the response (or its + revalidation) was generated at the origin server. + + Age values are non-negative decimal integers, representing time + in seconds.""", + ) + content_type = header_property[str]( + "Content-Type", + doc="""The Content-Type entity-header field indicates the media + type of the entity-body sent to the recipient or, in the case of + the HEAD method, the media type that would have been sent had + the request been a GET.""", + ) + content_length = header_property( + "Content-Length", + None, + int, + str, + doc="""The Content-Length entity-header field indicates the size + of the entity-body, in decimal number of OCTETs, sent to the + recipient or, in the case of the HEAD method, the size of the + entity-body that would have been sent had the request been a + GET.""", + ) + content_location = header_property[str]( + "Content-Location", + doc="""The Content-Location entity-header field MAY be used to + supply the resource location for the entity enclosed in the + message when that entity is accessible from a location separate + from the requested resource's URI.""", + ) + content_encoding = header_property[str]( + "Content-Encoding", + doc="""The Content-Encoding entity-header field is used as a + modifier to the media-type. When present, its value indicates + what additional content codings have been applied to the + entity-body, and thus what decoding mechanisms must be applied + in order to obtain the media-type referenced by the Content-Type + header field.""", + ) + content_md5 = header_property[str]( + "Content-MD5", + doc="""The Content-MD5 entity-header field, as defined in + RFC 1864, is an MD5 digest of the entity-body for the purpose of + providing an end-to-end message integrity check (MIC) of the + entity-body. (Note: a MIC is good for detecting accidental + modification of the entity-body in transit, but is not proof + against malicious attacks.)""", + ) + date = header_property( + "Date", + None, + parse_date, + http_date, + doc="""The Date general-header field represents the date and + time at which the message was originated, having the same + semantics as orig-date in RFC 822. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """, + ) + expires = header_property( + "Expires", + None, + parse_date, + http_date, + doc="""The Expires entity-header field gives the date/time after + which the response is considered stale. A stale cache entry may + not normally be returned by a cache. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """, + ) + last_modified = header_property( + "Last-Modified", + None, + parse_date, + http_date, + doc="""The Last-Modified entity-header field indicates the date + and time at which the origin server believes the variant was + last modified. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """, + ) + + @property + def retry_after(self) -> t.Optional[datetime]: + """The Retry-After response-header field can be used with a + 503 (Service Unavailable) response to indicate how long the + service is expected to be unavailable to the requesting client. + + Time in seconds until expiration or date. + + .. versionchanged:: 2.0 + The datetime object is timezone-aware. + """ + value = self.headers.get("retry-after") + if value is None: + return None + + try: + seconds = int(value) + except ValueError: + return parse_date(value) + + return datetime.now(timezone.utc) + timedelta(seconds=seconds) + + @retry_after.setter + def retry_after(self, value: t.Optional[t.Union[datetime, int, str]]) -> None: + if value is None: + if "retry-after" in self.headers: + del self.headers["retry-after"] + return + elif isinstance(value, datetime): + value = http_date(value) + else: + value = str(value) + self.headers["Retry-After"] = value + + vary = _set_property( + "Vary", + doc="""The Vary field value indicates the set of request-header + fields that fully determines, while the response is fresh, + whether a cache is permitted to use the response to reply to a + subsequent request without revalidation.""", + ) + content_language = _set_property( + "Content-Language", + doc="""The Content-Language entity-header field describes the + natural language(s) of the intended audience for the enclosed + entity. Note that this might not be equivalent to all the + languages used within the entity-body.""", + ) + allow = _set_property( + "Allow", + doc="""The Allow entity-header field lists the set of methods + supported by the resource identified by the Request-URI. The + purpose of this field is strictly to inform the recipient of + valid methods associated with the resource. An Allow header + field MUST be present in a 405 (Method Not Allowed) + response.""", + ) + + # ETag + + @property + def cache_control(self) -> ResponseCacheControl: + """The Cache-Control general-header field is used to specify + directives that MUST be obeyed by all caching mechanisms along the + request/response chain. + """ + + def on_update(cache_control: ResponseCacheControl) -> None: + if not cache_control and "cache-control" in self.headers: + del self.headers["cache-control"] + elif cache_control: + self.headers["Cache-Control"] = cache_control.to_header() + + return parse_cache_control_header( + self.headers.get("cache-control"), on_update, ResponseCacheControl + ) + + def set_etag(self, etag: str, weak: bool = False) -> None: + """Set the etag, and override the old one if there was one.""" + self.headers["ETag"] = quote_etag(etag, weak) + + def get_etag(self) -> t.Union[t.Tuple[str, bool], t.Tuple[None, None]]: + """Return a tuple in the form ``(etag, is_weak)``. If there is no + ETag the return value is ``(None, None)``. + """ + return unquote_etag(self.headers.get("ETag")) + + accept_ranges = header_property[str]( + "Accept-Ranges", + doc="""The `Accept-Ranges` header. Even though the name would + indicate that multiple values are supported, it must be one + string token only. + + The values ``'bytes'`` and ``'none'`` are common. + + .. versionadded:: 0.7""", + ) + + @property + def content_range(self) -> ContentRange: + """The ``Content-Range`` header as a + :class:`~werkzeug.datastructures.ContentRange` object. Available + even if the header is not set. + + .. versionadded:: 0.7 + """ + + def on_update(rng: ContentRange) -> None: + if not rng: + del self.headers["content-range"] + else: + self.headers["Content-Range"] = rng.to_header() + + rv = parse_content_range_header(self.headers.get("content-range"), on_update) + # always provide a content range object to make the descriptor + # more user friendly. It provides an unset() method that can be + # used to remove the header quickly. + if rv is None: + rv = ContentRange(None, None, None, on_update=on_update) + return rv + + @content_range.setter + def content_range(self, value: t.Optional[t.Union[ContentRange, str]]) -> None: + if not value: + del self.headers["content-range"] + elif isinstance(value, str): + self.headers["Content-Range"] = value + else: + self.headers["Content-Range"] = value.to_header() + + # Authorization + + @property + def www_authenticate(self) -> WWWAuthenticate: + """The ``WWW-Authenticate`` header in a parsed form.""" + + def on_update(www_auth: WWWAuthenticate) -> None: + if not www_auth and "www-authenticate" in self.headers: + del self.headers["www-authenticate"] + elif www_auth: + self.headers["WWW-Authenticate"] = www_auth.to_header() + + header = self.headers.get("www-authenticate") + return parse_www_authenticate_header(header, on_update) + + # CSP + + @property + def content_security_policy(self) -> ContentSecurityPolicy: + """The ``Content-Security-Policy`` header as a + :class:`~werkzeug.datastructures.ContentSecurityPolicy` object. Available + even if the header is not set. + + The Content-Security-Policy header adds an additional layer of + security to help detect and mitigate certain types of attacks. + """ + + def on_update(csp: ContentSecurityPolicy) -> None: + if not csp: + del self.headers["content-security-policy"] + else: + self.headers["Content-Security-Policy"] = csp.to_header() + + rv = parse_csp_header(self.headers.get("content-security-policy"), on_update) + if rv is None: + rv = ContentSecurityPolicy(None, on_update=on_update) + return rv + + @content_security_policy.setter + def content_security_policy( + self, value: t.Optional[t.Union[ContentSecurityPolicy, str]] + ) -> None: + if not value: + del self.headers["content-security-policy"] + elif isinstance(value, str): + self.headers["Content-Security-Policy"] = value + else: + self.headers["Content-Security-Policy"] = value.to_header() + + @property + def content_security_policy_report_only(self) -> ContentSecurityPolicy: + """The ``Content-Security-policy-report-only`` header as a + :class:`~werkzeug.datastructures.ContentSecurityPolicy` object. Available + even if the header is not set. + + The Content-Security-Policy-Report-Only header adds a csp policy + that is not enforced but is reported thereby helping detect + certain types of attacks. + """ + + def on_update(csp: ContentSecurityPolicy) -> None: + if not csp: + del self.headers["content-security-policy-report-only"] + else: + self.headers["Content-Security-policy-report-only"] = csp.to_header() + + rv = parse_csp_header( + self.headers.get("content-security-policy-report-only"), on_update + ) + if rv is None: + rv = ContentSecurityPolicy(None, on_update=on_update) + return rv + + @content_security_policy_report_only.setter + def content_security_policy_report_only( + self, value: t.Optional[t.Union[ContentSecurityPolicy, str]] + ) -> None: + if not value: + del self.headers["content-security-policy-report-only"] + elif isinstance(value, str): + self.headers["Content-Security-policy-report-only"] = value + else: + self.headers["Content-Security-policy-report-only"] = value.to_header() + + # CORS + + @property + def access_control_allow_credentials(self) -> bool: + """Whether credentials can be shared by the browser to + JavaScript code. As part of the preflight request it indicates + whether credentials can be used on the cross origin request. + """ + return "Access-Control-Allow-Credentials" in self.headers + + @access_control_allow_credentials.setter + def access_control_allow_credentials(self, value: t.Optional[bool]) -> None: + if value is True: + self.headers["Access-Control-Allow-Credentials"] = "true" + else: + self.headers.pop("Access-Control-Allow-Credentials", None) + + access_control_allow_headers = header_property( + "Access-Control-Allow-Headers", + load_func=parse_set_header, + dump_func=dump_header, + doc="Which headers can be sent with the cross origin request.", + ) + + access_control_allow_methods = header_property( + "Access-Control-Allow-Methods", + load_func=parse_set_header, + dump_func=dump_header, + doc="Which methods can be used for the cross origin request.", + ) + + access_control_allow_origin = header_property[str]( + "Access-Control-Allow-Origin", + doc="The origin or '*' for any origin that may make cross origin requests.", + ) + + access_control_expose_headers = header_property( + "Access-Control-Expose-Headers", + load_func=parse_set_header, + dump_func=dump_header, + doc="Which headers can be shared by the browser to JavaScript code.", + ) + + access_control_max_age = header_property( + "Access-Control-Max-Age", + load_func=int, + dump_func=str, + doc="The maximum age in seconds the access control settings can be cached for.", + ) + + cross_origin_opener_policy = header_property[COOP]( + "Cross-Origin-Opener-Policy", + load_func=lambda value: COOP(value), + dump_func=lambda value: value.value, + default=COOP.UNSAFE_NONE, + doc="""Allows control over sharing of browsing context group with cross-origin + documents. Values must be a member of the :class:`werkzeug.http.COOP` enum.""", + ) + + cross_origin_embedder_policy = header_property[COEP]( + "Cross-Origin-Embedder-Policy", + load_func=lambda value: COEP(value), + dump_func=lambda value: value.value, + default=COEP.UNSAFE_NONE, + doc="""Prevents a document from loading any cross-origin resources that do not + explicitly grant the document permission. Values must be a member of the + :class:`werkzeug.http.COEP` enum.""", + ) diff --git a/.vcrunch/Lib/site-packages/werkzeug/sansio/utils.py b/.vcrunch/Lib/site-packages/werkzeug/sansio/utils.py new file mode 100644 index 0000000..e639dcb --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/sansio/utils.py @@ -0,0 +1,165 @@ +import typing as t + +from .._internal import _encode_idna +from ..exceptions import SecurityError +from ..urls import uri_to_iri +from ..urls import url_quote + + +def host_is_trusted(hostname: str, trusted_list: t.Iterable[str]) -> bool: + """Check if a host matches a list of trusted names. + + :param hostname: The name to check. + :param trusted_list: A list of valid names to match. If a name + starts with a dot it will match all subdomains. + + .. versionadded:: 0.9 + """ + if not hostname: + return False + + if isinstance(trusted_list, str): + trusted_list = [trusted_list] + + def _normalize(hostname: str) -> bytes: + if ":" in hostname: + hostname = hostname.rsplit(":", 1)[0] + + return _encode_idna(hostname) + + try: + hostname_bytes = _normalize(hostname) + except UnicodeError: + return False + + for ref in trusted_list: + if ref.startswith("."): + ref = ref[1:] + suffix_match = True + else: + suffix_match = False + + try: + ref_bytes = _normalize(ref) + except UnicodeError: + return False + + if ref_bytes == hostname_bytes: + return True + + if suffix_match and hostname_bytes.endswith(b"." + ref_bytes): + return True + + return False + + +def get_host( + scheme: str, + host_header: t.Optional[str], + server: t.Optional[t.Tuple[str, t.Optional[int]]] = None, + trusted_hosts: t.Optional[t.Iterable[str]] = None, +) -> str: + """Return the host for the given parameters. + + This first checks the ``host_header``. If it's not present, then + ``server`` is used. The host will only contain the port if it is + different than the standard port for the protocol. + + Optionally, verify that the host is trusted using + :func:`host_is_trusted` and raise a + :exc:`~werkzeug.exceptions.SecurityError` if it is not. + + :param scheme: The protocol the request used, like ``"https"``. + :param host_header: The ``Host`` header value. + :param server: Address of the server. ``(host, port)``, or + ``(path, None)`` for unix sockets. + :param trusted_hosts: A list of trusted host names. + + :return: Host, with port if necessary. + :raise ~werkzeug.exceptions.SecurityError: If the host is not + trusted. + """ + host = "" + + if host_header is not None: + host = host_header + elif server is not None: + host = server[0] + + if server[1] is not None: + host = f"{host}:{server[1]}" + + if scheme in {"http", "ws"} and host.endswith(":80"): + host = host[:-3] + elif scheme in {"https", "wss"} and host.endswith(":443"): + host = host[:-4] + + if trusted_hosts is not None: + if not host_is_trusted(host, trusted_hosts): + raise SecurityError(f"Host {host!r} is not trusted.") + + return host + + +def get_current_url( + scheme: str, + host: str, + root_path: t.Optional[str] = None, + path: t.Optional[str] = None, + query_string: t.Optional[bytes] = None, +) -> str: + """Recreate the URL for a request. If an optional part isn't + provided, it and subsequent parts are not included in the URL. + + The URL is an IRI, not a URI, so it may contain Unicode characters. + Use :func:`~werkzeug.urls.iri_to_uri` to convert it to ASCII. + + :param scheme: The protocol the request used, like ``"https"``. + :param host: The host the request was made to. See :func:`get_host`. + :param root_path: Prefix that the application is mounted under. This + is prepended to ``path``. + :param path: The path part of the URL after ``root_path``. + :param query_string: The portion of the URL after the "?". + """ + url = [scheme, "://", host] + + if root_path is None: + url.append("/") + return uri_to_iri("".join(url)) + + url.append(url_quote(root_path.rstrip("/"))) + url.append("/") + + if path is None: + return uri_to_iri("".join(url)) + + url.append(url_quote(path.lstrip("/"))) + + if query_string: + url.append("?") + url.append(url_quote(query_string, safe=":&%=+$!*'(),")) + + return uri_to_iri("".join(url)) + + +def get_content_length( + http_content_length: t.Union[str, None] = None, + http_transfer_encoding: t.Union[str, None] = "", +) -> t.Optional[int]: + """Returns the content length as an integer or ``None`` if + unavailable or chunked transfer encoding is used. + + :param http_content_length: The Content-Length HTTP header. + :param http_transfer_encoding: The Transfer-Encoding HTTP header. + + .. versionadded:: 2.2 + """ + if http_transfer_encoding == "chunked": + return None + + if http_content_length is not None: + try: + return max(0, int(http_content_length)) + except (ValueError, TypeError): + pass + return None diff --git a/.vcrunch/Lib/site-packages/werkzeug/security.py b/.vcrunch/Lib/site-packages/werkzeug/security.py new file mode 100644 index 0000000..18d0919 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/security.py @@ -0,0 +1,140 @@ +import hashlib +import hmac +import os +import posixpath +import secrets +import typing as t + +if t.TYPE_CHECKING: + pass + +SALT_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" +DEFAULT_PBKDF2_ITERATIONS = 260000 + +_os_alt_seps: t.List[str] = list( + sep for sep in [os.path.sep, os.path.altsep] if sep is not None and sep != "/" +) + + +def gen_salt(length: int) -> str: + """Generate a random string of SALT_CHARS with specified ``length``.""" + if length <= 0: + raise ValueError("Salt length must be positive") + + return "".join(secrets.choice(SALT_CHARS) for _ in range(length)) + + +def _hash_internal(method: str, salt: str, password: str) -> t.Tuple[str, str]: + """Internal password hash helper. Supports plaintext without salt, + unsalted and salted passwords. In case salted passwords are used + hmac is used. + """ + if method == "plain": + return password, method + + salt = salt.encode("utf-8") + password = password.encode("utf-8") + + if method.startswith("pbkdf2:"): + if not salt: + raise ValueError("Salt is required for PBKDF2") + + args = method[7:].split(":") + + if len(args) not in (1, 2): + raise ValueError("Invalid number of arguments for PBKDF2") + + method = args.pop(0) + iterations = int(args[0] or 0) if args else DEFAULT_PBKDF2_ITERATIONS + return ( + hashlib.pbkdf2_hmac(method, password, salt, iterations).hex(), + f"pbkdf2:{method}:{iterations}", + ) + + if salt: + return hmac.new(salt, password, method).hexdigest(), method + + return hashlib.new(method, password).hexdigest(), method + + +def generate_password_hash( + password: str, method: str = "pbkdf2:sha256", salt_length: int = 16 +) -> str: + """Hash a password with the given method and salt with a string of + the given length. The format of the string returned includes the method + that was used so that :func:`check_password_hash` can check the hash. + + The format for the hashed string looks like this:: + + method$salt$hash + + This method can **not** generate unsalted passwords but it is possible + to set param method='plain' in order to enforce plaintext passwords. + If a salt is used, hmac is used internally to salt the password. + + If PBKDF2 is wanted it can be enabled by setting the method to + ``pbkdf2:method:iterations`` where iterations is optional:: + + pbkdf2:sha256:80000$salt$hash + pbkdf2:sha256$salt$hash + + :param password: the password to hash. + :param method: the hash method to use (one that hashlib supports). Can + optionally be in the format ``pbkdf2:method:iterations`` + to enable PBKDF2. + :param salt_length: the length of the salt in letters. + """ + salt = gen_salt(salt_length) if method != "plain" else "" + h, actual_method = _hash_internal(method, salt, password) + return f"{actual_method}${salt}${h}" + + +def check_password_hash(pwhash: str, password: str) -> bool: + """Check a password against a given salted and hashed password value. + In order to support unsalted legacy passwords this method supports + plain text passwords, md5 and sha1 hashes (both salted and unsalted). + + Returns `True` if the password matched, `False` otherwise. + + :param pwhash: a hashed string like returned by + :func:`generate_password_hash`. + :param password: the plaintext password to compare against the hash. + """ + if pwhash.count("$") < 2: + return False + + method, salt, hashval = pwhash.split("$", 2) + return hmac.compare_digest(_hash_internal(method, salt, password)[0], hashval) + + +def safe_join(directory: str, *pathnames: str) -> t.Optional[str]: + """Safely join zero or more untrusted path components to a base + directory to avoid escaping the base directory. + + :param directory: The trusted base directory. + :param pathnames: The untrusted path components relative to the + base directory. + :return: A safe path, otherwise ``None``. + """ + if not directory: + # Ensure we end up with ./path if directory="" is given, + # otherwise the first untrusted part could become trusted. + directory = "." + + parts = [directory] + + for filename in pathnames: + if filename != "": + filename = posixpath.normpath(filename) + + if ( + any(sep in filename for sep in _os_alt_seps) + or os.path.isabs(filename) + or filename == ".." + or filename.startswith("../") + ): + return None + + parts.append(filename) + + return posixpath.join(*parts) diff --git a/.vcrunch/Lib/site-packages/werkzeug/serving.py b/.vcrunch/Lib/site-packages/werkzeug/serving.py new file mode 100644 index 0000000..c482469 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/serving.py @@ -0,0 +1,1098 @@ +"""A WSGI and HTTP server for use **during development only**. This +server is convenient to use, but is not designed to be particularly +stable, secure, or efficient. Use a dedicate WSGI server and HTTP +server when deploying to production. + +It provides features like interactive debugging and code reloading. Use +``run_simple`` to start the server. Put this in a ``run.py`` script: + +.. code-block:: python + + from myapp import create_app + from werkzeug import run_simple +""" +import errno +import io +import os +import socket +import socketserver +import sys +import typing as t +from datetime import datetime as dt +from datetime import timedelta +from datetime import timezone +from http.server import BaseHTTPRequestHandler +from http.server import HTTPServer + +from ._internal import _log +from ._internal import _wsgi_encoding_dance +from .exceptions import InternalServerError +from .urls import uri_to_iri +from .urls import url_parse +from .urls import url_unquote + +try: + import ssl +except ImportError: + + class _SslDummy: + def __getattr__(self, name: str) -> t.Any: + raise RuntimeError( # noqa: B904 + "SSL is unavailable because this Python runtime was not" + " compiled with SSL/TLS support." + ) + + ssl = _SslDummy() # type: ignore + +_log_add_style = True + +if os.name == "nt": + try: + __import__("colorama") + except ImportError: + _log_add_style = False + +can_fork = hasattr(os, "fork") + +if can_fork: + ForkingMixIn = socketserver.ForkingMixIn +else: + + class ForkingMixIn: # type: ignore + pass + + +try: + af_unix = socket.AF_UNIX +except AttributeError: + af_unix = None # type: ignore + +LISTEN_QUEUE = 128 + +_TSSLContextArg = t.Optional[ + t.Union["ssl.SSLContext", t.Tuple[str, t.Optional[str]], "te.Literal['adhoc']"] +] + +if t.TYPE_CHECKING: + import typing_extensions as te # noqa: F401 + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + from cryptography.hazmat.primitives.asymmetric.rsa import ( + RSAPrivateKeyWithSerialization, + ) + from cryptography.x509 import Certificate + + +class DechunkedInput(io.RawIOBase): + """An input stream that handles Transfer-Encoding 'chunked'""" + + def __init__(self, rfile: t.IO[bytes]) -> None: + self._rfile = rfile + self._done = False + self._len = 0 + + def readable(self) -> bool: + return True + + def read_chunk_len(self) -> int: + try: + line = self._rfile.readline().decode("latin1") + _len = int(line.strip(), 16) + except ValueError as e: + raise OSError("Invalid chunk header") from e + if _len < 0: + raise OSError("Negative chunk length not allowed") + return _len + + def readinto(self, buf: bytearray) -> int: # type: ignore + read = 0 + while not self._done and read < len(buf): + if self._len == 0: + # This is the first chunk or we fully consumed the previous + # one. Read the next length of the next chunk + self._len = self.read_chunk_len() + + if self._len == 0: + # Found the final chunk of size 0. The stream is now exhausted, + # but there is still a final newline that should be consumed + self._done = True + + if self._len > 0: + # There is data (left) in this chunk, so append it to the + # buffer. If this operation fully consumes the chunk, this will + # reset self._len to 0. + n = min(len(buf), self._len) + + # If (read + chunk size) becomes more than len(buf), buf will + # grow beyond the original size and read more data than + # required. So only read as much data as can fit in buf. + if read + n > len(buf): + buf[read:] = self._rfile.read(len(buf) - read) + self._len -= len(buf) - read + read = len(buf) + else: + buf[read : read + n] = self._rfile.read(n) + self._len -= n + read += n + + if self._len == 0: + # Skip the terminating newline of a chunk that has been fully + # consumed. This also applies to the 0-sized final chunk + terminator = self._rfile.readline() + if terminator not in (b"\n", b"\r\n", b"\r"): + raise OSError("Missing chunk terminating newline") + + return read + + +class WSGIRequestHandler(BaseHTTPRequestHandler): + """A request handler that implements WSGI dispatching.""" + + server: "BaseWSGIServer" + + @property + def server_version(self) -> str: # type: ignore + from . import __version__ + + return f"Werkzeug/{__version__}" + + def make_environ(self) -> "WSGIEnvironment": + request_url = url_parse(self.path) + url_scheme = "http" if self.server.ssl_context is None else "https" + + if not self.client_address: + self.client_address = ("", 0) + elif isinstance(self.client_address, str): + self.client_address = (self.client_address, 0) + + # If there was no scheme but the path started with two slashes, + # the first segment may have been incorrectly parsed as the + # netloc, prepend it to the path again. + if not request_url.scheme and request_url.netloc: + path_info = f"/{request_url.netloc}{request_url.path}" + else: + path_info = request_url.path + + path_info = url_unquote(path_info) + + environ: "WSGIEnvironment" = { + "wsgi.version": (1, 0), + "wsgi.url_scheme": url_scheme, + "wsgi.input": self.rfile, + "wsgi.errors": sys.stderr, + "wsgi.multithread": self.server.multithread, + "wsgi.multiprocess": self.server.multiprocess, + "wsgi.run_once": False, + "werkzeug.socket": self.connection, + "SERVER_SOFTWARE": self.server_version, + "REQUEST_METHOD": self.command, + "SCRIPT_NAME": "", + "PATH_INFO": _wsgi_encoding_dance(path_info), + "QUERY_STRING": _wsgi_encoding_dance(request_url.query), + # Non-standard, added by mod_wsgi, uWSGI + "REQUEST_URI": _wsgi_encoding_dance(self.path), + # Non-standard, added by gunicorn + "RAW_URI": _wsgi_encoding_dance(self.path), + "REMOTE_ADDR": self.address_string(), + "REMOTE_PORT": self.port_integer(), + "SERVER_NAME": self.server.server_address[0], + "SERVER_PORT": str(self.server.server_address[1]), + "SERVER_PROTOCOL": self.request_version, + } + + for key, value in self.headers.items(): + key = key.upper().replace("-", "_") + value = value.replace("\r\n", "") + if key not in ("CONTENT_TYPE", "CONTENT_LENGTH"): + key = f"HTTP_{key}" + if key in environ: + value = f"{environ[key]},{value}" + environ[key] = value + + if environ.get("HTTP_TRANSFER_ENCODING", "").strip().lower() == "chunked": + environ["wsgi.input_terminated"] = True + environ["wsgi.input"] = DechunkedInput(environ["wsgi.input"]) + + # Per RFC 2616, if the URL is absolute, use that as the host. + # We're using "has a scheme" to indicate an absolute URL. + if request_url.scheme and request_url.netloc: + environ["HTTP_HOST"] = request_url.netloc + + try: + # binary_form=False gives nicer information, but wouldn't be compatible with + # what Nginx or Apache could return. + peer_cert = self.connection.getpeercert( # type: ignore[attr-defined] + binary_form=True + ) + if peer_cert is not None: + # Nginx and Apache use PEM format. + environ["SSL_CLIENT_CERT"] = ssl.DER_cert_to_PEM_cert(peer_cert) + except ValueError: + # SSL handshake hasn't finished. + self.server.log("error", "Cannot fetch SSL peer certificate info") + except AttributeError: + # Not using TLS, the socket will not have getpeercert(). + pass + + return environ + + def run_wsgi(self) -> None: + if self.headers.get("Expect", "").lower().strip() == "100-continue": + self.wfile.write(b"HTTP/1.1 100 Continue\r\n\r\n") + + self.environ = environ = self.make_environ() + status_set: t.Optional[str] = None + headers_set: t.Optional[t.List[t.Tuple[str, str]]] = None + status_sent: t.Optional[str] = None + headers_sent: t.Optional[t.List[t.Tuple[str, str]]] = None + chunk_response: bool = False + + def write(data: bytes) -> None: + nonlocal status_sent, headers_sent, chunk_response + assert status_set is not None, "write() before start_response" + assert headers_set is not None, "write() before start_response" + if status_sent is None: + status_sent = status_set + headers_sent = headers_set + try: + code_str, msg = status_sent.split(None, 1) + except ValueError: + code_str, msg = status_sent, "" + code = int(code_str) + self.send_response(code, msg) + header_keys = set() + for key, value in headers_sent: + self.send_header(key, value) + header_keys.add(key.lower()) + + # Use chunked transfer encoding if there is no content + # length. Do not use for 1xx and 204 responses. 304 + # responses and HEAD requests are also excluded, which + # is the more conservative behavior and matches other + # parts of the code. + # https://httpwg.org/specs/rfc7230.html#rfc.section.3.3.1 + if ( + not ( + "content-length" in header_keys + or environ["REQUEST_METHOD"] == "HEAD" + or (100 <= code < 200) + or code in {204, 304} + ) + and self.protocol_version >= "HTTP/1.1" + ): + chunk_response = True + self.send_header("Transfer-Encoding", "chunked") + + # Always close the connection. This disables HTTP/1.1 + # keep-alive connections. They aren't handled well by + # Python's http.server because it doesn't know how to + # drain the stream before the next request line. + self.send_header("Connection", "close") + self.end_headers() + + assert isinstance(data, bytes), "applications must write bytes" + + if data: + if chunk_response: + self.wfile.write(hex(len(data))[2:].encode()) + self.wfile.write(b"\r\n") + + self.wfile.write(data) + + if chunk_response: + self.wfile.write(b"\r\n") + + self.wfile.flush() + + def start_response(status, headers, exc_info=None): # type: ignore + nonlocal status_set, headers_set + if exc_info: + try: + if headers_sent: + raise exc_info[1].with_traceback(exc_info[2]) + finally: + exc_info = None + elif headers_set: + raise AssertionError("Headers already set") + status_set = status + headers_set = headers + return write + + def execute(app: "WSGIApplication") -> None: + application_iter = app(environ, start_response) + try: + for data in application_iter: + write(data) + if not headers_sent: + write(b"") + if chunk_response: + self.wfile.write(b"0\r\n\r\n") + finally: + if hasattr(application_iter, "close"): + application_iter.close() # type: ignore + + try: + execute(self.server.app) + except (ConnectionError, socket.timeout) as e: + self.connection_dropped(e, environ) + except Exception as e: + if self.server.passthrough_errors: + raise + + if status_sent is not None and chunk_response: + self.close_connection = True + + try: + # if we haven't yet sent the headers but they are set + # we roll back to be able to set them again. + if status_sent is None: + status_set = None + headers_set = None + execute(InternalServerError()) + except Exception: + pass + + from .debug.tbtools import DebugTraceback + + msg = DebugTraceback(e).render_traceback_text() + self.server.log("error", f"Error on request:\n{msg}") + + def handle(self) -> None: + """Handles a request ignoring dropped connections.""" + try: + super().handle() + except (ConnectionError, socket.timeout) as e: + self.connection_dropped(e) + except Exception as e: + if self.server.ssl_context is not None and is_ssl_error(e): + self.log_error("SSL error occurred: %s", e) + else: + raise + + def connection_dropped( + self, error: BaseException, environ: t.Optional["WSGIEnvironment"] = None + ) -> None: + """Called if the connection was closed by the client. By default + nothing happens. + """ + + def __getattr__(self, name: str) -> t.Any: + # All HTTP methods are handled by run_wsgi. + if name.startswith("do_"): + return self.run_wsgi + + # All other attributes are forwarded to the base class. + return getattr(super(), name) + + def address_string(self) -> str: + if getattr(self, "environ", None): + return self.environ["REMOTE_ADDR"] # type: ignore + + if not self.client_address: + return "" + + return self.client_address[0] + + def port_integer(self) -> int: + return self.client_address[1] + + def log_request( + self, code: t.Union[int, str] = "-", size: t.Union[int, str] = "-" + ) -> None: + try: + path = uri_to_iri(self.path) + msg = f"{self.command} {path} {self.request_version}" + except AttributeError: + # path isn't set if the requestline was bad + msg = self.requestline + + code = str(code) + + if code[0] == "1": # 1xx - Informational + msg = _ansi_style(msg, "bold") + elif code == "200": # 2xx - Success + pass + elif code == "304": # 304 - Resource Not Modified + msg = _ansi_style(msg, "cyan") + elif code[0] == "3": # 3xx - Redirection + msg = _ansi_style(msg, "green") + elif code == "404": # 404 - Resource Not Found + msg = _ansi_style(msg, "yellow") + elif code[0] == "4": # 4xx - Client Error + msg = _ansi_style(msg, "bold", "red") + else: # 5xx, or any other response + msg = _ansi_style(msg, "bold", "magenta") + + self.log("info", '"%s" %s %s', msg, code, size) + + def log_error(self, format: str, *args: t.Any) -> None: + self.log("error", format, *args) + + def log_message(self, format: str, *args: t.Any) -> None: + self.log("info", format, *args) + + def log(self, type: str, message: str, *args: t.Any) -> None: + _log( + type, + f"{self.address_string()} - - [{self.log_date_time_string()}] {message}\n", + *args, + ) + + +def _ansi_style(value: str, *styles: str) -> str: + if not _log_add_style: + return value + + codes = { + "bold": 1, + "red": 31, + "green": 32, + "yellow": 33, + "magenta": 35, + "cyan": 36, + } + + for style in styles: + value = f"\x1b[{codes[style]}m{value}" + + return f"{value}\x1b[0m" + + +def generate_adhoc_ssl_pair( + cn: t.Optional[str] = None, +) -> t.Tuple["Certificate", "RSAPrivateKeyWithSerialization"]: + try: + from cryptography import x509 + from cryptography.x509.oid import NameOID + from cryptography.hazmat.backends import default_backend + from cryptography.hazmat.primitives import hashes + from cryptography.hazmat.primitives.asymmetric import rsa + except ImportError: + raise TypeError( + "Using ad-hoc certificates requires the cryptography library." + ) from None + + backend = default_backend() + pkey = rsa.generate_private_key( + public_exponent=65537, key_size=2048, backend=backend + ) + + # pretty damn sure that this is not actually accepted by anyone + if cn is None: + cn = "*" + + subject = x509.Name( + [ + x509.NameAttribute(NameOID.ORGANIZATION_NAME, "Dummy Certificate"), + x509.NameAttribute(NameOID.COMMON_NAME, cn), + ] + ) + + backend = default_backend() + cert = ( + x509.CertificateBuilder() + .subject_name(subject) + .issuer_name(subject) + .public_key(pkey.public_key()) + .serial_number(x509.random_serial_number()) + .not_valid_before(dt.now(timezone.utc)) + .not_valid_after(dt.now(timezone.utc) + timedelta(days=365)) + .add_extension(x509.ExtendedKeyUsage([x509.OID_SERVER_AUTH]), critical=False) + .add_extension(x509.SubjectAlternativeName([x509.DNSName(cn)]), critical=False) + .sign(pkey, hashes.SHA256(), backend) + ) + return cert, pkey + + +def make_ssl_devcert( + base_path: str, host: t.Optional[str] = None, cn: t.Optional[str] = None +) -> t.Tuple[str, str]: + """Creates an SSL key for development. This should be used instead of + the ``'adhoc'`` key which generates a new cert on each server start. + It accepts a path for where it should store the key and cert and + either a host or CN. If a host is given it will use the CN + ``*.host/CN=host``. + + For more information see :func:`run_simple`. + + .. versionadded:: 0.9 + + :param base_path: the path to the certificate and key. The extension + ``.crt`` is added for the certificate, ``.key`` is + added for the key. + :param host: the name of the host. This can be used as an alternative + for the `cn`. + :param cn: the `CN` to use. + """ + + if host is not None: + cn = f"*.{host}/CN={host}" + cert, pkey = generate_adhoc_ssl_pair(cn=cn) + + from cryptography.hazmat.primitives import serialization + + cert_file = f"{base_path}.crt" + pkey_file = f"{base_path}.key" + + with open(cert_file, "wb") as f: + f.write(cert.public_bytes(serialization.Encoding.PEM)) + with open(pkey_file, "wb") as f: + f.write( + pkey.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ) + ) + + return cert_file, pkey_file + + +def generate_adhoc_ssl_context() -> "ssl.SSLContext": + """Generates an adhoc SSL context for the development server.""" + import tempfile + import atexit + + cert, pkey = generate_adhoc_ssl_pair() + + from cryptography.hazmat.primitives import serialization + + cert_handle, cert_file = tempfile.mkstemp() + pkey_handle, pkey_file = tempfile.mkstemp() + atexit.register(os.remove, pkey_file) + atexit.register(os.remove, cert_file) + + os.write(cert_handle, cert.public_bytes(serialization.Encoding.PEM)) + os.write( + pkey_handle, + pkey.private_bytes( + encoding=serialization.Encoding.PEM, + format=serialization.PrivateFormat.TraditionalOpenSSL, + encryption_algorithm=serialization.NoEncryption(), + ), + ) + + os.close(cert_handle) + os.close(pkey_handle) + ctx = load_ssl_context(cert_file, pkey_file) + return ctx + + +def load_ssl_context( + cert_file: str, pkey_file: t.Optional[str] = None, protocol: t.Optional[int] = None +) -> "ssl.SSLContext": + """Loads SSL context from cert/private key files and optional protocol. + Many parameters are directly taken from the API of + :py:class:`ssl.SSLContext`. + + :param cert_file: Path of the certificate to use. + :param pkey_file: Path of the private key to use. If not given, the key + will be obtained from the certificate file. + :param protocol: A ``PROTOCOL`` constant from the :mod:`ssl` module. + Defaults to :data:`ssl.PROTOCOL_TLS_SERVER`. + """ + if protocol is None: + protocol = ssl.PROTOCOL_TLS_SERVER + + ctx = ssl.SSLContext(protocol) + ctx.load_cert_chain(cert_file, pkey_file) + return ctx + + +def is_ssl_error(error: t.Optional[Exception] = None) -> bool: + """Checks if the given error (or the current one) is an SSL error.""" + if error is None: + error = t.cast(Exception, sys.exc_info()[1]) + return isinstance(error, ssl.SSLError) + + +def select_address_family(host: str, port: int) -> socket.AddressFamily: + """Return ``AF_INET4``, ``AF_INET6``, or ``AF_UNIX`` depending on + the host and port.""" + if host.startswith("unix://"): + return socket.AF_UNIX + elif ":" in host and hasattr(socket, "AF_INET6"): + return socket.AF_INET6 + return socket.AF_INET + + +def get_sockaddr( + host: str, port: int, family: socket.AddressFamily +) -> t.Union[t.Tuple[str, int], str]: + """Return a fully qualified socket address that can be passed to + :func:`socket.bind`.""" + if family == af_unix: + return host.split("://", 1)[1] + try: + res = socket.getaddrinfo( + host, port, family, socket.SOCK_STREAM, socket.IPPROTO_TCP + ) + except socket.gaierror: + return host, port + return res[0][4] # type: ignore + + +def get_interface_ip(family: socket.AddressFamily) -> str: + """Get the IP address of an external interface. Used when binding to + 0.0.0.0 or ::1 to show a more useful URL. + + :meta private: + """ + # arbitrary private address + host = "fd31:f903:5ab5:1::1" if family == socket.AF_INET6 else "10.253.155.219" + + with socket.socket(family, socket.SOCK_DGRAM) as s: + try: + s.connect((host, 58162)) + except OSError: + return "::1" if family == socket.AF_INET6 else "127.0.0.1" + + return s.getsockname()[0] # type: ignore + + +class BaseWSGIServer(HTTPServer): + """A WSGI server that that handles one request at a time. + + Use :func:`make_server` to create a server instance. + """ + + multithread = False + multiprocess = False + request_queue_size = LISTEN_QUEUE + + def __init__( + self, + host: str, + port: int, + app: "WSGIApplication", + handler: t.Optional[t.Type[WSGIRequestHandler]] = None, + passthrough_errors: bool = False, + ssl_context: t.Optional[_TSSLContextArg] = None, + fd: t.Optional[int] = None, + ) -> None: + if handler is None: + handler = WSGIRequestHandler + + # If the handler doesn't directly set a protocol version and + # thread or process workers are used, then allow chunked + # responses and keep-alive connections by enabling HTTP/1.1. + if "protocol_version" not in vars(handler) and ( + self.multithread or self.multiprocess + ): + handler.protocol_version = "HTTP/1.1" + + self.host = host + self.port = port + self.app = app + self.passthrough_errors = passthrough_errors + + self.address_family = address_family = select_address_family(host, port) + server_address = get_sockaddr(host, int(port), address_family) + + # Remove a leftover Unix socket file from a previous run. Don't + # remove a file that was set up by run_simple. + if address_family == af_unix and fd is None: + server_address = t.cast(str, server_address) + + if os.path.exists(server_address): + os.unlink(server_address) + + # Bind and activate will be handled manually, it should only + # happen if we're not using a socket that was already set up. + super().__init__( + server_address, # type: ignore[arg-type] + handler, + bind_and_activate=False, + ) + + if fd is None: + # No existing socket descriptor, do bind_and_activate=True. + try: + self.server_bind() + self.server_activate() + except BaseException: + self.server_close() + raise + else: + # Use the passed in socket directly. + self.socket = socket.fromfd(fd, address_family, socket.SOCK_STREAM) + self.server_address = self.socket.getsockname() + + if address_family != af_unix: + # If port was 0, this will record the bound port. + self.port = self.server_address[1] + + if ssl_context is not None: + if isinstance(ssl_context, tuple): + ssl_context = load_ssl_context(*ssl_context) + elif ssl_context == "adhoc": + ssl_context = generate_adhoc_ssl_context() + + self.socket = ssl_context.wrap_socket(self.socket, server_side=True) + self.ssl_context: t.Optional["ssl.SSLContext"] = ssl_context + else: + self.ssl_context = None + + def log(self, type: str, message: str, *args: t.Any) -> None: + _log(type, message, *args) + + def serve_forever(self, poll_interval: float = 0.5) -> None: + try: + super().serve_forever(poll_interval=poll_interval) + except KeyboardInterrupt: + pass + finally: + self.server_close() + + def handle_error( + self, request: t.Any, client_address: t.Union[t.Tuple[str, int], str] + ) -> None: + if self.passthrough_errors: + raise + + return super().handle_error(request, client_address) + + def log_startup(self) -> None: + """Show information about the address when starting the server.""" + dev_warning = ( + "WARNING: This is a development server. Do not use it in a production" + " deployment. Use a production WSGI server instead." + ) + dev_warning = _ansi_style(dev_warning, "bold", "red") + messages = [dev_warning] + + if self.address_family == af_unix: + messages.append(f" * Running on {self.host}") + else: + scheme = "http" if self.ssl_context is None else "https" + display_hostname = self.host + + if self.host in {"0.0.0.0", "::"}: + messages.append(f" * Running on all addresses ({self.host})") + + if self.host == "0.0.0.0": + localhost = "127.0.0.1" + display_hostname = get_interface_ip(socket.AF_INET) + else: + localhost = "[::1]" + display_hostname = get_interface_ip(socket.AF_INET6) + + messages.append(f" * Running on {scheme}://{localhost}:{self.port}") + + if ":" in display_hostname: + display_hostname = f"[{display_hostname}]" + + messages.append(f" * Running on {scheme}://{display_hostname}:{self.port}") + + _log("info", "\n".join(messages)) + + +class ThreadedWSGIServer(socketserver.ThreadingMixIn, BaseWSGIServer): + """A WSGI server that handles concurrent requests in separate + threads. + + Use :func:`make_server` to create a server instance. + """ + + multithread = True + daemon_threads = True + + +class ForkingWSGIServer(ForkingMixIn, BaseWSGIServer): + """A WSGI server that handles concurrent requests in separate forked + processes. + + Use :func:`make_server` to create a server instance. + """ + + multiprocess = True + + def __init__( + self, + host: str, + port: int, + app: "WSGIApplication", + processes: int = 40, + handler: t.Optional[t.Type[WSGIRequestHandler]] = None, + passthrough_errors: bool = False, + ssl_context: t.Optional[_TSSLContextArg] = None, + fd: t.Optional[int] = None, + ) -> None: + if not can_fork: + raise ValueError("Your platform does not support forking.") + + super().__init__(host, port, app, handler, passthrough_errors, ssl_context, fd) + self.max_children = processes + + +def make_server( + host: str, + port: int, + app: "WSGIApplication", + threaded: bool = False, + processes: int = 1, + request_handler: t.Optional[t.Type[WSGIRequestHandler]] = None, + passthrough_errors: bool = False, + ssl_context: t.Optional[_TSSLContextArg] = None, + fd: t.Optional[int] = None, +) -> BaseWSGIServer: + """Create an appropriate WSGI server instance based on the value of + ``threaded`` and ``processes``. + + This is called from :func:`run_simple`, but can be used separately + to have access to the server object, such as to run it in a separate + thread. + + See :func:`run_simple` for parameter docs. + """ + if threaded and processes > 1: + raise ValueError("Cannot have a multi-thread and multi-process server.") + + if threaded: + return ThreadedWSGIServer( + host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd + ) + + if processes > 1: + return ForkingWSGIServer( + host, + port, + app, + processes, + request_handler, + passthrough_errors, + ssl_context, + fd=fd, + ) + + return BaseWSGIServer( + host, port, app, request_handler, passthrough_errors, ssl_context, fd=fd + ) + + +def is_running_from_reloader() -> bool: + """Check if the server is running as a subprocess within the + Werkzeug reloader. + + .. versionadded:: 0.10 + """ + return os.environ.get("WERKZEUG_RUN_MAIN") == "true" + + +def prepare_socket(hostname: str, port: int) -> socket.socket: + """Prepare a socket for use by the WSGI server and reloader. + + The socket is marked inheritable so that it can be kept across + reloads instead of breaking connections. + + Catch errors during bind and show simpler error messages. For + "address already in use", show instructions for resolving the issue, + with special instructions for macOS. + + This is called from :func:`run_simple`, but can be used separately + to control server creation with :func:`make_server`. + """ + address_family = select_address_family(hostname, port) + server_address = get_sockaddr(hostname, port, address_family) + s = socket.socket(address_family, socket.SOCK_STREAM) + s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + s.set_inheritable(True) + + # Remove the socket file if it already exists. + if address_family == af_unix: + server_address = t.cast(str, server_address) + + if os.path.exists(server_address): + os.unlink(server_address) + + # Catch connection issues and show them without the traceback. Show + # extra instructions for address not found, and for macOS. + try: + s.bind(server_address) + except OSError as e: + print(e.strerror, file=sys.stderr) + + if e.errno == errno.EADDRINUSE: + print( + f"Port {port} is in use by another program. Either" + " identify and stop that program, or start the" + " server with a different port.", + file=sys.stderr, + ) + + if sys.platform == "darwin" and port == 5000: + print( + "On macOS, try disabling the 'AirPlay Receiver'" + " service from System Preferences -> Sharing.", + file=sys.stderr, + ) + + sys.exit(1) + + s.listen(LISTEN_QUEUE) + return s + + +def run_simple( + hostname: str, + port: int, + application: "WSGIApplication", + use_reloader: bool = False, + use_debugger: bool = False, + use_evalex: bool = True, + extra_files: t.Optional[t.Iterable[str]] = None, + exclude_patterns: t.Optional[t.Iterable[str]] = None, + reloader_interval: int = 1, + reloader_type: str = "auto", + threaded: bool = False, + processes: int = 1, + request_handler: t.Optional[t.Type[WSGIRequestHandler]] = None, + static_files: t.Optional[t.Dict[str, t.Union[str, t.Tuple[str, str]]]] = None, + passthrough_errors: bool = False, + ssl_context: t.Optional[_TSSLContextArg] = None, +) -> None: + """Start a development server for a WSGI application. Various + optional features can be enabled. + + .. warning:: + + Do not use the development server when deploying to production. + It is intended for use only during local development. It is not + designed to be particularly efficient, stable, or secure. + + :param hostname: The host to bind to, for example ``'localhost'``. + Can be a domain, IPv4 or IPv6 address, or file path starting + with ``unix://`` for a Unix socket. + :param port: The port to bind to, for example ``8080``. Using ``0`` + tells the OS to pick a random free port. + :param application: The WSGI application to run. + :param use_reloader: Use a reloader process to restart the server + process when files are changed. + :param use_debugger: Use Werkzeug's debugger, which will show + formatted tracebacks on unhandled exceptions. + :param use_evalex: Make the debugger interactive. A Python terminal + can be opened for any frame in the traceback. Some protection is + provided by requiring a PIN, but this should never be enabled + on a publicly visible server. + :param extra_files: The reloader will watch these files for changes + in addition to Python modules. For example, watch a + configuration file. + :param exclude_patterns: The reloader will ignore changes to any + files matching these :mod:`fnmatch` patterns. For example, + ignore cache files. + :param reloader_interval: How often the reloader tries to check for + changes. + :param reloader_type: The reloader to use. The ``'stat'`` reloader + is built in, but may require significant CPU to watch files. The + ``'watchdog'`` reloader is much more efficient but requires + installing the ``watchdog`` package first. + :param threaded: Handle concurrent requests using threads. Cannot be + used with ``processes``. + :param processes: Handle concurrent requests using up to this number + of processes. Cannot be used with ``threaded``. + :param request_handler: Use a different + :class:`~BaseHTTPServer.BaseHTTPRequestHandler` subclass to + handle requests. + :param static_files: A dict mapping URL prefixes to directories to + serve static files from using + :class:`~werkzeug.middleware.SharedDataMiddleware`. + :param passthrough_errors: Don't catch unhandled exceptions at the + server level, let the serve crash instead. If ``use_debugger`` + is enabled, the debugger will still catch such errors. + :param ssl_context: Configure TLS to serve over HTTPS. Can be an + :class:`ssl.SSLContext` object, a ``(cert_file, key_file)`` + tuple to create a typical context, or the string ``'adhoc'`` to + generate a temporary self-signed certificate. + + .. versionchanged:: 2.1 + Instructions are shown for dealing with an "address already in + use" error. + + .. versionchanged:: 2.1 + Running on ``0.0.0.0`` or ``::`` shows the loopback IP in + addition to a real IP. + + .. versionchanged:: 2.1 + The command-line interface was removed. + + .. versionchanged:: 2.0 + Running on ``0.0.0.0`` or ``::`` shows a real IP address that + was bound as well as a warning not to run the development server + in production. + + .. versionchanged:: 2.0 + The ``exclude_patterns`` parameter was added. + + .. versionchanged:: 0.15 + Bind to a Unix socket by passing a ``hostname`` that starts with + ``unix://``. + + .. versionchanged:: 0.10 + Improved the reloader and added support for changing the backend + through the ``reloader_type`` parameter. + + .. versionchanged:: 0.9 + A command-line interface was added. + + .. versionchanged:: 0.8 + ``ssl_context`` can be a tuple of paths to the certificate and + private key files. + + .. versionchanged:: 0.6 + The ``ssl_context`` parameter was added. + + .. versionchanged:: 0.5 + The ``static_files`` and ``passthrough_errors`` parameters were + added. + """ + if not isinstance(port, int): + raise TypeError("port must be an integer") + + if static_files: + from .middleware.shared_data import SharedDataMiddleware + + application = SharedDataMiddleware(application, static_files) + + if use_debugger: + from .debug import DebuggedApplication + + application = DebuggedApplication(application, evalex=use_evalex) + + if not is_running_from_reloader(): + s = prepare_socket(hostname, port) + fd = s.fileno() + # Silence a ResourceWarning about an unclosed socket. This object is no longer + # used, the server will create another with fromfd. + s.detach() + os.environ["WERKZEUG_SERVER_FD"] = str(fd) + else: + fd = int(os.environ["WERKZEUG_SERVER_FD"]) + + srv = make_server( + hostname, + port, + application, + threaded, + processes, + request_handler, + passthrough_errors, + ssl_context, + fd=fd, + ) + + if not is_running_from_reloader(): + srv.log_startup() + _log("info", _ansi_style("Press CTRL+C to quit", "yellow")) + + if use_reloader: + from ._reloader import run_with_reloader + + run_with_reloader( + srv.serve_forever, + extra_files=extra_files, + exclude_patterns=exclude_patterns, + interval=reloader_interval, + reloader_type=reloader_type, + ) + else: + srv.serve_forever() diff --git a/.vcrunch/Lib/site-packages/werkzeug/test.py b/.vcrunch/Lib/site-packages/werkzeug/test.py new file mode 100644 index 0000000..edb4d4a --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/test.py @@ -0,0 +1,1337 @@ +import mimetypes +import sys +import typing as t +from collections import defaultdict +from datetime import datetime +from datetime import timedelta +from http.cookiejar import CookieJar +from io import BytesIO +from itertools import chain +from random import random +from tempfile import TemporaryFile +from time import time +from urllib.request import Request as _UrllibRequest + +from ._internal import _get_environ +from ._internal import _make_encode_wrapper +from ._internal import _wsgi_decoding_dance +from ._internal import _wsgi_encoding_dance +from .datastructures import Authorization +from .datastructures import CallbackDict +from .datastructures import CombinedMultiDict +from .datastructures import EnvironHeaders +from .datastructures import FileMultiDict +from .datastructures import Headers +from .datastructures import MultiDict +from .http import dump_cookie +from .http import dump_options_header +from .http import parse_options_header +from .sansio.multipart import Data +from .sansio.multipart import Epilogue +from .sansio.multipart import Field +from .sansio.multipart import File +from .sansio.multipart import MultipartEncoder +from .sansio.multipart import Preamble +from .urls import iri_to_uri +from .urls import url_encode +from .urls import url_fix +from .urls import url_parse +from .urls import url_unparse +from .urls import url_unquote +from .utils import cached_property +from .utils import get_content_type +from .wrappers.request import Request +from .wrappers.response import Response +from .wsgi import ClosingIterator +from .wsgi import get_current_url + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +def stream_encode_multipart( + data: t.Mapping[str, t.Any], + use_tempfile: bool = True, + threshold: int = 1024 * 500, + boundary: t.Optional[str] = None, + charset: str = "utf-8", +) -> t.Tuple[t.IO[bytes], int, str]: + """Encode a dict of values (either strings or file descriptors or + :class:`FileStorage` objects.) into a multipart encoded string stored + in a file descriptor. + """ + if boundary is None: + boundary = f"---------------WerkzeugFormPart_{time()}{random()}" + + stream: t.IO[bytes] = BytesIO() + total_length = 0 + on_disk = False + write_binary: t.Callable[[bytes], int] + + if use_tempfile: + + def write_binary(s: bytes) -> int: + nonlocal stream, total_length, on_disk + + if on_disk: + return stream.write(s) + else: + length = len(s) + + if length + total_length <= threshold: + stream.write(s) + else: + new_stream = t.cast(t.IO[bytes], TemporaryFile("wb+")) + new_stream.write(stream.getvalue()) # type: ignore + new_stream.write(s) + stream = new_stream + on_disk = True + + total_length += length + return length + + else: + write_binary = stream.write + + encoder = MultipartEncoder(boundary.encode()) + write_binary(encoder.send_event(Preamble(data=b""))) + for key, value in _iter_data(data): + reader = getattr(value, "read", None) + if reader is not None: + filename = getattr(value, "filename", getattr(value, "name", None)) + content_type = getattr(value, "content_type", None) + if content_type is None: + content_type = ( + filename + and mimetypes.guess_type(filename)[0] + or "application/octet-stream" + ) + headers = Headers([("Content-Type", content_type)]) + if filename is None: + write_binary(encoder.send_event(Field(name=key, headers=headers))) + else: + write_binary( + encoder.send_event( + File(name=key, filename=filename, headers=headers) + ) + ) + while True: + chunk = reader(16384) + + if not chunk: + break + + write_binary(encoder.send_event(Data(data=chunk, more_data=True))) + else: + if not isinstance(value, str): + value = str(value) + write_binary(encoder.send_event(Field(name=key, headers=Headers()))) + write_binary( + encoder.send_event(Data(data=value.encode(charset), more_data=False)) + ) + + write_binary(encoder.send_event(Epilogue(data=b""))) + + length = stream.tell() + stream.seek(0) + return stream, length, boundary + + +def encode_multipart( + values: t.Mapping[str, t.Any], + boundary: t.Optional[str] = None, + charset: str = "utf-8", +) -> t.Tuple[str, bytes]: + """Like `stream_encode_multipart` but returns a tuple in the form + (``boundary``, ``data``) where data is bytes. + """ + stream, length, boundary = stream_encode_multipart( + values, use_tempfile=False, boundary=boundary, charset=charset + ) + return boundary, stream.read() + + +class _TestCookieHeaders: + """A headers adapter for cookielib""" + + def __init__(self, headers: t.Union[Headers, t.List[t.Tuple[str, str]]]) -> None: + self.headers = headers + + def getheaders(self, name: str) -> t.Iterable[str]: + headers = [] + name = name.lower() + for k, v in self.headers: + if k.lower() == name: + headers.append(v) + return headers + + def get_all( + self, name: str, default: t.Optional[t.Iterable[str]] = None + ) -> t.Iterable[str]: + headers = self.getheaders(name) + + if not headers: + return default # type: ignore + + return headers + + +class _TestCookieResponse: + """Something that looks like a httplib.HTTPResponse, but is actually just an + adapter for our test responses to make them available for cookielib. + """ + + def __init__(self, headers: t.Union[Headers, t.List[t.Tuple[str, str]]]) -> None: + self.headers = _TestCookieHeaders(headers) + + def info(self) -> _TestCookieHeaders: + return self.headers + + +class _TestCookieJar(CookieJar): + """A cookielib.CookieJar modified to inject and read cookie headers from + and to wsgi environments, and wsgi application responses. + """ + + def inject_wsgi(self, environ: "WSGIEnvironment") -> None: + """Inject the cookies as client headers into the server's wsgi + environment. + """ + cvals = [f"{c.name}={c.value}" for c in self] + + if cvals: + environ["HTTP_COOKIE"] = "; ".join(cvals) + else: + environ.pop("HTTP_COOKIE", None) + + def extract_wsgi( + self, + environ: "WSGIEnvironment", + headers: t.Union[Headers, t.List[t.Tuple[str, str]]], + ) -> None: + """Extract the server's set-cookie headers as cookies into the + cookie jar. + """ + self.extract_cookies( + _TestCookieResponse(headers), # type: ignore + _UrllibRequest(get_current_url(environ)), + ) + + +def _iter_data(data: t.Mapping[str, t.Any]) -> t.Iterator[t.Tuple[str, t.Any]]: + """Iterate over a mapping that might have a list of values, yielding + all key, value pairs. Almost like iter_multi_items but only allows + lists, not tuples, of values so tuples can be used for files. + """ + if isinstance(data, MultiDict): + yield from data.items(multi=True) + else: + for key, value in data.items(): + if isinstance(value, list): + for v in value: + yield key, v + else: + yield key, value + + +_TAnyMultiDict = t.TypeVar("_TAnyMultiDict", bound=MultiDict) + + +class EnvironBuilder: + """This class can be used to conveniently create a WSGI environment + for testing purposes. It can be used to quickly create WSGI environments + or request objects from arbitrary data. + + The signature of this class is also used in some other places as of + Werkzeug 0.5 (:func:`create_environ`, :meth:`Response.from_values`, + :meth:`Client.open`). Because of this most of the functionality is + available through the constructor alone. + + Files and regular form data can be manipulated independently of each + other with the :attr:`form` and :attr:`files` attributes, but are + passed with the same argument to the constructor: `data`. + + `data` can be any of these values: + + - a `str` or `bytes` object: The object is converted into an + :attr:`input_stream`, the :attr:`content_length` is set and you have to + provide a :attr:`content_type`. + - a `dict` or :class:`MultiDict`: The keys have to be strings. The values + have to be either any of the following objects, or a list of any of the + following objects: + + - a :class:`file`-like object: These are converted into + :class:`FileStorage` objects automatically. + - a `tuple`: The :meth:`~FileMultiDict.add_file` method is called + with the key and the unpacked `tuple` items as positional + arguments. + - a `str`: The string is set as form data for the associated key. + - a file-like object: The object content is loaded in memory and then + handled like a regular `str` or a `bytes`. + + :param path: the path of the request. In the WSGI environment this will + end up as `PATH_INFO`. If the `query_string` is not defined + and there is a question mark in the `path` everything after + it is used as query string. + :param base_url: the base URL is a URL that is used to extract the WSGI + URL scheme, host (server name + server port) and the + script root (`SCRIPT_NAME`). + :param query_string: an optional string or dict with URL parameters. + :param method: the HTTP method to use, defaults to `GET`. + :param input_stream: an optional input stream. Do not specify this and + `data`. As soon as an input stream is set you can't + modify :attr:`args` and :attr:`files` unless you + set the :attr:`input_stream` to `None` again. + :param content_type: The content type for the request. As of 0.5 you + don't have to provide this when specifying files + and form data via `data`. + :param content_length: The content length for the request. You don't + have to specify this when providing data via + `data`. + :param errors_stream: an optional error stream that is used for + `wsgi.errors`. Defaults to :data:`stderr`. + :param multithread: controls `wsgi.multithread`. Defaults to `False`. + :param multiprocess: controls `wsgi.multiprocess`. Defaults to `False`. + :param run_once: controls `wsgi.run_once`. Defaults to `False`. + :param headers: an optional list or :class:`Headers` object of headers. + :param data: a string or dict of form data or a file-object. + See explanation above. + :param json: An object to be serialized and assigned to ``data``. + Defaults the content type to ``"application/json"``. + Serialized with the function assigned to :attr:`json_dumps`. + :param environ_base: an optional dict of environment defaults. + :param environ_overrides: an optional dict of environment overrides. + :param charset: the charset used to encode string data. + :param auth: An authorization object to use for the + ``Authorization`` header value. A ``(username, password)`` tuple + is a shortcut for ``Basic`` authorization. + + .. versionchanged:: 2.1 + ``CONTENT_TYPE`` and ``CONTENT_LENGTH`` are not duplicated as + header keys in the environ. + + .. versionchanged:: 2.0 + ``REQUEST_URI`` and ``RAW_URI`` is the full raw URI including + the query string, not only the path. + + .. versionchanged:: 2.0 + The default :attr:`request_class` is ``Request`` instead of + ``BaseRequest``. + + .. versionadded:: 2.0 + Added the ``auth`` parameter. + + .. versionadded:: 0.15 + The ``json`` param and :meth:`json_dumps` method. + + .. versionadded:: 0.15 + The environ has keys ``REQUEST_URI`` and ``RAW_URI`` containing + the path before percent-decoding. This is not part of the WSGI + PEP, but many WSGI servers include it. + + .. versionchanged:: 0.6 + ``path`` and ``base_url`` can now be unicode strings that are + encoded with :func:`iri_to_uri`. + """ + + #: the server protocol to use. defaults to HTTP/1.1 + server_protocol = "HTTP/1.1" + + #: the wsgi version to use. defaults to (1, 0) + wsgi_version = (1, 0) + + #: The default request class used by :meth:`get_request`. + request_class = Request + + import json + + #: The serialization function used when ``json`` is passed. + json_dumps = staticmethod(json.dumps) + del json + + _args: t.Optional[MultiDict] + _query_string: t.Optional[str] + _input_stream: t.Optional[t.IO[bytes]] + _form: t.Optional[MultiDict] + _files: t.Optional[FileMultiDict] + + def __init__( + self, + path: str = "/", + base_url: t.Optional[str] = None, + query_string: t.Optional[t.Union[t.Mapping[str, str], str]] = None, + method: str = "GET", + input_stream: t.Optional[t.IO[bytes]] = None, + content_type: t.Optional[str] = None, + content_length: t.Optional[int] = None, + errors_stream: t.Optional[t.IO[str]] = None, + multithread: bool = False, + multiprocess: bool = False, + run_once: bool = False, + headers: t.Optional[t.Union[Headers, t.Iterable[t.Tuple[str, str]]]] = None, + data: t.Optional[ + t.Union[t.IO[bytes], str, bytes, t.Mapping[str, t.Any]] + ] = None, + environ_base: t.Optional[t.Mapping[str, t.Any]] = None, + environ_overrides: t.Optional[t.Mapping[str, t.Any]] = None, + charset: str = "utf-8", + mimetype: t.Optional[str] = None, + json: t.Optional[t.Mapping[str, t.Any]] = None, + auth: t.Optional[t.Union[Authorization, t.Tuple[str, str]]] = None, + ) -> None: + path_s = _make_encode_wrapper(path) + if query_string is not None and path_s("?") in path: + raise ValueError("Query string is defined in the path and as an argument") + request_uri = url_parse(path) + if query_string is None and path_s("?") in path: + query_string = request_uri.query + self.charset = charset + self.path = iri_to_uri(request_uri.path) + self.request_uri = path + if base_url is not None: + base_url = url_fix(iri_to_uri(base_url, charset), charset) + self.base_url = base_url # type: ignore + if isinstance(query_string, (bytes, str)): + self.query_string = query_string + else: + if query_string is None: + query_string = MultiDict() + elif not isinstance(query_string, MultiDict): + query_string = MultiDict(query_string) + self.args = query_string + self.method = method + if headers is None: + headers = Headers() + elif not isinstance(headers, Headers): + headers = Headers(headers) + self.headers = headers + if content_type is not None: + self.content_type = content_type + if errors_stream is None: + errors_stream = sys.stderr + self.errors_stream = errors_stream + self.multithread = multithread + self.multiprocess = multiprocess + self.run_once = run_once + self.environ_base = environ_base + self.environ_overrides = environ_overrides + self.input_stream = input_stream + self.content_length = content_length + self.closed = False + + if auth is not None: + if isinstance(auth, tuple): + auth = Authorization( + "basic", {"username": auth[0], "password": auth[1]} + ) + + self.headers.set("Authorization", auth.to_header()) + + if json is not None: + if data is not None: + raise TypeError("can't provide both json and data") + + data = self.json_dumps(json) + + if self.content_type is None: + self.content_type = "application/json" + + if data: + if input_stream is not None: + raise TypeError("can't provide input stream and data") + if hasattr(data, "read"): + data = data.read() # type: ignore + if isinstance(data, str): + data = data.encode(self.charset) + if isinstance(data, bytes): + self.input_stream = BytesIO(data) + if self.content_length is None: + self.content_length = len(data) + else: + for key, value in _iter_data(data): # type: ignore + if isinstance(value, (tuple, dict)) or hasattr(value, "read"): + self._add_file_from_data(key, value) + else: + self.form.setlistdefault(key).append(value) + + if mimetype is not None: + self.mimetype = mimetype + + @classmethod + def from_environ( + cls, environ: "WSGIEnvironment", **kwargs: t.Any + ) -> "EnvironBuilder": + """Turn an environ dict back into a builder. Any extra kwargs + override the args extracted from the environ. + + .. versionchanged:: 2.0 + Path and query values are passed through the WSGI decoding + dance to avoid double encoding. + + .. versionadded:: 0.15 + """ + headers = Headers(EnvironHeaders(environ)) + out = { + "path": _wsgi_decoding_dance(environ["PATH_INFO"]), + "base_url": cls._make_base_url( + environ["wsgi.url_scheme"], + headers.pop("Host"), + _wsgi_decoding_dance(environ["SCRIPT_NAME"]), + ), + "query_string": _wsgi_decoding_dance(environ["QUERY_STRING"]), + "method": environ["REQUEST_METHOD"], + "input_stream": environ["wsgi.input"], + "content_type": headers.pop("Content-Type", None), + "content_length": headers.pop("Content-Length", None), + "errors_stream": environ["wsgi.errors"], + "multithread": environ["wsgi.multithread"], + "multiprocess": environ["wsgi.multiprocess"], + "run_once": environ["wsgi.run_once"], + "headers": headers, + } + out.update(kwargs) + return cls(**out) + + def _add_file_from_data( + self, + key: str, + value: t.Union[ + t.IO[bytes], t.Tuple[t.IO[bytes], str], t.Tuple[t.IO[bytes], str, str] + ], + ) -> None: + """Called in the EnvironBuilder to add files from the data dict.""" + if isinstance(value, tuple): + self.files.add_file(key, *value) + else: + self.files.add_file(key, value) + + @staticmethod + def _make_base_url(scheme: str, host: str, script_root: str) -> str: + return url_unparse((scheme, host, script_root, "", "")).rstrip("/") + "/" + + @property + def base_url(self) -> str: + """The base URL is used to extract the URL scheme, host name, + port, and root path. + """ + return self._make_base_url(self.url_scheme, self.host, self.script_root) + + @base_url.setter + def base_url(self, value: t.Optional[str]) -> None: + if value is None: + scheme = "http" + netloc = "localhost" + script_root = "" + else: + scheme, netloc, script_root, qs, anchor = url_parse(value) + if qs or anchor: + raise ValueError("base url must not contain a query string or fragment") + self.script_root = script_root.rstrip("/") + self.host = netloc + self.url_scheme = scheme + + @property + def content_type(self) -> t.Optional[str]: + """The content type for the request. Reflected from and to + the :attr:`headers`. Do not set if you set :attr:`files` or + :attr:`form` for auto detection. + """ + ct = self.headers.get("Content-Type") + if ct is None and not self._input_stream: + if self._files: + return "multipart/form-data" + if self._form: + return "application/x-www-form-urlencoded" + return None + return ct + + @content_type.setter + def content_type(self, value: t.Optional[str]) -> None: + if value is None: + self.headers.pop("Content-Type", None) + else: + self.headers["Content-Type"] = value + + @property + def mimetype(self) -> t.Optional[str]: + """The mimetype (content type without charset etc.) + + .. versionadded:: 0.14 + """ + ct = self.content_type + return ct.split(";")[0].strip() if ct else None + + @mimetype.setter + def mimetype(self, value: str) -> None: + self.content_type = get_content_type(value, self.charset) + + @property + def mimetype_params(self) -> t.Mapping[str, str]: + """The mimetype parameters as dict. For example if the + content type is ``text/html; charset=utf-8`` the params would be + ``{'charset': 'utf-8'}``. + + .. versionadded:: 0.14 + """ + + def on_update(d: CallbackDict) -> None: + self.headers["Content-Type"] = dump_options_header(self.mimetype, d) + + d = parse_options_header(self.headers.get("content-type", ""))[1] + return CallbackDict(d, on_update) + + @property + def content_length(self) -> t.Optional[int]: + """The content length as integer. Reflected from and to the + :attr:`headers`. Do not set if you set :attr:`files` or + :attr:`form` for auto detection. + """ + return self.headers.get("Content-Length", type=int) + + @content_length.setter + def content_length(self, value: t.Optional[int]) -> None: + if value is None: + self.headers.pop("Content-Length", None) + else: + self.headers["Content-Length"] = str(value) + + def _get_form(self, name: str, storage: t.Type[_TAnyMultiDict]) -> _TAnyMultiDict: + """Common behavior for getting the :attr:`form` and + :attr:`files` properties. + + :param name: Name of the internal cached attribute. + :param storage: Storage class used for the data. + """ + if self.input_stream is not None: + raise AttributeError("an input stream is defined") + + rv = getattr(self, name) + + if rv is None: + rv = storage() + setattr(self, name, rv) + + return rv # type: ignore + + def _set_form(self, name: str, value: MultiDict) -> None: + """Common behavior for setting the :attr:`form` and + :attr:`files` properties. + + :param name: Name of the internal cached attribute. + :param value: Value to assign to the attribute. + """ + self._input_stream = None + setattr(self, name, value) + + @property + def form(self) -> MultiDict: + """A :class:`MultiDict` of form values.""" + return self._get_form("_form", MultiDict) + + @form.setter + def form(self, value: MultiDict) -> None: + self._set_form("_form", value) + + @property + def files(self) -> FileMultiDict: + """A :class:`FileMultiDict` of uploaded files. Use + :meth:`~FileMultiDict.add_file` to add new files. + """ + return self._get_form("_files", FileMultiDict) + + @files.setter + def files(self, value: FileMultiDict) -> None: + self._set_form("_files", value) + + @property + def input_stream(self) -> t.Optional[t.IO[bytes]]: + """An optional input stream. This is mutually exclusive with + setting :attr:`form` and :attr:`files`, setting it will clear + those. Do not provide this if the method is not ``POST`` or + another method that has a body. + """ + return self._input_stream + + @input_stream.setter + def input_stream(self, value: t.Optional[t.IO[bytes]]) -> None: + self._input_stream = value + self._form = None + self._files = None + + @property + def query_string(self) -> str: + """The query string. If you set this to a string + :attr:`args` will no longer be available. + """ + if self._query_string is None: + if self._args is not None: + return url_encode(self._args, charset=self.charset) + return "" + return self._query_string + + @query_string.setter + def query_string(self, value: t.Optional[str]) -> None: + self._query_string = value + self._args = None + + @property + def args(self) -> MultiDict: + """The URL arguments as :class:`MultiDict`.""" + if self._query_string is not None: + raise AttributeError("a query string is defined") + if self._args is None: + self._args = MultiDict() + return self._args + + @args.setter + def args(self, value: t.Optional[MultiDict]) -> None: + self._query_string = None + self._args = value + + @property + def server_name(self) -> str: + """The server name (read-only, use :attr:`host` to set)""" + return self.host.split(":", 1)[0] + + @property + def server_port(self) -> int: + """The server port as integer (read-only, use :attr:`host` to set)""" + pieces = self.host.split(":", 1) + + if len(pieces) == 2: + try: + return int(pieces[1]) + except ValueError: + pass + + if self.url_scheme == "https": + return 443 + return 80 + + def __del__(self) -> None: + try: + self.close() + except Exception: + pass + + def close(self) -> None: + """Closes all files. If you put real :class:`file` objects into the + :attr:`files` dict you can call this method to automatically close + them all in one go. + """ + if self.closed: + return + try: + files = self.files.values() + except AttributeError: + files = () # type: ignore + for f in files: + try: + f.close() + except Exception: + pass + self.closed = True + + def get_environ(self) -> "WSGIEnvironment": + """Return the built environ. + + .. versionchanged:: 0.15 + The content type and length headers are set based on + input stream detection. Previously this only set the WSGI + keys. + """ + input_stream = self.input_stream + content_length = self.content_length + + mimetype = self.mimetype + content_type = self.content_type + + if input_stream is not None: + start_pos = input_stream.tell() + input_stream.seek(0, 2) + end_pos = input_stream.tell() + input_stream.seek(start_pos) + content_length = end_pos - start_pos + elif mimetype == "multipart/form-data": + input_stream, content_length, boundary = stream_encode_multipart( + CombinedMultiDict([self.form, self.files]), charset=self.charset + ) + content_type = f'{mimetype}; boundary="{boundary}"' + elif mimetype == "application/x-www-form-urlencoded": + form_encoded = url_encode(self.form, charset=self.charset).encode("ascii") + content_length = len(form_encoded) + input_stream = BytesIO(form_encoded) + else: + input_stream = BytesIO() + + result: "WSGIEnvironment" = {} + if self.environ_base: + result.update(self.environ_base) + + def _path_encode(x: str) -> str: + return _wsgi_encoding_dance(url_unquote(x, self.charset), self.charset) + + raw_uri = _wsgi_encoding_dance(self.request_uri, self.charset) + result.update( + { + "REQUEST_METHOD": self.method, + "SCRIPT_NAME": _path_encode(self.script_root), + "PATH_INFO": _path_encode(self.path), + "QUERY_STRING": _wsgi_encoding_dance(self.query_string, self.charset), + # Non-standard, added by mod_wsgi, uWSGI + "REQUEST_URI": raw_uri, + # Non-standard, added by gunicorn + "RAW_URI": raw_uri, + "SERVER_NAME": self.server_name, + "SERVER_PORT": str(self.server_port), + "HTTP_HOST": self.host, + "SERVER_PROTOCOL": self.server_protocol, + "wsgi.version": self.wsgi_version, + "wsgi.url_scheme": self.url_scheme, + "wsgi.input": input_stream, + "wsgi.errors": self.errors_stream, + "wsgi.multithread": self.multithread, + "wsgi.multiprocess": self.multiprocess, + "wsgi.run_once": self.run_once, + } + ) + + headers = self.headers.copy() + # Don't send these as headers, they're part of the environ. + headers.remove("Content-Type") + headers.remove("Content-Length") + + if content_type is not None: + result["CONTENT_TYPE"] = content_type + + if content_length is not None: + result["CONTENT_LENGTH"] = str(content_length) + + combined_headers = defaultdict(list) + + for key, value in headers.to_wsgi_list(): + combined_headers[f"HTTP_{key.upper().replace('-', '_')}"].append(value) + + for key, values in combined_headers.items(): + result[key] = ", ".join(values) + + if self.environ_overrides: + result.update(self.environ_overrides) + + return result + + def get_request(self, cls: t.Optional[t.Type[Request]] = None) -> Request: + """Returns a request with the data. If the request class is not + specified :attr:`request_class` is used. + + :param cls: The request wrapper to use. + """ + if cls is None: + cls = self.request_class + + return cls(self.get_environ()) + + +class ClientRedirectError(Exception): + """If a redirect loop is detected when using follow_redirects=True with + the :cls:`Client`, then this exception is raised. + """ + + +class Client: + """This class allows you to send requests to a wrapped application. + + The use_cookies parameter indicates whether cookies should be stored and + sent for subsequent requests. This is True by default, but passing False + will disable this behaviour. + + If you want to request some subdomain of your application you may set + `allow_subdomain_redirects` to `True` as if not no external redirects + are allowed. + + .. versionchanged:: 2.1 + Removed deprecated behavior of treating the response as a + tuple. All data is available as properties on the returned + response object. + + .. versionchanged:: 2.0 + ``response_wrapper`` is always a subclass of + :class:``TestResponse``. + + .. versionchanged:: 0.5 + Added the ``use_cookies`` parameter. + """ + + def __init__( + self, + application: "WSGIApplication", + response_wrapper: t.Optional[t.Type["Response"]] = None, + use_cookies: bool = True, + allow_subdomain_redirects: bool = False, + ) -> None: + self.application = application + + if response_wrapper in {None, Response}: + response_wrapper = TestResponse + elif not isinstance(response_wrapper, TestResponse): + response_wrapper = type( + "WrapperTestResponse", + (TestResponse, response_wrapper), # type: ignore + {}, + ) + + self.response_wrapper = t.cast(t.Type["TestResponse"], response_wrapper) + + if use_cookies: + self.cookie_jar: t.Optional[_TestCookieJar] = _TestCookieJar() + else: + self.cookie_jar = None + + self.allow_subdomain_redirects = allow_subdomain_redirects + + def set_cookie( + self, + server_name: str, + key: str, + value: str = "", + max_age: t.Optional[t.Union[timedelta, int]] = None, + expires: t.Optional[t.Union[str, datetime, int, float]] = None, + path: str = "/", + domain: t.Optional[str] = None, + secure: bool = False, + httponly: bool = False, + samesite: t.Optional[str] = None, + charset: str = "utf-8", + ) -> None: + """Sets a cookie in the client's cookie jar. The server name + is required and has to match the one that is also passed to + the open call. + """ + assert self.cookie_jar is not None, "cookies disabled" + header = dump_cookie( + key, + value, + max_age, + expires, + path, + domain, + secure, + httponly, + charset, + samesite=samesite, + ) + environ = create_environ(path, base_url=f"http://{server_name}") + headers = [("Set-Cookie", header)] + self.cookie_jar.extract_wsgi(environ, headers) + + def delete_cookie( + self, + server_name: str, + key: str, + path: str = "/", + domain: t.Optional[str] = None, + secure: bool = False, + httponly: bool = False, + samesite: t.Optional[str] = None, + ) -> None: + """Deletes a cookie in the test client.""" + self.set_cookie( + server_name, + key, + expires=0, + max_age=0, + path=path, + domain=domain, + secure=secure, + httponly=httponly, + samesite=samesite, + ) + + def run_wsgi_app( + self, environ: "WSGIEnvironment", buffered: bool = False + ) -> t.Tuple[t.Iterable[bytes], str, Headers]: + """Runs the wrapped WSGI app with the given environment. + + :meta private: + """ + if self.cookie_jar is not None: + self.cookie_jar.inject_wsgi(environ) + + rv = run_wsgi_app(self.application, environ, buffered=buffered) + + if self.cookie_jar is not None: + self.cookie_jar.extract_wsgi(environ, rv[2]) + + return rv + + def resolve_redirect( + self, response: "TestResponse", buffered: bool = False + ) -> "TestResponse": + """Perform a new request to the location given by the redirect + response to the previous request. + + :meta private: + """ + scheme, netloc, path, qs, anchor = url_parse(response.location) + builder = EnvironBuilder.from_environ( + response.request.environ, path=path, query_string=qs + ) + + to_name_parts = netloc.split(":", 1)[0].split(".") + from_name_parts = builder.server_name.split(".") + + if to_name_parts != [""]: + # The new location has a host, use it for the base URL. + builder.url_scheme = scheme + builder.host = netloc + else: + # A local redirect with autocorrect_location_header=False + # doesn't have a host, so use the request's host. + to_name_parts = from_name_parts + + # Explain why a redirect to a different server name won't be followed. + if to_name_parts != from_name_parts: + if to_name_parts[-len(from_name_parts) :] == from_name_parts: + if not self.allow_subdomain_redirects: + raise RuntimeError("Following subdomain redirects is not enabled.") + else: + raise RuntimeError("Following external redirects is not supported.") + + path_parts = path.split("/") + root_parts = builder.script_root.split("/") + + if path_parts[: len(root_parts)] == root_parts: + # Strip the script root from the path. + builder.path = path[len(builder.script_root) :] + else: + # The new location is not under the script root, so use the + # whole path and clear the previous root. + builder.path = path + builder.script_root = "" + + # Only 307 and 308 preserve all of the original request. + if response.status_code not in {307, 308}: + # HEAD is preserved, everything else becomes GET. + if builder.method != "HEAD": + builder.method = "GET" + + # Clear the body and the headers that describe it. + + if builder.input_stream is not None: + builder.input_stream.close() + builder.input_stream = None + + builder.content_type = None + builder.content_length = None + builder.headers.pop("Transfer-Encoding", None) + + return self.open(builder, buffered=buffered) + + def open( + self, + *args: t.Any, + buffered: bool = False, + follow_redirects: bool = False, + **kwargs: t.Any, + ) -> "TestResponse": + """Generate an environ dict from the given arguments, make a + request to the application using it, and return the response. + + :param args: Passed to :class:`EnvironBuilder` to create the + environ for the request. If a single arg is passed, it can + be an existing :class:`EnvironBuilder` or an environ dict. + :param buffered: Convert the iterator returned by the app into + a list. If the iterator has a ``close()`` method, it is + called automatically. + :param follow_redirects: Make additional requests to follow HTTP + redirects until a non-redirect status is returned. + :attr:`TestResponse.history` lists the intermediate + responses. + + .. versionchanged:: 2.1 + Removed the ``as_tuple`` parameter. + + .. versionchanged:: 2.0 + ``as_tuple`` is deprecated and will be removed in Werkzeug + 2.1. Use :attr:`TestResponse.request` and + ``request.environ`` instead. + + .. versionchanged:: 2.0 + The request input stream is closed when calling + ``response.close()``. Input streams for redirects are + automatically closed. + + .. versionchanged:: 0.5 + If a dict is provided as file in the dict for the ``data`` + parameter the content type has to be called ``content_type`` + instead of ``mimetype``. This change was made for + consistency with :class:`werkzeug.FileWrapper`. + + .. versionchanged:: 0.5 + Added the ``follow_redirects`` parameter. + """ + request: t.Optional["Request"] = None + + if not kwargs and len(args) == 1: + arg = args[0] + + if isinstance(arg, EnvironBuilder): + request = arg.get_request() + elif isinstance(arg, dict): + request = EnvironBuilder.from_environ(arg).get_request() + elif isinstance(arg, Request): + request = arg + + if request is None: + builder = EnvironBuilder(*args, **kwargs) + + try: + request = builder.get_request() + finally: + builder.close() + + response = self.run_wsgi_app(request.environ, buffered=buffered) + response = self.response_wrapper(*response, request=request) + + redirects = set() + history: t.List["TestResponse"] = [] + + if not follow_redirects: + return response + + while response.status_code in { + 301, + 302, + 303, + 305, + 307, + 308, + }: + # Exhaust intermediate response bodies to ensure middleware + # that returns an iterator runs any cleanup code. + if not buffered: + response.make_sequence() + response.close() + + new_redirect_entry = (response.location, response.status_code) + + if new_redirect_entry in redirects: + raise ClientRedirectError( + f"Loop detected: A {response.status_code} redirect" + f" to {response.location} was already made." + ) + + redirects.add(new_redirect_entry) + response.history = tuple(history) + history.append(response) + response = self.resolve_redirect(response, buffered=buffered) + else: + # This is the final request after redirects. + response.history = tuple(history) + # Close the input stream when closing the response, in case + # the input is an open temporary file. + response.call_on_close(request.input_stream.close) + return response + + def get(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``GET``.""" + kw["method"] = "GET" + return self.open(*args, **kw) + + def post(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``POST``.""" + kw["method"] = "POST" + return self.open(*args, **kw) + + def put(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``PUT``.""" + kw["method"] = "PUT" + return self.open(*args, **kw) + + def delete(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``DELETE``.""" + kw["method"] = "DELETE" + return self.open(*args, **kw) + + def patch(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``PATCH``.""" + kw["method"] = "PATCH" + return self.open(*args, **kw) + + def options(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``OPTIONS``.""" + kw["method"] = "OPTIONS" + return self.open(*args, **kw) + + def head(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``HEAD``.""" + kw["method"] = "HEAD" + return self.open(*args, **kw) + + def trace(self, *args: t.Any, **kw: t.Any) -> "TestResponse": + """Call :meth:`open` with ``method`` set to ``TRACE``.""" + kw["method"] = "TRACE" + return self.open(*args, **kw) + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.application!r}>" + + +def create_environ(*args: t.Any, **kwargs: t.Any) -> "WSGIEnvironment": + """Create a new WSGI environ dict based on the values passed. The first + parameter should be the path of the request which defaults to '/'. The + second one can either be an absolute path (in that case the host is + localhost:80) or a full path to the request with scheme, netloc port and + the path to the script. + + This accepts the same arguments as the :class:`EnvironBuilder` + constructor. + + .. versionchanged:: 0.5 + This function is now a thin wrapper over :class:`EnvironBuilder` which + was added in 0.5. The `headers`, `environ_base`, `environ_overrides` + and `charset` parameters were added. + """ + builder = EnvironBuilder(*args, **kwargs) + + try: + return builder.get_environ() + finally: + builder.close() + + +def run_wsgi_app( + app: "WSGIApplication", environ: "WSGIEnvironment", buffered: bool = False +) -> t.Tuple[t.Iterable[bytes], str, Headers]: + """Return a tuple in the form (app_iter, status, headers) of the + application output. This works best if you pass it an application that + returns an iterator all the time. + + Sometimes applications may use the `write()` callable returned + by the `start_response` function. This tries to resolve such edge + cases automatically. But if you don't get the expected output you + should set `buffered` to `True` which enforces buffering. + + If passed an invalid WSGI application the behavior of this function is + undefined. Never pass non-conforming WSGI applications to this function. + + :param app: the application to execute. + :param buffered: set to `True` to enforce buffering. + :return: tuple in the form ``(app_iter, status, headers)`` + """ + # Copy environ to ensure any mutations by the app (ProxyFix, for + # example) don't affect subsequent requests (such as redirects). + environ = _get_environ(environ).copy() + status: str + response: t.Optional[t.Tuple[str, t.List[t.Tuple[str, str]]]] = None + buffer: t.List[bytes] = [] + + def start_response(status, headers, exc_info=None): # type: ignore + nonlocal response + + if exc_info: + try: + raise exc_info[1].with_traceback(exc_info[2]) + finally: + exc_info = None + + response = (status, headers) + return buffer.append + + app_rv = app(environ, start_response) + close_func = getattr(app_rv, "close", None) + app_iter: t.Iterable[bytes] = iter(app_rv) + + # when buffering we emit the close call early and convert the + # application iterator into a regular list + if buffered: + try: + app_iter = list(app_iter) + finally: + if close_func is not None: + close_func() + + # otherwise we iterate the application iter until we have a response, chain + # the already received data with the already collected data and wrap it in + # a new `ClosingIterator` if we need to restore a `close` callable from the + # original return value. + else: + for item in app_iter: + buffer.append(item) + + if response is not None: + break + + if buffer: + app_iter = chain(buffer, app_iter) + + if close_func is not None and app_iter is not app_rv: + app_iter = ClosingIterator(app_iter, close_func) + + status, headers = response # type: ignore + return app_iter, status, Headers(headers) + + +class TestResponse(Response): + """:class:`~werkzeug.wrappers.Response` subclass that provides extra + information about requests made with the test :class:`Client`. + + Test client requests will always return an instance of this class. + If a custom response class is passed to the client, it is + subclassed along with this to support test information. + + If the test request included large files, or if the application is + serving a file, call :meth:`close` to close any open files and + prevent Python showing a ``ResourceWarning``. + + .. versionchanged:: 2.2 + Set the ``default_mimetype`` to None to prevent a mimetype being + assumed if missing. + + .. versionchanged:: 2.1 + Removed deprecated behavior for treating the response instance + as a tuple. + + .. versionadded:: 2.0 + Test client methods always return instances of this class. + """ + + default_mimetype = None + # Don't assume a mimetype, instead use whatever the response provides + + request: Request + """A request object with the environ used to make the request that + resulted in this response. + """ + + history: t.Tuple["TestResponse", ...] + """A list of intermediate responses. Populated when the test request + is made with ``follow_redirects`` enabled. + """ + + # Tell Pytest to ignore this, it's not a test class. + __test__ = False + + def __init__( + self, + response: t.Iterable[bytes], + status: str, + headers: Headers, + request: Request, + history: t.Tuple["TestResponse"] = (), # type: ignore + **kwargs: t.Any, + ) -> None: + super().__init__(response, status, headers, **kwargs) + self.request = request + self.history = history + self._compat_tuple = response, status, headers + + @cached_property + def text(self) -> str: + """The response data as text. A shortcut for + ``response.get_data(as_text=True)``. + + .. versionadded:: 2.1 + """ + return self.get_data(as_text=True) diff --git a/.vcrunch/Lib/site-packages/werkzeug/testapp.py b/.vcrunch/Lib/site-packages/werkzeug/testapp.py new file mode 100644 index 0000000..0d7ffbb --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/testapp.py @@ -0,0 +1,241 @@ +"""A small application that can be used to test a WSGI server and check +it for WSGI compliance. +""" +import base64 +import os +import sys +import typing as t +from textwrap import wrap + +from markupsafe import escape + +from . import __version__ as _werkzeug_version +from .wrappers.request import Request +from .wrappers.response import Response + +if t.TYPE_CHECKING: + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIEnvironment + + +logo = Response( + base64.b64decode( + """ +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 +=""" + ), + mimetype="image/png", +) + + +TEMPLATE = """\ + + +WSGI Information + +

    + +

    WSGI Information

    +

    + This page displays all available information about the WSGI server and + the underlying Python interpreter. +

    Python Interpreter

    + + + + + + +
    Python Version + %(python_version)s +
    Platform + %(platform)s [%(os)s] +
    API Version + %(api_version)s +
    Byteorder + %(byteorder)s +
    Werkzeug Version + %(werkzeug_version)s +
    +

    WSGI Environment

    + %(wsgi_env)s
    +

    Installed Eggs

    +

    + The following python packages were installed on the system as + Python eggs: +

      %(python_eggs)s
    +

    System Path

    +

    + The following paths are the current contents of the load path. The + following entries are looked up for Python packages. Note that not + all items in this path are folders. Gray and underlined items are + entries pointing to invalid resources or used by custom import hooks + such as the zip importer. +

    + Items with a bright background were expanded for display from a relative + path. If you encounter such paths in the output you might want to check + your setup as relative paths are usually problematic in multithreaded + environments. +

      %(sys_path)s
    +
    +""" + + +def iter_sys_path() -> t.Iterator[t.Tuple[str, bool, bool]]: + if os.name == "posix": + + def strip(x: str) -> str: + prefix = os.path.expanduser("~") + if x.startswith(prefix): + x = f"~{x[len(prefix) :]}" + return x + + else: + + def strip(x: str) -> str: + return x + + cwd = os.path.abspath(os.getcwd()) + for item in sys.path: + path = os.path.join(cwd, item or os.path.curdir) + yield strip(os.path.normpath(path)), not os.path.isdir(path), path != item + + +def render_testapp(req: Request) -> bytes: + try: + import pkg_resources + except ImportError: + eggs: t.Iterable[t.Any] = () + else: + eggs = sorted( + pkg_resources.working_set, + key=lambda x: x.project_name.lower(), # type: ignore + ) + python_eggs = [] + for egg in eggs: + try: + version = egg.version + except (ValueError, AttributeError): + version = "unknown" + python_eggs.append( + f"
  • {escape(egg.project_name)} [{escape(version)}]" + ) + + wsgi_env = [] + sorted_environ = sorted(req.environ.items(), key=lambda x: repr(x[0]).lower()) + for key, value in sorted_environ: + value = "".join(wrap(str(escape(repr(value))))) + wsgi_env.append(f"{escape(key)}{value}") + + sys_path = [] + for item, virtual, expanded in iter_sys_path(): + class_ = [] + if virtual: + class_.append("virtual") + if expanded: + class_.append("exp") + class_ = f' class="{" ".join(class_)}"' if class_ else "" + sys_path.append(f"{escape(item)}") + + return ( + TEMPLATE + % { + "python_version": "
    ".join(escape(sys.version).splitlines()), + "platform": escape(sys.platform), + "os": escape(os.name), + "api_version": sys.api_version, + "byteorder": sys.byteorder, + "werkzeug_version": _werkzeug_version, + "python_eggs": "\n".join(python_eggs), + "wsgi_env": "\n".join(wsgi_env), + "sys_path": "\n".join(sys_path), + } + ).encode("utf-8") + + +def test_app( + environ: "WSGIEnvironment", start_response: "StartResponse" +) -> t.Iterable[bytes]: + """Simple test application that dumps the environment. You can use + it to check if Werkzeug is working properly: + + .. sourcecode:: pycon + + >>> from werkzeug.serving import run_simple + >>> from werkzeug.testapp import test_app + >>> run_simple('localhost', 3000, test_app) + * Running on http://localhost:3000/ + + The application displays important information from the WSGI environment, + the Python interpreter and the installed libraries. + """ + req = Request(environ, populate_request=False) + if req.args.get("resource") == "logo": + response = logo + else: + response = Response(render_testapp(req), mimetype="text/html") + return response(environ, start_response) + + +if __name__ == "__main__": + from .serving import run_simple + + run_simple("localhost", 5000, test_app, use_reloader=True) diff --git a/.vcrunch/Lib/site-packages/werkzeug/urls.py b/.vcrunch/Lib/site-packages/werkzeug/urls.py new file mode 100644 index 0000000..67c08b0 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/urls.py @@ -0,0 +1,1067 @@ +"""Functions for working with URLs. + +Contains implementations of functions from :mod:`urllib.parse` that +handle bytes and strings. +""" +import codecs +import os +import re +import typing as t + +from ._internal import _check_str_tuple +from ._internal import _decode_idna +from ._internal import _encode_idna +from ._internal import _make_encode_wrapper +from ._internal import _to_str + +if t.TYPE_CHECKING: + from . import datastructures as ds + +# A regular expression for what a valid schema looks like +_scheme_re = re.compile(r"^[a-zA-Z0-9+-.]+$") + +# Characters that are safe in any part of an URL. +_always_safe = frozenset( + bytearray( + b"abcdefghijklmnopqrstuvwxyz" + b"ABCDEFGHIJKLMNOPQRSTUVWXYZ" + b"0123456789" + b"-._~" + b"$!'()*+,;" # RFC3986 sub-delims set, not including query string delimiters &= + ) +) + +_hexdigits = "0123456789ABCDEFabcdef" +_hextobyte = { + f"{a}{b}".encode("ascii"): int(f"{a}{b}", 16) + for a in _hexdigits + for b in _hexdigits +} +_bytetohex = [f"%{char:02X}".encode("ascii") for char in range(256)] + + +class _URLTuple(t.NamedTuple): + scheme: str + netloc: str + path: str + query: str + fragment: str + + +class BaseURL(_URLTuple): + """Superclass of :py:class:`URL` and :py:class:`BytesURL`.""" + + __slots__ = () + _at: str + _colon: str + _lbracket: str + _rbracket: str + + def __str__(self) -> str: + return self.to_url() + + def replace(self, **kwargs: t.Any) -> "BaseURL": + """Return an URL with the same values, except for those parameters + given new values by whichever keyword arguments are specified.""" + return self._replace(**kwargs) + + @property + def host(self) -> t.Optional[str]: + """The host part of the URL if available, otherwise `None`. The + host is either the hostname or the IP address mentioned in the + URL. It will not contain the port. + """ + return self._split_host()[0] + + @property + def ascii_host(self) -> t.Optional[str]: + """Works exactly like :attr:`host` but will return a result that + is restricted to ASCII. If it finds a netloc that is not ASCII + it will attempt to idna decode it. This is useful for socket + operations when the URL might include internationalized characters. + """ + rv = self.host + if rv is not None and isinstance(rv, str): + try: + rv = _encode_idna(rv) # type: ignore + except UnicodeError: + rv = rv.encode("ascii", "ignore") # type: ignore + return _to_str(rv, "ascii", "ignore") + + @property + def port(self) -> t.Optional[int]: + """The port in the URL as an integer if it was present, `None` + otherwise. This does not fill in default ports. + """ + try: + rv = int(_to_str(self._split_host()[1])) + if 0 <= rv <= 65535: + return rv + except (ValueError, TypeError): + pass + return None + + @property + def auth(self) -> t.Optional[str]: + """The authentication part in the URL if available, `None` + otherwise. + """ + return self._split_netloc()[0] + + @property + def username(self) -> t.Optional[str]: + """The username if it was part of the URL, `None` otherwise. + This undergoes URL decoding and will always be a string. + """ + rv = self._split_auth()[0] + if rv is not None: + return _url_unquote_legacy(rv) + return None + + @property + def raw_username(self) -> t.Optional[str]: + """The username if it was part of the URL, `None` otherwise. + Unlike :attr:`username` this one is not being decoded. + """ + return self._split_auth()[0] + + @property + def password(self) -> t.Optional[str]: + """The password if it was part of the URL, `None` otherwise. + This undergoes URL decoding and will always be a string. + """ + rv = self._split_auth()[1] + if rv is not None: + return _url_unquote_legacy(rv) + return None + + @property + def raw_password(self) -> t.Optional[str]: + """The password if it was part of the URL, `None` otherwise. + Unlike :attr:`password` this one is not being decoded. + """ + return self._split_auth()[1] + + def decode_query(self, *args: t.Any, **kwargs: t.Any) -> "ds.MultiDict[str, str]": + """Decodes the query part of the URL. Ths is a shortcut for + calling :func:`url_decode` on the query argument. The arguments and + keyword arguments are forwarded to :func:`url_decode` unchanged. + """ + return url_decode(self.query, *args, **kwargs) + + def join(self, *args: t.Any, **kwargs: t.Any) -> "BaseURL": + """Joins this URL with another one. This is just a convenience + function for calling into :meth:`url_join` and then parsing the + return value again. + """ + return url_parse(url_join(self, *args, **kwargs)) + + def to_url(self) -> str: + """Returns a URL string or bytes depending on the type of the + information stored. This is just a convenience function + for calling :meth:`url_unparse` for this URL. + """ + return url_unparse(self) + + def encode_netloc(self) -> str: + """Encodes the netloc part to an ASCII safe URL as bytes.""" + rv = self.ascii_host or "" + if ":" in rv: + rv = f"[{rv}]" + port = self.port + if port is not None: + rv = f"{rv}:{port}" + auth = ":".join( + filter( + None, + [ + url_quote(self.raw_username or "", "utf-8", "strict", "/:%"), + url_quote(self.raw_password or "", "utf-8", "strict", "/:%"), + ], + ) + ) + if auth: + rv = f"{auth}@{rv}" + return rv + + def decode_netloc(self) -> str: + """Decodes the netloc part into a string.""" + rv = _decode_idna(self.host or "") + + if ":" in rv: + rv = f"[{rv}]" + port = self.port + if port is not None: + rv = f"{rv}:{port}" + auth = ":".join( + filter( + None, + [ + _url_unquote_legacy(self.raw_username or "", "/:%@"), + _url_unquote_legacy(self.raw_password or "", "/:%@"), + ], + ) + ) + if auth: + rv = f"{auth}@{rv}" + return rv + + def to_uri_tuple(self) -> "BaseURL": + """Returns a :class:`BytesURL` tuple that holds a URI. This will + encode all the information in the URL properly to ASCII using the + rules a web browser would follow. + + It's usually more interesting to directly call :meth:`iri_to_uri` which + will return a string. + """ + return url_parse(iri_to_uri(self)) + + def to_iri_tuple(self) -> "BaseURL": + """Returns a :class:`URL` tuple that holds a IRI. This will try + to decode as much information as possible in the URL without + losing information similar to how a web browser does it for the + URL bar. + + It's usually more interesting to directly call :meth:`uri_to_iri` which + will return a string. + """ + return url_parse(uri_to_iri(self)) + + def get_file_location( + self, pathformat: t.Optional[str] = None + ) -> t.Tuple[t.Optional[str], t.Optional[str]]: + """Returns a tuple with the location of the file in the form + ``(server, location)``. If the netloc is empty in the URL or + points to localhost, it's represented as ``None``. + + The `pathformat` by default is autodetection but needs to be set + when working with URLs of a specific system. The supported values + are ``'windows'`` when working with Windows or DOS paths and + ``'posix'`` when working with posix paths. + + If the URL does not point to a local file, the server and location + are both represented as ``None``. + + :param pathformat: The expected format of the path component. + Currently ``'windows'`` and ``'posix'`` are + supported. Defaults to ``None`` which is + autodetect. + """ + if self.scheme != "file": + return None, None + + path = url_unquote(self.path) + host = self.netloc or None + + if pathformat is None: + if os.name == "nt": + pathformat = "windows" + else: + pathformat = "posix" + + if pathformat == "windows": + if path[:1] == "/" and path[1:2].isalpha() and path[2:3] in "|:": + path = f"{path[1:2]}:{path[3:]}" + windows_share = path[:3] in ("\\" * 3, "/" * 3) + import ntpath + + path = ntpath.normpath(path) + # Windows shared drives are represented as ``\\host\\directory``. + # That results in a URL like ``file://///host/directory``, and a + # path like ``///host/directory``. We need to special-case this + # because the path contains the hostname. + if windows_share and host is None: + parts = path.lstrip("\\").split("\\", 1) + if len(parts) == 2: + host, path = parts + else: + host = parts[0] + path = "" + elif pathformat == "posix": + import posixpath + + path = posixpath.normpath(path) + else: + raise TypeError(f"Invalid path format {pathformat!r}") + + if host in ("127.0.0.1", "::1", "localhost"): + host = None + + return host, path + + def _split_netloc(self) -> t.Tuple[t.Optional[str], str]: + if self._at in self.netloc: + auth, _, netloc = self.netloc.partition(self._at) + return auth, netloc + return None, self.netloc + + def _split_auth(self) -> t.Tuple[t.Optional[str], t.Optional[str]]: + auth = self._split_netloc()[0] + if not auth: + return None, None + if self._colon not in auth: + return auth, None + + username, _, password = auth.partition(self._colon) + return username, password + + def _split_host(self) -> t.Tuple[t.Optional[str], t.Optional[str]]: + rv = self._split_netloc()[1] + if not rv: + return None, None + + if not rv.startswith(self._lbracket): + if self._colon in rv: + host, _, port = rv.partition(self._colon) + return host, port + return rv, None + + idx = rv.find(self._rbracket) + if idx < 0: + return rv, None + + host = rv[1:idx] + rest = rv[idx + 1 :] + if rest.startswith(self._colon): + return host, rest[1:] + return host, None + + +class URL(BaseURL): + """Represents a parsed URL. This behaves like a regular tuple but + also has some extra attributes that give further insight into the + URL. + """ + + __slots__ = () + _at = "@" + _colon = ":" + _lbracket = "[" + _rbracket = "]" + + def encode(self, charset: str = "utf-8", errors: str = "replace") -> "BytesURL": + """Encodes the URL to a tuple made out of bytes. The charset is + only being used for the path, query and fragment. + """ + return BytesURL( + self.scheme.encode("ascii"), # type: ignore + self.encode_netloc(), + self.path.encode(charset, errors), # type: ignore + self.query.encode(charset, errors), # type: ignore + self.fragment.encode(charset, errors), # type: ignore + ) + + +class BytesURL(BaseURL): + """Represents a parsed URL in bytes.""" + + __slots__ = () + _at = b"@" # type: ignore + _colon = b":" # type: ignore + _lbracket = b"[" # type: ignore + _rbracket = b"]" # type: ignore + + def __str__(self) -> str: + return self.to_url().decode("utf-8", "replace") # type: ignore + + def encode_netloc(self) -> bytes: # type: ignore + """Returns the netloc unchanged as bytes.""" + return self.netloc # type: ignore + + def decode(self, charset: str = "utf-8", errors: str = "replace") -> "URL": + """Decodes the URL to a tuple made out of strings. The charset is + only being used for the path, query and fragment. + """ + return URL( + self.scheme.decode("ascii"), # type: ignore + self.decode_netloc(), + self.path.decode(charset, errors), # type: ignore + self.query.decode(charset, errors), # type: ignore + self.fragment.decode(charset, errors), # type: ignore + ) + + +_unquote_maps: t.Dict[t.FrozenSet[int], t.Dict[bytes, int]] = {frozenset(): _hextobyte} + + +def _unquote_to_bytes( + string: t.Union[str, bytes], unsafe: t.Union[str, bytes] = "" +) -> bytes: + if isinstance(string, str): + string = string.encode("utf-8") + + if isinstance(unsafe, str): + unsafe = unsafe.encode("utf-8") + + unsafe = frozenset(bytearray(unsafe)) + groups = iter(string.split(b"%")) + result = bytearray(next(groups, b"")) + + try: + hex_to_byte = _unquote_maps[unsafe] + except KeyError: + hex_to_byte = _unquote_maps[unsafe] = { + h: b for h, b in _hextobyte.items() if b not in unsafe + } + + for group in groups: + code = group[:2] + + if code in hex_to_byte: + result.append(hex_to_byte[code]) + result.extend(group[2:]) + else: + result.append(37) # % + result.extend(group) + + return bytes(result) + + +def _url_encode_impl( + obj: t.Union[t.Mapping[str, str], t.Iterable[t.Tuple[str, str]]], + charset: str, + sort: bool, + key: t.Optional[t.Callable[[t.Tuple[str, str]], t.Any]], +) -> t.Iterator[str]: + from .datastructures import iter_multi_items + + iterable: t.Iterable[t.Tuple[str, str]] = iter_multi_items(obj) + + if sort: + iterable = sorted(iterable, key=key) + + for key_str, value_str in iterable: + if value_str is None: + continue + + if not isinstance(key_str, bytes): + key_bytes = str(key_str).encode(charset) + else: + key_bytes = key_str + + if not isinstance(value_str, bytes): + value_bytes = str(value_str).encode(charset) + else: + value_bytes = value_str + + yield f"{_fast_url_quote_plus(key_bytes)}={_fast_url_quote_plus(value_bytes)}" + + +def _url_unquote_legacy(value: str, unsafe: str = "") -> str: + try: + return url_unquote(value, charset="utf-8", errors="strict", unsafe=unsafe) + except UnicodeError: + return url_unquote(value, charset="latin1", unsafe=unsafe) + + +def url_parse( + url: str, scheme: t.Optional[str] = None, allow_fragments: bool = True +) -> BaseURL: + """Parses a URL from a string into a :class:`URL` tuple. If the URL + is lacking a scheme it can be provided as second argument. Otherwise, + it is ignored. Optionally fragments can be stripped from the URL + by setting `allow_fragments` to `False`. + + The inverse of this function is :func:`url_unparse`. + + :param url: the URL to parse. + :param scheme: the default schema to use if the URL is schemaless. + :param allow_fragments: if set to `False` a fragment will be removed + from the URL. + """ + s = _make_encode_wrapper(url) + is_text_based = isinstance(url, str) + + if scheme is None: + scheme = s("") + netloc = query = fragment = s("") + i = url.find(s(":")) + if i > 0 and _scheme_re.match(_to_str(url[:i], errors="replace")): + # make sure "iri" is not actually a port number (in which case + # "scheme" is really part of the path) + rest = url[i + 1 :] + if not rest or any(c not in s("0123456789") for c in rest): + # not a port number + scheme, url = url[:i].lower(), rest + + if url[:2] == s("//"): + delim = len(url) + for c in s("/?#"): + wdelim = url.find(c, 2) + if wdelim >= 0: + delim = min(delim, wdelim) + netloc, url = url[2:delim], url[delim:] + if (s("[") in netloc and s("]") not in netloc) or ( + s("]") in netloc and s("[") not in netloc + ): + raise ValueError("Invalid IPv6 URL") + + if allow_fragments and s("#") in url: + url, fragment = url.split(s("#"), 1) + if s("?") in url: + url, query = url.split(s("?"), 1) + + result_type = URL if is_text_based else BytesURL + return result_type(scheme, netloc, url, query, fragment) + + +def _make_fast_url_quote( + charset: str = "utf-8", + errors: str = "strict", + safe: t.Union[str, bytes] = "/:", + unsafe: t.Union[str, bytes] = "", +) -> t.Callable[[bytes], str]: + """Precompile the translation table for a URL encoding function. + + Unlike :func:`url_quote`, the generated function only takes the + string to quote. + + :param charset: The charset to encode the result with. + :param errors: How to handle encoding errors. + :param safe: An optional sequence of safe characters to never encode. + :param unsafe: An optional sequence of unsafe characters to always encode. + """ + if isinstance(safe, str): + safe = safe.encode(charset, errors) + + if isinstance(unsafe, str): + unsafe = unsafe.encode(charset, errors) + + safe = (frozenset(bytearray(safe)) | _always_safe) - frozenset(bytearray(unsafe)) + table = [chr(c) if c in safe else f"%{c:02X}" for c in range(256)] + + def quote(string: bytes) -> str: + return "".join([table[c] for c in string]) + + return quote + + +_fast_url_quote = _make_fast_url_quote() +_fast_quote_plus = _make_fast_url_quote(safe=" ", unsafe="+") + + +def _fast_url_quote_plus(string: bytes) -> str: + return _fast_quote_plus(string).replace(" ", "+") + + +def url_quote( + string: t.Union[str, bytes], + charset: str = "utf-8", + errors: str = "strict", + safe: t.Union[str, bytes] = "/:", + unsafe: t.Union[str, bytes] = "", +) -> str: + """URL encode a single string with a given encoding. + + :param s: the string to quote. + :param charset: the charset to be used. + :param safe: an optional sequence of safe characters. + :param unsafe: an optional sequence of unsafe characters. + + .. versionadded:: 0.9.2 + The `unsafe` parameter was added. + """ + if not isinstance(string, (str, bytes, bytearray)): + string = str(string) + if isinstance(string, str): + string = string.encode(charset, errors) + if isinstance(safe, str): + safe = safe.encode(charset, errors) + if isinstance(unsafe, str): + unsafe = unsafe.encode(charset, errors) + safe = (frozenset(bytearray(safe)) | _always_safe) - frozenset(bytearray(unsafe)) + rv = bytearray() + for char in bytearray(string): + if char in safe: + rv.append(char) + else: + rv.extend(_bytetohex[char]) + return bytes(rv).decode(charset) + + +def url_quote_plus( + string: str, charset: str = "utf-8", errors: str = "strict", safe: str = "" +) -> str: + """URL encode a single string with the given encoding and convert + whitespace to "+". + + :param s: The string to quote. + :param charset: The charset to be used. + :param safe: An optional sequence of safe characters. + """ + return url_quote(string, charset, errors, safe + " ", "+").replace(" ", "+") + + +def url_unparse(components: t.Tuple[str, str, str, str, str]) -> str: + """The reverse operation to :meth:`url_parse`. This accepts arbitrary + as well as :class:`URL` tuples and returns a URL as a string. + + :param components: the parsed URL as tuple which should be converted + into a URL string. + """ + _check_str_tuple(components) + scheme, netloc, path, query, fragment = components + s = _make_encode_wrapper(scheme) + url = s("") + + # We generally treat file:///x and file:/x the same which is also + # what browsers seem to do. This also allows us to ignore a schema + # register for netloc utilization or having to differentiate between + # empty and missing netloc. + if netloc or (scheme and path.startswith(s("/"))): + if path and path[:1] != s("/"): + path = s("/") + path + url = s("//") + (netloc or s("")) + path + elif path: + url += path + if scheme: + url = scheme + s(":") + url + if query: + url = url + s("?") + query + if fragment: + url = url + s("#") + fragment + return url + + +def url_unquote( + s: t.Union[str, bytes], + charset: str = "utf-8", + errors: str = "replace", + unsafe: str = "", +) -> str: + """URL decode a single string with a given encoding. If the charset + is set to `None` no decoding is performed and raw bytes are + returned. + + :param s: the string to unquote. + :param charset: the charset of the query string. If set to `None` + no decoding will take place. + :param errors: the error handling for the charset decoding. + """ + rv = _unquote_to_bytes(s, unsafe) + if charset is None: + return rv + return rv.decode(charset, errors) + + +def url_unquote_plus( + s: t.Union[str, bytes], charset: str = "utf-8", errors: str = "replace" +) -> str: + """URL decode a single string with the given `charset` and decode "+" to + whitespace. + + Per default encoding errors are ignored. If you want a different behavior + you can set `errors` to ``'replace'`` or ``'strict'``. + + :param s: The string to unquote. + :param charset: the charset of the query string. If set to `None` + no decoding will take place. + :param errors: The error handling for the `charset` decoding. + """ + if isinstance(s, str): + s = s.replace("+", " ") + else: + s = s.replace(b"+", b" ") + return url_unquote(s, charset, errors) + + +def url_fix(s: str, charset: str = "utf-8") -> str: + r"""Sometimes you get an URL by a user that just isn't a real URL because + it contains unsafe characters like ' ' and so on. This function can fix + some of the problems in a similar way browsers handle data entered by the + user: + + >>> url_fix('http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)') + 'http://de.wikipedia.org/wiki/Elf%20(Begriffskl%C3%A4rung)' + + :param s: the string with the URL to fix. + :param charset: The target charset for the URL if the url was given + as a string. + """ + # First step is to switch to text processing and to convert + # backslashes (which are invalid in URLs anyways) to slashes. This is + # consistent with what Chrome does. + s = _to_str(s, charset, "replace").replace("\\", "/") + + # For the specific case that we look like a malformed windows URL + # we want to fix this up manually: + if s.startswith("file://") and s[7:8].isalpha() and s[8:10] in (":/", "|/"): + s = f"file:///{s[7:]}" + + url = url_parse(s) + path = url_quote(url.path, charset, safe="/%+$!*'(),") + qs = url_quote_plus(url.query, charset, safe=":&%=+$!*'(),") + anchor = url_quote_plus(url.fragment, charset, safe=":&%=+$!*'(),") + return url_unparse((url.scheme, url.encode_netloc(), path, qs, anchor)) + + +# not-unreserved characters remain quoted when unquoting to IRI +_to_iri_unsafe = "".join([chr(c) for c in range(128) if c not in _always_safe]) + + +def _codec_error_url_quote(e: UnicodeError) -> t.Tuple[str, int]: + """Used in :func:`uri_to_iri` after unquoting to re-quote any + invalid bytes. + """ + # the docs state that UnicodeError does have these attributes, + # but mypy isn't picking them up + out = _fast_url_quote(e.object[e.start : e.end]) # type: ignore + return out, e.end # type: ignore + + +codecs.register_error("werkzeug.url_quote", _codec_error_url_quote) + + +def uri_to_iri( + uri: t.Union[str, t.Tuple[str, str, str, str, str]], + charset: str = "utf-8", + errors: str = "werkzeug.url_quote", +) -> str: + """Convert a URI to an IRI. All valid UTF-8 characters are unquoted, + leaving all reserved and invalid characters quoted. If the URL has + a domain, it is decoded from Punycode. + + >>> uri_to_iri("http://xn--n3h.net/p%C3%A5th?q=%C3%A8ry%DF") + 'http://\\u2603.net/p\\xe5th?q=\\xe8ry%DF' + + :param uri: The URI to convert. + :param charset: The encoding to encode unquoted bytes with. + :param errors: Error handler to use during ``bytes.encode``. By + default, invalid bytes are left quoted. + + .. versionchanged:: 0.15 + All reserved and invalid characters remain quoted. Previously, + only some reserved characters were preserved, and invalid bytes + were replaced instead of left quoted. + + .. versionadded:: 0.6 + """ + if isinstance(uri, tuple): + uri = url_unparse(uri) + + uri = url_parse(_to_str(uri, charset)) + path = url_unquote(uri.path, charset, errors, _to_iri_unsafe) + query = url_unquote(uri.query, charset, errors, _to_iri_unsafe) + fragment = url_unquote(uri.fragment, charset, errors, _to_iri_unsafe) + return url_unparse((uri.scheme, uri.decode_netloc(), path, query, fragment)) + + +# reserved characters remain unquoted when quoting to URI +_to_uri_safe = ":/?#[]@!$&'()*+,;=%" + + +def iri_to_uri( + iri: t.Union[str, t.Tuple[str, str, str, str, str]], + charset: str = "utf-8", + errors: str = "strict", + safe_conversion: bool = False, +) -> str: + """Convert an IRI to a URI. All non-ASCII and unsafe characters are + quoted. If the URL has a domain, it is encoded to Punycode. + + >>> iri_to_uri('http://\\u2603.net/p\\xe5th?q=\\xe8ry%DF') + 'http://xn--n3h.net/p%C3%A5th?q=%C3%A8ry%DF' + + :param iri: The IRI to convert. + :param charset: The encoding of the IRI. + :param errors: Error handler to use during ``bytes.encode``. + :param safe_conversion: Return the URL unchanged if it only contains + ASCII characters and no whitespace. See the explanation below. + + There is a general problem with IRI conversion with some protocols + that are in violation of the URI specification. Consider the + following two IRIs:: + + magnet:?xt=uri:whatever + itms-services://?action=download-manifest + + After parsing, we don't know if the scheme requires the ``//``, + which is dropped if empty, but conveys different meanings in the + final URL if it's present or not. In this case, you can use + ``safe_conversion``, which will return the URL unchanged if it only + contains ASCII characters and no whitespace. This can result in a + URI with unquoted characters if it was not already quoted correctly, + but preserves the URL's semantics. Werkzeug uses this for the + ``Location`` header for redirects. + + .. versionchanged:: 0.15 + All reserved characters remain unquoted. Previously, only some + reserved characters were left unquoted. + + .. versionchanged:: 0.9.6 + The ``safe_conversion`` parameter was added. + + .. versionadded:: 0.6 + """ + if isinstance(iri, tuple): + iri = url_unparse(iri) + + if safe_conversion: + # If we're not sure if it's safe to convert the URL, and it only + # contains ASCII characters, return it unconverted. + try: + native_iri = _to_str(iri) + ascii_iri = native_iri.encode("ascii") + + # Only return if it doesn't have whitespace. (Why?) + if len(ascii_iri.split()) == 1: + return native_iri + except UnicodeError: + pass + + iri = url_parse(_to_str(iri, charset, errors)) + path = url_quote(iri.path, charset, errors, _to_uri_safe) + query = url_quote(iri.query, charset, errors, _to_uri_safe) + fragment = url_quote(iri.fragment, charset, errors, _to_uri_safe) + return url_unparse((iri.scheme, iri.encode_netloc(), path, query, fragment)) + + +def url_decode( + s: t.AnyStr, + charset: str = "utf-8", + include_empty: bool = True, + errors: str = "replace", + separator: str = "&", + cls: t.Optional[t.Type["ds.MultiDict"]] = None, +) -> "ds.MultiDict[str, str]": + """Parse a query string and return it as a :class:`MultiDict`. + + :param s: The query string to parse. + :param charset: Decode bytes to string with this charset. If not + given, bytes are returned as-is. + :param include_empty: Include keys with empty values in the dict. + :param errors: Error handling behavior when decoding bytes. + :param separator: Separator character between pairs. + :param cls: Container to hold result instead of :class:`MultiDict`. + + .. versionchanged:: 2.0 + The ``decode_keys`` parameter is deprecated and will be removed + in Werkzeug 2.1. + + .. versionchanged:: 0.5 + In previous versions ";" and "&" could be used for url decoding. + Now only "&" is supported. If you want to use ";", a different + ``separator`` can be provided. + + .. versionchanged:: 0.5 + The ``cls`` parameter was added. + """ + if cls is None: + from .datastructures import MultiDict # noqa: F811 + + cls = MultiDict + if isinstance(s, str) and not isinstance(separator, str): + separator = separator.decode(charset or "ascii") + elif isinstance(s, bytes) and not isinstance(separator, bytes): + separator = separator.encode(charset or "ascii") # type: ignore + return cls( + _url_decode_impl( + s.split(separator), charset, include_empty, errors # type: ignore + ) + ) + + +def url_decode_stream( + stream: t.IO[bytes], + charset: str = "utf-8", + include_empty: bool = True, + errors: str = "replace", + separator: bytes = b"&", + cls: t.Optional[t.Type["ds.MultiDict"]] = None, + limit: t.Optional[int] = None, +) -> "ds.MultiDict[str, str]": + """Works like :func:`url_decode` but decodes a stream. The behavior + of stream and limit follows functions like + :func:`~werkzeug.wsgi.make_line_iter`. The generator of pairs is + directly fed to the `cls` so you can consume the data while it's + parsed. + + :param stream: a stream with the encoded querystring + :param charset: the charset of the query string. If set to `None` + no decoding will take place. + :param include_empty: Set to `False` if you don't want empty values to + appear in the dict. + :param errors: the decoding error behavior. + :param separator: the pair separator to be used, defaults to ``&`` + :param cls: an optional dict class to use. If this is not specified + or `None` the default :class:`MultiDict` is used. + :param limit: the content length of the URL data. Not necessary if + a limited stream is provided. + + .. versionchanged:: 2.0 + The ``decode_keys`` and ``return_iterator`` parameters are + deprecated and will be removed in Werkzeug 2.1. + + .. versionadded:: 0.8 + """ + from .wsgi import make_chunk_iter + + pair_iter = make_chunk_iter(stream, separator, limit) + decoder = _url_decode_impl(pair_iter, charset, include_empty, errors) + + if cls is None: + from .datastructures import MultiDict # noqa: F811 + + cls = MultiDict + + return cls(decoder) + + +def _url_decode_impl( + pair_iter: t.Iterable[t.AnyStr], charset: str, include_empty: bool, errors: str +) -> t.Iterator[t.Tuple[str, str]]: + for pair in pair_iter: + if not pair: + continue + s = _make_encode_wrapper(pair) + equal = s("=") + if equal in pair: + key, value = pair.split(equal, 1) + else: + if not include_empty: + continue + key = pair + value = s("") + yield ( + url_unquote_plus(key, charset, errors), + url_unquote_plus(value, charset, errors), + ) + + +def url_encode( + obj: t.Union[t.Mapping[str, str], t.Iterable[t.Tuple[str, str]]], + charset: str = "utf-8", + sort: bool = False, + key: t.Optional[t.Callable[[t.Tuple[str, str]], t.Any]] = None, + separator: str = "&", +) -> str: + """URL encode a dict/`MultiDict`. If a value is `None` it will not appear + in the result string. Per default only values are encoded into the target + charset strings. + + :param obj: the object to encode into a query string. + :param charset: the charset of the query string. + :param sort: set to `True` if you want parameters to be sorted by `key`. + :param separator: the separator to be used for the pairs. + :param key: an optional function to be used for sorting. For more details + check out the :func:`sorted` documentation. + + .. versionchanged:: 2.0 + The ``encode_keys`` parameter is deprecated and will be removed + in Werkzeug 2.1. + + .. versionchanged:: 0.5 + Added the ``sort``, ``key``, and ``separator`` parameters. + """ + separator = _to_str(separator, "ascii") + return separator.join(_url_encode_impl(obj, charset, sort, key)) + + +def url_encode_stream( + obj: t.Union[t.Mapping[str, str], t.Iterable[t.Tuple[str, str]]], + stream: t.Optional[t.IO[str]] = None, + charset: str = "utf-8", + sort: bool = False, + key: t.Optional[t.Callable[[t.Tuple[str, str]], t.Any]] = None, + separator: str = "&", +) -> None: + """Like :meth:`url_encode` but writes the results to a stream + object. If the stream is `None` a generator over all encoded + pairs is returned. + + :param obj: the object to encode into a query string. + :param stream: a stream to write the encoded object into or `None` if + an iterator over the encoded pairs should be returned. In + that case the separator argument is ignored. + :param charset: the charset of the query string. + :param sort: set to `True` if you want parameters to be sorted by `key`. + :param separator: the separator to be used for the pairs. + :param key: an optional function to be used for sorting. For more details + check out the :func:`sorted` documentation. + + .. versionchanged:: 2.0 + The ``encode_keys`` parameter is deprecated and will be removed + in Werkzeug 2.1. + + .. versionadded:: 0.8 + """ + separator = _to_str(separator, "ascii") + gen = _url_encode_impl(obj, charset, sort, key) + if stream is None: + return gen # type: ignore + for idx, chunk in enumerate(gen): + if idx: + stream.write(separator) + stream.write(chunk) + return None + + +def url_join( + base: t.Union[str, t.Tuple[str, str, str, str, str]], + url: t.Union[str, t.Tuple[str, str, str, str, str]], + allow_fragments: bool = True, +) -> str: + """Join a base URL and a possibly relative URL to form an absolute + interpretation of the latter. + + :param base: the base URL for the join operation. + :param url: the URL to join. + :param allow_fragments: indicates whether fragments should be allowed. + """ + if isinstance(base, tuple): + base = url_unparse(base) + if isinstance(url, tuple): + url = url_unparse(url) + + _check_str_tuple((base, url)) + s = _make_encode_wrapper(base) + + if not base: + return url + if not url: + return base + + bscheme, bnetloc, bpath, bquery, bfragment = url_parse( + base, allow_fragments=allow_fragments + ) + scheme, netloc, path, query, fragment = url_parse(url, bscheme, allow_fragments) + if scheme != bscheme: + return url + if netloc: + return url_unparse((scheme, netloc, path, query, fragment)) + netloc = bnetloc + + if path[:1] == s("/"): + segments = path.split(s("/")) + elif not path: + segments = bpath.split(s("/")) + if not query: + query = bquery + else: + segments = bpath.split(s("/"))[:-1] + path.split(s("/")) + + # If the rightmost part is "./" we want to keep the slash but + # remove the dot. + if segments[-1] == s("."): + segments[-1] = s("") + + # Resolve ".." and "." + segments = [segment for segment in segments if segment != s(".")] + while True: + i = 1 + n = len(segments) - 1 + while i < n: + if segments[i] == s("..") and segments[i - 1] not in (s(""), s("..")): + del segments[i - 1 : i + 1] + break + i += 1 + else: + break + + # Remove trailing ".." if the URL is absolute + unwanted_marker = [s(""), s("..")] + while segments[:2] == unwanted_marker: + del segments[1] + + path = s("/").join(segments) + return url_unparse((scheme, netloc, path, query, fragment)) diff --git a/.vcrunch/Lib/site-packages/werkzeug/user_agent.py b/.vcrunch/Lib/site-packages/werkzeug/user_agent.py new file mode 100644 index 0000000..66ffcbe --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/user_agent.py @@ -0,0 +1,47 @@ +import typing as t + + +class UserAgent: + """Represents a parsed user agent header value. + + The default implementation does no parsing, only the :attr:`string` + attribute is set. A subclass may parse the string to set the + common attributes or expose other information. Set + :attr:`werkzeug.wrappers.Request.user_agent_class` to use a + subclass. + + :param string: The header value to parse. + + .. versionadded:: 2.0 + This replaces the previous ``useragents`` module, but does not + provide a built-in parser. + """ + + platform: t.Optional[str] = None + """The OS name, if it could be parsed from the string.""" + + browser: t.Optional[str] = None + """The browser name, if it could be parsed from the string.""" + + version: t.Optional[str] = None + """The browser version, if it could be parsed from the string.""" + + language: t.Optional[str] = None + """The browser language, if it could be parsed from the string.""" + + def __init__(self, string: str) -> None: + self.string: str = string + """The original header value.""" + + def __repr__(self) -> str: + return f"<{type(self).__name__} {self.browser}/{self.version}>" + + def __str__(self) -> str: + return self.string + + def __bool__(self) -> bool: + return bool(self.browser) + + def to_header(self) -> str: + """Convert to a header value.""" + return self.string diff --git a/.vcrunch/Lib/site-packages/werkzeug/utils.py b/.vcrunch/Lib/site-packages/werkzeug/utils.py new file mode 100644 index 0000000..672e6e5 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/utils.py @@ -0,0 +1,705 @@ +import io +import mimetypes +import os +import pkgutil +import re +import sys +import typing as t +import unicodedata +from datetime import datetime +from time import time +from zlib import adler32 + +from markupsafe import escape + +from ._internal import _DictAccessorProperty +from ._internal import _missing +from ._internal import _TAccessorValue +from .datastructures import Headers +from .exceptions import NotFound +from .exceptions import RequestedRangeNotSatisfiable +from .security import safe_join +from .urls import url_quote +from .wsgi import wrap_file + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIEnvironment + from .wrappers.request import Request + from .wrappers.response import Response + +_T = t.TypeVar("_T") + +_entity_re = re.compile(r"&([^;]+);") +_filename_ascii_strip_re = re.compile(r"[^A-Za-z0-9_.-]") +_windows_device_files = ( + "CON", + "AUX", + "COM1", + "COM2", + "COM3", + "COM4", + "LPT1", + "LPT2", + "LPT3", + "PRN", + "NUL", +) + + +class cached_property(property, t.Generic[_T]): + """A :func:`property` that is only evaluated once. Subsequent access + returns the cached value. Setting the property sets the cached + value. Deleting the property clears the cached value, accessing it + again will evaluate it again. + + .. code-block:: python + + class Example: + @cached_property + def value(self): + # calculate something important here + return 42 + + e = Example() + e.value # evaluates + e.value # uses cache + e.value = 16 # sets cache + del e.value # clears cache + + If the class defines ``__slots__``, it must add ``_cache_{name}`` as + a slot. Alternatively, it can add ``__dict__``, but that's usually + not desirable. + + .. versionchanged:: 2.1 + Works with ``__slots__``. + + .. versionchanged:: 2.0 + ``del obj.name`` clears the cached value. + """ + + def __init__( + self, + fget: t.Callable[[t.Any], _T], + name: t.Optional[str] = None, + doc: t.Optional[str] = None, + ) -> None: + super().__init__(fget, doc=doc) + self.__name__ = name or fget.__name__ + self.slot_name = f"_cache_{self.__name__}" + self.__module__ = fget.__module__ + + def __set__(self, obj: object, value: _T) -> None: + if hasattr(obj, "__dict__"): + obj.__dict__[self.__name__] = value + else: + setattr(obj, self.slot_name, value) + + def __get__(self, obj: object, type: type = None) -> _T: # type: ignore + if obj is None: + return self # type: ignore + + obj_dict = getattr(obj, "__dict__", None) + + if obj_dict is not None: + value: _T = obj_dict.get(self.__name__, _missing) + else: + value = getattr(obj, self.slot_name, _missing) # type: ignore[arg-type] + + if value is _missing: + value = self.fget(obj) # type: ignore + + if obj_dict is not None: + obj.__dict__[self.__name__] = value + else: + setattr(obj, self.slot_name, value) + + return value + + def __delete__(self, obj: object) -> None: + if hasattr(obj, "__dict__"): + del obj.__dict__[self.__name__] + else: + setattr(obj, self.slot_name, _missing) + + +class environ_property(_DictAccessorProperty[_TAccessorValue]): + """Maps request attributes to environment variables. This works not only + for the Werkzeug request object, but also any other class with an + environ attribute: + + >>> class Test(object): + ... environ = {'key': 'value'} + ... test = environ_property('key') + >>> var = Test() + >>> var.test + 'value' + + If you pass it a second value it's used as default if the key does not + exist, the third one can be a converter that takes a value and converts + it. If it raises :exc:`ValueError` or :exc:`TypeError` the default value + is used. If no default value is provided `None` is used. + + Per default the property is read only. You have to explicitly enable it + by passing ``read_only=False`` to the constructor. + """ + + read_only = True + + def lookup(self, obj: "Request") -> "WSGIEnvironment": + return obj.environ + + +class header_property(_DictAccessorProperty[_TAccessorValue]): + """Like `environ_property` but for headers.""" + + def lookup(self, obj: t.Union["Request", "Response"]) -> Headers: + return obj.headers + + +# https://cgit.freedesktop.org/xdg/shared-mime-info/tree/freedesktop.org.xml.in +# https://www.iana.org/assignments/media-types/media-types.xhtml +# Types listed in the XDG mime info that have a charset in the IANA registration. +_charset_mimetypes = { + "application/ecmascript", + "application/javascript", + "application/sql", + "application/xml", + "application/xml-dtd", + "application/xml-external-parsed-entity", +} + + +def get_content_type(mimetype: str, charset: str) -> str: + """Returns the full content type string with charset for a mimetype. + + If the mimetype represents text, the charset parameter will be + appended, otherwise the mimetype is returned unchanged. + + :param mimetype: The mimetype to be used as content type. + :param charset: The charset to be appended for text mimetypes. + :return: The content type. + + .. versionchanged:: 0.15 + Any type that ends with ``+xml`` gets a charset, not just those + that start with ``application/``. Known text types such as + ``application/javascript`` are also given charsets. + """ + if ( + mimetype.startswith("text/") + or mimetype in _charset_mimetypes + or mimetype.endswith("+xml") + ): + mimetype += f"; charset={charset}" + + return mimetype + + +def secure_filename(filename: str) -> str: + r"""Pass it a filename and it will return a secure version of it. This + filename can then safely be stored on a regular file system and passed + to :func:`os.path.join`. The filename returned is an ASCII only string + for maximum portability. + + On windows systems the function also makes sure that the file is not + named after one of the special device files. + + >>> secure_filename("My cool movie.mov") + 'My_cool_movie.mov' + >>> secure_filename("../../../etc/passwd") + 'etc_passwd' + >>> secure_filename('i contain cool \xfcml\xe4uts.txt') + 'i_contain_cool_umlauts.txt' + + The function might return an empty filename. It's your responsibility + to ensure that the filename is unique and that you abort or + generate a random filename if the function returned an empty one. + + .. versionadded:: 0.5 + + :param filename: the filename to secure + """ + filename = unicodedata.normalize("NFKD", filename) + filename = filename.encode("ascii", "ignore").decode("ascii") + + for sep in os.path.sep, os.path.altsep: + if sep: + filename = filename.replace(sep, " ") + filename = str(_filename_ascii_strip_re.sub("", "_".join(filename.split()))).strip( + "._" + ) + + # on nt a couple of special files are present in each folder. We + # have to ensure that the target file is not such a filename. In + # this case we prepend an underline + if ( + os.name == "nt" + and filename + and filename.split(".")[0].upper() in _windows_device_files + ): + filename = f"_{filename}" + + return filename + + +def redirect( + location: str, code: int = 302, Response: t.Optional[t.Type["Response"]] = None +) -> "Response": + """Returns a response object (a WSGI application) that, if called, + redirects the client to the target location. Supported codes are + 301, 302, 303, 305, 307, and 308. 300 is not supported because + it's not a real redirect and 304 because it's the answer for a + request with a request with defined If-Modified-Since headers. + + .. versionadded:: 0.6 + The location can now be a unicode string that is encoded using + the :func:`iri_to_uri` function. + + .. versionadded:: 0.10 + The class used for the Response object can now be passed in. + + :param location: the location the response should redirect to. + :param code: the redirect status code. defaults to 302. + :param class Response: a Response class to use when instantiating a + response. The default is :class:`werkzeug.wrappers.Response` if + unspecified. + """ + if Response is None: + from .wrappers import Response # type: ignore + + display_location = escape(location) + if isinstance(location, str): + # Safe conversion is necessary here as we might redirect + # to a broken URI scheme (for instance itms-services). + from .urls import iri_to_uri + + location = iri_to_uri(location, safe_conversion=True) + + response = Response( # type: ignore + "\n" + "\n" + "Redirecting...\n" + "

    Redirecting...

    \n" + "

    You should be redirected automatically to the target URL: " + f'{display_location}. If' + " not, click the link.\n", + code, + mimetype="text/html", + ) + response.headers["Location"] = location + return response + + +def append_slash_redirect(environ: "WSGIEnvironment", code: int = 308) -> "Response": + """Redirect to the current URL with a slash appended. + + If the current URL is ``/user/42``, the redirect URL will be + ``42/``. When joined to the current URL during response + processing or by the browser, this will produce ``/user/42/``. + + The behavior is undefined if the path ends with a slash already. If + called unconditionally on a URL, it may produce a redirect loop. + + :param environ: Use the path and query from this WSGI environment + to produce the redirect URL. + :param code: the status code for the redirect. + + .. versionchanged:: 2.1 + Produce a relative URL that only modifies the last segment. + Relevant when the current path has multiple segments. + + .. versionchanged:: 2.1 + The default status code is 308 instead of 301. This preserves + the request method and body. + """ + tail = environ["PATH_INFO"].rpartition("/")[2] + + if not tail: + new_path = "./" + else: + new_path = f"{tail}/" + + query_string = environ.get("QUERY_STRING") + + if query_string: + new_path = f"{new_path}?{query_string}" + + return redirect(new_path, code) + + +def send_file( + path_or_file: t.Union[os.PathLike, str, t.IO[bytes]], + environ: "WSGIEnvironment", + mimetype: t.Optional[str] = None, + as_attachment: bool = False, + download_name: t.Optional[str] = None, + conditional: bool = True, + etag: t.Union[bool, str] = True, + last_modified: t.Optional[t.Union[datetime, int, float]] = None, + max_age: t.Optional[ + t.Union[int, t.Callable[[t.Optional[str]], t.Optional[int]]] + ] = None, + use_x_sendfile: bool = False, + response_class: t.Optional[t.Type["Response"]] = None, + _root_path: t.Optional[t.Union[os.PathLike, str]] = 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. + + 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``, ``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 environ: The WSGI environ for the current request. + :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. + :param use_x_sendfile: Set the ``X-Sendfile`` header to let the + server to efficiently send the file. Requires support from the + HTTP server. Requires passing a file path. + :param response_class: Build the response using this class. Defaults + to :class:`~werkzeug.wrappers.Response`. + :param _root_path: Do not use. For internal use only. Use + :func:`send_from_directory` to safely send files under a path. + + .. versionchanged:: 2.0.2 + ``send_file`` only sets a detected ``Content-Encoding`` if + ``as_attachment`` is disabled. + + .. versionadded:: 2.0 + Adapted from Flask's implementation. + + .. versionchanged:: 2.0 + ``download_name`` replaces Flask's ``attachment_filename`` + parameter. If ``as_attachment=False``, it is passed with + ``Content-Disposition: inline`` instead. + + .. versionchanged:: 2.0 + ``max_age`` replaces Flask's ``cache_timeout`` parameter. + ``conditional`` is enabled and ``max_age`` is not set by + default. + + .. versionchanged:: 2.0 + ``etag`` replaces Flask's ``add_etags`` parameter. It can be a + string to use instead of generating one. + + .. versionchanged:: 2.0 + If an encoding is returned when guessing ``mimetype`` from + ``download_name``, set the ``Content-Encoding`` header. + """ + if response_class is None: + from .wrappers import Response + + response_class = Response + + path: t.Optional[str] = None + file: t.Optional[t.IO[bytes]] = None + size: t.Optional[int] = None + mtime: t.Optional[float] = None + headers = Headers() + + if isinstance(path_or_file, (os.PathLike, str)) or hasattr( + path_or_file, "__fspath__" + ): + path_or_file = t.cast(t.Union[os.PathLike, str], path_or_file) + + # Flask will pass app.root_path, allowing its send_file wrapper + # to not have to deal with paths. + if _root_path is not None: + path = os.path.join(_root_path, path_or_file) + else: + path = os.path.abspath(path_or_file) + + stat = os.stat(path) + size = stat.st_size + mtime = stat.st_mtime + else: + file = path_or_file + + if download_name is None and path is not None: + download_name = os.path.basename(path) + + if mimetype is None: + if download_name is None: + raise TypeError( + "Unable to detect the MIME type because a file name is" + " not available. Either set 'download_name', pass a" + " path instead of a file, or set 'mimetype'." + ) + + mimetype, encoding = mimetypes.guess_type(download_name) + + if mimetype is None: + mimetype = "application/octet-stream" + + # Don't send encoding for attachments, it causes browsers to + # save decompress tar.gz files. + if encoding is not None and not as_attachment: + headers.set("Content-Encoding", encoding) + + if download_name is not None: + try: + download_name.encode("ascii") + except UnicodeEncodeError: + simple = unicodedata.normalize("NFKD", download_name) + simple = simple.encode("ascii", "ignore").decode("ascii") + quoted = url_quote(download_name, safe="") + names = {"filename": simple, "filename*": f"UTF-8''{quoted}"} + else: + names = {"filename": download_name} + + value = "attachment" if as_attachment else "inline" + headers.set("Content-Disposition", value, **names) + elif as_attachment: + raise TypeError( + "No name provided for attachment. Either set" + " 'download_name' or pass a path instead of a file." + ) + + if use_x_sendfile and path is not None: + headers["X-Sendfile"] = path + data = None + else: + if file is None: + file = open(path, "rb") # type: ignore + elif isinstance(file, io.BytesIO): + size = file.getbuffer().nbytes + elif isinstance(file, io.TextIOBase): + raise ValueError("Files must be opened in binary mode or use BytesIO.") + + data = wrap_file(environ, file) + + rv = response_class( + data, mimetype=mimetype, headers=headers, direct_passthrough=True + ) + + if size is not None: + rv.content_length = size + + if last_modified is not None: + rv.last_modified = last_modified # type: ignore + elif mtime is not None: + rv.last_modified = mtime # type: ignore + + rv.cache_control.no_cache = True + + # Flask will pass app.get_send_file_max_age, allowing its send_file + # wrapper to not have to deal with paths. + if callable(max_age): + max_age = max_age(path) + + if max_age is not None: + if max_age > 0: + rv.cache_control.no_cache = None + rv.cache_control.public = True + + rv.cache_control.max_age = max_age + rv.expires = int(time() + max_age) # type: ignore + + if isinstance(etag, str): + rv.set_etag(etag) + elif etag and path is not None: + check = adler32(path.encode("utf-8")) & 0xFFFFFFFF + rv.set_etag(f"{mtime}-{size}-{check}") + + if conditional: + try: + rv = rv.make_conditional(environ, accept_ranges=True, complete_length=size) + except RequestedRangeNotSatisfiable: + if file is not None: + file.close() + + raise + + # Some x-sendfile implementations incorrectly ignore the 304 + # status code and send the file anyway. + if rv.status_code == 304: + rv.headers.pop("x-sendfile", None) + + return rv + + +def send_from_directory( + directory: t.Union[os.PathLike, str], + path: t.Union[os.PathLike, str], + environ: "WSGIEnvironment", + **kwargs: t.Any, +) -> "Response": + """Send a file from within a directory using :func:`send_file`. + + 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, + returns a 404 :exc:`~werkzeug.exceptions.NotFound` error. + + :param directory: The directory that ``path`` must be located under. + :param path: The path to the file to send, relative to + ``directory``. + :param environ: The WSGI environ for the current request. + :param kwargs: Arguments to pass to :func:`send_file`. + + .. versionadded:: 2.0 + Adapted from Flask's implementation. + """ + path = safe_join(os.fspath(directory), os.fspath(path)) + + if path is None: + raise NotFound() + + # Flask will pass app.root_path, allowing its send_from_directory + # wrapper to not have to deal with paths. + if "_root_path" in kwargs: + path = os.path.join(kwargs["_root_path"], path) + + try: + if not os.path.isfile(path): + raise NotFound() + except ValueError: + # path contains null byte on Python < 3.8 + raise NotFound() from None + + return send_file(path, environ, **kwargs) + + +def import_string(import_name: str, silent: bool = False) -> t.Any: + """Imports an object based on a string. This is useful if you want to + use import paths as endpoints or something similar. An import path can + be specified either in dotted notation (``xml.sax.saxutils.escape``) + or with a colon as object delimiter (``xml.sax.saxutils:escape``). + + If `silent` is True the return value will be `None` if the import fails. + + :param import_name: the dotted name for the object to import. + :param silent: if set to `True` import errors are ignored and + `None` is returned instead. + :return: imported object + """ + import_name = import_name.replace(":", ".") + try: + try: + __import__(import_name) + except ImportError: + if "." not in import_name: + raise + else: + return sys.modules[import_name] + + module_name, obj_name = import_name.rsplit(".", 1) + module = __import__(module_name, globals(), locals(), [obj_name]) + try: + return getattr(module, obj_name) + except AttributeError as e: + raise ImportError(e) from None + + except ImportError as e: + if not silent: + raise ImportStringError(import_name, e).with_traceback( + sys.exc_info()[2] + ) from None + + return None + + +def find_modules( + import_path: str, include_packages: bool = False, recursive: bool = False +) -> t.Iterator[str]: + """Finds all the modules below a package. This can be useful to + automatically import all views / controllers so that their metaclasses / + function decorators have a chance to register themselves on the + application. + + Packages are not returned unless `include_packages` is `True`. This can + also recursively list modules but in that case it will import all the + packages to get the correct load path of that module. + + :param import_path: the dotted name for the package to find child modules. + :param include_packages: set to `True` if packages should be returned, too. + :param recursive: set to `True` if recursion should happen. + :return: generator + """ + module = import_string(import_path) + path = getattr(module, "__path__", None) + if path is None: + raise ValueError(f"{import_path!r} is not a package") + basename = f"{module.__name__}." + for _importer, modname, ispkg in pkgutil.iter_modules(path): + modname = basename + modname + if ispkg: + if include_packages: + yield modname + if recursive: + yield from find_modules(modname, include_packages, True) + else: + yield modname + + +class ImportStringError(ImportError): + """Provides information about a failed :func:`import_string` attempt.""" + + #: String in dotted notation that failed to be imported. + import_name: str + #: Wrapped exception. + exception: BaseException + + def __init__(self, import_name: str, exception: BaseException) -> None: + self.import_name = import_name + self.exception = exception + msg = import_name + name = "" + tracked = [] + for part in import_name.replace(":", ".").split("."): + name = f"{name}.{part}" if name else part + imported = import_string(name, silent=True) + if imported: + tracked.append((name, getattr(imported, "__file__", None))) + else: + track = [f"- {n!r} found in {i!r}." for n, i in tracked] + track.append(f"- {name!r} not found.") + track_str = "\n".join(track) + msg = ( + f"import_string() failed for {import_name!r}. Possible reasons" + f" are:\n\n" + "- missing __init__.py in a package;\n" + "- package or module path not included in sys.path;\n" + "- duplicated package or module name taking precedence in" + " sys.path;\n" + "- missing module, class, function or variable;\n\n" + f"Debugged import:\n\n{track_str}\n\n" + f"Original exception:\n\n{type(exception).__name__}: {exception}" + ) + break + + super().__init__(msg) + + def __repr__(self) -> str: + return f"<{type(self).__name__}({self.import_name!r}, {self.exception!r})>" diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/__init__.py b/.vcrunch/Lib/site-packages/werkzeug/wrappers/__init__.py new file mode 100644 index 0000000..b8c45d7 --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/wrappers/__init__.py @@ -0,0 +1,3 @@ +from .request import Request as Request +from .response import Response as Response +from .response import ResponseStream diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/__init__.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7f80c426cce4e3c25819fd30b5dae1e0c30ae635 GIT binary patch literal 297 zcmYk1!AiqG5QcY?)C6h8$1sPscM%c1iiZ>t!a~??hPpJ#uCu#VeIp;j7s=I=ui!;z zwL%BxpYMmC8OF?J$BgRxy;9FKKcYFTgv=GSJ0odX%RAQdn)Ap>m-K0!{&Gs3)fsWN zV&&wMQ@rG3UcqAk=Lw4noHc_3;*)<~c?8+tmXk5Zza++sV}biHrerZAd1IJIj`DSX zeJ<`Cpc8;vN#RVeYa_i-7zXtq7EgP)(QDzfhq;w%D>vZ84siPlVYA$!w3b#Zn??`X ZH_gJnjKxK7+R(vee83%%Oxcv5@*imXP!RwC literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/request.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ed781ffaa4eaa6ed8823d43f25551406a1cf1d20 GIT binary patch literal 20226 zcmch9TWlOxnqF1)h0W$gltfFGEX!q$cO>q}E!ks_ZLaMdnW8MsSd^BctZ`f3?qXLp z*-~HVs%lYeP!sRU8+#IX0wh2llFdQ__Qe5$ecP8HFL};Go(p*hFv!CMK^DQ}CHAb9 z@B7a=RmF?PgDj9Hy1Fi>{_~%6{`>zQ4yLB67Cuk@!*Xl$L(BRVFY=!vE`E$}blkQq z-}3FQRad`u-Ii;o?&#kFew}WySE`q6%P;uFZn-yBACvP^x6&K0kIQ)(=hb>u&c|>* zQJ;|W3eG3%lX5$7q`-F>Qe zq<%!s58(W0{ivMJbf4}Ws~?l|gE&84$Dn}oq3$!i6ZI3e6%_6~8$OiLoUA{G-@{$E z_k8_%X*G-UQ}t7}^{(YVlJ2ho*lzjkl~ z*RzeyXsy%mgVwX#T_V0DVLH}~#`9T=r z&cvloH@FcGLT`<49lFx%4P$S$8{}V`>BK?U=n+r@r#-$no;LW>PLB9N+r#5V6o-M= zYqY%CwgO7(nM05_cyw-Z)H#Wk-Mi9nqKNBbn^YdkzV`#ej(oU-HczzDv$wLXD6lR;J5l+dP( zwqtlQh2P4X*7*2%)&I~R^UMB3Fy&Y9o%Ee{0#VI;|Ga++ zXV2iidE4>7=f8k^C-C$S{O{xJS^rP{)BYKpoy5I4{||BYT;T3_=Lh~->EZd{lz{|1 zU-WDKxi6gh_oVd^^nBibN!q;-{K1{?a~3g=4gY1#-w*v){8u@T!I5^w|B?UNrzOn7 zY2EI1v}@{iZ|HWjXg6=#WpDsP!71H26M*kHw`loCYzcU-@A+@}ZwnT4xLWmp>|c

    3djKw%&Fb*$hUpIJq#J`Z^mgwx;`@4uBS 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc b/.vcrunch/Lib/site-packages/werkzeug/wrappers/__pycache__/response.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..24c86f4a764ed1e2ce7a263bba126cbeebb36d54 GIT binary patch literal 29155 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 Lxt~b?O_lyPr)-CO literal 0 HcmV?d00001 diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/request.py b/.vcrunch/Lib/site-packages/werkzeug/wrappers/request.py new file mode 100644 index 0000000..57b739c --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/wrappers/request.py @@ -0,0 +1,614 @@ +import functools +import json +import typing +import typing as t +from io import BytesIO + +from .._internal import _wsgi_decoding_dance +from ..datastructures import CombinedMultiDict +from ..datastructures import EnvironHeaders +from ..datastructures import FileStorage +from ..datastructures import ImmutableMultiDict +from ..datastructures import iter_multi_items +from ..datastructures import MultiDict +from ..formparser import default_stream_factory +from ..formparser import FormDataParser +from ..sansio.request import Request as _SansIORequest +from ..utils import cached_property +from ..utils import environ_property +from ..wsgi import _get_server +from ..wsgi import get_input_stream +from werkzeug.exceptions import BadRequest + +if t.TYPE_CHECKING: + import typing_extensions as te + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +class Request(_SansIORequest): + """Represents an incoming WSGI HTTP request, with headers and body + taken from the WSGI environment. Has properties and methods for + using the functionality defined by various HTTP specs. The data in + requests object is read-only. + + Text data is assumed to use UTF-8 encoding, which should be true for + the vast majority of modern clients. Using an encoding set by the + client is unsafe in Python due to extra encodings it provides, such + as ``zip``. To change the assumed encoding, subclass and replace + :attr:`charset`. + + :param environ: The WSGI environ is generated by the WSGI server and + contains information about the server configuration and client + request. + :param populate_request: Add this request object to the WSGI environ + as ``environ['werkzeug.request']``. Can be useful when + debugging. + :param shallow: Makes reading from :attr:`stream` (and any method + that would read from it) raise a :exc:`RuntimeError`. Useful to + prevent consuming the form data in middleware, which would make + it unavailable to the final application. + + .. versionchanged:: 2.1 + Remove the ``disable_data_descriptor`` attribute. + + .. versionchanged:: 2.0 + Combine ``BaseRequest`` and mixins into a single ``Request`` + class. Using the old classes is deprecated and will be removed + in Werkzeug 2.1. + + .. versionchanged:: 0.5 + Read-only mode is enforced with immutable classes for all data. + """ + + #: the maximum content length. This is forwarded to the form data + #: parsing function (:func:`parse_form_data`). When set and the + #: :attr:`form` or :attr:`files` attribute is accessed and the + #: parsing fails because more than the specified value is transmitted + #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. + #: + #: Have a look at :doc:`/request_data` for more details. + #: + #: .. versionadded:: 0.5 + max_content_length: t.Optional[int] = None + + #: the maximum form field size. This is forwarded to the form data + #: parsing function (:func:`parse_form_data`). When set and the + #: :attr:`form` or :attr:`files` attribute is accessed and the + #: data in memory for post data is longer than the specified value a + #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised. + #: + #: Have a look at :doc:`/request_data` for more details. + #: + #: .. versionadded:: 0.5 + max_form_memory_size: t.Optional[int] = None + + #: The form data parser that should be used. Can be replaced to customize + #: the form date parsing. + form_data_parser_class: t.Type[FormDataParser] = FormDataParser + + #: The WSGI environment containing HTTP headers and information from + #: the WSGI server. + environ: "WSGIEnvironment" + + #: Set when creating the request object. If ``True``, reading from + #: the request body will cause a ``RuntimeException``. Useful to + #: prevent modifying the stream from middleware. + shallow: bool + + def __init__( + self, + environ: "WSGIEnvironment", + populate_request: bool = True, + shallow: bool = False, + ) -> None: + super().__init__( + method=environ.get("REQUEST_METHOD", "GET"), + scheme=environ.get("wsgi.url_scheme", "http"), + server=_get_server(environ), + root_path=_wsgi_decoding_dance( + environ.get("SCRIPT_NAME") or "", self.charset, self.encoding_errors + ), + path=_wsgi_decoding_dance( + environ.get("PATH_INFO") or "", self.charset, self.encoding_errors + ), + query_string=environ.get("QUERY_STRING", "").encode("latin1"), + headers=EnvironHeaders(environ), + remote_addr=environ.get("REMOTE_ADDR"), + ) + self.environ = environ + self.shallow = shallow + + if populate_request and not shallow: + self.environ["werkzeug.request"] = self + + @classmethod + def from_values(cls, *args: t.Any, **kwargs: t.Any) -> "Request": + """Create a new request object based on the values provided. If + environ is given missing values are filled from there. This method is + useful for small scripts when you need to simulate a request from an URL. + Do not use this method for unittesting, there is a full featured client + object (:class:`Client`) that allows to create multipart requests, + support for cookies etc. + + This accepts the same options as the + :class:`~werkzeug.test.EnvironBuilder`. + + .. versionchanged:: 0.5 + This method now accepts the same arguments as + :class:`~werkzeug.test.EnvironBuilder`. Because of this the + `environ` parameter is now called `environ_overrides`. + + :return: request object + """ + from ..test import EnvironBuilder + + charset = kwargs.pop("charset", cls.charset) + kwargs["charset"] = charset + builder = EnvironBuilder(*args, **kwargs) + try: + return builder.get_request(cls) + finally: + builder.close() + + @classmethod + def application( + cls, f: t.Callable[["Request"], "WSGIApplication"] + ) -> "WSGIApplication": + """Decorate a function as responder that accepts the request as + the last argument. This works like the :func:`responder` + decorator but the function is passed the request object as the + last argument and the request object will be closed + automatically:: + + @Request.application + def my_wsgi_app(request): + return Response('Hello World!') + + As of Werkzeug 0.14 HTTP exceptions are automatically caught and + converted to responses instead of failing. + + :param f: the WSGI callable to decorate + :return: a new WSGI callable + """ + #: return a callable that wraps the -2nd argument with the request + #: and calls the function with all the arguments up to that one and + #: the request. The return value is then called with the latest + #: two arguments. This makes it possible to use this decorator for + #: both standalone WSGI functions as well as bound methods and + #: partially applied functions. + from ..exceptions import HTTPException + + @functools.wraps(f) + def application(*args): # type: ignore + request = cls(args[-2]) + with request: + try: + resp = f(*args[:-2] + (request,)) + except HTTPException as e: + resp = e.get_response(args[-2]) + return resp(*args[-2:]) + + return t.cast("WSGIApplication", application) + + def _get_file_stream( + self, + total_content_length: t.Optional[int], + content_type: t.Optional[str], + filename: t.Optional[str] = None, + content_length: t.Optional[int] = None, + ) -> t.IO[bytes]: + """Called to get a stream for the file upload. + + This must provide a file-like class with `read()`, `readline()` + and `seek()` methods that is both writeable and readable. + + The default implementation returns a temporary file if the total + content length is higher than 500KB. Because many browsers do not + provide a content length for the files only the total content + length matters. + + :param total_content_length: the total content length of all the + data in the request combined. This value + is guaranteed to be there. + :param content_type: the mimetype of the uploaded file. + :param filename: the filename of the uploaded file. May be `None`. + :param content_length: the length of this file. This value is usually + not provided because webbrowsers do not provide + this value. + """ + return default_stream_factory( + total_content_length=total_content_length, + filename=filename, + content_type=content_type, + content_length=content_length, + ) + + @property + def want_form_data_parsed(self) -> bool: + """``True`` if the request method carries content. By default + this is true if a ``Content-Type`` is sent. + + .. versionadded:: 0.8 + """ + return bool(self.environ.get("CONTENT_TYPE")) + + def make_form_data_parser(self) -> FormDataParser: + """Creates the form data parser. Instantiates the + :attr:`form_data_parser_class` with some parameters. + + .. versionadded:: 0.8 + """ + return self.form_data_parser_class( + self._get_file_stream, + self.charset, + self.encoding_errors, + self.max_form_memory_size, + self.max_content_length, + self.parameter_storage_class, + ) + + def _load_form_data(self) -> None: + """Method used internally to retrieve submitted data. After calling + this sets `form` and `files` on the request object to multi dicts + filled with the incoming form data. As a matter of fact the input + stream will be empty afterwards. You can also call this method to + force the parsing of the form data. + + .. versionadded:: 0.8 + """ + # abort early if we have already consumed the stream + if "form" in self.__dict__: + return + + if self.want_form_data_parsed: + parser = self.make_form_data_parser() + data = parser.parse( + self._get_stream_for_parsing(), + self.mimetype, + self.content_length, + self.mimetype_params, + ) + else: + data = ( + self.stream, + self.parameter_storage_class(), + self.parameter_storage_class(), + ) + + # inject the values into the instance dict so that we bypass + # our cached_property non-data descriptor. + d = self.__dict__ + d["stream"], d["form"], d["files"] = data + + def _get_stream_for_parsing(self) -> t.IO[bytes]: + """This is the same as accessing :attr:`stream` with the difference + that if it finds cached data from calling :meth:`get_data` first it + will create a new stream out of the cached data. + + .. versionadded:: 0.9.3 + """ + cached_data = getattr(self, "_cached_data", None) + if cached_data is not None: + return BytesIO(cached_data) + return self.stream + + def close(self) -> None: + """Closes associated resources of this request object. This + closes all file handles explicitly. You can also use the request + object in a with statement which will automatically close it. + + .. versionadded:: 0.9 + """ + files = self.__dict__.get("files") + for _key, value in iter_multi_items(files or ()): + value.close() + + def __enter__(self) -> "Request": + return self + + def __exit__(self, exc_type, exc_value, tb) -> None: # type: ignore + self.close() + + @cached_property + def stream(self) -> t.IO[bytes]: + """ + If the incoming form data was not encoded with a known mimetype + the data is stored unmodified in this stream for consumption. Most + of the time it is a better idea to use :attr:`data` which will give + you that data as a string. The stream only returns the data once. + + Unlike :attr:`input_stream` this stream is properly guarded that you + can't accidentally read past the length of the input. Werkzeug will + internally always refer to this stream to read data which makes it + possible to wrap this object with a stream that does filtering. + + .. versionchanged:: 0.9 + This stream is now always available but might be consumed by the + form parser later on. Previously the stream was only set if no + parsing happened. + """ + if self.shallow: + raise RuntimeError( + "This request was created with 'shallow=True', reading" + " from the input stream is disabled." + ) + + return get_input_stream(self.environ) + + input_stream = environ_property[t.IO[bytes]]( + "wsgi.input", + doc="""The WSGI input stream. + + In general it's a bad idea to use this one because you can + easily read past the boundary. Use the :attr:`stream` + instead.""", + ) + + @cached_property + def data(self) -> bytes: + """ + Contains the incoming request data as string in case it came with + a mimetype Werkzeug does not handle. + """ + return self.get_data(parse_form_data=True) + + @typing.overload + def get_data( # type: ignore + self, + cache: bool = True, + as_text: "te.Literal[False]" = False, + parse_form_data: bool = False, + ) -> bytes: + ... + + @typing.overload + def get_data( + self, + cache: bool = True, + as_text: "te.Literal[True]" = ..., + parse_form_data: bool = False, + ) -> str: + ... + + def get_data( + self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False + ) -> t.Union[bytes, str]: + """This reads the buffered incoming data from the client into one + bytes object. By default this is cached but that behavior can be + changed by setting `cache` to `False`. + + Usually it's a bad idea to call this method without checking the + content length first as a client could send dozens of megabytes or more + to cause memory problems on the server. + + Note that if the form data was already parsed this method will not + return anything as form data parsing does not cache the data like + this method does. To implicitly invoke form data parsing function + set `parse_form_data` to `True`. When this is done the return value + of this method will be an empty string if the form parser handles + the data. This generally is not necessary as if the whole data is + cached (which is the default) the form parser will used the cached + data to parse the form data. Please be generally aware of checking + the content length first in any case before calling this method + to avoid exhausting server memory. + + If `as_text` is set to `True` the return value will be a decoded + string. + + .. versionadded:: 0.9 + """ + rv = getattr(self, "_cached_data", None) + if rv is None: + if parse_form_data: + self._load_form_data() + rv = self.stream.read() + if cache: + self._cached_data = rv + if as_text: + rv = rv.decode(self.charset, self.encoding_errors) + return rv + + @cached_property + def form(self) -> "ImmutableMultiDict[str, str]": + """The form parameters. By default an + :class:`~werkzeug.datastructures.ImmutableMultiDict` + is returned from this function. This can be changed by setting + :attr:`parameter_storage_class` to a different type. This might + be necessary if the order of the form data is important. + + Please keep in mind that file uploads will not end up here, but instead + in the :attr:`files` attribute. + + .. versionchanged:: 0.9 + + Previous to Werkzeug 0.9 this would only contain form data for POST + and PUT requests. + """ + self._load_form_data() + return self.form + + @cached_property + def values(self) -> "CombinedMultiDict[str, str]": + """A :class:`werkzeug.datastructures.CombinedMultiDict` that + combines :attr:`args` and :attr:`form`. + + For GET requests, only ``args`` are present, not ``form``. + + .. versionchanged:: 2.0 + For GET requests, only ``args`` are present, not ``form``. + """ + sources = [self.args] + + if self.method != "GET": + # GET requests can have a body, and some caching proxies + # might not treat that differently than a normal GET + # request, allowing form data to "invisibly" affect the + # cache without indication in the query string / URL. + sources.append(self.form) + + args = [] + + for d in sources: + if not isinstance(d, MultiDict): + d = MultiDict(d) + + args.append(d) + + return CombinedMultiDict(args) + + @cached_property + def files(self) -> "ImmutableMultiDict[str, FileStorage]": + """:class:`~werkzeug.datastructures.MultiDict` object containing + all uploaded files. Each key in :attr:`files` is the name from the + ````. Each value in :attr:`files` is a + Werkzeug :class:`~werkzeug.datastructures.FileStorage` object. + + It basically behaves like a standard file object you know from Python, + with the difference that it also has a + :meth:`~werkzeug.datastructures.FileStorage.save` function that can + store the file on the filesystem. + + Note that :attr:`files` will only contain data if the request method was + POST, PUT or PATCH and the ``

    `` that posted to the request had + ``enctype="multipart/form-data"``. It will be empty otherwise. + + See the :class:`~werkzeug.datastructures.MultiDict` / + :class:`~werkzeug.datastructures.FileStorage` documentation for + more details about the used data structure. + """ + self._load_form_data() + return self.files + + @property + def script_root(self) -> str: + """Alias for :attr:`self.root_path`. ``environ["SCRIPT_ROOT"]`` + without a trailing slash. + """ + return self.root_path + + @cached_property + def url_root(self) -> str: + """Alias for :attr:`root_url`. The URL with scheme, host, and + root path. For example, ``https://example.com/app/``. + """ + return self.root_url + + remote_user = environ_property[str]( + "REMOTE_USER", + doc="""If the server supports user authentication, and the + script is protected, this attribute contains the username the + user has authenticated as.""", + ) + is_multithread = environ_property[bool]( + "wsgi.multithread", + doc="""boolean that is `True` if the application is served by a + multithreaded WSGI server.""", + ) + is_multiprocess = environ_property[bool]( + "wsgi.multiprocess", + doc="""boolean that is `True` if the application is served by a + WSGI server that spawns multiple processes.""", + ) + is_run_once = environ_property[bool]( + "wsgi.run_once", + doc="""boolean that is `True` if the application will be + executed only once in a process lifetime. This is the case for + CGI for example, but it's not guaranteed that the execution only + happens one time.""", + ) + + # JSON + + #: A module or other object that has ``dumps`` and ``loads`` + #: functions that match the API of the built-in :mod:`json` module. + json_module = json + + @property + def json(self) -> t.Optional[t.Any]: + """The parsed JSON data if :attr:`mimetype` indicates JSON + (:mimetype:`application/json`, see :attr:`is_json`). + + Calls :meth:`get_json` with default arguments. + + If the request content type is not ``application/json``, this + will raise a 400 Bad Request error. + + .. versionchanged:: 2.1 + Raise a 400 error if the content type is incorrect. + """ + return self.get_json() + + # Cached values for ``(silent=False, silent=True)``. Initialized + # with sentinel values. + _cached_json: t.Tuple[t.Any, t.Any] = (Ellipsis, Ellipsis) + + def get_json( + self, force: bool = False, silent: bool = False, cache: bool = True + ) -> t.Optional[t.Any]: + """Parse :attr:`data` as JSON. + + If the mimetype does not indicate JSON + (:mimetype:`application/json`, see :attr:`is_json`), or parsing + fails, :meth:`on_json_loading_failed` is called and + its return value is used as the return value. By default this + raises a 400 Bad Request error. + + :param force: Ignore the mimetype and always try to parse JSON. + :param silent: Silence mimetype and parsing errors, and + return ``None`` instead. + :param cache: Store the parsed JSON to return for subsequent + calls. + + .. versionchanged:: 2.1 + Raise a 400 error if the content type is incorrect. + """ + if cache and self._cached_json[silent] is not Ellipsis: + return self._cached_json[silent] + + if not (force or self.is_json): + if not silent: + return self.on_json_loading_failed(None) + else: + return None + + data = self.get_data(cache=cache) + + try: + rv = self.json_module.loads(data) + except ValueError as e: + if silent: + rv = None + + if cache: + normal_rv, _ = self._cached_json + self._cached_json = (normal_rv, rv) + else: + rv = self.on_json_loading_failed(e) + + if cache: + _, silent_rv = self._cached_json + self._cached_json = (rv, silent_rv) + else: + if cache: + self._cached_json = (rv, rv) + + return rv + + def on_json_loading_failed(self, e: t.Optional[ValueError]) -> t.Any: + """Called if :meth:`get_json` fails and isn't silenced. + + If this method returns a value, it is used as the return value + for :meth:`get_json`. The default implementation raises + :exc:`~werkzeug.exceptions.BadRequest`. + + :param e: If parsing failed, this is the exception. It will be + ``None`` if the content type wasn't ``application/json``. + """ + if e is not None: + raise BadRequest(f"Failed to decode JSON object: {e}") + + raise BadRequest( + "Did not attempt to load JSON data because the request" + " Content-Type was not 'application/json'." + ) diff --git a/.vcrunch/Lib/site-packages/werkzeug/wrappers/response.py b/.vcrunch/Lib/site-packages/werkzeug/wrappers/response.py new file mode 100644 index 0000000..7e888cb --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/wrappers/response.py @@ -0,0 +1,877 @@ +import json +import typing +import typing as t +import warnings +from http import HTTPStatus + +from .._internal import _to_bytes +from ..datastructures import Headers +from ..http import remove_entity_headers +from ..sansio.response import Response as _SansIOResponse +from ..urls import iri_to_uri +from ..urls import url_join +from ..utils import cached_property +from ..wsgi import ClosingIterator +from ..wsgi import get_current_url +from werkzeug._internal import _get_environ +from werkzeug.http import generate_etag +from werkzeug.http import http_date +from werkzeug.http import is_resource_modified +from werkzeug.http import parse_etags +from werkzeug.http import parse_range_header +from werkzeug.wsgi import _RangeWrapper + +if t.TYPE_CHECKING: + import typing_extensions as te + from _typeshed.wsgi import StartResponse + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + from .request import Request + + +def _warn_if_string(iterable: t.Iterable) -> None: + """Helper for the response objects to check if the iterable returned + to the WSGI server is not a string. + """ + if isinstance(iterable, str): + warnings.warn( + "Response iterable was set to a string. This will appear to" + " work but means that the server will send the data to the" + " client one character at a time. This is almost never" + " intended behavior, use 'response.data' to assign strings" + " to the response object.", + stacklevel=2, + ) + + +def _iter_encoded( + iterable: t.Iterable[t.Union[str, bytes]], charset: str +) -> t.Iterator[bytes]: + for item in iterable: + if isinstance(item, str): + yield item.encode(charset) + else: + yield item + + +def _clean_accept_ranges(accept_ranges: t.Union[bool, str]) -> str: + if accept_ranges is True: + return "bytes" + elif accept_ranges is False: + return "none" + elif isinstance(accept_ranges, str): + return accept_ranges + raise ValueError("Invalid accept_ranges value") + + +class Response(_SansIOResponse): + """Represents an outgoing WSGI HTTP response with body, status, and + headers. Has properties and methods for using the functionality + defined by various HTTP specs. + + The response body is flexible to support different use cases. The + simple form is passing bytes, or a string which will be encoded as + UTF-8. Passing an iterable of bytes or strings makes this a + streaming response. A generator is particularly useful for building + a CSV file in memory or using SSE (Server Sent Events). A file-like + object is also iterable, although the + :func:`~werkzeug.utils.send_file` helper should be used in that + case. + + The response object is itself a WSGI application callable. When + called (:meth:`__call__`) with ``environ`` and ``start_response``, + it will pass its status and headers to ``start_response`` then + return its body as an iterable. + + .. code-block:: python + + from werkzeug.wrappers.response import Response + + def index(): + return Response("Hello, World!") + + def application(environ, start_response): + path = environ.get("PATH_INFO") or "/" + + if path == "/": + response = index() + else: + response = Response("Not Found", status=404) + + return response(environ, start_response) + + :param response: The data for the body of the response. A string or + bytes, or tuple or list of strings or bytes, for a fixed-length + response, or any other iterable of strings or bytes for a + streaming response. Defaults to an empty body. + :param status: The status code for the response. Either an int, in + which case the default status message is added, or a string in + the form ``{code} {message}``, like ``404 Not Found``. Defaults + to 200. + :param headers: A :class:`~werkzeug.datastructures.Headers` object, + or a list of ``(key, value)`` tuples that will be converted to a + ``Headers`` object. + :param mimetype: The mime type (content type without charset or + other parameters) of the response. If the value starts with + ``text/`` (or matches some other special cases), the charset + will be added to create the ``content_type``. + :param content_type: The full content type of the response. + Overrides building the value from ``mimetype``. + :param direct_passthrough: Pass the response body directly through + as the WSGI iterable. This can be used when the body is a binary + file or other iterator of bytes, to skip some unnecessary + checks. Use :func:`~werkzeug.utils.send_file` instead of setting + this manually. + + .. versionchanged:: 2.0 + Combine ``BaseResponse`` and mixins into a single ``Response`` + class. Using the old classes is deprecated and will be removed + in Werkzeug 2.1. + + .. versionchanged:: 0.5 + The ``direct_passthrough`` parameter was added. + """ + + #: if set to `False` accessing properties on the response object will + #: not try to consume the response iterator and convert it into a list. + #: + #: .. versionadded:: 0.6.2 + #: + #: That attribute was previously called `implicit_seqence_conversion`. + #: (Notice the typo). If you did use this feature, you have to adapt + #: your code to the name change. + implicit_sequence_conversion = True + + #: If a redirect ``Location`` header is a relative URL, make it an + #: absolute URL, including scheme and domain. + #: + #: .. versionchanged:: 2.1 + #: This is disabled by default, so responses will send relative + #: redirects. + #: + #: .. versionadded:: 0.8 + autocorrect_location_header = False + + #: Should this response object automatically set the content-length + #: header if possible? This is true by default. + #: + #: .. versionadded:: 0.8 + automatically_set_content_length = True + + #: The response body to send as the WSGI iterable. A list of strings + #: or bytes represents a fixed-length response, any other iterable + #: is a streaming response. Strings are encoded to bytes as UTF-8. + #: + #: Do not set to a plain string or bytes, that will cause sending + #: the response to be very inefficient as it will iterate one byte + #: at a time. + response: t.Union[t.Iterable[str], t.Iterable[bytes]] + + def __init__( + self, + response: t.Optional[ + t.Union[t.Iterable[bytes], bytes, t.Iterable[str], str] + ] = None, + status: t.Optional[t.Union[int, str, HTTPStatus]] = None, + headers: t.Optional[ + t.Union[ + t.Mapping[str, t.Union[str, int, t.Iterable[t.Union[str, int]]]], + t.Iterable[t.Tuple[str, t.Union[str, int]]], + ] + ] = None, + mimetype: t.Optional[str] = None, + content_type: t.Optional[str] = None, + direct_passthrough: bool = False, + ) -> None: + super().__init__( + status=status, + headers=headers, + mimetype=mimetype, + content_type=content_type, + ) + + #: Pass the response body directly through as the WSGI iterable. + #: This can be used when the body is a binary file or other + #: iterator of bytes, to skip some unnecessary checks. Use + #: :func:`~werkzeug.utils.send_file` instead of setting this + #: manually. + self.direct_passthrough = direct_passthrough + self._on_close: t.List[t.Callable[[], t.Any]] = [] + + # we set the response after the headers so that if a class changes + # the charset attribute, the data is set in the correct charset. + if response is None: + self.response = [] + elif isinstance(response, (str, bytes, bytearray)): + self.set_data(response) + else: + self.response = response + + def call_on_close(self, func: t.Callable[[], t.Any]) -> t.Callable[[], t.Any]: + """Adds a function to the internal list of functions that should + be called as part of closing down the response. Since 0.7 this + function also returns the function that was passed so that this + can be used as a decorator. + + .. versionadded:: 0.6 + """ + self._on_close.append(func) + return func + + def __repr__(self) -> str: + if self.is_sequence: + body_info = f"{sum(map(len, self.iter_encoded()))} bytes" + else: + body_info = "streamed" if self.is_streamed else "likely-streamed" + return f"<{type(self).__name__} {body_info} [{self.status}]>" + + @classmethod + def force_type( + cls, response: "Response", environ: t.Optional["WSGIEnvironment"] = None + ) -> "Response": + """Enforce that the WSGI response is a response object of the current + type. Werkzeug will use the :class:`Response` internally in many + situations like the exceptions. If you call :meth:`get_response` on an + exception you will get back a regular :class:`Response` object, even + if you are using a custom subclass. + + This method can enforce a given response type, and it will also + convert arbitrary WSGI callables into response objects if an environ + is provided:: + + # convert a Werkzeug response object into an instance of the + # MyResponseClass subclass. + response = MyResponseClass.force_type(response) + + # convert any WSGI application into a response object + response = MyResponseClass.force_type(response, environ) + + This is especially useful if you want to post-process responses in + the main dispatcher and use functionality provided by your subclass. + + Keep in mind that this will modify response objects in place if + possible! + + :param response: a response object or wsgi application. + :param environ: a WSGI environment object. + :return: a response object. + """ + if not isinstance(response, Response): + if environ is None: + raise TypeError( + "cannot convert WSGI application into response" + " objects without an environ" + ) + + from ..test import run_wsgi_app + + response = Response(*run_wsgi_app(response, environ)) + + response.__class__ = cls + return response + + @classmethod + def from_app( + cls, app: "WSGIApplication", environ: "WSGIEnvironment", buffered: bool = False + ) -> "Response": + """Create a new response object from an application output. This + works best if you pass it an application that returns a generator all + the time. Sometimes applications may use the `write()` callable + returned by the `start_response` function. This tries to resolve such + edge cases automatically. But if you don't get the expected output + you should set `buffered` to `True` which enforces buffering. + + :param app: the WSGI application to execute. + :param environ: the WSGI environment to execute against. + :param buffered: set to `True` to enforce buffering. + :return: a response object. + """ + from ..test import run_wsgi_app + + return cls(*run_wsgi_app(app, environ, buffered)) + + @typing.overload + def get_data(self, as_text: "te.Literal[False]" = False) -> bytes: + ... + + @typing.overload + def get_data(self, as_text: "te.Literal[True]") -> str: + ... + + def get_data(self, as_text: bool = False) -> t.Union[bytes, str]: + """The string representation of the response body. Whenever you call + this property the response iterable is encoded and flattened. This + can lead to unwanted behavior if you stream big data. + + This behavior can be disabled by setting + :attr:`implicit_sequence_conversion` to `False`. + + If `as_text` is set to `True` the return value will be a decoded + string. + + .. versionadded:: 0.9 + """ + self._ensure_sequence() + rv = b"".join(self.iter_encoded()) + + if as_text: + return rv.decode(self.charset) + + return rv + + def set_data(self, value: t.Union[bytes, str]) -> None: + """Sets a new string as response. The value must be a string or + bytes. If a string is set it's encoded to the charset of the + response (utf-8 by default). + + .. versionadded:: 0.9 + """ + # if a string is set, it's encoded directly so that we + # can set the content length + if isinstance(value, str): + value = value.encode(self.charset) + else: + value = bytes(value) + self.response = [value] + if self.automatically_set_content_length: + self.headers["Content-Length"] = str(len(value)) + + data = property( + get_data, + set_data, + doc="A descriptor that calls :meth:`get_data` and :meth:`set_data`.", + ) + + def calculate_content_length(self) -> t.Optional[int]: + """Returns the content length if available or `None` otherwise.""" + try: + self._ensure_sequence() + except RuntimeError: + return None + return sum(len(x) for x in self.iter_encoded()) + + def _ensure_sequence(self, mutable: bool = False) -> None: + """This method can be called by methods that need a sequence. If + `mutable` is true, it will also ensure that the response sequence + is a standard Python list. + + .. versionadded:: 0.6 + """ + if self.is_sequence: + # if we need a mutable object, we ensure it's a list. + if mutable and not isinstance(self.response, list): + self.response = list(self.response) # type: ignore + return + if self.direct_passthrough: + raise RuntimeError( + "Attempted implicit sequence conversion but the" + " response object is in direct passthrough mode." + ) + if not self.implicit_sequence_conversion: + raise RuntimeError( + "The response object required the iterable to be a" + " sequence, but the implicit conversion was disabled." + " Call make_sequence() yourself." + ) + self.make_sequence() + + def make_sequence(self) -> None: + """Converts the response iterator in a list. By default this happens + automatically if required. If `implicit_sequence_conversion` is + disabled, this method is not automatically called and some properties + might raise exceptions. This also encodes all the items. + + .. versionadded:: 0.6 + """ + if not self.is_sequence: + # if we consume an iterable we have to ensure that the close + # method of the iterable is called if available when we tear + # down the response + close = getattr(self.response, "close", None) + self.response = list(self.iter_encoded()) + if close is not None: + self.call_on_close(close) + + def iter_encoded(self) -> t.Iterator[bytes]: + """Iter the response encoded with the encoding of the response. + If the response object is invoked as WSGI application the return + value of this method is used as application iterator unless + :attr:`direct_passthrough` was activated. + """ + if __debug__: + _warn_if_string(self.response) + # Encode in a separate function so that self.response is fetched + # early. This allows us to wrap the response with the return + # value from get_app_iter or iter_encoded. + return _iter_encoded(self.response, self.charset) + + @property + def is_streamed(self) -> bool: + """If the response is streamed (the response is not an iterable with + a length information) this property is `True`. In this case streamed + means that there is no information about the number of iterations. + This is usually `True` if a generator is passed to the response object. + + This is useful for checking before applying some sort of post + filtering that should not take place for streamed responses. + """ + try: + len(self.response) # type: ignore + except (TypeError, AttributeError): + return True + return False + + @property + def is_sequence(self) -> bool: + """If the iterator is buffered, this property will be `True`. A + response object will consider an iterator to be buffered if the + response attribute is a list or tuple. + + .. versionadded:: 0.6 + """ + return isinstance(self.response, (tuple, list)) + + def close(self) -> None: + """Close the wrapped response if possible. You can also use the object + in a with statement which will automatically close it. + + .. versionadded:: 0.9 + Can now be used in a with statement. + """ + if hasattr(self.response, "close"): + self.response.close() # type: ignore + for func in self._on_close: + func() + + def __enter__(self) -> "Response": + return self + + def __exit__(self, exc_type, exc_value, tb): # type: ignore + self.close() + + def freeze(self) -> None: + """Make the response object ready to be pickled. Does the + following: + + * Buffer the response into a list, ignoring + :attr:`implicity_sequence_conversion` and + :attr:`direct_passthrough`. + * Set the ``Content-Length`` header. + * Generate an ``ETag`` header if one is not already set. + + .. versionchanged:: 2.1 + Removed the ``no_etag`` parameter. + + .. versionchanged:: 2.0 + An ``ETag`` header is added, the ``no_etag`` parameter is + deprecated and will be removed in Werkzeug 2.1. + + .. versionchanged:: 0.6 + The ``Content-Length`` header is set. + """ + # Always freeze the encoded response body, ignore + # implicit_sequence_conversion and direct_passthrough. + self.response = list(self.iter_encoded()) + self.headers["Content-Length"] = str(sum(map(len, self.response))) + self.add_etag() + + def get_wsgi_headers(self, environ: "WSGIEnvironment") -> Headers: + """This is automatically called right before the response is started + and returns headers modified for the given environment. It returns a + copy of the headers from the response with some modifications applied + if necessary. + + For example the location header (if present) is joined with the root + URL of the environment. Also the content length is automatically set + to zero here for certain status codes. + + .. versionchanged:: 0.6 + Previously that function was called `fix_headers` and modified + the response object in place. Also since 0.6, IRIs in location + and content-location headers are handled properly. + + Also starting with 0.6, Werkzeug will attempt to set the content + length if it is able to figure it out on its own. This is the + case if all the strings in the response iterable are already + encoded and the iterable is buffered. + + :param environ: the WSGI environment of the request. + :return: returns a new :class:`~werkzeug.datastructures.Headers` + object. + """ + headers = Headers(self.headers) + location: t.Optional[str] = None + content_location: t.Optional[str] = None + content_length: t.Optional[t.Union[str, int]] = None + status = self.status_code + + # iterate over the headers to find all values in one go. Because + # get_wsgi_headers is used each response that gives us a tiny + # speedup. + for key, value in headers: + ikey = key.lower() + if ikey == "location": + location = value + elif ikey == "content-location": + content_location = value + elif ikey == "content-length": + content_length = value + + # make sure the location header is an absolute URL + if location is not None: + old_location = location + if isinstance(location, str): + # Safe conversion is necessary here as we might redirect + # to a broken URI scheme (for instance itms-services). + location = iri_to_uri(location, safe_conversion=True) + + if self.autocorrect_location_header: + current_url = get_current_url(environ, strip_querystring=True) + if isinstance(current_url, str): + current_url = iri_to_uri(current_url) + location = url_join(current_url, location) + if location != old_location: + headers["Location"] = location + + # make sure the content location is a URL + if content_location is not None and isinstance(content_location, str): + headers["Content-Location"] = iri_to_uri(content_location) + + if 100 <= status < 200 or status == 204: + # Per section 3.3.2 of RFC 7230, "a server MUST NOT send a + # Content-Length header field in any response with a status + # code of 1xx (Informational) or 204 (No Content)." + headers.remove("Content-Length") + elif status == 304: + remove_entity_headers(headers) + + # if we can determine the content length automatically, we + # should try to do that. But only if this does not involve + # flattening the iterator or encoding of strings in the + # response. We however should not do that if we have a 304 + # response. + if ( + self.automatically_set_content_length + and self.is_sequence + and content_length is None + and status not in (204, 304) + and not (100 <= status < 200) + ): + try: + content_length = sum(len(_to_bytes(x, "ascii")) for x in self.response) + except UnicodeError: + # Something other than bytes, can't safely figure out + # the length of the response. + pass + else: + headers["Content-Length"] = str(content_length) + + return headers + + def get_app_iter(self, environ: "WSGIEnvironment") -> t.Iterable[bytes]: + """Returns the application iterator for the given environ. Depending + on the request method and the current status code the return value + might be an empty response rather than the one from the response. + + If the request method is `HEAD` or the status code is in a range + where the HTTP specification requires an empty response, an empty + iterable is returned. + + .. versionadded:: 0.6 + + :param environ: the WSGI environment of the request. + :return: a response iterable. + """ + status = self.status_code + if ( + environ["REQUEST_METHOD"] == "HEAD" + or 100 <= status < 200 + or status in (204, 304) + ): + iterable: t.Iterable[bytes] = () + elif self.direct_passthrough: + if __debug__: + _warn_if_string(self.response) + return self.response # type: ignore + else: + iterable = self.iter_encoded() + return ClosingIterator(iterable, self.close) + + def get_wsgi_response( + self, environ: "WSGIEnvironment" + ) -> t.Tuple[t.Iterable[bytes], str, t.List[t.Tuple[str, str]]]: + """Returns the final WSGI response as tuple. The first item in + the tuple is the application iterator, the second the status and + the third the list of headers. The response returned is created + specially for the given environment. For example if the request + method in the WSGI environment is ``'HEAD'`` the response will + be empty and only the headers and status code will be present. + + .. versionadded:: 0.6 + + :param environ: the WSGI environment of the request. + :return: an ``(app_iter, status, headers)`` tuple. + """ + headers = self.get_wsgi_headers(environ) + app_iter = self.get_app_iter(environ) + return app_iter, self.status, headers.to_wsgi_list() + + def __call__( + self, environ: "WSGIEnvironment", start_response: "StartResponse" + ) -> t.Iterable[bytes]: + """Process this response as WSGI application. + + :param environ: the WSGI environment. + :param start_response: the response callable provided by the WSGI + server. + :return: an application iterator + """ + app_iter, status, headers = self.get_wsgi_response(environ) + start_response(status, headers) + return app_iter + + # JSON + + #: A module or other object that has ``dumps`` and ``loads`` + #: functions that match the API of the built-in :mod:`json` module. + json_module = json + + @property + def json(self) -> t.Optional[t.Any]: + """The parsed JSON data if :attr:`mimetype` indicates JSON + (:mimetype:`application/json`, see :attr:`is_json`). + + Calls :meth:`get_json` with default arguments. + """ + return self.get_json() + + def get_json(self, force: bool = False, silent: bool = False) -> t.Optional[t.Any]: + """Parse :attr:`data` as JSON. Useful during testing. + + If the mimetype does not indicate JSON + (:mimetype:`application/json`, see :attr:`is_json`), this + returns ``None``. + + Unlike :meth:`Request.get_json`, the result is not cached. + + :param force: Ignore the mimetype and always try to parse JSON. + :param silent: Silence parsing errors and return ``None`` + instead. + """ + if not (force or self.is_json): + return None + + data = self.get_data() + + try: + return self.json_module.loads(data) + except ValueError: + if not silent: + raise + + return None + + # Stream + + @cached_property + def stream(self) -> "ResponseStream": + """The response iterable as write-only stream.""" + return ResponseStream(self) + + def _wrap_range_response(self, start: int, length: int) -> None: + """Wrap existing Response in case of Range Request context.""" + if self.status_code == 206: + self.response = _RangeWrapper(self.response, start, length) # type: ignore + + def _is_range_request_processable(self, environ: "WSGIEnvironment") -> bool: + """Return ``True`` if `Range` header is present and if underlying + resource is considered unchanged when compared with `If-Range` header. + """ + return ( + "HTTP_IF_RANGE" not in environ + or not is_resource_modified( + environ, + self.headers.get("etag"), + None, + self.headers.get("last-modified"), + ignore_if_range=False, + ) + ) and "HTTP_RANGE" in environ + + def _process_range_request( + self, + environ: "WSGIEnvironment", + complete_length: t.Optional[int] = None, + accept_ranges: t.Optional[t.Union[bool, str]] = None, + ) -> bool: + """Handle Range Request related headers (RFC7233). If `Accept-Ranges` + header is valid, and Range Request is processable, we set the headers + as described by the RFC, and wrap the underlying response in a + RangeWrapper. + + Returns ``True`` if Range Request can be fulfilled, ``False`` otherwise. + + :raises: :class:`~werkzeug.exceptions.RequestedRangeNotSatisfiable` + if `Range` header could not be parsed or satisfied. + + .. versionchanged:: 2.0 + Returns ``False`` if the length is 0. + """ + from ..exceptions import RequestedRangeNotSatisfiable + + if ( + accept_ranges is None + or complete_length is None + or complete_length == 0 + or not self._is_range_request_processable(environ) + ): + return False + + parsed_range = parse_range_header(environ.get("HTTP_RANGE")) + + if parsed_range is None: + raise RequestedRangeNotSatisfiable(complete_length) + + range_tuple = parsed_range.range_for_length(complete_length) + content_range_header = parsed_range.to_content_range_header(complete_length) + + if range_tuple is None or content_range_header is None: + raise RequestedRangeNotSatisfiable(complete_length) + + content_length = range_tuple[1] - range_tuple[0] + self.headers["Content-Length"] = content_length + self.headers["Accept-Ranges"] = accept_ranges + self.content_range = content_range_header # type: ignore + self.status_code = 206 + self._wrap_range_response(range_tuple[0], content_length) + return True + + def make_conditional( + self, + request_or_environ: t.Union["WSGIEnvironment", "Request"], + accept_ranges: t.Union[bool, str] = False, + complete_length: t.Optional[int] = None, + ) -> "Response": + """Make the response conditional to the request. This method works + best if an etag was defined for the response already. The `add_etag` + method can be used to do that. If called without etag just the date + header is set. + + This does nothing if the request method in the request or environ is + anything but GET or HEAD. + + For optimal performance when handling range requests, it's recommended + that your response data object implements `seekable`, `seek` and `tell` + methods as described by :py:class:`io.IOBase`. Objects returned by + :meth:`~werkzeug.wsgi.wrap_file` automatically implement those methods. + + It does not remove the body of the response because that's something + the :meth:`__call__` function does for us automatically. + + Returns self so that you can do ``return resp.make_conditional(req)`` + but modifies the object in-place. + + :param request_or_environ: a request object or WSGI environment to be + used to make the response conditional + against. + :param accept_ranges: This parameter dictates the value of + `Accept-Ranges` header. If ``False`` (default), + the header is not set. If ``True``, it will be set + to ``"bytes"``. If ``None``, it will be set to + ``"none"``. If it's a string, it will use this + value. + :param complete_length: Will be used only in valid Range Requests. + It will set `Content-Range` complete length + value and compute `Content-Length` real value. + This parameter is mandatory for successful + Range Requests completion. + :raises: :class:`~werkzeug.exceptions.RequestedRangeNotSatisfiable` + if `Range` header could not be parsed or satisfied. + + .. versionchanged:: 2.0 + Range processing is skipped if length is 0 instead of + raising a 416 Range Not Satisfiable error. + """ + environ = _get_environ(request_or_environ) + if environ["REQUEST_METHOD"] in ("GET", "HEAD"): + # if the date is not in the headers, add it now. We however + # will not override an already existing header. Unfortunately + # this header will be overridden by many WSGI servers including + # wsgiref. + if "date" not in self.headers: + self.headers["Date"] = http_date() + accept_ranges = _clean_accept_ranges(accept_ranges) + is206 = self._process_range_request(environ, complete_length, accept_ranges) + if not is206 and not is_resource_modified( + environ, + self.headers.get("etag"), + None, + self.headers.get("last-modified"), + ): + if parse_etags(environ.get("HTTP_IF_MATCH")): + self.status_code = 412 + else: + self.status_code = 304 + if ( + self.automatically_set_content_length + and "content-length" not in self.headers + ): + length = self.calculate_content_length() + if length is not None: + self.headers["Content-Length"] = length + return self + + def add_etag(self, overwrite: bool = False, weak: bool = False) -> None: + """Add an etag for the current response if there is none yet. + + .. versionchanged:: 2.0 + SHA-1 is used to generate the value. MD5 may not be + available in some environments. + """ + if overwrite or "etag" not in self.headers: + self.set_etag(generate_etag(self.get_data()), weak) + + +class ResponseStream: + """A file descriptor like object used by :meth:`Response.stream` to + represent the body of the stream. It directly pushes into the + response iterable of the response object. + """ + + mode = "wb+" + + def __init__(self, response: Response): + self.response = response + self.closed = False + + def write(self, value: bytes) -> int: + if self.closed: + raise ValueError("I/O operation on closed file") + self.response._ensure_sequence(mutable=True) + self.response.response.append(value) # type: ignore + self.response.headers.pop("Content-Length", None) + return len(value) + + def writelines(self, seq: t.Iterable[bytes]) -> None: + for item in seq: + self.write(item) + + def close(self) -> None: + self.closed = True + + def flush(self) -> None: + if self.closed: + raise ValueError("I/O operation on closed file") + + def isatty(self) -> bool: + if self.closed: + raise ValueError("I/O operation on closed file") + return False + + def tell(self) -> int: + self.response._ensure_sequence() + return sum(map(len, self.response.response)) + + @property + def encoding(self) -> str: + return self.response.charset diff --git a/.vcrunch/Lib/site-packages/werkzeug/wsgi.py b/.vcrunch/Lib/site-packages/werkzeug/wsgi.py new file mode 100644 index 0000000..24ece0b --- /dev/null +++ b/.vcrunch/Lib/site-packages/werkzeug/wsgi.py @@ -0,0 +1,1020 @@ +import io +import re +import typing as t +import warnings +from functools import partial +from functools import update_wrapper +from itertools import chain + +from ._internal import _make_encode_wrapper +from ._internal import _to_bytes +from ._internal import _to_str +from .sansio import utils as _sansio_utils +from .sansio.utils import host_is_trusted # noqa: F401 # Imported as part of API +from .urls import _URLTuple +from .urls import uri_to_iri +from .urls import url_join +from .urls import url_parse +from .urls import url_quote + +if t.TYPE_CHECKING: + from _typeshed.wsgi import WSGIApplication + from _typeshed.wsgi import WSGIEnvironment + + +def responder(f: t.Callable[..., "WSGIApplication"]) -> "WSGIApplication": + """Marks a function as responder. Decorate a function with it and it + will automatically call the return value as WSGI application. + + Example:: + + @responder + def application(environ, start_response): + return Response('Hello World!') + """ + return update_wrapper(lambda *a: f(*a)(*a[-2:]), f) + + +def get_current_url( + environ: "WSGIEnvironment", + root_only: bool = False, + strip_querystring: bool = False, + host_only: bool = False, + trusted_hosts: t.Optional[t.Iterable[str]] = None, +) -> str: + """Recreate the URL for a request from the parts in a WSGI + environment. + + The URL is an IRI, not a URI, so it may contain Unicode characters. + Use :func:`~werkzeug.urls.iri_to_uri` to convert it to ASCII. + + :param environ: The WSGI environment to get the URL parts from. + :param root_only: Only build the root path, don't include the + remaining path or query string. + :param strip_querystring: Don't include the query string. + :param host_only: Only build the scheme and host. + :param trusted_hosts: A list of trusted host names to validate the + host against. + """ + parts = { + "scheme": environ["wsgi.url_scheme"], + "host": get_host(environ, trusted_hosts), + } + + if not host_only: + parts["root_path"] = environ.get("SCRIPT_NAME", "") + + if not root_only: + parts["path"] = environ.get("PATH_INFO", "") + + if not strip_querystring: + parts["query_string"] = environ.get("QUERY_STRING", "").encode("latin1") + + return _sansio_utils.get_current_url(**parts) + + +def _get_server( + environ: "WSGIEnvironment", +) -> t.Optional[t.Tuple[str, t.Optional[int]]]: + name = environ.get("SERVER_NAME") + + if name is None: + return None + + try: + port: t.Optional[int] = int(environ.get("SERVER_PORT", None)) + except (TypeError, ValueError): + # unix socket + port = None + + return name, port + + +def get_host( + environ: "WSGIEnvironment", trusted_hosts: t.Optional[t.Iterable[str]] = None +) -> str: + """Return the host for the given WSGI environment. + + The ``Host`` header is preferred, then ``SERVER_NAME`` if it's not + set. The returned host will only contain the port if it is different + than the standard port for the protocol. + + Optionally, verify that the host is trusted using + :func:`host_is_trusted` and raise a + :exc:`~werkzeug.exceptions.SecurityError` if it is not. + + :param environ: A WSGI environment dict. + :param trusted_hosts: A list of trusted host names. + + :return: Host, with port if necessary. + :raise ~werkzeug.exceptions.SecurityError: If the host is not + trusted. + """ + return _sansio_utils.get_host( + environ["wsgi.url_scheme"], + environ.get("HTTP_HOST"), + _get_server(environ), + trusted_hosts, + ) + + +def get_content_length(environ: "WSGIEnvironment") -> t.Optional[int]: + """Returns the content length from the WSGI environment as + integer. If it's not available or chunked transfer encoding is used, + ``None`` is returned. + + .. versionadded:: 0.9 + + :param environ: the WSGI environ to fetch the content length from. + """ + return _sansio_utils.get_content_length( + http_content_length=environ.get("CONTENT_LENGTH"), + http_transfer_encoding=environ.get("HTTP_TRANSFER_ENCODING", ""), + ) + + +def get_input_stream( + environ: "WSGIEnvironment", safe_fallback: bool = True +) -> t.IO[bytes]: + """Returns the input stream from the WSGI environment and wraps it + in the most sensible way possible. The stream returned is not the + raw WSGI stream in most cases but one that is safe to read from + without taking into account the content length. + + If content length is not set, the stream will be empty for safety reasons. + If the WSGI server supports chunked or infinite streams, it should set + the ``wsgi.input_terminated`` value in the WSGI environ to indicate that. + + .. versionadded:: 0.9 + + :param environ: the WSGI environ to fetch the stream from. + :param safe_fallback: use an empty stream as a safe fallback when the + content length is not set. Disabling this allows infinite streams, + which can be a denial-of-service risk. + """ + stream = t.cast(t.IO[bytes], environ["wsgi.input"]) + content_length = get_content_length(environ) + + # A wsgi extension that tells us if the input is terminated. In + # that case we return the stream unchanged as we know we can safely + # read it until the end. + if environ.get("wsgi.input_terminated"): + return stream + + # If the request doesn't specify a content length, returning the stream is + # potentially dangerous because it could be infinite, malicious or not. If + # safe_fallback is true, return an empty stream instead for safety. + if content_length is None: + return io.BytesIO() if safe_fallback else stream + + # Otherwise limit the stream to the content length + return t.cast(t.IO[bytes], LimitedStream(stream, content_length)) + + +def get_query_string(environ: "WSGIEnvironment") -> str: + """Returns the ``QUERY_STRING`` from the WSGI environment. This also + takes care of the WSGI decoding dance. The string returned will be + restricted to ASCII characters. + + :param environ: WSGI environment to get the query string from. + + .. deprecated:: 2.2 + Will be removed in Werkzeug 2.3. + + .. versionadded:: 0.9 + """ + warnings.warn( + "'get_query_string' is deprecated and will be removed in Werkzeug 2.3.", + DeprecationWarning, + stacklevel=2, + ) + qs = environ.get("QUERY_STRING", "").encode("latin1") + # QUERY_STRING really should be ascii safe but some browsers + # will send us some unicode stuff (I am looking at you IE). + # In that case we want to urllib quote it badly. + return url_quote(qs, safe=":&%=+$!*'(),") + + +def get_path_info( + environ: "WSGIEnvironment", charset: str = "utf-8", errors: str = "replace" +) -> str: + """Return the ``PATH_INFO`` from the WSGI environment and decode it + unless ``charset`` is ``None``. + + :param environ: WSGI environment to get the path from. + :param charset: The charset for the path info, or ``None`` if no + decoding should be performed. + :param errors: The decoding error handling. + + .. versionadded:: 0.9 + """ + path = environ.get("PATH_INFO", "").encode("latin1") + return _to_str(path, charset, errors, allow_none_charset=True) # type: ignore + + +def get_script_name( + environ: "WSGIEnvironment", charset: str = "utf-8", errors: str = "replace" +) -> str: + """Return the ``SCRIPT_NAME`` from the WSGI environment and decode + it unless `charset` is set to ``None``. + + :param environ: WSGI environment to get the path from. + :param charset: The charset for the path, or ``None`` if no decoding + should be performed. + :param errors: The decoding error handling. + + .. deprecated:: 2.2 + Will be removed in Werkzeug 2.3. + + .. versionadded:: 0.9 + """ + warnings.warn( + "'get_script_name' is deprecated and will be removed in Werkzeug 2.3.", + DeprecationWarning, + stacklevel=2, + ) + path = environ.get("SCRIPT_NAME", "").encode("latin1") + return _to_str(path, charset, errors, allow_none_charset=True) # type: ignore + + +def pop_path_info( + environ: "WSGIEnvironment", charset: str = "utf-8", errors: str = "replace" +) -> t.Optional[str]: + """Removes and returns the next segment of `PATH_INFO`, pushing it onto + `SCRIPT_NAME`. Returns `None` if there is nothing left on `PATH_INFO`. + + If the `charset` is set to `None` bytes are returned. + + If there are empty segments (``'/foo//bar``) these are ignored but + properly pushed to the `SCRIPT_NAME`: + + >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'} + >>> pop_path_info(env) + 'a' + >>> env['SCRIPT_NAME'] + '/foo/a' + >>> pop_path_info(env) + 'b' + >>> env['SCRIPT_NAME'] + '/foo/a/b' + + .. deprecated:: 2.2 + Will be removed in Werkzeug 2.3. + + .. versionadded:: 0.5 + + .. versionchanged:: 0.9 + The path is now decoded and a charset and encoding + parameter can be provided. + + :param environ: the WSGI environment that is modified. + :param charset: The ``encoding`` parameter passed to + :func:`bytes.decode`. + :param errors: The ``errors`` paramater passed to + :func:`bytes.decode`. + """ + warnings.warn( + "'pop_path_info' is deprecated and will be removed in Werkzeug 2.3.", + DeprecationWarning, + stacklevel=2, + ) + + path = environ.get("PATH_INFO") + if not path: + return None + + script_name = environ.get("SCRIPT_NAME", "") + + # shift multiple leading slashes over + old_path = path + path = path.lstrip("/") + if path != old_path: + script_name += "/" * (len(old_path) - len(path)) + + if "/" not in path: + environ["PATH_INFO"] = "" + environ["SCRIPT_NAME"] = script_name + path + rv = path.encode("latin1") + else: + segment, path = path.split("/", 1) + environ["PATH_INFO"] = f"/{path}" + environ["SCRIPT_NAME"] = script_name + segment + rv = segment.encode("latin1") + + return _to_str(rv, charset, errors, allow_none_charset=True) # type: ignore + + +def peek_path_info( + environ: "WSGIEnvironment", charset: str = "utf-8", errors: str = "replace" +) -> t.Optional[str]: + """Returns the next segment on the `PATH_INFO` or `None` if there + is none. Works like :func:`pop_path_info` without modifying the + environment: + + >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'} + >>> peek_path_info(env) + 'a' + >>> peek_path_info(env) + 'a' + + If the `charset` is set to `None` bytes are returned. + + .. deprecated:: 2.2 + Will be removed in Werkzeug 2.3. + + .. versionadded:: 0.5 + + .. versionchanged:: 0.9 + The path is now decoded and a charset and encoding + parameter can be provided. + + :param environ: the WSGI environment that is checked. + """ + warnings.warn( + "'peek_path_info' is deprecated and will be removed in Werkzeug 2.3.", + DeprecationWarning, + stacklevel=2, + ) + + segments = environ.get("PATH_INFO", "").lstrip("/").split("/", 1) + if segments: + return _to_str( # type: ignore + segments[0].encode("latin1"), charset, errors, allow_none_charset=True + ) + return None + + +def extract_path_info( + environ_or_baseurl: t.Union[str, "WSGIEnvironment"], + path_or_url: t.Union[str, _URLTuple], + charset: str = "utf-8", + errors: str = "werkzeug.url_quote", + collapse_http_schemes: bool = True, +) -> t.Optional[str]: + """Extracts the path info from the given URL (or WSGI environment) and + path. The path info returned is a string. The URLs might also be IRIs. + + If the path info could not be determined, `None` is returned. + + Some examples: + + >>> extract_path_info('http://example.com/app', '/app/hello') + '/hello' + >>> extract_path_info('http://example.com/app', + ... 'https://example.com/app/hello') + '/hello' + >>> extract_path_info('http://example.com/app', + ... 'https://example.com/app/hello', + ... collapse_http_schemes=False) is None + True + + Instead of providing a base URL you can also pass a WSGI environment. + + :param environ_or_baseurl: a WSGI environment dict, a base URL or + base IRI. This is the root of the + application. + :param path_or_url: an absolute path from the server root, a + relative path (in which case it's the path info) + or a full URL. + :param charset: the charset for byte data in URLs + :param errors: the error handling on decode + :param collapse_http_schemes: if set to `False` the algorithm does + not assume that http and https on the + same server point to the same + resource. + + .. deprecated:: 2.2 + Will be removed in Werkzeug 2.3. + + .. versionchanged:: 0.15 + The ``errors`` parameter defaults to leaving invalid bytes + quoted instead of replacing them. + + .. versionadded:: 0.6 + + """ + warnings.warn( + "'extract_path_info' is deprecated and will be removed in Werkzeug 2.3.", + DeprecationWarning, + stacklevel=2, + ) + + def _normalize_netloc(scheme: str, netloc: str) -> str: + parts = netloc.split("@", 1)[-1].split(":", 1) + port: t.Optional[str] + + if len(parts) == 2: + netloc, port = parts + if (scheme == "http" and port == "80") or ( + scheme == "https" and port == "443" + ): + port = None + else: + netloc = parts[0] + port = None + + if port is not None: + netloc += f":{port}" + + return netloc + + # make sure whatever we are working on is a IRI and parse it + path = uri_to_iri(path_or_url, charset, errors) + if isinstance(environ_or_baseurl, dict): + environ_or_baseurl = get_current_url(environ_or_baseurl, root_only=True) + base_iri = uri_to_iri(environ_or_baseurl, charset, errors) + base_scheme, base_netloc, base_path = url_parse(base_iri)[:3] + cur_scheme, cur_netloc, cur_path = url_parse(url_join(base_iri, path))[:3] + + # normalize the network location + base_netloc = _normalize_netloc(base_scheme, base_netloc) + cur_netloc = _normalize_netloc(cur_scheme, cur_netloc) + + # is that IRI even on a known HTTP scheme? + if collapse_http_schemes: + for scheme in base_scheme, cur_scheme: + if scheme not in ("http", "https"): + return None + else: + if not (base_scheme in ("http", "https") and base_scheme == cur_scheme): + return None + + # are the netlocs compatible? + if base_netloc != cur_netloc: + return None + + # are we below the application path? + base_path = base_path.rstrip("/") + if not cur_path.startswith(base_path): + return None + + return f"/{cur_path[len(base_path) :].lstrip('/')}" + + +class ClosingIterator: + """The WSGI specification requires that all middlewares and gateways + respect the `close` callback of the iterable returned by the application. + Because it is useful to add another close action to a returned iterable + and adding a custom iterable is a boring task this class can be used for + that:: + + return ClosingIterator(app(environ, start_response), [cleanup_session, + cleanup_locals]) + + If there is just one close function it can be passed instead of the list. + + A closing iterator is not needed if the application uses response objects + and finishes the processing if the response is started:: + + try: + return response(environ, start_response) + finally: + cleanup_session() + cleanup_locals() + """ + + def __init__( + self, + iterable: t.Iterable[bytes], + callbacks: t.Optional[ + t.Union[t.Callable[[], None], t.Iterable[t.Callable[[], None]]] + ] = None, + ) -> None: + iterator = iter(iterable) + self._next = t.cast(t.Callable[[], bytes], partial(next, iterator)) + if callbacks is None: + callbacks = [] + elif callable(callbacks): + callbacks = [callbacks] + else: + callbacks = list(callbacks) + iterable_close = getattr(iterable, "close", None) + if iterable_close: + callbacks.insert(0, iterable_close) + self._callbacks = callbacks + + def __iter__(self) -> "ClosingIterator": + return self + + def __next__(self) -> bytes: + return self._next() + + def close(self) -> None: + for callback in self._callbacks: + callback() + + +def wrap_file( + environ: "WSGIEnvironment", file: t.IO[bytes], buffer_size: int = 8192 +) -> t.Iterable[bytes]: + """Wraps a file. This uses the WSGI server's file wrapper if available + or otherwise the generic :class:`FileWrapper`. + + .. versionadded:: 0.5 + + If the file wrapper from the WSGI server is used it's important to not + iterate over it from inside the application but to pass it through + unchanged. If you want to pass out a file wrapper inside a response + object you have to set :attr:`Response.direct_passthrough` to `True`. + + More information about file wrappers are available in :pep:`333`. + + :param file: a :class:`file`-like object with a :meth:`~file.read` method. + :param buffer_size: number of bytes for one iteration. + """ + return environ.get("wsgi.file_wrapper", FileWrapper)( # type: ignore + file, buffer_size + ) + + +class FileWrapper: + """This class can be used to convert a :class:`file`-like object into + an iterable. It yields `buffer_size` blocks until the file is fully + read. + + You should not use this class directly but rather use the + :func:`wrap_file` function that uses the WSGI server's file wrapper + support if it's available. + + .. versionadded:: 0.5 + + If you're using this object together with a :class:`Response` you have + to use the `direct_passthrough` mode. + + :param file: a :class:`file`-like object with a :meth:`~file.read` method. + :param buffer_size: number of bytes for one iteration. + """ + + def __init__(self, file: t.IO[bytes], buffer_size: int = 8192) -> None: + self.file = file + self.buffer_size = buffer_size + + def close(self) -> None: + if hasattr(self.file, "close"): + self.file.close() + + def seekable(self) -> bool: + if hasattr(self.file, "seekable"): + return self.file.seekable() + if hasattr(self.file, "seek"): + return True + return False + + def seek(self, *args: t.Any) -> None: + if hasattr(self.file, "seek"): + self.file.seek(*args) + + def tell(self) -> t.Optional[int]: + if hasattr(self.file, "tell"): + return self.file.tell() + return None + + def __iter__(self) -> "FileWrapper": + return self + + def __next__(self) -> bytes: + data = self.file.read(self.buffer_size) + if data: + return data + raise StopIteration() + + +class _RangeWrapper: + # private for now, but should we make it public in the future ? + + """This class can be used to convert an iterable object into + an iterable that will only yield a piece of the underlying content. + It yields blocks until the underlying stream range is fully read. + The yielded blocks will have a size that can't exceed the original + iterator defined block size, but that can be smaller. + + If you're using this object together with a :class:`Response` you have + to use the `direct_passthrough` mode. + + :param iterable: an iterable object with a :meth:`__next__` method. + :param start_byte: byte from which read will start. + :param byte_range: how many bytes to read. + """ + + def __init__( + self, + iterable: t.Union[t.Iterable[bytes], t.IO[bytes]], + start_byte: int = 0, + byte_range: t.Optional[int] = None, + ): + self.iterable = iter(iterable) + self.byte_range = byte_range + self.start_byte = start_byte + self.end_byte = None + + if byte_range is not None: + self.end_byte = start_byte + byte_range + + self.read_length = 0 + self.seekable = ( + hasattr(iterable, "seekable") and iterable.seekable() # type: ignore + ) + self.end_reached = False + + def __iter__(self) -> "_RangeWrapper": + return self + + def _next_chunk(self) -> bytes: + try: + chunk = next(self.iterable) + self.read_length += len(chunk) + return chunk + except StopIteration: + self.end_reached = True + raise + + def _first_iteration(self) -> t.Tuple[t.Optional[bytes], int]: + chunk = None + if self.seekable: + self.iterable.seek(self.start_byte) # type: ignore + self.read_length = self.iterable.tell() # type: ignore + contextual_read_length = self.read_length + else: + while self.read_length <= self.start_byte: + chunk = self._next_chunk() + if chunk is not None: + chunk = chunk[self.start_byte - self.read_length :] + contextual_read_length = self.start_byte + return chunk, contextual_read_length + + def _next(self) -> bytes: + if self.end_reached: + raise StopIteration() + chunk = None + contextual_read_length = self.read_length + if self.read_length == 0: + chunk, contextual_read_length = self._first_iteration() + if chunk is None: + chunk = self._next_chunk() + if self.end_byte is not None and self.read_length >= self.end_byte: + self.end_reached = True + return chunk[: self.end_byte - contextual_read_length] + return chunk + + def __next__(self) -> bytes: + chunk = self._next() + if chunk: + return chunk + self.end_reached = True + raise StopIteration() + + def close(self) -> None: + if hasattr(self.iterable, "close"): + self.iterable.close() # type: ignore + + +def _make_chunk_iter( + stream: t.Union[t.Iterable[bytes], t.IO[bytes]], + limit: t.Optional[int], + buffer_size: int, +) -> t.Iterator[bytes]: + """Helper for the line and chunk iter functions.""" + if isinstance(stream, (bytes, bytearray, str)): + raise TypeError( + "Passed a string or byte object instead of true iterator or stream." + ) + if not hasattr(stream, "read"): + for item in stream: + if item: + yield item + return + stream = t.cast(t.IO[bytes], stream) + if not isinstance(stream, LimitedStream) and limit is not None: + stream = t.cast(t.IO[bytes], LimitedStream(stream, limit)) + _read = stream.read + while True: + item = _read(buffer_size) + if not item: + break + yield item + + +def make_line_iter( + stream: t.Union[t.Iterable[bytes], t.IO[bytes]], + limit: t.Optional[int] = None, + buffer_size: int = 10 * 1024, + cap_at_buffer: bool = False, +) -> t.Iterator[bytes]: + """Safely iterates line-based over an input stream. If the input stream + is not a :class:`LimitedStream` the `limit` parameter is mandatory. + + This uses the stream's :meth:`~file.read` method internally as opposite + to the :meth:`~file.readline` method that is unsafe and can only be used + in violation of the WSGI specification. The same problem applies to the + `__iter__` function of the input stream which calls :meth:`~file.readline` + without arguments. + + If you need line-by-line processing it's strongly recommended to iterate + over the input stream using this helper function. + + .. versionchanged:: 0.8 + This function now ensures that the limit was reached. + + .. versionadded:: 0.9 + added support for iterators as input stream. + + .. versionadded:: 0.11.10 + added support for the `cap_at_buffer` parameter. + + :param stream: the stream or iterate to iterate over. + :param limit: the limit in bytes for the stream. (Usually + content length. Not necessary if the `stream` + is a :class:`LimitedStream`. + :param buffer_size: The optional buffer size. + :param cap_at_buffer: if this is set chunks are split if they are longer + than the buffer size. Internally this is implemented + that the buffer size might be exhausted by a factor + of two however. + """ + _iter = _make_chunk_iter(stream, limit, buffer_size) + + first_item = next(_iter, "") + if not first_item: + return + + s = _make_encode_wrapper(first_item) + empty = t.cast(bytes, s("")) + cr = t.cast(bytes, s("\r")) + lf = t.cast(bytes, s("\n")) + crlf = t.cast(bytes, s("\r\n")) + + _iter = t.cast(t.Iterator[bytes], chain((first_item,), _iter)) + + def _iter_basic_lines() -> t.Iterator[bytes]: + _join = empty.join + buffer: t.List[bytes] = [] + while True: + new_data = next(_iter, "") + if not new_data: + break + new_buf: t.List[bytes] = [] + buf_size = 0 + for item in t.cast( + t.Iterator[bytes], chain(buffer, new_data.splitlines(True)) + ): + new_buf.append(item) + buf_size += len(item) + if item and item[-1:] in crlf: + yield _join(new_buf) + new_buf = [] + elif cap_at_buffer and buf_size >= buffer_size: + rv = _join(new_buf) + while len(rv) >= buffer_size: + yield rv[:buffer_size] + rv = rv[buffer_size:] + new_buf = [rv] + buffer = new_buf + if buffer: + yield _join(buffer) + + # This hackery is necessary to merge 'foo\r' and '\n' into one item + # of 'foo\r\n' if we were unlucky and we hit a chunk boundary. + previous = empty + for item in _iter_basic_lines(): + if item == lf and previous[-1:] == cr: + previous += item + item = empty + if previous: + yield previous + previous = item + if previous: + yield previous + + +def make_chunk_iter( + stream: t.Union[t.Iterable[bytes], t.IO[bytes]], + separator: bytes, + limit: t.Optional[int] = None, + buffer_size: int = 10 * 1024, + cap_at_buffer: bool = False, +) -> t.Iterator[bytes]: + """Works like :func:`make_line_iter` but accepts a separator + which divides chunks. If you want newline based processing + you should use :func:`make_line_iter` instead as it + supports arbitrary newline markers. + + .. versionadded:: 0.8 + + .. versionadded:: 0.9 + added support for iterators as input stream. + + .. versionadded:: 0.11.10 + added support for the `cap_at_buffer` parameter. + + :param stream: the stream or iterate to iterate over. + :param separator: the separator that divides chunks. + :param limit: the limit in bytes for the stream. (Usually + content length. Not necessary if the `stream` + is otherwise already limited). + :param buffer_size: The optional buffer size. + :param cap_at_buffer: if this is set chunks are split if they are longer + than the buffer size. Internally this is implemented + that the buffer size might be exhausted by a factor + of two however. + """ + _iter = _make_chunk_iter(stream, limit, buffer_size) + + first_item = next(_iter, b"") + if not first_item: + return + + _iter = t.cast(t.Iterator[bytes], chain((first_item,), _iter)) + if isinstance(first_item, str): + separator = _to_str(separator) + _split = re.compile(f"({re.escape(separator)})").split + _join = "".join + else: + separator = _to_bytes(separator) + _split = re.compile(b"(" + re.escape(separator) + b")").split + _join = b"".join + + buffer: t.List[bytes] = [] + while True: + new_data = next(_iter, b"") + if not new_data: + break + chunks = _split(new_data) + new_buf: t.List[bytes] = [] + buf_size = 0 + for item in chain(buffer, chunks): + if item == separator: + yield _join(new_buf) + new_buf = [] + buf_size = 0 + else: + buf_size += len(item) + new_buf.append(item) + + if cap_at_buffer and buf_size >= buffer_size: + rv = _join(new_buf) + while len(rv) >= buffer_size: + yield rv[:buffer_size] + rv = rv[buffer_size:] + new_buf = [rv] + buf_size = len(rv) + + buffer = new_buf + if buffer: + yield _join(buffer) + + +class LimitedStream(io.IOBase): + """Wraps a stream so that it doesn't read more than n bytes. If the + stream is exhausted and the caller tries to get more bytes from it + :func:`on_exhausted` is called which by default returns an empty + string. The return value of that function is forwarded + to the reader function. So if it returns an empty string + :meth:`read` will return an empty string as well. + + The limit however must never be higher than what the stream can + output. Otherwise :meth:`readlines` will try to read past the + limit. + + .. admonition:: Note on WSGI compliance + + calls to :meth:`readline` and :meth:`readlines` are not + WSGI compliant because it passes a size argument to the + readline methods. Unfortunately the WSGI PEP is not safely + implementable without a size argument to :meth:`readline` + because there is no EOF marker in the stream. As a result + of that the use of :meth:`readline` is discouraged. + + For the same reason iterating over the :class:`LimitedStream` + is not portable. It internally calls :meth:`readline`. + + We strongly suggest using :meth:`read` only or using the + :func:`make_line_iter` which safely iterates line-based + over a WSGI input stream. + + :param stream: the stream to wrap. + :param limit: the limit for the stream, must not be longer than + what the string can provide if the stream does not + end with `EOF` (like `wsgi.input`) + """ + + def __init__(self, stream: t.IO[bytes], limit: int) -> None: + self._read = stream.read + self._readline = stream.readline + self._pos = 0 + self.limit = limit + + def __iter__(self) -> "LimitedStream": + return self + + @property + def is_exhausted(self) -> bool: + """If the stream is exhausted this attribute is `True`.""" + return self._pos >= self.limit + + def on_exhausted(self) -> bytes: + """This is called when the stream tries to read past the limit. + The return value of this function is returned from the reading + function. + """ + # Read null bytes from the stream so that we get the + # correct end of stream marker. + return self._read(0) + + def on_disconnect(self) -> bytes: + """What should happen if a disconnect is detected? The return + value of this function is returned from read functions in case + the client went away. By default a + :exc:`~werkzeug.exceptions.ClientDisconnected` exception is raised. + """ + from .exceptions import ClientDisconnected + + raise ClientDisconnected() + + def exhaust(self, chunk_size: int = 1024 * 64) -> None: + """Exhaust the stream. This consumes all the data left until the + limit is reached. + + :param chunk_size: the size for a chunk. It will read the chunk + until the stream is exhausted and throw away + the results. + """ + to_read = self.limit - self._pos + chunk = chunk_size + while to_read > 0: + chunk = min(to_read, chunk) + self.read(chunk) + to_read -= chunk + + def read(self, size: t.Optional[int] = None) -> bytes: + """Read `size` bytes or if size is not provided everything is read. + + :param size: the number of bytes read. + """ + if self._pos >= self.limit: + return self.on_exhausted() + if size is None or size == -1: # -1 is for consistence with file + size = self.limit + to_read = min(self.limit - self._pos, size) + try: + read = self._read(to_read) + except (OSError, ValueError): + return self.on_disconnect() + if to_read and len(read) != to_read: + return self.on_disconnect() + self._pos += len(read) + return read + + def readline(self, size: t.Optional[int] = None) -> bytes: + """Reads one line from the stream.""" + if self._pos >= self.limit: + return self.on_exhausted() + if size is None: + size = self.limit - self._pos + else: + size = min(size, self.limit - self._pos) + try: + line = self._readline(size) + except (ValueError, OSError): + return self.on_disconnect() + if size and not line: + return self.on_disconnect() + self._pos += len(line) + return line + + def readlines(self, size: t.Optional[int] = None) -> t.List[bytes]: + """Reads a file into a list of strings. It calls :meth:`readline` + until the file is read to the end. It does support the optional + `size` argument if the underlying stream supports it for + `readline`. + """ + last_pos = self._pos + result = [] + if size is not None: + end = min(self.limit, last_pos + size) + else: + end = self.limit + while True: + if size is not None: + size -= last_pos - self._pos + if self._pos >= end: + break + result.append(self.readline(size)) + if size is not None: + last_pos = self._pos + return result + + def tell(self) -> int: + """Returns the position of the stream. + + .. versionadded:: 0.9 + """ + return self._pos + + def __next__(self) -> bytes: + line = self.readline() + if not line: + raise StopIteration() + return line + + def readable(self) -> bool: + return True diff --git a/.vcrunch/Scripts/Activate.ps1 b/.vcrunch/Scripts/Activate.ps1 new file mode 100644 index 0000000..181c1ef --- /dev/null +++ b/.vcrunch/Scripts/Activate.ps1 @@ -0,0 +1,405 @@ +<# +.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 virutal 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" + +# SIG # Begin signature block +# MIIc+QYJKoZIhvcNAQcCoIIc6jCCHOYCAQExDzANBglghkgBZQMEAgEFADB5Bgor +# BgEEAYI3AgEEoGswaTA0BgorBgEEAYI3AgEeMCYCAwEAAAQQH8w7YFlLCE63JNLG +# KX7zUQIBAAIBAAIBAAIBAAIBADAxMA0GCWCGSAFlAwQCAQUABCB/jbdIOBl7aFn0 +# IOwX0LZ7IuNFjwXgmb5mWup4AsyxRaCCC38wggUwMIIEGKADAgECAhAECRgbX9W7 +# ZnVTQ7VvlVAIMA0GCSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQK +# EwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNV +# BAMTG0RpZ2lDZXJ0IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xMzEwMjIxMjAwMDBa +# Fw0yODEwMjIxMjAwMDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2Vy +# dCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lD +# ZXJ0IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwggEiMA0GCSqGSIb3 +# DQEBAQUAA4IBDwAwggEKAoIBAQD407Mcfw4Rr2d3B9MLMUkZz9D7RZmxOttE9X/l +# qJ3bMtdx6nadBS63j/qSQ8Cl+YnUNxnXtqrwnIal2CWsDnkoOn7p0WfTxvspJ8fT +# eyOU5JEjlpB3gvmhhCNmElQzUHSxKCa7JGnCwlLyFGeKiUXULaGj6YgsIJWuHEqH +# CN8M9eJNYBi+qsSyrnAxZjNxPqxwoqvOf+l8y5Kh5TsxHM/q8grkV7tKtel05iv+ +# bMt+dDk2DZDv5LVOpKnqagqrhPOsZ061xPeM0SAlI+sIZD5SlsHyDxL0xY4PwaLo +# LFH3c7y9hbFig3NBggfkOItqcyDQD2RzPJ6fpjOp/RnfJZPRAgMBAAGjggHNMIIB +# yTASBgNVHRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBhjATBgNVHSUEDDAK +# BggrBgEFBQcDAzB5BggrBgEFBQcBAQRtMGswJAYIKwYBBQUHMAGGGGh0dHA6Ly9v +# Y3NwLmRpZ2ljZXJ0LmNvbTBDBggrBgEFBQcwAoY3aHR0cDovL2NhY2VydHMuZGln +# aWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJlZElEUm9vdENBLmNydDCBgQYDVR0fBHow +# eDA6oDigNoY0aHR0cDovL2NybDQuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0QXNzdXJl +# ZElEUm9vdENBLmNybDA6oDigNoY0aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL0Rp +# Z2lDZXJ0QXNzdXJlZElEUm9vdENBLmNybDBPBgNVHSAESDBGMDgGCmCGSAGG/WwA +# AgQwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cuZGlnaWNlcnQuY29tL0NQUzAK +# BghghkgBhv1sAzAdBgNVHQ4EFgQUWsS5eyoKo6XqcQPAYPkt9mV1DlgwHwYDVR0j +# BBgwFoAUReuir/SSy4IxLVGLp6chnfNtyA8wDQYJKoZIhvcNAQELBQADggEBAD7s +# DVoks/Mi0RXILHwlKXaoHV0cLToaxO8wYdd+C2D9wz0PxK+L/e8q3yBVN7Dh9tGS +# dQ9RtG6ljlriXiSBThCk7j9xjmMOE0ut119EefM2FAaK95xGTlz/kLEbBw6RFfu6 +# r7VRwo0kriTGxycqoSkoGjpxKAI8LpGjwCUR4pwUR6F6aGivm6dcIFzZcbEMj7uo +# +MUSaJ/PQMtARKUT8OZkDCUIQjKyNookAv4vcn4c10lFluhZHen6dGRrsutmQ9qz +# sIzV6Q3d9gEgzpkxYz0IGhizgZtPxpMQBvwHgfqL2vmCSfdibqFT+hKUGIUukpHq +# aGxEMrJmoecYpJpkUe8wggZHMIIFL6ADAgECAhADPtXtoGXRuMkd/PkqbJvYMA0G +# CSqGSIb3DQEBCwUAMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ +# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0 +# IFNIQTIgQXNzdXJlZCBJRCBDb2RlIFNpZ25pbmcgQ0EwHhcNMTgxMjE4MDAwMDAw +# WhcNMjExMjIyMTIwMDAwWjCBgzELMAkGA1UEBhMCVVMxFjAUBgNVBAgTDU5ldyBI +# YW1wc2hpcmUxEjAQBgNVBAcTCVdvbGZlYm9ybzEjMCEGA1UEChMaUHl0aG9uIFNv +# ZnR3YXJlIEZvdW5kYXRpb24xIzAhBgNVBAMTGlB5dGhvbiBTb2Z0d2FyZSBGb3Vu +# ZGF0aW9uMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAqr2kS7J1uW7o +# JRxlsdrETAjKarfoH5TI8PWST6Yb2xPooP7vHT4iaVXyL5Lze1f53Jw67Sp+u524 +# fJXf30qHViEWxumy2RWG0nciU2d+mMqzjlaAWSZNF0u4RcvyDJokEV0RUOqI5CG5 +# zPI3W9uQ6LiUk3HCYW6kpH177A5T3pw/Po8O8KErJGn1anaqtIICq99ySxrMad/2 +# hPMBRf6Ndah7f7HPn1gkSSTAoejyuqF5h+B0qI4+JK5+VLvz659VTbAWJsYakkxZ +# xVWYpFv4KeQSSwoo0DzMvmERsTzNvVBMWhu9OriJNg+QfFmf96zVTu93cZ+r7xMp +# bXyfIOGKhHMaRuZ8ihuWIx3gI9WHDFX6fBKR8+HlhdkaiBEWIsXRoy+EQUyK7zUs +# +FqOo2sRYttbs8MTF9YDKFZwyPjn9Wn+gLGd5NUEVyNvD9QVGBEtN7vx87bduJUB +# 8F4DylEsMtZTfjw/au6AmOnmneK5UcqSJuwRyZaGNk7y3qj06utx+HTTqHgi975U +# pxfyrwAqkovoZEWBVSpvku8PVhkBXcLmNe6MEHlFiaMoiADAeKmX5RFRkN+VrmYG +# Tg4zajxfdHeIY8TvLf48tTfmnQJd98geJQv/01NUy/FxuwqAuTkaez5Nl1LxP0Cp +# THhghzO4FRD4itT2wqTh4jpojw9QZnsCAwEAAaOCAcUwggHBMB8GA1UdIwQYMBaA +# FFrEuXsqCqOl6nEDwGD5LfZldQ5YMB0GA1UdDgQWBBT8Kr9+1L6s84KcpM97IgE7 +# uI8H8jAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwdwYDVR0f +# BHAwbjA1oDOgMYYvaHR0cDovL2NybDMuZGlnaWNlcnQuY29tL3NoYTItYXNzdXJl +# ZC1jcy1nMS5jcmwwNaAzoDGGL2h0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9zaGEy +# LWFzc3VyZWQtY3MtZzEuY3JsMEwGA1UdIARFMEMwNwYJYIZIAYb9bAMBMCowKAYI +# KwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMwCAYGZ4EMAQQB +# MIGEBggrBgEFBQcBAQR4MHYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2lj +# ZXJ0LmNvbTBOBggrBgEFBQcwAoZCaHR0cDovL2NhY2VydHMuZGlnaWNlcnQuY29t +# L0RpZ2lDZXJ0U0hBMkFzc3VyZWRJRENvZGVTaWduaW5nQ0EuY3J0MAwGA1UdEwEB +# /wQCMAAwDQYJKoZIhvcNAQELBQADggEBAEt1oS21X0axiafPjyY+vlYqjWKuUu/Y +# FuYWIEq6iRRaFabNDhj9RBFQF/aJiE5msrQEOfAD6/6gVSH91lZWBqg6NEeG9T9S +# XbiAPvJ9CEWFsdkXUrjbWhvCnuZ7kqUuU5BAumI1QRbpYgZL3UA+iZXkmjbGh1ln +# 8rUhWIxbBYL4Sg2nqpB44p7CUFYkPj/MbwU2gvBV2pXjj5WaskoZtsACMv5g42BN +# oVLoRAi+ev6s07POt+JtHRIm87lTyuc8wh0swTPUwksKbLU1Zdj9CpqtzXnuVE0w +# 50exJvRSK3Vt4g+0vigpI3qPmDdpkf9+4Mvy0XMNcqrthw20R+PkIlMxghDQMIIQ +# zAIBATCBhjByMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkw +# FwYDVQQLExB3d3cuZGlnaWNlcnQuY29tMTEwLwYDVQQDEyhEaWdpQ2VydCBTSEEy +# IEFzc3VyZWQgSUQgQ29kZSBTaWduaW5nIENBAhADPtXtoGXRuMkd/PkqbJvYMA0G +# CWCGSAFlAwQCAQUAoIGaMBkGCSqGSIb3DQEJAzEMBgorBgEEAYI3AgEEMBwGCisG +# AQQBgjcCAQsxDjAMBgorBgEEAYI3AgEVMC4GCisGAQQBgjcCAQwxIDAeoByAGgBQ +# AHkAdABoAG8AbgAgADMALgAxADAALgAwMC8GCSqGSIb3DQEJBDEiBCBSbvNxuLmL +# Fyf70+vzWnE86JSS2JLTJbh9WhRqgW9MeDANBgkqhkiG9w0BAQEFAASCAgCAiz/E +# icJSsvY4x2vZnY3UjThg0S9qs+r104rhPxj39k4Qw7szI4yjQQbb2bvnoJA3LoFo +# RROlFg9dXJ8YWRZRNkla+zHX7bIsWO2aIFCnOCOUFH19ttlrTvnal6uLp7P9+wQs +# rller1aRyNIM47dYn+CGxD4NEJ/NIqhCjuRKl0v1Dkps/2md0YkoEcnRXNb3vq6x +# +2L9x3zAcBmVwVM4SFFZ2ZZQG/aHgihbVoNxxTXhYDcwaL5uRrNelz9KXDn+GYpk +# K7ZUFbmNfgnhieLHqF0hk7wLZtHI1BSmsOAFrkApcuIVLzD8aSgDbAMVZEv3GkTx +# Img7jKusLIITGuUWT8wO1LDUXT54qBkQhue6kJ3rqSa2agtg/OWxtQ9JwGSOiRaW +# wlRJjsihrw8Nx1Kcr5EwruBBLFiF+mv/C5ikLvwES1ZKoLccqCftuEptcbmsyEZS +# ov39SslaIWvqfy7rfz+KFfP9WHJxobV6DY4essDCMNcoYXkRwhbT+rr0ydDH23DS +# 3hbXpCuKsy5IAMB7Xk8/uuXV2The/qKmkkmu0KuFOu2/3oqVOC4a27IjkvBCSRhp +# /yWQSM/JQk+KwQ31XCVHeGWf7kqMgCXwkZfkw/lvusXzMuWZqT6bfZ0eGjqX/6jC +# kNwr4fCZtxx0cFLzmCr6/yClCYoDCfGoc1I+D6GCDX0wgg15BgorBgEEAYI3AwMB +# MYINaTCCDWUGCSqGSIb3DQEHAqCCDVYwgg1SAgEDMQ8wDQYJYIZIAWUDBAIBBQAw +# dwYLKoZIhvcNAQkQAQSgaARmMGQCAQEGCWCGSAGG/WwHATAxMA0GCWCGSAFlAwQC +# AQUABCBEd30afcCyVMH4hw1ZZPb4JotijhQZtXQ42klvgjTVGwIQDDJTIO6lXwNY +# 7qTonYA8LxgPMjAyMTEwMDQxOTExMzFaoIIKNzCCBP4wggPmoAMCAQICEA1CSuC+ +# Ooj/YEAhzhQA8N0wDQYJKoZIhvcNAQELBQAwcjELMAkGA1UEBhMCVVMxFTATBgNV +# BAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8G +# A1UEAxMoRGlnaUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQTAe +# Fw0yMTAxMDEwMDAwMDBaFw0zMTAxMDYwMDAwMDBaMEgxCzAJBgNVBAYTAlVTMRcw +# FQYDVQQKEw5EaWdpQ2VydCwgSW5jLjEgMB4GA1UEAxMXRGlnaUNlcnQgVGltZXN0 +# YW1wIDIwMjEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDC5mGEZ8WK +# 9Q0IpEXKY2tR1zoRQr0KdXVNlLQMULUmEP4dyG+RawyW5xpcSO9E5b+bYc0VkWJa +# uP9nC5xj/TZqgfop+N0rcIXeAhjzeG28ffnHbQk9vmp2h+mKvfiEXR52yeTGdnY6 +# U9HR01o2j8aj4S8bOrdh1nPsTm0zinxdRS1LsVDmQTo3VobckyON91Al6GTm3dOP +# L1e1hyDrDo4s1SPa9E14RuMDgzEpSlwMMYpKjIjF9zBa+RSvFV9sQ0kJ/SYjU/aN +# Y+gaq1uxHTDCm2mCtNv8VlS8H6GHq756WwogL0sJyZWnjbL61mOLTqVyHO6fegFz +# +BnW/g1JhL0BAgMBAAGjggG4MIIBtDAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/ +# BAIwADAWBgNVHSUBAf8EDDAKBggrBgEFBQcDCDBBBgNVHSAEOjA4MDYGCWCGSAGG +# /WwHATApMCcGCCsGAQUFBwIBFhtodHRwOi8vd3d3LmRpZ2ljZXJ0LmNvbS9DUFMw +# HwYDVR0jBBgwFoAU9LbhIB3+Ka7S5GGlsqIlssgXNW4wHQYDVR0OBBYEFDZEho6k +# urBmvrwoLR1ENt3janq8MHEGA1UdHwRqMGgwMqAwoC6GLGh0dHA6Ly9jcmwzLmRp +# Z2ljZXJ0LmNvbS9zaGEyLWFzc3VyZWQtdHMuY3JsMDKgMKAuhixodHRwOi8vY3Js +# NC5kaWdpY2VydC5jb20vc2hhMi1hc3N1cmVkLXRzLmNybDCBhQYIKwYBBQUHAQEE +# eTB3MCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5jb20wTwYIKwYB +# BQUHMAKGQ2h0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydFNIQTJB +# c3N1cmVkSURUaW1lc3RhbXBpbmdDQS5jcnQwDQYJKoZIhvcNAQELBQADggEBAEgc +# 3LXpmiO85xrnIA6OZ0b9QnJRdAojR6OrktIlxHBZvhSg5SeBpU0UFRkHefDRBMOG +# 2Tu9/kQCZk3taaQP9rhwz2Lo9VFKeHk2eie38+dSn5On7UOee+e03UEiifuHokYD +# Tvz0/rdkd2NfI1Jpg4L6GlPtkMyNoRdzDfTzZTlwS/Oc1np72gy8PTLQG8v1Yfx1 +# CAB2vIEO+MDhXM/EEXLnG2RJ2CKadRVC9S0yOIHa9GCiurRS+1zgYSQlT7LfySmo +# c0NR2r1j1h9bm/cuG08THfdKDXF+l7f0P4TrweOjSaH6zqe/Vs+6WXZhiV9+p7SO +# Z3j5NpjhyyjaW4emii8wggUxMIIEGaADAgECAhAKoSXW1jIbfkHkBdo2l8IVMA0G +# CSqGSIb3DQEBCwUAMGUxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJ +# bmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20xJDAiBgNVBAMTG0RpZ2lDZXJ0 +# IEFzc3VyZWQgSUQgUm9vdCBDQTAeFw0xNjAxMDcxMjAwMDBaFw0zMTAxMDcxMjAw +# MDBaMHIxCzAJBgNVBAYTAlVTMRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNV +# BAsTEHd3dy5kaWdpY2VydC5jb20xMTAvBgNVBAMTKERpZ2lDZXJ0IFNIQTIgQXNz +# dXJlZCBJRCBUaW1lc3RhbXBpbmcgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw +# ggEKAoIBAQC90DLuS82Pf92puoKZxTlUKFe2I0rEDgdFM1EQfdD5fU1ofue2oPSN +# s4jkl79jIZCYvxO8V9PD4X4I1moUADj3Lh477sym9jJZ/l9lP+Cb6+NGRwYaVX4L +# J37AovWg4N4iPw7/fpX786O6Ij4YrBHk8JkDbTuFfAnT7l3ImgtU46gJcWvgzyIQ +# D3XPcXJOCq3fQDpct1HhoXkUxk0kIzBdvOw8YGqsLwfM/fDqR9mIUF79Zm5WYScp +# iYRR5oLnRlD9lCosp+R1PrqYD4R/nzEU1q3V8mTLex4F0IQZchfxFwbvPc3WTe8G +# Qv2iUypPhR3EHTyvz9qsEPXdrKzpVv+TAgMBAAGjggHOMIIByjAdBgNVHQ4EFgQU +# 9LbhIB3+Ka7S5GGlsqIlssgXNW4wHwYDVR0jBBgwFoAUReuir/SSy4IxLVGLp6ch +# nfNtyA8wEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwEwYDVR0l +# BAwwCgYIKwYBBQUHAwgweQYIKwYBBQUHAQEEbTBrMCQGCCsGAQUFBzABhhhodHRw +# Oi8vb2NzcC5kaWdpY2VydC5jb20wQwYIKwYBBQUHMAKGN2h0dHA6Ly9jYWNlcnRz +# LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcnQwgYEGA1Ud +# HwR6MHgwOqA4oDaGNGh0dHA6Ly9jcmw0LmRpZ2ljZXJ0LmNvbS9EaWdpQ2VydEFz +# c3VyZWRJRFJvb3RDQS5jcmwwOqA4oDaGNGh0dHA6Ly9jcmwzLmRpZ2ljZXJ0LmNv +# bS9EaWdpQ2VydEFzc3VyZWRJRFJvb3RDQS5jcmwwUAYDVR0gBEkwRzA4BgpghkgB +# hv1sAAIEMCowKAYIKwYBBQUHAgEWHGh0dHBzOi8vd3d3LmRpZ2ljZXJ0LmNvbS9D +# UFMwCwYJYIZIAYb9bAcBMA0GCSqGSIb3DQEBCwUAA4IBAQBxlRLpUYdWac3v3dp8 +# qmN6s3jPBjdAhO9LhL/KzwMC/cWnww4gQiyvd/MrHwwhWiq3BTQdaq6Z+CeiZr8J +# qmDfdqQ6kw/4stHYfBli6F6CJR7Euhx7LCHi1lssFDVDBGiy23UC4HLHmNY8ZOUf +# SBAYX4k4YU1iRiSHY4yRUiyvKYnleB/WCxSlgNcSR3CzddWThZN+tpJn+1Nhiaj1 +# a5bA9FhpDXzIAbG5KHW3mWOFIoxhynmUfln8jA/jb7UBJrZspe6HUSHkWGCbugwt +# K22ixH67xCUrRwIIfEmuE7bhfEJCKMYYVs9BNLZmXbZ0e/VWMyIvIjayS6JKldj1 +# po5SMYIChjCCAoICAQEwgYYwcjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lD +# ZXJ0IEluYzEZMBcGA1UECxMQd3d3LmRpZ2ljZXJ0LmNvbTExMC8GA1UEAxMoRGln +# aUNlcnQgU0hBMiBBc3N1cmVkIElEIFRpbWVzdGFtcGluZyBDQQIQDUJK4L46iP9g +# QCHOFADw3TANBglghkgBZQMEAgEFAKCB0TAaBgkqhkiG9w0BCQMxDQYLKoZIhvcN +# AQkQAQQwHAYJKoZIhvcNAQkFMQ8XDTIxMTAwNDE5MTEzMVowKwYLKoZIhvcNAQkQ +# AgwxHDAaMBgwFgQU4deCqOGRvu9ryhaRtaq0lKYkm/MwLwYJKoZIhvcNAQkEMSIE +# ILvICiD0Bu7OdD0pC2wAqLO9UGMzUOfGejuSENvWkuXdMDcGCyqGSIb3DQEJEAIv +# MSgwJjAkMCIEILMQkAa8CtmDB5FXKeBEA0Fcg+MpK2FPJpZMjTVx7PWpMA0GCSqG +# SIb3DQEBAQUABIIBAIaCoJWKRd6cHB/KrrlVmBY469068xG7ok+T18bfcLmNrvPF +# 7PGY5a4qcMZj+rBevyfWTrOreNAWyNhnxIT0qYneSTJOMytTPYnJI+GhvGwQjDhC +# Eg/JeLOe9guMq7P/ZNvFur+VoCz6sgR/Q+9IGUhJ/7liABdMwNLK38r5VEaSAnSW +# RetjuSqtMoZc2KtjL/MUY26sUwjsMD0tgt0EOF4nrcv3rWl++TsJUEqYr+aFpNu4 +# eVaTNeS0V7sRGQbWAQohkES879Lpqv7KaEW+h426+cc5el260gynz7vTzUuaamvW +# Nfbvu83P5Tk1nRA1Ds2aSqn/RMu6cNNjD8ntV5o= +# SIG # End signature block diff --git a/.vcrunch/Scripts/activate b/.vcrunch/Scripts/activate new file mode 100644 index 0000000..a5d4148 --- /dev/null +++ b/.vcrunch/Scripts/activate @@ -0,0 +1,69 @@ +# 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 + + # This should detect bash and zsh, which have a hash command that must + # be called to get it to forget past commands. Without forgetting + # past commands the $PATH changes we made may not be respected + if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null + fi + + 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 + +VIRTUAL_ENV="C:\Users\erica\soupboat\crunch\.vcrunch" +export VIRTUAL_ENV + +_OLD_VIRTUAL_PATH="$PATH" +PATH="$VIRTUAL_ENV/Scripts:$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="(.vcrunch) ${PS1:-}" + export PS1 + VIRTUAL_ENV_PROMPT="(.vcrunch) " + export VIRTUAL_ENV_PROMPT +fi + +# This should detect bash and zsh, which have a hash command that must +# be called to get it to forget past commands. Without forgetting +# past commands the $PATH changes we made may not be respected +if [ -n "${BASH:-}" -o -n "${ZSH_VERSION:-}" ] ; then + hash -r 2> /dev/null +fi diff --git a/.vcrunch/Scripts/activate.bat b/.vcrunch/Scripts/activate.bat new file mode 100644 index 0000000..a709c06 --- /dev/null +++ b/.vcrunch/Scripts/activate.bat @@ -0,0 +1,34 @@ +@echo off + +rem This file is UTF-8 encoded, so we need to update the current code page while executing it +for /f "tokens=2 delims=:." %%a in ('"%SystemRoot%\System32\chcp.com"') do ( + set _OLD_CODEPAGE=%%a +) +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" 65001 > nul +) + +set VIRTUAL_ENV=C:\Users\erica\soupboat\crunch\.vcrunch + +if not defined PROMPT set PROMPT=$P$G + +if defined _OLD_VIRTUAL_PROMPT set PROMPT=%_OLD_VIRTUAL_PROMPT% +if defined _OLD_VIRTUAL_PYTHONHOME set PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME% + +set _OLD_VIRTUAL_PROMPT=%PROMPT% +set PROMPT=(.vcrunch) %PROMPT% + +if defined PYTHONHOME set _OLD_VIRTUAL_PYTHONHOME=%PYTHONHOME% +set PYTHONHOME= + +if defined _OLD_VIRTUAL_PATH set PATH=%_OLD_VIRTUAL_PATH% +if not defined _OLD_VIRTUAL_PATH set _OLD_VIRTUAL_PATH=%PATH% + +set PATH=%VIRTUAL_ENV%\Scripts;%PATH% +set VIRTUAL_ENV_PROMPT=(.vcrunch) + +:END +if defined _OLD_CODEPAGE ( + "%SystemRoot%\System32\chcp.com" %_OLD_CODEPAGE% > nul + set _OLD_CODEPAGE= +) diff --git a/.vcrunch/Scripts/deactivate.bat b/.vcrunch/Scripts/deactivate.bat new file mode 100644 index 0000000..62a39a7 --- /dev/null +++ b/.vcrunch/Scripts/deactivate.bat @@ -0,0 +1,22 @@ +@echo off + +if defined _OLD_VIRTUAL_PROMPT ( + set "PROMPT=%_OLD_VIRTUAL_PROMPT%" +) +set _OLD_VIRTUAL_PROMPT= + +if defined _OLD_VIRTUAL_PYTHONHOME ( + set "PYTHONHOME=%_OLD_VIRTUAL_PYTHONHOME%" + set _OLD_VIRTUAL_PYTHONHOME= +) + +if defined _OLD_VIRTUAL_PATH ( + set "PATH=%_OLD_VIRTUAL_PATH%" +) + +set _OLD_VIRTUAL_PATH= + +set VIRTUAL_ENV= +set VIRTUAL_ENV_PROMPT= + +:END diff --git a/.vcrunch/Scripts/flask.exe b/.vcrunch/Scripts/flask.exe new file mode 100644 index 0000000000000000000000000000000000000000..a15bfbb7aedd42828fdbb6844bea1f91c0f61dcd GIT binary patch literal 106356 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%0DR4z)WQcb>Rku)_txjy8TEHVs#H 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%0DqcKFn%RX-DF>qCHtfd(>0m&Tp(1(DRhHdoti)C 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%0DS07BAj6-njF-qy0mJ8pj3rJ?3!<- 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 z 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 literal 0 HcmV?d00001 diff --git a/.vcrunch/Scripts/pythonw.exe b/.vcrunch/Scripts/pythonw.exe new file mode 100644 index 0000000000000000000000000000000000000000..c1c2531d554b91055a8ec54c2e6be096d3b2160c GIT binary patch literal 232688 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 literal 0 HcmV?d00001 diff --git a/app.py b/app.py new file mode 100644 index 0000000..9d85f56 --- /dev/null +++ b/app.py @@ -0,0 +1,34 @@ +# Critical evaluation of crunchiness + +from flask import Flask, render_template, url_for, request, redirect + + + # --------- Flask --------- # + +class PrefixMiddleware(object): + def __init__(self, app, prefix=""): + self.app = app + self.prefix = prefix + + def __call__(self, environ, start_response): + + if environ["PATH_INFO"].startswith(self.prefix): + environ["PATH_INFO"] = environ["PATH_INFO"][len(self.prefix):] + environ["SCRIPT_NAME"] = self.prefix + return self.app(environ, start_response) + else: + start_response("404", [("Content-Type", "text/plain")]) + return ["This url does not belong to the app.".encode()] + +app = Flask(__name__) +app.wsgi_app = PrefixMiddleware(app.wsgi_app, prefix='/soupboat/crunch') + + +@app.route('/') +def index(): + return render_template('index.html') + + +app.run(port=3140) + + diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..653deba --- /dev/null +++ b/templates/index.html @@ -0,0 +1 @@ +

    hello

    \ No newline at end of file